XmlRpcSocket.cpp
Go to the documentation of this file.
1 // this file modified by Morgan Quigley on 22 Apr 2008.
2 // added features: server can be opened on port 0 and you can read back
3 // what port the OS gave you
4 
6 #include "xmlrpcpp/XmlRpcUtil.h"
7 
8 #ifndef MAKEDEPEND
9 
10 #if defined(_WINDOWS)
11 # include <stdio.h>
12 # include <winsock2.h>
13 # include <ws2tcpip.h>
14 //# pragma lib(WS2_32.lib)
15 
16 // MS VS10 actually has these definitions (as opposed to earlier versions),
17 // so if present, temporarily disable them and reset to WSA codes for this file only.
18 #ifdef EAGAIN
19  #undef EAGAIN
20 #endif
21 #ifdef EINTR
22  #undef EINTR
23 #endif
24 #ifdef EINPROGRESS
25  #undef EINPROGRESS
26 #endif
27 #ifdef EWOULDBLOCK
28  #undef EWOULDBLOCK
29 #endif
30 #ifdef ETIMEDOUT
31  #undef ETIMEDOUT
32 #endif
33 # define EAGAIN WSATRY_AGAIN
34 # define EINTR WSAEINTR
35 # define EINPROGRESS WSAEINPROGRESS
36 # define EWOULDBLOCK WSAEWOULDBLOCK
37 # define ETIMEDOUT WSAETIMEDOUT
38 #else
39 extern "C" {
40 # include <unistd.h>
41 # include <stdio.h>
42 # include <sys/types.h>
43 # include <sys/socket.h>
44 # include <netinet/in.h>
45 # include <netdb.h>
46 # include <errno.h>
47 # include <fcntl.h>
48 # include <string.h>
49 # include <stdlib.h>
50 # include <arpa/inet.h>
51 }
52 #endif // _WINDOWS
53 
54 #endif // MAKEDEPEND
55 
56 // MSG_NOSIGNAL does not exists on OS X
57 #if defined(__APPLE__) || defined(__MACH__)
58 # ifndef MSG_NOSIGNAL
59 # define MSG_NOSIGNAL SO_NOSIGPIPE
60 # endif
61 #endif
62 
63 
64 using namespace XmlRpc;
65 
66 
67 bool XmlRpcSocket::s_use_ipv6_ = false;
68 
69 #if defined(_WINDOWS)
70 
71 static void initWinSock()
72 {
73  static bool wsInit = false;
74  if (! wsInit)
75  {
76  WORD wVersionRequested = MAKEWORD( 2, 0 );
77  WSADATA wsaData;
78  WSAStartup(wVersionRequested, &wsaData);
79  wsInit = true;
80  }
81 }
82 
83 #else
84 
85 #define initWinSock()
86 
87 #endif // _WINDOWS
88 
89 
90 // These errors are not considered fatal for an IO operation; the operation will be re-tried.
91 static inline bool
93 {
94  int err = XmlRpcSocket::getError();
95  return (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
96 }
97 
98 int
100 {
101  initWinSock();
102  return (int) ::socket(s_use_ipv6_ ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
103 }
104 
105 
106 void
108 {
109  XmlRpcUtil::log(4, "XmlRpcSocket::close: fd %d.", fd);
110 #if defined(_WINDOWS)
111  closesocket(fd);
112 #else
113  ::close(fd);
114 #endif // _WINDOWS
115 }
116 
117 
118 
119 
120 bool
122 {
123 #if defined(_WINDOWS)
124  unsigned long flag = 1;
125  return (ioctlsocket((SOCKET)fd, FIONBIO, &flag) == 0);
126 #else
127  return (fcntl(fd, F_SETFL, O_NONBLOCK) == 0);
128 #endif // _WINDOWS
129 }
130 
131 
132 bool
134 {
135  // Allow this port to be re-bound immediately so server re-starts are not delayed
136  int sflag = 1;
137  return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&sflag, sizeof(sflag)) == 0);
138 }
139 
140 
141 // Bind to a specified port
142 bool
143 XmlRpcSocket::bind(int fd, int port)
144 {
145  sockaddr_storage ss;
146  socklen_t ss_len;
147  memset(&ss, 0, sizeof(ss));
148 
149  if (s_use_ipv6_)
150  {
151  sockaddr_in6 *address = (sockaddr_in6 *)&ss;
152  ss_len = sizeof(sockaddr_in6);
153 
154  address->sin6_family = AF_INET6;
155  address->sin6_addr = in6addr_any;
156  address->sin6_port = htons((u_short) port);
157  }
158  else
159  {
160  sockaddr_in *address = (sockaddr_in *)&ss;
161  ss_len = sizeof(sockaddr_in);
162 
163  address->sin_family = AF_INET;
164  address->sin_addr.s_addr = htonl(INADDR_ANY);
165  address->sin_port = htons((u_short) port);
166  }
167 
168  return (::bind(fd, (sockaddr*)&ss, ss_len) == 0);
169 }
170 
171 
172 // Set socket in listen mode
173 bool
174 XmlRpcSocket::listen(int fd, int backlog)
175 {
176  return (::listen(fd, backlog) == 0);
177 }
178 
179 
180 int
182 {
183  struct sockaddr_in addr;
184 #if defined(_WINDOWS)
185  int
186 #else
187  socklen_t
188 #endif
189  addrlen = sizeof(addr);
190  // accept will truncate the address if the buffer is too small.
191  // As we are not using it, no special case for IPv6
192  // has to be made.
193  return (int) ::accept(fd, (struct sockaddr*)&addr, &addrlen);
194 }
195 
196 
197 
198 // Connect a socket to a server (from a client)
199 bool
200 XmlRpcSocket::connect(int fd, std::string& host, int port)
201 {
202  sockaddr_storage ss;
203  socklen_t ss_len;
204  memset(&ss, 0, sizeof(ss));
205 
206  struct addrinfo* addr;
207  struct addrinfo hints;
208  memset(&hints, 0, sizeof(hints));
209  hints.ai_family = AF_UNSPEC;
210  if (getaddrinfo(host.c_str(), NULL, &hints, &addr) != 0)
211  {
212  fprintf(stderr, "Couldn't find an %s address for [%s]\n", s_use_ipv6_ ? "AF_INET6" : "AF_INET", host.c_str());
213  return false;
214  }
215 
216  bool found = false;
217  struct addrinfo* it = addr;
218 
219  for (; it; it = it->ai_next)
220  {
221  if (!s_use_ipv6_ && it->ai_family == AF_INET)
222  {
223  sockaddr_in *address = (sockaddr_in *)&ss;
224  ss_len = sizeof(sockaddr_in);
225 
226  memcpy(address, it->ai_addr, it->ai_addrlen);
227  address->sin_family = it->ai_family;
228  address->sin_port = htons((u_short) port);
229 
230  XmlRpcUtil::log(5, "found host as %s\n", inet_ntoa(address->sin_addr));
231  found = true;
232  break;
233  }
234  if (s_use_ipv6_ && it->ai_family == AF_INET6)
235  {
236  sockaddr_in6 *address = (sockaddr_in6 *)&ss;
237  ss_len = sizeof(sockaddr_in6);
238 
239  memcpy(address, it->ai_addr, it->ai_addrlen);
240  address->sin6_family = it->ai_family;
241  address->sin6_port = htons((u_short) port);
242 
243  char buf[128];
244  // TODO IPV6: check if this also works under Windows
245  XmlRpcUtil::log(5, "found ipv6 host as %s\n", inet_ntop(AF_INET6, (void*)&(address->sin6_addr), buf, sizeof(buf)));
246  found = true;
247  break;
248  }
249 
250  }
251 
252  if (!found)
253  {
254  printf("Couldn't find an %s address for [%s]\n", s_use_ipv6_ ? "AF_INET6" : "AF_INET", host.c_str());
255  freeaddrinfo(addr);
256  return false;
257  }
258 
259  // For asynch operation, this will return EWOULDBLOCK (windows) or
260  // EINPROGRESS (linux) and we just need to wait for the socket to be writable...
261  int result = ::connect(fd, (sockaddr*)&ss, ss_len);
262  if (result != 0 ) {
263  int error = getError();
264  if ( (error != EINPROGRESS) && error != EWOULDBLOCK) { // actually, should probably do a platform check here, EWOULDBLOCK on WIN32 and EINPROGRESS otherwise
265  printf("::connect error = %d\n", getError());
266  }
267  }
268 
269  freeaddrinfo(addr);
270 
271  return result == 0 || nonFatalError();
272 }
273 
274 
275 
276 // Read available text from the specified socket. Returns false on error.
277 bool
278 XmlRpcSocket::nbRead(int fd, std::string& s, bool *eof)
279 {
280  const int READ_SIZE = 4096; // Number of bytes to attempt to read at a time
281  char readBuf[READ_SIZE];
282 
283  bool wouldBlock = false;
284  *eof = false;
285 
286  while ( ! wouldBlock && ! *eof) {
287 #if defined(_WINDOWS)
288  int n = recv(fd, readBuf, READ_SIZE-1, 0);
289 #else
290  int n = read(fd, readBuf, READ_SIZE-1);
291 #endif
292  XmlRpcUtil::log(5, "XmlRpcSocket::nbRead: read/recv returned %d.", n);
293 
294  if (n > 0) {
295  readBuf[n] = 0;
296  s.append(readBuf, n);
297  } else if (n == 0) {
298  *eof = true;
299  } else if (nonFatalError()) {
300  wouldBlock = true;
301  } else {
302  return false; // Error
303  }
304  }
305  // Watch for integer overrun
306  if (s.length() > size_t(__INT_MAX__)) {
307  XmlRpcUtil::error("XmlRpcSocket::nbRead: text size (%u) exceeds the maximum allowed size (%s).",
308  s.length(), __INT_MAX__);
309  s.clear();
310  return false;
311  }
312  return true;
313 }
314 
315 
316 // Write text to the specified socket. Returns false on error.
317 bool
318 XmlRpcSocket::nbWrite(int fd, std::string& s, int *bytesSoFar)
319 {
320  // Watch for integer overrun
321  if (s.length() > size_t(__INT_MAX__)) {
322  XmlRpcUtil::error("XmlRpcSocket::nbWrite: text size (%u) exceeds the maximum allowed size(%s)",
323  s.length(), __INT_MAX__);
324  return false;
325  }
326  int nToWrite = int(s.length()) - *bytesSoFar;
327  char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar;
328  bool wouldBlock = false;
329 
330  while ( nToWrite > 0 && ! wouldBlock ) {
331 #if defined(_WINDOWS)
332  int n = send(fd, sp, nToWrite, 0);
333 #else
334  int n = write(fd, sp, nToWrite);
335 #endif
336  XmlRpcUtil::log(5, "XmlRpcSocket::nbWrite: send/write returned %d.", n);
337 
338  if (n > 0) {
339  sp += n;
340  *bytesSoFar += n;
341  nToWrite -= n;
342  } else if (nonFatalError()) {
343  wouldBlock = true;
344  } else {
345  return false; // Error
346  }
347  }
348  return true;
349 }
350 
351 
352 // Returns last errno
353 int
355 {
356 #if defined(_WINDOWS)
357  return WSAGetLastError();
358 #else
359  return errno;
360 #endif
361 }
362 
363 
364 // Returns message corresponding to last errno
365 std::string
367 {
368  return getErrorMsg(getError());
369 }
370 
371 // Returns message corresponding to errno... well, it should anyway
372 std::string
374 {
375  char err[60];
376 #ifdef _MSC_VER
377  strerror_s(err,60,error);
378 #else
379  snprintf(err,sizeof(err),"%s",strerror(error));
380 #endif
381  return std::string(err);
382 }
383 
385 {
386  sockaddr_storage ss;
387  socklen_t ss_len = sizeof(ss);
388  getsockname(socket, (sockaddr *)&ss, &ss_len);
389 
390  sockaddr_in *sin = (sockaddr_in *)&ss;
391  sockaddr_in6 *sin6 = (sockaddr_in6 *)&ss;
392 
393  switch (ss.ss_family)
394  {
395  case AF_INET:
396  return ntohs(sin->sin_port);
397  case AF_INET6:
398  return ntohs(sin6->sin6_port);
399  }
400  return 0;
401 }
402 
Definition: XmlRpc.h:39
#define initWinSock()
static bool setReuseAddr(int socket)
static int get_port(int socket)
static int accept(int socket)
Accept a client connection request.
XmlRpcServer s
Definition: HelloServer.cpp:11
static void error(const char *fmt,...)
Dump error messages somewhere.
Definition: XmlRpcUtil.cpp:95
static bool nbRead(int socket, std::string &s, bool *eof)
Read text from the specified socket. Returns false on error.
static bool connect(int socket, std::string &host, int port)
Connect a socket to a server (from a client)
static std::string getErrorMsg()
Returns message corresponding to last error.
static bool bind(int socket, int port)
Bind to a specified port.
static int getError()
Returns last errno.
static bool s_use_ipv6_
Definition: XmlRpcSocket.h:26
static bool listen(int socket, int backlog)
Set socket in listen mode.
static int socket()
Creates a stream (TCP) socket. Returns -1 on failure.
static void close(int socket)
Closes a socket.
static bool nbWrite(int socket, std::string &s, int *bytesSoFar)
Write text to the specified socket. Returns false on error.
static bool setNonBlocking(int socket)
Sets a stream (TCP) socket to perform non-blocking IO. Returns false on failure.
static bool nonFatalError()
static void log(int level, const char *fmt,...)
Dump messages somewhere.
Definition: XmlRpcUtil.cpp:80


xmlrpcpp
Author(s): Chris Morley, Konstantin Pilipchuk, Morgan Quigley, Austin Hendrix, Dirk Thomas
autogenerated on Mon Nov 2 2020 03:52:24