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