Changeset View
Standalone View
network/StunClient.cpp
Show First 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | bool ReceiveStunResponse(ENetHost* transactionHost, std::vector<u8>& buffer) | ||||
ENSURE(transactionHost); | ENSURE(transactionHost); | ||||
// TransportAddress sender; | // TransportAddress sender; | ||||
const int LEN = 2048; | const int LEN = 2048; | ||||
char input_buffer[LEN]; | char input_buffer[LEN]; | ||||
memset(input_buffer, 0, LEN); | memset(input_buffer, 0, LEN); | ||||
#ifdef ENET_IPV6 | |||||
sockaddr_in6 addr; | |||||
#else | |||||
sockaddr_in addr; | sockaddr_in addr; | ||||
#endif | |||||
socklen_t from_len = sizeof(addr); | socklen_t from_len = sizeof(addr); | ||||
int len = recvfrom(transactionHost->socket, input_buffer, LEN, 0, (sockaddr*)(&addr), &from_len); | int len = recvfrom(transactionHost->socket, input_buffer, LEN, 0, (sockaddr*)(&addr), &from_len); | ||||
int delay = 200; | int delay = 200; | ||||
CFG_GET_VAL("lobby.stun.delay", delay); | CFG_GET_VAL("lobby.stun.delay", delay); | ||||
// Wait to receive the message because enet sockets are non-blocking | // Wait to receive the message because enet sockets are non-blocking | ||||
const int max_tries = 5; | const int max_tries = 5; | ||||
for (int count = 0; len < 0 && (count < max_tries || max_tries == -1); ++count) | for (int count = 0; len < 0 && (count < max_tries || max_tries == -1); ++count) | ||||
{ | { | ||||
usleep(delay * 1000); | usleep(delay * 1000); | ||||
len = recvfrom(transactionHost->socket, input_buffer, LEN, 0, (sockaddr*)(&addr), &from_len); | len = recvfrom(transactionHost->socket, input_buffer, LEN, 0, (sockaddr*)(&addr), &from_len); | ||||
} | } | ||||
if (len < 0) | if (len < 0) | ||||
{ | { | ||||
LOGERROR("GetPublicAddress: recvfrom error (%d): %s", errno, strerror(errno)); | LOGERROR("GetPublicAddress: recvfrom error (%d): %s", errno, strerror(errno)); | ||||
return false; | return false; | ||||
} | } | ||||
#ifdef ENET_IPV6 | |||||
u32 sender_ip = ntohl(((u32*)addr.sin6_addr.s6_addr)[3]); | |||||
u16 sender_port = ntohs(addr.sin6_port); | |||||
bool sender_is_ipv4 = !memcmp(addr.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xFF\xFF", 12); | |||||
vladislavbelov: It may looks hacky for some readers, I'd prefer the old version of the initialization. | |||||
LefoAuthorUnsubmitted Done Inline ActionsWhat you mean by old version of initialization? Lefo: What you mean by old version of initialization?
I agree it does not look good.
How about this? | |||||
vladislavbelovUnsubmitted Done Inline ActionsYep, something like that. vladislavbelov: Yep, something like that. | |||||
#else | |||||
u32 sender_ip = ntohl((u32)(addr.sin_addr.s_addr)); | u32 sender_ip = ntohl((u32)(addr.sin_addr.s_addr)); | ||||
u16 sender_port = ntohs(addr.sin_port); | u16 sender_port = ntohs(addr.sin_port); | ||||
bool sender_is_ipv4 = true; | |||||
#endif | |||||
if (sender_ip != m_StunServerIP) | if (!sender_is_ipv4 || sender_ip != m_StunServerIP || sender_port != m_StunServerPort) { | ||||
LOGERROR("GetPublicAddress: Received stun response from different address: %d:%d (%d.%d.%d.%d:%d) %s", | char ipStr[256] = "(error)"; | ||||
addr.sin_addr.s_addr, | getnameinfo((struct sockaddr *)&addr, sizeof(addr), ipStr, sizeof(ipStr), nullptr, 0, NI_NUMERICHOST); | ||||
addr.sin_port, | LOGERROR("GetPublicAddress: Received stun response from different address: [%s]:%d", ipStr, (int)sender_port); | ||||
(sender_ip >> 24) & 0xff, | } | ||||
(sender_ip >> 16) & 0xff, | |||||
(sender_ip >> 8) & 0xff, | |||||
(sender_ip >> 0) & 0xff, | |||||
sender_port, | |||||
input_buffer); | |||||
// Convert to network string. | // Convert to network string. | ||||
buffer.resize(len); | buffer.resize(len); | ||||
memcpy(buffer.data(), (u8*)input_buffer, len); | memcpy(buffer.data(), (u8*)input_buffer, len); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | JS::Value StunClient::FindStunEndpointHost(const ScriptInterface& scriptInterface, int port) | ||||
bool success = STUNRequestAndResponse(transactionHost); | bool success = STUNRequestAndResponse(transactionHost); | ||||
enet_host_destroy(transactionHost); | enet_host_destroy(transactionHost); | ||||
if (!success) | if (!success) | ||||
return JS::UndefinedValue(); | return JS::UndefinedValue(); | ||||
// Convert m_IP to string | // Convert m_IP to string | ||||
char ipStr[256] = "(error)"; | char ipStr[256] = "(error)"; | ||||
ENetAddress addr; | struct sockaddr_in addr = {}; | ||||
addr.host = ntohl(m_IP); | addr.sin_family = AF_INET; | ||||
enet_address_get_host_ip(&addr, ipStr, ARRAY_SIZE(ipStr)); | addr.sin_addr.s_addr = ntohl(m_IP); | ||||
getnameinfo((struct sockaddr *)&addr, sizeof(addr), ipStr, sizeof(ipStr), nullptr, 0, NI_NUMERICHOST); | |||||
JSContext* cx = scriptInterface.GetContext(); | JSContext* cx = scriptInterface.GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::RootedValue stunEndpoint(cx); | JS::RootedValue stunEndpoint(cx); | ||||
scriptInterface.Eval("({})", &stunEndpoint); | scriptInterface.Eval("({})", &stunEndpoint); | ||||
scriptInterface.SetProperty(stunEndpoint, "ip", CStr(ipStr)); | scriptInterface.SetProperty(stunEndpoint, "ip", CStr(ipStr)); | ||||
scriptInterface.SetProperty(stunEndpoint, "port", m_Port); | scriptInterface.SetProperty(stunEndpoint, "port", m_Port); | ||||
return stunEndpoint; | return stunEndpoint; | ||||
} | } | ||||
StunClient::StunEndpoint* StunClient::FindStunEndpointJoin(ENetHost* transactionHost) | StunClient::StunEndpoint* StunClient::FindStunEndpointJoin(ENetHost* transactionHost) | ||||
{ | { | ||||
ENSURE(transactionHost); | ENSURE(transactionHost); | ||||
if (!STUNRequestAndResponse(transactionHost)) | if (!STUNRequestAndResponse(transactionHost)) | ||||
return nullptr; | return nullptr; | ||||
// Convert m_IP to string | // Convert m_IP to string | ||||
char ipStr[256] = "(error)"; | char ipStr[256] = "(error)"; | ||||
ENetAddress addr; | struct sockaddr_in addr = {}; | ||||
addr.host = ntohl(m_IP); | addr.sin_family = AF_INET; | ||||
enet_address_get_host_ip(&addr, ipStr, ARRAY_SIZE(ipStr)); | addr.sin_addr.s_addr = ntohl(m_IP); | ||||
getnameinfo((struct sockaddr *)&addr, sizeof(addr), ipStr, sizeof(ipStr), nullptr, 0, NI_NUMERICHOST); | |||||
return new StunEndpoint({ m_IP, m_Port }); | return new StunEndpoint({ m_IP, m_Port }); | ||||
} | } | ||||
void StunClient::SendHolePunchingMessages(ENetHost* enetClient, const char* serverAddress, u16 serverPort) | void StunClient::SendHolePunchingMessages(ENetHost* enetClient, const char* serverAddress, u16 serverPort) | ||||
{ | { | ||||
// Convert ip string to int64 | // Convert ip string to struct in_addr | ||||
ENetAddress addr; | struct in_addr addr; | ||||
addr.port = serverPort; | |||||
enet_address_set_host(&addr, serverAddress); | struct addrinfo hints = {}; | ||||
hints.ai_flags = AI_NUMERICHOST; | |||||
hints.ai_family = AF_INET; | |||||
hints.ai_socktype = SOCK_DGRAM; | |||||
struct addrinfo* res; | |||||
int status = getaddrinfo(serverAddress, nullptr, &hints, &res); | |||||
vladislavbelovUnsubmitted Done Inline ActionsYou don't use status anywhere else. So put it inside the if statement. vladislavbelov: You don't use `status` anywhere else. So put it inside the `if` statement. | |||||
LefoAuthorUnsubmitted Done Inline ActionsCondition of if depends on status so I can't do that. Lefo: Condition of if depends on status so I can't do that.
I could declare status inside if… | |||||
vladislavbelovUnsubmitted Done Inline ActionsI meant, that if (status != 0) equals to if (status), so it could be written so: if (int status = getaddrinfo(serverAddress, nullptr, &hints, &res)) { // ... } vladislavbelov: I meant, that `if (status != 0)` equals to `if (status)`, so it could be written so… | |||||
LefoAuthorUnsubmitted Done Inline ActionsOk, I also updated previously untouched code above to make it consistent with this. Lefo: Ok, I also updated previously untouched code above to make it consistent with this. | |||||
if (status != 0) | |||||
{ | |||||
#ifdef UNICODE | |||||
LOGERROR("SendHolePunchingMessages: Error in getaddrinfo: %s", utf8_from_wstring(gai_strerror(status))); | |||||
#else | |||||
LOGERROR("SendHolePunchingMessages: Error in getaddrinfo: %s", gai_strerror(status)); | |||||
#endif | |||||
return; | |||||
} | |||||
ENSURE(res); | |||||
addr = ((struct sockaddr_in *)res->ai_addr)->sin_addr; | |||||
freeaddrinfo(res); | |||||
int delay = 200; | int delay = 200; | ||||
CFG_GET_VAL("lobby.stun.delay", delay); | CFG_GET_VAL("lobby.stun.delay", delay); | ||||
// Send an UDP message from enet host to ip:port | // Send an UDP message from enet host to ip:port | ||||
for (int i = 0; i < 3; ++i) | for (int i = 0; i < 3; ++i) | ||||
{ | { | ||||
StunClient::SendStunRequest(enetClient, htonl(addr.host), serverPort); | StunClient::SendStunRequest(enetClient, ntohl(addr.s_addr), serverPort); | ||||
usleep(delay * 1000); | usleep(delay * 1000); | ||||
} | } | ||||
} | } |
It may looks hacky for some readers, I'd prefer the old version of the initialization.