From ee06cd3ba2e83e92890930f9469e276d8ed9ea5c Mon Sep 17 00:00:00 2001 From: konstin Date: Sat, 8 Aug 2015 13:58:21 +0200 Subject: [PATCH 1/7] Improve readability and add documentation for GetPublicAddress::asynchronousUpdate() --- src/network/protocols/get_public_address.cpp | 173 ++++++++++--------- 1 file changed, 90 insertions(+), 83 deletions(-) diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index 7034217df..f095b15f7 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -68,8 +68,14 @@ void GetPublicAddress::setup() m_state = NOTHING_DONE; } +/** Detects public IP-address and port by first sending a request to a randomly + * selected STUN server and then parsing and validating the response */ void GetPublicAddress::asynchronousUpdate() { + // Creates a request and sends it to a random STUN server randomly slected + // from the list saved in the config file + // The request is send through m_transaction_host, from which the answer + // can be retrieved if (m_state == NOTHING_DONE) { // format : 00MMMMMCMMMCMMMM (cf rfc 5389) @@ -129,7 +135,7 @@ void GetPublicAddress::asynchronousUpdate() Log::error("getaddrinfo", gai_strerror(status)); return; } - for(p = res;p != NULL; p = p->ai_next) + for (p = res; p != NULL; p = p->ai_next) { struct sockaddr_in* current_interface = (struct sockaddr_in*)(p->ai_addr); @@ -145,6 +151,8 @@ void GetPublicAddress::asynchronousUpdate() freeaddrinfo(res); // free the linked list } + // Gets the response from the STUN server, checks it for its validity and + // then parses the answer into address and port if (m_state == TEST_SENT) { uint8_t* data = m_transaction_host->receiveRawPacket(TransportAddress(m_stun_server_ip, 3478), 2000); @@ -153,96 +161,95 @@ void GetPublicAddress::asynchronousUpdate() m_state = NOTHING_DONE; // will send the test again to an other server return; } - assert(data); // check that the stun response is a response, contains the magic cookie and the transaction ID - if ( data[0] == 0x01 && - data[1] == 0x01 && - data[4] == (uint8_t)(m_stun_magic_cookie>>24) && - data[5] == (uint8_t)(m_stun_magic_cookie>>16) && - data[6] == (uint8_t)(m_stun_magic_cookie>>8) && - data[7] == (uint8_t)(m_stun_magic_cookie) ) + if (data[0] != 0x01 || + data[1] != 0x01 || + data[4] != (uint8_t)(m_stun_magic_cookie>>24) || + data[5] != (uint8_t)(m_stun_magic_cookie>>16) || + data[6] != (uint8_t)(m_stun_magic_cookie>>8) || + data[7] != (uint8_t)(m_stun_magic_cookie)) { - if( - data[8] == (uint8_t)(m_stun_tansaction_id[0]>>24) && - data[9] == (uint8_t)(m_stun_tansaction_id[0]>>16) && - data[10] == (uint8_t)(m_stun_tansaction_id[0]>>8 ) && - data[11] == (uint8_t)(m_stun_tansaction_id[0] ) && - data[12] == (uint8_t)(m_stun_tansaction_id[1]>>24) && - data[13] == (uint8_t)(m_stun_tansaction_id[1]>>16) && - data[14] == (uint8_t)(m_stun_tansaction_id[1]>>8 ) && - data[15] == (uint8_t)(m_stun_tansaction_id[1] ) && - data[16] == (uint8_t)(m_stun_tansaction_id[2]>>24) && - data[17] == (uint8_t)(m_stun_tansaction_id[2]>>16) && - data[18] == (uint8_t)(m_stun_tansaction_id[2]>>8 ) && - data[19] == (uint8_t)(m_stun_tansaction_id[2] )) - { - Log::verbose("GetPublicAddress", "The STUN server responded with a valid answer"); - int message_size = data[2]*256+data[3]; + return; // invalid data -> try again + } - // parse the stun message now: - bool finish = false; - uint8_t* attributes = data+20; - if (message_size == 0) - { - Log::error("GetPublicAddress", "STUN answer does not contain any information."); - finish = true; - } - if (message_size < 4) // cannot even read the size - { - Log::error("GetPublicAddress", "STUN message is not valid."); - finish = true; - } - uint16_t port; - uint32_t address; - bool valid = false; - while(!finish) - { - int type = attributes[0]*256+attributes[1]; - int size = attributes[2]*256+attributes[3]; - switch(type) - { - case 0: - case 1: - assert(size == 8); - assert(attributes[5] == 0x01); // IPv4 only - port = attributes[6]*256+attributes[7]; - address = (attributes[8]<<24 & 0xFF000000)+(attributes[9]<<16 & 0x00FF0000)+(attributes[10]<<8 & 0x0000FF00)+(attributes[11] & 0x000000FF); - finish = true; - valid = true; - continue; - break; - default: - break; - } - attributes = attributes + 4 + size; - message_size -= 4 + size; - if (message_size == 0) - finish = true; - if (message_size < 4) // cannot even read the size - { - Log::error("GetPublicAddress", "STUN message is not valid."); - finish = true; - } - } - // finished parsing, we know our public transport address - if (valid) - { - 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; - TransportAddress* addr = static_cast(m_callback_object); - addr->ip = address; - addr->port = port; - } - else - m_state = NOTHING_DONE; // need to re-send the stun request - } - else + if (data[8] != (uint8_t)(m_stun_tansaction_id[0]>>24) || + data[9] != (uint8_t)(m_stun_tansaction_id[0]>>16) || + data[10] != (uint8_t)(m_stun_tansaction_id[0]>>8 ) || + data[11] != (uint8_t)(m_stun_tansaction_id[0] ) || + data[12] != (uint8_t)(m_stun_tansaction_id[1]>>24) || + data[13] != (uint8_t)(m_stun_tansaction_id[1]>>16) || + data[14] != (uint8_t)(m_stun_tansaction_id[1]>>8 ) || + data[15] != (uint8_t)(m_stun_tansaction_id[1] ) || + data[16] != (uint8_t)(m_stun_tansaction_id[2]>>24) || + data[17] != (uint8_t)(m_stun_tansaction_id[2]>>16) || + data[18] != (uint8_t)(m_stun_tansaction_id[2]>>8 ) || + data[19] != (uint8_t)(m_stun_tansaction_id[2] )) + { + m_state = NOTHING_DONE; // need to re-send the stun request + Log::warn("GetPublicAddress", "The STUN server responded with a invalid answer"); + return; + } + + Log::verbose("GetPublicAddress", "The STUN server responded with a valid answer"); + int message_size = data[2]*256+data[3]; + + // The stun message is valid, so we parse it now: + bool finish = false; + uint8_t* attributes = data+20; + if (message_size == 0) + { + Log::error("GetPublicAddress", "STUN answer does not contain any information."); + finish = true; + } + if (message_size < 4) // cannot even read the size + { + Log::error("GetPublicAddress", "STUN message is not valid."); + finish = true; + } + + // This are the address and port that is wanted + uint16_t port; + uint32_t address; + bool valid = false; + while(!finish) + { + int type = attributes[0]*256+attributes[1]; + int size = attributes[2]*256+attributes[3]; + if (type == 0 || type == 1) { - m_state = NOTHING_DONE; // need to re-send the stun request + assert(size == 8); + assert(attributes[5] == 0x01); // IPv4 only + port = attributes[6]*256+attributes[7]; + // The (IPv4) address was sent as 4 distinct bytes, but needs to be pack into one 4-byte int + address = (attributes[8]<<24 & 0xFF000000) + (attributes[9]<<16 & 0x00FF0000) + (attributes[10]<<8 & 0x0000FF00) + (attributes[11] & 0x000000FF); + finish = true; + valid = true; + continue; } + attributes = attributes + 4 + size; + message_size -= 4 + size; + if (message_size == 0) + finish = true; + if (message_size < 4) // cannot even read the size + finish = true; + } + // finished parsing, we know our public transport address + if (valid) + { + 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; + TransportAddress* addr = static_cast(m_callback_object); + addr->ip = address; + addr->port = port; + } + else + { + Log::error("GetPublicAddress", "STUN message is not valid."); + m_state = NOTHING_DONE; // need to re-send the stun request } } + // The address and the port are known, so the connection can be closed if (m_state == ADDRESS_KNOWN) { m_state = EXITING; From 5ec9fa38ab627115bb834501bbe1327ea6892d49 Mon Sep 17 00:00:00 2001 From: konstin Date: Sat, 8 Aug 2015 15:03:35 +0200 Subject: [PATCH 2/7] Implement a consistent error managing for GetPublicAddress::asynchronousUpdate() by moving the STUN response parsing into its own function --- src/network/protocols/get_public_address.cpp | 198 +++++++++---------- src/network/protocols/get_public_address.hpp | 5 + 2 files changed, 100 insertions(+), 103 deletions(-) diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index f095b15f7..433ae8844 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -29,6 +29,8 @@ #include +#include + #ifdef __MINGW32__ # undef _WIN32_WINNT # define _WIN32_WINNT 0x501 @@ -68,6 +70,94 @@ void GetPublicAddress::setup() m_state = NOTHING_DONE; } +/** + * Gets the response from the STUN server, checks it for its validity and + * then parses the answer into address and port + * \return "" if the adress could be parsed or an error message +*/ +std::string GetPublicAddress::parseResponse() +{ + uint8_t* data = m_transaction_host->receiveRawPacket(TransportAddress(m_stun_server_ip, 3478), 2000); + if (!data) + return "STUN response contains no data at all"; + + // check that the stun response is a response, contains the magic cookie and the transaction ID + if (data[0] != 0x01 || + data[1] != 0x01 || + data[4] != (uint8_t)(m_stun_magic_cookie>>24) || + data[5] != (uint8_t)(m_stun_magic_cookie>>16) || + data[6] != (uint8_t)(m_stun_magic_cookie>>8) || + data[7] != (uint8_t)(m_stun_magic_cookie)) + { + return "STUN response doesn't contain the magic cookie"; + } + + if (data[8] != (uint8_t)(m_stun_tansaction_id[0]>>24) || + data[9] != (uint8_t)(m_stun_tansaction_id[0]>>16) || + data[10] != (uint8_t)(m_stun_tansaction_id[0]>>8 ) || + data[11] != (uint8_t)(m_stun_tansaction_id[0] ) || + data[12] != (uint8_t)(m_stun_tansaction_id[1]>>24) || + data[13] != (uint8_t)(m_stun_tansaction_id[1]>>16) || + data[14] != (uint8_t)(m_stun_tansaction_id[1]>>8 ) || + data[15] != (uint8_t)(m_stun_tansaction_id[1] ) || + data[16] != (uint8_t)(m_stun_tansaction_id[2]>>24) || + data[17] != (uint8_t)(m_stun_tansaction_id[2]>>16) || + data[18] != (uint8_t)(m_stun_tansaction_id[2]>>8 ) || + data[19] != (uint8_t)(m_stun_tansaction_id[2] )) + { + return "STUN response doesn't contain the transaction ID"; + } + + Log::verbose("GetPublicAddress", "The STUN server responded with a valid answer"); + int message_size = data[2]*256+data[3]; + + // The stun message is valid, so we parse it now: + uint8_t* attributes = data+20; + if (message_size == 0) + return "STUN response does not contain any information."; + if (message_size < 4) // cannot even read the size + return "STUN response is too short."; + + + // Those are the port and the address to be detected + uint16_t port; + uint32_t address; + while(true) + { + int type = attributes[0]*256+attributes[1]; + int size = attributes[2]*256+attributes[3]; + if (type == 0 || type == 1) + { + assert(size == 8); + assert(attributes[5] == 0x01); // IPv4 only + port = attributes[6]*256+attributes[7]; + // The (IPv4) address was sent as 4 distinct bytes, but needs to be packed into one 4-byte int + address = (attributes[8]<<24 & 0xFF000000) + (attributes[9]<<16 & 0x00FF0000) + (attributes[10]<<8 & 0x0000FF00) + (attributes[11] & 0x000000FF); + break; + } + attributes = attributes + 4 + size; + message_size -= 4 + size; + if (message_size == 0) + return "STUN response is invalid."; + if (message_size < 4) // cannot even read the size + return "STUN response is invalid."; + } + + // finished parsing, we know our public transport address + 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); + TransportAddress* addr = static_cast(m_callback_object); + addr->ip = address; + addr->port = port; + + // The address and the port are known, so the connection can be closed + m_state = EXITING; + // terminate the protocol + m_listener->requestTerminate(this); + + return ""; +} + + /** Detects public IP-address and port by first sending a request to a randomly * selected STUN server and then parsing and validating the response */ void GetPublicAddress::asynchronousUpdate() @@ -151,112 +241,14 @@ void GetPublicAddress::asynchronousUpdate() freeaddrinfo(res); // free the linked list } - // Gets the response from the STUN server, checks it for its validity and - // then parses the answer into address and port + if (m_state == TEST_SENT) { - uint8_t* data = m_transaction_host->receiveRawPacket(TransportAddress(m_stun_server_ip, 3478), 2000); - if (!data) + std::string message = parseResponse(); + if (message != "") { - m_state = NOTHING_DONE; // will send the test again to an other server - return; + Log::warn("GetPublicAddress", "%s", message.c_str()); + m_state = NOTHING_DONE; } - - // check that the stun response is a response, contains the magic cookie and the transaction ID - if (data[0] != 0x01 || - data[1] != 0x01 || - data[4] != (uint8_t)(m_stun_magic_cookie>>24) || - data[5] != (uint8_t)(m_stun_magic_cookie>>16) || - data[6] != (uint8_t)(m_stun_magic_cookie>>8) || - data[7] != (uint8_t)(m_stun_magic_cookie)) - { - return; // invalid data -> try again - } - - if (data[8] != (uint8_t)(m_stun_tansaction_id[0]>>24) || - data[9] != (uint8_t)(m_stun_tansaction_id[0]>>16) || - data[10] != (uint8_t)(m_stun_tansaction_id[0]>>8 ) || - data[11] != (uint8_t)(m_stun_tansaction_id[0] ) || - data[12] != (uint8_t)(m_stun_tansaction_id[1]>>24) || - data[13] != (uint8_t)(m_stun_tansaction_id[1]>>16) || - data[14] != (uint8_t)(m_stun_tansaction_id[1]>>8 ) || - data[15] != (uint8_t)(m_stun_tansaction_id[1] ) || - data[16] != (uint8_t)(m_stun_tansaction_id[2]>>24) || - data[17] != (uint8_t)(m_stun_tansaction_id[2]>>16) || - data[18] != (uint8_t)(m_stun_tansaction_id[2]>>8 ) || - data[19] != (uint8_t)(m_stun_tansaction_id[2] )) - { - m_state = NOTHING_DONE; // need to re-send the stun request - Log::warn("GetPublicAddress", "The STUN server responded with a invalid answer"); - return; - } - - Log::verbose("GetPublicAddress", "The STUN server responded with a valid answer"); - int message_size = data[2]*256+data[3]; - - // The stun message is valid, so we parse it now: - bool finish = false; - uint8_t* attributes = data+20; - if (message_size == 0) - { - Log::error("GetPublicAddress", "STUN answer does not contain any information."); - finish = true; - } - if (message_size < 4) // cannot even read the size - { - Log::error("GetPublicAddress", "STUN message is not valid."); - finish = true; - } - - // This are the address and port that is wanted - uint16_t port; - uint32_t address; - bool valid = false; - while(!finish) - { - int type = attributes[0]*256+attributes[1]; - int size = attributes[2]*256+attributes[3]; - if (type == 0 || type == 1) - { - assert(size == 8); - assert(attributes[5] == 0x01); // IPv4 only - port = attributes[6]*256+attributes[7]; - // The (IPv4) address was sent as 4 distinct bytes, but needs to be pack into one 4-byte int - address = (attributes[8]<<24 & 0xFF000000) + (attributes[9]<<16 & 0x00FF0000) + (attributes[10]<<8 & 0x0000FF00) + (attributes[11] & 0x000000FF); - finish = true; - valid = true; - continue; - } - attributes = attributes + 4 + size; - message_size -= 4 + size; - if (message_size == 0) - finish = true; - if (message_size < 4) // cannot even read the size - finish = true; - } - // finished parsing, we know our public transport address - if (valid) - { - 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; - TransportAddress* addr = static_cast(m_callback_object); - addr->ip = address; - addr->port = port; - } - else - { - Log::error("GetPublicAddress", "STUN message is not valid."); - m_state = NOTHING_DONE; // need to re-send the stun request - } - } - // The address and the port are known, so the connection can be closed - if (m_state == ADDRESS_KNOWN) - { - m_state = EXITING; - // terminate the protocol - m_listener->requestTerminate(this); - } - if (m_state == EXITING) - { } } diff --git a/src/network/protocols/get_public_address.hpp b/src/network/protocols/get_public_address.hpp index 0e7f80b7a..06dd77c9a 100644 --- a/src/network/protocols/get_public_address.hpp +++ b/src/network/protocols/get_public_address.hpp @@ -21,6 +21,8 @@ #include "network/protocol.hpp" +#include + class GetPublicAddress : public Protocol { public: @@ -46,6 +48,9 @@ class GetPublicAddress : public Protocol static const uint32_t m_stun_magic_cookie = 0x2112A442; uint32_t m_stun_server_ip; STKHost* m_transaction_host; + + private: + std::string parseResponse(); }; #endif // GET_PUBLIC_ADDRESS_HPP From 1ce3be98ee3b38bdea7bde73eb09fe97bab8cece Mon Sep 17 00:00:00 2001 From: konstin Date: Sat, 8 Aug 2015 15:06:55 +0200 Subject: [PATCH 3/7] Move the STUN request creating and sending from GetPublicAddress::asynchronousUpdate() into its own function --- src/network/protocols/get_public_address.cpp | 163 ++++++++++--------- src/network/protocols/get_public_address.hpp | 1 + 2 files changed, 84 insertions(+), 80 deletions(-) diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index 433ae8844..c4356eba1 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -73,7 +73,7 @@ void GetPublicAddress::setup() /** * Gets the response from the STUN server, checks it for its validity and * then parses the answer into address and port - * \return "" if the adress could be parsed or an error message + * \return "" if the address could be parsed or an error message */ std::string GetPublicAddress::parseResponse() { @@ -158,90 +158,93 @@ std::string GetPublicAddress::parseResponse() } +/** Creates a request and sends it to a random STUN server randomly slected + * from the list saved in the config file + * The request is send through m_transaction_host, from which the answer + * will be retrieved by parseResponse() + */ +void GetPublicAddress::createStunRequest() +{ + // format : 00MMMMMCMMMCMMMM (cf rfc 5389) + uint16_t message_type = 0x0001; // binding request + m_stun_tansaction_id[0] = stunRand(); + m_stun_tansaction_id[1] = stunRand(); + m_stun_tansaction_id[2] = stunRand(); + uint16_t message_length = 0x0000; + + uint8_t bytes[21]; // the message to be sent + // bytes 0-1 : the type of the message, + bytes[0] = (uint8_t)(message_type>>8); + bytes[1] = (uint8_t)(message_type); + + // bytes 2-3 : message length added to header (attributes) + bytes[2] = (uint8_t)(message_length>>8); + bytes[3] = (uint8_t)(message_length); + + // bytes 4-7 : magic cookie to recognize the stun protocol + bytes[4] = (uint8_t)(m_stun_magic_cookie>>24); + bytes[5] = (uint8_t)(m_stun_magic_cookie>>16); + bytes[6] = (uint8_t)(m_stun_magic_cookie>>8); + bytes[7] = (uint8_t)(m_stun_magic_cookie); + + // bytes 8-19 : the transaction id + bytes[8] = (uint8_t)(m_stun_tansaction_id[0]>>24); + bytes[9] = (uint8_t)(m_stun_tansaction_id[0]>>16); + bytes[10] = (uint8_t)(m_stun_tansaction_id[0]>>8); + bytes[11] = (uint8_t)(m_stun_tansaction_id[0]); + bytes[12] = (uint8_t)(m_stun_tansaction_id[1]>>24); + bytes[13] = (uint8_t)(m_stun_tansaction_id[1]>>16); + bytes[14] = (uint8_t)(m_stun_tansaction_id[1]>>8); + bytes[15] = (uint8_t)(m_stun_tansaction_id[1]); + bytes[16] = (uint8_t)(m_stun_tansaction_id[2]>>24); + bytes[17] = (uint8_t)(m_stun_tansaction_id[2]>>16); + bytes[18] = (uint8_t)(m_stun_tansaction_id[2]>>8); + bytes[19] = (uint8_t)(m_stun_tansaction_id[2]); + bytes[20] = '\0'; + + // time to pick a random stun server + std::vector stun_servers = UserConfigParams::m_stun_servers; + + RandomGenerator random_gen; + int rand_result = random_gen.get((int)stun_servers.size()); + Log::verbose("GetPublicAddress", "Using STUN server %s", + stun_servers[rand_result].c_str()); + + // resolve the name into an IP address + struct addrinfo hints, *res, *p; + int status; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(stun_servers[rand_result].c_str(), NULL, &hints, &res)) != 0) { + Log::error("getaddrinfo", gai_strerror(status)); + return; + } + for (p = res; p != NULL; p = p->ai_next) + { + struct sockaddr_in* current_interface = (struct sockaddr_in*)(p->ai_addr); + + m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr); + 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 + return; + } + freeaddrinfo(res); // free the linked list +} + + /** Detects public IP-address and port by first sending a request to a randomly * selected STUN server and then parsing and validating the response */ void GetPublicAddress::asynchronousUpdate() { - // Creates a request and sends it to a random STUN server randomly slected - // from the list saved in the config file - // The request is send through m_transaction_host, from which the answer - // can be retrieved if (m_state == NOTHING_DONE) - { - // format : 00MMMMMCMMMCMMMM (cf rfc 5389) - uint16_t message_type = 0x0001; // binding request - m_stun_tansaction_id[0] = stunRand(); - m_stun_tansaction_id[1] = stunRand(); - m_stun_tansaction_id[2] = stunRand(); - uint16_t message_length = 0x0000; - - uint8_t bytes[21]; // the message to be sent - // bytes 0-1 : the type of the message, - bytes[0] = (uint8_t)(message_type>>8); - bytes[1] = (uint8_t)(message_type); - - // bytes 2-3 : message length added to header (attributes) - bytes[2] = (uint8_t)(message_length>>8); - bytes[3] = (uint8_t)(message_length); - - // bytes 4-7 : magic cookie to recognize the stun protocol - bytes[4] = (uint8_t)(m_stun_magic_cookie>>24); - bytes[5] = (uint8_t)(m_stun_magic_cookie>>16); - bytes[6] = (uint8_t)(m_stun_magic_cookie>>8); - bytes[7] = (uint8_t)(m_stun_magic_cookie); - - // bytes 8-19 : the transaction id - bytes[8] = (uint8_t)(m_stun_tansaction_id[0]>>24); - bytes[9] = (uint8_t)(m_stun_tansaction_id[0]>>16); - bytes[10] = (uint8_t)(m_stun_tansaction_id[0]>>8); - bytes[11] = (uint8_t)(m_stun_tansaction_id[0]); - bytes[12] = (uint8_t)(m_stun_tansaction_id[1]>>24); - bytes[13] = (uint8_t)(m_stun_tansaction_id[1]>>16); - bytes[14] = (uint8_t)(m_stun_tansaction_id[1]>>8); - bytes[15] = (uint8_t)(m_stun_tansaction_id[1]); - bytes[16] = (uint8_t)(m_stun_tansaction_id[2]>>24); - bytes[17] = (uint8_t)(m_stun_tansaction_id[2]>>16); - bytes[18] = (uint8_t)(m_stun_tansaction_id[2]>>8); - bytes[19] = (uint8_t)(m_stun_tansaction_id[2]); - bytes[20] = '\0'; - - // time to pick a random stun server - std::vector stun_servers = UserConfigParams::m_stun_servers; - - RandomGenerator random_gen; - int rand_result = random_gen.get((int)stun_servers.size()); - Log::verbose("GetPublicAddress", "Using STUN server %s", - stun_servers[rand_result].c_str()); - - // resolve the name into an IP address - struct addrinfo hints, *res, *p; - int status; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version - hints.ai_socktype = SOCK_STREAM; - - if ((status = getaddrinfo(stun_servers[rand_result].c_str(), NULL, &hints, &res)) != 0) { - Log::error("getaddrinfo", gai_strerror(status)); - return; - } - for (p = res; p != NULL; p = p->ai_next) - { - struct sockaddr_in* current_interface = (struct sockaddr_in*)(p->ai_addr); - - m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr); - 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 - return; - } - freeaddrinfo(res); // free the linked list - - } - + createStunRequest(); if (m_state == TEST_SENT) { std::string message = parseResponse(); diff --git a/src/network/protocols/get_public_address.hpp b/src/network/protocols/get_public_address.hpp index 06dd77c9a..6897b4641 100644 --- a/src/network/protocols/get_public_address.hpp +++ b/src/network/protocols/get_public_address.hpp @@ -51,6 +51,7 @@ class GetPublicAddress : public Protocol private: std::string parseResponse(); + void createStunRequest(); }; #endif // GET_PUBLIC_ADDRESS_HPP From a4fa65673ed967b96dc8fde6b9244ba23c7d929a Mon Sep 17 00:00:00 2001 From: konstin Date: Sat, 8 Aug 2015 20:16:43 +0200 Subject: [PATCH 4/7] huge amount of small improvements, most thanks to leyyin --- src/network/protocols/get_public_address.cpp | 78 +++++++------------- src/network/protocols/get_public_address.hpp | 6 +- 2 files changed, 30 insertions(+), 54 deletions(-) diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index c4356eba1..aa53754e6 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -45,31 +45,6 @@ #endif #include - -int stunRand() -{ - static bool init = false; - if (!init) - { - srand((unsigned int)time(NULL)); - init = true; - } - return rand(); -} - -GetPublicAddress::GetPublicAddress(CallbackObject* callback_object) : Protocol(callback_object, PROTOCOL_SILENT) -{ -} - -GetPublicAddress::~GetPublicAddress() -{ -} - -void GetPublicAddress::setup() -{ - m_state = NOTHING_DONE; -} - /** * Gets the response from the STUN server, checks it for its validity and * then parses the answer into address and port @@ -122,7 +97,7 @@ std::string GetPublicAddress::parseResponse() // Those are the port and the address to be detected uint16_t port; uint32_t address; - while(true) + while (true) { int type = attributes[0]*256+attributes[1]; int size = attributes[2]*256+attributes[3]; @@ -131,8 +106,12 @@ std::string GetPublicAddress::parseResponse() assert(size == 8); assert(attributes[5] == 0x01); // IPv4 only port = attributes[6]*256+attributes[7]; - // The (IPv4) address was sent as 4 distinct bytes, but needs to be packed into one 4-byte int - address = (attributes[8]<<24 & 0xFF000000) + (attributes[9]<<16 & 0x00FF0000) + (attributes[10]<<8 & 0x0000FF00) + (attributes[11] & 0x000000FF); + // The (IPv4) address was sent as 4 distinct bytes, + // but needs to be packed into one 4-byte int + address = (attributes[8]<<24 & 0xFF000000) + + (attributes[9]<<16 & 0x00FF0000) + + (attributes[10]<<8 & 0x0000FF00) + + (attributes[11] & 0x000000FF); break; } attributes = attributes + 4 + size; @@ -144,7 +123,8 @@ std::string GetPublicAddress::parseResponse() } // finished parsing, we know our public transport address - 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); + 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); TransportAddress* addr = static_cast(m_callback_object); addr->ip = address; addr->port = port; @@ -158,7 +138,7 @@ std::string GetPublicAddress::parseResponse() } -/** Creates a request and sends it to a random STUN server randomly slected +/** Creates a request and sends it to a random STUN server randomly selected * from the list saved in the config file * The request is send through m_transaction_host, from which the answer * will be retrieved by parseResponse() @@ -167,9 +147,9 @@ void GetPublicAddress::createStunRequest() { // format : 00MMMMMCMMMCMMMM (cf rfc 5389) uint16_t message_type = 0x0001; // binding request - m_stun_tansaction_id[0] = stunRand(); - m_stun_tansaction_id[1] = stunRand(); - m_stun_tansaction_id[2] = stunRand(); + m_stun_tansaction_id[0] = rand(); + m_stun_tansaction_id[1] = rand(); + m_stun_tansaction_id[2] = rand(); uint16_t message_length = 0x0000; uint8_t bytes[21]; // the message to be sent @@ -210,32 +190,28 @@ void GetPublicAddress::createStunRequest() Log::verbose("GetPublicAddress", "Using STUN server %s", stun_servers[rand_result].c_str()); - // resolve the name into an IP address - struct addrinfo hints, *res, *p; - int status; + struct addrinfo hints, *res; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version hints.ai_socktype = SOCK_STREAM; - if ((status = getaddrinfo(stun_servers[rand_result].c_str(), NULL, &hints, &res)) != 0) { - Log::error("getaddrinfo", gai_strerror(status)); - return; - } - for (p = res; p != NULL; p = p->ai_next) + // Resolve the stun server name so we can send it a STUN request + int status = getaddrinfo(stun_servers[rand_result].c_str(), NULL, &hints, &res); + if (status != 0) { - struct sockaddr_in* current_interface = (struct sockaddr_in*)(p->ai_addr); - - m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr); - 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 + Log::error("GetPublicAddress", "Error in getaddrinfo: %s", gai_strerror(status)); return; } - freeaddrinfo(res); // free the linked list + assert (res != NULL) // documentation says it points to "one or more addrinfo structures" + + struct sockaddr_in* current_interface = (struct sockaddr_in*)(res->ai_addr); + m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr); + 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); } diff --git a/src/network/protocols/get_public_address.hpp b/src/network/protocols/get_public_address.hpp index 6897b4641..e80791e0b 100644 --- a/src/network/protocols/get_public_address.hpp +++ b/src/network/protocols/get_public_address.hpp @@ -26,12 +26,12 @@ class GetPublicAddress : public Protocol { public: - GetPublicAddress(CallbackObject* callback_object); - virtual ~GetPublicAddress(); + GetPublicAddress(CallbackObject* callback_object) : Protocol(callback_object, PROTOCOL_SILENT) {} + virtual ~GetPublicAddress() {} virtual bool notifyEvent(Event* event) { return true; } virtual bool notifyEventAsynchronous(Event* event) { return true; } - virtual void setup(); + virtual void setup() { m_state = NOTHING_DONE; } virtual void update() {} virtual void asynchronousUpdate(); From d9697cbbe0c16936c8d5bca16a852069eaa43391 Mon Sep 17 00:00:00 2001 From: konstin Date: Sat, 8 Aug 2015 20:27:19 +0200 Subject: [PATCH 5/7] order functions chronologically --- src/network/protocols/get_public_address.cpp | 158 +++++++++---------- 1 file changed, 77 insertions(+), 81 deletions(-) diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index aa53754e6..885391225 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -23,7 +23,6 @@ #include "network/client_network_manager.hpp" #include "network/protocols/connect_to_server.hpp" #include "network/network_interface.hpp" - #include "utils/log.hpp" #include "utils/random_generator.hpp" @@ -45,6 +44,82 @@ #endif #include +/** Creates a request and sends it to a random STUN server randomly selected + * from the list saved in the config file + * The request is send through m_transaction_host, from which the answer + * will be retrieved by parseResponse() + */ +void GetPublicAddress::createStunRequest() +{ + // format : 00MMMMMCMMMCMMMM (cf rfc 5389) + uint16_t message_type = 0x0001; // binding request + m_stun_tansaction_id[0] = rand(); + m_stun_tansaction_id[1] = rand(); + m_stun_tansaction_id[2] = rand(); + uint16_t message_length = 0x0000; + + uint8_t bytes[21]; // the message to be sent + // bytes 0-1 : the type of the message, + bytes[0] = (uint8_t)(message_type>>8); + bytes[1] = (uint8_t)(message_type); + + // bytes 2-3 : message length added to header (attributes) + bytes[2] = (uint8_t)(message_length>>8); + bytes[3] = (uint8_t)(message_length); + + // bytes 4-7 : magic cookie to recognize the stun protocol + bytes[4] = (uint8_t)(m_stun_magic_cookie>>24); + bytes[5] = (uint8_t)(m_stun_magic_cookie>>16); + bytes[6] = (uint8_t)(m_stun_magic_cookie>>8); + bytes[7] = (uint8_t)(m_stun_magic_cookie); + + // bytes 8-19 : the transaction id + bytes[8] = (uint8_t)(m_stun_tansaction_id[0]>>24); + bytes[9] = (uint8_t)(m_stun_tansaction_id[0]>>16); + bytes[10] = (uint8_t)(m_stun_tansaction_id[0]>>8); + bytes[11] = (uint8_t)(m_stun_tansaction_id[0]); + bytes[12] = (uint8_t)(m_stun_tansaction_id[1]>>24); + bytes[13] = (uint8_t)(m_stun_tansaction_id[1]>>16); + bytes[14] = (uint8_t)(m_stun_tansaction_id[1]>>8); + bytes[15] = (uint8_t)(m_stun_tansaction_id[1]); + bytes[16] = (uint8_t)(m_stun_tansaction_id[2]>>24); + bytes[17] = (uint8_t)(m_stun_tansaction_id[2]>>16); + bytes[18] = (uint8_t)(m_stun_tansaction_id[2]>>8); + bytes[19] = (uint8_t)(m_stun_tansaction_id[2]); + bytes[20] = '\0'; + + // time to pick a random stun server + std::vector stun_servers = UserConfigParams::m_stun_servers; + + RandomGenerator random_gen; + int rand_result = random_gen.get((int)stun_servers.size()); + Log::debug("GetPublicAddress", "Using STUN server %s", + stun_servers[rand_result].c_str()); + + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version + hints.ai_socktype = SOCK_STREAM; + + // Resolve the stun server name so we can send it a STUN request + int status = getaddrinfo(stun_servers[rand_result].c_str(), NULL, &hints, &res); + if (status != 0) + { + Log::error("GetPublicAddress", "Error in getaddrinfo: %s", gai_strerror(status)); + return; + } + assert (res != NULL) // documentation says it points to "one or more addrinfo structures" + + struct sockaddr_in* current_interface = (struct sockaddr_in*)(res->ai_addr); + m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr); + 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); +} + /** * Gets the response from the STUN server, checks it for its validity and * then parses the answer into address and port @@ -137,92 +212,13 @@ std::string GetPublicAddress::parseResponse() return ""; } - -/** Creates a request and sends it to a random STUN server randomly selected - * from the list saved in the config file - * The request is send through m_transaction_host, from which the answer - * will be retrieved by parseResponse() - */ -void GetPublicAddress::createStunRequest() -{ - // format : 00MMMMMCMMMCMMMM (cf rfc 5389) - uint16_t message_type = 0x0001; // binding request - m_stun_tansaction_id[0] = rand(); - m_stun_tansaction_id[1] = rand(); - m_stun_tansaction_id[2] = rand(); - uint16_t message_length = 0x0000; - - uint8_t bytes[21]; // the message to be sent - // bytes 0-1 : the type of the message, - bytes[0] = (uint8_t)(message_type>>8); - bytes[1] = (uint8_t)(message_type); - - // bytes 2-3 : message length added to header (attributes) - bytes[2] = (uint8_t)(message_length>>8); - bytes[3] = (uint8_t)(message_length); - - // bytes 4-7 : magic cookie to recognize the stun protocol - bytes[4] = (uint8_t)(m_stun_magic_cookie>>24); - bytes[5] = (uint8_t)(m_stun_magic_cookie>>16); - bytes[6] = (uint8_t)(m_stun_magic_cookie>>8); - bytes[7] = (uint8_t)(m_stun_magic_cookie); - - // bytes 8-19 : the transaction id - bytes[8] = (uint8_t)(m_stun_tansaction_id[0]>>24); - bytes[9] = (uint8_t)(m_stun_tansaction_id[0]>>16); - bytes[10] = (uint8_t)(m_stun_tansaction_id[0]>>8); - bytes[11] = (uint8_t)(m_stun_tansaction_id[0]); - bytes[12] = (uint8_t)(m_stun_tansaction_id[1]>>24); - bytes[13] = (uint8_t)(m_stun_tansaction_id[1]>>16); - bytes[14] = (uint8_t)(m_stun_tansaction_id[1]>>8); - bytes[15] = (uint8_t)(m_stun_tansaction_id[1]); - bytes[16] = (uint8_t)(m_stun_tansaction_id[2]>>24); - bytes[17] = (uint8_t)(m_stun_tansaction_id[2]>>16); - bytes[18] = (uint8_t)(m_stun_tansaction_id[2]>>8); - bytes[19] = (uint8_t)(m_stun_tansaction_id[2]); - bytes[20] = '\0'; - - // time to pick a random stun server - std::vector stun_servers = UserConfigParams::m_stun_servers; - - RandomGenerator random_gen; - int rand_result = random_gen.get((int)stun_servers.size()); - Log::verbose("GetPublicAddress", "Using STUN server %s", - stun_servers[rand_result].c_str()); - - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version - hints.ai_socktype = SOCK_STREAM; - - // Resolve the stun server name so we can send it a STUN request - int status = getaddrinfo(stun_servers[rand_result].c_str(), NULL, &hints, &res); - if (status != 0) - { - Log::error("GetPublicAddress", "Error in getaddrinfo: %s", gai_strerror(status)); - return; - } - assert (res != NULL) // documentation says it points to "one or more addrinfo structures" - - struct sockaddr_in* current_interface = (struct sockaddr_in*)(res->ai_addr); - m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr); - 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); -} - - /** Detects public IP-address and port by first sending a request to a randomly * selected STUN server and then parsing and validating the response */ void GetPublicAddress::asynchronousUpdate() { if (m_state == NOTHING_DONE) - createStunRequest(); - if (m_state == TEST_SENT) { + createStunRequest(); std::string message = parseResponse(); if (message != "") { From 1eb3b6f74eb1a8eb5f606be9ffcb25db3c541e0e Mon Sep 17 00:00:00 2001 From: konstin Date: Sat, 8 Aug 2015 21:01:03 +0200 Subject: [PATCH 6/7] More small improvements --- src/network/protocols/get_public_address.cpp | 111 ++++++++----------- src/network/protocols/get_public_address.hpp | 19 ++-- src/states_screens/main_menu_screen.cpp | 6 +- 3 files changed, 58 insertions(+), 78 deletions(-) diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index 885391225..6461faecd 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -24,7 +24,6 @@ #include "network/protocols/connect_to_server.hpp" #include "network/network_interface.hpp" #include "utils/log.hpp" -#include "utils/random_generator.hpp" #include @@ -44,57 +43,46 @@ #endif #include -/** Creates a request and sends it to a random STUN server randomly selected - * from the list saved in the config file +constexpr uint8_t GetPublicAddress::m_stun_magic_cookie[4]; // make the linker happy + +/** Creates a STUN request and sends it to a random STUN server selected from + * the list stored in the config file. See https://tools.ietf.org/html/rfc5389#section-6 + * for details on the message structure. * The request is send through m_transaction_host, from which the answer - * will be retrieved by parseResponse() + * will be retrieved by parseStunResponse() */ void GetPublicAddress::createStunRequest() { - // format : 00MMMMMCMMMCMMMM (cf rfc 5389) - uint16_t message_type = 0x0001; // binding request - m_stun_tansaction_id[0] = rand(); - m_stun_tansaction_id[1] = rand(); - m_stun_tansaction_id[2] = rand(); - uint16_t message_length = 0x0000; - uint8_t bytes[21]; // the message to be sent - // bytes 0-1 : the type of the message, + // bytes 0-1: the type of the message + uint16_t message_type = 0x0001; // binding request bytes[0] = (uint8_t)(message_type>>8); bytes[1] = (uint8_t)(message_type); - // bytes 2-3 : message length added to header (attributes) + // bytes 2-3: message length added to header (attributes) + uint16_t message_length = 0x0000; bytes[2] = (uint8_t)(message_length>>8); bytes[3] = (uint8_t)(message_length); - // bytes 4-7 : magic cookie to recognize the stun protocol - bytes[4] = (uint8_t)(m_stun_magic_cookie>>24); - bytes[5] = (uint8_t)(m_stun_magic_cookie>>16); - bytes[6] = (uint8_t)(m_stun_magic_cookie>>8); - bytes[7] = (uint8_t)(m_stun_magic_cookie); + // bytes 4-7: magic cookie to recognize the stun protocol + for (int i = 0; i < 4; i++) + bytes[i + 4] = m_stun_magic_cookie[i]; - // bytes 8-19 : the transaction id - bytes[8] = (uint8_t)(m_stun_tansaction_id[0]>>24); - bytes[9] = (uint8_t)(m_stun_tansaction_id[0]>>16); - bytes[10] = (uint8_t)(m_stun_tansaction_id[0]>>8); - bytes[11] = (uint8_t)(m_stun_tansaction_id[0]); - bytes[12] = (uint8_t)(m_stun_tansaction_id[1]>>24); - bytes[13] = (uint8_t)(m_stun_tansaction_id[1]>>16); - bytes[14] = (uint8_t)(m_stun_tansaction_id[1]>>8); - bytes[15] = (uint8_t)(m_stun_tansaction_id[1]); - bytes[16] = (uint8_t)(m_stun_tansaction_id[2]>>24); - bytes[17] = (uint8_t)(m_stun_tansaction_id[2]>>16); - bytes[18] = (uint8_t)(m_stun_tansaction_id[2]>>8); - bytes[19] = (uint8_t)(m_stun_tansaction_id[2]); + + // bytes 8-19: the transaction id + for (int i = 0; i < 12; i++) + { + uint8_t random_byte = rand() % 256; + bytes[i+8] = random_byte; + m_stun_tansaction_id[i] = random_byte; + } bytes[20] = '\0'; // time to pick a random stun server std::vector stun_servers = UserConfigParams::m_stun_servers; - RandomGenerator random_gen; - int rand_result = random_gen.get((int)stun_servers.size()); - Log::debug("GetPublicAddress", "Using STUN server %s", - stun_servers[rand_result].c_str()); + const char* server_name = stun_servers[rand() % stun_servers.size()].c_str(); + Log::debug("GetPublicAddress", "Using STUN server %s", server_name); struct addrinfo hints, *res; @@ -103,21 +91,21 @@ void GetPublicAddress::createStunRequest() hints.ai_socktype = SOCK_STREAM; // Resolve the stun server name so we can send it a STUN request - int status = getaddrinfo(stun_servers[rand_result].c_str(), NULL, &hints, &res); + int status = getaddrinfo(server_name, NULL, &hints, &res); if (status != 0) { Log::error("GetPublicAddress", "Error in getaddrinfo: %s", gai_strerror(status)); return; } - assert (res != NULL) // documentation says it points to "one or more addrinfo structures" + assert (res != NULL); // documentation says it points to "one or more addrinfo structures" struct sockaddr_in* current_interface = (struct sockaddr_in*)(res->ai_addr); m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr); 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; + m_transaction_host->sendRawPacket(bytes, 20, TransportAddress(m_stun_server_ip, m_stun_server_port)); freeaddrinfo(res); + m_state = STUN_REQUEST_SENT; } /** @@ -125,40 +113,29 @@ void GetPublicAddress::createStunRequest() * then parses the answer into address and port * \return "" if the address could be parsed or an error message */ -std::string GetPublicAddress::parseResponse() +std::string GetPublicAddress::parseStunResponse() { - uint8_t* data = m_transaction_host->receiveRawPacket(TransportAddress(m_stun_server_ip, 3478), 2000); + uint8_t* data = m_transaction_host->receiveRawPacket(TransportAddress(m_stun_server_ip, m_stun_server_port), 2000); if (!data) return "STUN response contains no data at all"; // check that the stun response is a response, contains the magic cookie and the transaction ID - if (data[0] != 0x01 || - data[1] != 0x01 || - data[4] != (uint8_t)(m_stun_magic_cookie>>24) || - data[5] != (uint8_t)(m_stun_magic_cookie>>16) || - data[6] != (uint8_t)(m_stun_magic_cookie>>8) || - data[7] != (uint8_t)(m_stun_magic_cookie)) - { + if (data[0] != 0x01 || data[1] != 0x01) return "STUN response doesn't contain the magic cookie"; - } - if (data[8] != (uint8_t)(m_stun_tansaction_id[0]>>24) || - data[9] != (uint8_t)(m_stun_tansaction_id[0]>>16) || - data[10] != (uint8_t)(m_stun_tansaction_id[0]>>8 ) || - data[11] != (uint8_t)(m_stun_tansaction_id[0] ) || - data[12] != (uint8_t)(m_stun_tansaction_id[1]>>24) || - data[13] != (uint8_t)(m_stun_tansaction_id[1]>>16) || - data[14] != (uint8_t)(m_stun_tansaction_id[1]>>8 ) || - data[15] != (uint8_t)(m_stun_tansaction_id[1] ) || - data[16] != (uint8_t)(m_stun_tansaction_id[2]>>24) || - data[17] != (uint8_t)(m_stun_tansaction_id[2]>>16) || - data[18] != (uint8_t)(m_stun_tansaction_id[2]>>8 ) || - data[19] != (uint8_t)(m_stun_tansaction_id[2] )) + for (int i = 0; i < 4; i++) { - return "STUN response doesn't contain the transaction ID"; + if (data[i + 4] != m_stun_magic_cookie[i]) + return "STUN response doesn't contain the magic cookie"; } - Log::verbose("GetPublicAddress", "The STUN server responded with a valid answer"); + for (int i = 0; i < 12; i++) + { + if (data[i+8] != m_stun_tansaction_id[i]) + return "STUN response doesn't contain the transaction ID"; + } + + Log::debug("GetPublicAddress", "The STUN server responded with a valid answer"); int message_size = data[2]*256+data[3]; // The stun message is valid, so we parse it now: @@ -199,14 +176,13 @@ std::string GetPublicAddress::parseResponse() // finished parsing, we know our public transport address 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); + address>>24&0xff, address>>16&0xff, address>>8&0xff, address&0xff, port); TransportAddress* addr = static_cast(m_callback_object); addr->ip = address; addr->port = port; // The address and the port are known, so the connection can be closed m_state = EXITING; - // terminate the protocol m_listener->requestTerminate(this); return ""; @@ -219,7 +195,10 @@ void GetPublicAddress::asynchronousUpdate() if (m_state == NOTHING_DONE) { createStunRequest(); - std::string message = parseResponse(); + } + if (m_state == STUN_REQUEST_SENT) + { + std::string message = parseStunResponse(); if (message != "") { Log::warn("GetPublicAddress", "%s", message.c_str()); diff --git a/src/network/protocols/get_public_address.hpp b/src/network/protocols/get_public_address.hpp index e80791e0b..481397afa 100644 --- a/src/network/protocols/get_public_address.hpp +++ b/src/network/protocols/get_public_address.hpp @@ -35,23 +35,24 @@ class GetPublicAddress : public Protocol virtual void update() {} virtual void asynchronousUpdate(); - protected: + private: + void createStunRequest(); + std::string parseStunResponse(); + + // Constants + static constexpr uint8_t m_stun_magic_cookie[4] = {0x21, 0x12, 0xA4, 0x42}; + static const int m_stun_server_port = 3478; + enum STATE { NOTHING_DONE, - TEST_SENT, - ADDRESS_KNOWN, + STUN_REQUEST_SENT, EXITING }; STATE m_state; - uint32_t m_stun_tansaction_id[3]; - static const uint32_t m_stun_magic_cookie = 0x2112A442; + uint8_t m_stun_tansaction_id[12]; uint32_t m_stun_server_ip; STKHost* m_transaction_host; - - private: - std::string parseResponse(); - void createStunRequest(); }; #endif // GET_PUBLIC_ADDRESS_HPP diff --git a/src/states_screens/main_menu_screen.cpp b/src/states_screens/main_menu_screen.cpp index 4d27f3be1..af449fba9 100644 --- a/src/states_screens/main_menu_screen.cpp +++ b/src/states_screens/main_menu_screen.cpp @@ -175,7 +175,7 @@ void MainMenuScreen::onUpdate(float delta) m_online->setLabel( _("Login" )); m_user_id->setText(player->getName()); } - else + else { // now must be either logging in or logging out m_online->setActive(false); @@ -297,7 +297,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, StoryModeStatus* sms = PlayerManager::getCurrentPlayer()->getStoryModeStatus(); sms->unlockFeature(const_cast(sms->getChallengeStatus("gp1")), RaceManager::DIFFICULTY_HARD); - + StateManager::get()->enterGameState(); race_manager->setMinorMode(RaceManager::MINOR_MODE_CUTSCENE); race_manager->setNumKarts(0); @@ -307,7 +307,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, FeatureUnlockedCutScene* scene = FeatureUnlockedCutScene::getInstance(); - + std::vector parts; parts.push_back("featunlocked"); ((CutsceneWorld*)World::getWorld())->setParts(parts); From c78abbddf76cb39460894e0628fda874496471e8 Mon Sep 17 00:00:00 2001 From: konstin Date: Sat, 15 Aug 2015 15:10:30 +0200 Subject: [PATCH 7/7] try to fix travis CI compilation --- src/network/protocols/get_public_address.cpp | 2 +- src/network/protocols/get_public_address.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index 6461faecd..a4cabcdc0 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -43,7 +43,7 @@ #endif #include -constexpr uint8_t GetPublicAddress::m_stun_magic_cookie[4]; // make the linker happy +const uint8_t GetPublicAddress::m_stun_magic_cookie[4] = {0x21, 0x12, 0xA4, 0x42}; // make the linker happy /** Creates a STUN request and sends it to a random STUN server selected from * the list stored in the config file. See https://tools.ietf.org/html/rfc5389#section-6 diff --git a/src/network/protocols/get_public_address.hpp b/src/network/protocols/get_public_address.hpp index 481397afa..667064c5c 100644 --- a/src/network/protocols/get_public_address.hpp +++ b/src/network/protocols/get_public_address.hpp @@ -40,7 +40,7 @@ class GetPublicAddress : public Protocol std::string parseStunResponse(); // Constants - static constexpr uint8_t m_stun_magic_cookie[4] = {0x21, 0x12, 0xA4, 0x42}; + static const uint8_t m_stun_magic_cookie[4]; static const int m_stun_server_port = 3478; enum STATE