Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages | Examples

ArSocket.cpp

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004, 2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006, 2007 MobileRobots Inc.
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 #include "ArExport.h"
00027 #include "ariaOSDef.h"
00028 #include "ArSocket.h"
00029 #include "ArLog.h"
00030 
00031 
00032 void ArSocket::internalInit(void)
00033 {
00034   myCloseFunctor = NULL;
00035   myStringAutoEcho = true;
00036   myStringEcho = false;
00037   myStringPosLast = 0;
00038   myStringPos = 0;
00039   myStringGotComplete = false;
00040   myStringBufEmpty[0] = '\0';
00041   myStringGotEscapeChars = false;
00042   myStringHaveEchoed = false;
00043   sprintf(myIPString, "none");
00044   resetTracking();
00045 }
00046 
00047 AREXPORT int ArSocket::sendTo(const void *msg, int len)
00048 {
00049   int ret;
00050   ret = ::sendto(myFD, (char*)msg, len, 0, (struct sockaddr*)&mySin,
00051           sizeof(mySin));
00052   if (ret > 0)
00053   {
00054     mySends++;
00055     myBytesSent += ret;
00056   }
00057   return ret;
00058 }
00059 
00060 AREXPORT int ArSocket::sendTo(const void *msg, int len, 
00061                   struct sockaddr_in *sin)
00062 { 
00063   int ret;
00064   ret = ::sendto(myFD, (char*)msg, len, 0, (struct sockaddr*)sin,
00065           sizeof(struct sockaddr_in));
00066   if (ret > 0)
00067   {
00068     mySends++;
00069     myBytesSent += ret;
00070   }
00071   return ret;
00072 }
00073 
00074 
00075 AREXPORT int ArSocket::recvFrom(void *msg, int len, sockaddr_in *sin)
00076 {
00077 
00078 #ifdef WIN32
00079   int i=sizeof(sockaddr_in);
00080 #else
00081   socklen_t i=sizeof(sockaddr_in);
00082 #endif
00083   int ret;
00084   ret = ::recvfrom(myFD, (char*)msg, len, 0, (struct sockaddr*)sin, &i);
00085   if (ret > 0)
00086   {
00087     myRecvs++;
00088     myBytesRecvd += ret;
00089   }
00090   return ret;
00091 }
00092 
00098 AREXPORT int ArSocket::write(const void *buff, size_t len)
00099 {
00100 
00101   if (myFD < 0)
00102   {
00103     ArLog::log(ArLog::Terse, "ArSocket::write: called after socket closed");
00104     return 0;
00105   }
00106 
00107   struct timeval tval;
00108   fd_set fdSet;
00109   tval.tv_sec = 0;
00110   tval.tv_usec = 0;
00111   FD_ZERO(&fdSet);
00112   FD_SET(myFD, &fdSet);
00113   
00114 
00115   if (select(myFD + 1, NULL, &fdSet, NULL, &tval) <= 0)
00116     return 0;
00117   
00118   int ret;
00119 #ifdef WIN32
00120   ret = ::send(myFD, (char*)buff, len, 0);
00121 #else
00122   ret = ::write(myFD, (char*)buff, len);
00123 #endif
00124 
00125   if (ret > 0)
00126   {
00127     mySends++;
00128     myBytesSent += ret;
00129   }
00130   return ret;
00131 }
00132 
00139 AREXPORT int ArSocket::read(void *buff, size_t len, unsigned int msWait)
00140 {
00141   if (myFD < 0)
00142   {
00143     ArLog::log(ArLog::Terse, "ArSocket::read: called after socket closed");
00144     return 0;
00145   }
00146 
00147   int ret;
00148   if (msWait != 0)
00149   {
00150     struct timeval tval;
00151     fd_set fdSet;
00152     tval.tv_sec = msWait / 1000;
00153     tval.tv_usec = (msWait % 1000) * 1000;
00154     FD_ZERO(&fdSet);
00155     FD_SET(myFD, &fdSet);
00156     if (select(myFD + 1, &fdSet, NULL, NULL, &tval) <= 0)
00157       return 0;
00158   }
00159   ret = ::recv(myFD, (char*)buff, len, 0);
00160   if (ret > 0)
00161   {
00162     myRecvs++;
00163     myBytesRecvd += ret;
00164   }
00165   return ret;
00166 }
00167 
00168 
00169 
00170 /*
00171    This cannot write more than 512 number of bytes
00172    @param str the string to write to the socket
00173    @return number of bytes written
00174 **/
00175 AREXPORT int ArSocket::writeString(const char *str, ...)
00176 {
00177   char buf[1200];
00178   int len;
00179   int ret;
00180   myWriteStringMutex.lock();
00181   va_list ptr;
00182   va_start(ptr, str);
00183   vsnprintf(buf, sizeof(buf), str, ptr);
00184   va_end(ptr);
00185   if (myLogWriteStrings)
00186     ArLog::log(ArLog::Normal, "Sent to %s: %s", getIPString(), buf);
00187   len = strlen(buf);
00188   buf[len] = '\n';
00189   len++;
00190   buf[len] = '\r';
00191   len++;
00192   ret = write(buf, len);
00193   myWriteStringMutex.unlock();
00194   return ret;
00195 }
00196 
00197 void ArSocket::setIPString(void)
00198 {
00199   unsigned char *bytes;
00200   bytes = (unsigned char *)inAddr();
00201   if (bytes != NULL)
00202     sprintf(myIPString, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
00203 }
00204 
00205 
00216 AREXPORT char *ArSocket::readString(void)
00217 {
00218   size_t i;
00219   int n;
00220 
00221   myReadStringMutex.lock();
00222   myStringBufEmpty[0] = '\0';
00223   
00224   // read one byte at a time
00225   for (i = myStringPos; i < sizeof(myStringBuf); i++)
00226   {
00227     
00228     n = read(&myStringBuf[i], 1);
00229     if (n > 0)
00230     {
00231       if (i == 0 && myStringBuf[i] < 0)
00232       {
00233     myStringGotEscapeChars = true;
00234       }
00235       if (myStringBuf[i] == '\n' || myStringBuf[i] == '\r')
00236       {
00237     if (i != 0)
00238       myStringGotComplete = true;
00239     myStringBuf[i] = '\0';
00240     myStringPos = 0;
00241     myStringPosLast = 0;
00242     // if we have leading escape characters get rid of them
00243     if (myStringBuf[0] < 0)
00244     {
00245       int ei;
00246       myStringGotEscapeChars = true;
00247       // increment out the escape chars
00248       for (ei = 0; 
00249            myStringBuf[ei] < 0 || (ei > 0 && myStringBuf[ei - 1] < 0); 
00250            ei++);
00251       // okay now return the good stuff
00252       doStringEcho();
00253       myReadStringMutex.unlock();
00254       return &myStringBuf[ei];
00255     }
00256     // if we don't return what we got
00257     doStringEcho();
00258     myReadStringMutex.unlock();
00259     return myStringBuf;
00260       }
00261       // if its not an ending character but was good keep going
00262       else
00263     continue;
00264     }
00265     // failed
00266     else if (n == 0)
00267     {
00268       myReadStringMutex.unlock();
00269       return NULL;
00270     }
00271     else // which means (n < 0)
00272     {
00273 #ifdef WIN32
00274       if (WSAGetLastError() == WSAEWOULDBLOCK)
00275       {
00276     myStringPos = i;
00277     doStringEcho();
00278     myReadStringMutex.unlock();
00279     return myStringBufEmpty;
00280       }
00281 #endif
00282 #ifndef WIN32
00283       if (errno == EAGAIN)
00284       {
00285     myStringPos = i;
00286     doStringEcho();
00287     myReadStringMutex.unlock();
00288     return myStringBufEmpty;
00289       }
00290 #endif
00291       perror("Error in reading from network");
00292       myReadStringMutex.unlock();
00293       return NULL;
00294     }
00295   }
00296   // if they want a 0 length string
00297   ArLog::log(ArLog::Normal, "Some trouble in ArSocket::readString to %s", getIPString());
00298   writeString("String too long");
00299   myReadStringMutex.unlock();
00300   return NULL;
00301 }
00302 
00303 void ArSocket::doStringEcho(void)
00304 {
00305   size_t to;
00306 
00307   if (!myStringAutoEcho && !myStringEcho)
00308     return;
00309 
00310   // if we're echoing complete thel ines
00311   if (myStringHaveEchoed && myStringGotComplete)
00312   {
00313     write("\n\r", 2);
00314     myStringGotComplete = false;
00315   }
00316 
00317   // if there's nothing to send we don't need to send it
00318   if (myStringPosLast == myStringPos)
00319     return;
00320   
00321   // we probably don't need it if its doing escape chars
00322   if (myStringAutoEcho && myStringGotEscapeChars)
00323     return;
00324 
00325   myStringHaveEchoed = true;
00326   to = strchr(myStringBuf, '\0') - myStringBuf;
00327   write(&myStringBuf[myStringPosLast], myStringPos - myStringPosLast);
00328   myStringPosLast = myStringPos;
00329 }
00330 

Generated on Tue Feb 20 10:51:41 2007 for Aria by  doxygen 1.4.0