http: Cancel remote server connects faster.

This way the UI doesn't appear to hang when you click cancel.
This commit is contained in:
Unknown W. Brackets 2017-03-22 00:00:52 -07:00
parent 52bcd78301
commit 2faaf0a9fa
3 changed files with 55 additions and 22 deletions

View File

@ -50,6 +50,7 @@ static std::mutex serverStatusLock;
static std::condition_variable serverStatusCond;
static bool scanCancelled = false;
static bool scanAborted = false;
static void UpdateStatus(ServerStatus s) {
std::lock_guard<std::mutex> guard(serverStatusLock);
@ -69,7 +70,7 @@ static void RegisterServer(int port) {
Buffer theVoid;
if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT)) {
if (http.Connect()) {
if (http.Connect(2, 20.0, &scanCancelled)) {
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);
@ -190,12 +191,24 @@ static bool FindServer(std::string &resultHost, int &resultPort) {
Buffer result;
int code = 500;
auto TryServer = [&](const std::string &host, int port) {
// Don't wait as long for a connect - we need a good connection for smooth streaming anyway.
// This way if it's down, we'll find the right one faster.
if (http.Resolve(host.c_str(), port) && http.Connect(1, 10.0, &scanCancelled)) {
http.Disconnect();
resultHost = host;
resultPort = port;
return true;
}
return false;
};
// Try last server first, if it is set
if (g_Config.iLastRemoteISOPort && g_Config.sLastRemoteISOServer != "" && http.Resolve(g_Config.sLastRemoteISOServer.c_str(), g_Config.iLastRemoteISOPort) && http.Connect()) {
http.Disconnect();
resultHost = g_Config.sLastRemoteISOServer;
resultPort = g_Config.iLastRemoteISOPort;
return true;
if (g_Config.iLastRemoteISOPort && g_Config.sLastRemoteISOServer != "") {
if (TryServer(g_Config.sLastRemoteISOServer.c_str(), g_Config.iLastRemoteISOPort)) {
return true;
}
}
//don't scan if in manual mode
@ -205,7 +218,7 @@ 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)) {
if (http.Connect()) {
if (http.Connect(2, 20.0, &scanCancelled)) {
code = http.GET("/match/list", &result);
http.Disconnect();
}
@ -230,7 +243,7 @@ static bool FindServer(std::string &resultHost, int &resultPort) {
std::vector<std::string> servers;
const json_value *entry = entries->first_child;
while (entry) {
while (entry && !scanCancelled) {
const char *host = entry->getString("ip", "");
int port = entry->getInt("p", 0);
@ -238,10 +251,7 @@ static bool FindServer(std::string &resultHost, int &resultPort) {
snprintf(url, sizeof(url), "http://%s:%d", host, port);
servers.push_back(url);
if (http.Resolve(host, port) && http.Connect()) {
http.Disconnect();
resultHost = host;
resultPort = port;
if (TryServer(host, port)) {
return true;
}
@ -271,7 +281,7 @@ static bool LoadGameList(const std::string &host, int port, std::vector<std::str
// Start by requesting the list of games from the server.
if (http.Resolve(host.c_str(), port)) {
if (http.Connect()) {
if (http.Connect(2, 20.0, &scanCancelled)) {
code = http.GET(subdir.c_str(), &result,responseHeaders);
http.Disconnect();
}
@ -441,6 +451,7 @@ UI::EventReturn RemoteISOScreen::HandleSettings(UI::EventParams &e) {
RemoteISOConnectScreen::RemoteISOConnectScreen() : status_(ScanStatus::SCANNING), nextRetry_(0.0) {
scanCancelled = false;
scanAborted = false;
scanThread_ = new std::thread([](RemoteISOConnectScreen *thiz) {
thiz->ExecuteScan();
@ -455,6 +466,7 @@ RemoteISOConnectScreen::~RemoteISOConnectScreen() {
sleep_ms(1);
if (--maxWait < 0) {
// If it does ever wake up, it may crash... but better than hanging?
scanAborted = true;
break;
}
}
@ -536,7 +548,7 @@ void RemoteISOConnectScreen::update() {
void RemoteISOConnectScreen::ExecuteScan() {
FindServer(host_, port_);
if (scanCancelled) {
if (scanAborted) {
return;
}
@ -551,7 +563,7 @@ ScanStatus RemoteISOConnectScreen::GetStatus() {
void RemoteISOConnectScreen::ExecuteLoad() {
bool result = LoadGameList(host_, port_, games_);
if (scanCancelled) {
if (scanAborted) {
return;
}

View File

@ -73,7 +73,7 @@ bool Connection::Resolve(const char *host, int port) {
return true;
}
bool Connection::Connect(int maxTries, double timeout) {
bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) {
if (port_ <= 0) {
ELOG("Bad port");
return false;
@ -106,10 +106,26 @@ bool Connection::Connect(int maxTries, double timeout) {
}
}
struct timeval tv;
tv.tv_sec = floor(timeout);
tv.tv_usec = (timeout - floor(timeout)) * 1000000.0;
if (select(maxfd, NULL, &fds, NULL, &tv) > 0) {
int selectResult = 0;
long timeoutHalfSeconds = floor(2 * timeout);
while (timeoutHalfSeconds >= 0 && selectResult == 0) {
struct timeval tv;
tv.tv_sec = 0;
if (timeoutHalfSeconds > 0) {
// Wait up to 0.5 seconds between cancel checks.
tv.tv_usec = 500000;
} else {
// Wait the remaining <= 0.5 seconds. Possibly 0, but that's okay.
tv.tv_usec = (timeout - floor(2 * timeout) / 2) * 1000000.0;
}
--timeoutHalfSeconds;
selectResult = select(maxfd, nullptr, &fds, nullptr, &tv);
if (cancelConnect && *cancelConnect) {
break;
}
}
if (selectResult > 0) {
// Something connected. Pick the first one that did (if multiple.)
for (int sock : sockets) {
if ((intptr_t)sock_ == -1 && FD_ISSET(sock, &fds)) {
@ -123,6 +139,11 @@ bool Connection::Connect(int maxTries, double timeout) {
// Great, now we're good to go.
return true;
}
if (cancelConnect && *cancelConnect) {
break;
}
sleep_ms(1);
}

View File

@ -29,7 +29,7 @@ public:
// Inits the sockaddr_in.
bool Resolve(const char *host, int port);
bool Connect(int maxTries = 2, double timeout = 20.0f);
bool Connect(int maxTries = 2, double timeout = 20.0f, bool *cancelConnect = nullptr);
void Disconnect();
// Only to be used for bring-up and debugging.
@ -167,4 +167,4 @@ private:
std::vector<std::shared_ptr<Download>> downloads_;
};
} // http
} // http