/** \brief Thread function checking if data is received. * This function tries to get data from network low-level functions as * often as possible. When something is received, it generates an * event and passes it to the Network Manager. * \param self : used to pass the ENet host to the function. */ void* STKHost::mainLoop(void* self) { VS::setThreadName("STKHost"); ENetEvent event; STKHost* myself = (STKHost*)(self); ENetHost* host = myself->m_network->getENetHost(); if(NetworkConfig::get()->isServer() && NetworkConfig::get()->isLAN() ) { TransportAddress address(0, 2757); ENetAddress eaddr = address.toEnetAddress(); myself->m_lan_network = new Network(1, 1, 0, 0, &eaddr); } while (!myself->mustStopListening()) { if(myself->m_lan_network) { myself->handleLANRequests(); } // if discovery host while (enet_host_service(host, &event, 20) != 0) { if (event.type == ENET_EVENT_TYPE_NONE) continue; // Create an STKEvent with the event data. This will also // create the peer if it doesn't exist already Event* stk_event = new Event(&event); if (stk_event->getType() == EVENT_TYPE_MESSAGE) Network::logPacket(stk_event->data(), true); Log::verbose("STKHost", "Event of type %d received", (int)(stk_event->getType())); STKPeer* peer = stk_event->getPeer(); if (stk_event->getType() == EVENT_TYPE_CONNECTED) { Log::info("STKHost", "A client has just connected. There are " "now %lu peers.", myself->m_peers.size()); Log::debug("STKHost", "Addresses are : %lx, %lx", stk_event->getPeer(), peer); } // EVENT_TYPE_CONNECTED else if (stk_event->getType() == EVENT_TYPE_MESSAGE) { TransportAddress stk_addr(peer->getAddress()); Log::verbose("NetworkManager", "Message, Sender : %s, message = \"%s\"", stk_addr.toString(/*show port*/false).c_str(), stk_event->data().std_string().c_str()); } // if message event // notify for the event now. ProtocolManager::getInstance()->propagateEvent(stk_event); } // while enet_host_service } // while !mustStopListening free(myself->m_listening_thread); myself->m_listening_thread = NULL; Log::info("STKHost", "Listening has been stopped"); return NULL; } // mainLoop
void ConnectToServer::asynchronousUpdate() { switch(m_state) { case NONE: { Log::info("ConnectToServer", "Protocol starting"); m_current_protocol_id = m_listener->requestStart(new GetPublicAddress(&m_public_address)); 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 { m_state = SHOWING_SELF_ADDRESS; NetworkManager::getInstance()->setPublicAddress(m_public_address); // set our public address 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 { 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_state = REQUESTING_CONNECTION; } else { 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 { Log::info("ConnectToServer", "Server's address known"); if (m_server_address.ip == m_public_address.ip) // we're in the same lan (same public ip address) !! 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.ip == 0 || m_server_address.port == 0) { // server data not correct, hide address and stop m_state = HIDING_ADDRESS; Log::error("ConnectToServer", "Server address is "ADDRESS_FORMAT, ADDRESS_ARGS(m_server_address.ip, m_server_address.port)); m_current_protocol_id = m_listener->requestStart(new HidePublicAddress()); return; } if (m_server_address.ip == m_public_address.ip) // we're in the same lan (same public ip address) !! { // 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.ip = -1; // 255.255.255.255 broadcast_address.port = 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 : %u:%u", sender.ip, sender.port); #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; if (ntohl(sa->sin_addr.s_addr) == sender.ip) // this interface is ours sender.ip = 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++) { int ip = ntohl(table->table[i].dwAddr); if(sender.ip == ip) // this interface is ours { sender.ip = 0x7f000001; // 127.0.0.1 break; } } delete[] table; #endif m_server_address = sender; m_state = CONNECTING; } } else { m_state = CONNECTING; m_current_protocol_id = m_listener->requestStart(new PingProtocol(m_server_address, 2.0)); } } break; case CONNECTING: // waiting the server to answer our connection { static double timer = 0; if (StkTime::getRealTime() > timer+5.0) // every 5 seconds { timer = StkTime::getRealTime(); NetworkManager::getInstance()->connect(m_server_address); Log::info("ConnectToServer", "Trying to connect to %u:%u", m_server_address.ip, m_server_address.port); } break; } 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()); 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 { 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)); } break; case DONE: m_listener->requestTerminate(this); m_state = EXITING; break; case EXITING: break; } }
/** 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 = STKHost::get(); host->stopListening(); // stop the listening Log::info("ConnectToServer", "Waiting broadcast message."); TransportAddress sender; // get the sender const int LEN=256; char buffer[LEN]; int len = host->receiveRawPacket(buffer, LEN, &sender, 2000); if(len<0) { Log::warn("ConnectToServer", "Received invalid server information message."); return; } BareNetworkString message(buffer, len); std::string received; message.decodeString(&received); host->startListening(); // start listening again std::string aloha("aloha_stk"); if (received==aloha) { 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