• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
initWinSock()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
nonFatalError()58 nonFatalError()
59 {
60   int err = XmlRpcSocket::getError();
61   return (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
62 }
63 
64 
65 
66 int
socket()67 XmlRpcSocket::socket()
68 {
69   initWinSock();
70   return (int) ::socket(AF_INET, SOCK_STREAM, 0);
71 }
72 
73 
74 void
close(int fd)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
setNonBlocking(int fd)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
setReuseAddr(int fd)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
bind(int fd,int port)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
listen(int fd,int backlog)124 XmlRpcSocket::listen(int fd, int backlog)
125 {
126   return (::listen(fd, backlog) == 0);
127 }
128 
129 
130 int
accept(int fd)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
connect(int fd,std::string & host,int port)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
nbRead(int fd,std::string & s,bool * eof)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
nbWrite(int fd,std::string & s,int * bytesSoFar)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
getError()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
getErrorMsg()246 XmlRpcSocket::getErrorMsg()
247 {
248   return getErrorMsg(getError());
249 }
250 
251 // Returns message corresponding to errno... well, it should anyway
252 std::string
getErrorMsg(int error)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