/* RetroArch - A frontend for libretro. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2016-2017 - Gregor Richards * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- * ation, either version 3 of the License, or (at your option) any later version. * * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with RetroArch. * If not, see . */ #ifndef __RARCH_NETPLAY_PRIVATE_H #define __RARCH_NETPLAY_PRIVATE_H #include "netplay.h" #include #include #include #include #include "../../msg_hash.h" #include "../../verbosity.h" #define WORDS_PER_INPUT 3 /* Buttons, left stick, right stick */ #define WORDS_PER_FRAME (WORDS_PER_INPUT+2) /* + frameno, playerno */ #define NETPLAY_PROTOCOL_VERSION 4 #define RARCH_DEFAULT_PORT 55435 #define RARCH_DEFAULT_NICK "Anonymous" #define NETPLAY_NICK_LEN 32 #define NETPLAY_PASS_LEN 128 #define NETPLAY_PASS_HASH_LEN 64 /* length of a SHA-256 hash */ #define MAX_SERVER_STALL_TIME_USEC (5*1000*1000) #define MAX_CLIENT_STALL_TIME_USEC (10*1000*1000) #define CATCH_UP_CHECK_TIME_USEC (500*1000) #define MAX_RETRIES 16 #define RETRY_MS 500 #define NETPLAY_MAX_STALL_FRAMES 60 #define NETPLAY_FRAME_RUN_TIME_WINDOW 120 #define NETPLAY_MAX_REQ_STALL_TIME 60 #define NETPLAY_MAX_REQ_STALL_FREQUENCY 120 #define PREV_PTR(x) ((x) == 0 ? netplay->buffer_size - 1 : (x) - 1) #define NEXT_PTR(x) ((x + 1) % netplay->buffer_size) /* Quirks mandated by how particular cores save states. This is distilled from * the larger set of quirks that the quirks environment can communicate. */ #define NETPLAY_QUIRK_NO_SAVESTATES (1<<0) #define NETPLAY_QUIRK_NO_TRANSMISSION (1<<1) #define NETPLAY_QUIRK_INITIALIZATION (1<<2) #define NETPLAY_QUIRK_ENDIAN_DEPENDENT (1<<3) #define NETPLAY_QUIRK_PLATFORM_DEPENDENT (1<<4) /* Mapping of serialization quirks to netplay quirks. */ #define NETPLAY_QUIRK_MAP_UNDERSTOOD \ (RETRO_SERIALIZATION_QUIRK_INCOMPLETE \ |RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE \ |RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE \ |RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION \ |RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT \ |RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT) #define NETPLAY_QUIRK_MAP_NO_SAVESTATES \ (RETRO_SERIALIZATION_QUIRK_INCOMPLETE) #define NETPLAY_QUIRK_MAP_NO_TRANSMISSION \ (RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION) #define NETPLAY_QUIRK_MAP_INITIALIZATION \ (RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE) #define NETPLAY_QUIRK_MAP_ENDIAN_DEPENDENT \ (RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT) #define NETPLAY_QUIRK_MAP_PLATFORM_DEPENDENT \ (RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT) /* Compression protocols supported */ #define NETPLAY_COMPRESSION_ZLIB (1<<0) #if HAVE_ZLIB #define NETPLAY_COMPRESSION_SUPPORTED NETPLAY_COMPRESSION_ZLIB #else #define NETPLAY_COMPRESSION_SUPPORTED 0 #endif enum netplay_cmd { /* Basic commands */ /* Acknowlegement response */ NETPLAY_CMD_ACK = 0x0000, /* Failed acknowlegement response */ NETPLAY_CMD_NAK = 0x0001, /* Gracefully disconnects from host */ NETPLAY_CMD_DISCONNECT = 0x0002, /* Input data */ NETPLAY_CMD_INPUT = 0x0003, /* Non-input data */ NETPLAY_CMD_NOINPUT = 0x0004, /* Initialization commands */ /* Inform the other side of our nick (must be first command) */ NETPLAY_CMD_NICK = 0x0020, /* Give the connection password */ NETPLAY_CMD_PASSWORD = 0x0021, /* Give core/content info */ NETPLAY_CMD_INFO = 0x0022, /* Initial synchronization info (frame, sram, player info) */ NETPLAY_CMD_SYNC = 0x0023, /* Join spectator mode */ NETPLAY_CMD_SPECTATE = 0x0024, /* Join play mode */ NETPLAY_CMD_PLAY = 0x0025, /* Report player mode */ NETPLAY_CMD_MODE = 0x0026, /* Report player mode refused */ NETPLAY_CMD_MODE_REFUSED = 0x0027, /* Loading and synchronization */ /* Send the CRC hash of a frame's state */ NETPLAY_CMD_CRC = 0x0040, /* Request a savestate */ NETPLAY_CMD_REQUEST_SAVESTATE = 0x0041, /* Send a savestate for the client to load */ NETPLAY_CMD_LOAD_SAVESTATE = 0x0042, /* Pauses the game, takes no arguments */ NETPLAY_CMD_PAUSE = 0x0043, /* Resumes the game, takes no arguments */ NETPLAY_CMD_RESUME = 0x0044, /* Request that a client stall because it's running fast */ NETPLAY_CMD_STALL = 0x0045, /* Request a core reset */ NETPLAY_CMD_RESET = 0x0046, /* Sends over cheats enabled on client (unsupported) */ NETPLAY_CMD_CHEATS = 0x0047, /* Misc. commands */ /* Swap inputs between player 1 and player 2 */ NETPLAY_CMD_FLIP_PLAYERS = 0x0060, /* Sends multiple config requests over, * See enum netplay_cmd_cfg */ NETPLAY_CMD_CFG = 0x0061, /* CMD_CFG streamlines sending multiple configurations. This acknowledges each one individually */ NETPLAY_CMD_CFG_ACK = 0x0062 }; #define NETPLAY_CMD_INPUT_BIT_SERVER (1U<<31) #define NETPLAY_CMD_SYNC_BIT_PAUSED (1U<<31) #define NETPLAY_CMD_PLAY_BIT_SLAVE (1U) #define NETPLAY_CMD_MODE_BIT_SLAVE (1U<<18) #define NETPLAY_CMD_MODE_BIT_PLAYING (1U<<17) #define NETPLAY_CMD_MODE_BIT_YOU (1U<<16) /* These are the reasons given for mode changes to be rejected */ enum netplay_cmd_mode_reasons { /* Other/unknown reason */ NETPLAY_CMD_MODE_REFUSED_REASON_OTHER, /* You don't have permission to play */ NETPLAY_CMD_MODE_REFUSED_REASON_UNPRIVILEGED, /* There are no free player slots */ NETPLAY_CMD_MODE_REFUSED_REASON_NO_SLOTS }; enum rarch_netplay_connection_mode { NETPLAY_CONNECTION_NONE = 0, /* Initialization: */ NETPLAY_CONNECTION_INIT, /* Waiting for header */ NETPLAY_CONNECTION_PRE_NICK, /* Waiting for nick */ NETPLAY_CONNECTION_PRE_PASSWORD, /* Waiting for password */ NETPLAY_CONNECTION_PRE_INFO, /* Waiting for core/content info */ NETPLAY_CONNECTION_PRE_SYNC, /* Waiting for sync */ /* Ready: */ NETPLAY_CONNECTION_CONNECTED, /* Modes above this are connected */ NETPLAY_CONNECTION_SPECTATING, /* Spectator mode */ NETPLAY_CONNECTION_SLAVE, /* Playing in slave mode */ NETPLAY_CONNECTION_PLAYING /* Normal ready state */ }; enum rarch_netplay_stall_reason { NETPLAY_STALL_NONE = 0, /* We're so far ahead that we can't read more data without overflowing the * buffer */ NETPLAY_STALL_RUNNING_FAST, /* We're in spectator or slave mode and are running ahead at all */ NETPLAY_STALL_SPECTATOR_WAIT, /* Our actual execution is catching up with latency-adjusted input frames */ NETPLAY_STALL_INPUT_LATENCY, /* The server asked us to stall */ NETPLAY_STALL_SERVER_REQUESTED, /* We have no connection and must have one to proceed */ NETPLAY_STALL_NO_CONNECTION }; typedef uint32_t netplay_input_state_t[WORDS_PER_INPUT]; struct delta_frame { bool used; /* a bit derpy, but this is how we know if the delta's been used at all */ uint32_t frame; /* The serialized state of the core at this frame, before input */ void *state; /* The CRC-32 of the serialized state if we've calculated it, else 0 */ uint32_t crc; /* The real, simulated and local input. If we're playing, self_state is * mirrored to the appropriate real_input_state player. */ netplay_input_state_t real_input_state[MAX_USERS]; netplay_input_state_t simulated_input_state[MAX_USERS]; netplay_input_state_t self_state; /* Have we read local input? */ bool have_local; /* Have we read the real (remote) input? */ bool have_real[MAX_USERS]; /* Is the current state as of self_frame_count using the real (remote) data? */ bool used_real[MAX_USERS]; }; struct socket_buffer { unsigned char *data; size_t bufsz; size_t start, end; size_t read; }; /* Each connection gets a connection struct */ struct netplay_connection { /* Is this connection buffer in use? */ bool active; /* fd associated with this connection */ int fd; /* Address of peer */ struct sockaddr_storage addr; /* Nickname of peer */ char nick[NETPLAY_NICK_LEN]; /* Salt associated with password transaction */ uint32_t salt; /* Is this connection allowed to play (server only)? */ bool can_play; /* Buffers for sending and receiving data */ struct socket_buffer send_packet_buffer, recv_packet_buffer; /* Mode of the connection */ enum rarch_netplay_connection_mode mode; /* Player # of connected player */ uint32_t player; /* What compression does this peer support? */ uint32_t compression_supported; /* Is this player paused? */ bool paused; /* Is this connection stalling? */ enum rarch_netplay_stall_reason stall; retro_time_t stall_time; /* For the server: When was the last time we requested this client to stall? * For the client: How many frames of stall do we have left? */ uint32_t stall_frame; }; /* Compression transcoder */ struct compression_transcoder { const struct trans_stream_backend *compression_backend; void *compression_stream; const struct trans_stream_backend *decompression_backend; void *decompression_stream; }; struct netplay { /* Are we the server? */ bool is_server; /* Our nickname */ char nick[NETPLAY_NICK_LEN]; /* TCP connection for listening (server only) */ int listen_fd; /* Our player number */ uint32_t self_player; /* Our mode and status */ enum rarch_netplay_connection_mode self_mode; /* All of our connections */ struct netplay_connection *connections; size_t connections_size; struct netplay_connection one_connection; /* Client only */ /* Bitmap of players with controllers (low bit is player 1) */ uint32_t connected_players; /* Bitmap of players playing in slave mode (should be a subset of * connected_players) */ uint32_t connected_slaves; /* Number of desync operations we're currently performing. If set, we don't * attempt to stay in sync. */ uint32_t desync; /* Maximum player number */ uint32_t player_max; struct retro_callbacks cbs; /* TCP port (only set if serving) */ uint16_t tcp_port; /* NAT traversal info (if NAT traversal is used and serving) */ bool nat_traversal, nat_traversal_task_oustanding; struct natt_status nat_traversal_state; struct delta_frame *buffer; size_t buffer_size; /* Compression transcoder */ struct compression_transcoder compress_nil, compress_zlib; /* 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 player */ size_t read_ptr[MAX_USERS]; uint32_t read_frame_count[MAX_USERS]; /* 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; /* Size of savestates */ size_t state_size; /* Are we replaying old frames? */ bool is_replay; /* We don't want to poll several times on a frame. */ bool can_poll; /* Force a rewind to other_frame_count/other_ptr. This is for synchronized * events, such as player flipping or savestate loading. */ bool force_rewind; /* 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; /* Have we requested a savestate as a sync point? */ bool savestate_request_outstanding; /* A buffer for outgoing input packets. */ uint32_t input_packet_buffer[2 + WORDS_PER_FRAME]; /* Our local socket info */ struct addrinfo *addr; /* Counter for timeouts */ unsigned timeout_cnt; /* User flipping * Flipping state. If frame >= flip_frame, we apply the flip. * If not, we apply the opposite, effectively creating a trigger point. */ bool flip; uint32_t flip_frame; /* Netplay pausing */ bool local_paused; bool remote_paused; /* If true, never progress without peer input (stateless/rewindless mode) */ bool stateless_mode; /* We stall if we're far enough ahead that we couldn't transparently rewind. * To know if we could transparently rewind, we need to know how long * running a frame takes. We record that every frame and get a running * (window) average */ retro_time_t frame_run_time[NETPLAY_FRAME_RUN_TIME_WINDOW]; int frame_run_time_ptr; retro_time_t frame_run_time_sum, frame_run_time_avg; /* Latency frames and limits */ unsigned input_latency_frames; /* Are we stalled? */ enum rarch_netplay_stall_reason stall; /* How long have we been stalled? */ retro_time_t stall_time; /* Opposite of stalling, should we be catching up? */ bool catch_up; /* When did we start falling behind? */ retro_time_t catch_up_time; /* How far behind did we fall? */ uint32_t catch_up_behind; /* Frequency with which to check CRCs */ int check_frames; /* Have we checked whether CRCs are valid at all? */ bool crc_validity_checked; /* Are they valid? */ bool crcs_valid; }; /*************************************************************** * 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 * * Data receiver for all handshake states. */ bool netplay_handshake(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. * @server : IP address of server. * @port : Port of server. * @stateless_mode : Shall we run in stateless mode? * @check_frames : Frequency with which to check CRCs. * @cb : Libretro callbacks. * @nat_traversal : If true, attempt NAT traversal. * @nick : Nickname of user. * @quirks : Netplay quirks required for this session. * * Creates a new netplay handle. A NULL server means we're * hosting. * * Returns: new netplay data. */ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port, bool stateless_mode, int check_frames, const struct retro_callbacks *cb, bool nat_traversal, const char *nick, uint64_t quirks); /** * netplay_free * @netplay : pointer to netplay object * * Frees netplay data/ */ void netplay_free(netplay_t *netplay); /*************************************************************** * NETPLAY-IO.C **************************************************************/ /** * netplay_hangup: * * Disconnects an active Netplay connection due to an error */ void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection); /** * 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); /** * 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); /** * 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_cmd_stall * * Send a stall command. */ bool netplay_cmd_stall(netplay_t *netplay, struct netplay_connection *connection, uint32_t frames); /** * netplay_poll_net_input * * Poll input from the network */ int netplay_poll_net_input(netplay_t *netplay, bool block); /** * netplay_handle_slaves * * Handle any slave connections */ void netplay_handle_slaves(netplay_t *netplay); /** * 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); /*************************************************************** * NETPLAY-SYNC.C **************************************************************/ /** * 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); /** * 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); /** * netplay_sync_pre_frame * @netplay : pointer to netplay object * * Pre-frame for Netplay synchronization. */ bool netplay_sync_pre_frame(netplay_t *netplay); /** * netplay_sync_post_frame * @netplay : pointer to netplay object * @stalled : true if we're currently stalled * * 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, bool stalled); #endif