PageRenderTime 97ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/utilities/xmlrpcpp/src/XmlRpcSocket.cpp

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