$search
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 00055 using namespace XmlRpc; 00056 00057 00058 00059 #if defined(_WINDOWS) 00060 00061 static void initWinSock() 00062 { 00063 static bool wsInit = false; 00064 if (! wsInit) 00065 { 00066 WORD wVersionRequested = MAKEWORD( 2, 0 ); 00067 WSADATA wsaData; 00068 WSAStartup(wVersionRequested, &wsaData); 00069 wsInit = true; 00070 } 00071 } 00072 00073 #else 00074 00075 #define initWinSock() 00076 00077 #endif // _WINDOWS 00078 00079 00080 // These errors are not considered fatal for an IO operation; the operation will be re-tried. 00081 static inline bool 00082 nonFatalError() 00083 { 00084 int err = XmlRpcSocket::getError(); 00085 return (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK || err == EINTR); 00086 } 00087 00088 00089 00090 int 00091 XmlRpcSocket::socket() 00092 { 00093 initWinSock(); 00094 return (int) ::socket(AF_INET, SOCK_STREAM, 0); 00095 } 00096 00097 00098 void 00099 XmlRpcSocket::close(int fd) 00100 { 00101 XmlRpcUtil::log(4, "XmlRpcSocket::close: fd %d.", fd); 00102 #if defined(_WINDOWS) 00103 closesocket(fd); 00104 #else 00105 ::close(fd); 00106 #endif // _WINDOWS 00107 } 00108 00109 00110 00111 00112 bool 00113 XmlRpcSocket::setNonBlocking(int fd) 00114 { 00115 #if defined(_WINDOWS) 00116 unsigned long flag = 1; 00117 return (ioctlsocket((SOCKET)fd, FIONBIO, &flag) == 0); 00118 #else 00119 return (fcntl(fd, F_SETFL, O_NONBLOCK) == 0); 00120 #endif // _WINDOWS 00121 } 00122 00123 00124 bool 00125 XmlRpcSocket::setReuseAddr(int fd) 00126 { 00127 // Allow this port to be re-bound immediately so server re-starts are not delayed 00128 int sflag = 1; 00129 return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&sflag, sizeof(sflag)) == 0); 00130 } 00131 00132 00133 // Bind to a specified port 00134 bool 00135 XmlRpcSocket::bind(int fd, int port) 00136 { 00137 struct sockaddr_in saddr; 00138 memset(&saddr, 0, sizeof(saddr)); 00139 saddr.sin_family = AF_INET; 00140 saddr.sin_addr.s_addr = htonl(INADDR_ANY); 00141 saddr.sin_port = htons((u_short) port); 00142 return (::bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0); 00143 } 00144 00145 00146 // Set socket in listen mode 00147 bool 00148 XmlRpcSocket::listen(int fd, int backlog) 00149 { 00150 return (::listen(fd, backlog) == 0); 00151 } 00152 00153 00154 int 00155 XmlRpcSocket::accept(int fd) 00156 { 00157 struct sockaddr_in addr; 00158 #if defined(_WINDOWS) 00159 int 00160 #else 00161 socklen_t 00162 #endif 00163 addrlen = sizeof(addr); 00164 00165 return (int) ::accept(fd, (struct sockaddr*)&addr, &addrlen); 00166 } 00167 00168 00169 00170 // Connect a socket to a server (from a client) 00171 bool 00172 XmlRpcSocket::connect(int fd, std::string& host, int port) 00173 { 00174 struct sockaddr_in saddr; 00175 memset(&saddr, 0, sizeof(saddr)); 00176 saddr.sin_family = AF_INET; 00177 00178 struct addrinfo* addr; 00179 if (getaddrinfo(host.c_str(), NULL, NULL, &addr) != 0) 00180 { 00181 return false; 00182 } 00183 00184 bool found = false; 00185 struct addrinfo* it = addr; 00186 for (; it; it = it->ai_next) 00187 { 00188 if (it->ai_family == AF_INET) 00189 { 00190 memcpy(&saddr, it->ai_addr, it->ai_addrlen); 00191 saddr.sin_family = it->ai_family; 00192 saddr.sin_port = htons((u_short) port); 00193 00194 found = true; 00195 break; 00196 } 00197 } 00198 00199 if (!found) 00200 { 00201 printf("Couldn't find an AF_INET address for [%s]\n", host.c_str()); 00202 freeaddrinfo(addr); 00203 return false; 00204 } 00205 00206 // For asynch operation, this will return EWOULDBLOCK (windows) or 00207 // EINPROGRESS (linux) and we just need to wait for the socket to be writable... 00208 int result = ::connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); 00209 if (result != 0 ) { 00210 int error = getError(); 00211 if ( (error != EINPROGRESS) && error != EWOULDBLOCK) { // actually, should probably do a platform check here, EWOULDBLOCK on WIN32 and EINPROGRESS otherwise 00212 printf("::connect error = %d\n", getError()); 00213 } 00214 } 00215 00216 freeaddrinfo(addr); 00217 00218 return result == 0 || nonFatalError(); 00219 } 00220 00221 00222 00223 // Read available text from the specified socket. Returns false on error. 00224 bool 00225 XmlRpcSocket::nbRead(int fd, std::string& s, bool *eof) 00226 { 00227 const int READ_SIZE = 4096; // Number of bytes to attempt to read at a time 00228 char readBuf[READ_SIZE]; 00229 00230 bool wouldBlock = false; 00231 *eof = false; 00232 00233 while ( ! wouldBlock && ! *eof) { 00234 #if defined(_WINDOWS) 00235 int n = recv(fd, readBuf, READ_SIZE-1, 0); 00236 #else 00237 int n = read(fd, readBuf, READ_SIZE-1); 00238 #endif 00239 XmlRpcUtil::log(5, "XmlRpcSocket::nbRead: read/recv returned %d.", n); 00240 00241 if (n > 0) { 00242 readBuf[n] = 0; 00243 s.append(readBuf, n); 00244 } else if (n == 0) { 00245 *eof = true; 00246 } else if (nonFatalError()) { 00247 wouldBlock = true; 00248 } else { 00249 return false; // Error 00250 } 00251 } 00252 return true; 00253 } 00254 00255 00256 // Write text to the specified socket. Returns false on error. 00257 bool 00258 XmlRpcSocket::nbWrite(int fd, std::string& s, int *bytesSoFar) 00259 { 00260 int nToWrite = int(s.length()) - *bytesSoFar; 00261 char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar; 00262 bool wouldBlock = false; 00263 00264 while ( nToWrite > 0 && ! wouldBlock ) { 00265 #if defined(_WINDOWS) 00266 int n = send(fd, sp, nToWrite, 0); 00267 #else 00268 int n = write(fd, sp, nToWrite); 00269 #endif 00270 XmlRpcUtil::log(5, "XmlRpcSocket::nbWrite: send/write returned %d.", n); 00271 00272 if (n > 0) { 00273 sp += n; 00274 *bytesSoFar += n; 00275 nToWrite -= n; 00276 } else if (nonFatalError()) { 00277 wouldBlock = true; 00278 } else { 00279 return false; // Error 00280 } 00281 } 00282 return true; 00283 } 00284 00285 00286 // Returns last errno 00287 int 00288 XmlRpcSocket::getError() 00289 { 00290 #if defined(_WINDOWS) 00291 return WSAGetLastError(); 00292 #else 00293 return errno; 00294 #endif 00295 } 00296 00297 00298 // Returns message corresponding to last errno 00299 std::string 00300 XmlRpcSocket::getErrorMsg() 00301 { 00302 return getErrorMsg(getError()); 00303 } 00304 00305 // Returns message corresponding to errno... well, it should anyway 00306 std::string 00307 XmlRpcSocket::getErrorMsg(int error) 00308 { 00309 char err[60]; 00310 #ifdef _MSC_VER 00311 strerror_s(err,60,error); 00312 #else 00313 snprintf(err,sizeof(err),"%s",strerror(error)); 00314 #endif 00315 return std::string(err); 00316 } 00317 00318 int XmlRpcSocket::get_port(int socket) 00319 { 00320 sockaddr_in sin; 00321 socklen_t sin_len = sizeof(sin); 00322 getsockname(socket, (sockaddr *)&sin, &sin_len); 00323 return ntohs(sin.sin_port); 00324 } 00325