summaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2009-04-03 01:24:52 +0000
committerrubidium <rubidium@openttd.org>2009-04-03 01:24:52 +0000
commit632d74c6b1a17f3bc3419158dfc1bb5a2e5f77b5 (patch)
tree3d2dcf19488a31930bdb82d46f8ddc4b53aba59a /src/network
parentba5aafb9bba4887b502dba32e56747fe10af604e (diff)
downloadopenttd-632d74c6b1a17f3bc3419158dfc1bb5a2e5f77b5.tar.xz
(svn r15922) -Codechange: unify the ways to listen on a socket
Diffstat (limited to 'src/network')
-rw-r--r--src/network/core/address.cpp58
-rw-r--r--src/network/core/address.h12
-rw-r--r--src/network/core/udp.cpp29
-rw-r--r--src/network/core/udp.h2
-rw-r--r--src/network/network.cpp37
-rw-r--r--src/network/network_udp.cpp10
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<NetworkCompanyState>(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) {