From da7efcb93981ee529f8d1b56839b581791ef53cb Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Thu, 15 Dec 2016 08:42:03 -0500 Subject: [PATCH] Cleaning up netplay headers. --- network/netplay/netplay_buf.c | 55 +++- network/netplay/netplay_delta.c | 17 +- network/netplay/netplay_discovery.c | 6 + network/netplay/netplay_frontend.c | 142 +++------ network/netplay/netplay_handshake.c | 44 ++- network/netplay/netplay_init.c | 139 +++++---- network/netplay/netplay_io.c | 91 +++++- network/netplay/netplay_private.h | 449 ++++++++++++++++++++-------- network/netplay/netplay_sync.c | 13 +- 9 files changed, 646 insertions(+), 310 deletions(-) diff --git a/network/netplay/netplay_buf.c b/network/netplay/netplay_buf.c index 8a69930bcc..6e18939eee 100644 --- a/network/netplay/netplay_buf.c +++ b/network/netplay/netplay_buf.c @@ -13,6 +13,8 @@ * If not, see . */ +#include + #include #include @@ -47,6 +49,11 @@ static size_t buf_remaining(struct socket_buffer *sbuf) return sbuf->bufsz - buf_used(sbuf) - 1; } +/** + * netplay_init_socket_buffer + * + * Initialize a new socket buffer. + */ bool netplay_init_socket_buffer(struct socket_buffer *sbuf, size_t size) { sbuf->data = malloc(size); @@ -57,6 +64,11 @@ bool netplay_init_socket_buffer(struct socket_buffer *sbuf, size_t size) return true; } +/** + * netplay_resize_socket_buffer + * + * Resize the given socket_buffer's buffer to the requested size. + */ bool netplay_resize_socket_buffer(struct socket_buffer *sbuf, size_t newsize) { unsigned char *newdata = malloc(newsize); @@ -91,6 +103,11 @@ bool netplay_resize_socket_buffer(struct socket_buffer *sbuf, size_t newsize) return true; } +/** + * netplay_deinit_socket_buffer + * + * Free a socket buffer. + */ void netplay_deinit_socket_buffer(struct socket_buffer *sbuf) { if (sbuf->data) @@ -102,7 +119,13 @@ void netplay_clear_socket_buffer(struct socket_buffer *sbuf) sbuf->start = sbuf->read = sbuf->end = 0; } -bool netplay_send(struct socket_buffer *sbuf, int sockfd, const void *buf, size_t len) +/** + * netplay_send + * + * Queue the given data for sending. + */ +bool netplay_send(struct socket_buffer *sbuf, int sockfd, const void *buf, + size_t len) { if (buf_remaining(sbuf) < len) { @@ -143,6 +166,14 @@ bool netplay_send(struct socket_buffer *sbuf, int sockfd, const void *buf, size_ return netplay_send_flush(sbuf, sockfd, false); } +/** + * netplay_send_flush + * + * Flush unsent data in the given socket buffer, blocking to do so if + * requested. + * + * Returns false only on socket failures, true otherwise. + */ bool netplay_send_flush(struct socket_buffer *sbuf, int sockfd, bool block) { ssize_t sent; @@ -205,7 +236,15 @@ bool netplay_send_flush(struct socket_buffer *sbuf, int sockfd, bool block) return true; } -ssize_t netplay_recv(struct socket_buffer *sbuf, int sockfd, void *buf, size_t len, bool block) +/** + * netplay_recv + * + * Receive buffered or fresh data. + * + * Returns number of bytes returned, which may be short or 0, or -1 on error. + */ +ssize_t netplay_recv(struct socket_buffer *sbuf, int sockfd, void *buf, + size_t len, bool block) { bool error; ssize_t recvd; @@ -295,11 +334,23 @@ ssize_t netplay_recv(struct socket_buffer *sbuf, int sockfd, void *buf, size_t l return recvd; } +/** + * netplay_recv_reset + * + * Reset our recv buffer so that future netplay_recvs will read the same data + * again. + */ void netplay_recv_reset(struct socket_buffer *sbuf) { sbuf->read = sbuf->start; } +/** + * netplay_recv_flush + * + * Flush our recv buffer, so a future netplay_recv_reset will reset to this + * point. + */ void netplay_recv_flush(struct socket_buffer *sbuf) { sbuf->start = sbuf->read; diff --git a/network/netplay/netplay_delta.c b/network/netplay/netplay_delta.c index b5c49760e8..894478107b 100644 --- a/network/netplay/netplay_delta.c +++ b/network/netplay/netplay_delta.c @@ -23,7 +23,17 @@ #include "netplay_private.h" -bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, uint32_t frame) +/** + * netplay_delta_frame_ready + * + * Prepares, if possible, a delta frame for input, and reports whether it is + * ready. + * + * Returns: True if the delta frame is ready for input at the given frame, + * false otherwise. + */ +bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, + uint32_t frame) { void *remember_state; if (delta->used) @@ -43,6 +53,11 @@ bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, ui return true; } +/** + * netplay_delta_frame_crc + * + * Get the CRC for the serialization of this frame. + */ uint32_t netplay_delta_frame_crc(netplay_t *netplay, struct delta_frame *delta) { if (!netplay->state_size) diff --git a/network/netplay/netplay_discovery.c b/network/netplay/netplay_discovery.c index b360db50b4..34780a6c17 100644 --- a/network/netplay/netplay_discovery.c +++ b/network/netplay/netplay_discovery.c @@ -32,6 +32,7 @@ */ #include +#include #include #include @@ -191,6 +192,11 @@ error: return false; } +/** + * netplay_lan_ad_server + * + * Respond to any LAN ad queries that the netplay server has received. + */ bool netplay_lan_ad_server(netplay_t *netplay) { fd_set fds; diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index fd9e0c00c4..e33771334f 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -28,10 +28,6 @@ #include "../../input/input_driver.h" #include "../../runloop.h" -#ifndef HAVE_SOCKET_LEGACY -static void announce_nat_traversal(netplay_t *netplay); -#endif - /* Only used before init_netplay */ static bool netplay_enabled = false; static bool netplay_is_client = false; @@ -286,13 +282,18 @@ static bool netplay_poll(void) return true; } -/* Netplay polling callbacks */ +/** + * input_poll_net + * + * Poll the network if necessary. + */ void input_poll_net(void) { if (!netplay_should_skip(netplay_data) && netplay_can_poll(netplay_data)) netplay_poll(); } +/* Netplay polling callbacks */ void video_frame_net(const void *data, unsigned width, unsigned height, size_t pitch) { @@ -436,6 +437,42 @@ static void netplay_flip_users(netplay_t *netplay) netplay->flip_frame = flip_frame; } +/** + * netplay_frontend_paused + * @netplay : pointer to netplay object + * @paused : true if frontend is paused + * + * Inform Netplay of the frontend's pause state (paused or otherwise) + */ +static void netplay_frontend_paused(netplay_t *netplay, bool paused) +{ + size_t i; + + /* Nothing to do if we already knew this */ + if (netplay->local_paused == paused) + return; + + netplay->local_paused = paused; + + /* If other connections are paused, nothing to say */ + if (netplay->remote_paused) + return; + + /* Have to send manually because every buffer must be flushed immediately */ + for (i = 0; i < netplay->connections_size; i++) + { + struct netplay_connection *connection = &netplay->connections[i]; + if (connection->active && connection->mode >= NETPLAY_CONNECTION_CONNECTED) + { + netplay_send_raw_cmd(netplay, connection, + paused ? NETPLAY_CMD_PAUSE : NETPLAY_CMD_RESUME, NULL, 0); + + /* We're not going to be polled, so we need to flush this command now */ + netplay_send_flush(&connection->send_packet_buffer, connection->fd, true); + } + } +} + /** * netplay_pre_frame: * @netplay : pointer to netplay object @@ -478,7 +515,7 @@ bool netplay_pre_frame(netplay_t *netplay) #ifndef HAVE_SOCKET_LEGACY if (!netplay->nat_traversal_state.request_outstanding || netplay->nat_traversal_state.have_inet4) - announce_nat_traversal(netplay); + netplay_announce_nat_traversal(netplay); #endif } } @@ -515,42 +552,6 @@ void netplay_post_frame(netplay_t *netplay) } } -/** - * netplay_frontend_paused - * @netplay : pointer to netplay object - * @paused : true if frontend is paused - * - * Inform Netplay of the frontend's pause state (paused or otherwise) - **/ -void netplay_frontend_paused(netplay_t *netplay, bool paused) -{ - size_t i; - - /* Nothing to do if we already knew this */ - if (netplay->local_paused == paused) - return; - - netplay->local_paused = paused; - - /* If other connections are paused, nothing to say */ - if (netplay->remote_paused) - return; - - /* Have to send manually because every buffer must be flushed immediately */ - for (i = 0; i < netplay->connections_size; i++) - { - struct netplay_connection *connection = &netplay->connections[i]; - if (connection->active && connection->mode >= NETPLAY_CONNECTION_CONNECTED) - { - netplay_send_raw_cmd(netplay, connection, - paused ? NETPLAY_CMD_PAUSE : NETPLAY_CMD_RESUME, NULL, 0); - - /* We're not going to be polled, so we need to flush this command now */ - netplay_send_flush(&connection->send_packet_buffer, connection->fd, true); - } - } -} - /** * netplay_load_savestate * @netplay : pointer to netplay object @@ -669,63 +670,6 @@ void netplay_load_savestate(netplay_t *netplay, } } -/** - * netplay_init_nat_traversal - * - * Initialize the NAT traversal library and try to open a port - */ -void netplay_init_nat_traversal(netplay_t *netplay) -{ - natt_init(); - - if (!natt_new(&netplay->nat_traversal_state)) - { - netplay->nat_traversal = false; - return; - } - - natt_open_port_any(&netplay->nat_traversal_state, netplay->tcp_port, SOCKET_PROTOCOL_TCP); - -#ifndef HAVE_SOCKET_LEGACY - if (!netplay->nat_traversal_state.request_outstanding) - announce_nat_traversal(netplay); -#endif -} - -#ifndef HAVE_SOCKET_LEGACY -static void announce_nat_traversal(netplay_t *netplay) -{ - char msg[512], host[PATH_MAX_LENGTH], port[6]; - - if (netplay->nat_traversal_state.have_inet4) - { - if (getnameinfo((const struct sockaddr *) &netplay->nat_traversal_state.ext_inet4_addr, - sizeof(struct sockaddr_in), - host, PATH_MAX_LENGTH, port, 6, NI_NUMERICHOST|NI_NUMERICSERV) != 0) - return; - - } -#ifdef HAVE_INET6 - else if (netplay->nat_traversal_state.have_inet6) - { - if (getnameinfo((const struct sockaddr *) &netplay->nat_traversal_state.ext_inet6_addr, - sizeof(struct sockaddr_in6), - host, PATH_MAX_LENGTH, port, 6, NI_NUMERICHOST|NI_NUMERICSERV) != 0) - return; - - } -#endif - else - return; - - snprintf(msg, sizeof(msg), "%s: %s:%s\n", - msg_hash_to_str(MSG_PUBLIC_ADDRESS), - host, port); - runloop_msg_queue_push(msg, 1, 180, false); - RARCH_LOG("%s\n", msg); -} -#endif - /** * netplay_toggle_play_spectate * diff --git a/network/netplay/netplay_handshake.c b/network/netplay/netplay_handshake.c index 90e6cc7996..e8856810f6 100644 --- a/network/netplay/netplay_handshake.c +++ b/network/netplay/netplay_handshake.c @@ -229,7 +229,13 @@ static uint32_t simple_rand_uint32() parts[2]); } -bool netplay_handshake_init_send(netplay_t *netplay, struct netplay_connection *connection) +/** + * netplay_handshake_init_send + * + * Initialize our handshake and send the first part of the handshake protocol. + */ +bool netplay_handshake_init_send(netplay_t *netplay, + struct netplay_connection *connection) { uint32_t *content_crc_ptr = NULL; uint32_t header[5] = {0}; @@ -307,7 +313,14 @@ static void handshake_password(void *ignore, const char *line) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); } -bool netplay_handshake_init(netplay_t *netplay, struct netplay_connection *connection, bool *had_input) +/** + * netplay_handshake_init + * + * Data receiver for the initial part of the handshake, i.e., waiting for the + * netplay header. + */ +bool netplay_handshake_init(netplay_t *netplay, + struct netplay_connection *connection, bool *had_input) { uint32_t header[5] = {0}; ssize_t recvd; @@ -509,7 +522,14 @@ bool netplay_handshake_sync(netplay_t *netplay, struct netplay_connection *conne return true; } -bool netplay_handshake_pre_nick(netplay_t *netplay, struct netplay_connection *connection, bool *had_input) +/** + * netplay_handshake_pre_nick + * + * Data receiver for the second stage of handshake, receiving the other side's + * nickname. + */ +bool netplay_handshake_pre_nick(netplay_t *netplay, + struct netplay_connection *connection, bool *had_input) { struct nick_buf_s nick_buf; ssize_t recvd; @@ -567,7 +587,14 @@ bool netplay_handshake_pre_nick(netplay_t *netplay, struct netplay_connection *c return true; } -bool netplay_handshake_pre_password(netplay_t *netplay, struct netplay_connection *connection, bool *had_input) +/** + * netplay_handshake_pre_password + * + * Data receiver for the third, optional stage of server handshake, receiving + * the password. + */ +bool netplay_handshake_pre_password(netplay_t *netplay, + struct netplay_connection *connection, bool *had_input) { struct password_buf_s password_buf, corr_password_buf; char password[8+NETPLAY_PASS_LEN]; /* 8 for salt */ @@ -630,7 +657,14 @@ bool netplay_handshake_pre_password(netplay_t *netplay, struct netplay_connectio return true; } -bool netplay_handshake_pre_sync(netplay_t *netplay, struct netplay_connection *connection, bool *had_input) +/** + * netplay_handshake_pre_sync + * + * Data receiver for the client's third handshake stage, receiving the + * synchronization information. + */ +bool netplay_handshake_pre_sync(netplay_t *netplay, + struct netplay_connection *connection, bool *had_input) { uint32_t cmd[2]; uint32_t new_frame_count, connected_players, flip_frame; diff --git a/network/netplay/netplay_init.c b/network/netplay/netplay_init.c index dcbd2e71cb..579f1cb09d 100644 --- a/network/netplay/netplay_init.c +++ b/network/netplay/netplay_init.c @@ -264,62 +264,6 @@ static bool netplay_init_socket_buffers(netplay_t *netplay) return true; } -/** - * netplay_try_init_serialization - * - * Try to initialize serialization. For quirky cores. - * - * Returns true if serialization is now ready, false otherwise. - */ -bool netplay_try_init_serialization(netplay_t *netplay) -{ - retro_ctx_serialize_info_t serial_info; - size_t packet_buffer_size; - - if (netplay->state_size) - return true; - - if (!netplay_init_serialization(netplay)) - return false; - - /* Check if we can actually save */ - serial_info.data_const = NULL; - serial_info.data = netplay->buffer[netplay->self_ptr].state; - serial_info.size = netplay->state_size; - - if (!core_serialize(&serial_info)) - return false; - - /* Once initialized, we no longer exhibit this quirk */ - netplay->quirks &= ~((uint64_t) NETPLAY_QUIRK_INITIALIZATION); - - return netplay_init_socket_buffers(netplay); -} - -bool netplay_wait_and_init_serialization(netplay_t *netplay) -{ - int frame; - - if (netplay->state_size) - return true; - - /* Wait a maximum of 60 frames */ - for (frame = 0; frame < 60; frame++) { - if (netplay_try_init_serialization(netplay)) - return true; - -#if defined(HAVE_THREADS) - autosave_lock(); -#endif - core_run(); -#if defined(HAVE_THREADS) - autosave_unlock(); -#endif - } - - return false; -} - bool netplay_init_serialization(netplay_t *netplay) { unsigned i; @@ -358,6 +302,70 @@ bool netplay_init_serialization(netplay_t *netplay) return true; } +/** + * netplay_try_init_serialization + * + * Try to initialize serialization. For quirky cores. + * + * Returns true if serialization is now ready, false otherwise. + */ +bool netplay_try_init_serialization(netplay_t *netplay) +{ + retro_ctx_serialize_info_t serial_info; + size_t packet_buffer_size; + + if (netplay->state_size) + return true; + + if (!netplay_init_serialization(netplay)) + return false; + + /* Check if we can actually save */ + serial_info.data_const = NULL; + serial_info.data = netplay->buffer[netplay->self_ptr].state; + serial_info.size = netplay->state_size; + + if (!core_serialize(&serial_info)) + return false; + + /* Once initialized, we no longer exhibit this quirk */ + netplay->quirks &= ~((uint64_t) NETPLAY_QUIRK_INITIALIZATION); + + return netplay_init_socket_buffers(netplay); +} + +/** + * netplay_wait_and_init_serialization + * + * Try very hard to initialize serialization, simulating multiple frames if + * necessary. For quirky cores. + * + * Returns true if serialization is now ready, false otherwise. + */ +bool netplay_wait_and_init_serialization(netplay_t *netplay) +{ + int frame; + + if (netplay->state_size) + return true; + + /* Wait a maximum of 60 frames */ + for (frame = 0; frame < 60; frame++) { + if (netplay_try_init_serialization(netplay)) + return true; + +#if defined(HAVE_THREADS) + autosave_lock(); +#endif + core_run(); +#if defined(HAVE_THREADS) + autosave_unlock(); +#endif + } + + return false; +} + static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) { size_t packet_buffer_size; @@ -397,15 +405,16 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) * @nick : Nickname of user. * @quirks : Netplay quirks required for this session. * - * Creates a new netplay handle. A NULL host means we're - * hosting (user 1). + * Creates a new netplay handle. A NULL server means we're + * hosting. * - * Returns: new netplay handle. - **/ + * Returns: new netplay data. + */ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port, const char *play_password, const char *spectate_password, - unsigned delay_frames, unsigned check_frames, const struct retro_callbacks - *cb, bool nat_traversal, const char *nick, uint64_t quirks) + unsigned delay_frames, unsigned check_frames, + const struct retro_callbacks *cb, bool nat_traversal, const char *nick, + uint64_t quirks) { netplay_t *netplay = (netplay_t*)calloc(1, sizeof(*netplay)); if (!netplay) @@ -486,11 +495,11 @@ error: } /** - * netplay_free: + * netplay_free * @netplay : pointer to netplay object * - * Frees netplay handle. - **/ + * Frees netplay data/ + */ void netplay_free(netplay_t *netplay) { size_t i; diff --git a/network/netplay/netplay_io.c b/network/netplay/netplay_io.c index ab603ed386..b1e15c1c15 100644 --- a/network/netplay/netplay_io.c +++ b/network/netplay/netplay_io.c @@ -54,7 +54,7 @@ static void remote_unpaused(netplay_t *netplay, struct netplay_connection *conne * netplay_hangup: * * Disconnects an active Netplay connection due to an error - **/ + */ void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection) { if (!netplay) @@ -145,7 +145,13 @@ static bool send_input_frame(netplay_t *netplay, return true; } -/* Send the current input frame */ +/** + * netplay_send_cur_input + * + * Send the current input frame to a given connection. + * + * Returns true if successful, false otherwise. + */ bool netplay_send_cur_input(netplay_t *netplay, struct netplay_connection *connection) { @@ -203,9 +209,9 @@ bool netplay_send_cur_input(netplay_t *netplay, /** * netplay_send_raw_cmd * - * Send a raw Netplay command to the given connection + * Send a raw Netplay command to the given connection. * - * Returns true on success, false on failure + * Returns true on success, false on failure. */ bool netplay_send_raw_cmd(netplay_t *netplay, struct netplay_connection *connection, uint32_t cmd, const void *data, @@ -258,6 +264,11 @@ static bool netplay_cmd_nak(netplay_t *netplay, return false; } +/** + * netplay_cmd_crc + * + * Send a CRC command to all active clients. + */ bool netplay_cmd_crc(netplay_t *netplay, struct delta_frame *delta) { uint32_t payload[2]; @@ -275,6 +286,11 @@ bool netplay_cmd_crc(netplay_t *netplay, struct delta_frame *delta) return success; } +/** + * netplay_cmd_request_savestate + * + * Send a savestate request command. + */ bool netplay_cmd_request_savestate(netplay_t *netplay) { if (netplay->connections_size == 0 || @@ -288,6 +304,11 @@ bool netplay_cmd_request_savestate(netplay_t *netplay) NETPLAY_CMD_REQUEST_SAVESTATE, NULL, 0); } +/** + * netplay_cmd_mode + * + * Send a mode request command to either play or spectate. + */ bool netplay_cmd_mode(netplay_t *netplay, struct netplay_connection *connection, enum rarch_netplay_connection_mode mode) @@ -1079,3 +1100,65 @@ bool netplay_flip_port(netplay_t *netplay) return netplay->flip ^ (frame < netplay->flip_frame); } + +/** + * netplay_announce_nat_traversal + * + * Announce successful NAT traversal. + */ +void netplay_announce_nat_traversal(netplay_t *netplay) +{ +#ifndef HAVE_SOCKET_LEGACY + char msg[512], host[PATH_MAX_LENGTH], port[6]; + + if (netplay->nat_traversal_state.have_inet4) + { + if (getnameinfo((const struct sockaddr *) &netplay->nat_traversal_state.ext_inet4_addr, + sizeof(struct sockaddr_in), + host, PATH_MAX_LENGTH, port, 6, NI_NUMERICHOST|NI_NUMERICSERV) != 0) + return; + + } +#ifdef HAVE_INET6 + else if (netplay->nat_traversal_state.have_inet6) + { + if (getnameinfo((const struct sockaddr *) &netplay->nat_traversal_state.ext_inet6_addr, + sizeof(struct sockaddr_in6), + host, PATH_MAX_LENGTH, port, 6, NI_NUMERICHOST|NI_NUMERICSERV) != 0) + return; + + } +#endif + else + return; + + snprintf(msg, sizeof(msg), "%s: %s:%s\n", + msg_hash_to_str(MSG_PUBLIC_ADDRESS), + host, port); + runloop_msg_queue_push(msg, 1, 180, false); + RARCH_LOG("%s\n", msg); +#endif +} + +/** + * netplay_init_nat_traversal + * + * Initialize the NAT traversal library and try to open a port + */ +void netplay_init_nat_traversal(netplay_t *netplay) +{ + natt_init(); + + if (!natt_new(&netplay->nat_traversal_state)) + { + netplay->nat_traversal = false; + return; + } + + natt_open_port_any(&netplay->nat_traversal_state, netplay->tcp_port, SOCKET_PROTOCOL_TCP); + +#ifndef HAVE_SOCKET_LEGACY + if (!netplay->nat_traversal_state.request_outstanding) + netplay_announce_nat_traversal(netplay); +#endif +} diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index 81c4a2fb05..25b7cae79d 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -24,16 +24,10 @@ #include #include #include -#include -#include "../../core.h" #include "../../msg_hash.h" #include "../../verbosity.h" -#ifdef ANDROID -#define HAVE_IPV6 -#endif - #define WORDS_PER_INPUT 3 /* Buttons, left stick, right stick */ #define WORDS_PER_FRAME (WORDS_PER_INPUT+2) /* + frameno, playerno */ @@ -419,8 +413,209 @@ struct netplay uint32_t check_frames; }; + +/*************************************************************** + * NETPLAY-BUF.C + **************************************************************/ + +/** + * netplay_init_socket_buffer + * + * Initialize a new socket buffer. + */ +bool netplay_init_socket_buffer(struct socket_buffer *sbuf, size_t size); + +/** + * netplay_resize_socket_buffer + * + * Resize the given socket_buffer's buffer to the requested size. + */ +bool netplay_resize_socket_buffer(struct socket_buffer *sbuf, size_t newsize); + +/** + * netplay_deinit_socket_buffer + * + * Free a socket buffer. + */ +void netplay_deinit_socket_buffer(struct socket_buffer *sbuf); + +/** + * netplay_send + * + * Queue the given data for sending. + */ +bool netplay_send(struct socket_buffer *sbuf, int sockfd, const void *buf, + size_t len); + +/** + * netplay_send_flush + * + * Flush unsent data in the given socket buffer, blocking to do so if + * requested. + * + * Returns false only on socket failures, true otherwise. + */ +bool netplay_send_flush(struct socket_buffer *sbuf, int sockfd, bool block); + +/** + * netplay_recv + * + * Receive buffered or fresh data. + * + * Returns number of bytes returned, which may be short or 0, or -1 on error. + */ +ssize_t netplay_recv(struct socket_buffer *sbuf, int sockfd, void *buf, + size_t len, bool block); + +/** + * netplay_recv_reset + * + * Reset our recv buffer so that future netplay_recvs will read the same data + * again. + */ +void netplay_recv_reset(struct socket_buffer *sbuf); + +/** + * netplay_recv_flush + * + * Flush our recv buffer, so a future netplay_recv_reset will reset to this + * point. + */ +void netplay_recv_flush(struct socket_buffer *sbuf); + + +/*************************************************************** + * NETPLAY-DELTA.C + **************************************************************/ + +/** + * netplay_delta_frame_ready + * + * Prepares, if possible, a delta frame for input, and reports whether it is + * ready. + * + * Returns: True if the delta frame is ready for input at the given frame, + * false otherwise. + */ +bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, + uint32_t frame); + +/** + * netplay_delta_frame_crc + * + * Get the CRC for the serialization of this frame. + */ +uint32_t netplay_delta_frame_crc(netplay_t *netplay, struct delta_frame *delta); + + +/*************************************************************** + * NETPLAY-DISCOVERY.C + **************************************************************/ + +/** + * netplay_lan_ad_server + * + * Respond to any LAN ad queries that the netplay server has received. + */ +bool netplay_lan_ad_server(netplay_t *netplay); + + +/*************************************************************** + * NETPLAY-FRONTEND.C + **************************************************************/ + +/** + * netplay_load_savestate + * @netplay : pointer to netplay object + * @serial_info : the savestate being loaded, NULL means + * "load it yourself" + * @save : Whether to save the provided serial_info + * into the frame buffer + * + * Inform Netplay of a savestate load and send it to the other side + **/ +void netplay_load_savestate(netplay_t *netplay, + retro_ctx_serialize_info_t *serial_info, bool save); + +/** + * input_poll_net + * + * Poll the network if necessary. + */ void input_poll_net(void); +/*************************************************************** + * NETPLAY-HANDSHAKE.C + **************************************************************/ + +/** + * netplay_handshake_init_send + * + * Initialize our handshake and send the first part of the handshake protocol. + */ +bool netplay_handshake_init_send(netplay_t *netplay, + struct netplay_connection *connection); + +/** + * netplay_handshake_init + * + * Data receiver for the initial part of the handshake, i.e., waiting for the + * netplay header. + */ +bool netplay_handshake_init(netplay_t *netplay, + struct netplay_connection *connection, bool *had_input); + +/** + * netplay_handshake_pre_nick + * + * Data receiver for the second stage of handshake, receiving the other side's + * nickname. + */ +bool netplay_handshake_pre_nick(netplay_t *netplay, + struct netplay_connection *connection, bool *had_input); + +/** + * netplay_handshake_pre_password + * + * Data receiver for the third, optional stage of server handshake, receiving + * the password. + */ +bool netplay_handshake_pre_password(netplay_t *netplay, + struct netplay_connection *connection, bool *had_input); + +/** + * netplay_handshake_pre_sync + * + * Data receiver for the client's third handshake stage, receiving the + * synchronization information. + */ +bool netplay_handshake_pre_sync(netplay_t *netplay, + struct netplay_connection *connection, bool *had_input); + + +/*************************************************************** + * NETPLAY-INIT.C + **************************************************************/ + +/** + * netplay_try_init_serialization + * + * Try to initialize serialization. For quirky cores. + * + * Returns true if serialization is now ready, false otherwise. + */ +bool netplay_try_init_serialization(netplay_t *netplay); + +/** + * netplay_wait_and_init_serialization + * + * Try very hard to initialize serialization, simulating multiple frames if + * necessary. For quirky cores. + * + * Returns true if serialization is now ready, false otherwise. + */ +bool netplay_wait_and_init_serialization(netplay_t *netplay); + /** * netplay_new: * @direct_host : Netplay host discovered from scanning. @@ -435,160 +630,158 @@ void input_poll_net(void); * @nick : Nickname of user. * @quirks : Netplay quirks required for this session. * - * Creates a new netplay handle. A NULL host means we're - * hosting (user 1). + * Creates a new netplay handle. A NULL server means we're + * hosting. * - * Returns: new netplay handle. - **/ + * Returns: new netplay data. + */ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port, const char *play_password, const char *spectate_password, - unsigned delay_frames, unsigned check_frames, const struct retro_callbacks - *cb, bool nat_traversal, const char *nick, uint64_t quirks); + unsigned delay_frames, unsigned check_frames, + const struct retro_callbacks *cb, bool nat_traversal, const char *nick, + uint64_t quirks); /** - * netplay_free: + * netplay_free * @netplay : pointer to netplay object * - * Frees netplay handle. - **/ -void netplay_free(netplay_t *handle); + * Frees netplay data/ + */ +void netplay_free(netplay_t *netplay); + + +/*************************************************************** + * NETPLAY-IO.C + **************************************************************/ /** - * netplay_pre_frame: - * @netplay : pointer to netplay object + * netplay_hangup: * - * Pre-frame for Netplay. - * Call this before running retro_run(). - * - * Returns: true (1) if the frontend is clear to emulate the frame, false (0) - * if we're stalled or paused - **/ -bool netplay_pre_frame(netplay_t *handle); + * Disconnects an active Netplay connection due to an error + */ +void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection); /** - * netplay_post_frame: - * @netplay : pointer to netplay object + * netplay_send_cur_input * - * Post-frame for Netplay. - * We check if we have new input and replay from recorded input. - * Call this after running retro_run(). - **/ -void netplay_post_frame(netplay_t *handle); - -/** - * netplay_frontend_paused - * @netplay : pointer to netplay object - * @paused : true if frontend is paused + * Send the current input frame to a given connection. * - * Inform Netplay of the frontend's pause state (paused or otherwise) - **/ -void netplay_frontend_paused(netplay_t *netplay, bool paused); - -/** - * netplay_load_savestate - * @netplay : pointer to netplay object - * @serial_info : the savestate being loaded, NULL means "load it yourself" - * @save : whether to save the provided serial_info into the frame buffer - * - * Inform Netplay of a savestate load and send it to the other side - **/ -void netplay_load_savestate(netplay_t *netplay, retro_ctx_serialize_info_t *serial_info, bool save); - -/** - * netplay_disconnect - * @netplay : pointer to netplay object - * - * Disconnect netplay. - * - * Returns: true (1) if successful. At present, cannot fail. - **/ -bool netplay_disconnect(netplay_t *netplay); - -bool netplay_sync_pre_frame(netplay_t *netplay); - -void netplay_sync_post_frame(netplay_t *netplay); - -/* Normally called at init time, unless the INITIALIZATION quirk is set */ -bool netplay_init_serialization(netplay_t *netplay); - -/* Force serialization to be ready by fast-forwarding the core */ -bool netplay_wait_and_init_serialization(netplay_t *netplay); - -void netplay_simulate_input(netplay_t *netplay, size_t sim_ptr, bool resim); - -void netplay_log_connection(const struct sockaddr_storage *their_addr, - unsigned slot, const char *nick); - -bool netplay_get_nickname(netplay_t *netplay, int fd); - -bool netplay_send_nickname(netplay_t *netplay, int fd); - -/* Various netplay initialization modes: */ -bool netplay_handshake_init_send(netplay_t *netplay, struct netplay_connection *connection); -bool netplay_handshake_init(netplay_t *netplay, struct netplay_connection *connection, bool *had_input); -bool netplay_handshake_pre_nick(netplay_t *netplay, struct netplay_connection *connection, bool *had_input); -bool netplay_handshake_pre_password(netplay_t *netplay, struct netplay_connection *connection, bool *had_input); -bool netplay_handshake_pre_sync(netplay_t *netplay, struct netplay_connection *connection, bool *had_input); - -uint32_t netplay_impl_magic(void); - -bool netplay_is_server(netplay_t* netplay); - -bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, uint32_t frame); - -uint32_t netplay_delta_frame_crc(netplay_t *netplay, struct delta_frame *delta); - -bool netplay_cmd_crc(netplay_t *netplay, struct delta_frame *delta); - -bool netplay_cmd_request_savestate(netplay_t *netplay); - -bool netplay_cmd_mode(netplay_t *netplay, - struct netplay_connection *connection, - enum rarch_netplay_connection_mode mode); - + * Returns true if successful, false otherwise. + */ bool netplay_send_cur_input(netplay_t *netplay, struct netplay_connection *connection); -int netplay_poll_net_input(netplay_t *netplay, bool block); - -void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection); - -void netplay_update_unread_ptr(netplay_t *netplay); - -bool netplay_flip_port(netplay_t *netplay); - +/** + * netplay_send_raw_cmd + * + * Send a raw Netplay command to the given connection. + * + * Returns true on success, false on failure. + */ bool netplay_send_raw_cmd(netplay_t *netplay, struct netplay_connection *connection, uint32_t cmd, const void *data, size_t size); +/** + * netplay_send_raw_cmd_all + * + * Send a raw Netplay command to all connections, optionally excluding one + * (typically the client that the relevant command came from) + */ void netplay_send_raw_cmd_all(netplay_t *netplay, struct netplay_connection *except, uint32_t cmd, const void *data, size_t size); -bool netplay_try_init_serialization(netplay_t *netplay); +/** + * netplay_cmd_crc + * + * Send a CRC command to all active clients. + */ +bool netplay_cmd_crc(netplay_t *netplay, struct delta_frame *delta); +/** + * netplay_cmd_request_savestate + * + * Send a savestate request command. + */ +bool netplay_cmd_request_savestate(netplay_t *netplay); + +/** + * netplay_cmd_mode + * + * Send a mode request command to either play or spectate. + */ +bool netplay_cmd_mode(netplay_t *netplay, + struct netplay_connection *connection, + enum rarch_netplay_connection_mode mode); + +/** + * netplay_poll_net_input + * + * Poll input from the network + */ +int netplay_poll_net_input(netplay_t *netplay, bool block); + +/** + * netplay_flip_port + * + * Should we flip ports 0 and 1? + */ +bool netplay_flip_port(netplay_t *netplay); + +/** + * netplay_announce_nat_traversal + * + * Announce successful NAT traversal. + */ +void netplay_announce_nat_traversal(netplay_t *netplay); + +/** + * netplay_init_nat_traversal + * + * Initialize the NAT traversal library and try to open a port + */ void netplay_init_nat_traversal(netplay_t *netplay); -/* DISCOVERY: */ -bool netplay_lan_ad_server(netplay_t *netplay); +/*************************************************************** + * NETPLAY-SYNC.C + **************************************************************/ -bool netplay_init_socket_buffer(struct socket_buffer *sbuf, size_t size); +/** + * netplay_update_unread_ptr + * + * Update the global unread_ptr and unread_frame_count to correspond to the + * earliest unread frame count of any connected player + */ +void netplay_update_unread_ptr(netplay_t *netplay); -bool netplay_resize_socket_buffer(struct socket_buffer *sbuf, size_t newsize); +/** + * netplay_simulate_input + * @netplay : pointer to netplay object + * @sim_ptr : frame index for which to simulate input + * @resim : are we resimulating, or simulating this frame for the + * first time? + * + * "Simulate" input by assuming it hasn't changed since the last read input. + */ +void netplay_simulate_input(netplay_t *netplay, size_t sim_ptr, bool resim); -void netplay_deinit_socket_buffer(struct socket_buffer *sbuf); +/** + * netplay_sync_pre_frame + * @netplay : pointer to netplay object + * + * Pre-frame for Netplay synchronization. + */ +bool netplay_sync_pre_frame(netplay_t *netplay); -void netplay_clear_socket_buffer(struct socket_buffer *sbuf); - -bool netplay_send(struct socket_buffer *sbuf, int sockfd, const void *buf, size_t len); - -bool netplay_send_flush(struct socket_buffer *sbuf, int sockfd, bool block); - -ssize_t netplay_recv(struct socket_buffer *sbuf, int sockfd, void *buf, size_t len, bool block); - -void netplay_recv_reset(struct socket_buffer *sbuf); - -void netplay_recv_flush(struct socket_buffer *sbuf); +/** + * netplay_sync_post_frame + * @netplay : pointer to netplay object + * + * Post-frame for Netplay synchronization. + * We check if we have new input and replay from recorded input. + */ +void netplay_sync_post_frame(netplay_t *netplay); #endif diff --git a/network/netplay/netplay_sync.c b/network/netplay/netplay_sync.c index 7635074ca7..f927f24719 100644 --- a/network/netplay/netplay_sync.c +++ b/network/netplay/netplay_sync.c @@ -32,7 +32,8 @@ * netplay_update_unread_ptr * * Update the global unread_ptr and unread_frame_count to correspond to the - * earliest unread frame count of any connected player */ + * earliest unread frame count of any connected player + */ void netplay_update_unread_ptr(netplay_t *netplay) { if (netplay->is_server && !netplay->connected_players) @@ -70,7 +71,7 @@ void netplay_update_unread_ptr(netplay_t *netplay) } /** - * netplay_simulate_input: + * netplay_simulate_input * @netplay : pointer to netplay object * @sim_ptr : frame index for which to simulate input * @resim : are we resimulating, or simulating this frame for the @@ -162,11 +163,11 @@ static void netplay_handle_frame_hash(netplay_t *netplay, struct delta_frame *de } /** - * netplay_sync_pre_frame: + * netplay_sync_pre_frame * @netplay : pointer to netplay object * * Pre-frame for Netplay synchronization. - **/ + */ bool netplay_sync_pre_frame(netplay_t *netplay) { retro_ctx_serialize_info_t serial_info; @@ -329,12 +330,12 @@ process: } /** - * netplay_sync_post_frame: + * netplay_sync_post_frame * @netplay : pointer to netplay object * * Post-frame for Netplay synchronization. * We check if we have new input and replay from recorded input. - **/ + */ void netplay_sync_post_frame(netplay_t *netplay) { netplay->self_ptr = NEXT_PTR(netplay->self_ptr);