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  return true;
306 }
307 
308 
309 // Write text to the specified socket. Returns false on error.
310 bool
311 XmlRpcSocket::nbWrite(int fd, std::string& s, int *bytesSoFar)
312 {
313  int nToWrite = int(s.length()) - *bytesSoFar;
314  char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar;
315  bool wouldBlock = false;
316 
317  while ( nToWrite > 0 && ! wouldBlock ) {
318 #if defined(_WINDOWS)
319  int n = send(fd, sp, nToWrite, 0);
320 #else
321  int n = write(fd, sp, nToWrite);
322 #endif
323  XmlRpcUtil::log(5, "XmlRpcSocket::nbWrite: send/write returned %d.", n);
324 
325  if (n > 0) {
326  sp += n;
327  *bytesSoFar += n;
328  nToWrite -= n;
329  } else if (nonFatalError()) {
330  wouldBlock = true;
331  } else {
332  return false; // Error
333  }
334  }
335  return true;
336 }
337 
338 
339 // Returns last errno
340 int
342 {
343 #if defined(_WINDOWS)
344  return WSAGetLastError();
345 #else
346  return errno;
347 #endif
348 }
349 
350 
351 // Returns message corresponding to last errno
352 std::string
354 {
355  return getErrorMsg(getError());
356 }
357 
358 // Returns message corresponding to errno... well, it should anyway
359 std::string
361 {
362  char err[60];
363 #ifdef _MSC_VER
364  strerror_s(err,60,error);
365 #else
366  snprintf(err,sizeof(err),"%s",strerror(error));
367 #endif
368  return std::string(err);
369 }
370 
372 {
373  sockaddr_storage ss;
374  socklen_t ss_len = sizeof(ss);
375  getsockname(socket, (sockaddr *)&ss, &ss_len);
376 
377  sockaddr_in *sin = (sockaddr_in *)&ss;
378  sockaddr_in6 *sin6 = (sockaddr_in6 *)&ss;
379 
380  switch (ss.ss_family)
381  {
382  case AF_INET:
383  return ntohs(sin->sin_port);
384  case AF_INET6:
385  return ntohs(sin6->sin6_port);
386  }
387  return 0;
388 }
389 
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 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
autogenerated on Sat Oct 5 2019 03:58:22