Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 :
5 : This program is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU Lesser General Public License as published by
7 : the Free Software Foundation; either version 2.1 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU Lesser General Public License for more details.
14 :
15 : You should have received a copy of the GNU Lesser General Public License along
16 : with this program; if not, write to the Free Software Foundation, Inc.,
17 : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "socket.h"
21 :
22 : #include <stdio.h>
23 : #include <iostream>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <errno.h>
27 : #include <sstream>
28 : #include <iomanip>
29 : #include "util/string.h"
30 : #include "util/numeric.h"
31 : #include "constants.h"
32 : #include "debug.h"
33 : #include "settings.h"
34 : #include "log.h"
35 :
36 : #ifdef _WIN32
37 : #ifndef WIN32_LEAN_AND_MEAN
38 : #define WIN32_LEAN_AND_MEAN
39 : #endif
40 : // Without this some of the network functions are not found on mingw
41 : #ifndef _WIN32_WINNT
42 : #define _WIN32_WINNT 0x0501
43 : #endif
44 : #include <windows.h>
45 : #include <winsock2.h>
46 : #include <ws2tcpip.h>
47 : typedef SOCKET socket_t;
48 : typedef int socklen_t;
49 : #else
50 : #include <sys/types.h>
51 : #include <sys/socket.h>
52 : #include <netinet/in.h>
53 : #include <fcntl.h>
54 : #include <netdb.h>
55 : #include <unistd.h>
56 : #include <arpa/inet.h>
57 : typedef int socket_t;
58 : #endif
59 :
60 : // Set to true to enable verbose debug output
61 : bool socket_enable_debug_output = false; // yuck
62 :
63 : static bool g_sockets_initialized = false;
64 :
65 : // Initialize sockets
66 1 : void sockets_init()
67 : {
68 : #ifdef _WIN32
69 : // Windows needs sockets to be initialized before use
70 : WSADATA WsaData;
71 : if(WSAStartup( MAKEWORD(2,2), &WsaData ) != NO_ERROR)
72 : throw SocketException("WSAStartup failed");
73 : #endif
74 1 : g_sockets_initialized = true;
75 1 : }
76 :
77 1 : void sockets_cleanup()
78 : {
79 : #ifdef _WIN32
80 : // On Windows, cleanup sockets after use
81 : WSACleanup();
82 : #endif
83 1 : }
84 :
85 : /*
86 : Address
87 : */
88 :
89 35998 : Address::Address()
90 : {
91 35998 : m_addr_family = 0;
92 35998 : memset(&m_address, 0, sizeof(m_address));
93 35998 : m_port = 0;
94 35998 : }
95 :
96 4795 : Address::Address(u32 address, u16 port)
97 : {
98 4795 : memset(&m_address, 0, sizeof(m_address));
99 4795 : setAddress(address);
100 4795 : setPort(port);
101 4795 : }
102 :
103 1 : Address::Address(u8 a, u8 b, u8 c, u8 d, u16 port)
104 : {
105 1 : memset(&m_address, 0, sizeof(m_address));
106 1 : setAddress(a, b, c, d);
107 1 : setPort(port);
108 1 : }
109 :
110 0 : Address::Address(const IPv6AddressBytes *ipv6_bytes, u16 port)
111 : {
112 0 : memset(&m_address, 0, sizeof(m_address));
113 0 : setAddress(ipv6_bytes);
114 0 : setPort(port);
115 0 : }
116 :
117 : // Equality (address family, address and port must be equal)
118 4795 : bool Address::operator==(const Address &address)
119 : {
120 4795 : if(address.m_addr_family != m_addr_family || address.m_port != m_port)
121 0 : return false;
122 4795 : else if(m_addr_family == AF_INET)
123 : {
124 4795 : return m_address.ipv4.sin_addr.s_addr ==
125 4795 : address.m_address.ipv4.sin_addr.s_addr;
126 : }
127 0 : else if(m_addr_family == AF_INET6)
128 : {
129 0 : return memcmp(m_address.ipv6.sin6_addr.s6_addr,
130 0 : address.m_address.ipv6.sin6_addr.s6_addr, 16) == 0;
131 : }
132 : else
133 0 : return false;
134 : }
135 :
136 4795 : bool Address::operator!=(const Address &address)
137 : {
138 4795 : return !(*this == address);
139 : }
140 :
141 1 : void Address::Resolve(const char *name)
142 : {
143 1 : if (!name || name[0] == 0) {
144 0 : if (m_addr_family == AF_INET) {
145 0 : setAddress((u32) 0);
146 0 : } else if (m_addr_family == AF_INET6) {
147 0 : setAddress((IPv6AddressBytes*) 0);
148 : }
149 0 : return;
150 : }
151 :
152 : struct addrinfo *resolved, hints;
153 1 : memset(&hints, 0, sizeof(hints));
154 :
155 : // Setup hints
156 1 : hints.ai_socktype = 0;
157 1 : hints.ai_protocol = 0;
158 1 : hints.ai_flags = 0;
159 1 : if(g_settings->getBool("enable_ipv6"))
160 : {
161 : // AF_UNSPEC allows both IPv6 and IPv4 addresses to be returned
162 1 : hints.ai_family = AF_UNSPEC;
163 : }
164 : else
165 : {
166 0 : hints.ai_family = AF_INET;
167 : }
168 :
169 : // Do getaddrinfo()
170 1 : int e = getaddrinfo(name, NULL, &hints, &resolved);
171 1 : if(e != 0)
172 0 : throw ResolveError(gai_strerror(e));
173 :
174 : // Copy data
175 1 : if(resolved->ai_family == AF_INET)
176 : {
177 1 : struct sockaddr_in *t = (struct sockaddr_in *) resolved->ai_addr;
178 1 : m_addr_family = AF_INET;
179 1 : m_address.ipv4 = *t;
180 : }
181 0 : else if(resolved->ai_family == AF_INET6)
182 : {
183 0 : struct sockaddr_in6 *t = (struct sockaddr_in6 *) resolved->ai_addr;
184 0 : m_addr_family = AF_INET6;
185 0 : m_address.ipv6 = *t;
186 : }
187 : else
188 : {
189 0 : freeaddrinfo(resolved);
190 0 : throw ResolveError("");
191 : }
192 1 : freeaddrinfo(resolved);
193 : }
194 :
195 : // IP address -> textual representation
196 2 : std::string Address::serializeString() const
197 : {
198 : // windows XP doesnt have inet_ntop, maybe use better func
199 : #ifdef _WIN32
200 : if(m_addr_family == AF_INET)
201 : {
202 : u8 a, b, c, d;
203 : u32 addr;
204 : addr = ntohl(m_address.ipv4.sin_addr.s_addr);
205 : a = (addr & 0xFF000000) >> 24;
206 : b = (addr & 0x00FF0000) >> 16;
207 : c = (addr & 0x0000FF00) >> 8;
208 : d = (addr & 0x000000FF);
209 : return itos(a) + "." + itos(b) + "." + itos(c) + "." + itos(d);
210 : }
211 : else if(m_addr_family == AF_INET6)
212 : {
213 : std::ostringstream os;
214 : for(int i = 0; i < 16; i += 2)
215 : {
216 : u16 section =
217 : (m_address.ipv6.sin6_addr.s6_addr[i] << 8) |
218 : (m_address.ipv6.sin6_addr.s6_addr[i + 1]);
219 : os << std::hex << section;
220 : if(i < 14)
221 : os << ":";
222 : }
223 : return os.str();
224 : }
225 : else
226 : return std::string("");
227 : #else
228 : char str[INET6_ADDRSTRLEN];
229 2 : if (inet_ntop(m_addr_family, (m_addr_family == AF_INET) ? (void*)&(m_address.ipv4.sin_addr) : (void*)&(m_address.ipv6.sin6_addr), str, INET6_ADDRSTRLEN) == NULL) {
230 0 : return std::string("");
231 : }
232 2 : return std::string(str);
233 : #endif
234 : }
235 :
236 4612 : struct sockaddr_in Address::getAddress() const
237 : {
238 4612 : return m_address.ipv4; // NOTE: NO PORT INCLUDED, use getPort()
239 : }
240 :
241 0 : struct sockaddr_in6 Address::getAddress6() const
242 : {
243 0 : return m_address.ipv6; // NOTE: NO PORT INCLUDED, use getPort()
244 : }
245 :
246 4613 : u16 Address::getPort() const
247 : {
248 4613 : return m_port;
249 : }
250 :
251 4612 : int Address::getFamily() const
252 : {
253 4612 : return m_addr_family;
254 : }
255 :
256 3 : bool Address::isIPv6() const
257 : {
258 3 : return m_addr_family == AF_INET6;
259 : }
260 :
261 1 : bool Address::isZero() const
262 : {
263 1 : if (m_addr_family == AF_INET) {
264 1 : return m_address.ipv4.sin_addr.s_addr == 0;
265 0 : } else if (m_addr_family == AF_INET6) {
266 : static const char zero[16] = {0};
267 0 : return memcmp(m_address.ipv6.sin6_addr.s6_addr,
268 0 : zero, 16) == 0;
269 : }
270 0 : return false;
271 : }
272 :
273 4795 : void Address::setAddress(u32 address)
274 : {
275 4795 : m_addr_family = AF_INET;
276 4795 : m_address.ipv4.sin_family = AF_INET;
277 4795 : m_address.ipv4.sin_addr.s_addr = htonl(address);
278 4795 : }
279 :
280 2 : void Address::setAddress(u8 a, u8 b, u8 c, u8 d)
281 : {
282 2 : m_addr_family = AF_INET;
283 2 : m_address.ipv4.sin_family = AF_INET;
284 2 : u32 addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
285 2 : m_address.ipv4.sin_addr.s_addr = addr;
286 2 : }
287 :
288 0 : void Address::setAddress(const IPv6AddressBytes *ipv6_bytes)
289 : {
290 0 : m_addr_family = AF_INET6;
291 0 : m_address.ipv6.sin6_family = AF_INET6;
292 0 : if (ipv6_bytes)
293 0 : memcpy(m_address.ipv6.sin6_addr.s6_addr, ipv6_bytes->bytes, 16);
294 : else
295 0 : memset(m_address.ipv6.sin6_addr.s6_addr, 0, 16);
296 0 : }
297 :
298 4796 : void Address::setPort(u16 port)
299 : {
300 4796 : m_port = port;
301 4796 : }
302 :
303 1 : void Address::print(std::ostream *s) const
304 : {
305 1 : if(m_addr_family == AF_INET6)
306 0 : *s << "[" << serializeString() << "]:" << m_port;
307 : else
308 1 : *s << serializeString() << ":" << m_port;
309 1 : }
310 :
311 : /*
312 : UDPSocket
313 : */
314 :
315 1 : UDPSocket::UDPSocket(bool ipv6)
316 : {
317 1 : init(ipv6, false);
318 1 : }
319 :
320 1 : bool UDPSocket::init(bool ipv6, bool noExceptions)
321 : {
322 1 : if (g_sockets_initialized == false) {
323 0 : dstream << "Sockets not initialized" << std::endl;
324 0 : return false;
325 : }
326 :
327 : // Use IPv6 if specified
328 1 : m_addr_family = ipv6 ? AF_INET6 : AF_INET;
329 1 : m_handle = socket(m_addr_family, SOCK_DGRAM, IPPROTO_UDP);
330 :
331 1 : if (socket_enable_debug_output) {
332 0 : dstream << "UDPSocket(" << (int) m_handle
333 0 : << ")::UDPSocket(): ipv6 = "
334 0 : << (ipv6 ? "true" : "false")
335 0 : << std::endl;
336 : }
337 :
338 1 : if (m_handle <= 0) {
339 0 : if (noExceptions) {
340 0 : return false;
341 : } else {
342 0 : throw SocketException("Failed to create socket");
343 : }
344 : }
345 :
346 1 : setTimeoutMs(0);
347 :
348 1 : return true;
349 : }
350 :
351 :
352 2 : UDPSocket::~UDPSocket()
353 : {
354 1 : if (socket_enable_debug_output) {
355 0 : dstream << "UDPSocket( " << (int) m_handle << ")::~UDPSocket()"
356 0 : << std::endl;
357 : }
358 :
359 : #ifdef _WIN32
360 : closesocket(m_handle);
361 : #else
362 1 : close(m_handle);
363 : #endif
364 1 : }
365 :
366 1 : void UDPSocket::Bind(Address addr)
367 : {
368 1 : if(socket_enable_debug_output) {
369 0 : dstream << "UDPSocket(" << (int) m_handle << ")::Bind(): "
370 0 : << addr.serializeString() << ":"
371 0 : << addr.getPort() << std::endl;
372 : }
373 :
374 1 : if (addr.getFamily() != m_addr_family) {
375 : static const char *errmsg = "Socket and bind address families do not match";
376 0 : errorstream << "Bind failed: " << errmsg << std::endl;
377 0 : throw SocketException(errmsg);
378 : }
379 :
380 1 : if(m_addr_family == AF_INET6) {
381 : struct sockaddr_in6 address;
382 0 : memset(&address, 0, sizeof(address));
383 :
384 0 : address = addr.getAddress6();
385 0 : address.sin6_family = AF_INET6;
386 0 : address.sin6_port = htons(addr.getPort());
387 :
388 0 : if(bind(m_handle, (const struct sockaddr *) &address,
389 : sizeof(struct sockaddr_in6)) < 0) {
390 0 : dstream << (int) m_handle << ": Bind failed: "
391 0 : << strerror(errno) << std::endl;
392 0 : throw SocketException("Failed to bind socket");
393 : }
394 : } else {
395 : struct sockaddr_in address;
396 1 : memset(&address, 0, sizeof(address));
397 :
398 1 : address = addr.getAddress();
399 1 : address.sin_family = AF_INET;
400 1 : address.sin_port = htons(addr.getPort());
401 :
402 1 : if (bind(m_handle, (const struct sockaddr *) &address,
403 : sizeof(struct sockaddr_in)) < 0) {
404 0 : dstream << (int)m_handle << ": Bind failed: "
405 0 : << strerror(errno) << std::endl;
406 0 : throw SocketException("Failed to bind socket");
407 : }
408 : }
409 1 : }
410 :
411 4611 : void UDPSocket::Send(const Address & destination, const void * data, int size)
412 : {
413 4611 : bool dumping_packet = false; // for INTERNET_SIMULATOR
414 :
415 : if(INTERNET_SIMULATOR)
416 : dumping_packet = myrand() % INTERNET_SIMULATOR_PACKET_LOSS == 0;
417 :
418 4611 : if(socket_enable_debug_output) {
419 : // Print packet destination and size
420 0 : dstream << (int)m_handle << " -> ";
421 0 : destination.print(&dstream);
422 0 : dstream << ", size=" << size;
423 :
424 : // Print packet contents
425 0 : dstream << ", data=";
426 0 : for(int i = 0; i < size && i < 20; i++) {
427 0 : if(i % 2 == 0)
428 0 : dstream << " ";
429 0 : unsigned int a = ((const unsigned char *)data)[i];
430 0 : dstream << std::hex << std::setw(2) << std::setfill('0') << a;
431 : }
432 :
433 0 : if(size > 20)
434 0 : dstream << "...";
435 :
436 0 : if(dumping_packet)
437 0 : dstream << " (DUMPED BY INTERNET_SIMULATOR)";
438 :
439 0 : dstream << std::endl;
440 : }
441 :
442 4611 : if(dumping_packet) {
443 : // Lol let's forget it
444 0 : dstream << "UDPSocket::Send(): INTERNET_SIMULATOR: dumping packet."
445 0 : << std::endl;
446 0 : return;
447 : }
448 :
449 4611 : if(destination.getFamily() != m_addr_family)
450 0 : throw SendFailedException("Address family mismatch");
451 :
452 : int sent;
453 4611 : if(m_addr_family == AF_INET6) {
454 0 : struct sockaddr_in6 address = destination.getAddress6();
455 0 : address.sin6_port = htons(destination.getPort());
456 0 : sent = sendto(m_handle, (const char *)data, size,
457 0 : 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in6));
458 : } else {
459 4611 : struct sockaddr_in address = destination.getAddress();
460 4611 : address.sin_port = htons(destination.getPort());
461 4611 : sent = sendto(m_handle, (const char *)data, size,
462 4611 : 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in));
463 : }
464 :
465 4611 : if(sent != size)
466 0 : throw SendFailedException("Failed to send packet");
467 : }
468 :
469 4795 : int UDPSocket::Receive(Address & sender, void *data, int size)
470 : {
471 : // Return on timeout
472 4795 : if(WaitData(m_timeout_ms) == false)
473 0 : return -1;
474 :
475 : int received;
476 4795 : if (m_addr_family == AF_INET6) {
477 : struct sockaddr_in6 address;
478 0 : memset(&address, 0, sizeof(address));
479 0 : socklen_t address_len = sizeof(address);
480 :
481 0 : received = recvfrom(m_handle, (char *) data,
482 0 : size, 0, (struct sockaddr *) &address, &address_len);
483 :
484 0 : if(received < 0)
485 0 : return -1;
486 :
487 0 : u16 address_port = ntohs(address.sin6_port);
488 0 : IPv6AddressBytes bytes;
489 0 : memcpy(bytes.bytes, address.sin6_addr.s6_addr, 16);
490 0 : sender = Address(&bytes, address_port);
491 : } else {
492 : struct sockaddr_in address;
493 4795 : memset(&address, 0, sizeof(address));
494 :
495 4795 : socklen_t address_len = sizeof(address);
496 :
497 4795 : received = recvfrom(m_handle, (char *)data,
498 4795 : size, 0, (struct sockaddr *)&address, &address_len);
499 :
500 4795 : if(received < 0)
501 0 : return -1;
502 :
503 4795 : u32 address_ip = ntohl(address.sin_addr.s_addr);
504 4795 : u16 address_port = ntohs(address.sin_port);
505 :
506 4795 : sender = Address(address_ip, address_port);
507 : }
508 :
509 4795 : if (socket_enable_debug_output) {
510 : // Print packet sender and size
511 0 : dstream << (int) m_handle << " <- ";
512 0 : sender.print(&dstream);
513 0 : dstream << ", size=" << received;
514 :
515 : // Print packet contents
516 0 : dstream << ", data=";
517 0 : for(int i = 0; i < received && i < 20; i++) {
518 0 : if(i % 2 == 0)
519 0 : dstream << " ";
520 0 : unsigned int a = ((const unsigned char *) data)[i];
521 0 : dstream << std::hex << std::setw(2) << std::setfill('0') << a;
522 : }
523 0 : if(received > 20)
524 0 : dstream << "...";
525 :
526 0 : dstream << std::endl;
527 : }
528 :
529 4795 : return received;
530 : }
531 :
532 41076 : int UDPSocket::GetHandle()
533 : {
534 41076 : return m_handle;
535 : }
536 :
537 2 : void UDPSocket::setTimeoutMs(int timeout_ms)
538 : {
539 2 : m_timeout_ms = timeout_ms;
540 2 : }
541 :
542 10002 : bool UDPSocket::WaitData(int timeout_ms)
543 : {
544 : fd_set readset;
545 : int result;
546 :
547 : // Initialize the set
548 10002 : FD_ZERO(&readset);
549 10002 : FD_SET(m_handle, &readset);
550 :
551 : // Initialize time out struct
552 : struct timeval tv;
553 10002 : tv.tv_sec = 0;
554 10002 : tv.tv_usec = timeout_ms * 1000;
555 :
556 : // select()
557 10002 : result = select(m_handle+1, &readset, NULL, NULL, &tv);
558 :
559 10002 : if (result == 0)
560 412 : return false;
561 9590 : else if (result < 0 && (errno == EINTR || errno == EBADF)) {
562 : // N.B. select() fails when sockets are destroyed on Connection's dtor
563 : // with EBADF. Instead of doing tricky synchronization, allow this
564 : // thread to exit but don't throw an exception.
565 0 : return false;
566 9590 : } else if (result < 0) {
567 0 : dstream << (int) m_handle << ": Select failed: "
568 0 : << strerror(errno) << std::endl;
569 :
570 : #ifdef _WIN32
571 : int e = WSAGetLastError();
572 : dstream << (int) m_handle << ": WSAGetLastError()="
573 : << e << std::endl;
574 : if(e == 10004 /* = WSAEINTR */ || e == 10009 /*WSAEBADF*/)
575 : {
576 : dstream << "WARNING: Ignoring WSAEINTR/WSAEBADF." << std::endl;
577 : return false;
578 : }
579 : #endif
580 :
581 0 : throw SocketException("Select failed");
582 9590 : } else if(FD_ISSET(m_handle, &readset) == false) {
583 : // No data
584 0 : return false;
585 : }
586 :
587 : // There is data
588 9590 : return true;
589 3 : }
|