From b770fa19fbfbf229b519f7983ab597da3e73d1eb Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 25 Apr 2018 20:26:23 +0200 Subject: [PATCH] Auto refresh for lan server detection --- src/network/network.cpp | 135 ---------------- src/network/network.hpp | 7 - src/network/protocols/connect_to_server.cpp | 2 +- src/network/servers_manager.cpp | 171 +++++++++++++++++++- src/network/servers_manager.hpp | 12 +- src/states_screens/server_selection.cpp | 24 ++- src/states_screens/server_selection.hpp | 4 +- 7 files changed, 201 insertions(+), 154 deletions(-) diff --git a/src/network/network.cpp b/src/network/network.cpp index 6d9b6d27a..4eb275463 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -230,138 +230,3 @@ void Network::closeLog() m_log_file.unlock(); } } // closeLog - -// ---------------------------------------------------------------------------- -/** Sets a list of default broadcast addresses which is used in case no valid - * broadcast address is found. This list includes default private network - * addresses. - */ -void Network::setDefaultBroadcastAddresses() -{ - // Add some common LAN addresses - m_broadcast_address.emplace_back(std::string("192.168.255.255")); - m_broadcast_address.emplace_back(std::string("192.168.0.255") ); - m_broadcast_address.emplace_back(std::string("192.168.1.255") ); - m_broadcast_address.emplace_back(std::string("172.31.255.255") ); - m_broadcast_address.emplace_back(std::string("172.16.255.255") ); - m_broadcast_address.emplace_back(std::string("172.16.0.255") ); - m_broadcast_address.emplace_back(std::string("10.255.255.255") ); - m_broadcast_address.emplace_back(std::string("10.0.255.255") ); - m_broadcast_address.emplace_back(std::string("10.0.0.255") ); - m_broadcast_address.emplace_back(std::string("255.255.255.255")); - m_broadcast_address.emplace_back(std::string("127.0.0.255") ); - m_broadcast_address.emplace_back(std::string("127.0.0.1") ); -} // setDefaultBroadcastAddresses - -// ---------------------------------------------------------------------------- -/** This masks various possible broadcast addresses. For example, in a /16 - * network it would first use *.*.255.255, then *.*.*.255. Also if the - * length of the mask is not a multiple of 8, the original value will - * be used, before multiple of 8 are create: /22 (*.3f.ff.ff), then - * /16 (*.*.ff.ff), /8 (*.*.*.ff). While this is usually an overkill, - * it can help in the case that the router does not forward a broadcast - * as expected (this problem often happens with 255.255.255.255, which is - * why this broadcast address creation code was added). - * \param a The transport address for which the broadcast addresses need - * to be created. - * \param len Number of bits to be or'ed. - */ -void Network::addAllBroadcastAddresses(const TransportAddress &a, int len) -{ - // Try different broadcast addresses - by masking on - // byte boundaries - while (len > 0) - { - unsigned int mask = (1 << len) - 1; - TransportAddress bcast(a.getIP() | mask, - NetworkConfig::get()->getServerDiscoveryPort()); - Log::info("Broadcast", "address %s length %d mask %x --> %s", - a.toString().c_str(), - len, mask, - bcast.toString().c_str()); - m_broadcast_address.push_back(bcast); - if (len % 8 != 0) - len -= (len % 8); - else - len = len - 8; - } // while len > 0 -} // addAllBroadcastAddresses - -// ---------------------------------------------------------------------------- -/** Returns a list of all possible broadcast addresses on this machine. - * It queries all adapters for active IPV4 interfaces, determines their - * netmask to create the broadcast addresses. It will also add 'smaller' - * broadcast addesses, e.g. in a /16 network, it will add *.*.255.255 and - * *.*.*.255, since it was sometimes observed that routers would not let - * all broadcast addresses through. Duplicated answers (from the same server - * to different addersses) will be filtered out in ServersManager. - */ -const std::vector& Network::getBroadcastAddresses() -{ - if (m_broadcast_address.size() > 0) return m_broadcast_address; - -#ifdef WIN32 - IP_ADAPTER_ADDRESSES *addresses; - int count = 100, return_code; - - int iteration = 0; - do - { - addresses = new IP_ADAPTER_ADDRESSES[count]; - ULONG buf_len = sizeof(IP_ADAPTER_ADDRESSES)*count; - long flags = 0; - return_code = GetAdaptersAddresses(AF_INET, flags, NULL, addresses, - &buf_len); - iteration++; - } while (return_code == ERROR_BUFFER_OVERFLOW && iteration<10); - - if (return_code == ERROR_BUFFER_OVERFLOW) - { - Log::warn("NetworkConfig", "Can not get broadcast addresses."); - setDefaultBroadcastAddresses(); - return m_broadcast_address; - } - - for (IP_ADAPTER_ADDRESSES *p = addresses; p; p = p->Next) - { - // Check all operational IP4 adapters - if (p->OperStatus == IfOperStatusUp && - p->FirstUnicastAddress->Address.lpSockaddr->sa_family == AF_INET) - { - const sockaddr_in *sa = (sockaddr_in*)p->FirstUnicastAddress->Address.lpSockaddr; - // Use sa->sin_addr.S_un.S_addr and htonl? - TransportAddress ta(sa->sin_addr.S_un.S_un_b.s_b1, - sa->sin_addr.S_un.S_un_b.s_b2, - sa->sin_addr.S_un.S_un_b.s_b3, - sa->sin_addr.S_un.S_un_b.s_b4); - int len = 32 - p->FirstUnicastAddress->OnLinkPrefixLength; - addAllBroadcastAddresses(ta, len); - } - } -#else - struct ifaddrs *addresses, *p; - - getifaddrs(&addresses); - for (p = addresses; p; p = p->ifa_next) - { - if (p->ifa_addr->sa_family == AF_INET) - { - struct sockaddr_in *sa = (struct sockaddr_in *) p->ifa_addr; - TransportAddress ta(htonl(sa->sin_addr.s_addr), 0); - uint32_t u = ((sockaddr_in*)(p->ifa_netmask))->sin_addr.s_addr; - // Convert mask to #bits: SWAT algorithm - u = u - ((u >> 1) & 0x55555555); - u = (u & 0x33333333) + ((u >> 2) & 0x33333333); - u = (((u + (u >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; - - printf("Interface: %s\tAddress: %s\tmask: %x\n", p->ifa_name, - ta.toString().c_str(), u); - addAllBroadcastAddresses(ta, u); - } - } - - -#endif - return m_broadcast_address; -} // getBroadcastAddresses - diff --git a/src/network/network.hpp b/src/network/network.hpp index d6d0a5fb8..c50038bcc 100644 --- a/src/network/network.hpp +++ b/src/network/network.hpp @@ -51,12 +51,6 @@ private: /** Where to log packets. If NULL for FILE* logging is disabled. */ static Synchronised m_log_file; - /** List of broadcast addresses to use. */ - std::vector m_broadcast_address; - - void setDefaultBroadcastAddresses(); - void addAllBroadcastAddresses(const TransportAddress &a, int len); - public: Network(int peer_count, int channel_limit, uint32_t max_incoming_bandwidth, @@ -75,7 +69,6 @@ public: TransportAddress* sender, int max_tries = -1); void broadcastPacket(NetworkString *data, bool reliable = true); - const std::vector& getBroadcastAddresses(); // ------------------------------------------------------------------------ /** Returns a pointer to the ENet host object. */ diff --git a/src/network/protocols/connect_to_server.cpp b/src/network/protocols/connect_to_server.cpp index bed2b1a84..ad82b50f0 100644 --- a/src/network/protocols/connect_to_server.cpp +++ b/src/network/protocols/connect_to_server.cpp @@ -82,7 +82,7 @@ void ConnectToServer::asynchronousUpdate() { if (!m_server) { - while (!ServersManager::get()->refresh()) + while (!ServersManager::get()->refresh(false)) StkTime::sleep(1); while (!ServersManager::get()->listUpdated()) StkTime::sleep(1); diff --git a/src/network/servers_manager.cpp b/src/network/servers_manager.cpp index 76ad6d9da..e74fbc447 100644 --- a/src/network/servers_manager.cpp +++ b/src/network/servers_manager.cpp @@ -33,6 +33,14 @@ #include #include +#if defined(WIN32) +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x600 +# include +#else +# include +#endif + #define SERVER_REFRESH_INTERVAL 5.0f static ServersManager* g_manager_singleton(NULL); @@ -136,7 +144,7 @@ Online::XMLRequest* ServersManager::getLANRefreshRequest() const addr.port = STKHost::PORT_ANY; Network *broadcast = new Network(1, 1, 0, 0, &addr); const std::vector &all_bcast = - broadcast->getBroadcastAddresses(); + ServersManager::get()->getBroadcastAddresses(); for (auto &bcast_addr : all_bcast) { Log::info("Server Discovery", "Broadcasting to %s", @@ -225,7 +233,7 @@ void ServersManager::setLanServers(const std::mapisWAN()) - Online::RequestManager::get()->addRequest(getWANRefreshRequest()); + { + Online::RequestManager::get()->addRequest(getWANRefreshRequest()); + } else - Online::RequestManager::get()->addRequest(getLANRefreshRequest()); + { + if (full_refresh) + { + updateBroadcastAddresses(); + } + + Online::RequestManager::get()->addRequest(getLANRefreshRequest()); + } + return true; } // refresh @@ -275,3 +294,147 @@ void ServersManager::setWanServers(bool success, const XMLNode* input) m_last_load_time.store((float)StkTime::getRealTime()); m_list_updated = true; } // refresh + +// ---------------------------------------------------------------------------- +/** Sets a list of default broadcast addresses which is used in case no valid + * broadcast address is found. This list includes default private network + * addresses. + */ +void ServersManager::setDefaultBroadcastAddresses() +{ + // Add some common LAN addresses + m_broadcast_address.emplace_back(std::string("192.168.255.255")); + m_broadcast_address.emplace_back(std::string("192.168.0.255") ); + m_broadcast_address.emplace_back(std::string("192.168.1.255") ); + m_broadcast_address.emplace_back(std::string("172.31.255.255") ); + m_broadcast_address.emplace_back(std::string("172.16.255.255") ); + m_broadcast_address.emplace_back(std::string("172.16.0.255") ); + m_broadcast_address.emplace_back(std::string("10.255.255.255") ); + m_broadcast_address.emplace_back(std::string("10.0.255.255") ); + m_broadcast_address.emplace_back(std::string("10.0.0.255") ); + m_broadcast_address.emplace_back(std::string("255.255.255.255")); + m_broadcast_address.emplace_back(std::string("127.0.0.255") ); + m_broadcast_address.emplace_back(std::string("127.0.0.1") ); +} // setDefaultBroadcastAddresses + +// ---------------------------------------------------------------------------- +/** This masks various possible broadcast addresses. For example, in a /16 + * network it would first use *.*.255.255, then *.*.*.255. Also if the + * length of the mask is not a multiple of 8, the original value will + * be used, before multiple of 8 are create: /22 (*.3f.ff.ff), then + * /16 (*.*.ff.ff), /8 (*.*.*.ff). While this is usually an overkill, + * it can help in the case that the router does not forward a broadcast + * as expected (this problem often happens with 255.255.255.255, which is + * why this broadcast address creation code was added). + * \param a The transport address for which the broadcast addresses need + * to be created. + * \param len Number of bits to be or'ed. + */ +void ServersManager::addAllBroadcastAddresses(const TransportAddress &a, int len) +{ + // Try different broadcast addresses - by masking on + // byte boundaries + while (len > 0) + { + unsigned int mask = (1 << len) - 1; + TransportAddress bcast(a.getIP() | mask, + NetworkConfig::get()->getServerDiscoveryPort()); + Log::info("Broadcast", "address %s length %d mask %x --> %s", + a.toString().c_str(), + len, mask, + bcast.toString().c_str()); + m_broadcast_address.push_back(bcast); + if (len % 8 != 0) + len -= (len % 8); + else + len = len - 8; + } // while len > 0 +} // addAllBroadcastAddresses + +// ---------------------------------------------------------------------------- +/** Updates a list of all possible broadcast addresses on this machine. + * It queries all adapters for active IPV4 interfaces, determines their + * netmask to create the broadcast addresses. It will also add 'smaller' + * broadcast addesses, e.g. in a /16 network, it will add *.*.255.255 and + * *.*.*.255, since it was sometimes observed that routers would not let + * all broadcast addresses through. Duplicated answers (from the same server + * to different addersses) will be filtered out in ServersManager. + */ +void ServersManager::updateBroadcastAddresses() +{ + m_broadcast_address.clear(); + +#ifdef WIN32 + IP_ADAPTER_ADDRESSES *addresses; + int count = 100, return_code; + + int iteration = 0; + do + { + addresses = new IP_ADAPTER_ADDRESSES[count]; + ULONG buf_len = sizeof(IP_ADAPTER_ADDRESSES)*count; + long flags = 0; + return_code = GetAdaptersAddresses(AF_INET, flags, NULL, addresses, + &buf_len); + iteration++; + } while (return_code == ERROR_BUFFER_OVERFLOW && iteration<10); + + if (return_code == ERROR_BUFFER_OVERFLOW) + { + Log::warn("NetworkConfig", "Can not get broadcast addresses."); + setDefaultBroadcastAddresses(); + return; + } + + for (IP_ADAPTER_ADDRESSES *p = addresses; p; p = p->Next) + { + // Check all operational IP4 adapters + if (p->OperStatus == IfOperStatusUp && + p->FirstUnicastAddress->Address.lpSockaddr->sa_family == AF_INET) + { + const sockaddr_in *sa = (sockaddr_in*)p->FirstUnicastAddress->Address.lpSockaddr; + // Use sa->sin_addr.S_un.S_addr and htonl? + TransportAddress ta(sa->sin_addr.S_un.S_un_b.s_b1, + sa->sin_addr.S_un.S_un_b.s_b2, + sa->sin_addr.S_un.S_un_b.s_b3, + sa->sin_addr.S_un.S_un_b.s_b4); + int len = 32 - p->FirstUnicastAddress->OnLinkPrefixLength; + addAllBroadcastAddresses(ta, len); + } + } +#else + struct ifaddrs *addresses, *p; + + getifaddrs(&addresses); + for (p = addresses; p; p = p->ifa_next) + { + if (p->ifa_addr->sa_family == AF_INET) + { + struct sockaddr_in *sa = (struct sockaddr_in *) p->ifa_addr; + TransportAddress ta(htonl(sa->sin_addr.s_addr), 0); + uint32_t u = ((sockaddr_in*)(p->ifa_netmask))->sin_addr.s_addr; + // Convert mask to #bits: SWAT algorithm + u = u - ((u >> 1) & 0x55555555); + u = (u & 0x33333333) + ((u >> 2) & 0x33333333); + u = (((u + (u >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; + + printf("Interface: %s\tAddress: %s\tmask: %x\n", p->ifa_name, + ta.toString().c_str(), u); + addAllBroadcastAddresses(ta, u); + } + } +#endif +} // updateBroadcastAddresses + +// ---------------------------------------------------------------------------- +/** Returns a list of all possible broadcast addresses on this machine. + */ +const std::vector& ServersManager::getBroadcastAddresses() +{ + if (m_broadcast_address.empty()) + { + updateBroadcastAddresses(); + } + + return m_broadcast_address; +} // getBroadcastAddresses diff --git a/src/network/servers_manager.hpp b/src/network/servers_manager.hpp index cafde353a..40f4a7179 100644 --- a/src/network/servers_manager.hpp +++ b/src/network/servers_manager.hpp @@ -29,6 +29,7 @@ namespace Online { class XMLRequest; } class Server; +class TransportAddress; class XMLNode; /** @@ -40,6 +41,9 @@ class ServersManager private: /** List of servers */ std::vector > m_servers; + + /** List of broadcast addresses to use. */ + std::vector m_broadcast_address; std::atomic m_last_load_time; @@ -57,6 +61,10 @@ private: // ------------------------------------------------------------------------ void setLanServers(const std::map >& servers); + + void setDefaultBroadcastAddresses(); + void addAllBroadcastAddresses(const TransportAddress &a, int len); + void updateBroadcastAddresses(); public: // ------------------------------------------------------------------------ // Singleton @@ -66,11 +74,13 @@ public: // ------------------------------------------------------------------------ void cleanUpServers() { m_servers.clear(); } // ------------------------------------------------------------------------ - bool refresh(); + bool refresh(bool full_refresh); // ------------------------------------------------------------------------ std::vector >& getServers() { return m_servers; } // ------------------------------------------------------------------------ bool listUpdated() const { return m_list_updated; } + // ------------------------------------------------------------------------ + const std::vector& getBroadcastAddresses(); }; // class ServersManager #endif // HEADER_SERVERS_MANAGER_HPP diff --git a/src/states_screens/server_selection.cpp b/src/states_screens/server_selection.cpp index 4fab27af9..7087cf9ec 100644 --- a/src/states_screens/server_selection.cpp +++ b/src/states_screens/server_selection.cpp @@ -42,6 +42,7 @@ using namespace Online; ServerSelection::ServerSelection() : Screen("online/server_selection.stkgui") { m_refreshing_server = false; + m_refresh_timer = 0.0f; } // ServerSelection // ---------------------------------------------------------------------------- @@ -65,15 +66,16 @@ void ServerSelection::tearDown() /** Requests the servers manager to update its list of servers, and disables * the 'refresh' button (till the refresh was finished). */ -void ServerSelection::refresh() +void ServerSelection::refresh(bool full_refresh) { // If the request was created (i.e. no error, and not re-requested within // 5 seconds), clear the list and display the waiting message: - if (ServersManager::get()->refresh()) + if (ServersManager::get()->refresh(full_refresh)) { m_server_list_widget->clear(); m_reload_widget->setActive(false); m_refreshing_server = true; + m_refresh_timer = 0.0f; } } // refresh @@ -120,7 +122,7 @@ void ServerSelection::init() Screen::init(); m_sort_desc = true; /** Triggers the loading of the server list in the servers manager. */ - refresh(); + refresh(true); } // init // ---------------------------------------------------------------------------- @@ -215,7 +217,7 @@ void ServerSelection::eventCallback(GUIEngine::Widget* widget, } else if (name == "reload") { - refresh(); + refresh(true); } else if (name == "private_server") { @@ -250,6 +252,17 @@ void ServerSelection::onUpdate(float dt) ServerInfoDialog *sid = new ServerInfoDialog(m_servers[0]); sid->requestJoin(); } + + if (ServersManager::get()->getServers().empty() && !m_refreshing_server && + !NetworkConfig::get()->isWAN()) + { + m_refresh_timer += dt; + + if (m_refresh_timer > 10.0f) + { + refresh(false); + } + } if (!m_refreshing_server) return; @@ -269,8 +282,9 @@ void ServerSelection::onUpdate(float dt) else { SFXManager::get()->quickSound("anvil"); - new MessageDialog(_("No server is available.")); m_server_list_widget->clear(); + m_server_list_widget->addItem("loading", + _("No server is available.")); } m_reload_widget->setActive(true); } diff --git a/src/states_screens/server_selection.hpp b/src/states_screens/server_selection.hpp index b2c0d2131..dd7ac6dff 100644 --- a/src/states_screens/server_selection.hpp +++ b/src/states_screens/server_selection.hpp @@ -59,13 +59,15 @@ private: bool m_sort_desc; bool m_refreshing_server; + + float m_refresh_timer; /** Load the servers into the main list.*/ void loadList(unsigned sort_case); void copyFromServersManager(); - void refresh(); + void refresh(bool full_refresh); public: /** \brief implement callback from parent class GUIEngine::Screen */