Home | History | Annotate | Download | only in src
      1 
      2 #include "XmlRpcSocket.h"
      3 #include "XmlRpcUtil.h"
      4 
      5 #ifndef MAKEDEPEND
      6 
      7 #if defined(_WINDOWS)
      8 # include <stdio.h>
      9 # include <winsock2.h>
     10 //# pragma lib(WS2_32.lib)
     11 
     12 # define EINPROGRESS	WSAEINPROGRESS
     13 # define EWOULDBLOCK	WSAEWOULDBLOCK
     14 # define ETIMEDOUT	    WSAETIMEDOUT
     15 #else
     16 extern "C" {
     17 # include <unistd.h>
     18 # include <stdio.h>
     19 # include <sys/types.h>
     20 # include <sys/socket.h>
     21 # include <netinet/in.h>
     22 # include <netdb.h>
     23 # include <errno.h>
     24 # include <fcntl.h>
     25 }
     26 #endif  // _WINDOWS
     27 
     28 #endif // MAKEDEPEND
     29 
     30 
     31 using namespace XmlRpc;
     32 
     33 
     34 
     35 #if defined(_WINDOWS)
     36 
     37 static void initWinSock()
     38 {
     39   static bool wsInit = false;
     40   if (! wsInit)
     41   {
     42     WORD wVersionRequested = MAKEWORD( 2, 0 );
     43     WSADATA wsaData;
     44     WSAStartup(wVersionRequested, &wsaData);
     45     wsInit = true;
     46   }
     47 }
     48 
     49 #else
     50 
     51 #define initWinSock()
     52 
     53 #endif // _WINDOWS
     54 
     55 
     56 // These errors are not considered fatal for an IO operation; the operation will be re-tried.
     57 static inline bool
     58 nonFatalError()
     59 {
     60   int err = XmlRpcSocket::getError();
     61   return (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
     62 }
     63 
     64 
     65 
     66 int
     67 XmlRpcSocket::socket()
     68 {
     69   initWinSock();
     70   return (int) ::socket(AF_INET, SOCK_STREAM, 0);
     71 }
     72 
     73 
     74 void
     75 XmlRpcSocket::close(int fd)
     76 {
     77   XmlRpcUtil::log(4, "XmlRpcSocket::close: fd %d.", fd);
     78 #if defined(_WINDOWS)
     79   closesocket(fd);
     80 #else
     81   ::close(fd);
     82 #endif // _WINDOWS
     83 }
     84 
     85 
     86 
     87 
     88 bool
     89 XmlRpcSocket::setNonBlocking(int fd)
     90 {
     91 #if defined(_WINDOWS)
     92   unsigned long flag = 1;
     93   return (ioctlsocket((SOCKET)fd, FIONBIO, &flag) == 0);
     94 #else
     95   return (fcntl(fd, F_SETFL, O_NONBLOCK) == 0);
     96 #endif // _WINDOWS
     97 }
     98 
     99 
    100 bool
    101 XmlRpcSocket::setReuseAddr(int fd)
    102 {
    103   // Allow this port to be re-bound immediately so server re-starts are not delayed
    104   int sflag = 1;
    105   return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&sflag, sizeof(sflag)) == 0);
    106 }
    107 
    108 
    109 // Bind to a specified port
    110 bool
    111 XmlRpcSocket::bind(int fd, int port)
    112 {
    113   struct sockaddr_in saddr;
    114   memset(&saddr, 0, sizeof(saddr));
    115   saddr.sin_family = AF_INET;
    116   saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    117   saddr.sin_port = htons((u_short) port);
    118   return (::bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0);
    119 }
    120 
    121 
    122 // Set socket in listen mode
    123 bool
    124 XmlRpcSocket::listen(int fd, int backlog)
    125 {
    126   return (::listen(fd, backlog) == 0);
    127 }
    128 
    129 
    130 int
    131 XmlRpcSocket::accept(int fd)
    132 {
    133   struct sockaddr_in addr;
    134 #if defined(_WINDOWS)
    135   int
    136 #else
    137   socklen_t
    138 #endif
    139     addrlen = sizeof(addr);
    140 
    141   return (int) ::accept(fd, (struct sockaddr*)&addr, &addrlen);
    142 }
    143 
    144 
    145 
    146 // Connect a socket to a server (from a client)
    147 bool
    148 XmlRpcSocket::connect(int fd, std::string& host, int port)
    149 {
    150   struct sockaddr_in saddr;
    151   memset(&saddr, 0, sizeof(saddr));
    152   saddr.sin_family = AF_INET;
    153 
    154   struct hostent *hp = gethostbyname(host.c_str());
    155   if (hp == 0) return false;
    156 
    157   saddr.sin_family = hp->h_addrtype;
    158   memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
    159   saddr.sin_port = htons((u_short) port);
    160 
    161   // For asynch operation, this will return EWOULDBLOCK (windows) or
    162   // EINPROGRESS (linux) and we just need to wait for the socket to be writable...
    163   int result = ::connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
    164   return result == 0 || nonFatalError();
    165 }
    166 
    167 
    168 
    169 // Read available text from the specified socket. Returns false on error.
    170 bool
    171 XmlRpcSocket::nbRead(int fd, std::string& s, bool *eof)
    172 {
    173   const int READ_SIZE = 4096;   // Number of bytes to attempt to read at a time
    174   char readBuf[READ_SIZE];
    175 
    176   bool wouldBlock = false;
    177   *eof = false;
    178 
    179   while ( ! wouldBlock && ! *eof) {
    180 #if defined(_WINDOWS)
    181     int n = recv(fd, readBuf, READ_SIZE-1, 0);
    182 #else
    183     int n = read(fd, readBuf, READ_SIZE-1);
    184 #endif
    185     XmlRpcUtil::log(5, "XmlRpcSocket::nbRead: read/recv returned %d.", n);
    186 
    187     if (n > 0) {
    188       readBuf[n] = 0;
    189       s.append(readBuf, n);
    190     } else if (n == 0) {
    191       *eof = true;
    192     } else if (nonFatalError()) {
    193       wouldBlock = true;
    194     } else {
    195       return false;   // Error
    196     }
    197   }
    198   return true;
    199 }
    200 
    201 
    202 // Write text to the specified socket. Returns false on error.
    203 bool
    204 XmlRpcSocket::nbWrite(int fd, std::string& s, int *bytesSoFar)
    205 {
    206   int nToWrite = int(s.length()) - *bytesSoFar;
    207   char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar;
    208   bool wouldBlock = false;
    209 
    210   while ( nToWrite > 0 && ! wouldBlock ) {
    211 #if defined(_WINDOWS)
    212     int n = send(fd, sp, nToWrite, 0);
    213 #else
    214     int n = write(fd, sp, nToWrite);
    215 #endif
    216     XmlRpcUtil::log(5, "XmlRpcSocket::nbWrite: send/write returned %d.", n);
    217 
    218     if (n > 0) {
    219       sp += n;
    220       *bytesSoFar += n;
    221       nToWrite -= n;
    222     } else if (nonFatalError()) {
    223       wouldBlock = true;
    224     } else {
    225       return false;   // Error
    226     }
    227   }
    228   return true;
    229 }
    230 
    231 
    232 // Returns last errno
    233 int
    234 XmlRpcSocket::getError()
    235 {
    236 #if defined(_WINDOWS)
    237   return WSAGetLastError();
    238 #else
    239   return errno;
    240 #endif
    241 }
    242 
    243 
    244 // Returns message corresponding to last errno
    245 std::string
    246 XmlRpcSocket::getErrorMsg()
    247 {
    248   return getErrorMsg(getError());
    249 }
    250 
    251 // Returns message corresponding to errno... well, it should anyway
    252 std::string
    253 XmlRpcSocket::getErrorMsg(int error)
    254 {
    255   char err[60];
    256   snprintf(err,sizeof(err),"error %d", error);
    257   return std::string(err);
    258 }
    259 
    260 
    261