diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index 2955c660a8..fd81962801 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -823,18 +823,6 @@ static int init_tcp_connection(const struct addrinfo *res, goto end; } - if (!spectate) - { - int new_fd = accept(fd, other_addr, &addr_size); - if (new_fd < 0) - { - ret = false; - goto end; - } - - socket_close(fd); - fd = new_fd; - } } end: @@ -973,6 +961,7 @@ netplay_t *netplay_new(const char *server, uint16_t port, netplay->port = server ? 0 : 1; netplay->spectate.enabled = spectate; netplay->is_server = server == NULL; + netplay->savestates_work = true; strlcpy(netplay->nick, nick, sizeof(netplay->nick)); netplay->stall_frames = frames; netplay->check_frames = check_frames; @@ -1289,7 +1278,12 @@ bool init_netplay(void) global->netplay.is_client = true; } else + { RARCH_LOG("Waiting for client...\n"); + runloop_msg_queue_push( + "Waiting for client...", + 0, 180, false); + } netplay_data = (netplay_t*)netplay_new( global->netplay.is_client ? global->netplay.server : NULL, diff --git a/network/netplay/netplay_common.c b/network/netplay/netplay_common.c index b19b104ce5..73d8ea52c3 100644 --- a/network/netplay/netplay_common.c +++ b/network/netplay/netplay_common.c @@ -185,6 +185,7 @@ bool netplay_get_info(netplay_t *netplay) retro_ctx_memory_info_t mem_info; uint32_t *content_crc_ptr = NULL; const void *sram = NULL; + size_t i; if (!socket_receive_all_blocking(netplay->fd, header, sizeof(header))) { @@ -243,6 +244,20 @@ bool netplay_get_info(netplay_t *netplay) return false; } + /* Reset our frame count so it's consistent with the client */ + netplay->self_frame_count = netplay->read_frame_count = netplay->other_frame_count = 0; + for (i = 0; i < netplay->buffer_size; i++) + { + if (i == netplay->self_ptr) + { + netplay->buffer[i].frame = 0; + } + else + { + netplay->buffer[i].used = false; + } + } + #ifndef HAVE_SOCKET_LEGACY netplay_log_connection(&netplay->other_addr, 0, netplay->other_nick); #endif diff --git a/network/netplay/netplay_net.c b/network/netplay/netplay_net.c index 56ede8892e..0ad4852f6e 100644 --- a/network/netplay/netplay_net.c +++ b/network/netplay/netplay_net.c @@ -18,6 +18,9 @@ #include #include +#include +#include + #include "netplay_private.h" #include "retro_assert.h" @@ -76,15 +79,80 @@ static bool netplay_net_pre_frame(netplay_t *netplay) { /* If the core can't serialize properly, we must stall for the * remote input on EVERY frame, because we can't recover */ + netplay->savestates_work = false; netplay->stall_frames = 0; + if (!netplay->has_connection) + netplay->stall = RARCH_NETPLAY_STALL_NO_CONNECTION; + } + } + + if (netplay->is_server && !netplay->has_connection) + { + fd_set fds; + struct timeval tmp_tv = {0}; + int new_fd, idx, i; + struct sockaddr_storage their_addr; + socklen_t addr_size; + + /* Check for a connection */ + FD_ZERO(&fds); + FD_SET(netplay->fd, &fds); + if (socket_select(netplay->fd + 1, &fds, NULL, NULL, &tmp_tv) > 0 && + FD_ISSET(netplay->fd, &fds)) + { + addr_size = sizeof(their_addr); + new_fd = accept(netplay->fd, (struct sockaddr*)&their_addr, &addr_size); + if (new_fd < 0) + { + RARCH_ERR("%s\n", msg_hash_to_str(MSG_NETPLAY_FAILED)); + return true; + } + + socket_close(netplay->fd); + netplay->fd = new_fd; + +#if defined(IPPROTO_TCP) && defined(TCP_NODELAY) + { + int flag = 1; + setsockopt(netplay->fd, IPPROTO_TCP, TCP_NODELAY, (void*)&flag, sizeof(int)); + } +#endif + + /* Connection header */ + if (netplay_get_info(netplay)) + { + netplay->has_connection = true; + + /* If we're not at frame 0, send them the savestate */ + if (netplay->self_frame_count != 0 && netplay->savestates_work) + { + serial_info.size = netplay->state_size; + serial_info.data_const = netplay->buffer[netplay->self_ptr].state; + netplay_load_savestate(netplay, &serial_info, false); + } + + /* And expect the current frame from the other side */ + netplay->read_frame_count = netplay->other_frame_count = netplay->self_frame_count; + netplay->read_ptr = netplay->other_ptr = netplay->read_ptr; + + /* Unstall if we were waiting for this */ + if (netplay->stall == RARCH_NETPLAY_STALL_NO_CONNECTION) + netplay->stall = 0; + + } + else + { + socket_close(netplay->fd); + /* FIXME: Get in a state to accept another client */ + + } } } netplay->can_poll = true; - input_poll_net(); - return true; + return (netplay->stall != RARCH_NETPLAY_STALL_NO_CONNECTION); } /** @@ -195,18 +263,12 @@ static void netplay_net_post_frame(netplay_t *netplay) static bool netplay_net_info_cb(netplay_t* netplay, unsigned frames) { - if (netplay_is_server(netplay)) + if (!netplay_is_server(netplay)) { if (!netplay_send_info(netplay)) return false; + netplay->has_connection = true; } - else - { - if (!netplay_get_info(netplay)) - return false; - } - - netplay->has_connection = true; return true; } diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index e8082899e8..b4f86d8819 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -74,7 +74,8 @@ struct netplay_callbacks { enum rarch_netplay_stall_reasons { RARCH_NETPLAY_STALL_NONE = 0, - RARCH_NETPLAY_STALL_RUNNING_FAST + RARCH_NETPLAY_STALL_RUNNING_FAST, + RARCH_NETPLAY_STALL_NO_CONNECTION }; struct netplay @@ -115,6 +116,9 @@ struct netplay * events, such as player flipping or savestate loading. */ bool force_rewind; + /* Does the core support savestates? */ + bool savestates_work; + /* Force our state to be sent to the other side. Used when they request a * savestate, to send at the next pre-frame. */ bool force_send_savestate;