diff --git a/src/network/protocols/connect_to_server.cpp b/src/network/protocols/connect_to_server.cpp index 1b9025ea9..fe3981fd6 100644 --- a/src/network/protocols/connect_to_server.cpp +++ b/src/network/protocols/connect_to_server.cpp @@ -38,31 +38,36 @@ #endif // ---------------------------------------------------------------------------- - -ConnectToServer::ConnectToServer() : - Protocol(NULL, PROTOCOL_CONNECTION) +/** Quick join/ + */ +ConnectToServer::ConnectToServer() : Protocol(NULL, PROTOCOL_CONNECTION) { - m_server_id = 0; + m_server_id = 0; + m_host_id = 0; m_quick_join = true; - m_state = NONE; -} + m_state = NONE; +} // ConnectToServer() // ---------------------------------------------------------------------------- - -ConnectToServer::ConnectToServer(uint32_t server_id, uint32_t host_id) : - Protocol(NULL, PROTOCOL_CONNECTION) +/** Specify server to connect to. + * \param server_id Id of server to connect to. + * \param host_id Id of host. + */ +ConnectToServer::ConnectToServer(uint32_t server_id, uint32_t host_id) + : Protocol(NULL, PROTOCOL_CONNECTION) { - m_server_id = server_id; - m_host_id = host_id; + m_server_id = server_id; + m_host_id = host_id; m_quick_join = false; - m_state = NONE; -} + m_state = NONE; +} // ConnectToServer(server, host) // ---------------------------------------------------------------------------- - +/** Destructor. + */ ConnectToServer::~ConnectToServer() { -} +} // ~ConnectToServer // ---------------------------------------------------------------------------- @@ -75,20 +80,18 @@ bool ConnectToServer::notifyEventAsynchronous(Event* event) m_state = CONNECTED; // we received a message, we are connected } return true; -} +} // notifyEventAsynchronous // ---------------------------------------------------------------------------- - void ConnectToServer::setup() { - Log::info("ConnectToServer", "SETUPP"); + Log::info("ConnectToServer", "SETUP"); m_state = NONE; m_server_address.clear(); m_current_protocol_id = 0; -} +} // setup // ---------------------------------------------------------------------------- - void ConnectToServer::asynchronousUpdate() { switch(m_state) @@ -96,154 +99,89 @@ void ConnectToServer::asynchronousUpdate() case NONE: { Log::info("ConnectToServer", "Protocol starting"); - m_current_protocol_id = m_listener->requestStart(new GetPublicAddress()); + m_current_protocol_id = + m_listener->requestStart(new GetPublicAddress()); m_state = GETTING_SELF_ADDRESS; break; } case GETTING_SELF_ADDRESS: - if (m_listener->getProtocolState(m_current_protocol_id) - == PROTOCOL_STATE_TERMINATED) // now we know the public addr + if (m_listener->getProtocolState(m_current_protocol_id) == + PROTOCOL_STATE_TERMINATED) // now we know the public addr { m_state = SHOWING_SELF_ADDRESS; - m_current_protocol_id = m_listener->requestStart(new ShowPublicAddress()); + m_current_protocol_id = + m_listener->requestStart(new ShowPublicAddress()); Log::info("ConnectToServer", "Public address known"); - /* - if (m_quick_join) - m_current_protocol_id = m_listener->requestStart(new QuickJoinProtocol(&m_server_address, &m_server_id)); - else - m_current_protocol_id = m_listener->requestStart(new GetPeerAddress(m_server_id, &m_server_address));*/ } break; case SHOWING_SELF_ADDRESS: - if (m_listener->getProtocolState(m_current_protocol_id) - == PROTOCOL_STATE_TERMINATED) // now our public address is in the database + if (m_listener->getProtocolState(m_current_protocol_id) == + PROTOCOL_STATE_TERMINATED) { + // now our public address is in the database Log::info("ConnectToServer", "Public address shown"); if (m_quick_join) { - m_current_protocol_id = m_listener->requestStart(new QuickJoinProtocol(&m_server_address, &m_server_id)); + m_current_protocol_id = m_listener->requestStart( + new QuickJoinProtocol(&m_server_address, + &m_server_id) ); m_state = REQUESTING_CONNECTION; } else { - m_current_protocol_id = m_listener->requestStart(new GetPeerAddress(m_host_id, &m_server_address)); + m_current_protocol_id = m_listener->requestStart( + new GetPeerAddress(m_host_id, + &m_server_address) ); m_state = GETTING_SERVER_ADDRESS; } } break; case GETTING_SERVER_ADDRESS: - if (m_listener->getProtocolState(m_current_protocol_id) - == PROTOCOL_STATE_TERMINATED) // we know the server address + if (m_listener->getProtocolState(m_current_protocol_id) == + PROTOCOL_STATE_TERMINATED) // we know the server address { Log::info("ConnectToServer", "Server's address known"); // we're in the same lan (same public ip address) !! - if (m_server_address.getIP() == - NetworkManager::getInstance()->getPublicAddress().getIP()) - Log::info("ConnectToServer", - "Server appears to be in the same LAN."); - m_state = REQUESTING_CONNECTION; - m_current_protocol_id = - m_listener->requestStart(new RequestConnection(m_server_id)); - } - break; - case REQUESTING_CONNECTION: - if (m_listener->getProtocolState(m_current_protocol_id) - == PROTOCOL_STATE_TERMINATED) // server knows we wanna connect - { - Log::info("ConnectToServer", "Connection request made"); - if (m_server_address.getIP() == 0 || - m_server_address.getPort() == 0 ) - { // server data not correct, hide address and stop - m_state = HIDING_ADDRESS; - Log::error("ConnectToServer", "Server address is %s", - m_server_address.toString().c_str()); - m_current_protocol_id = m_listener->requestStart(new HidePublicAddress()); - return; - } - // we're in the same lan (same public ip address) !! if (m_server_address.getIP() == NetworkManager::getInstance()->getPublicAddress().getIP()) { - // just send a broadcast packet, the client will know our ip address and will connect - STKHost* host = NetworkManager::getInstance()->getHost(); - host->stopListening(); // stop the listening - TransportAddress sender; - - TransportAddress broadcast_address; - broadcast_address.setIP(-1); // 255.255.255.255 - broadcast_address.setPort(7321); // 0b10101100000101101101111111111111; // for test - char data2[] = "aloha_stk\0"; - host->sendRawPacket((uint8_t*)(data2), 10, broadcast_address); - - Log::info("ConnectToServer", "Waiting broadcast message."); - const uint8_t* received_data = host->receiveRawPacket(&sender); // get the sender - - host->startListening(); // start listening again - const char data[] = "aloha_stk\0"; - if (strcmp(data, (char*)(received_data)) == 0) - { - Log::info("ConnectToServer", "LAN Server found : %s", - sender.toString().c_str()); -#ifndef WIN32 - // just check if the ip is ours : if so, then just use localhost (127.0.0.1) - struct ifaddrs *ifap, *ifa; - struct sockaddr_in *sa; - getifaddrs (&ifap); // get the info - for (ifa = ifap; ifa; ifa = ifa->ifa_next) - { - if (ifa->ifa_addr->sa_family==AF_INET) - { - sa = (struct sockaddr_in *) ifa->ifa_addr; - - // This interface is ours - if (ntohl(sa->sin_addr.s_addr) == sender.getIP()) - sender.setIP(0x7f000001); // 127.0.0.1 - } - } - freeifaddrs(ifap); -#else - // Query the list of all IP addresses on the local host - // First call to GetIpAddrTable with 0 bytes buffer - // will return insufficient buffer error, and size - // will contain the number of bytes needed for all - // data. Repeat the process of querying the size - // using GetIpAddrTable in a while loop since it - // can happen that an interface comes online between - // the previous call to GetIpAddrTable and the next - // call. - MIB_IPADDRTABLE *table = NULL; - unsigned long size = 0; - int error = GetIpAddrTable(table, &size, 0); - // Also add a count to limit the while loop - in - // case that something strange is going on. - int count = 0; - while(error==ERROR_INSUFFICIENT_BUFFER && count < 10) - { - delete[] table; // deleting NULL is legal - table = (MIB_IPADDRTABLE*)new char[size]; - error = GetIpAddrTable(table, &size, 0); - count ++; - } // while insufficient buffer - for(unsigned int i=0; idwNumEntries; i++) - { - unsigned int ip = ntohl(table->table[i].dwAddr); - if(sender.getIP() == ip) // this interface is ours - { - sender.setIP(0x7f000001); // 127.0.0.1 - break; - } - } - delete[] table; - -#endif - m_server_address.copy(sender); - m_state = CONNECTING; - } + Log::info("ConnectToServer", + "Server appears to be in the same LAN."); + } + m_state = REQUESTING_CONNECTION; + m_current_protocol_id = + m_listener->requestStart( + new RequestConnection(m_server_id)); + } + break; + case REQUESTING_CONNECTION: + if (m_listener->getProtocolState(m_current_protocol_id) == + PROTOCOL_STATE_TERMINATED) + { + // Server knows we want to connect + Log::info("ConnectToServer", "Connection request made"); + if (m_server_address.getIP() == 0 || + m_server_address.getPort() == 0 ) + { + // server data not correct, hide address and stop + m_state = HIDING_ADDRESS; + Log::error("ConnectToServer", "Server address is %s", + m_server_address.toString().c_str()); + m_current_protocol_id = + m_listener->requestStart(new HidePublicAddress()); + return; + } + if (m_server_address.getIP() == NetworkManager::getInstance() + ->getPublicAddress().getIP()) + { + // we're in the same lan (same public ip address) !! + handleSameLAN(); } else { m_state = CONNECTING; - m_current_protocol_id = m_listener->requestStart(new PingProtocol(m_server_address, 2.0)); + m_current_protocol_id = m_listener->requestStart( + new PingProtocol(m_server_address, 2.0)); } } break; @@ -262,20 +200,27 @@ void ConnectToServer::asynchronousUpdate() case CONNECTED: { Log::info("ConnectToServer", "Connected"); - m_listener->requestTerminate( m_listener->getProtocol(m_current_protocol_id)); // kill the ping protocol because we're connected - m_current_protocol_id = m_listener->requestStart(new HidePublicAddress()); + // Kill the ping protocol because we're connected + m_listener->requestTerminate( + m_listener->getProtocol(m_current_protocol_id)); + m_current_protocol_id = + m_listener->requestStart(new HidePublicAddress()); ClientNetworkManager::getInstance()->setConnected(true); m_state = HIDING_ADDRESS; break; } case HIDING_ADDRESS: if (m_listener->getProtocolState(m_current_protocol_id) - == PROTOCOL_STATE_TERMINATED) // we have hidden our address + == PROTOCOL_STATE_TERMINATED) // we have hidden our address { Log::info("ConnectToServer", "Address hidden"); m_state = DONE; - if (ClientNetworkManager::getInstance()->isConnected()) // lobby room protocol if we're connected only - m_listener->requestStart(new ClientLobbyRoomProtocol(m_server_address)); + // lobby room protocol if we're connected only + if (ClientNetworkManager::getInstance()->isConnected()) + { + m_listener->requestStart( + new ClientLobbyRoomProtocol(m_server_address)); + } } break; case DONE: @@ -288,4 +233,88 @@ void ConnectToServer::asynchronousUpdate() } // ---------------------------------------------------------------------------- +/** Called when the server is on the same LAN. It uses broadcast to + * find and conntect to the server. + */ +void ConnectToServer::handleSameLAN() +{ + // just send a broadcast packet, the client will know our + // ip address and will connect + STKHost* host = NetworkManager::getInstance()->getHost(); + host->stopListening(); // stop the listening + TransportAddress broadcast_address; + broadcast_address.setIP(-1); // 255.255.255.255 + broadcast_address.setPort(7321); + char data2[] = "aloha_stk\0"; + host->sendRawPacket((uint8_t*)(data2), 10, broadcast_address); + + Log::info("ConnectToServer", "Waiting broadcast message."); + + TransportAddress sender; + // get the sender + const uint8_t* received_data = host->receiveRawPacket(&sender); + + host->startListening(); // start listening again + const char data[] = "aloha_stk\0"; + if (strcmp(data, (char*)(received_data)) == 0) + { + Log::info("ConnectToServer", "LAN Server found : %s", + sender.toString().c_str()); +#ifndef WIN32 + // just check if the ip is ours : if so, + // then just use localhost (127.0.0.1) + struct ifaddrs *ifap, *ifa; + struct sockaddr_in *sa; + getifaddrs(&ifap); // get the info + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr->sa_family == AF_INET) + { + sa = (struct sockaddr_in *) ifa->ifa_addr; + + // This interface is ours + if (ntohl(sa->sin_addr.s_addr) == sender.getIP()) + sender.setIP(0x7f000001); // 127.0.0.1 + } + } + freeifaddrs(ifap); +#else + // Query the list of all IP addresses on the local host + // First call to GetIpAddrTable with 0 bytes buffer + // will return insufficient buffer error, and size + // will contain the number of bytes needed for all + // data. Repeat the process of querying the size + // using GetIpAddrTable in a while loop since it + // can happen that an interface comes online between + // the previous call to GetIpAddrTable and the next + // call. + MIB_IPADDRTABLE *table = NULL; + unsigned long size = 0; + int error = GetIpAddrTable(table, &size, 0); + // Also add a count to limit the while loop - in + // case that something strange is going on. + int count = 0; + while (error == ERROR_INSUFFICIENT_BUFFER && count < 10) + { + delete[] table; // deleting NULL is legal + table = (MIB_IPADDRTABLE*)new char[size]; + error = GetIpAddrTable(table, &size, 0); + count++; + } // while insufficient buffer + for (unsigned int i = 0; i < table->dwNumEntries; i++) + { + unsigned int ip = ntohl(table->table[i].dwAddr); + if (sender.getIP() == ip) // this interface is ours + { + sender.setIP(0x7f000001); // 127.0.0.1 + break; + } + } + delete[] table; + +#endif + m_server_address.copy(sender); + m_state = CONNECTING; + } +} // handleSameLAN diff --git a/src/network/protocols/connect_to_server.hpp b/src/network/protocols/connect_to_server.hpp index d41c8147e..f2979a49b 100644 --- a/src/network/protocols/connect_to_server.hpp +++ b/src/network/protocols/connect_to_server.hpp @@ -21,41 +21,46 @@ #include "network/protocol.hpp" #include "network/types.hpp" +#include "utils/cpp2011.hpp" #include class ConnectToServer : public Protocol, public CallbackObject { - public: - ConnectToServer(); //!< Quick join - ConnectToServer(uint32_t server_id, uint32_t host_id); //!< Specify server id - virtual ~ConnectToServer(); +private: + TransportAddress m_server_address; + uint32_t m_server_id; + uint32_t m_host_id; + uint32_t m_current_protocol_id; + bool m_quick_join; - virtual bool notifyEventAsynchronous(Event* event); - virtual void setup(); - virtual void update() {} - virtual void asynchronousUpdate(); + enum State + { + NONE, + GETTING_SELF_ADDRESS, + SHOWING_SELF_ADDRESS, + GETTING_SERVER_ADDRESS, + REQUESTING_CONNECTION, + CONNECTING, + CONNECTED, + HIDING_ADDRESS, + DONE, + EXITING + }; + /** State for finite state machine. */ + State m_state; - protected: - TransportAddress m_server_address; - uint32_t m_server_id; - uint32_t m_host_id; - uint32_t m_current_protocol_id; - bool m_quick_join; + void handleSameLAN(); - enum STATE - { - NONE, - GETTING_SELF_ADDRESS, - SHOWING_SELF_ADDRESS, - GETTING_SERVER_ADDRESS, - REQUESTING_CONNECTION, - CONNECTING, - CONNECTED, - HIDING_ADDRESS, - DONE, - EXITING - }; - STATE m_state; -}; +public: + ConnectToServer(); + ConnectToServer(uint32_t server_id, uint32_t host_id); + virtual ~ConnectToServer(); + + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; + virtual void setup() OVERRIDE; + virtual void asynchronousUpdate(); + virtual void update() OVERRIDE {} + +}; // class ConnectToServer #endif // CONNECT_TO_SERVER_HPP