From 632d74c6b1a17f3bc3419158dfc1bb5a2e5f77b5 Mon Sep 17 00:00:00 2001 From: rubidium Date: Fri, 3 Apr 2009 01:24:52 +0000 Subject: (svn r15922) -Codechange: unify the ways to listen on a socket --- src/network/core/address.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++- src/network/core/address.h | 12 +++++++-- src/network/core/udp.cpp | 29 ++++------------------ src/network/core/udp.h | 2 +- src/network/network.cpp | 37 +++++++--------------------- src/network/network_udp.cpp | 10 ++++---- 6 files changed, 87 insertions(+), 61 deletions(-) diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index c1313fe74..68eb692b1 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -82,7 +82,7 @@ SOCKET NetworkAddress::Connect() int e = getaddrinfo(this->GetHostname(), port_name, &hints, &ai); if (e != 0) { DEBUG(net, 0, "getaddrinfo failed: %s", gai_strerror(e)); - return false; + return INVALID_SOCKET; } SOCKET sock = INVALID_SOCKET; @@ -111,4 +111,60 @@ SOCKET NetworkAddress::Connect() return sock; } +SOCKET NetworkAddress::Listen(int family, int socktype) +{ + struct addrinfo *ai; + struct addrinfo hints; + memset(&hints, 0, sizeof (hints)); + hints.ai_family = family; + hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; + hints.ai_socktype = socktype; + + /* The port needs to be a string. Six is enough to contain all characters + '\0'. */ + char port_name[6] = { '0' }; + seprintf(port_name, lastof(port_name), "%u", this->GetPort()); + + int e = getaddrinfo(this->GetHostname(), port_name, &hints, &ai); + if (e != 0) { + DEBUG(net, 0, "getaddrinfo failed: %s", gai_strerror(e)); + return INVALID_SOCKET; + } + + SOCKET sock = INVALID_SOCKET; + for (struct addrinfo *runp = ai; runp != NULL; runp = runp->ai_next) { + sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); + if (sock == INVALID_SOCKET) { + DEBUG(net, 1, "could not create socket: %s", strerror(errno)); + continue; + } + + if (!SetNoDelay(sock)) DEBUG(net, 1, "Setting TCP_NODELAY failed"); + + if (bind(sock, runp->ai_addr, runp->ai_addrlen) != 0) { + DEBUG(net, 1, "could not bind: %s", strerror(errno)); + closesocket(sock); + sock = INVALID_SOCKET; + continue; + } + + if (socktype != SOCK_DGRAM && listen(sock, 1) != 0) { + DEBUG(net, 1, "could not listen: %s", strerror(errno)); + closesocket(sock); + sock = INVALID_SOCKET; + continue; + } + + /* Connection succeeded */ + if (!SetNonBlocking(sock)) DEBUG(net, 0, "Setting non-blocking mode failed"); + + this->address_length = runp->ai_addrlen; + assert(sizeof(this->address) >= runp->ai_addrlen); + memcpy(&this->address, runp->ai_addr, runp->ai_addrlen); + break; + } + freeaddrinfo (ai); + + return sock; +} + #endif /* ENABLE_NETWORK */ diff --git a/src/network/core/address.h b/src/network/core/address.h index 3e8ca0343..c42805add 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -52,8 +52,8 @@ public: * @param ip the unresolved hostname * @param port the port */ - NetworkAddress(const char *hostname = NULL, uint16 port = 0) : - hostname(hostname == NULL ? NULL : strdup(hostname)), + NetworkAddress(const char *hostname = "0.0.0.0", uint16 port = 0) : + hostname(strdup(hostname)), address_length(0) { memset(&this->address, 0, sizeof(this->address)); @@ -159,6 +159,14 @@ public: * @return the connected socket or INVALID_SOCKET. */ SOCKET Connect(); + + /** + * Make the given socket listen. + * @param family the type of 'protocol' (IPv4, IPv6) + * @param socktype the type of socket (TCP, UDP, etc) + * @return the listening socket or INVALID_SOCKET. + */ + SOCKET Listen(int family, int socktype); }; #endif /* ENABLE_NETWORK */ diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp index 4818767d9..473d438ea 100644 --- a/src/network/core/udp.cpp +++ b/src/network/core/udp.cpp @@ -17,45 +17,26 @@ /** * Start listening on the given host and port. - * @param host the host (ip) to listen on - * @param port the port to listen on + * @param address the host to listen on * @param broadcast whether to allow broadcast sending/receiving * @return true if the listening succeeded */ -bool NetworkUDPSocketHandler::Listen(const uint32 host, const uint16 port, const bool broadcast) +bool NetworkUDPSocketHandler::Listen(NetworkAddress address, bool broadcast) { - struct sockaddr_in sin; - /* Make sure socket is closed */ this->Close(); - this->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (!this->IsConnected()) { - DEBUG(net, 0, "[udp] failed to start UDP listener"); - return false; - } - - SetNonBlocking(this->sock); - - sin.sin_family = AF_INET; - /* Listen on all IPs */ - sin.sin_addr.s_addr = host; - sin.sin_port = htons(port); - - if (bind(this->sock, (struct sockaddr*)&sin, sizeof(sin)) != 0) { - DEBUG(net, 0, "[udp] bind failed on %s:%i", inet_ntoa(*(struct in_addr *)&host), port); - return false; - } + this->sock = address.Listen(AF_INET, SOCK_DGRAM); if (broadcast) { /* Enable broadcast */ unsigned long val = 1; #ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */ - setsockopt(this->sock, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val)); + setsockopt(this->sock, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)); #endif } - DEBUG(net, 1, "[udp] listening on port %s:%d", inet_ntoa(*(struct in_addr *)&host), port); + DEBUG(net, 1, "[udp] listening on port %s", address.GetAddressAsString()); return true; } diff --git a/src/network/core/udp.h b/src/network/core/udp.h index dd019b3bb..61f0f8f8e 100644 --- a/src/network/core/udp.h +++ b/src/network/core/udp.h @@ -125,7 +125,7 @@ public: /** On destructing of this class, the socket needs to be closed */ virtual ~NetworkUDPSocketHandler() { this->Close(); } - bool Listen(uint32 host, uint16 port, bool broadcast); + bool Listen(NetworkAddress address, bool broadcast); void Close(); void SendPacket(Packet *p, NetworkAddress *recv); diff --git a/src/network/network.cpp b/src/network/network.cpp index 74e0dadc1..88206ae0c 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -556,39 +556,20 @@ static void NetworkAcceptClients() /* Set up the listen socket for the server */ static bool NetworkListen() { - SOCKET ls; - struct sockaddr_in sin; + NetworkAddress address(_settings_client.network.server_bind_ip, _settings_client.network.server_port); - DEBUG(net, 1, "Listening on %s:%d", _settings_client.network.server_bind_ip, _settings_client.network.server_port); + DEBUG(net, 1, "Listening on %s", address.GetAddressAsString()); - ls = socket(AF_INET, SOCK_STREAM, 0); + SOCKET ls = address.Listen(AF_INET, SOCK_STREAM); if (ls == INVALID_SOCKET) { - ServerStartError("socket() on listen socket failed"); - return false; - } - - { // reuse the socket - int reuse = 1; - /* The (const char*) cast is needed for windows!! */ - if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1) { - ServerStartError("setsockopt() on listen socket failed"); - return false; - } - } - - if (!SetNonBlocking(ls)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error? - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = _network_server_bind_ip; - sin.sin_port = htons(_settings_client.network.server_port); - - if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0) { - ServerStartError("bind() failed"); + ServerStartError("Could not create listening socket"); return false; } - if (listen(ls, 1) != 0) { - ServerStartError("listen() failed"); + int reuse = 1; + /* The (const char*) cast is needed for windows!! */ + if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1) { + ServerStartError("setsockopt() on listen socket failed"); return false; } @@ -795,7 +776,7 @@ bool NetworkServerStart() /* Try to start UDP-server */ _network_udp_server = true; - _network_udp_server = _udp_server_socket->Listen(_network_server_bind_ip, _settings_client.network.server_port, false); + _network_udp_server = _udp_server_socket->Listen(NetworkAddress(_network_server_bind_ip, _settings_client.network.server_port), false); _network_company_states = CallocT(MAX_COMPANIES); _network_server = true; diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 031e9cbf1..b49fa9bd9 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -378,7 +378,7 @@ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket) void NetworkUDPQueryMasterServer() { if (!_udp_client_socket->IsConnected()) { - if (!_udp_client_socket->Listen(0, 0, true)) return; + if (!_udp_client_socket->Listen(NetworkAddress(), true)) return; } Packet p(PACKET_UDP_CLIENT_GET_LIST); @@ -400,7 +400,7 @@ void NetworkUDPSearchGame() /* No UDP-socket yet.. */ if (!_udp_client_socket->IsConnected()) { - if (!_udp_client_socket->Listen(0, 0, true)) return; + if (!_udp_client_socket->Listen(NetworkAddress(), true)) return; } DEBUG(net, 0, "[udp] searching server"); @@ -448,7 +448,7 @@ void NetworkUDPQueryServer(NetworkAddress address, bool manually) { /* No UDP-socket yet.. */ if (!_udp_client_socket->IsConnected()) { - if (!_udp_client_socket->Listen(0, 0, true)) return; + if (!_udp_client_socket->Listen(NetworkAddress(), true)) return; } NetworkUDPQueryServerInfo *info = new NetworkUDPQueryServerInfo(address, manually); @@ -483,7 +483,7 @@ void NetworkUDPRemoveAdvertise() /* check for socket */ if (!_udp_master_socket->IsConnected()) { - if (!_udp_master_socket->Listen(_network_server_bind_ip, 0, false)) return; + if (!_udp_master_socket->Listen(NetworkAddress(_network_server_bind_ip, 0), false)) return; } if (!ThreadObject::New(NetworkUDPRemoveAdvertiseThread, NULL)) { @@ -520,7 +520,7 @@ void NetworkUDPAdvertise() /* check for socket */ if (!_udp_master_socket->IsConnected()) { - if (!_udp_master_socket->Listen(_network_server_bind_ip, 0, false)) return; + if (!_udp_master_socket->Listen(NetworkAddress(_network_server_bind_ip, 0), false)) return; } if (_network_need_advertise) { -- cgit v1.2.3-54-g00ecf