From ff8fda6219d79873dd2aaaa672ab51c7f962d191 Mon Sep 17 00:00:00 2001 From: hilnius Date: Thu, 5 Sep 2013 20:19:44 +0000 Subject: [PATCH] cleaning way of stopping the listening thread (now uses a mutex locked/unlocked) Fixed some other bugs. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/hilnius@13633 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- src/network/protocols/connect_to_server.cpp | 10 +-- src/network/protocols/get_public_address.cpp | 8 +- src/network/protocols/get_public_address.hpp | 1 + src/network/stk_host.cpp | 78 ++++++++++++++------ src/network/stk_host.hpp | 7 ++ 5 files changed, 73 insertions(+), 31 deletions(-) diff --git a/src/network/protocols/connect_to_server.cpp b/src/network/protocols/connect_to_server.cpp index 6a60aeeee..208bedabd 100644 --- a/src/network/protocols/connect_to_server.cpp +++ b/src/network/protocols/connect_to_server.cpp @@ -161,7 +161,6 @@ void ConnectToServer::asynchronousUpdate() { // just send a broadcast packet, the client will know our ip address and will connect STKHost* host = NetworkManager::getInstance()->getHost(); - NetworkManager::getInstance()->setManualSocketsMode(true); TransportAddress sender; Log::info("ConnectToServer", "Waiting broadcast message."); const uint8_t* received_data = host->receiveRawPacket(&sender); // get the sender @@ -173,9 +172,11 @@ void ConnectToServer::asynchronousUpdate() // 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); - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family==AF_INET) { + 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 (turnEndianness(sa->sin_addr.s_addr) == sender.ip) // this interface is ours sender.ip = 0x7f000001; // 127.0.0.1 @@ -220,7 +221,6 @@ void ConnectToServer::asynchronousUpdate() m_server_address = sender; m_state = CONNECTING; } - NetworkManager::getInstance()->setManualSocketsMode(false); } else { diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index c6549ef9a..6a3ed5d01 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -125,8 +125,9 @@ void GetPublicAddress::asynchronousUpdate() struct sockaddr_in* current_interface = (struct sockaddr_in*)(p->ai_addr); m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr); - NetworkManager::getInstance()->setManualSocketsMode(true); - NetworkManager::getInstance()->getHost()->sendRawPacket(bytes, 20, TransportAddress(m_stun_server_ip, 3478)); + m_transaction_host = new STKHost(); + m_transaction_host->setupClient(1,1,0,0); + m_transaction_host->sendRawPacket(bytes, 20, TransportAddress(m_stun_server_ip, 3478)); m_state = TEST_SENT; freeaddrinfo(res); // free the linked list @@ -137,7 +138,7 @@ void GetPublicAddress::asynchronousUpdate() } if (m_state == TEST_SENT) { - uint8_t* data = NetworkManager::getInstance()->getHost()->receiveRawPacket(TransportAddress(m_stun_server_ip, 3478), 2000); + uint8_t* data = m_transaction_host->receiveRawPacket(TransportAddress(m_stun_server_ip, 3478), 2000); if (!data) { m_state = NOTHING_DONE; // will send the test again to an other server @@ -220,7 +221,6 @@ void GetPublicAddress::asynchronousUpdate() { Log::debug("GetPublicAddress", "The public address has been found : %i.%i.%i.%i:%i", address>>24&0xff, address>>16&0xff, address>>8&0xff, address&0xff, port); m_state = ADDRESS_KNOWN; - NetworkManager::getInstance()->setManualSocketsMode(false); TransportAddress* addr = static_cast(m_callback_object); addr->ip = address; addr->port = port; diff --git a/src/network/protocols/get_public_address.hpp b/src/network/protocols/get_public_address.hpp index 442758791..408a031ba 100644 --- a/src/network/protocols/get_public_address.hpp +++ b/src/network/protocols/get_public_address.hpp @@ -45,6 +45,7 @@ class GetPublicAddress : public Protocol uint32_t m_stun_tansaction_id[3]; static const uint32_t m_stun_magic_cookie = 0x2112A442; uint32_t m_stun_server_ip; + STKHost* m_transaction_host; }; #endif // GET_PUBLIC_ADDRESS_HPP diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index d09b2b3f2..f2dd27dff 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -37,8 +37,9 @@ void* STKHost::receive_data(void* self) { ENetEvent event; - ENetHost* host = (((STKHost*)(self))->m_host); - while (1) + STKHost* myself = (STKHost*)(self); + ENetHost* host = myself->m_host; + while (!myself->mustStopListening()) { while (enet_host_service(host, &event, 20) != 0) { Event* evt = new Event(&event); @@ -47,6 +48,9 @@ void* STKHost::receive_data(void* self) delete evt; } } + myself->m_listening = false; + delete myself->m_listening_thread; + myself->m_listening_thread = NULL; return NULL; } @@ -56,18 +60,14 @@ STKHost::STKHost() { m_host = NULL; m_listening_thread = NULL; + pthread_mutex_init(&m_exit_mutex, NULL); } // ---------------------------------------------------------------------------- STKHost::~STKHost() { - if (m_listening_thread) - { - pthread_cancel(*m_listening_thread);//, SIGKILL); with kill - delete m_listening_thread; - m_listening_thread = NULL; - } + stopListening(); if (m_host) { enet_host_destroy(m_host); @@ -84,6 +84,13 @@ void STKHost::setupServer(uint32_t address, uint16_t port, int peer_count, addr->host = address; addr->port = port; +#ifdef WIN32/* + addr->host = 0; + addr->host += ((unsigned int)(192)<<0); // 192.168.0.11 + addr->host += ((unsigned int)(168)<<8); // 192.168.0.11 + addr->host += ((unsigned int)(11)<<24); // 192.168.0.11*/ +#endif + m_host = enet_host_create(addr, peer_count, channel_limit, max_incoming_bandwidth, max_outgoing_bandwidth); if (m_host == NULL) @@ -114,8 +121,10 @@ void STKHost::setupClient(int peer_count, int channel_limit, void STKHost::startListening() { + pthread_mutex_lock(&m_exit_mutex); // will let the update function start m_listening_thread = (pthread_t*)(malloc(sizeof(pthread_t))); pthread_create(m_listening_thread, NULL, &STKHost::receive_data, this); + m_listening = true; } // ---------------------------------------------------------------------------- @@ -124,8 +133,7 @@ void STKHost::stopListening() { if(m_listening_thread) { - pthread_cancel(*m_listening_thread); - m_listening_thread = NULL; + pthread_mutex_unlock(&m_exit_mutex); // will stop the update function } } @@ -182,12 +190,16 @@ uint8_t* STKHost::receiveRawPacket(TransportAddress* sender) int i = 0; // wait to receive the message because enet sockets are non-blocking - while(len < 0) + while(len == -1) // nothing received { i++; len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, &addr, &from_len); Time::sleep(1); // wait 1 millisecond between two checks } + if (len == SOCKET_ERROR) + { + Log::error("STKHost", "Problem with the socket. Please contact the dev team."); + } struct sockaddr_in *sin = (struct sockaddr_in *) (&addr); // we received the data sender->ip = turnEndianness((uint32_t)(sin->sin_addr.s_addr)); @@ -211,32 +223,40 @@ uint8_t* STKHost::receiveRawPacket(TransportAddress sender, int max_tries) memset(buffer, 0, 2048); socklen_t from_len; - struct sockaddr addr; + struct sockaddr_in addr; from_len = sizeof(addr); - int len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, &addr, &from_len); + int len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, (struct sockaddr*)(&addr), &from_len); int i = 0; // wait to receive the message because enet sockets are non-blocking - while(len < 0 || ( - (uint8_t)(addr.sa_data[2]) != (sender.ip>>24&0xff) - && (uint8_t)(addr.sa_data[3]) != (sender.ip>>16&0xff) - && (uint8_t)(addr.sa_data[4]) != (sender.ip>>8&0xff) - && (uint8_t)(addr.sa_data[5]) != (sender.ip&0xff))) + while(len < 0 || addr.sin_addr.s_addr == sender.ip) { i++; - len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, &addr, &from_len); + if (len>=0) + { + Log::info("STKHost", "Message received but the ip address didn't match the expected one."); + } + len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, (struct sockaddr*)(&addr), &from_len); + uint32_t addr1 = addr.sin_addr.s_addr; + uint32_t addr2 = sender.ip; + uint32_t addr3 = ntohl(addr1); + uint32_t addr4 = ntohl(addr2); Time::sleep(1); // wait 1 millisecond between two checks if (i >= max_tries && max_tries != -1) { - Log::verbose("STKHost", "No answer from the server."); + Log::verbose("STKHost", "No answer from the server on %u.%u.%u.%u:%u", (m_host->address.host&0xff), + (m_host->address.host>>8&0xff), + (m_host->address.host>>16&0xff), + (m_host->address.host>>24&0xff), + (m_host->address.port)); return NULL; } } - if (addr.sa_family == AF_INET) + if (addr.sin_family == AF_INET) { char s[20]; - inet_ntop(AF_INET, &(((struct sockaddr_in *)&addr)->sin_addr), s, 20); + inet_ntop(AF_INET, &(addr.sin_addr), s, 20); Log::info("STKHost", "IPv4 Address of the sender was %s", s); } return buffer; @@ -281,3 +301,17 @@ bool STKHost::isConnectedTo(TransportAddress peer) } return false; } + +// --------------------------------------------------------------------------- + +int STKHost::mustStopListening() +{ + switch(pthread_mutex_trylock(&m_exit_mutex)) { + case 0: /* if we got the lock, unlock and return 1 (true) */ + pthread_mutex_unlock(&m_exit_mutex); + return 1; + case EBUSY: /* return 0 (false) if the mutex was locked */ + return 0; + } + return 1; +} \ No newline at end of file diff --git a/src/network/stk_host.hpp b/src/network/stk_host.hpp index ac9466127..9d1067713 100644 --- a/src/network/stk_host.hpp +++ b/src/network/stk_host.hpp @@ -140,9 +140,16 @@ class STKHost * \return True if the peer is known and connected, false elseway. */ bool isConnectedTo(TransportAddress peer_address); + + /*! \brief Returns true when the thread should stop listening. */ + int mustStopListening(); + /*! \brief Returns true when the thread has stopped listening. */ + bool hasStoppedListening() { return m_listening; } protected: ENetHost* m_host; //!< ENet host interfacing sockets. pthread_t* m_listening_thread; //!< Thread listening network events. + pthread_mutex_t m_exit_mutex; //!< Mutex to kill properly the thread + bool m_listening; };