diff options
author | rubidium <rubidium@openttd.org> | 2009-04-07 20:27:13 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2009-04-07 20:27:13 +0000 |
commit | 2a6e9288fd9e238c2f0b68243fced9e3cf794100 (patch) | |
tree | 6cab21c9baf3fb1ca74033e132561b40ed015d91 /src | |
parent | 6db7f15b3ad8addb7187bec3d309a4e6481ac431 (diff) | |
download | openttd-2a6e9288fd9e238c2f0b68243fced9e3cf794100.tar.xz |
(svn r15971) -Codechange: make it possible for UDP socket handlers to bind to multiple sockets.
Diffstat (limited to 'src')
-rw-r--r-- | src/network/core/core.h | 11 | ||||
-rw-r--r-- | src/network/core/tcp.cpp | 5 | ||||
-rw-r--r-- | src/network/core/tcp.h | 7 | ||||
-rw-r--r-- | src/network/core/udp.cpp | 131 | ||||
-rw-r--r-- | src/network/core/udp.h | 11 | ||||
-rw-r--r-- | src/network/network.cpp | 5 | ||||
-rw-r--r-- | src/network/network_udp.cpp | 33 |
7 files changed, 106 insertions, 97 deletions
diff --git a/src/network/core/core.h b/src/network/core/core.h index bc348255d..4fca89f54 100644 --- a/src/network/core/core.h +++ b/src/network/core/core.h @@ -38,11 +38,8 @@ struct Packet; class NetworkSocketHandler { bool has_quit; ///< Whether the current client has quit/send a bad packet public: - /* TODO: make socket protected once the TCP stuff is in a real class too */ - SOCKET sock; ///< The socket currently connected to -public: /** Create a new unbound socket */ - NetworkSocketHandler(SOCKET s = INVALID_SOCKET) { this->sock = s; this->has_quit = false; } + NetworkSocketHandler() { this->has_quit = false; } /** Close the socket when distructing the socket handler */ virtual ~NetworkSocketHandler() { this->Close(); } @@ -58,12 +55,6 @@ public: virtual NetworkRecvStatus CloseConnection() { this->has_quit = true; return NETWORK_RECV_STATUS_OKAY; } /** - * Whether this socket is currently bound to a socket. - * @return true when the socket is bound, false otherwise - */ - bool IsConnected() const { return this->sock != INVALID_SOCKET; } - - /** * Whether the current client connected to the socket has quit. * In the case of UDP, for example, once a client quits (send bad * data), the socket in not closed; only the packet is dropped. diff --git a/src/network/core/tcp.cpp b/src/network/core/tcp.cpp index 1ed8b618c..a80defb4c 100644 --- a/src/network/core/tcp.cpp +++ b/src/network/core/tcp.cpp @@ -13,8 +13,9 @@ #include "tcp.h" NetworkTCPSocketHandler::NetworkTCPSocketHandler(SOCKET s) : - NetworkSocketHandler(s), - packet_queue(NULL), packet_recv(NULL), writable(false) + NetworkSocketHandler(), + packet_queue(NULL), packet_recv(NULL), + sock(s), writable(false) { } diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h index 90edba014..7e4964813 100644 --- a/src/network/core/tcp.h +++ b/src/network/core/tcp.h @@ -20,8 +20,15 @@ private: Packet *packet_queue; ///< Packets that are awaiting delivery Packet *packet_recv; ///< Partially received packet public: + SOCKET sock; ///< The socket currently connected to bool writable; ///< Can we write to this socket? + /** + * Whether this socket is currently bound to a socket. + * @return true when the socket is bound, false otherwise + */ + bool IsConnected() const { return this->sock != INVALID_SOCKET; } + virtual NetworkRecvStatus CloseConnection(); void Send_Packet(Packet *packet); bool Send_Packets(); diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp index df5a68cb5..96ece0ace 100644 --- a/src/network/core/udp.cpp +++ b/src/network/core/udp.cpp @@ -16,29 +16,39 @@ #include "udp.h" /** + * Create an UDP socket but don't listen yet. + * @param bind the addresses to bind to. + */ +NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind) +{ + if (bind != NULL) { + for (NetworkAddress *addr = bind->Begin(); addr != bind->End(); addr++) { + *this->bind.Append() = *addr; + } + } else { + *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET); + } +} + + +/** * Start listening on the given host and port. - * @param address the host to listen on - * @param broadcast whether to allow broadcast sending/receiving - * @return true if the listening succeeded + * @return true if at least one port is listening */ -bool NetworkUDPSocketHandler::Listen(NetworkAddress address, bool broadcast) +bool NetworkUDPSocketHandler::Listen() { /* Make sure socket is closed */ this->Close(); - 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)); -#endif + for (NetworkAddress *addr = this->bind.Begin(); addr != this->bind.End(); addr++) { + addr->Listen(AF_UNSPEC, SOCK_DGRAM, &this->sockets); } - DEBUG(net, 1, "[udp] listening on port %s", address.GetAddressAsString()); + for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { + DEBUG(net, 1, "[udp] listening on port %s", s->first.GetAddressAsString()); + } - return true; + return this->sockets.Length() != 0; } /** @@ -46,10 +56,10 @@ bool NetworkUDPSocketHandler::Listen(NetworkAddress address, bool broadcast) */ void NetworkUDPSocketHandler::Close() { - if (!this->IsConnected()) return; - - closesocket(this->sock); - this->sock = INVALID_SOCKET; + for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { + closesocket(s->second); + } + this->sockets.Clear(); } NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection() @@ -62,18 +72,35 @@ NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection() * Send a packet over UDP * @param p the packet to send * @param recv the receiver (target) of the packet + * @param all send the packet using all sockets that can send it + * @param broadcast whether to send a broadcast message */ -void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv) +void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool all, bool broadcast) { - int res; + if (this->sockets.Length() == 0) this->Listen(); - p->PrepareToSend(); + for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { + /* Not the same type */ + if (s->first.GetAddress()->ss_family != recv->GetAddress()->ss_family) continue; - /* Send the buffer */ - res = sendto(this->sock, (const char*)p->buffer, p->size, 0, (struct sockaddr *)recv->GetAddress(), recv->GetAddressLength()); + p->PrepareToSend(); - /* Check for any errors, but ignore it otherwise */ - if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR()); +#ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */ + if (broadcast) { + /* Enable broadcast */ + unsigned long val = 1; + setsockopt(s->second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)); + } +#endif + + /* Send the buffer */ + int res = sendto(s->second, (const char*)p->buffer, p->size, 0, (struct sockaddr *)recv->GetAddress(), recv->GetAddressLength()); + + /* Check for any errors, but ignore it otherwise */ + if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", recv->GetAddressAsString(), GET_LAST_ERROR()); + + if (!all) break; + } } /** @@ -81,37 +108,33 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv) */ void NetworkUDPSocketHandler::ReceivePackets() { - struct sockaddr_storage client_addr; - memset(&client_addr, 0, sizeof(client_addr)); - - socklen_t client_len; - int nbytes; - Packet p(this); - int packet_len; - - if (!this->IsConnected()) return; - - packet_len = sizeof(p.buffer); - client_len = sizeof(client_addr); - - /* Try to receive anything */ - SetNonBlocking(this->sock); // Some OSes seem to lose the non-blocking status of the socket - nbytes = recvfrom(this->sock, (char*)p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len); - - /* We got some bytes for the base header of the packet. */ - if (nbytes > 2) { - NetworkAddress address(client_addr, client_len); - p.PrepareToRead(); + for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { + struct sockaddr_storage client_addr; + memset(&client_addr, 0, sizeof(client_addr)); + + Packet p(this); + int packet_len = sizeof(p.buffer); + socklen_t client_len = sizeof(client_addr); + + /* Try to receive anything */ + SetNonBlocking(s->second); // Some OSes seem to lose the non-blocking status of the socket + int nbytes = recvfrom(s->second, (char*)p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len); + + /* We got some bytes for the base header of the packet. */ + if (nbytes > 2) { + NetworkAddress address(client_addr, client_len); + p.PrepareToRead(); + + /* If the size does not match the packet must be corrupted. + * Otherwise it will be marked as corrupted later on. */ + if (nbytes != p.size) { + DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString()); + return; + } - /* If the size does not match the packet must be corrupted. - * Otherwise it will be marked as corrupted later on. */ - if (nbytes != p.size) { - DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString()); - return; + /* Handle the packet */ + this->HandleUDPPacket(&p, &address); } - - /* Handle the packet */ - this->HandleUDPPacket(&p, &address); } } diff --git a/src/network/core/udp.h b/src/network/core/udp.h index 20e228100..2302dab0d 100644 --- a/src/network/core/udp.h +++ b/src/network/core/udp.h @@ -96,6 +96,11 @@ enum PacketUDPType { /** Base socket handler for all UDP sockets */ class NetworkUDPSocketHandler : public NetworkSocketHandler { protected: + /** The address to bind to. */ + NetworkAddressList bind; + /** The opened sockets. */ + SocketList sockets; + NetworkRecvStatus CloseConnection(); /* Declare all possible packets here. If it can be received by the @@ -124,13 +129,15 @@ protected: */ virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) { NOT_REACHED(); } public: + NetworkUDPSocketHandler(NetworkAddressList *bind = NULL); + /** On destructing of this class, the socket needs to be closed */ virtual ~NetworkUDPSocketHandler() { this->Close(); } - bool Listen(NetworkAddress address, bool broadcast); + bool Listen(); void Close(); - void SendPacket(Packet *p, NetworkAddress *recv); + void SendPacket(Packet *p, NetworkAddress *recv, bool all = false, bool broadcast = false); void ReceivePackets(); void Send_NetworkGameInfo(Packet *p, const NetworkGameInfo *info); diff --git a/src/network/network.cpp b/src/network/network.cpp index 60c163c37..e1d3ad2a8 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -274,7 +274,7 @@ static void NetworkClientError(NetworkRecvStatus res, NetworkClientSocket *cs) /* We just want to close the connection.. */ if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) { - cs->CloseConnection(); + cs->NetworkSocketHandler::CloseConnection(); NetworkCloseClient(cs); _networking = false; @@ -738,8 +738,7 @@ bool NetworkServerStart() if (!NetworkListen()) return false; /* Try to start UDP-server */ - _network_udp_server = true; - _network_udp_server = _udp_server_socket->Listen(NetworkAddress(_settings_client.network.server_bind_ip, _settings_client.network.server_port), false); + _network_udp_server = _udp_server_socket->Listen(); _network_company_states = CallocT<NetworkCompanyState>(MAX_COMPANIES); _network_server = true; diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 44d0ea414..55988edca 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -74,6 +74,7 @@ protected: DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO); DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS); public: + ServerNetworkUDPSocketHandler(NetworkAddressList *addresses) : NetworkUDPSocketHandler(addresses) {} virtual ~ServerNetworkUDPSocketHandler() {} }; @@ -376,7 +377,7 @@ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket) DEBUG(net, 4, "[udp] broadcasting to %s", addr->GetHostname()); - socket->SendPacket(&p, addr); + socket->SendPacket(&p, addr, true, true); } } @@ -384,10 +385,6 @@ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket) /* Request the the server-list from the master server */ void NetworkUDPQueryMasterServer() { - if (!_udp_client_socket->IsConnected()) { - if (!_udp_client_socket->Listen(NetworkAddress(), true)) return; - } - Packet p(PACKET_UDP_CLIENT_GET_LIST); NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT); @@ -405,11 +402,6 @@ void NetworkUDPSearchGame() /* We are still searching.. */ if (_network_udp_broadcast > 0) return; - /* No UDP-socket yet.. */ - if (!_udp_client_socket->IsConnected()) { - if (!_udp_client_socket->Listen(NetworkAddress(), true)) return; - } - DEBUG(net, 0, "[udp] searching server"); NetworkUDPBroadCast(_udp_client_socket); @@ -453,11 +445,6 @@ void NetworkUDPQueryServerThread(void *pntr) void NetworkUDPQueryServer(NetworkAddress address, bool manually) { - /* No UDP-socket yet.. */ - if (!_udp_client_socket->IsConnected()) { - if (!_udp_client_socket->Listen(NetworkAddress(), true)) return; - } - NetworkUDPQueryServerInfo *info = new NetworkUDPQueryServerInfo(address, manually); if (address.IsResolved() || !ThreadObject::New(NetworkUDPQueryServerThread, info)) { NetworkUDPQueryServerThread(info); @@ -488,11 +475,6 @@ void NetworkUDPRemoveAdvertise() /* Check if we are advertising */ if (!_networking || !_network_server || !_network_udp_server) return; - /* check for socket */ - if (!_udp_master_socket->IsConnected()) { - if (!_udp_master_socket->Listen(NetworkAddress(_settings_client.network.server_bind_ip, 0), false)) return; - } - if (!ThreadObject::New(NetworkUDPRemoveAdvertiseThread, NULL)) { NetworkUDPRemoveAdvertiseThread(NULL); } @@ -526,11 +508,6 @@ void NetworkUDPAdvertise() if (!_networking || !_network_server || !_network_udp_server || !_settings_client.network.server_advertise) return; - /* check for socket */ - if (!_udp_master_socket->IsConnected()) { - if (!_udp_master_socket->Listen(NetworkAddress(_settings_client.network.server_bind_ip, 0), false)) return; - } - if (_network_need_advertise) { _network_need_advertise = false; _network_advertise_retries = ADVERTISE_RETRY_TIMES; @@ -559,8 +536,12 @@ void NetworkUDPInitialize() assert(_udp_client_socket == NULL && _udp_server_socket == NULL && _udp_master_socket == NULL); _network_udp_mutex->BeginCritical(); + + NetworkAddressList server; + *server.Append() = NetworkAddress(_settings_client.network.server_bind_ip, _settings_client.network.server_port); + _udp_client_socket = new ClientNetworkUDPSocketHandler(); - _udp_server_socket = new ServerNetworkUDPSocketHandler(); + _udp_server_socket = new ServerNetworkUDPSocketHandler(&server); _udp_master_socket = new MasterNetworkUDPSocketHandler(); _network_udp_server = false; |