mirror of
https://github.com/libretro/RetroArch
synced 2025-03-02 19:13:34 +00:00
Cleaning up netplay headers.
This commit is contained in:
parent
9c6ac2b934
commit
da7efcb939
@ -13,6 +13,8 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>.
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <net/net_compat.h>
|
#include <net/net_compat.h>
|
||||||
#include <net/net_socket.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;
|
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)
|
bool netplay_init_socket_buffer(struct socket_buffer *sbuf, size_t size)
|
||||||
{
|
{
|
||||||
sbuf->data = malloc(size);
|
sbuf->data = malloc(size);
|
||||||
@ -57,6 +64,11 @@ bool netplay_init_socket_buffer(struct socket_buffer *sbuf, size_t size)
|
|||||||
return true;
|
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)
|
bool netplay_resize_socket_buffer(struct socket_buffer *sbuf, size_t newsize)
|
||||||
{
|
{
|
||||||
unsigned char *newdata = malloc(newsize);
|
unsigned char *newdata = malloc(newsize);
|
||||||
@ -91,6 +103,11 @@ bool netplay_resize_socket_buffer(struct socket_buffer *sbuf, size_t newsize)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netplay_deinit_socket_buffer
|
||||||
|
*
|
||||||
|
* Free a socket buffer.
|
||||||
|
*/
|
||||||
void netplay_deinit_socket_buffer(struct socket_buffer *sbuf)
|
void netplay_deinit_socket_buffer(struct socket_buffer *sbuf)
|
||||||
{
|
{
|
||||||
if (sbuf->data)
|
if (sbuf->data)
|
||||||
@ -102,7 +119,13 @@ void netplay_clear_socket_buffer(struct socket_buffer *sbuf)
|
|||||||
sbuf->start = sbuf->read = sbuf->end = 0;
|
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)
|
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);
|
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)
|
bool netplay_send_flush(struct socket_buffer *sbuf, int sockfd, bool block)
|
||||||
{
|
{
|
||||||
ssize_t sent;
|
ssize_t sent;
|
||||||
@ -205,7 +236,15 @@ bool netplay_send_flush(struct socket_buffer *sbuf, int sockfd, bool block)
|
|||||||
return true;
|
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;
|
bool error;
|
||||||
ssize_t recvd;
|
ssize_t recvd;
|
||||||
@ -295,11 +334,23 @@ ssize_t netplay_recv(struct socket_buffer *sbuf, int sockfd, void *buf, size_t l
|
|||||||
return recvd;
|
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)
|
void netplay_recv_reset(struct socket_buffer *sbuf)
|
||||||
{
|
{
|
||||||
sbuf->read = sbuf->start;
|
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)
|
void netplay_recv_flush(struct socket_buffer *sbuf)
|
||||||
{
|
{
|
||||||
sbuf->start = sbuf->read;
|
sbuf->start = sbuf->read;
|
||||||
|
@ -23,7 +23,17 @@
|
|||||||
|
|
||||||
#include "netplay_private.h"
|
#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;
|
void *remember_state;
|
||||||
if (delta->used)
|
if (delta->used)
|
||||||
@ -43,6 +53,11 @@ bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, ui
|
|||||||
return true;
|
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)
|
uint32_t netplay_delta_frame_crc(netplay_t *netplay, struct delta_frame *delta)
|
||||||
{
|
{
|
||||||
if (!netplay->state_size)
|
if (!netplay->state_size)
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <compat/strl.h>
|
#include <compat/strl.h>
|
||||||
@ -191,6 +192,11 @@ error:
|
|||||||
return false;
|
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)
|
bool netplay_lan_ad_server(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
|
@ -28,10 +28,6 @@
|
|||||||
#include "../../input/input_driver.h"
|
#include "../../input/input_driver.h"
|
||||||
#include "../../runloop.h"
|
#include "../../runloop.h"
|
||||||
|
|
||||||
#ifndef HAVE_SOCKET_LEGACY
|
|
||||||
static void announce_nat_traversal(netplay_t *netplay);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Only used before init_netplay */
|
/* Only used before init_netplay */
|
||||||
static bool netplay_enabled = false;
|
static bool netplay_enabled = false;
|
||||||
static bool netplay_is_client = false;
|
static bool netplay_is_client = false;
|
||||||
@ -286,13 +282,18 @@ static bool netplay_poll(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Netplay polling callbacks */
|
/**
|
||||||
|
* input_poll_net
|
||||||
|
*
|
||||||
|
* Poll the network if necessary.
|
||||||
|
*/
|
||||||
void input_poll_net(void)
|
void input_poll_net(void)
|
||||||
{
|
{
|
||||||
if (!netplay_should_skip(netplay_data) && netplay_can_poll(netplay_data))
|
if (!netplay_should_skip(netplay_data) && netplay_can_poll(netplay_data))
|
||||||
netplay_poll();
|
netplay_poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Netplay polling callbacks */
|
||||||
void video_frame_net(const void *data, unsigned width,
|
void video_frame_net(const void *data, unsigned width,
|
||||||
unsigned height, size_t pitch)
|
unsigned height, size_t pitch)
|
||||||
{
|
{
|
||||||
@ -436,6 +437,42 @@ static void netplay_flip_users(netplay_t *netplay)
|
|||||||
netplay->flip_frame = flip_frame;
|
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_pre_frame:
|
||||||
* @netplay : pointer to netplay object
|
* @netplay : pointer to netplay object
|
||||||
@ -478,7 +515,7 @@ bool netplay_pre_frame(netplay_t *netplay)
|
|||||||
#ifndef HAVE_SOCKET_LEGACY
|
#ifndef HAVE_SOCKET_LEGACY
|
||||||
if (!netplay->nat_traversal_state.request_outstanding ||
|
if (!netplay->nat_traversal_state.request_outstanding ||
|
||||||
netplay->nat_traversal_state.have_inet4)
|
netplay->nat_traversal_state.have_inet4)
|
||||||
announce_nat_traversal(netplay);
|
netplay_announce_nat_traversal(netplay);
|
||||||
#endif
|
#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_load_savestate
|
||||||
* @netplay : pointer to netplay object
|
* @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
|
* netplay_toggle_play_spectate
|
||||||
*
|
*
|
||||||
|
@ -229,7 +229,13 @@ static uint32_t simple_rand_uint32()
|
|||||||
parts[2]);
|
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 *content_crc_ptr = NULL;
|
||||||
uint32_t header[5] = {0};
|
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);
|
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};
|
uint32_t header[5] = {0};
|
||||||
ssize_t recvd;
|
ssize_t recvd;
|
||||||
@ -509,7 +522,14 @@ bool netplay_handshake_sync(netplay_t *netplay, struct netplay_connection *conne
|
|||||||
return true;
|
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;
|
struct nick_buf_s nick_buf;
|
||||||
ssize_t recvd;
|
ssize_t recvd;
|
||||||
@ -567,7 +587,14 @@ bool netplay_handshake_pre_nick(netplay_t *netplay, struct netplay_connection *c
|
|||||||
return true;
|
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;
|
struct password_buf_s password_buf, corr_password_buf;
|
||||||
char password[8+NETPLAY_PASS_LEN]; /* 8 for salt */
|
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;
|
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 cmd[2];
|
||||||
uint32_t new_frame_count, connected_players, flip_frame;
|
uint32_t new_frame_count, connected_players, flip_frame;
|
||||||
|
@ -264,62 +264,6 @@ static bool netplay_init_socket_buffers(netplay_t *netplay)
|
|||||||
return true;
|
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)
|
bool netplay_init_serialization(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@ -358,6 +302,70 @@ bool netplay_init_serialization(netplay_t *netplay)
|
|||||||
return true;
|
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)
|
static bool netplay_init_buffers(netplay_t *netplay, unsigned frames)
|
||||||
{
|
{
|
||||||
size_t packet_buffer_size;
|
size_t packet_buffer_size;
|
||||||
@ -397,15 +405,16 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames)
|
|||||||
* @nick : Nickname of user.
|
* @nick : Nickname of user.
|
||||||
* @quirks : Netplay quirks required for this session.
|
* @quirks : Netplay quirks required for this session.
|
||||||
*
|
*
|
||||||
* Creates a new netplay handle. A NULL host means we're
|
* Creates a new netplay handle. A NULL server means we're
|
||||||
* hosting (user 1).
|
* hosting.
|
||||||
*
|
*
|
||||||
* Returns: new netplay handle.
|
* Returns: new netplay data.
|
||||||
**/
|
*/
|
||||||
netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port,
|
netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port,
|
||||||
const char *play_password, const char *spectate_password,
|
const char *play_password, const char *spectate_password,
|
||||||
unsigned delay_frames, unsigned check_frames, const struct retro_callbacks
|
unsigned delay_frames, unsigned check_frames,
|
||||||
*cb, bool nat_traversal, const char *nick, uint64_t quirks)
|
const struct retro_callbacks *cb, bool nat_traversal, const char *nick,
|
||||||
|
uint64_t quirks)
|
||||||
{
|
{
|
||||||
netplay_t *netplay = (netplay_t*)calloc(1, sizeof(*netplay));
|
netplay_t *netplay = (netplay_t*)calloc(1, sizeof(*netplay));
|
||||||
if (!netplay)
|
if (!netplay)
|
||||||
@ -486,11 +495,11 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netplay_free:
|
* netplay_free
|
||||||
* @netplay : pointer to netplay object
|
* @netplay : pointer to netplay object
|
||||||
*
|
*
|
||||||
* Frees netplay handle.
|
* Frees netplay data/
|
||||||
**/
|
*/
|
||||||
void netplay_free(netplay_t *netplay)
|
void netplay_free(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -54,7 +54,7 @@ static void remote_unpaused(netplay_t *netplay, struct netplay_connection *conne
|
|||||||
* netplay_hangup:
|
* netplay_hangup:
|
||||||
*
|
*
|
||||||
* Disconnects an active Netplay connection due to an error
|
* Disconnects an active Netplay connection due to an error
|
||||||
**/
|
*/
|
||||||
void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection)
|
void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection)
|
||||||
{
|
{
|
||||||
if (!netplay)
|
if (!netplay)
|
||||||
@ -145,7 +145,13 @@ static bool send_input_frame(netplay_t *netplay,
|
|||||||
return true;
|
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,
|
bool netplay_send_cur_input(netplay_t *netplay,
|
||||||
struct netplay_connection *connection)
|
struct netplay_connection *connection)
|
||||||
{
|
{
|
||||||
@ -203,9 +209,9 @@ bool netplay_send_cur_input(netplay_t *netplay,
|
|||||||
/**
|
/**
|
||||||
* netplay_send_raw_cmd
|
* 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,
|
bool netplay_send_raw_cmd(netplay_t *netplay,
|
||||||
struct netplay_connection *connection, uint32_t cmd, const void *data,
|
struct netplay_connection *connection, uint32_t cmd, const void *data,
|
||||||
@ -258,6 +264,11 @@ static bool netplay_cmd_nak(netplay_t *netplay,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netplay_cmd_crc
|
||||||
|
*
|
||||||
|
* Send a CRC command to all active clients.
|
||||||
|
*/
|
||||||
bool netplay_cmd_crc(netplay_t *netplay, struct delta_frame *delta)
|
bool netplay_cmd_crc(netplay_t *netplay, struct delta_frame *delta)
|
||||||
{
|
{
|
||||||
uint32_t payload[2];
|
uint32_t payload[2];
|
||||||
@ -275,6 +286,11 @@ bool netplay_cmd_crc(netplay_t *netplay, struct delta_frame *delta)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netplay_cmd_request_savestate
|
||||||
|
*
|
||||||
|
* Send a savestate request command.
|
||||||
|
*/
|
||||||
bool netplay_cmd_request_savestate(netplay_t *netplay)
|
bool netplay_cmd_request_savestate(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
if (netplay->connections_size == 0 ||
|
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_REQUEST_SAVESTATE, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netplay_cmd_mode
|
||||||
|
*
|
||||||
|
* Send a mode request command to either play or spectate.
|
||||||
|
*/
|
||||||
bool netplay_cmd_mode(netplay_t *netplay,
|
bool netplay_cmd_mode(netplay_t *netplay,
|
||||||
struct netplay_connection *connection,
|
struct netplay_connection *connection,
|
||||||
enum rarch_netplay_connection_mode mode)
|
enum rarch_netplay_connection_mode mode)
|
||||||
@ -1079,3 +1100,65 @@ bool netplay_flip_port(netplay_t *netplay)
|
|||||||
|
|
||||||
return netplay->flip ^ (frame < netplay->flip_frame);
|
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
|
||||||
|
}
|
||||||
|
@ -24,16 +24,10 @@
|
|||||||
#include <net/net_natt.h>
|
#include <net/net_natt.h>
|
||||||
#include <features/features_cpu.h>
|
#include <features/features_cpu.h>
|
||||||
#include <streams/trans_stream.h>
|
#include <streams/trans_stream.h>
|
||||||
#include <retro_endianness.h>
|
|
||||||
|
|
||||||
#include "../../core.h"
|
|
||||||
#include "../../msg_hash.h"
|
#include "../../msg_hash.h"
|
||||||
#include "../../verbosity.h"
|
#include "../../verbosity.h"
|
||||||
|
|
||||||
#ifdef ANDROID
|
|
||||||
#define HAVE_IPV6
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define WORDS_PER_INPUT 3 /* Buttons, left stick, right stick */
|
#define WORDS_PER_INPUT 3 /* Buttons, left stick, right stick */
|
||||||
#define WORDS_PER_FRAME (WORDS_PER_INPUT+2) /* + frameno, playerno */
|
#define WORDS_PER_FRAME (WORDS_PER_INPUT+2) /* + frameno, playerno */
|
||||||
|
|
||||||
@ -419,8 +413,209 @@ struct netplay
|
|||||||
uint32_t check_frames;
|
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);
|
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:
|
* netplay_new:
|
||||||
* @direct_host : Netplay host discovered from scanning.
|
* @direct_host : Netplay host discovered from scanning.
|
||||||
@ -435,160 +630,158 @@ void input_poll_net(void);
|
|||||||
* @nick : Nickname of user.
|
* @nick : Nickname of user.
|
||||||
* @quirks : Netplay quirks required for this session.
|
* @quirks : Netplay quirks required for this session.
|
||||||
*
|
*
|
||||||
* Creates a new netplay handle. A NULL host means we're
|
* Creates a new netplay handle. A NULL server means we're
|
||||||
* hosting (user 1).
|
* hosting.
|
||||||
*
|
*
|
||||||
* Returns: new netplay handle.
|
* Returns: new netplay data.
|
||||||
**/
|
*/
|
||||||
netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port,
|
netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port,
|
||||||
const char *play_password, const char *spectate_password,
|
const char *play_password, const char *spectate_password,
|
||||||
unsigned delay_frames, unsigned check_frames, const struct retro_callbacks
|
unsigned delay_frames, unsigned check_frames,
|
||||||
*cb, bool nat_traversal, const char *nick, uint64_t quirks);
|
const struct retro_callbacks *cb, bool nat_traversal, const char *nick,
|
||||||
|
uint64_t quirks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netplay_free:
|
* netplay_free
|
||||||
* @netplay : pointer to netplay object
|
* @netplay : pointer to netplay object
|
||||||
*
|
*
|
||||||
* Frees netplay handle.
|
* Frees netplay data/
|
||||||
**/
|
*/
|
||||||
void netplay_free(netplay_t *handle);
|
void netplay_free(netplay_t *netplay);
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* NETPLAY-IO.C
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netplay_pre_frame:
|
* netplay_hangup:
|
||||||
* @netplay : pointer to netplay object
|
|
||||||
*
|
*
|
||||||
* Pre-frame for Netplay.
|
* Disconnects an active Netplay connection due to an error
|
||||||
* Call this before running retro_run().
|
*/
|
||||||
*
|
void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection);
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netplay_post_frame:
|
* netplay_send_cur_input
|
||||||
* @netplay : pointer to netplay object
|
|
||||||
*
|
*
|
||||||
* Post-frame for Netplay.
|
* Send the current input frame to a given connection.
|
||||||
* 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
|
|
||||||
*
|
*
|
||||||
* Inform Netplay of the frontend's pause state (paused or otherwise)
|
* Returns true if successful, false 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);
|
|
||||||
|
|
||||||
bool netplay_send_cur_input(netplay_t *netplay,
|
bool netplay_send_cur_input(netplay_t *netplay,
|
||||||
struct netplay_connection *connection);
|
struct netplay_connection *connection);
|
||||||
|
|
||||||
int netplay_poll_net_input(netplay_t *netplay, bool block);
|
/**
|
||||||
|
* netplay_send_raw_cmd
|
||||||
void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection);
|
*
|
||||||
|
* Send a raw Netplay command to the given connection.
|
||||||
void netplay_update_unread_ptr(netplay_t *netplay);
|
*
|
||||||
|
* Returns true on success, false on failure.
|
||||||
bool netplay_flip_port(netplay_t *netplay);
|
*/
|
||||||
|
|
||||||
bool netplay_send_raw_cmd(netplay_t *netplay,
|
bool netplay_send_raw_cmd(netplay_t *netplay,
|
||||||
struct netplay_connection *connection, uint32_t cmd, const void *data,
|
struct netplay_connection *connection, uint32_t cmd, const void *data,
|
||||||
size_t size);
|
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,
|
void netplay_send_raw_cmd_all(netplay_t *netplay,
|
||||||
struct netplay_connection *except, uint32_t cmd, const void *data,
|
struct netplay_connection *except, uint32_t cmd, const void *data,
|
||||||
size_t size);
|
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);
|
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);
|
/**
|
||||||
|
* netplay_sync_post_frame
|
||||||
bool netplay_send(struct socket_buffer *sbuf, int sockfd, const void *buf, size_t len);
|
* @netplay : pointer to netplay object
|
||||||
|
*
|
||||||
bool netplay_send_flush(struct socket_buffer *sbuf, int sockfd, bool block);
|
* Post-frame for Netplay synchronization.
|
||||||
|
* We check if we have new input and replay from recorded input.
|
||||||
ssize_t netplay_recv(struct socket_buffer *sbuf, int sockfd, void *buf, size_t len, bool block);
|
*/
|
||||||
|
void netplay_sync_post_frame(netplay_t *netplay);
|
||||||
void netplay_recv_reset(struct socket_buffer *sbuf);
|
|
||||||
|
|
||||||
void netplay_recv_flush(struct socket_buffer *sbuf);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
* netplay_update_unread_ptr
|
* netplay_update_unread_ptr
|
||||||
*
|
*
|
||||||
* Update the global unread_ptr and unread_frame_count to correspond to the
|
* 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)
|
void netplay_update_unread_ptr(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
if (netplay->is_server && !netplay->connected_players)
|
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
|
* @netplay : pointer to netplay object
|
||||||
* @sim_ptr : frame index for which to simulate input
|
* @sim_ptr : frame index for which to simulate input
|
||||||
* @resim : are we resimulating, or simulating this frame for the
|
* @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
|
* @netplay : pointer to netplay object
|
||||||
*
|
*
|
||||||
* Pre-frame for Netplay synchronization.
|
* Pre-frame for Netplay synchronization.
|
||||||
**/
|
*/
|
||||||
bool netplay_sync_pre_frame(netplay_t *netplay)
|
bool netplay_sync_pre_frame(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
retro_ctx_serialize_info_t serial_info;
|
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
|
* @netplay : pointer to netplay object
|
||||||
*
|
*
|
||||||
* Post-frame for Netplay synchronization.
|
* Post-frame for Netplay synchronization.
|
||||||
* We check if we have new input and replay from recorded input.
|
* We check if we have new input and replay from recorded input.
|
||||||
**/
|
*/
|
||||||
void netplay_sync_post_frame(netplay_t *netplay)
|
void netplay_sync_post_frame(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
|
netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user