/* 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 "netplay_protocol.h" #include #include #include "../../retroarch_types.h" #ifndef VITA #define RARCH_DEFAULT_PORT 55435 #else #define RARCH_DEFAULT_PORT 19492 #endif #define RARCH_DISCOVERY_PORT 55435 #define RARCH_DEFAULT_NICK "Anonymous" #define NETPLAY_PASS_LEN 128 #define NETPLAY_PASS_HASH_LEN 64 /* length of a SHA-256 hash */ #define NETPLAY_ANNOUNCE_AFTER 5000000 #define NETPLAY_PING_AFTER 3000000 #define NETPLAY_ANNOUNCE_TIME 20000000 #define NETPLAY_PING_TIME 3000000 #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 MAX_INPUT_DEVICES 16 /* We allow only 32 clients to fit into a 32-bit bitmap */ #define MAX_CLIENTS 32 /* Because the callback keyboard reverses some assumptions, when the keyboard * callbacks are in use, we assign a pseudodevice for it */ #define RETRO_DEVICE_NETPLAY_KEYBOARD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_KEYBOARD, 65535) #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_INITIALIZATION (1 << 0) #define NETPLAY_QUIRK_ENDIAN_DEPENDENT (1 << 1) #define NETPLAY_QUIRK_PLATFORM_DEPENDENT (1 << 2) /* 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 /* The keys supported by netplay */ enum netplay_keys { NETPLAY_KEY_UNKNOWN = 0, #define K(k) NETPLAY_KEY_ ## k, #define KL(k,l) K(k) #include "netplay_keys.h" #undef KL #undef K NETPLAY_KEY_LAST }; 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 */ /* 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, /* Chat commands */ /* Sends a player chat message. * The server is responsible for formatting/truncating * the message and relaying it to all playing clients, * including the one that sent the message. */ NETPLAY_CMD_PLAYER_CHAT = 0x1000, /* Ping commands */ /* Sends a ping command to the server/client. * Intended for estimating the latency between these two peers. */ NETPLAY_CMD_PING_REQUEST = 0x1100, NETPLAY_CMD_PING_RESPONSE = 0x1101, /* Setting commands */ /* These host settings should be honored by the client, * but they are not enforced. */ NETPLAY_CMD_SETTING_ALLOW_PAUSING = 0x2000, NETPLAY_CMD_SETTING_INPUT_LATENCY_FRAMES = 0x2001 }; #define NETPLAY_CMD_SYNC_BIT_PAUSED (1U<<31) #define NETPLAY_CMD_PLAY_BIT_SLAVE (1U<<31) #define NETPLAY_CMD_MODE_BIT_YOU (1U<<31) #define NETPLAY_CMD_MODE_BIT_PLAYING (1U<<30) #define NETPLAY_CMD_MODE_BIT_SLAVE (1U<<29) /* 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, /* You're changing modes too fast */ NETPLAY_CMD_MODE_REFUSED_REASON_TOO_FAST, /* You requested a particular port but it's not available */ NETPLAY_CMD_MODE_REFUSED_REASON_NOT_AVAILABLE }; /* Real preferences for sharing devices */ enum rarch_netplay_share_preference { /* Prefer not to share, shouldn't be set as a sharing mode for an shared device */ NETPLAY_SHARE_NO_SHARING = 0x00, /* No preference. Only for requests. Set if sharing is requested but either * digital or analog doesn't have a preference. */ NETPLAY_SHARE_NO_PREFERENCE = 0x01, /* For digital devices */ NETPLAY_SHARE_DIGITAL_BITS = 0x1C, NETPLAY_SHARE_DIGITAL_OR = 0x04, NETPLAY_SHARE_DIGITAL_XOR = 0x08, NETPLAY_SHARE_DIGITAL_VOTE = 0x0C, /* For analog devices */ NETPLAY_SHARE_ANALOG_BITS = 0xE0, NETPLAY_SHARE_ANALOG_MAX = 0x20, NETPLAY_SHARE_ANALOG_AVERAGE = 0x40 }; 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 }; /* Input state for a particular client-device pair */ typedef struct netplay_input_state { /* The next input state (forming a list) */ struct netplay_input_state *next; /* Whose data is this? */ uint32_t client_num; /* How many words of input data do we have? */ uint32_t size; /* Is this a buffer with real data? */ bool used; /* The input data itself (note: should expand beyond 1 by overallocating). */ uint32_t data[1]; /* Warning: No members allowed past this point, due to dynamic resizing. */ } *netplay_input_state_t; struct delta_frame { /* The resolved input, i.e., what's actually going to the core. One input per device. */ netplay_input_state_t resolved_input[MAX_INPUT_DEVICES]; /* ptr alignment */ /* 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 simulated_input[MAX_INPUT_DEVICES]; /* The serialized state of the core at this frame, before input */ void *state; uint32_t frame; /* The CRC-32 of the serialized state if we've calculated it, else 0 */ uint32_t crc; /* Have we read local input? */ bool have_local; /* Have we read the real (remote) input? */ bool have_real[MAX_CLIENTS]; /* A bit derpy, but this is how we know if the delta * has been used at all. */ bool used; }; struct socket_buffer { unsigned char *data; size_t bufsz; size_t start; size_t end; size_t read; }; /* We do it like this instead of using sockaddr_storage in order to have relay server IPv6 support on platforms that do not support IPv6. */ typedef struct netplay_address { /* Can hold an IPv6 address aswell as an IPv4 address in the ::ffff:a.b.c.d format. */ uint8_t addr[16]; } netplay_address_t; enum netplay_connection_flags { /* Is this connection buffer in use? */ NETPLAY_CONN_FLAG_ACTIVE = (1 << 0), /* Is this player paused? */ NETPLAY_CONN_FLAG_PAUSED = (1 << 1), /* Is this connection allowed to play (server only)? */ NETPLAY_CONN_FLAG_CAN_PLAY = (1 << 2), /* Did we request a ping response? */ NETPLAY_CONN_FLAG_PING_REQUESTED = (1 << 3) }; /* Each connection gets a connection struct */ struct netplay_connection { /* Timer used to estimate a connection's latency */ retro_time_t ping_timer; /* Connection's address */ netplay_address_t addr; /* Buffers for sending and receiving data */ struct socket_buffer send_packet_buffer; struct socket_buffer recv_packet_buffer; /* What compression does this peer support? */ uint32_t compression_supported; /* Salt associated with password transaction */ uint32_t salt; /* Which netplay protocol is this connection running? */ uint32_t netplay_protocol; /* If the mode is a DELAYED_DISCONNECT or SPECTATOR, * the transmission of the mode change may have to * wait for data to be forwarded. * This is the frame to wait for, or 0 if no delay * is active. */ uint32_t delay_frame; /* 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; /* How many times has this connection caused a stall because it's running too slow? */ uint32_t stall_slow; /* What latency is this connection running on? * Network latency has limited precision as we estimate it * once every pre-frame. */ int32_t ping; /* fd associated with this connection */ int fd; /* Mode of the connection */ enum rarch_netplay_connection_mode mode; /* Is this connection stalling? */ enum rarch_netplay_stall_reason stall; uint8_t flags; /* Nickname of peer */ char nick[NETPLAY_NICK_LEN]; }; /* Compression transcoder */ struct compression_transcoder { const struct trans_stream_backend *compression_backend; const struct trans_stream_backend *decompression_backend; void *compression_stream; void *decompression_stream; }; typedef struct mitm_id { uint32_t magic; uint8_t unique[12]; } mitm_id_t; #define NETPLAY_MITM_MAX_PENDING 8 struct netplay_mitm_handler { struct { retro_time_t timeout; mitm_id_t id; netplay_address_t addr; int fd; bool has_addr; } pending[NETPLAY_MITM_MAX_PENDING]; mitm_id_t id_buf; netplay_address_t addr_buf; struct addrinfo *base_addr; const struct addrinfo *addr; size_t id_recvd; size_t addr_recvd; }; struct netplay_ban_list { netplay_address_t *list; size_t size; size_t allocated; }; struct netplay_chat { struct { uint32_t frames; char nick[NETPLAY_NICK_LEN]; char msg[NETPLAY_CHAT_MAX_SIZE]; } messages[NETPLAY_CHAT_MAX_MESSAGES]; }; struct netplay { /* 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]; retro_time_t frame_run_time_sum; retro_time_t frame_run_time_avg; /* When did we start falling behind? */ retro_time_t catch_up_time; /* How long have we been stalled? */ retro_time_t stall_time; retro_time_t next_announce; retro_time_t next_ping; struct retro_callbacks cbs; /* Compression transcoder */ struct compression_transcoder compress_nil; struct compression_transcoder compress_zlib; /* MITM session id */ mitm_id_t mitm_session_id; /* Banned addresses */ struct netplay_ban_list ban_list; /* Chat messages */ struct netplay_chat chat; /* MITM connection handler */ struct netplay_mitm_handler *mitm_handler; /* All of our connections */ struct netplay_connection *connections; 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; /* Quirks in the savestate implementation */ uint32_t quirks; /* Our client number */ uint32_t self_client_num; /* Bitmap of clients with input devices */ uint32_t connected_players; /* Bitmap of clients playing in slave mode (should be a subset of * connected_players) */ uint32_t connected_slaves; /* For each client, the bitmap of devices they're connected to */ uint32_t client_devices[MAX_CLIENTS]; /* For each device, the bitmap of clients connected */ uint32_t device_clients[MAX_INPUT_DEVICES]; /* Our own device bitmap */ uint32_t self_devices; /* The device types for every connected device. * We store them and ignore any menu changes, * as netplay needs fixed devices. */ uint32_t config_devices[MAX_INPUT_DEVICES]; uint32_t self_frame_count; uint32_t run_frame_count; uint32_t other_frame_count; uint32_t unread_frame_count; uint32_t read_frame_count[MAX_CLIENTS]; uint32_t server_frame_count; uint32_t replay_frame_count; /* Frequency with which to check CRCs */ uint32_t check_frames; /* How far behind did we fall? */ uint32_t catch_up_behind; /* Number of desync operations we're currently performing. * If set, we don't attempt to stay in sync. */ uint32_t desync; /* Host settings */ int32_t input_latency_frames_min; int32_t input_latency_frames_max; /* TCP connection for listening (server only) */ int listen_fd; int frame_run_time_ptr; /* Latency frames; positive to hide network latency, * negative to hide input latency */ int input_latency_frames; /* Our mode and status */ enum rarch_netplay_connection_mode self_mode; /* Are we stalled? */ enum rarch_netplay_stall_reason stall; /* Keyboard mapping (network and host) */ uint16_t mapping_hton[RETROK_LAST]; uint16_t mapping_ntoh[NETPLAY_KEY_LAST]; /* TCP port (only set if serving) */ uint16_t tcp_port; uint16_t ext_tcp_port; /* The sharing mode for each device */ uint8_t device_share_modes[MAX_INPUT_DEVICES]; /* Our nickname */ char nick[NETPLAY_NICK_LEN]; /* Set to true if we have a device that most cores * translate to "up/down" actions, typically a keyboard. * We need to keep track of this because with such a device, * we need to "fix" the input state to the frame BEFORE a * state load, then perform the state load, and the * up/down states will proceed as expected. */ bool have_updown_device; /* Are we the server? */ bool is_server; bool nat_traversal; /* Have we checked whether CRCs are valid at all? */ bool crc_validity_checked; /* Are they valid? */ bool crcs_valid; /* Netplay pausing */ bool local_paused; bool remote_paused; /* Are we replaying old frames? */ bool is_replay; /* Opposite of stalling, should we be catching up? */ bool catch_up; /* Force a rewind to other_frame_count/other_ptr. * This is for synchronized events, such as restarting * or savestate loading. */ bool force_rewind; /* Force a reset */ bool force_reset; /* 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; /* Host settings */ bool allow_pausing; }; void video_frame_net(const void *data, unsigned width, unsigned height, size_t pitch); void audio_sample_net(int16_t left, int16_t right); size_t audio_sample_batch_net(const int16_t *data, size_t frames); int16_t input_state_net(unsigned port, unsigned device, unsigned idx, unsigned id); /*************************************************************** * NETPLAY-BUF.C **************************************************************/ /** * 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, 0, or -1 on error. */ ssize_t netplay_recv(struct socket_buffer *sbuf, int sockfd, void *buf, size_t len); /** * 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-FRONTEND.C **************************************************************/ /** * input_poll_net * @netplay : pointer to netplay object * * Poll the network if necessary. */ void input_poll_net(netplay_t *netplay); /*************************************************************** * NETPLAY-INIT.C **************************************************************/ /** * 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-IO.C **************************************************************/ /** * 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_mode * * Send a mode change request. As a server, * the request is to ourself, and so honored instantly. */ bool netplay_cmd_mode(netplay_t *netplay, enum rarch_netplay_connection_mode mode); /*************************************************************** * NETPLAY-SYNC.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); #endif