LCOV - code coverage report
Current view: top level - src - socket.cpp (source / functions) Hit Total Coverage
Test: report Lines: 141 258 54.7 %
Date: 2015-07-11 18:23:49 Functions: 29 32 90.6 %

          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 : }

Generated by: LCOV version 1.11