MOOS 0.2375
|
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