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