socket.cpp 9.0 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 <cerrno>
  22. #include <sstream>
  23. #include <iomanip>
  24. #include "util/string.h"
  25. #include "util/numeric.h"
  26. #include "constants.h"
  27. #include "debug.h"
  28. #include "settings.h"
  29. #include "log.h"
  30. #ifdef _WIN32
  31. // Without this some of the network functions are not found on mingw
  32. #ifndef _WIN32_WINNT
  33. #define _WIN32_WINNT 0x0501
  34. #endif
  35. #include <windows.h>
  36. #include <winsock2.h>
  37. #include <ws2tcpip.h>
  38. #define LAST_SOCKET_ERR() WSAGetLastError()
  39. typedef SOCKET socket_t;
  40. typedef int socklen_t;
  41. #else
  42. #include <sys/types.h>
  43. #include <sys/socket.h>
  44. #include <netinet/in.h>
  45. #include <fcntl.h>
  46. #include <netdb.h>
  47. #include <unistd.h>
  48. #include <arpa/inet.h>
  49. #define LAST_SOCKET_ERR() (errno)
  50. typedef int socket_t;
  51. #endif
  52. // Set to true to enable verbose debug output
  53. bool socket_enable_debug_output = false; // yuck
  54. static bool g_sockets_initialized = false;
  55. // Initialize sockets
  56. void sockets_init()
  57. {
  58. #ifdef _WIN32
  59. // Windows needs sockets to be initialized before use
  60. WSADATA WsaData;
  61. if (WSAStartup(MAKEWORD(2, 2), &WsaData) != NO_ERROR)
  62. throw SocketException("WSAStartup failed");
  63. #endif
  64. g_sockets_initialized = true;
  65. }
  66. void sockets_cleanup()
  67. {
  68. #ifdef _WIN32
  69. // On Windows, cleanup sockets after use
  70. WSACleanup();
  71. #endif
  72. }
  73. /*
  74. UDPSocket
  75. */
  76. UDPSocket::UDPSocket(bool ipv6)
  77. {
  78. init(ipv6, false);
  79. }
  80. bool UDPSocket::init(bool ipv6, bool noExceptions)
  81. {
  82. if (!g_sockets_initialized) {
  83. dstream << "Sockets not initialized" << std::endl;
  84. return false;
  85. }
  86. // Use IPv6 if specified
  87. m_addr_family = ipv6 ? AF_INET6 : AF_INET;
  88. m_handle = socket(m_addr_family, SOCK_DGRAM, IPPROTO_UDP);
  89. if (socket_enable_debug_output) {
  90. dstream << "UDPSocket(" << (int)m_handle
  91. << ")::UDPSocket(): ipv6 = " << (ipv6 ? "true" : "false")
  92. << std::endl;
  93. }
  94. if (m_handle <= 0) {
  95. if (noExceptions) {
  96. return false;
  97. }
  98. throw SocketException(std::string("Failed to create socket: error ") +
  99. itos(LAST_SOCKET_ERR()));
  100. }
  101. setTimeoutMs(0);
  102. if (m_addr_family == AF_INET6) {
  103. // Allow our socket to accept both IPv4 and IPv6 connections
  104. // required on Windows:
  105. // https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx
  106. int value = 0;
  107. setsockopt(m_handle, IPPROTO_IPV6, IPV6_V6ONLY,
  108. reinterpret_cast<char *>(&value), sizeof(value));
  109. }
  110. return true;
  111. }
  112. UDPSocket::~UDPSocket()
  113. {
  114. if (socket_enable_debug_output) {
  115. dstream << "UDPSocket( " << (int)m_handle << ")::~UDPSocket()"
  116. << std::endl;
  117. }
  118. #ifdef _WIN32
  119. closesocket(m_handle);
  120. #else
  121. close(m_handle);
  122. #endif
  123. }
  124. void UDPSocket::Bind(Address addr)
  125. {
  126. if (socket_enable_debug_output) {
  127. dstream << "UDPSocket(" << (int)m_handle
  128. << ")::Bind(): " << addr.serializeString() << ":"
  129. << addr.getPort() << std::endl;
  130. }
  131. if (addr.getFamily() != m_addr_family) {
  132. static const char *errmsg =
  133. "Socket and bind address families do not match";
  134. errorstream << "Bind failed: " << errmsg << std::endl;
  135. throw SocketException(errmsg);
  136. }
  137. if (m_addr_family == AF_INET6) {
  138. struct sockaddr_in6 address;
  139. memset(&address, 0, sizeof(address));
  140. address = addr.getAddress6();
  141. address.sin6_family = AF_INET6;
  142. address.sin6_port = htons(addr.getPort());
  143. if (bind(m_handle, (const struct sockaddr *)&address,
  144. sizeof(struct sockaddr_in6)) < 0) {
  145. dstream << (int)m_handle << ": Bind failed: " << strerror(errno)
  146. << std::endl;
  147. throw SocketException("Failed to bind socket");
  148. }
  149. } else {
  150. struct sockaddr_in address;
  151. memset(&address, 0, sizeof(address));
  152. address = addr.getAddress();
  153. address.sin_family = AF_INET;
  154. address.sin_port = htons(addr.getPort());
  155. if (bind(m_handle, (const struct sockaddr *)&address,
  156. sizeof(struct sockaddr_in)) < 0) {
  157. dstream << (int)m_handle << ": Bind failed: " << strerror(errno)
  158. << std::endl;
  159. throw SocketException("Failed to bind socket");
  160. }
  161. }
  162. }
  163. void UDPSocket::Send(const Address &destination, const void *data, int size)
  164. {
  165. bool dumping_packet = false; // for INTERNET_SIMULATOR
  166. if (INTERNET_SIMULATOR)
  167. dumping_packet = myrand() % INTERNET_SIMULATOR_PACKET_LOSS == 0;
  168. if (socket_enable_debug_output) {
  169. // Print packet destination and size
  170. dstream << (int)m_handle << " -> ";
  171. destination.print(&dstream);
  172. dstream << ", size=" << size;
  173. // Print packet contents
  174. dstream << ", data=";
  175. for (int i = 0; i < size && i < 20; i++) {
  176. if (i % 2 == 0)
  177. dstream << " ";
  178. unsigned int a = ((const unsigned char *)data)[i];
  179. dstream << std::hex << std::setw(2) << std::setfill('0') << a;
  180. }
  181. if (size > 20)
  182. dstream << "...";
  183. if (dumping_packet)
  184. dstream << " (DUMPED BY INTERNET_SIMULATOR)";
  185. dstream << std::endl;
  186. }
  187. if (dumping_packet) {
  188. // Lol let's forget it
  189. dstream << "UDPSocket::Send(): INTERNET_SIMULATOR: dumping packet."
  190. << std::endl;
  191. return;
  192. }
  193. if (destination.getFamily() != m_addr_family)
  194. throw SendFailedException("Address family mismatch");
  195. int sent;
  196. if (m_addr_family == AF_INET6) {
  197. struct sockaddr_in6 address = destination.getAddress6();
  198. address.sin6_port = htons(destination.getPort());
  199. sent = sendto(m_handle, (const char *)data, size, 0,
  200. (struct sockaddr *)&address, sizeof(struct sockaddr_in6));
  201. } else {
  202. struct sockaddr_in address = 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. IPv6AddressBytes bytes;
  226. memcpy(bytes.bytes, address.sin6_addr.s6_addr, 16);
  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. dstream << (int)m_handle << " <- ";
  243. sender.print(&dstream);
  244. dstream << ", size=" << received;
  245. // Print packet contents
  246. dstream << ", data=";
  247. for (int i = 0; i < received && i < 20; i++) {
  248. if (i % 2 == 0)
  249. dstream << " ";
  250. unsigned int a = ((const unsigned char *)data)[i];
  251. dstream << std::hex << std::setw(2) << std::setfill('0') << a;
  252. }
  253. if (received > 20)
  254. dstream << "...";
  255. dstream << 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. if (result < 0 && (errno == EINTR || errno == EBADF)) {
  283. // N.B. select() fails when sockets are destroyed on Connection's dtor
  284. // with EBADF. Instead of doing tricky synchronization, allow this
  285. // thread to exit but don't throw an exception.
  286. return false;
  287. }
  288. if (result < 0) {
  289. dstream << m_handle << ": Select failed: " << strerror(errno)
  290. << std::endl;
  291. #ifdef _WIN32
  292. int e = WSAGetLastError();
  293. dstream << (int)m_handle << ": WSAGetLastError()=" << e << std::endl;
  294. if (e == 10004 /* WSAEINTR */ || e == 10009 /* WSAEBADF */) {
  295. infostream << "Ignoring WSAEINTR/WSAEBADF." << std::endl;
  296. return false;
  297. }
  298. #endif
  299. throw SocketException("Select failed");
  300. } else if (!FD_ISSET(m_handle, &readset)) {
  301. // No data
  302. return false;
  303. }
  304. // There is data
  305. return true;
  306. }