MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Core/MOOSLIB/XPCTcpSocket.cpp
Go to the documentation of this file.
00001 
00002 //
00003 //   MOOS - Mission Oriented Operating Suite 
00004 //  
00005 //   A suit of Applications and Libraries for Mobile Robotics Research 
00006 //   Copyright (C) 2001-2005 Massachusetts Institute of Technology and 
00007 //   Oxford University. 
00008 //    
00009 //   This software was written by Paul Newman at MIT 2001-2002 and Oxford 
00010 //   University 2003-2005. email: pnewman@robots.ox.ac.uk. 
00011 //      
00012 //   This file is part of a  MOOS Core Component. 
00013 //        
00014 //   This program is free software; you can redistribute it and/or 
00015 //   modify it under the terms of the GNU General Public License as 
00016 //   published by the Free Software Foundation; either version 2 of the 
00017 //   License, or (at your option) any later version. 
00018 //          
00019 //   This program is distributed in the hope that it will be useful, 
00020 //   but WITHOUT ANY WARRANTY; without even the implied warranty of 
00021 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
00022 //   General Public License for more details. 
00023 //            
00024 //   You should have received a copy of the GNU General Public License 
00025 //   along with this program; if not, write to the Free Software 
00026 //   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
00027 //   02111-1307, USA. 
00028 //
00029 //   The XPC classes in MOOS are modified versions of the source provided 
00030 //   in "Making UNIX and Windows NT Talk" by Mark Nadelson and Thomas Haga 
00031 //
00033 #include "XPCTcpSocket.h"
00034 #ifdef _WIN32
00035 #else
00036 #include <sys/time.h>
00037 #endif
00038 
00039 #include <string>
00040 
00041 
00042 
00043 void XPCTcpSocket::vConnect(const char *_sHost)
00044 {
00045     struct sockaddr_in serverAddress;
00046     
00047     serverAddress.sin_family = AF_INET;
00048     serverAddress.sin_port = htons(iPort);
00049     
00050     // Resolve the IP address of the given host name
00051     std::string sHost(_sHost);
00052     hostType HostType;
00053     if(sHost.find_first_not_of("0123456789. ")!=std::string::npos)
00054     {
00055         HostType = NAME;
00056         XPCGetHostInfo getHostInfo(_sHost, HostType);
00057         
00058         // Store the IP address and socket port number
00059         serverAddress.sin_addr.s_addr =inet_addr(getHostInfo.sGetHostAddress());
00060         
00061     }
00062     else
00063     {
00064         HostType = ADDRESS;
00065         // Store the IP address and socket port number
00066         serverAddress.sin_addr.s_addr =inet_addr(_sHost);
00067     }        
00068     
00069     // Connect to the given address
00070     if (connect(iSocket, (struct sockaddr *)&serverAddress,sizeof(serverAddress)) == -1)
00071     {
00072         char sMsg[512];
00073         sprintf(sMsg, "Error Connecting To Socket. %s", sGetError());
00074         XPCException socketExcept(sMsg);
00075         throw socketExcept;
00076         return;
00077     }
00078 }
00079 
00080 XPCTcpSocket *XPCTcpSocket::Accept(char *_sHost)
00081 {
00082     short int iNewSocket;   // Stores the new socket file descriptor
00083     
00084     struct sockaddr_in clientAddress;       // Stores the connected clients info
00085     
00086     // Gets the length of the client's address
00087     int iClientAddressLen = sizeof(clientAddress);
00088     
00089     // Accepts a new client connection and stores its socket file descriptor
00090     if ((iNewSocket = accept(iSocket, (struct sockaddr *)&clientAddress,(socklen_t*)&iClientAddressLen)) == -1)
00091     {
00092         char sMsg[512];
00093         
00094         sprintf(sMsg, "Error Accepting Socket. %s", sGetError());
00095         XPCException socketExcept(sMsg);
00096         throw socketExcept;
00097         return NULL;
00098     } 
00099     
00100     // If the host name is requested
00101     if (_sHost != NULL)
00102     {
00103         // Get the ascii representation of the address
00104         char *sAddress = inet_ntoa((struct in_addr)clientAddress.sin_addr);
00105         
00106         // Get the host name given the address
00107         try
00108         {
00109             XPCGetHostInfo getHostInfo(sAddress, ADDRESS);
00110             // Store the host name
00111             strcpy(_sHost, getHostInfo.sGetHostName());
00112         }
00113         catch(XPCException e)
00114         {
00115             strcpy(_sHost, sAddress);
00116             printf("INFO: %s using numeric address %s\n",e.sGetException(),_sHost);
00117         }
00118         
00119     }
00120     
00121     // Create and return the new XPCTcpSocket object
00122     XPCTcpSocket *newSocket = new XPCTcpSocket(iNewSocket);
00123     
00124     return newSocket;
00125 }
00126 
00127 void XPCTcpSocket::vListen(int _iNumPorts)
00128 {
00129     // Incoming connections are listened for
00130     if (listen(iSocket, _iNumPorts) == -1)
00131     {
00132         char sMsg[512];       
00133         sprintf(sMsg, "Error Listening To Socket. %s", sGetError());
00134         throw XPCException(sMsg);;
00135         return;
00136     }
00137 }       
00138 
00139 int XPCTcpSocket::iSendMessage(void *_vMessage, int _iMessageSize)
00140 {
00141     int iNumBytes;  // Stores the number of bytes sent
00142     
00143     // Sends the message to the connected host
00144 #ifdef _WIN32
00145     if ((iNumBytes = send(iSocket, (char *)_vMessage, _iMessageSize, 0)) ==
00146         -1)
00147 #else
00148                 if ((iNumBytes = send(iSocket, _vMessage, _iMessageSize, 0)) ==
00149                         -1)
00150 #endif          
00151     {
00152         char sMsg[512];        
00153         sprintf(sMsg, "Error sending socket message: %s", sGetError());
00154         throw XPCException(sMsg);
00155         return 0;
00156     }
00157     return iNumBytes;
00158 }
00159 
00160 #ifdef WINDOWS_NT
00161 int XPCTcpSocket::iRecieveMessageAll(void *_vMessage, int _iMessageSize)
00162 {
00163     int iNumBytes = 0;      // The number of bytes received
00164     
00165     int iCurrentSize = _iMessageSize;       // The number of bytes wanted toreceive
00166     int iOffsetSize = 0;                    // The number of bytes currentlyrecieved
00167     
00168     // While the number of bytes received is less than the number requestedcontinue to
00169     // retrieve more data
00170     while (iNumBytes < iCurrentSize)
00171     {
00172         // The socket message is recieved and stored within the mesageoffset by the 
00173         // offset number of bytes
00174         iNumBytes = recv(iSocket, (char *)_vMessage + iOffsetSize,iCurrentSize, 0);
00175         if (iNumBytes == -1)
00176         {
00177             // If the reason for failure is a client disconnect, an exception isnot thrown.
00178             // The number of bytes returned is 0
00179             if (WSAGetLastError() == WSAECONNRESET)
00180                 return 0;
00181             
00182             char sMsg[512];
00183             
00184             sprintf(sMsg, "Error receiving on socket: %s", sGetError());
00185             XPCException socketExcept(sMsg);
00186             throw socketExcept;
00187             return iNumBytes;
00188         }
00189         else if (iNumBytes == 0)
00190             return iNumBytes;
00191         
00192         // If the total number of bytes requested are not returned, theoffset is adjusted
00193         // and the number of bytes left to receive is also adjusted
00194         else if (iNumBytes < iCurrentSize)
00195         {
00196             iOffsetSize += iNumBytes;
00197             iCurrentSize = iCurrentSize - iNumBytes;
00198             iNumBytes = 0;
00199         }
00200     }
00201     
00202     return _iMessageSize;   
00203 }
00204 #endif
00205 
00206 int XPCTcpSocket::iRecieveMessage(void *_vMessage, int _iMessageSize, int _iOption)
00207 {
00208     int iNumBytes;  // The number of bytes recieved
00209     
00210 #ifdef WINDOWS_NT
00211     if (_iOption == MSG_WAITALL)
00212         // If the option is MSG_WAITALL and this is a WINDOW_NT machinecall iReceiveMessageAll
00213         // to process it
00214         return iRecieveMessageAll(_vMessage, _iMessageSize);
00215 #endif
00216     
00217     // Recieves a TCP socket message.  The number of bytes received isreturned
00218     iNumBytes = recv(iSocket, (char *)_vMessage, _iMessageSize, _iOption);
00219     if (iNumBytes == -1)
00220     {
00221         // If the reason for failure is a client disconnect, anexception is not thrown.
00222         // The number of bytes returned is 0    
00223 #ifdef UNIX
00224         if (errno == ECONNRESET)
00225             return 0;
00226 #else
00227         if (WSAGetLastError() == WSAECONNRESET)
00228             return 0;
00229 #endif
00230         char sMsg[512];
00231         
00232         sprintf(sMsg, "Error receiving on socket: %s", sGetError());
00233         printf("%s\n",sMsg);
00234         throw XPCException(sMsg);
00235         
00236     }
00237     
00238     return iNumBytes;
00239 }
00240 
00241 void XPCTcpSocket::vBindSocket()
00242 {
00243     // Bind the socket to the given address and port number
00244     if (bind(iSocket, (struct sockaddr *)&clientAddress,sizeof(clientAddress)) == -1)
00245     {
00246         char sMsg[512];
00247         sprintf(sMsg, "Error binding to socket: %s", sGetError());
00248         XPCException socketExcept(sMsg);
00249         throw socketExcept;
00250         return;
00251     }
00252 }
00253 
00254 int XPCTcpSocket::iReadMessageWithTimeOut(void *_vMessage, int _iMessageSize, double dfTimeOut,int _iOption)
00255 {
00256     int iNumBytes = 0;
00257     
00258     struct timeval timeout;        // The timeout value for the select system call
00259     fd_set fdset;                // Set of "watched" file descriptors
00260     
00261     
00262     // The socket file descriptor set is cleared and the socket file 
00263     // descriptor contained within tcpSocket is added to the file
00264     // descriptor set.
00265     FD_ZERO(&fdset);
00266     
00267     FD_SET((unsigned int)iGetSocketFd(), &fdset);
00268     
00269     
00270     // The select system call is set to timeout after 1 seconds with no data existing
00271     // on the socket. This has to be here, within the loop as Linux actually writes over
00272     // the timeout structure on completion of select (now that was a hard bug to find)
00273     
00274     if(dfTimeOut<1)
00275     {
00276         dfTimeOut=1.0;
00277     }
00278     
00279     timeout.tv_sec    = (int)dfTimeOut;
00280     timeout.tv_usec = 0;
00281     
00282     
00283     // A select is setup to return when data is available on the socket
00284     // for reading.  If data is not available after timeout seconds, select
00285     // returns with a value of 0.  If data is available on the socket,
00286     // the select returns and data can be retrieved off the socket.
00287     int iSelectRet = select(iGetSocketFd() + 1,
00288         &fdset,
00289         NULL,
00290         NULL,
00291         &timeout);
00292     
00293     // If select returns a -1, then it failed and the thread exits.
00294     switch(iSelectRet)
00295     {
00296     case -1:
00297         //                Trace("Select failed ");
00298         iNumBytes=-1;
00299         break;
00300         
00301     case 0:
00302         //timeout...nothing to read
00303         iNumBytes = 0;
00304         break;
00305         
00306     default:
00307         
00308         if (FD_ISSET(iGetSocketFd(), &fdset) != 0)
00309         {
00310             //something to do read:
00311             return iRecieveMessage(_vMessage,_iMessageSize,_iOption);
00312         }
00313         break;
00314     }
00315     
00316     //zero socket set..
00317     FD_ZERO(&fdset);
00318     
00319     return iNumBytes;
00320 }
00321 
00322 
00323 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines