socket.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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. return true;
  103. }
  104. UDPSocket::~UDPSocket()
  105. {
  106. if (socket_enable_debug_output) {
  107. dstream << "UDPSocket( " << (int)m_handle << ")::~UDPSocket()"
  108. << std::endl;
  109. }
  110. #ifdef _WIN32
  111. closesocket(m_handle);
  112. #else
  113. close(m_handle);
  114. #endif
  115. }
  116. void UDPSocket::Bind(Address addr)
  117. {
  118. if (socket_enable_debug_output) {
  119. dstream << "UDPSocket(" << (int)m_handle
  120. << ")::Bind(): " << addr.serializeString() << ":"
  121. << addr.getPort() << std::endl;
  122. }
  123. if (addr.getFamily() != m_addr_family) {
  124. static const char *errmsg =
  125. "Socket and bind address families do not match";
  126. errorstream << "Bind failed: " << errmsg << std::endl;
  127. throw SocketException(errmsg);
  128. }
  129. if (m_addr_family == AF_INET6) {
  130. struct sockaddr_in6 address;
  131. memset(&address, 0, sizeof(address));
  132. address = addr.getAddress6();
  133. address.sin6_family = AF_INET6;
  134. address.sin6_port = htons(addr.getPort());
  135. if (bind(m_handle, (const struct sockaddr *)&address,
  136. sizeof(struct sockaddr_in6)) < 0) {
  137. dstream << (int)m_handle << ": Bind failed: " << strerror(errno)
  138. << std::endl;
  139. throw SocketException("Failed to bind socket");
  140. }
  141. } else {
  142. struct sockaddr_in address;
  143. memset(&address, 0, sizeof(address));
  144. address = addr.getAddress();
  145. address.sin_family = AF_INET;
  146. address.sin_port = htons(addr.getPort());
  147. if (bind(m_handle, (const struct sockaddr *)&address,
  148. sizeof(struct sockaddr_in)) < 0) {
  149. dstream << (int)m_handle << ": Bind failed: " << strerror(errno)
  150. << std::endl;
  151. throw SocketException("Failed to bind socket");
  152. }
  153. }
  154. }
  155. void UDPSocket::Send(const Address &destination, const void *data, int size)
  156. {
  157. bool dumping_packet = false; // for INTERNET_SIMULATOR
  158. if (INTERNET_SIMULATOR)
  159. dumping_packet = myrand() % INTERNET_SIMULATOR_PACKET_LOSS == 0;
  160. if (socket_enable_debug_output) {
  161. // Print packet destination and size
  162. dstream << (int)m_handle << " -> ";
  163. destination.print(&dstream);
  164. dstream << ", size=" << size;
  165. // Print packet contents
  166. dstream << ", data=";
  167. for (int i = 0; i < size && i < 20; i++) {
  168. if (i % 2 == 0)
  169. dstream << " ";
  170. unsigned int a = ((const unsigned char *)data)[i];
  171. dstream << std::hex << std::setw(2) << std::setfill('0') << a;
  172. }
  173. if (size > 20)
  174. dstream << "...";
  175. if (dumping_packet)
  176. dstream << " (DUMPED BY INTERNET_SIMULATOR)";
  177. dstream << std::endl;
  178. }
  179. if (dumping_packet) {
  180. // Lol let's forget it
  181. dstream << "UDPSocket::Send(): INTERNET_SIMULATOR: dumping packet."
  182. << std::endl;
  183. return;
  184. }
  185. if (destination.getFamily() != m_addr_family)
  186. throw SendFailedException("Address family mismatch");
  187. int sent;
  188. if (m_addr_family == AF_INET6) {
  189. struct sockaddr_in6 address = destination.getAddress6();
  190. address.sin6_port = htons(destination.getPort());
  191. sent = sendto(m_handle, (const char *)data, size, 0,
  192. (struct sockaddr *)&address, sizeof(struct sockaddr_in6));
  193. } else {
  194. struct sockaddr_in address = destination.getAddress();
  195. address.sin_port = htons(destination.getPort());
  196. sent = sendto(m_handle, (const char *)data, size, 0,
  197. (struct sockaddr *)&address, sizeof(struct sockaddr_in));
  198. }
  199. if (sent != size)
  200. throw SendFailedException("Failed to send packet");
  201. }
  202. int UDPSocket::Receive(Address &sender, void *data, int size)
  203. {
  204. // Return on timeout
  205. if (!WaitData(m_timeout_ms))
  206. return -1;
  207. int received;
  208. if (m_addr_family == AF_INET6) {
  209. struct sockaddr_in6 address;
  210. memset(&address, 0, sizeof(address));
  211. socklen_t address_len = sizeof(address);
  212. received = recvfrom(m_handle, (char *)data, size, 0,
  213. (struct sockaddr *)&address, &address_len);
  214. if (received < 0)
  215. return -1;
  216. u16 address_port = ntohs(address.sin6_port);
  217. IPv6AddressBytes bytes;
  218. memcpy(bytes.bytes, address.sin6_addr.s6_addr, 16);
  219. sender = Address(&bytes, address_port);
  220. } else {
  221. struct sockaddr_in address;
  222. memset(&address, 0, sizeof(address));
  223. socklen_t address_len = sizeof(address);
  224. received = recvfrom(m_handle, (char *)data, size, 0,
  225. (struct sockaddr *)&address, &address_len);
  226. if (received < 0)
  227. return -1;
  228. u32 address_ip = ntohl(address.sin_addr.s_addr);
  229. u16 address_port = ntohs(address.sin_port);
  230. sender = Address(address_ip, address_port);
  231. }
  232. if (socket_enable_debug_output) {
  233. // Print packet sender and size
  234. dstream << (int)m_handle << " <- ";
  235. sender.print(&dstream);
  236. dstream << ", size=" << received;
  237. // Print packet contents
  238. dstream << ", data=";
  239. for (int i = 0; i < received && i < 20; i++) {
  240. if (i % 2 == 0)
  241. dstream << " ";
  242. unsigned int a = ((const unsigned char *)data)[i];
  243. dstream << std::hex << std::setw(2) << std::setfill('0') << a;
  244. }
  245. if (received > 20)
  246. dstream << "...";
  247. dstream << std::endl;
  248. }
  249. return received;
  250. }
  251. int UDPSocket::GetHandle()
  252. {
  253. return m_handle;
  254. }
  255. void UDPSocket::setTimeoutMs(int timeout_ms)
  256. {
  257. m_timeout_ms = timeout_ms;
  258. }
  259. bool UDPSocket::WaitData(int timeout_ms)
  260. {
  261. fd_set readset;
  262. int result;
  263. // Initialize the set
  264. FD_ZERO(&readset);
  265. FD_SET(m_handle, &readset);
  266. // Initialize time out struct
  267. struct timeval tv;
  268. tv.tv_sec = 0;
  269. tv.tv_usec = timeout_ms * 1000;
  270. // select()
  271. result = select(m_handle + 1, &readset, NULL, NULL, &tv);
  272. if (result == 0)
  273. return false;
  274. if (result < 0 && (errno == EINTR || errno == EBADF)) {
  275. // N.B. select() fails when sockets are destroyed on Connection's dtor
  276. // with EBADF. Instead of doing tricky synchronization, allow this
  277. // thread to exit but don't throw an exception.
  278. return false;
  279. }
  280. if (result < 0) {
  281. dstream << m_handle << ": Select failed: " << strerror(errno)
  282. << std::endl;
  283. #ifdef _WIN32
  284. int e = WSAGetLastError();
  285. dstream << (int)m_handle << ": WSAGetLastError()=" << e << std::endl;
  286. if (e == 10004 /* WSAEINTR */ || e == 10009 /* WSAEBADF */) {
  287. infostream << "Ignoring WSAEINTR/WSAEBADF." << std::endl;
  288. return false;
  289. }
  290. #endif
  291. throw SocketException("Select failed");
  292. } else if (!FD_ISSET(m_handle, &readset)) {
  293. // No data
  294. return false;
  295. }
  296. // There is data
  297. return true;
  298. }