diff --git a/port/linux/src/p2p.c b/port/linux/src/p2p.c index bbf2a9b2..e33646c6 100644 --- a/port/linux/src/p2p.c +++ b/port/linux/src/p2p.c @@ -1434,6 +1434,26 @@ static int stun_settled(void) return 1; } +/* the p2p thread was stopped for longer than a peer lasts: the process was +suspended (a phone app in the background) or the machine slept (a laptop). +The NAT's mapping of the tunnel may have lapsed, so this machine's public +address is asked again before an offer names it, and the brokers' +connections, which the network may have dropped, are made anew rather than +at their silence timeout */ +static void network_resumed(unsigned long stopped) +{ + int index; + + for (index = 0; index < p2p.stun_count; index++) + { + p2p.stun[index].has_mapped = 0; + p2p.stun[index].attempts = 0; + } + p2p_signal_reconnect(); + platform_log("Internet play: the game was stopped for %lu seconds; its public address is asked again and " + "the brokers reconnected", stopped / 1000); +} + /* ---------- stand-ins for peers' ports */ static void close_socket(int *socket) @@ -3126,6 +3146,7 @@ static void *p2p_thread(void *unused) streams; otherwise the thread can sleep longer */ int wait = webrtc_busy ? LOOP_INTERVAL : LOOP_INTERVAL * 5; int index, asked; + unsigned long waited; /* what to wait for */ read_owners[read_count] = _owner_tunnel; @@ -3186,6 +3207,7 @@ static void *p2p_thread(void *unused) memcpy(asked_write, write, sizeof(*write) * (size_t)write_count); pthread_mutex_unlock(&p2p_lock); + waited = p2p_now(); if (posix_socket_select(read, &read_count, write, &write_count, NULL, &error_count, 0, wait * 1000, 0) < 0) { @@ -3195,6 +3217,13 @@ static void *p2p_thread(void *unused) #ifdef HALO_PROFILE profile_trace_begin(p2p_profile_names.pass); #endif + /* the wait lasted far longer than asked (the process was suspended + or the machine slept): what the sockets report is stale */ + if (elapsed(waited, (unsigned long)wait + PEER_TIMEOUT)) + { + network_resumed(p2p_now() - waited); + read_count = write_count = 0; + } /* what is ready (the lists now hold only ready sockets, in the order asked, so each one's owner is found going along both); a socket diff --git a/port/linux/src/p2p_internal.h b/port/linux/src/p2p_internal.h index 5fd17d0e..3bd83289 100644 --- a/port/linux/src/p2p_internal.h +++ b/port/linux/src/p2p_internal.h @@ -154,6 +154,10 @@ int p2p_signal_join_player(const unsigned char *player_hash, const unsigned char void p2p_signal_stop_joining_player(const unsigned char *identifier); /* whether any broker is connected */ int p2p_signal_connected(void); +/* every broker's connection made anew at once: after the p2p thread was +stopped (the process was suspended, or the machine slept), the old ones +may carry nothing, and would be noticed only at their silence timeout */ +void p2p_signal_reconnect(void); /* the server browser's topics: the own slot and the queries (a listed game), and every slot (browsing) */ void p2p_signal_lobby_topics(int listed, int browsing); diff --git a/port/linux/src/p2p_signal.c b/port/linux/src/p2p_signal.c index 426f1eee..bb6f98c3 100644 --- a/port/linux/src/p2p_signal.c +++ b/port/linux/src/p2p_signal.c @@ -1918,6 +1918,23 @@ int p2p_signal_connected(void) return 0; } +void p2p_signal_reconnect(void) +{ + int index; + + for (index = 0; index < signalling.broker_count; index++) + { + struct broker *broker = &signalling.brokers[index]; + + if (broker->state == _broker_idle && broker->socket < 0 && !broker->failures) + continue; + broker_close(broker, 0); + broker->failures = 0; + /* (again at once) */ + broker->state_time = p2p_now() - MAXIMUM_RETRY_INTERVAL; + } +} + static void sync_all_topics(void) { int index;