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, const 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  int getaddr_err = getaddrinfo(host.c_str(), NULL, &hints, &addr);
211  if (0 != getaddr_err) {
212 #if !defined(_WINDOWS)
213  if(getaddr_err == EAI_SYSTEM) {
214  XmlRpcUtil::error("Couldn't find an %s address for [%s]: %s\n", s_use_ipv6_ ? "AF_INET6" : "AF_INET", host.c_str(), XmlRpcSocket::getErrorMsg().c_str());
215  } else {
216 #else
217  {
218 #endif
219  XmlRpcUtil::error("Couldn't find an %s address for [%s]: %s\n", s_use_ipv6_ ? "AF_INET6" : "AF_INET", host.c_str(), gai_strerror(getaddr_err));
220  }
221  return false;
222  }
223 
224  bool found = false;
225  struct addrinfo* it = addr;
226 
227  for (; it; it = it->ai_next)
228  {
229  if (!s_use_ipv6_ && it->ai_family == AF_INET)
230  {
231  sockaddr_in *address = (sockaddr_in *)&ss;
232  ss_len = sizeof(sockaddr_in);
233 
234  memcpy(address, it->ai_addr, it->ai_addrlen);
235  address->sin_family = it->ai_family;
236  address->sin_port = htons((u_short) port);
237 
238  XmlRpcUtil::log(5, "found host as %s\n", inet_ntoa(address->sin_addr));
239  found = true;
240  break;
241  }
242  if (s_use_ipv6_ && it->ai_family == AF_INET6)
243  {
244  sockaddr_in6 *address = (sockaddr_in6 *)&ss;
245  ss_len = sizeof(sockaddr_in6);
246 
247  memcpy(address, it->ai_addr, it->ai_addrlen);
248  address->sin6_family = it->ai_family;
249  address->sin6_port = htons((u_short) port);
250 
251  char buf[128];
252  // TODO IPV6: check if this also works under Windows
253  XmlRpcUtil::log(5, "found ipv6 host as %s\n", inet_ntop(AF_INET6, (void*)&(address->sin6_addr), buf, sizeof(buf)));
254  found = true;
255  break;
256  }
257 
258  }
259 
260  if (!found)
261  {
262  XmlRpcUtil::error("Couldn't find an %s address for [%s]\n", s_use_ipv6_ ? "AF_INET6" : "AF_INET", host.c_str());
263  freeaddrinfo(addr);
264  return false;
265  }
266 
267  // For asynch operation, this will return EWOULDBLOCK (windows) or
268  // EINPROGRESS (linux) and we just need to wait for the socket to be writable...
269  int result = ::connect(fd, (sockaddr*)&ss, ss_len);
270  bool success = true;
271  if (result != 0 ) {
272  int error = getError();
273  // platform check here, EWOULDBLOCK on WIN32 and EINPROGRESS otherwise
274 #if defined(_WINDOWS)
275  if (error != EWOULDBLOCK) {
276 #else
277  if (error != EINPROGRESS) {
278 #endif
279  XmlRpcUtil::error("::connect error = %s\n", getErrorMsg(error).c_str());
280  success = false;
281  }
282  }
283 
284  freeaddrinfo(addr);
285 
286  return success;
287 }
288 
289 
290 
291 // Read available text from the specified socket. Returns false on error.
292 bool
293 XmlRpcSocket::nbRead(int fd, std::string& s, bool *eof)
294 {
295  const int READ_SIZE = 4096; // Number of bytes to attempt to read at a time
296  char readBuf[READ_SIZE];
297 
298  bool wouldBlock = false;
299  *eof = false;
300 
301  while ( ! wouldBlock && ! *eof) {
302 #if defined(_WINDOWS)
303  int n = recv(fd, readBuf, READ_SIZE-1, 0);
304 #else
305  int n = read(fd, readBuf, READ_SIZE-1);
306 #endif
307  XmlRpcUtil::log(5, "XmlRpcSocket::nbRead: read/recv returned %d.", n);
308 
309  if (n > 0) {
310  readBuf[n] = 0;
311  s.append(readBuf, n);
312  } else if (n == 0) {
313  *eof = true;
314  } else if (nonFatalError()) {
315  wouldBlock = true;
316  } else {
317  return false; // Error
318  }
319  }
320  return true;
321 }
322 
323 
324 // Write text to the specified socket. Returns false on error.
325 bool
326 XmlRpcSocket::nbWrite(int fd, const std::string& s, int *bytesSoFar)
327 {
328  int nToWrite = int(s.length()) - *bytesSoFar;
329  char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar;
330  bool wouldBlock = false;
331 
332  while ( nToWrite > 0 && ! wouldBlock ) {
333 #if defined(_WINDOWS)
334  int n = send(fd, sp, nToWrite, 0);
335 #else
336  int n = write(fd, sp, nToWrite);
337 #endif
338  XmlRpcUtil::log(5, "XmlRpcSocket::nbWrite: send/write returned %d.", n);
339 
340  if (n > 0) {
341  sp += n;
342  *bytesSoFar += n;
343  nToWrite -= n;
344  } else if (nonFatalError()) {
345  wouldBlock = true;
346  } else {
347  return false; // Error
348  }
349  }
350  return true;
351 }
352 
353 
354 // Returns last errno
355 int
357 {
358 #if defined(_WINDOWS)
359  return WSAGetLastError();
360 #else
361  return errno;
362 #endif
363 }
364 
365 
366 // Returns message corresponding to last errno
367 std::string
369 {
370  return getErrorMsg(getError());
371 }
372 
373 // Returns message corresponding to errno... well, it should anyway
374 std::string
376 {
377  char err[60];
378  std::snprintf(err,sizeof(err),"%s",strerror(error));
379  return std::string(err);
380 }
381 
383 {
384  sockaddr_storage ss;
385  socklen_t ss_len = sizeof(ss);
386  if(getsockname(socket, (sockaddr *)&ss, &ss_len) == 0) {
387  sockaddr_in *sin = (sockaddr_in *)&ss;
388  sockaddr_in6 *sin6 = (sockaddr_in6 *)&ss;
389 
390  switch (ss.ss_family)
391  {
392  case AF_INET:
393  return ntohs(sin->sin_port);
394  case AF_INET6:
395  return ntohs(sin6->sin6_port);
396  }
397  }
398  return 0;
399 }
400 
#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 std::string getErrorMsg()
Returns message corresponding to last error.
static bool nbWrite(int socket, const std::string &s, int *bytesSoFar)
Write text to the specified socket. Returns false on error.
static bool bind(int socket, int port)
Bind to a specified port.
static int getError()
Returns last errno.
static bool connect(int socket, const std::string &host, int port)
Connect a socket to a server (from a client)
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 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
autogenerated on Mon Jun 1 2020 03:22:44