X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fsocket.cpp;h=e82052f7728083430f32e3ed2bdd2d914045dc99;hb=c6766b275f25368e78eeffc68719b0ca1979c819;hp=a889223b474873e1a5f3947ca06efc1ee455b7ee;hpb=f764297be2d55c9b8350077e44e3d62a9e058bcf;p=oweals%2Fminetest.git diff --git a/src/socket.cpp b/src/socket.cpp index a889223b4..e82052f77 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -19,6 +19,20 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "socket.h" +#include +#include +#include +#include +#include +#include +#include +#include "util/string.h" +#include "util/numeric.h" +#include "constants.h" +#include "debug.h" +#include "settings.h" +#include "log.h" + #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN @@ -30,9 +44,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include - #ifdef _MSC_VER - #pragma comment(lib, "ws2_32.lib") - #endif typedef SOCKET socket_t; typedef int socklen_t; #else @@ -46,23 +57,10 @@ typedef int socklen_t; typedef int socket_t; #endif -#include "constants.h" -#include "debug.h" -#include "settings.h" -#include "main.h" // for g_settings -#include -#include -#include -#include -#include -#include -#include "util/string.h" -#include "util/numeric.h" - // Set to true to enable verbose debug output -bool socket_enable_debug_output = false; +bool socket_enable_debug_output = false; // yuck -bool g_sockets_initialized = false; +static bool g_sockets_initialized = false; // Initialize sockets void sockets_init() @@ -91,30 +89,33 @@ void sockets_cleanup() Address::Address() { m_addr_family = 0; - memset(&m_address, 0, sizeof m_address); + memset(&m_address, 0, sizeof(m_address)); m_port = 0; } Address::Address(u32 address, u16 port) { + memset(&m_address, 0, sizeof(m_address)); setAddress(address); setPort(port); } Address::Address(u8 a, u8 b, u8 c, u8 d, u16 port) { + memset(&m_address, 0, sizeof(m_address)); setAddress(a, b, c, d); setPort(port); } -Address::Address(const IPv6AddressBytes * ipv6_bytes, u16 port) +Address::Address(const IPv6AddressBytes *ipv6_bytes, u16 port) { + memset(&m_address, 0, sizeof(m_address)); setAddress(ipv6_bytes); setPort(port); } // Equality (address family, address and port must be equal) -bool Address::operator==(Address &address) +bool Address::operator==(const Address &address) { if(address.m_addr_family != m_addr_family || address.m_port != m_port) return false; @@ -132,16 +133,25 @@ bool Address::operator==(Address &address) return false; } -bool Address::operator!=(Address &address) +bool Address::operator!=(const Address &address) { return !(*this == address); } void Address::Resolve(const char *name) { + if (!name || name[0] == 0) { + if (m_addr_family == AF_INET) { + setAddress((u32) 0); + } else if (m_addr_family == AF_INET6) { + setAddress((IPv6AddressBytes*) 0); + } + return; + } + struct addrinfo *resolved, hints; memset(&hints, 0, sizeof(hints)); - + // Setup hints hints.ai_socktype = 0; hints.ai_protocol = 0; @@ -155,7 +165,7 @@ void Address::Resolve(const char *name) { hints.ai_family = AF_INET; } - + // Do getaddrinfo() int e = getaddrinfo(name, NULL, &hints, &resolved); if(e != 0) @@ -185,11 +195,42 @@ void Address::Resolve(const char *name) // IP address -> textual representation std::string Address::serializeString() const { +// windows XP doesnt have inet_ntop, maybe use better func +#ifdef _WIN32 + if(m_addr_family == AF_INET) + { + u8 a, b, c, d; + u32 addr; + addr = ntohl(m_address.ipv4.sin_addr.s_addr); + a = (addr & 0xFF000000) >> 24; + b = (addr & 0x00FF0000) >> 16; + c = (addr & 0x0000FF00) >> 8; + d = (addr & 0x000000FF); + return itos(a) + "." + itos(b) + "." + itos(c) + "." + itos(d); + } + else if(m_addr_family == AF_INET6) + { + std::ostringstream os; + for(int i = 0; i < 16; i += 2) + { + u16 section = + (m_address.ipv6.sin6_addr.s6_addr[i] << 8) | + (m_address.ipv6.sin6_addr.s6_addr[i + 1]); + os << std::hex << section; + if(i < 14) + os << ":"; + } + return os.str(); + } + else + return std::string(""); +#else char str[INET6_ADDRSTRLEN]; 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) { - return std::string(""); + return std::string(""); } return std::string(str); +#endif } struct sockaddr_in Address::getAddress() const @@ -217,6 +258,18 @@ bool Address::isIPv6() const return m_addr_family == AF_INET6; } +bool Address::isZero() const +{ + if (m_addr_family == AF_INET) { + return m_address.ipv4.sin_addr.s_addr == 0; + } else if (m_addr_family == AF_INET6) { + static const char zero[16] = {0}; + return memcmp(m_address.ipv6.sin6_addr.s6_addr, + zero, 16) == 0; + } + return false; +} + void Address::setAddress(u32 address) { m_addr_family = AF_INET; @@ -232,11 +285,11 @@ void Address::setAddress(u8 a, u8 b, u8 c, u8 d) m_address.ipv4.sin_addr.s_addr = addr; } -void Address::setAddress(const IPv6AddressBytes * ipv6_bytes) +void Address::setAddress(const IPv6AddressBytes *ipv6_bytes) { m_addr_family = AF_INET6; m_address.ipv6.sin6_family = AF_INET6; - if(ipv6_bytes) + if (ipv6_bytes) memcpy(m_address.ipv6.sin6_addr.s6_addr, ipv6_bytes->bytes, 16); else memset(m_address.ipv6.sin6_addr.s6_addr, 0, 16); @@ -250,13 +303,9 @@ void Address::setPort(u16 port) void Address::print(std::ostream *s) const { if(m_addr_family == AF_INET6) - { - (*s) << "[" << serializeString() << "]:" << m_port; - } + *s << "[" << serializeString() << "]:" << m_port; else - { - (*s) << serializeString() << ":" << m_port; - } + *s << serializeString() << ":" << m_port; } /* @@ -265,33 +314,44 @@ void Address::print(std::ostream *s) const UDPSocket::UDPSocket(bool ipv6) { - if(g_sockets_initialized == false) - throw SocketException("Sockets not initialized"); + init(ipv6, false); +} + +bool UDPSocket::init(bool ipv6, bool noExceptions) +{ + if (g_sockets_initialized == false) { + dstream << "Sockets not initialized" << std::endl; + return false; + } // Use IPv6 if specified m_addr_family = ipv6 ? AF_INET6 : AF_INET; m_handle = socket(m_addr_family, SOCK_DGRAM, IPPROTO_UDP); - - if(socket_enable_debug_output) - { + + if (socket_enable_debug_output) { dstream << "UDPSocket(" << (int) m_handle << ")::UDPSocket(): ipv6 = " << (ipv6 ? "true" : "false") << std::endl; } - if(m_handle <= 0) - { - throw SocketException("Failed to create socket"); + if (m_handle <= 0) { + if (noExceptions) { + return false; + } else { + throw SocketException("Failed to create socket"); + } } setTimeoutMs(0); + + return true; } + UDPSocket::~UDPSocket() { - if(socket_enable_debug_output) - { + if (socket_enable_debug_output) { dstream << "UDPSocket( " << (int) m_handle << ")::~UDPSocket()" << std::endl; } @@ -303,40 +363,45 @@ UDPSocket::~UDPSocket() #endif } -void UDPSocket::Bind(u16 port) +void UDPSocket::Bind(Address addr) { - if(socket_enable_debug_output) - { + if(socket_enable_debug_output) { dstream << "UDPSocket(" << (int) m_handle << ")::Bind(): " - << "port=" << port << std::endl; + << addr.serializeString() << ":" + << addr.getPort() << std::endl; } - if(m_addr_family == AF_INET6) - { + if (addr.getFamily() != m_addr_family) { + static const char *errmsg = "Socket and bind address families do not match"; + errorstream << "Bind failed: " << errmsg << std::endl; + throw SocketException(errmsg); + } + + if(m_addr_family == AF_INET6) { struct sockaddr_in6 address; + memset(&address, 0, sizeof(address)); + + address = addr.getAddress6(); address.sin6_family = AF_INET6; - address.sin6_addr = in6addr_any; - address.sin6_port = htons(port); + address.sin6_port = htons(addr.getPort()); if(bind(m_handle, (const struct sockaddr *) &address, - sizeof(struct sockaddr_in6)) < 0) - { + sizeof(struct sockaddr_in6)) < 0) { dstream << (int) m_handle << ": Bind failed: " << strerror(errno) << std::endl; throw SocketException("Failed to bind socket"); } - } - else - { + } else { struct sockaddr_in address; + memset(&address, 0, sizeof(address)); + + address = addr.getAddress(); address.sin_family = AF_INET; - address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons(port); + address.sin_port = htons(addr.getPort()); - if(bind(m_handle, (const struct sockaddr *) &address, - sizeof(struct sockaddr_in)) < 0) - { - dstream << (int) m_handle << ": Bind failed: " + if (bind(m_handle, (const struct sockaddr *) &address, + sizeof(struct sockaddr_in)) < 0) { + dstream << (int)m_handle << ": Bind failed: " << strerror(errno) << std::endl; throw SocketException("Failed to bind socket"); } @@ -348,39 +413,35 @@ void UDPSocket::Send(const Address & destination, const void * data, int size) bool dumping_packet = false; // for INTERNET_SIMULATOR if(INTERNET_SIMULATOR) - dumping_packet = (myrand() % INTERNET_SIMULATOR_PACKET_LOSS == 0); + dumping_packet = myrand() % INTERNET_SIMULATOR_PACKET_LOSS == 0; - if(socket_enable_debug_output) - { + if(socket_enable_debug_output) { // Print packet destination and size - dstream << (int) m_handle << " -> "; + dstream << (int)m_handle << " -> "; destination.print(&dstream); dstream << ", size=" << size; - + // Print packet contents dstream << ", data="; - for(int i = 0; i < size && i < 20; i++) - { + for(int i = 0; i < size && i < 20; i++) { if(i % 2 == 0) - DEBUGPRINT(" "); - unsigned int a = ((const unsigned char *) data)[i]; - DEBUGPRINT("%.2X", a); + dstream << " "; + unsigned int a = ((const unsigned char *)data)[i]; + dstream << std::hex << std::setw(2) << std::setfill('0') << a; } - + if(size > 20) dstream << "..."; - + if(dumping_packet) dstream << " (DUMPED BY INTERNET_SIMULATOR)"; - + dstream << std::endl; } - if(dumping_packet) - { + if(dumping_packet) { // Lol let's forget it - dstream << "UDPSocket::Send(): " - "INTERNET_SIMULATOR: dumping packet." + dstream << "UDPSocket::Send(): INTERNET_SIMULATOR: dumping packet." << std::endl; return; } @@ -389,39 +450,32 @@ void UDPSocket::Send(const Address & destination, const void * data, int size) throw SendFailedException("Address family mismatch"); int sent; - if(m_addr_family == AF_INET6) - { + if(m_addr_family == AF_INET6) { struct sockaddr_in6 address = destination.getAddress6(); address.sin6_port = htons(destination.getPort()); - sent = sendto(m_handle, (const char *) data, size, - 0, (struct sockaddr *) &address, sizeof(struct sockaddr_in6)); - } - else - { + sent = sendto(m_handle, (const char *)data, size, + 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in6)); + } else { struct sockaddr_in address = destination.getAddress(); address.sin_port = htons(destination.getPort()); - sent = sendto(m_handle, (const char *) data, size, - 0, (struct sockaddr *) &address, sizeof(struct sockaddr_in)); + sent = sendto(m_handle, (const char *)data, size, + 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); } if(sent != size) - { throw SendFailedException("Failed to send packet"); - } } -int UDPSocket::Receive(Address & sender, void * data, int size) +int UDPSocket::Receive(Address & sender, void *data, int size) { // Return on timeout if(WaitData(m_timeout_ms) == false) - { return -1; - } int received; - if(m_addr_family == AF_INET6) - { + if (m_addr_family == AF_INET6) { struct sockaddr_in6 address; + memset(&address, 0, sizeof(address)); socklen_t address_len = sizeof(address); received = recvfrom(m_handle, (char *) data, @@ -434,14 +488,14 @@ int UDPSocket::Receive(Address & sender, void * data, int size) IPv6AddressBytes bytes; memcpy(bytes.bytes, address.sin6_addr.s6_addr, 16); sender = Address(&bytes, address_port); - } - else - { + } else { struct sockaddr_in address; + memset(&address, 0, sizeof(address)); + socklen_t address_len = sizeof(address); - received = recvfrom(m_handle, (char *) data, - size, 0, (struct sockaddr *) &address, &address_len); + received = recvfrom(m_handle, (char *)data, + size, 0, (struct sockaddr *)&address, &address_len); if(received < 0) return -1; @@ -452,25 +506,23 @@ int UDPSocket::Receive(Address & sender, void * data, int size) sender = Address(address_ip, address_port); } - if(socket_enable_debug_output) - { + if (socket_enable_debug_output) { // Print packet sender and size dstream << (int) m_handle << " <- "; sender.print(&dstream); dstream << ", size=" << received; - + // Print packet contents dstream << ", data="; - for(int i = 0; i < received && i < 20; i++) - { + for(int i = 0; i < received && i < 20; i++) { if(i % 2 == 0) - DEBUGPRINT(" "); + dstream << " "; unsigned int a = ((const unsigned char *) data)[i]; - DEBUGPRINT("%.2X", a); + dstream << std::hex << std::setw(2) << std::setfill('0') << a; } if(received > 20) dstream << "..."; - + dstream << std::endl; } @@ -504,12 +556,14 @@ bool UDPSocket::WaitData(int timeout_ms) // select() result = select(m_handle+1, &readset, NULL, NULL, &tv); - if(result == 0) + if (result == 0) return false; - else if(result < 0 && errno == EINTR) + else if (result < 0 && (errno == EINTR || errno == EBADF)) { + // N.B. select() fails when sockets are destroyed on Connection's dtor + // with EBADF. Instead of doing tricky synchronization, allow this + // thread to exit but don't throw an exception. return false; - else if(result < 0) - { + } else if (result < 0) { dstream << (int) m_handle << ": Select failed: " << strerror(errno) << std::endl; @@ -517,23 +571,19 @@ bool UDPSocket::WaitData(int timeout_ms) int e = WSAGetLastError(); dstream << (int) m_handle << ": WSAGetLastError()=" << e << std::endl; - if(e == 10004 /* = WSAEINTR */) + if(e == 10004 /* = WSAEINTR */ || e == 10009 /*WSAEBADF*/) { - dstream << "WARNING: Ignoring WSAEINTR." << std::endl; + dstream << "WARNING: Ignoring WSAEINTR/WSAEBADF." << std::endl; return false; } #endif throw SocketException("Select failed"); - } - else if(FD_ISSET(m_handle, &readset) == false) - { + } else if(FD_ISSET(m_handle, &readset) == false) { // No data return false; } - + // There is data return true; } - -