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