From 26132a2330880cbbbf621c5af552d6e829f4f27d Mon Sep 17 00:00:00 2001 From: Cthulhu-throwaway <96153783+Cthulhu-throwaway@users.noreply.github.com> Date: Sat, 25 Dec 2021 09:42:22 -0300 Subject: [PATCH] Netplay and NAT struct improvements (#13416) Reordered netplay and NAT structs to follow the coding guidelines more closely. Moved part of the chat struct out of the program's image and into the heap. --- libretro-common/include/net/net_natt.h | 12 +- libretro-common/net/net_natt.c | 4 +- network/netplay/netplay.h | 57 ++++---- network/netplay/netplay_frontend.c | 151 ++++++++++----------- network/netplay/netplay_private.h | 175 ++++++++++++------------- 5 files changed, 199 insertions(+), 200 deletions(-) diff --git a/libretro-common/include/net/net_natt.h b/libretro-common/include/net/net_natt.h index 03916deca6..43c7948681 100644 --- a/libretro-common/include/net/net_natt.h +++ b/libretro-common/include/net/net_natt.h @@ -54,40 +54,40 @@ enum nat_traversal_status struct natt_device { + struct sockaddr_in ext_addr; char desc [512]; char control [512]; char service_type[512]; - struct sockaddr_in ext_addr; bool busy; }; struct natt_request { - struct natt_device *device; struct sockaddr_in addr; + struct natt_device *device; enum socket_protocol proto; bool success; }; struct nat_traversal_data { - size_t iface; struct natt_request request; + size_t iface; enum natt_forward_type forward_type; enum nat_traversal_status status; }; typedef struct { + /* Timeout for our discovery request. */ + retro_time_t timeout; + /* List of available network interfaces. */ struct net_ifinfo interfaces; /* Device we are operating on. */ struct natt_device device; - /* Timeout for our discovery request. */ - retro_time_t timeout; - /* File descriptor of the socket we are receiving discovery data. */ int fd; } natt_state_t; diff --git a/libretro-common/net/net_natt.c b/libretro-common/net/net_natt.c index 57f1293b3c..55505139ef 100644 --- a/libretro-common/net/net_natt.c +++ b/libretro-common/net/net_natt.c @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if !defined(HAVE_SOCKET_LEGACY) && defined(_WIN32) +#if !defined(HAVE_SOCKET_LEGACY) && defined(_WIN32) && defined(_MSC_VER) #pragma comment(lib, "Iphlpapi") #endif @@ -43,7 +43,7 @@ #include #endif -static natt_state_t natt_st = {{0}, {{0}}, 0, -1}; +static natt_state_t natt_st = {0, {0}, {{0}}, -1}; natt_state_t *natt_state_get_ptr(void) { diff --git a/network/netplay/netplay.h b/network/netplay/netplay.h index 15f996d343..2790138f4a 100644 --- a/network/netplay/netplay.h +++ b/network/netplay/netplay.h @@ -200,52 +200,57 @@ struct netplay_host_list size_t size; }; -struct netplay_chat_data -{ - char nick[NETPLAY_NICK_LEN]; - char msg[NETPLAY_CHAT_MAX_SIZE]; - uint32_t frames; -}; - -struct netplay_chat_buffer -{ - char nick[NETPLAY_NICK_LEN]; - char msg[NETPLAY_CHAT_MAX_SIZE]; - uint8_t alpha; -}; - struct netplay_chat { struct { - struct netplay_chat_data data; - struct netplay_chat_buffer buffer; + uint32_t frames; + char nick[NETPLAY_NICK_LEN]; + char msg[NETPLAY_CHAT_MAX_SIZE]; } messages[NETPLAY_CHAT_MAX_MESSAGES]; uint32_t message_slots; }; +struct netplay_chat_buffer +{ + struct + { + uint8_t alpha; + char nick[NETPLAY_NICK_LEN]; + char msg[NETPLAY_CHAT_MAX_SIZE]; + } messages[NETPLAY_CHAT_MAX_MESSAGES]; +}; + typedef struct { - netplay_t *data; /* Used while Netplay is running */ - struct netplay_room host_room; /* ptr alignment */ + /* NAT traversal info (if NAT traversal is used and serving) */ + struct nat_traversal_data nat_traversal_request; +#ifdef HAVE_NETPLAYDISCOVERY + /* Packet buffer for advertisement and responses */ + struct ad_packet ad_packet_buffer; + /* List of discovered hosts */ + struct netplay_host_list discovered_hosts; +#endif + struct netplay_chat_buffer chat_buffer; + struct netplay_room host_room; struct netplay_room *room_list; struct netplay_rooms *rooms_data; + /* Used while Netplay is running */ + netplay_t *data; + /* Chat messages */ + struct netplay_chat *chat; #ifdef HAVE_NETPLAYDISCOVERY + size_t discovered_hosts_allocated; /* LAN discovery sockets */ int lan_ad_server_fd; int lan_ad_client_fd; - /* Packet buffer for advertisement and responses */ - struct ad_packet ad_packet_buffer; /* uint32_t alignment */ - /* List of discovered hosts */ - struct netplay_host_list discovered_hosts; - size_t discovered_hosts_allocated; #endif int room_count; int reannounce; int reping; int latest_ping; - uint16_t mapping[RETROK_LAST]; unsigned server_port_deferred; + uint16_t mapping[RETROK_LAST]; char server_address_deferred[256]; char server_session_deferred[32]; bool netplay_client_deferred; @@ -259,10 +264,6 @@ typedef struct bool has_set_netplay_ip_port; bool has_set_netplay_stateless_mode; bool has_set_netplay_check_frames; - /* NAT traversal info (if NAT traversal is used and serving) */ - struct nat_traversal_data nat_traversal_request; - /* Chat messages */ - struct netplay_chat chat; } net_driver_state_t; net_driver_state_t *networking_state_get_ptr(void); diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index fabc4382a1..e86a19ba18 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -20,7 +20,7 @@ #pragma comment(lib, "ws2_32") #endif -#ifdef _WIN32 +#if defined(_WIN32) && defined(_MSC_VER) #pragma comment(lib, "Iphlpapi") #endif @@ -4891,7 +4891,6 @@ static void relay_chat(netplay_t *netplay, static void show_chat(const char *nick, const char *msg) { char formatted_chat[NETPLAY_CHAT_MAX_SIZE]; - net_driver_state_t *net_st = &networking_driver_st; /* Truncate the message if necessary. */ snprintf(formatted_chat, sizeof(formatted_chat), @@ -4902,30 +4901,35 @@ static void show_chat(const char *nick, const char *msg) #ifdef HAVE_GFX_WIDGETS if (gfx_widgets_ready()) { - struct netplay_chat_data *data; + uint32_t msg_slot; + net_driver_state_t *net_st = &networking_driver_st; + struct netplay_chat *chat = net_st->chat; /* Do we have a free slot for this message? If not, get rid of the oldest message to make room for it. */ - if (!net_st->chat.message_slots) + if (!chat->message_slots) { int i; - for (i = ARRAY_SIZE(net_st->chat.messages) - 2; i >= 0; i--) + for (i = ARRAY_SIZE(chat->messages) - 2; i >= 0; i--) { - memcpy(&net_st->chat.messages[i+1].data, - &net_st->chat.messages[i].data, - sizeof(*data)); + memcpy(&chat->messages[i+1], &chat->messages[i], + sizeof(*chat->messages)); } - data = &net_st->chat.messages[0].data; + + msg_slot = 0; } else { - data = &net_st->chat.messages[--net_st->chat.message_slots].data; + msg_slot = --chat->message_slots; } - strlcpy(data->nick, nick, sizeof(data->nick)); - strlcpy(data->msg, msg, sizeof(data->msg)); - data->frames = NETPLAY_CHAT_FRAME_TIME; + chat->messages[msg_slot].frames = + NETPLAY_CHAT_FRAME_TIME; + strlcpy(chat->messages[msg_slot].nick, nick, + sizeof(chat->messages[msg_slot].nick)); + strlcpy(chat->messages[msg_slot].msg, msg, + sizeof(chat->messages[msg_slot].msg)); } else #endif @@ -8309,12 +8313,8 @@ void deinit_netplay(void) #endif } - for (i = 0; i < ARRAY_SIZE(net_st->chat.messages); i++) - { - *net_st->chat.messages[i].data.nick = '\0'; - *net_st->chat.messages[i].data.msg = '\0'; - net_st->chat.messages[i].data.frames = 0; - } + free(net_st->chat); + net_st->chat = NULL; core_unset_netplay_callbacks(); } @@ -8432,13 +8432,10 @@ bool init_netplay(const char *server, unsigned port, const char *mitm_session) return false; } - for (i = 0; i < ARRAY_SIZE(net_st->chat.messages); i++) - { - *net_st->chat.messages[i].data.nick = '\0'; - *net_st->chat.messages[i].data.msg = '\0'; - net_st->chat.messages[i].data.frames = 0; - } - net_st->chat.message_slots = ARRAY_SIZE(net_st->chat.messages); + net_st->chat = calloc(1, sizeof(*net_st->chat)); + if (!net_st->chat) + return false; + net_st->chat->message_slots = ARRAY_SIZE(net_st->chat->messages); net_st->reannounce = -1; net_st->reping = -1; @@ -8680,56 +8677,66 @@ static void gfx_widget_netplay_chat_iterate(void *user_data, bool is_threaded) { size_t i; - settings_t *settings = config_get_ptr(); net_driver_state_t *net_st = &networking_driver_st; -#ifdef HAVE_MENU - bool menu_open = menu_state_get_ptr()->alive; -#endif - bool fade_chat = settings->bools.netplay_fade_chat; + struct netplay_chat *chat = net_st->chat; + struct netplay_chat_buffer *chat_buffer = &net_st->chat_buffer; - /* Move the messages to a thread-safe buffer - before drawing them. */ - for (i = 0; i < ARRAY_SIZE(net_st->chat.messages); i++) + if (chat) { - struct netplay_chat_data *data = - &net_st->chat.messages[i].data; - struct netplay_chat_buffer *buffer = - &net_st->chat.messages[i].buffer; - - /* Don't show chat while in the menu */ + settings_t *settings = config_get_ptr(); #ifdef HAVE_MENU - if (menu_open) + bool menu_open = menu_state_get_ptr()->alive; +#endif + bool fade_chat = settings->bools.netplay_fade_chat; + + /* Move the messages to a thread-safe buffer + before drawing them. */ + for (i = 0; i < ARRAY_SIZE(chat->messages); i++) { - buffer->alpha = 0; - continue; - } + uint32_t *frames = &chat->messages[i].frames; + uint8_t *alpha = &chat_buffer->messages[i].alpha; + +#ifdef HAVE_MENU + /* Don't show chat while in the menu */ + if (menu_open) + { + *alpha = 0; + continue; + } #endif - /* If we are not fading, set alpha to max. */ - if (!fade_chat) - { - buffer->alpha = 0xFF; - } - else if (data->frames) - { - float alpha_percent = (float) data->frames / - (float) NETPLAY_CHAT_FRAME_TIME; + /* If we are not fading, set alpha to max. */ + if (!fade_chat) + { + *alpha = 0xFF; + } + else if (*frames) + { + float alpha_percent = (float) *frames / + (float) NETPLAY_CHAT_FRAME_TIME; - buffer->alpha = (uint8_t) float_max( - alpha_percent * 255.0f, 1.0f); + *alpha = (uint8_t) float_max( + alpha_percent * 255.0f, 1.0f); - data->frames--; - } - else - { - buffer->alpha = 0; - continue; - } + (*frames)--; + } + else + { + *alpha = 0; + continue; + } - memcpy(buffer->nick, data->nick, - sizeof(buffer->nick)); - memcpy(buffer->msg, data->msg, - sizeof(buffer->msg)); + memcpy(chat_buffer->messages[i].nick, chat->messages[i].nick, + sizeof(chat_buffer->messages[i].nick)); + memcpy(chat_buffer->messages[i].msg, chat->messages[i].msg, + sizeof(chat_buffer->messages[i].msg)); + } + } + /* If we are not in netplay, do nothing. */ + else + { + for (i = 0; i < ARRAY_SIZE(chat->messages); i++) + chat_buffer->messages[i].alpha = 0; } } @@ -8739,24 +8746,22 @@ static void gfx_widget_netplay_chat_frame(void *data, void *userdata) video_frame_info_t *video_info = data; dispgfx_widget_t *p_dispwidget = userdata; net_driver_state_t *net_st = &networking_driver_st; + struct netplay_chat_buffer *chat_buffer = &net_st->chat_buffer; int line_height = p_dispwidget->gfx_widget_fonts.regular.line_height + p_dispwidget->simple_widget_padding / 3.0f; int height = video_info->height - line_height; - for (i = 0; i < ARRAY_SIZE(net_st->chat.messages); i++) + for (i = 0; i < ARRAY_SIZE(chat_buffer->messages); i++) { char formatted_nick[NETPLAY_CHAT_MAX_SIZE]; char formatted_msg[NETPLAY_CHAT_MAX_SIZE]; int formatted_nick_len; int formatted_nick_width; - const char *nick = - net_st->chat.messages[i].buffer.nick; - const char *msg = - net_st->chat.messages[i].buffer.msg; - uint8_t alpha = - net_st->chat.messages[i].buffer.alpha; + uint8_t alpha = chat_buffer->messages[i].alpha; + const char *nick = chat_buffer->messages[i].nick; + const char *msg = chat_buffer->messages[i].msg; if (!alpha || string_is_empty(nick) || string_is_empty(msg)) continue; diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index aea22eb526..6c9151cdb8 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -324,6 +324,10 @@ struct delta_frame /* The real input */ netplay_input_state_t real_input[MAX_INPUT_DEVICES]; /* ptr alignment */ + /* The simulated input. is_real here means the simulation is done, i.e., + * it's a real simulation, not real input. */ + netplay_input_state_t simlated_input[MAX_INPUT_DEVICES]; + /* The serialized state of the core at this frame, before input */ void *state; @@ -332,10 +336,6 @@ struct delta_frame /* The CRC-32 of the serialized state if we've calculated it, else 0 */ uint32_t crc; - /* The simulated input. is_real here means the simulation is done, i.e., - * it's a real simulation, not real input. */ - netplay_input_state_t simlated_input[MAX_INPUT_DEVICES]; - /* Have we read local input? */ bool have_local; @@ -362,6 +362,9 @@ struct netplay_connection /* Is this connection stalling? */ retro_time_t stall_time; + /* Timer used to estimate a connection's latency */ + retro_time_t ping_timer; + /* Address of peer */ struct sockaddr_storage addr; @@ -389,6 +392,14 @@ struct netplay_connection /* Salt associated with password transaction */ uint32_t salt; + /* Which netplay protocol is this connection running? */ + uint32_t netplay_protocol; + + /* What latency is this connection running on? + * Network latency has limited precision as we estimate it + * once every pre-frame. */ + int32_t ping; + /* Is this connection stalling? */ enum rarch_netplay_stall_reason stall; @@ -407,17 +418,6 @@ struct netplay_connection /* Is this connection buffer in use? */ bool active; - /* Which netplay protocol is this connection running? */ - uint32_t netplay_protocol; - - /* Timer used to estimate a connection's latency */ - retro_time_t ping_timer; - - /* What latency is this connection running on? - * Network latency has limited precision as we estimate it - * once every pre-frame. */ - int32_t ping; - /* Did we request a ping response? */ bool ping_requested; }; @@ -440,19 +440,20 @@ typedef struct mitm_id #define NETPLAY_MITM_MAX_PENDING 8 struct netplay_mitm_pending { - int fds[NETPLAY_MITM_MAX_PENDING]; - mitm_id_t ids[NETPLAY_MITM_MAX_PENDING]; retro_time_t timeouts[NETPLAY_MITM_MAX_PENDING]; - + mitm_id_t ids[NETPLAY_MITM_MAX_PENDING]; mitm_id_t id_buf; - size_t id_recvd; - - struct addrinfo *base_addr; + struct addrinfo *base_addr; const struct addrinfo *addr; + size_t id_recvd; + int fds[NETPLAY_MITM_MAX_PENDING]; }; struct netplay { + /* Quirks in the savestate implementation */ + uint64_t quirks; + /* When did we start falling behind? */ retro_time_t catch_up_time; /* How long have we been stalled? */ @@ -466,7 +467,63 @@ struct netplay retro_time_t frame_run_time[NETPLAY_FRAME_RUN_TIME_WINDOW]; retro_time_t frame_run_time_sum, frame_run_time_avg; - struct netplay_connection one_connection; /* Client only */ /* retro_time_t alignment */ + struct retro_callbacks cbs; + + /* Compression transcoder */ + struct compression_transcoder compress_nil, + compress_zlib; + + /* MITM session id */ + mitm_id_t mitm_session_id; + + struct netplay_connection one_connection; /* Client only */ + /* All of our connections */ + struct netplay_connection *connections; + + /* MITM connection handler */ + struct netplay_mitm_pending *mitm_pending; + + /* Our local socket info */ + struct addrinfo *addr; + + struct delta_frame *buffer; + + /* A buffer into which to compress frames for transfer */ + uint8_t *zbuffer; + + size_t connections_size; + size_t buffer_size; + size_t zbuffer_size; + /* The size of our packet buffers */ + size_t packet_buffer_size; + /* Size of savestates */ + size_t state_size; + + /* The frame we're currently inputting */ + size_t self_ptr; + /* The frame we're currently running, which may be + * behind the frame we're currently inputting if + * we're using input latency */ + size_t run_ptr; + /* The first frame at which some data might be unreliable */ + size_t other_ptr; + /* Pointer to the first frame for which we're missing + * the data of at least one connected player excluding ourself. + * Generally, other_ptr <= unread_ptr <= self_ptr, + * but unread_ptr can get ahead of self_ptr if the peer + * is running fast. */ + size_t unread_ptr; + /* Pointer to the next frame to read from each client */ + size_t read_ptr[MAX_CLIENTS]; + /* Pointer to the next frame to read from the server + * (as it might not be a player but still synchronizes) + */ + size_t server_ptr; + /* A pointer used temporarily for replay. */ + size_t replay_ptr; + + /* Pseudo random seed */ + unsigned long simple_rand_next; /* TCP connection for listening (server only) */ int listen_fd; @@ -474,10 +531,6 @@ struct netplay /* Our client number */ uint32_t self_client_num; - /* All of our connections */ - struct netplay_connection *connections; - size_t connections_size; - /* Bitmap of clients with input devices */ uint32_t connected_players; @@ -503,69 +556,19 @@ struct netplay * as netplay needs fixed devices. */ uint32_t config_devices[MAX_INPUT_DEVICES]; - struct retro_callbacks cbs; - - struct delta_frame *buffer; - size_t buffer_size; - - /* Compression transcoder */ - struct compression_transcoder compress_nil, - compress_zlib; - - /* Size of savestates */ - size_t state_size; - - /* A buffer into which to compress frames for transfer */ - uint8_t *zbuffer; - size_t zbuffer_size; - - /* The size of our packet buffers */ - size_t packet_buffer_size; - - /* The frame we're currently inputting */ - size_t self_ptr; uint32_t self_frame_count; - - /* The frame we're currently running, which may be - * behind the frame we're currently inputting if - * we're using input latency */ - size_t run_ptr; uint32_t run_frame_count; - - /* The first frame at which some data might be unreliable */ - size_t other_ptr; uint32_t other_frame_count; - - /* Pointer to the first frame for which we're missing - * the data of at least one connected player excluding ourself. - * Generally, other_ptr <= unread_ptr <= self_ptr, - * but unread_ptr can get ahead of self_ptr if the peer - * is running fast. */ - size_t unread_ptr; uint32_t unread_frame_count; - - /* Pointer to the next frame to read from each client */ - size_t read_ptr[MAX_CLIENTS]; uint32_t read_frame_count[MAX_CLIENTS]; - - /* Pointer to the next frame to read from the server - * (as it might not be a player but still synchronizes) - */ - size_t server_ptr; uint32_t server_frame_count; - - /* A pointer used temporarily for replay. */ - size_t replay_ptr; uint32_t replay_frame_count; - /* Our local socket info */ - struct addrinfo *addr; + int frame_run_time_ptr; /* Counter for timeouts */ unsigned timeout_cnt; - int frame_run_time_ptr; - /* Latency frames; positive to hide network latency, * negative to hide input latency */ int input_latency_frames; @@ -576,6 +579,10 @@ struct netplay /* How far behind did we fall? */ uint32_t catch_up_behind; + /* Host settings */ + int32_t input_latency_frames_min; + int32_t input_latency_frames_max; + /* Are we stalled? */ enum rarch_netplay_stall_reason stall; @@ -616,9 +623,6 @@ struct netplay /* Force a reset */ bool force_reset; - /* Quirks in the savestate implementation */ - uint64_t quirks; - /* Force our state to be sent to all connections */ bool force_send_savestate; @@ -648,19 +652,8 @@ struct netplay /* Are we the connected? */ bool is_connected; - /* MITM session id */ - mitm_id_t mitm_session_id; - - /* MITM connection handler */ - struct netplay_mitm_pending *mitm_pending; - /* Host settings */ - int32_t input_latency_frames_min; - int32_t input_latency_frames_max; bool allow_pausing; - - /* Pseudo random seed */ - unsigned long simple_rand_next; }; /***************************************************************