From 5f3772a42c322a99d2ea57b6c97b76fceccbb781 Mon Sep 17 00:00:00 2001 From: rubidium Date: Tue, 20 Jan 2009 01:32:06 +0000 Subject: (svn r15157) -Codechange: wrap the hostname/ip and port into a single structure so we can pass either one of them and not convert an ip to a string and then back again. --- src/console_cmds.cpp | 2 +- src/network/network.cpp | 52 +++++++++++++++-------- src/network/network_func.h | 4 +- src/network/network_gamelist.cpp | 9 +--- src/network/network_gui.cpp | 16 +++---- src/network/network_internal.h | 2 +- src/network/network_type.h | 91 ++++++++++++++++++++++++++++++++++++++++ src/network/network_udp.cpp | 27 +++++------- src/network/network_udp.h | 2 +- src/openttd.cpp | 6 +-- 10 files changed, 155 insertions(+), 56 deletions(-) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index ad3375873..c0ef53e30 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -692,7 +692,7 @@ DEF_CONSOLE_CMD(ConNetworkConnect) IConsolePrintF(CC_DEFAULT, " port: %s", port); } - NetworkClientConnectGame(ip, rport); + NetworkClientConnectGame(NetworkAddress(ip, rport)); return true; } diff --git a/src/network/network.cpp b/src/network/network.cpp index a9175385a..edf6a51b6 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -451,12 +451,12 @@ void NetworkCloseClient(NetworkClientSocket *cs) } // A client wants to connect to a server -static bool NetworkConnect(const char *hostname, int port) +static bool NetworkConnect(NetworkAddress address) { SOCKET s; struct sockaddr_in sin; - DEBUG(net, 1, "Connecting to %s %d", hostname, port); + DEBUG(net, 1, "Connecting to %s %d", address.GetHostname(), address.GetPort()); s = socket(AF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { @@ -467,8 +467,8 @@ static bool NetworkConnect(const char *hostname, int port) if (!SetNoDelay(s)) DEBUG(net, 1, "Setting TCP_NODELAY failed"); sin.sin_family = AF_INET; - sin.sin_addr.s_addr = NetworkResolveHost(hostname); - sin.sin_port = htons(port); + sin.sin_addr.s_addr = address.GetIP(); + sin.sin_port = htons(address.GetIP()); _network_last_host_ip = sin.sin_addr.s_addr; /* We failed to connect for which reason what so ever */ @@ -664,7 +664,7 @@ static void NetworkInitialize() // Query a server to fetch his game-info // If game_info is true, only the gameinfo is fetched, // else only the client_info is fetched -void NetworkTCPQueryServer(const char *host, unsigned short port) +void NetworkTCPQueryServer(NetworkAddress address) { if (!_network_available) return; @@ -672,7 +672,7 @@ void NetworkTCPQueryServer(const char *host, unsigned short port) NetworkInitialize(); // Try to connect - _networking = NetworkConnect(host, port); + _networking = NetworkConnect(address); // We are connected if (_networking) { @@ -701,7 +701,7 @@ void NetworkAddServer(const char *b) ParseConnectionString(&company, &port, host); if (port != NULL) rport = atoi(port); - NetworkUDPQueryServer(host, rport, true); + NetworkUDPQueryServer(NetworkAddress(host, rport), true); } } @@ -727,20 +727,20 @@ void NetworkRebuildHostList() } // Used by clients, to connect to a server -void NetworkClientConnectGame(const char *host, uint16 port) +void NetworkClientConnectGame(NetworkAddress address) { if (!_network_available) return; - if (port == 0) return; + if (address.GetPort() == 0) return; - strecpy(_settings_client.network.last_host, host, lastof(_settings_client.network.last_host)); - _settings_client.network.last_port = port; + strecpy(_settings_client.network.last_host, address.GetHostname(), lastof(_settings_client.network.last_host)); + _settings_client.network.last_port = address.GetPort(); NetworkDisconnect(); NetworkInitialize(); // Try to connect - _networking = NetworkConnect(host, port); + _networking = NetworkConnect(address); // We are connected if (_networking) { @@ -1073,13 +1073,13 @@ static void NetworkGenerateUniqueId() snprintf(_settings_client.network.network_id, sizeof(_settings_client.network.network_id), "%s", hex_output); } -void NetworkStartDebugLog(const char *hostname, uint16 port) +void NetworkStartDebugLog(NetworkAddress address) { extern SOCKET _debug_socket; // Comes from debug.c SOCKET s; struct sockaddr_in sin; - DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", hostname, port); + DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", address.GetHostname(), address.GetPort()); s = socket(AF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { @@ -1090,11 +1090,11 @@ void NetworkStartDebugLog(const char *hostname, uint16 port) if (!SetNoDelay(s)) DEBUG(net, 1, "Setting TCP_NODELAY failed"); sin.sin_family = AF_INET; - sin.sin_addr.s_addr = NetworkResolveHost(hostname); - sin.sin_port = htons(port); + sin.sin_addr.s_addr = address.GetIP(); + sin.sin_port = htons(address.GetPort()); if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) != 0) { - DEBUG(net, 0, "Failed to redirection DEBUG() to %s:%d", hostname, port); + DEBUG(net, 0, "Failed to redirection DEBUG() to %s:%d", address.GetHostname(), address.GetIP()); return; } @@ -1154,6 +1154,24 @@ bool IsNetworkCompatibleVersion(const char *other) return strncmp(_openttd_revision, other, NETWORK_REVISION_LENGTH - 1) == 0; } +const char *NetworkAddress::GetHostname() const +{ + if (this->hostname != NULL) return this->hostname; + + in_addr addr; + addr.s_addr = this->ip; + return inet_ntoa(addr); +} + +uint32 NetworkAddress::GetIP() +{ + if (!this->resolved) { + this->ip = NetworkResolveHost(this->hostname); + this->resolved = true; + } + return this->ip; +} + #endif /* ENABLE_NETWORK */ /* NOTE: this variable needs to be always available */ diff --git a/src/network/network_func.h b/src/network/network_func.h index db3de7f8f..c2de52ca7 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -32,11 +32,11 @@ void NetworkGameLoop(); void NetworkUDPGameLoop(); void NetworkUDPCloseAll(); void ParseConnectionString(const char **company, const char **port, char *connection_string); -void NetworkStartDebugLog(const char *hostname, uint16 port); +void NetworkStartDebugLog(NetworkAddress address); void NetworkPopulateCompanyStats(NetworkCompanyStats *stats); void NetworkUpdateClientInfo(ClientID client_id); -void NetworkClientConnectGame(const char *host, uint16 port); +void NetworkClientConnectGame(NetworkAddress address); void NetworkClientSendRcon(const char *password, const char *command); void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data = 0); void NetworkClientSetPassword(const char *password); diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index efec52220..235e9afe3 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -96,18 +96,13 @@ void NetworkGameListRequery() if (++requery_cnt < REQUERY_EVERY_X_GAMELOOPS) return; requery_cnt = 0; - struct in_addr ip; - NetworkGameList *item; - - for (item = _network_game_list; item != NULL; item = item->next) { + for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) { item->retries++; if (item->retries < REFRESH_GAMEINFO_X_REQUERIES && (item->online || item->retries >= MAX_GAME_LIST_REQUERY_COUNT)) continue; - ip.s_addr = item->ip; - /* item gets mostly zeroed by NetworkUDPQueryServer */ uint8 retries = item->retries; - NetworkUDPQueryServer(inet_ntoa(ip), item->port); + NetworkUDPQueryServer(NetworkAddress(item->ip, item->port)); item->retries = (retries >= REFRESH_GAMEINFO_X_REQUERIES) ? 0 : retries; } } diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index f9b0b7cc9..7209e8145 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -558,7 +558,7 @@ public: break; case NGWW_REFRESH: // Refresh - if (this->server != NULL) NetworkUDPQueryServer(this->server->info.hostname, this->server->port); + if (this->server != NULL) NetworkUDPQueryServer(NetworkAddress(this->server->info.hostname, this->server->port)); break; case NGWW_NEWGRF: // NewGRF Settings @@ -1313,22 +1313,22 @@ struct NetworkLobbyWindow : public Window { case NLWW_JOIN: // Join company /* Button can be clicked only when it is enabled */ _network_playas = this->company; - NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port); + NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); break; case NLWW_NEW: // New company _network_playas = COMPANY_NEW_COMPANY; - NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port); + NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); break; case NLWW_SPECTATE: // Spectate game _network_playas = COMPANY_SPECTATOR; - NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port); + NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); break; case NLWW_REFRESH: // Refresh - NetworkTCPQueryServer(_settings_client.network.last_host, _settings_client.network.last_port); // company info - NetworkUDPQueryServer(_settings_client.network.last_host, _settings_client.network.last_port); // general data + NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info + NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data /* Clear the information so removed companies don't remain */ memset(this->company_info, 0, sizeof(company_info)); break; @@ -1381,8 +1381,8 @@ static void ShowNetworkLobbyWindow(NetworkGameList *ngl) { DeleteWindowById(WC_NETWORK_WINDOW, 0); - NetworkTCPQueryServer(_settings_client.network.last_host, _settings_client.network.last_port); // company info - NetworkUDPQueryServer(_settings_client.network.last_host, _settings_client.network.last_port); // general data + NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info + NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data new NetworkLobbyWindow(&_network_lobby_window_desc, ngl); } diff --git a/src/network/network_internal.h b/src/network/network_internal.h index be78ae772..8065d660b 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -122,7 +122,7 @@ extern uint16 _network_udp_broadcast; extern uint8 _network_advertise_retries; -void NetworkTCPQueryServer(const char *host, unsigned short port); +void NetworkTCPQueryServer(NetworkAddress address); void NetworkAddServer(const char *b); void NetworkRebuildHostList(); diff --git a/src/network/network_type.h b/src/network/network_type.h index 9104e2f0f..4c6c3e829 100644 --- a/src/network/network_type.h +++ b/src/network/network_type.h @@ -11,6 +11,7 @@ #include "../economy_type.h" #include "core/config.h" #include "core/game.h" +#include "core/os_abstraction.h" enum { /** How many clients can we have */ @@ -114,5 +115,95 @@ enum NetworkErrorCode { NETWORK_ERROR_FULL, }; +/** + * Wrapper for (un)resolved network addresses; there's no reason to transform + * a numeric IP to a string and then back again to pass it to functions. It + * furthermore allows easier delaying of the hostname lookup. + */ +class NetworkAddress { +private: + bool resolved; ///< Has the IP address been resolved + char *hostname; ///< The hostname, NULL if there isn't one + uint32 ip; ///< The resolved IP address + uint16 port; ///< The port associated with the address + +public: + /** + * Create a network address based on a resolved IP and port + * @param ip the resolved ip + * @param port the port + */ + NetworkAddress(in_addr_t ip, uint16 port) : + resolved(true), + hostname(NULL), + ip(ip), + port(port) + { + } + + /** + * Create a network address based on a unresolved host and port + * @param ip the unresolved hostname + * @param port the port + */ + NetworkAddress(const char *hostname, uint16 port) : + resolved(false), + hostname(strdup(hostname)), + ip(0), + port(port) + { + } + + /** + * Make a clone of another address + * @param address the address to clone + */ + NetworkAddress(const NetworkAddress &address) : + resolved(address.resolved), + hostname(address.hostname == NULL ? NULL : strdup(address.hostname)), + ip(address.ip), + port(address.port) + { + } + + /** Clean up our mess */ + ~NetworkAddress() + { + free(hostname); + } + + /** + * Get the hostname; in case it wasn't given the + * IPv4 dotted representation is given. + * @return the hostname + */ + const char *GetHostname() const; + + /** + * Get the IP address. If the IP has not been resolved yet this will resolve + * it possibly blocking this function for a while + * @return the IP address + */ + uint32 GetIP(); + + /** + * Get the port + * @return the port + */ + uint16 GetPort() const + { + return this->port; + } + + /** + * Check whether the IP address has been resolved already + * @return true iff the port has been resolved + */ + bool IsResolved() const + { + return this->resolved; + } +}; + #endif /* ENABLE_NETWORK */ #endif /* NETWORK_TYPE_H */ diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 822347b41..9c42d8d31 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -276,27 +276,22 @@ DEF_UDP_RECEIVE_COMMAND(Client, PACKET_UDP_SERVER_RESPONSE) DEF_UDP_RECEIVE_COMMAND(Client, PACKET_UDP_MASTER_RESPONSE_LIST) { - int i; - struct in_addr ip; - uint16 port; - uint8 ver; - /* packet begins with the protocol version (uint8) * then an uint16 which indicates how many * ip:port pairs are in this packet, after that * an uint32 (ip) and an uint16 (port) for each pair */ - ver = p->Recv_uint8(); + uint8 ver = p->Recv_uint8(); if (ver == 1) { - for (i = p->Recv_uint16(); i != 0 ; i--) { - ip.s_addr = TO_LE32(p->Recv_uint32()); - port = p->Recv_uint16(); + for (int i = p->Recv_uint16(); i != 0 ; i--) { + uint32 ip = TO_LE32(p->Recv_uint32()); + uint16 port = p->Recv_uint16(); /* Somehow we reached the end of the packet */ if (this->HasClientQuit()) return; - NetworkUDPQueryServer(inet_ntoa(ip), port); + NetworkUDPQueryServer(NetworkAddress(ip, port)); } } } @@ -425,7 +420,7 @@ void NetworkUDPSearchGame() _network_udp_broadcast = 300; // Stay searching for 300 ticks } -void NetworkUDPQueryServer(const char *host, unsigned short port, bool manually) +void NetworkUDPQueryServer(NetworkAddress address, bool manually) { struct sockaddr_in out_addr; NetworkGameList *item; @@ -436,17 +431,17 @@ void NetworkUDPQueryServer(const char *host, unsigned short port, bool manually) } out_addr.sin_family = AF_INET; - out_addr.sin_port = htons(port); - out_addr.sin_addr.s_addr = NetworkResolveHost(host); + out_addr.sin_port = htons(address.GetPort()); + out_addr.sin_addr.s_addr = address.GetIP(); // Clear item in gamelist - item = NetworkGameListAddItem(inet_addr(inet_ntoa(out_addr.sin_addr)), ntohs(out_addr.sin_port)); + item = NetworkGameListAddItem(address.GetIP(), address.GetPort()); if (item == NULL) return; if (StrEmpty(item->info.server_name)) { memset(&item->info, 0, sizeof(item->info)); - strecpy(item->info.server_name, host, lastof(item->info.server_name)); - strecpy(item->info.hostname, host, lastof(item->info.hostname)); + strecpy(item->info.server_name, address.GetHostname(), lastof(item->info.server_name)); + strecpy(item->info.hostname, address.GetHostname(), lastof(item->info.hostname)); item->online = false; } item->manually = manually; diff --git a/src/network/network_udp.h b/src/network/network_udp.h index 48fa4e1e6..736524c00 100644 --- a/src/network/network_udp.h +++ b/src/network/network_udp.h @@ -10,7 +10,7 @@ void NetworkUDPInitialize(); void NetworkUDPSearchGame(); void NetworkUDPQueryMasterServer(); -void NetworkUDPQueryServer(const char *host, unsigned short port, bool manually = false); +void NetworkUDPQueryServer(NetworkAddress address, bool manually = false); void NetworkUDPAdvertise(); void NetworkUDPRemoveAdvertise(); void NetworkUDPShutdown(); diff --git a/src/openttd.cpp b/src/openttd.cpp index 703bfdb7c..1150cabfa 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -681,7 +681,7 @@ int ttd_main(int argc, char *argv[]) ParseConnectionString(¬_used, &port, debuglog_conn); if (port != NULL) rport = atoi(port); - NetworkStartDebugLog(debuglog_conn, rport); + NetworkStartDebugLog(NetworkAddress(debuglog_conn, rport)); } #endif /* ENABLE_NETWORK */ @@ -728,7 +728,7 @@ int ttd_main(int argc, char *argv[]) LoadIntroGame(); _switch_mode = SM_NONE; - NetworkClientConnectGame(network_conn, rport); + NetworkClientConnectGame(NetworkAddress(network_conn, rport)); } } #endif /* ENABLE_NETWORK */ @@ -1219,7 +1219,7 @@ void GameLoop() if (_network_reconnect > 0 && --_network_reconnect == 0) { /* This means that we want to reconnect to the last host * We do this here, because it means that the network is really closed */ - NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port); + NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); } /* Singleplayer */ StateGameLoop(); -- cgit v1.2.3-54-g00ecf