PageRenderTime 60ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/sources/utils/network/socket.cpp

https://bitbucket.org/dbacchet/dbsdev
C++ | 690 lines | 508 code | 134 blank | 48 comment | 98 complexity | 107e68f1fdb87b69501579e744074f70 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0, BSD-2-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. #include "basic_types.h"
  2. #if OS==OS_WINDOWS
  3. #define WINVER 0x0501 // set windows xp as minimum required system
  4. #define _WIN32_WINNT 0x0501 // set windows xp as minimum required system
  5. #include <winsock2.h>
  6. #include <ws2tcpip.h>
  7. #define snprintf _snprintf
  8. #else
  9. #include <arpa/inet.h>
  10. #include <sys/fcntl.h>
  11. #include <sys/types.h>
  12. #include <sys/socket.h>
  13. #include <sys/unistd.h>
  14. #include <sys/time.h>
  15. #include <netdb.h>
  16. #include <sys/ioctl.h>
  17. #include <errno.h>
  18. #endif
  19. #include <cstdio>
  20. #include "socket.h"
  21. // local functions
  22. namespace
  23. {
  24. #if OS==OS_WINDOWS
  25. static void close(int socketHandler)
  26. {
  27. closesocket(socketHandler);
  28. }
  29. // function provided here for compatibility with WindowsXP. On Vista and above this function is already present
  30. static const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
  31. {
  32. if (af == AF_INET)
  33. {
  34. struct sockaddr_in in;
  35. memset(&in, 0, sizeof(in));
  36. in.sin_family = AF_INET;
  37. memcpy(&in.sin_addr, src, sizeof(struct in_addr));
  38. getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
  39. return dst;
  40. }
  41. else if (af == AF_INET6)
  42. {
  43. struct sockaddr_in6 in;
  44. memset(&in, 0, sizeof(in));
  45. in.sin6_family = AF_INET6;
  46. memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
  47. getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
  48. return dst;
  49. }
  50. return NULL;
  51. }
  52. #endif
  53. static uint16_t get_in_port(struct sockaddr* sa)
  54. {
  55. if (sa->sa_family == AF_INET)
  56. return ntohs(((struct sockaddr_in*)sa)->sin_port);
  57. return ntohs(((struct sockaddr_in6*)sa)->sin6_port);
  58. }
  59. static uint16_t get_local_port(int socketHandler)
  60. {
  61. struct sockaddr_storage sin;
  62. #if OS==OS_WINDOWS
  63. int size;
  64. #else
  65. socklen_t size;
  66. #endif
  67. size = sizeof(sin);
  68. if(getsockname(socketHandler, (struct sockaddr*)&sin, &size) == 0)
  69. return get_in_port((struct sockaddr*)&sin);
  70. else
  71. return 0;
  72. }
  73. static bool check_read_error(void)
  74. {
  75. #if OS==OS_WINDOWS
  76. if(WSAGetLastError() != WSAEWOULDBLOCK)
  77. return true;
  78. #else
  79. if(errno != EAGAIN && errno != EWOULDBLOCK)
  80. return true;
  81. #endif
  82. return false;
  83. }
  84. static void *get_in_addr(struct sockaddr *sa)
  85. {
  86. if (sa->sa_family == AF_INET)
  87. return &(((struct sockaddr_in*)sa)->sin_addr);
  88. return &(((struct sockaddr_in6*)sa)->sin6_addr);
  89. }
  90. static int get_local_address(int socketHandler, char address[network::ADDR_STRLEN])
  91. {
  92. struct sockaddr_storage sin;
  93. #if OS==OS_WINDOWS
  94. int size;
  95. #else
  96. socklen_t size;
  97. #endif
  98. size = sizeof(sin);
  99. if(getsockname(socketHandler, (struct sockaddr*)&sin, &size) != 0)
  100. return -1;
  101. inet_ntop(sin.ss_family, get_in_addr((struct sockaddr *)&sin), address, network::ADDR_STRLEN);
  102. return 0;
  103. }
  104. } // empty namespace
  105. namespace network
  106. {
  107. /// Receives data and stores it in buffer until buffer_size reached.
  108. /// @param buffer A pointer to a buffer where received data will be stored
  109. /// @param buffer_size Size of the buffer (in bytes)
  110. /// @return Size of received data or (-1) if Socket is non-blocking and there's no data received.
  111. int tcp_read(Socket *sock, void* buffer, size_t buffer_size)
  112. {
  113. return recv(sock->_socket_handler, (char*)buffer, buffer_size, 0);
  114. }
  115. /// Sends the data contained in buffer. Requires the Socket to be a CLIENT socket.
  116. /// @pre Socket must be CLIENT
  117. /// @param buffer A pointer to the data we want to send
  118. /// @param size Length of the data to be sent (bytes)
  119. bool tcp_send(Socket *sock, const void* buffer, size_t size)
  120. {
  121. if(sock->_type != CLIENT)
  122. {
  123. printf("ERROR: tcp_send: Expected client socket (socket with host and port target)\n");
  124. return false;
  125. }
  126. if(sock->_protocol != TCP)
  127. {
  128. printf("ERROR: tcp_send: Expected TCP protocol\n");
  129. return false;
  130. }
  131. size_t sentData = 0;
  132. while (sentData < size)
  133. {
  134. int status = ::send(sock->_socket_handler, (const char*)buffer + sentData, size - sentData, 0);
  135. if(status==-1 )
  136. {
  137. printf("ERROR: Error sending data\n");
  138. return false;
  139. }
  140. sentData += status;
  141. }
  142. return true;
  143. }
  144. // same as tcp read: duplicated for naming consistency
  145. int udp_read(Socket *sock, void* buffer, size_t buffer_size)
  146. {
  147. return recv(sock->_socket_handler, (char*)buffer, buffer_size, 0);
  148. }
  149. /// Requires the socket to be UDP. Source host address and port are returned in hostFrom and
  150. /// portFrom parameters. Data recieved is written in buffer address up to buffer_size.
  151. /// @param buffer Pointer to a buffer where received data will be stored
  152. /// @param buffer_size Size of the buffer
  153. /// @param[out] hostFrom Here the function will store the address of the remote host
  154. /// @param[out] portFrom Here the function will store the remote port
  155. /// @return the length of the data recieved
  156. int udp_read_from(Socket *sock, void *buffer, size_t buffer_size, char remote_host[ADDR_STRLEN], uint16_t *remote_port)
  157. {
  158. if(sock->_protocol!=UDP)
  159. {
  160. printf("ERROR: udp_read_from: UDP socket required\n");
  161. return -1;
  162. }
  163. struct sockaddr_storage addr;
  164. socklen_t addrSize = sizeof(addr);
  165. int status = recvfrom(sock->_socket_handler, (char*)buffer, buffer_size, 0, (struct sockaddr *)&addr, &addrSize);
  166. if(status == -1)
  167. {
  168. if(remote_host)
  169. strcpy(remote_host,"");
  170. if(remote_port)
  171. *remote_port = 0;
  172. if (check_read_error())
  173. {
  174. printf("ERROR: udp_read_from\n");
  175. return -1;
  176. }
  177. }
  178. else
  179. {
  180. if(remote_port)
  181. *remote_port = get_in_port((struct sockaddr*)&addr);
  182. if(remote_host)
  183. inet_ntop(addr.ss_family, get_in_addr((struct sockaddr *)&addr), remote_host, ADDR_STRLEN);
  184. }
  185. return status;
  186. }
  187. /// Sends the data contained in buffer to a given host:port. Requires the socket to be an UDP socket]
  188. ///
  189. /// @param buffer A pointer to the data we want to send
  190. /// @param size Size of the data to send (bytes)
  191. /// @param hostTo Target/remote host
  192. /// @param portTo Target/remote port
  193. bool udp_send_to(Socket *sock, const void *buffer, size_t size, const char *remote_host, uint16_t remote_port)
  194. {
  195. if(sock->_protocol != UDP)
  196. {
  197. printf("ERROR: udp_send_to: UDP socket required\n");
  198. return false;
  199. }
  200. struct addrinfo conf, *res;
  201. memset(&conf, 0, sizeof(conf));
  202. conf.ai_socktype = SOCK_DGRAM;
  203. conf.ai_family = AF_INET;
  204. if (sock->_ip_ver==IP6)
  205. conf.ai_family = AF_INET6;
  206. char portStr[10];
  207. snprintf(portStr, 10, "%u", remote_port);
  208. int status = getaddrinfo(remote_host, portStr, &conf, &res);
  209. if(status != 0)
  210. {
  211. printf("ERROR: udp_send_to: error setting addrInfo\n");
  212. return false;
  213. }
  214. size_t sentBytes = 0;
  215. while(sentBytes < size)
  216. {
  217. int status = ::sendto(sock->_socket_handler, (const char*)buffer + sentBytes, size - sentBytes, 0, res->ai_addr, res->ai_addrlen);
  218. if(status == -1)
  219. {
  220. printf("ERROR: udp_send_to: could not send the data\n");
  221. return false;
  222. }
  223. sentBytes += status;
  224. }
  225. return true;
  226. }
  227. bool init_tcp_client_socket(Socket *sock)
  228. {
  229. struct addrinfo conf, *res = NULL;
  230. memset(&conf, 0, sizeof(conf));
  231. conf.ai_socktype = SOCK_STREAM;
  232. conf.ai_family = AF_UNSPEC;
  233. if (sock->_ip_ver==IP4)
  234. conf.ai_family = AF_INET;
  235. else if (sock->_ip_ver==IP6)
  236. conf.ai_family = AF_INET6;
  237. char portStr[10];
  238. snprintf(portStr, 10, "%u", sock->_remote_port);
  239. int status = getaddrinfo(sock->_remote_host, portStr, &conf, &res);
  240. if(status != 0)
  241. {
  242. printf("ERROR: init_tcp_client_socket: Error setting addrInfo\n");
  243. return false;
  244. }
  245. bool connected = false;
  246. while(!connected && res)
  247. {
  248. sock->_socket_handler = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  249. if(sock->_socket_handler != -1)
  250. {
  251. status = connect(sock->_socket_handler, res->ai_addr, res->ai_addrlen);
  252. if(status != -1)
  253. connected = true;
  254. else
  255. close(sock->_socket_handler);
  256. }
  257. if(connected && sock->_ip_ver == ANY)
  258. switch(res->ai_family)
  259. {
  260. case AF_INET:
  261. sock->_ip_ver = IP4;
  262. break;
  263. case AF_INET6:
  264. sock->_ip_ver = IP6;
  265. break;
  266. }
  267. res = res->ai_next;
  268. }
  269. if(!connected)
  270. {
  271. printf("ERROR: init_tcp_client_socket: error in socket connection/bind\n");
  272. return false;
  273. }
  274. if(!sock->_local_port)
  275. sock->_local_port = get_local_port(sock->_socket_handler);
  276. get_local_address(sock->_socket_handler, sock->_local_host);
  277. return true;
  278. }
  279. bool init_tcp_server_socket(Socket *sock)
  280. {
  281. struct addrinfo conf, *res = NULL;
  282. memset(&conf, 0, sizeof(conf));
  283. conf.ai_flags = AI_PASSIVE;
  284. conf.ai_socktype = SOCK_STREAM;
  285. conf.ai_family = AF_INET;
  286. if (sock->_ip_ver==IP6)
  287. conf.ai_family = AF_INET6;
  288. char portStr[10];
  289. snprintf(portStr, 10, "%u", sock->_local_port);
  290. const char* host = NULL;
  291. if (0!=strcmp(sock->_local_host,""))
  292. host = sock->_local_host;
  293. int status = getaddrinfo(host, portStr, &conf, &res);
  294. if(status != 0)
  295. {
  296. printf("ERROR: init_tcp_server_socket() unable to set addrinfo\n");
  297. return false;
  298. }
  299. bool connected = false;
  300. while(!connected && res)
  301. {
  302. sock->_socket_handler = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  303. if(sock->_socket_handler != -1)
  304. {
  305. int yes = 1;
  306. #if OS==OS_WINDOWS
  307. char *optval = (char*)&yes;
  308. #else
  309. void *optval = (void*)&yes;
  310. #endif
  311. if (setsockopt(sock->_socket_handler, SOL_SOCKET, SO_REUSEADDR, optval, sizeof(int)) == -1)
  312. {
  313. printf("ERROR: init_tcp_server_socket: Error establishing socket options\n");
  314. return false;
  315. }
  316. if (bind(sock->_socket_handler, res->ai_addr, res->ai_addrlen) == -1)
  317. close(sock->_socket_handler);
  318. else
  319. connected = true;
  320. if (listen(sock->_socket_handler, sock->_listen_queue_size) == -1)
  321. {
  322. printf("ERROR: init_tcp_server_socket: could not start listening\n");
  323. return false;
  324. }
  325. }
  326. res = res->ai_next;
  327. }
  328. if(!connected)
  329. {
  330. printf("ERROR: init_tcp_server_socket: error in socket connection/bind\n");
  331. return false;
  332. }
  333. return true;
  334. }
  335. bool init_udp_socket(Socket *sock)
  336. {
  337. struct addrinfo conf, *res = NULL;
  338. memset(&conf, 0, sizeof(conf));
  339. conf.ai_flags = AI_PASSIVE;
  340. conf.ai_socktype = SOCK_DGRAM;
  341. conf.ai_family = AF_UNSPEC;
  342. if (sock->_ip_ver==IP4) conf.ai_family = AF_INET;
  343. if (sock->_ip_ver==IP6) conf.ai_family = AF_INET6;
  344. char portStr[10];
  345. snprintf(portStr, 10, "%u", sock->_local_port);
  346. const char* host = NULL;
  347. if (0!=strcmp(sock->_local_host,""))
  348. host = sock->_local_host;
  349. int status = getaddrinfo(host, portStr, &conf, &res);
  350. if(status != 0)
  351. {
  352. printf("ERROR: init_udp_socket: Error setting addrInfo\n");
  353. return false;
  354. }
  355. bool connected = false;
  356. while(!connected && res)
  357. {
  358. sock->_socket_handler = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  359. if(sock->_socket_handler != -1)
  360. {
  361. if (bind(sock->_socket_handler, res->ai_addr, res->ai_addrlen) == -1)
  362. close(sock->_socket_handler);
  363. else
  364. connected = true;
  365. }
  366. if(connected && sock->_ip_ver == ANY)
  367. switch(res->ai_family)
  368. {
  369. case AF_INET:
  370. sock->_ip_ver = IP4;
  371. break;
  372. case AF_INET6:
  373. sock->_ip_ver = IP6;
  374. break;
  375. }
  376. res = res->ai_next;
  377. }
  378. if(!connected)
  379. {
  380. printf("ERROR: init_udp_socket: error in socket connection/bind\n");
  381. return false;
  382. }
  383. if(!sock->_local_port)
  384. sock->_local_port = get_local_port(sock->_socket_handler);
  385. get_local_address(sock->_socket_handler, sock->_local_host);
  386. return true;
  387. }
  388. /// Sets the Socket as blocking (if blocking is true) or as non-blocking (otherwise)
  389. /// @param blocking true to set the Socket as blocking; false to set the Socket as non-blocking
  390. void socket_set_blocking(Socket *sock, bool blocking)
  391. {
  392. sock->_blocking = blocking;
  393. int result = -1;
  394. #if OS==OS_WINDOWS
  395. u_long non_blocking = !blocking;
  396. result = ioctlsocket(sock->_socket_handler, FIONBIO, &non_blocking);
  397. if(result!=0)
  398. result = -1;
  399. #else
  400. int flags = fcntl(sock->_socket_handler, F_GETFL);
  401. if(blocking)
  402. result = fcntl(sock->_socket_handler, F_SETFL, flags & ~O_NONBLOCK);
  403. else
  404. result = fcntl(sock->_socket_handler, F_SETFL, flags | O_NONBLOCK);
  405. #endif
  406. }
  407. /// Creates a new CLIENT socket to handle the communication (send/recieve data) of
  408. /// this accepted connection. Requires the socket to be a SERVER TCP socket.
  409. /// @return A CLIENT socket that handles the new connection
  410. Socket* tcp_server_accept(Socket *server)
  411. {
  412. if(server->_protocol!=TCP || server->_type!=SERVER)
  413. {
  414. printf("ERROR: tcp_server_accept: required a TCP server socket\n");
  415. return NULL;
  416. }
  417. struct sockaddr_storage incoming_addr;
  418. #if OS==OS_WINDOWS
  419. int addrSize = sizeof(incoming_addr);
  420. #else
  421. socklen_t addrSize = sizeof(incoming_addr);
  422. #endif
  423. int new_handler = ::accept(server->_socket_handler, (struct sockaddr *)&incoming_addr, &addrSize);
  424. if(new_handler == -1)
  425. return NULL;
  426. Socket* acceptSocket = new Socket();
  427. acceptSocket->_socket_handler = new_handler;
  428. inet_ntop(incoming_addr.ss_family, get_in_addr((struct sockaddr *)&incoming_addr), acceptSocket->_remote_host, ADDR_STRLEN);
  429. acceptSocket->_remote_port = get_in_port((struct sockaddr *)&incoming_addr);
  430. acceptSocket->_local_port = get_local_port(acceptSocket->_socket_handler);
  431. get_local_address(acceptSocket->_socket_handler, acceptSocket->_local_host);
  432. acceptSocket->_protocol = server->_protocol;
  433. acceptSocket->_ip_ver = server->_ip_ver;
  434. acceptSocket->_type = CLIENT;
  435. acceptSocket->_listen_queue_size = 0;
  436. socket_set_blocking(acceptSocket,server->_blocking);
  437. return acceptSocket;
  438. }
  439. /// disconnect (close) the socket
  440. void socket_disconnect(Socket *sock)
  441. {
  442. if (sock && sock->_socket_handler!=-1)
  443. {
  444. close(sock->_socket_handler);
  445. sock->_socket_handler = -1;
  446. }
  447. }
  448. /// Creates a socket, connect it (if TCP) and sets it ready to send to hostTo:portTo.
  449. /// The local port of the socket is choosen by OS.
  450. /// @param hostTo the target/remote host
  451. /// @param portTo the target/remote port
  452. /// @param protocol the protocol to be used (TCP or UDP). TCP by default.
  453. /// @param ipVer the IP version to be used (IP4, IP6 or ANY). ANY by default.
  454. Socket* create_tcp_client(const char *remote_host, uint16_t remote_port, IPVer ipVer)
  455. {
  456. Socket *socket = new Socket();
  457. strcpy(socket->_remote_host,remote_host);
  458. socket->_remote_port = remote_port;
  459. socket->_local_port = 0;
  460. socket->_protocol = TCP;
  461. socket->_ip_ver = ipVer;
  462. socket->_type = CLIENT;
  463. socket->_blocking = true;
  464. socket->_listen_queue_size = 0;
  465. if (init_tcp_client_socket(socket))
  466. return socket;
  467. else
  468. {
  469. delete socket;
  470. return NULL;
  471. }
  472. }
  473. ///Creates a socket, binds it to portFrom port and listens for connections (if TCP).
  474. ///@param portFrom the local port the socket will be bound to
  475. ///@param protocol the protocol to be used (TCP or UDP). TCP by default.
  476. ///@param ipVer the IP version to be used (IP4, IP6 or ANY). IP4 by default.
  477. ///@param hostFrom the local address to be binded to (example: "localhost" or "127.0.0.1"). Empty (by default) means all available addresses.
  478. ///@param listen_queue_size the size of the internal buffer of the SERVER TCP socket where the connection requests are stored until accepted
  479. Socket* create_tcp_server(uint16_t local_port, const char *local_host, IPVer ipVer, uint16_t listen_queue_size)
  480. {
  481. Socket *socket = new Socket();
  482. strcpy(socket->_local_host,local_host);
  483. socket->_remote_port = 0;
  484. socket->_local_port = local_port;
  485. socket->_protocol = TCP;
  486. socket->_ip_ver = ipVer;
  487. socket->_type = SERVER;
  488. socket->_blocking = true;
  489. socket->_listen_queue_size = listen_queue_size;
  490. if (init_tcp_server_socket(socket))
  491. return socket;
  492. else
  493. {
  494. delete socket;
  495. return NULL;
  496. }
  497. }
  498. /// This client constructor for UDP Sockets allows to expecify the local port the socket
  499. /// will be bound to. It sets the socket ready to send data to hostTo:portTo.
  500. /// @param hostTo the target/remote host
  501. /// @param portTo the target/remote port
  502. /// @param portFrom the local port the socket will be bound to
  503. /// @param ipVer the IP version to be used (IP4, IP6 or ANY). ANY by default.
  504. Socket* create_udp_client(const char *remote_host, uint16_t remote_port, uint16_t local_port, IPVer ipVer)
  505. {
  506. Socket *socket = new Socket();
  507. strcpy(socket->_remote_host,remote_host);
  508. socket->_remote_port = remote_port;
  509. socket->_local_port = local_port;
  510. socket->_protocol = UDP;
  511. socket->_ip_ver = ipVer;
  512. socket->_type = CLIENT;
  513. socket->_blocking = true;
  514. socket->_listen_queue_size = 0;
  515. if (init_udp_socket(socket))
  516. return socket;
  517. else
  518. {
  519. delete socket;
  520. return NULL;
  521. }
  522. }
  523. void print_socket_data(Socket *sock)
  524. {
  525. printf("Socket data: \n"
  526. " _local_host = %s\n"
  527. " _local_port = %u\n"
  528. " _remote_host = %s\n"
  529. " _remote_port = %u\n"
  530. " _protocol = %d\n"
  531. " _ip_ver = %d\n"
  532. " _type = %d\n"
  533. " _blocking = %s\n"
  534. " _listen_queue_size = %u\n", sock->_local_host,
  535. sock->_local_port,
  536. sock->_remote_host,
  537. sock->_remote_port,
  538. sock->_protocol,
  539. sock->_ip_ver,
  540. sock->_type,
  541. sock->_blocking ? "true" : "false",
  542. sock->_listen_queue_size);
  543. }
  544. }
  545. namespace network_globals
  546. {
  547. bool init()
  548. {
  549. #if OS==OS_WINDOWS
  550. WSADATA wsaData;
  551. if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0)
  552. return false;
  553. #endif
  554. return true;
  555. }
  556. }