Support for Netplay reconnection

In net server mode, when the client disconnects, the server now returns
to listening mode, in anticipation of the client reconnecting.
This commit is contained in:
Gregor Richards 2016-09-21 22:36:29 -04:00
parent af46e81080
commit 42f8ed4338
2 changed files with 45 additions and 17 deletions

View File

@ -47,15 +47,39 @@ enum
static void *netplay_data = NULL; static void *netplay_data = NULL;
static bool init_socket(netplay_t *netplay, const char *server, uint16_t port);
/** /**
* warn_hangup: * hangup:
* *
* Warns that netplay has disconnected. * Disconnects an active Netplay connection due to an error
**/ **/
static void warn_hangup(void) static void hangup(netplay_t *netplay)
{ {
RARCH_WARN("Netplay has disconnected. Will continue without connection ...\n"); if (netplay && netplay->has_connection)
runloop_msg_queue_push("Netplay has disconnected. Will continue without connection.", 0, 480, false); {
RARCH_WARN("Netplay has disconnected. Will continue without connection ...\n");
runloop_msg_queue_push("Netplay has disconnected. Will continue without connection.", 0, 480, false);
socket_close(netplay->fd);
netplay->fd = -1;
if (netplay->is_server && !netplay->spectate.enabled)
{
/* In server mode, make the socket listen for a new connection */
if (!init_socket(netplay, NULL, netplay->tcp_port))
{
RARCH_WARN("Failed to reinitialize Netplay.\n");
runloop_msg_queue_push("Failed to reinitialize Netplay.", 0, 480, false);
}
}
netplay->has_connection = false;
netplay->remote_paused = false;
}
} }
static bool netplay_info_cb(netplay_t* netplay, unsigned frames) static bool netplay_info_cb(netplay_t* netplay, unsigned frames)
@ -163,8 +187,7 @@ static bool get_self_input_state(netplay_t *netplay)
if (!socket_send_all_blocking(netplay->fd, if (!socket_send_all_blocking(netplay->fd,
netplay->packet_buffer, sizeof(netplay->packet_buffer), false)) netplay->packet_buffer, sizeof(netplay->packet_buffer), false))
{ {
warn_hangup(); hangup(netplay);
netplay->has_connection = false;
return false; return false;
} }
} }
@ -324,7 +347,7 @@ static bool netplay_get_cmd(netplay_t *netplay)
return netplay_cmd_nak(netplay); return netplay_cmd_nak(netplay);
case NETPLAY_CMD_DISCONNECT: case NETPLAY_CMD_DISCONNECT:
warn_hangup(); hangup(netplay);
return true; return true;
case NETPLAY_CMD_CRC: case NETPLAY_CMD_CRC:
@ -566,8 +589,7 @@ static bool netplay_poll(netplay_t *netplay)
res = poll_input(netplay, (netplay->stall_frames == 0) && (netplay->read_frame_count <= netplay->self_frame_count)); res = poll_input(netplay, (netplay->stall_frames == 0) && (netplay->read_frame_count <= netplay->self_frame_count));
if (res == -1) if (res == -1)
{ {
netplay->has_connection = false; hangup(netplay);
warn_hangup();
return false; return false;
} }
@ -602,8 +624,7 @@ static bool netplay_poll(netplay_t *netplay)
else if (now - netplay->stall_time >= MAX_STALL_TIME_USEC) else if (now - netplay->stall_time >= MAX_STALL_TIME_USEC)
{ {
/* Stalled out! */ /* Stalled out! */
netplay->has_connection = false; hangup(netplay);
warn_hangup();
return false; return false;
} }
} }
@ -823,6 +844,11 @@ static int init_tcp_connection(const struct addrinfo *res,
goto end; goto end;
} }
#if defined(F_SETFD) && defined(FD_CLOEXEC)
/* Don't let any inherited processes keep open our port */
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
} }
end: end:
@ -957,6 +983,7 @@ netplay_t *netplay_new(const char *server, uint16_t port,
return NULL; return NULL;
netplay->fd = -1; netplay->fd = -1;
netplay->tcp_port = server ? 0 : port;
netplay->cbs = *cb; netplay->cbs = *cb;
netplay->port = server ? 0 : 1; netplay->port = server ? 0 : 1;
netplay->spectate.enabled = spectate; netplay->spectate.enabled = spectate;
@ -1082,7 +1109,8 @@ void netplay_free(netplay_t *netplay)
{ {
unsigned i; unsigned i;
socket_close(netplay->fd); if (netplay->fd >= 0)
socket_close(netplay->fd);
if (netplay->spectate.enabled) if (netplay->spectate.enabled)
{ {
@ -1224,15 +1252,13 @@ void netplay_load_savestate(netplay_t *netplay, retro_ctx_serialize_info_t *seri
if (!socket_send_all_blocking(netplay->fd, header, sizeof(header), false)) if (!socket_send_all_blocking(netplay->fd, header, sizeof(header), false))
{ {
warn_hangup(); hangup(netplay);
netplay->has_connection = false;
return; return;
} }
if (!socket_send_all_blocking(netplay->fd, serial_info->data_const, serial_info->size, false)) if (!socket_send_all_blocking(netplay->fd, serial_info->data_const, serial_info->size, false))
{ {
warn_hangup(); hangup(netplay);
netplay->has_connection = false;
return; return;
} }
} }

View File

@ -87,6 +87,8 @@ struct netplay
struct retro_callbacks cbs; struct retro_callbacks cbs;
/* TCP connection for state sending, etc. Also used for commands */ /* TCP connection for state sending, etc. Also used for commands */
int fd; int fd;
/* TCP port (if serving) */
uint16_t tcp_port;
/* Which port is governed by netplay (other user)? */ /* Which port is governed by netplay (other user)? */
unsigned port; unsigned port;
bool has_connection; bool has_connection;