socket.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "socket.h"
  17. #include <cstdio>
  18. #include <iostream>
  19. #include <cstdlib>
  20. #include <cstring>
  21. #include <iomanip>
  22. #include "util/string.h"
  23. #include "util/numeric.h"
  24. #include "constants.h"
  25. #include "debug.h"
  26. #include "log.h"
  27. #ifdef _WIN32
  28. // Without this some of the network functions are not found on mingw
  29. #ifndef _WIN32_WINNT
  30. #define _WIN32_WINNT 0x0501
  31. #endif
  32. #include <windows.h>
  33. #include <winsock2.h>
  34. #include <ws2tcpip.h>
  35. #define LAST_SOCKET_ERR() WSAGetLastError()
  36. #define SOCKET_ERR_STR(e) itos(e)
  37. typedef int socklen_t;
  38. #else
  39. #include <cerrno>
  40. #include <sys/types.h>
  41. #include <sys/socket.h>
  42. #include <netinet/in.h>
  43. #include <fcntl.h>
  44. #include <netdb.h>
  45. #include <unistd.h>
  46. #include <arpa/inet.h>
  47. #define LAST_SOCKET_ERR() (errno)
  48. #define SOCKET_ERR_STR(e) strerror(e)
  49. #endif
  50. // Set to true to enable verbose debug output
  51. bool socket_enable_debug_output = false; // yuck
  52. static bool g_sockets_initialized = false;
  53. // Initialize sockets
  54. void sockets_init()
  55. {
  56. #ifdef _WIN32
  57. // Windows needs sockets to be initialized before use
  58. WSADATA WsaData;
  59. if (WSAStartup(MAKEWORD(2, 2), &WsaData) != NO_ERROR)
  60. throw SocketException("WSAStartup failed");
  61. #endif
  62. g_sockets_initialized = true;
  63. }
  64. void sockets_cleanup()
  65. {
  66. #ifdef _WIN32
  67. // On Windows, cleanup sockets after use
  68. WSACleanup();
  69. #endif
  70. }
  71. /*
  72. UDPSocket
  73. */
  74. UDPSocket::UDPSocket(bool ipv6)
  75. {
  76. init(ipv6, false);
  77. }
  78. bool UDPSocket::init(bool ipv6, bool noExceptions)
  79. {
  80. if (!g_sockets_initialized) {
  81. tracestream << "Sockets not initialized" << std::endl;
  82. return false;
  83. }
  84. // Use IPv6 if specified
  85. m_addr_family = ipv6 ? AF_INET6 : AF_INET;
  86. m_handle = socket(m_addr_family, SOCK_DGRAM, IPPROTO_UDP);
  87. if (socket_enable_debug_output) {
  88. tracestream << "UDPSocket(" << (int)m_handle
  89. << ")::UDPSocket(): ipv6 = " << (ipv6 ? "true" : "false")
  90. << std::endl;
  91. }
  92. if (m_handle <= 0) {
  93. if (noExceptions) {
  94. return false;
  95. }
  96. throw SocketException(std::string("Failed to create socket: error ") +
  97. SOCKET_ERR_STR(LAST_SOCKET_ERR()));
  98. }
  99. setTimeoutMs(0);
  100. if (m_addr_family == AF_INET6) {
  101. // Allow our socket to accept both IPv4 and IPv6 connections
  102. // required on Windows:
  103. // https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx
  104. int value = 0;
  105. setsockopt(m_handle, IPPROTO_IPV6, IPV6_V6ONLY,
  106. reinterpret_cast<char *>(&value), sizeof(value));
  107. }
  108. return true;
  109. }
  110. UDPSocket::~UDPSocket()
  111. {
  112. if (socket_enable_debug_output) {
  113. tracestream << "UDPSocket( " << (int)m_handle << ")::~UDPSocket()"
  114. << std::endl;
  115. }
  116. #ifdef _WIN32
  117. closesocket(m_handle);
  118. #else
  119. close(m_handle);
  120. #endif
  121. }
  122. void UDPSocket::Bind(Address addr)
  123. {
  124. if (socket_enable_debug_output) {
  125. tracestream << "UDPSocket(" << (int)m_handle
  126. << ")::Bind(): " << addr.serializeString() << ":"
  127. << addr.getPort() << std::endl;
  128. }
  129. if (addr.getFamily() != m_addr_family) {
  130. const char *errmsg =
  131. "Socket and bind address families do not match";
  132. errorstream << "Bind failed: " << errmsg << std::endl;
  133. throw SocketException(errmsg);
  134. }
  135. int ret = 0;
  136. if (m_addr_family == AF_INET6) {
  137. struct sockaddr_in6 address;
  138. memset(&address, 0, sizeof(address));
  139. address.sin6_family = AF_INET6;
  140. address.sin6_addr = addr.getAddress6();
  141. address.sin6_port = htons(addr.getPort());
  142. ret = bind(m_handle, (const struct sockaddr *) &address,
  143. sizeof(struct sockaddr_in6));
  144. } else {
  145. struct sockaddr_in address;
  146. memset(&address, 0, sizeof(address));
  147. address.sin_family = AF_INET;
  148. address.sin_addr = addr.getAddress();
  149. address.sin_port = htons(addr.getPort());
  150. ret = bind(m_handle, (const struct sockaddr *) &address,
  151. sizeof(struct sockaddr_in));
  152. }
  153. if (ret < 0) {
  154. tracestream << (int)m_handle << ": Bind failed: "
  155. << SOCKET_ERR_STR(LAST_SOCKET_ERR()) << std::endl;
  156. throw SocketException("Failed to bind socket");
  157. }
  158. }
  159. void UDPSocket::Send(const Address &destination, const void *data, int size)
  160. {
  161. bool dumping_packet = false; // for INTERNET_SIMULATOR
  162. if (INTERNET_SIMULATOR)
  163. dumping_packet = myrand() % INTERNET_SIMULATOR_PACKET_LOSS == 0;
  164. if (socket_enable_debug_output) {
  165. // Print packet destination and size
  166. tracestream << (int)m_handle << " -> ";
  167. destination.print(tracestream);
  168. tracestream << ", size=" << size;
  169. // Print packet contents
  170. tracestream << ", data=";
  171. for (int i = 0; i < size && i < 20; i++) {
  172. if (i % 2 == 0)
  173. tracestream << " ";
  174. unsigned int a = ((const unsigned char *)data)[i];
  175. tracestream << std::hex << std::setw(2) << std::setfill('0') << a;
  176. }
  177. if (size > 20)
  178. tracestream << "...";
  179. if (dumping_packet)
  180. tracestream << " (DUMPED BY INTERNET_SIMULATOR)";
  181. tracestream << std::endl;
  182. }
  183. if (dumping_packet) {
  184. // Lol let's forget it
  185. tracestream << "UDPSocket::Send(): INTERNET_SIMULATOR: dumping packet."
  186. << std::endl;
  187. return;
  188. }
  189. if (destination.getFamily() != m_addr_family)
  190. throw SendFailedException("Address family mismatch");
  191. int sent;
  192. if (m_addr_family == AF_INET6) {
  193. struct sockaddr_in6 address = {};
  194. address.sin6_family = AF_INET6;
  195. address.sin6_addr = destination.getAddress6();
  196. address.sin6_port = htons(destination.getPort());
  197. sent = sendto(m_handle, (const char *)data, size, 0,
  198. (struct sockaddr *)&address, sizeof(struct sockaddr_in6));
  199. } else {
  200. struct sockaddr_in address = {};
  201. address.sin_family = AF_INET;
  202. address.sin_addr = destination.getAddress();
  203. address.sin_port = htons(destination.getPort());
  204. sent = sendto(m_handle, (const char *)data, size, 0,
  205. (struct sockaddr *)&address, sizeof(struct sockaddr_in));
  206. }
  207. if (sent != size)
  208. throw SendFailedException("Failed to send packet");
  209. }
  210. int UDPSocket::Receive(Address &sender, void *data, int size)
  211. {
  212. // Return on timeout
  213. if (!WaitData(m_timeout_ms))
  214. return -1;
  215. int received;
  216. if (m_addr_family == AF_INET6) {
  217. struct sockaddr_in6 address;
  218. memset(&address, 0, sizeof(address));
  219. socklen_t address_len = sizeof(address);
  220. received = recvfrom(m_handle, (char *)data, size, 0,
  221. (struct sockaddr *)&address, &address_len);
  222. if (received < 0)
  223. return -1;
  224. u16 address_port = ntohs(address.sin6_port);
  225. const auto *bytes = reinterpret_cast<IPv6AddressBytes*>
  226. (address.sin6_addr.s6_addr);
  227. sender = Address(bytes, address_port);
  228. } else {
  229. struct sockaddr_in address;
  230. memset(&address, 0, sizeof(address));
  231. socklen_t address_len = sizeof(address);
  232. received = recvfrom(m_handle, (char *)data, size, 0,
  233. (struct sockaddr *)&address, &address_len);
  234. if (received < 0)
  235. return -1;
  236. u32 address_ip = ntohl(address.sin_addr.s_addr);
  237. u16 address_port = ntohs(address.sin_port);
  238. sender = Address(address_ip, address_port);
  239. }
  240. if (socket_enable_debug_output) {
  241. // Print packet sender and size
  242. tracestream << (int)m_handle << " <- ";
  243. sender.print(tracestream);
  244. tracestream << ", size=" << received;
  245. // Print packet contents
  246. tracestream << ", data=";
  247. for (int i = 0; i < received && i < 20; i++) {
  248. if (i % 2 == 0)
  249. tracestream << " ";
  250. unsigned int a = ((const unsigned char *)data)[i];
  251. tracestream << std::hex << std::setw(2) << std::setfill('0') << a;
  252. }
  253. if (received > 20)
  254. tracestream << "...";
  255. tracestream << std::endl;
  256. }
  257. return received;
  258. }
  259. int UDPSocket::GetHandle()
  260. {
  261. return m_handle;
  262. }
  263. void UDPSocket::setTimeoutMs(int timeout_ms)
  264. {
  265. m_timeout_ms = timeout_ms;
  266. }
  267. bool UDPSocket::WaitData(int timeout_ms)
  268. {
  269. fd_set readset;
  270. int result;
  271. // Initialize the set
  272. FD_ZERO(&readset);
  273. FD_SET(m_handle, &readset);
  274. // Initialize time out struct
  275. struct timeval tv;
  276. tv.tv_sec = 0;
  277. tv.tv_usec = timeout_ms * 1000;
  278. // select()
  279. result = select(m_handle + 1, &readset, NULL, NULL, &tv);
  280. if (result == 0)
  281. return false;
  282. int e = LAST_SOCKET_ERR();
  283. #ifdef _WIN32
  284. if (result < 0 && (e == WSAEINTR || e == WSAEBADF)) {
  285. #else
  286. if (result < 0 && (e == EINTR || e == EBADF)) {
  287. #endif
  288. // N.B. select() fails when sockets are destroyed on Connection's dtor
  289. // with EBADF. Instead of doing tricky synchronization, allow this
  290. // thread to exit but don't throw an exception.
  291. return false;
  292. }
  293. if (result < 0) {
  294. tracestream << (int)m_handle << ": Select failed: " << SOCKET_ERR_STR(e)
  295. << std::endl;
  296. throw SocketException("Select failed");
  297. } else if (!FD_ISSET(m_handle, &readset)) {
  298. // No data
  299. return false;
  300. }
  301. // There is data
  302. return true;
  303. }