From 3c47440d0cffa6eaf741607ac619858daf20f230 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 4 Jul 2016 07:34:40 -0700 Subject: [PATCH] http: Set an explicit timeout on HTTP connect. Before we were just relying on whatever timeout connect() wanted. --- UI/RemoteISOScreen.cpp | 28 ++++++++-------- ext/native/net/http_client.cpp | 59 ++++++++++++++++++++++++++-------- ext/native/net/http_client.h | 2 +- 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index f5e2a519330d..48435ed598f8 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -67,14 +67,14 @@ static void RegisterServer(int port) { Buffer theVoid; if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT)) { - http.Connect(); + if (http.Connect()) { + char resource[1024] = {}; + std::string ip = fd_util::GetLocalIP(http.sock()); + snprintf(resource, sizeof(resource) - 1, "/match/update?local=%s&port=%d", ip.c_str(), port); - char resource[1024] = {}; - std::string ip = fd_util::GetLocalIP(http.sock()); - snprintf(resource, sizeof(resource) - 1, "/match/update?local=%s&port=%d", ip.c_str(), port); - - http.GET(resource, &theVoid); - http.Disconnect(); + http.GET(resource, &theVoid); + http.Disconnect(); + } } } @@ -191,9 +191,10 @@ static bool FindServer(std::string &resultHost, int &resultPort) { // Start by requesting a list of recent local ips for this network. if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT)) { - http.Connect(); - code = http.GET("/match/list", &result); - http.Disconnect(); + if (http.Connect()) { + code = http.GET("/match/list", &result); + http.Disconnect(); + } } if (code != 200 || scanCancelled) { @@ -244,9 +245,10 @@ static bool LoadGameList(const std::string &host, int port, std::vector +#include #include +#include #include #define closesocket close #else @@ -12,6 +14,7 @@ #include #endif +#include #include #include @@ -19,12 +22,13 @@ #include "base/buffer.h" #include "base/stringutil.h" #include "data/compression.h" +#include "file/fd_util.h" #include "net/resolve.h" #include "net/url.h" namespace net { -Connection::Connection() +Connection::Connection() : port_(-1), resolved_(NULL), sock_(-1) { } @@ -68,33 +72,60 @@ bool Connection::Resolve(const char *host, int port) { return true; } -bool Connection::Connect(int maxTries) { +bool Connection::Connect(int maxTries, double timeout) { if (port_ <= 0) { ELOG("Bad port"); return false; } - sock_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if ((intptr_t)sock_ == -1) { - ELOG("Bad socket"); - return false; - } + sock_ = -1; for (int tries = maxTries; tries > 0; --tries) { - for (addrinfo *possible = resolved_; possible != NULL; possible = possible->ai_next) { + std::vector sockets; + fd_set fds; + int maxfd = 1; + FD_ZERO(&fds); + for (addrinfo *possible = resolved_; possible != nullptr; possible = possible->ai_next) { // TODO: Could support ipv6 without huge difficulty... if (possible->ai_family != AF_INET) continue; - int retval = connect(sock_, possible->ai_addr, (int)possible->ai_addrlen); - if (retval >= 0) - return true; + int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if ((intptr_t)sock == -1) { + ELOG("Bad socket"); + continue; + } + fd_util::SetNonBlocking(sock, true); + + // Start trying to connect (async with timeout.) + connect(sock, possible->ai_addr, (int)possible->ai_addrlen); + sockets.push_back(sock); + FD_SET(sock, &fds); + if (maxfd < sock + 1) { + maxfd = sock + 1; + } + } + + struct timeval tv; + tv.tv_sec = floor(timeout); + tv.tv_usec = (timeout - floor(timeout)) * 1000000.0; + if (select(maxfd, NULL, &fds, NULL, &tv) > 0) { + // Something connected. Pick the first one that did (if multiple.) + for (int sock : sockets) { + if ((intptr_t)sock_ == -1 && FD_ISSET(sock, &fds)) { + fd_util::SetNonBlocking(sock, false); + sock_ = sock; + } else { + closesocket(sock); + } + } + + // Great, now we're good to go. + return true; } sleep_ms(1); } - // Let's not leak this socket. - closesocket(sock_); - sock_ = -1; + // Nothing connected, unfortunately. return false; } diff --git a/ext/native/net/http_client.h b/ext/native/net/http_client.h index e8ca917da974..cb150631e6ee 100644 --- a/ext/native/net/http_client.h +++ b/ext/native/net/http_client.h @@ -27,7 +27,7 @@ class Connection { // Inits the sockaddr_in. bool Resolve(const char *host, int port); - bool Connect(int maxTries = 2); + bool Connect(int maxTries = 2, double timeout = 20.0f); void Disconnect(); // Only to be used for bring-up and debugging.