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