Cleaning up netplay headers.

This commit is contained in:
Gregor Richards 2016-12-15 08:42:03 -05:00
parent 9c6ac2b934
commit da7efcb939
9 changed files with 646 additions and 310 deletions

View File

@ -13,6 +13,8 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <net/net_compat.h>
#include <net/net_socket.h>
@ -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;

View File

@ -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)

View File

@ -32,6 +32,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <compat/strl.h>
@ -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;

View File

@ -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
*

View File

@ -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;

View File

@ -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;

View File

@ -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
}

View File

@ -24,16 +24,10 @@
#include <net/net_natt.h>
#include <features/features_cpu.h>
#include <streams/trans_stream.h>
#include <retro_endianness.h>
#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

View File

@ -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);