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


xmlrpcpp
Author(s): Chris Morley, Konstantin Pilipchuk, Morgan Quigley, Austin Hendrix, Dirk Thomas , Jacob Perron
autogenerated on Thu Nov 23 2023 04:01:41