summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2009-04-07 20:27:13 +0000
committerrubidium <rubidium@openttd.org>2009-04-07 20:27:13 +0000
commit2a6e9288fd9e238c2f0b68243fced9e3cf794100 (patch)
tree6cab21c9baf3fb1ca74033e132561b40ed015d91
parent6db7f15b3ad8addb7187bec3d309a4e6481ac431 (diff)
downloadopenttd-2a6e9288fd9e238c2f0b68243fced9e3cf794100.tar.xz
(svn r15971) -Codechange: make it possible for UDP socket handlers to bind to multiple sockets.
-rw-r--r--src/network/core/core.h11
-rw-r--r--src/network/core/tcp.cpp5
-rw-r--r--src/network/core/tcp.h7
-rw-r--r--src/network/core/udp.cpp131
-rw-r--r--src/network/core/udp.h11
-rw-r--r--src/network/network.cpp5
-rw-r--r--src/network/network_udp.cpp33
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;