XmlRpcSocket.cpp
Go to the documentation of this file.
00001 // this file modified by Morgan Quigley on 22 Apr 2008.
00002 // added features: server can be opened on port 0 and you can read back
00003 // what port the OS gave you
00004 
00005 #include "XmlRpcSocket.h"
00006 #include "XmlRpcUtil.h"
00007 
00008 #ifndef MAKEDEPEND
00009 
00010 #if defined(_WINDOWS)
00011 # include <stdio.h>
00012 # include <winsock2.h>
00013 # include <ws2tcpip.h>
00014 //# pragma lib(WS2_32.lib)
00015 
00016 // MS VS10 actually has these definitions (as opposed to earlier versions),
00017 // so if present, temporarily disable them and reset to WSA codes for this file only.
00018 #ifdef EAGAIN
00019   #undef EAGAIN
00020 #endif
00021 #ifdef EINTR
00022   #undef EINTR
00023 #endif
00024 #ifdef EINPROGRESS
00025   #undef EINPROGRESS
00026 #endif
00027 #ifdef  EWOULDBLOCK
00028   #undef EWOULDBLOCK
00029 #endif
00030 #ifdef ETIMEDOUT
00031   #undef ETIMEDOUT
00032 #endif
00033 # define EAGAIN         WSATRY_AGAIN
00034 # define EINTR                  WSAEINTR
00035 # define EINPROGRESS    WSAEINPROGRESS
00036 # define EWOULDBLOCK    WSAEWOULDBLOCK
00037 # define ETIMEDOUT          WSAETIMEDOUT
00038 #else
00039 extern "C" {
00040 # include <unistd.h>
00041 # include <stdio.h>
00042 # include <sys/types.h>
00043 # include <sys/socket.h>
00044 # include <netinet/in.h>
00045 # include <netdb.h>
00046 # include <errno.h>
00047 # include <fcntl.h>
00048 # include <string.h>
00049 }
00050 #endif  // _WINDOWS
00051 
00052 #endif // MAKEDEPEND
00053 
00054 // MSG_NOSIGNAL does not exists on OS X
00055 #if defined(__APPLE__) || defined(__MACH__)
00056 # ifndef MSG_NOSIGNAL
00057 #   define MSG_NOSIGNAL SO_NOSIGPIPE
00058 # endif
00059 #endif
00060 
00061 
00062 using namespace XmlRpc;
00063 
00064 
00065 
00066 #if defined(_WINDOWS)
00067 
00068 static void initWinSock()
00069 {
00070   static bool wsInit = false;
00071   if (! wsInit)
00072   {
00073     WORD wVersionRequested = MAKEWORD( 2, 0 );
00074     WSADATA wsaData;
00075     WSAStartup(wVersionRequested, &wsaData);
00076     wsInit = true;
00077   }
00078 }
00079 
00080 #else
00081 
00082 #define initWinSock()
00083 
00084 #endif // _WINDOWS
00085 
00086 
00087 // These errors are not considered fatal for an IO operation; the operation will be re-tried.
00088 static inline bool
00089 nonFatalError()
00090 {
00091   int err = XmlRpcSocket::getError();
00092   return (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
00093 }
00094 
00095 
00096 
00097 int
00098 XmlRpcSocket::socket()
00099 {
00100   initWinSock();
00101   return (int) ::socket(AF_INET, SOCK_STREAM, 0);
00102 }
00103 
00104 
00105 void
00106 XmlRpcSocket::close(int fd)
00107 {
00108   XmlRpcUtil::log(4, "XmlRpcSocket::close: fd %d.", fd);
00109 #if defined(_WINDOWS)
00110   closesocket(fd);
00111 #else
00112   ::close(fd);
00113 #endif // _WINDOWS
00114 }
00115 
00116 
00117 
00118 
00119 bool
00120 XmlRpcSocket::setNonBlocking(int fd)
00121 {
00122 #if defined(_WINDOWS)
00123   unsigned long flag = 1;
00124   return (ioctlsocket((SOCKET)fd, FIONBIO, &flag) == 0);
00125 #else
00126   return (fcntl(fd, F_SETFL, O_NONBLOCK) == 0);
00127 #endif // _WINDOWS
00128 }
00129 
00130 
00131 bool
00132 XmlRpcSocket::setReuseAddr(int fd)
00133 {
00134   // Allow this port to be re-bound immediately so server re-starts are not delayed
00135   int sflag = 1;
00136   return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&sflag, sizeof(sflag)) == 0);
00137 }
00138 
00139 
00140 // Bind to a specified port
00141 bool
00142 XmlRpcSocket::bind(int fd, int port)
00143 {
00144   struct sockaddr_in saddr;
00145   memset(&saddr, 0, sizeof(saddr));
00146   saddr.sin_family = AF_INET;
00147   saddr.sin_addr.s_addr = htonl(INADDR_ANY);
00148   saddr.sin_port = htons((u_short) port);
00149   return (::bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0);
00150 }
00151 
00152 
00153 // Set socket in listen mode
00154 bool
00155 XmlRpcSocket::listen(int fd, int backlog)
00156 {
00157   return (::listen(fd, backlog) == 0);
00158 }
00159 
00160 
00161 int
00162 XmlRpcSocket::accept(int fd)
00163 {
00164   struct sockaddr_in addr;
00165 #if defined(_WINDOWS)
00166   int
00167 #else
00168   socklen_t
00169 #endif
00170     addrlen = sizeof(addr);
00171 
00172   return (int) ::accept(fd, (struct sockaddr*)&addr, &addrlen);
00173 }
00174 
00175 
00176 
00177 // Connect a socket to a server (from a client)
00178 bool
00179 XmlRpcSocket::connect(int fd, std::string& host, int port)
00180 {
00181   struct sockaddr_in saddr;
00182   memset(&saddr, 0, sizeof(saddr));
00183   saddr.sin_family = AF_INET;
00184 
00185   struct addrinfo* addr;
00186   if (getaddrinfo(host.c_str(), NULL, NULL, &addr) != 0)
00187   {
00188     return false;
00189   }
00190 
00191   bool found = false;
00192   struct addrinfo* it = addr;
00193   for (; it; it = it->ai_next)
00194   {
00195     if (it->ai_family == AF_INET)
00196     {
00197       memcpy(&saddr, it->ai_addr, it->ai_addrlen);
00198       saddr.sin_family = it->ai_family;
00199       saddr.sin_port = htons((u_short) port);
00200 
00201       found = true;
00202       break;
00203     }
00204   }
00205 
00206   if (!found)
00207   {
00208     printf("Couldn't find an AF_INET address for [%s]\n", host.c_str());
00209     freeaddrinfo(addr);
00210     return false;
00211   }
00212 
00213   // For asynch operation, this will return EWOULDBLOCK (windows) or
00214   // EINPROGRESS (linux) and we just need to wait for the socket to be writable...
00215   int result = ::connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
00216   if (result != 0 ) {
00217           int error = getError();
00218           if ( (error != EINPROGRESS) && error != EWOULDBLOCK) { // actually, should probably do a platform check here, EWOULDBLOCK on WIN32 and EINPROGRESS otherwise
00219                     printf("::connect error = %d\n", getError());
00220           }
00221   }
00222 
00223   freeaddrinfo(addr);
00224 
00225   return result == 0 || nonFatalError();
00226 }
00227 
00228 
00229 
00230 // Read available text from the specified socket. Returns false on error.
00231 bool
00232 XmlRpcSocket::nbRead(int fd, std::string& s, bool *eof)
00233 {
00234   const int READ_SIZE = 4096;   // Number of bytes to attempt to read at a time
00235   char readBuf[READ_SIZE];
00236 
00237   bool wouldBlock = false;
00238   *eof = false;
00239 
00240   while ( ! wouldBlock && ! *eof) {
00241 #if defined(_WINDOWS)
00242     int n = recv(fd, readBuf, READ_SIZE-1, 0);
00243 #else
00244     int n = read(fd, readBuf, READ_SIZE-1);
00245 #endif
00246     XmlRpcUtil::log(5, "XmlRpcSocket::nbRead: read/recv returned %d.", n);
00247 
00248     if (n > 0) {
00249       readBuf[n] = 0;
00250       s.append(readBuf, n);
00251     } else if (n == 0) {
00252       *eof = true;
00253     } else if (nonFatalError()) {
00254       wouldBlock = true;
00255     } else {
00256       return false;   // Error
00257     }
00258   }
00259   return true;
00260 }
00261 
00262 
00263 // Write text to the specified socket. Returns false on error.
00264 bool
00265 XmlRpcSocket::nbWrite(int fd, std::string& s, int *bytesSoFar)
00266 {
00267   int nToWrite = int(s.length()) - *bytesSoFar;
00268   char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar;
00269   bool wouldBlock = false;
00270 
00271   while ( nToWrite > 0 && ! wouldBlock ) {
00272 #if defined(_WINDOWS)
00273     int n = send(fd, sp, nToWrite, 0);
00274 #else
00275     int n = send(fd, sp, nToWrite, MSG_NOSIGNAL);
00276 #endif
00277     XmlRpcUtil::log(5, "XmlRpcSocket::nbWrite: send/write returned %d.", n);
00278 
00279     if (n > 0) {
00280       sp += n;
00281       *bytesSoFar += n;
00282       nToWrite -= n;
00283     } else if (nonFatalError()) {
00284       wouldBlock = true;
00285     } else {
00286       return false;   // Error
00287     }
00288   }
00289   return true;
00290 }
00291 
00292 
00293 // Returns last errno
00294 int
00295 XmlRpcSocket::getError()
00296 {
00297 #if defined(_WINDOWS)
00298   return WSAGetLastError();
00299 #else
00300   return errno;
00301 #endif
00302 }
00303 
00304 
00305 // Returns message corresponding to last errno
00306 std::string
00307 XmlRpcSocket::getErrorMsg()
00308 {
00309   return getErrorMsg(getError());
00310 }
00311 
00312 // Returns message corresponding to errno... well, it should anyway
00313 std::string
00314 XmlRpcSocket::getErrorMsg(int error)
00315 {
00316   char err[60];
00317 #ifdef _MSC_VER
00318   strerror_s(err,60,error);
00319 #else
00320   snprintf(err,sizeof(err),"%s",strerror(error));
00321 #endif
00322   return std::string(err);
00323 }
00324 
00325 int XmlRpcSocket::get_port(int socket)
00326 {
00327   sockaddr_in sin;
00328   socklen_t sin_len = sizeof(sin);
00329   getsockname(socket, (sockaddr *)&sin, &sin_len);
00330   return ntohs(sin.sin_port);
00331 }
00332 


xmlrpcpp
Author(s): Chris Morley and Konstantin Pilipchuk, slight modifications and ROS wrapping by Morgan Quigley
autogenerated on Sat Dec 28 2013 17:42:59