mirror of
https://github.com/libretro/RetroArch
synced 2025-02-07 03:40:24 +00:00
(Cthulhu88) Netplay - initial netplay tunnel
This commit is contained in:
parent
82b8c0a60e
commit
369cafe1ad
@ -39,6 +39,9 @@
|
|||||||
#define NETPLAY_HOST_STR_LEN 32
|
#define NETPLAY_HOST_STR_LEN 32
|
||||||
#define NETPLAY_HOST_LONGSTR_LEN 256
|
#define NETPLAY_HOST_LONGSTR_LEN 256
|
||||||
|
|
||||||
|
#define NETPLAY_MITM_MAX_PENDING 8
|
||||||
|
#define NETPLAY_MITM_ID_SIZE 16
|
||||||
|
|
||||||
enum rarch_netplay_ctl_state
|
enum rarch_netplay_ctl_state
|
||||||
{
|
{
|
||||||
RARCH_NETPLAY_CTL_NONE = 0,
|
RARCH_NETPLAY_CTL_NONE = 0,
|
||||||
@ -185,6 +188,16 @@ struct netplay_host_list
|
|||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct netplay_mitm_pending
|
||||||
|
{
|
||||||
|
int *fds;
|
||||||
|
uint8_t *ids[NETPLAY_MITM_ID_SIZE];
|
||||||
|
retro_time_t *timeouts;
|
||||||
|
|
||||||
|
int current;
|
||||||
|
int next;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
netplay_t *data; /* Used while Netplay is running */
|
netplay_t *data; /* Used while Netplay is running */
|
||||||
@ -210,6 +223,8 @@ typedef struct
|
|||||||
bool in_netplay;
|
bool in_netplay;
|
||||||
bool netplay_client_deferred;
|
bool netplay_client_deferred;
|
||||||
bool is_mitm;
|
bool is_mitm;
|
||||||
|
uint8_t mitm_id[NETPLAY_MITM_ID_SIZE];
|
||||||
|
struct netplay_mitm_pending mitm_pending;
|
||||||
bool has_set_netplay_mode;
|
bool has_set_netplay_mode;
|
||||||
bool has_set_netplay_ip_address;
|
bool has_set_netplay_ip_address;
|
||||||
bool has_set_netplay_ip_port;
|
bool has_set_netplay_ip_port;
|
||||||
|
@ -5759,8 +5759,7 @@ void netplay_init_nat_traversal(netplay_t *netplay)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int init_tcp_connection(const struct addrinfo *res,
|
static int init_tcp_connection(const struct addrinfo *res,
|
||||||
bool server,
|
bool is_server, bool use_mitm)
|
||||||
struct sockaddr *other_addr, socklen_t addr_size)
|
|
||||||
{
|
{
|
||||||
#ifndef HAVE_SOCKET_LEGACY
|
#ifndef HAVE_SOCKET_LEGACY
|
||||||
char msg[512];
|
char msg[512];
|
||||||
@ -5788,7 +5787,7 @@ static int init_tcp_connection(const struct addrinfo *res,
|
|||||||
RARCH_WARN("Cannot set Netplay port to close-on-exec. It may fail to reopen if the client disconnects.\n");
|
RARCH_WARN("Cannot set Netplay port to close-on-exec. It may fail to reopen if the client disconnects.\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (server)
|
if (!is_server)
|
||||||
{
|
{
|
||||||
if (!socket_connect(fd, (void*)res, false))
|
if (!socket_connect(fd, (void*)res, false))
|
||||||
return fd;
|
return fd;
|
||||||
@ -5809,34 +5808,101 @@ static int init_tcp_connection(const struct addrinfo *res,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if defined(HAVE_INET6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
#ifdef __NETPLAY_MITM_NEW
|
||||||
/* Make sure we accept connections on both IPv6 and IPv4 */
|
if (use_mitm)
|
||||||
if (res->ai_family == AF_INET6)
|
|
||||||
{
|
{
|
||||||
int on = 0;
|
if (!socket_connect(fd, (void*)res, false))
|
||||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
|
{
|
||||||
(const char*)&on, sizeof(on)) < 0)
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
RARCH_WARN("Failed to listen on both IPv6 and IPv4\n");
|
|
||||||
}
|
/* Relay server should provide us with our session ID. */
|
||||||
|
if (socket_receive_all_blocking(fd, net_st->mitm_id, sizeof(net_st->mitm_id)))
|
||||||
|
{
|
||||||
|
/* Initialize data for handling tunneled client connections. */
|
||||||
|
int *fds;
|
||||||
|
uint8_t *ids;
|
||||||
|
retro_time_t *timeouts;
|
||||||
|
|
||||||
|
fds = malloc(
|
||||||
|
NETPLAY_MITM_MAX_PENDING * sizeof(*fds));
|
||||||
|
ids = malloc(
|
||||||
|
NETPLAY_MITM_MAX_PENDING * NETPLAY_MITM_ID_SIZE * sizeof(*ids));
|
||||||
|
timeouts = malloc(
|
||||||
|
NETPLAY_MITM_MAX_PENDING * sizeof(*timeouts));
|
||||||
|
|
||||||
|
if (fds && ids && timeouts)
|
||||||
|
{
|
||||||
|
memset(fds, -1,
|
||||||
|
NETPLAY_MITM_MAX_PENDING * sizeof(*fds));
|
||||||
|
|
||||||
|
net_st->mitm_pending.fds = fds;
|
||||||
|
net_st->mitm_pending.ids = ids;
|
||||||
|
net_st->mitm_pending.timeouts = timeouts;
|
||||||
|
|
||||||
|
net_st->mitm_pending.current = 0;
|
||||||
|
net_st->mitm_pending.next = -1;
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(fds);
|
||||||
|
free(ids);
|
||||||
|
free(timeouts);
|
||||||
|
}
|
||||||
|
|
||||||
|
dmsg = "Failed to create a tunnel session.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifndef HAVE_SOCKET_LEGACY
|
||||||
|
if (!getnameinfo(res->ai_addr, res->ai_addrlen,
|
||||||
|
host, sizeof(host), port, sizeof(port),
|
||||||
|
NI_NUMERICHOST | NI_NUMERICSERV))
|
||||||
|
{
|
||||||
|
snprintf(msg, sizeof(msg),
|
||||||
|
"Failed to connect to relay server %s on port %s.",
|
||||||
|
host, port);
|
||||||
|
dmsg = msg;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
dmsg = "Failed to connect to relay server.";
|
||||||
#endif
|
#endif
|
||||||
if (socket_bind(fd, (void*)res))
|
}
|
||||||
{
|
|
||||||
if (!listen(fd, 1024))
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifndef HAVE_SOCKET_LEGACY
|
|
||||||
if (!getnameinfo(res->ai_addr, res->ai_addrlen,
|
|
||||||
NULL, 0, port, sizeof(port), NI_NUMERICSERV))
|
|
||||||
{
|
|
||||||
snprintf(msg, sizeof(msg), "Failed to bind port %s.", port);
|
|
||||||
dmsg = msg;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
dmsg = "Failed to bind port.";
|
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HAVE_INET6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||||
|
/* Make sure we accept connections on both IPv6 and IPv4 */
|
||||||
|
if (res->ai_family == AF_INET6)
|
||||||
|
{
|
||||||
|
int on = 0;
|
||||||
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||||
|
(const char*)&on, sizeof(on)) < 0)
|
||||||
|
RARCH_WARN("Failed to listen on both IPv6 and IPv4\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (socket_bind(fd, (void*)res))
|
||||||
|
{
|
||||||
|
if (!listen(fd, 1024))
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifndef HAVE_SOCKET_LEGACY
|
||||||
|
if (!getnameinfo(res->ai_addr, res->ai_addrlen,
|
||||||
|
NULL, 0, port, sizeof(port), NI_NUMERICSERV))
|
||||||
|
{
|
||||||
|
snprintf(msg, sizeof(msg), "Failed to bind port %s.", port);
|
||||||
|
dmsg = msg;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
dmsg = "Failed to bind port.";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef __NETPLAY_MITM_NEW
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_close(fd);
|
socket_close(fd);
|
||||||
@ -5847,20 +5913,19 @@ static int init_tcp_connection(const struct addrinfo *res,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool init_tcp_socket(netplay_t *netplay, void *direct_host,
|
static bool init_tcp_socket(netplay_t *netplay,
|
||||||
const char *server, uint16_t port)
|
const char *server, const char *mitm, uint16_t port)
|
||||||
{
|
{
|
||||||
struct addrinfo *res;
|
struct addrinfo *res;
|
||||||
const struct addrinfo *tmp_info;
|
const struct addrinfo *tmp_info;
|
||||||
struct sockaddr_storage sad;
|
char port_buf[6];
|
||||||
struct addrinfo hints = {0};
|
struct addrinfo hints = {0};
|
||||||
|
bool use_mitm = !server && mitm;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
|
||||||
if (!direct_host)
|
if (!server)
|
||||||
{
|
{
|
||||||
char port_buf[6];
|
if (!use_mitm)
|
||||||
snprintf(port_buf, sizeof(port_buf), "%hu", port);
|
|
||||||
if (!server)
|
|
||||||
{
|
{
|
||||||
hints.ai_flags = AI_PASSIVE;
|
hints.ai_flags = AI_PASSIVE;
|
||||||
#ifdef HAVE_INET6
|
#ifdef HAVE_INET6
|
||||||
@ -5870,62 +5935,58 @@ static bool init_tcp_socket(netplay_t *netplay, void *direct_host,
|
|||||||
hints.ai_family = AF_INET;
|
hints.ai_family = AF_INET;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
else
|
||||||
|
{
|
||||||
if (getaddrinfo_retro(server, port_buf, &hints, &res))
|
/* IPv4 only for relay servers. */
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
|
snprintf(port_buf, sizeof(port_buf), "%hu", port);
|
||||||
|
|
||||||
|
if (getaddrinfo_retro(use_mitm ? mitm : server, port_buf,
|
||||||
|
&hints, &res))
|
||||||
|
{
|
||||||
|
if (!server && !use_mitm)
|
||||||
{
|
{
|
||||||
if (!server)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_INET6
|
#ifdef HAVE_INET6
|
||||||
try_ipv4:
|
try_ipv4:
|
||||||
/* Didn't work with IPv6, try IPv4 */
|
/* Didn't work with IPv6, try IPv4 */
|
||||||
hints.ai_family = AF_INET;
|
hints.ai_family = AF_INET;
|
||||||
if (getaddrinfo_retro(server, port_buf, &hints, &res))
|
if (getaddrinfo_retro(server, port_buf, &hints, &res))
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
RARCH_ERR("Failed to set a hosting address.\n");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
char msg[512];
|
RARCH_ERR("Failed to set a hosting address.\n");
|
||||||
snprintf(msg, sizeof(msg),
|
|
||||||
"Failed to resolve host: %s\n", server);
|
|
||||||
RARCH_ERR(msg);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (!res)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* If we're serving on IPv6, make sure we accept all connections, including
|
|
||||||
* IPv4 */
|
|
||||||
#ifdef HAVE_INET6
|
|
||||||
if (!server && res->ai_family == AF_INET6)
|
|
||||||
{
|
{
|
||||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) res->ai_addr;
|
char msg[512];
|
||||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
snprintf(msg, sizeof(msg),
|
||||||
IN6ADDR_SETANY(sin6);
|
"Failed to resolve host: %s\n", use_mitm ? mitm : server);
|
||||||
#else
|
RARCH_ERR(msg);
|
||||||
sin6->sin6_addr = in6addr_any;
|
return false;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* If we're serving on IPv6, make sure we accept all connections, including
|
||||||
|
* IPv4 */
|
||||||
|
#ifdef HAVE_INET6
|
||||||
|
if (!server && !use_mitm && res->ai_family == AF_INET6)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) res->ai_addr;
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||||
|
IN6ADDR_SETANY(sin6);
|
||||||
|
#else
|
||||||
|
sin6->sin6_addr = in6addr_any;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
#endif
|
||||||
{
|
|
||||||
/* I'll build my own addrinfo! */
|
|
||||||
struct netplay_host *host = (struct netplay_host *)direct_host;
|
|
||||||
hints.ai_family = host->addr.sa_family;
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
|
||||||
hints.ai_protocol = 0;
|
|
||||||
hints.ai_addrlen = host->addrlen;
|
|
||||||
hints.ai_addr = &host->addr;
|
|
||||||
res = &hints;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If "localhost" is used, it is important to check every possible
|
/* If "localhost" is used, it is important to check every possible
|
||||||
* address for IPv4/IPv6. */
|
* address for IPv4/IPv6. */
|
||||||
@ -5933,34 +5994,31 @@ try_ipv4:
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
fd = init_tcp_connection(
|
fd = init_tcp_connection(tmp_info, !server, use_mitm);
|
||||||
tmp_info, direct_host || server,
|
|
||||||
(struct sockaddr *)
|
|
||||||
memset(&sad, 0, sizeof(sad)), sizeof(sad));
|
|
||||||
|
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
break;
|
break;
|
||||||
} while ((tmp_info = tmp_info->ai_next));
|
} while ((tmp_info = tmp_info->ai_next));
|
||||||
|
|
||||||
if (!direct_host)
|
freeaddrinfo_retro(res);
|
||||||
freeaddrinfo_retro(res);
|
|
||||||
res = NULL;
|
res = NULL;
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_INET6
|
#ifdef HAVE_INET6
|
||||||
if (!direct_host && !server && hints.ai_family == AF_INET6)
|
if (!server && !use_mitm && hints.ai_family == AF_INET6)
|
||||||
goto try_ipv4;
|
goto try_ipv4;
|
||||||
#endif
|
#endif
|
||||||
RARCH_ERR("Failed to set up netplay sockets.\n");
|
RARCH_ERR("Failed to set up netplay sockets.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (direct_host || server)
|
if (server)
|
||||||
{
|
{
|
||||||
netplay->connections[0].active = true;
|
netplay->connections[0].active = true;
|
||||||
netplay->connections[0].fd = fd;
|
netplay->connections[0].fd = fd;
|
||||||
netplay->connections[0].addr = sad;
|
memset(&netplay->connections[0].addr, 0,
|
||||||
|
sizeof(netplay->connections[0].addr));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
netplay->listen_fd = fd;
|
netplay->listen_fd = fd;
|
||||||
@ -5974,7 +6032,7 @@ static bool init_socket(netplay_t *netplay, void *direct_host,
|
|||||||
if (!network_init())
|
if (!network_init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!init_tcp_socket(netplay, direct_host, server, port))
|
if (!init_tcp_socket(netplay, server, NULL, port))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (netplay->is_server && netplay->nat_traversal)
|
if (netplay->is_server && netplay->nat_traversal)
|
||||||
@ -7531,11 +7589,26 @@ void deinit_netplay(void)
|
|||||||
if (net_st->data)
|
if (net_st->data)
|
||||||
{
|
{
|
||||||
netplay_free(net_st->data);
|
netplay_free(net_st->data);
|
||||||
|
net_st->data = NULL;
|
||||||
net_st->netplay_enabled = false;
|
net_st->netplay_enabled = false;
|
||||||
net_st->netplay_is_client = false;
|
net_st->netplay_is_client = false;
|
||||||
net_st->is_mitm = false;
|
net_st->is_mitm = false;
|
||||||
}
|
}
|
||||||
net_st->data = NULL;
|
if (net_st->mitm_pending.fds)
|
||||||
|
{
|
||||||
|
free(net_st->mitm_pending.fds);
|
||||||
|
net_st->mitm_pending.fds = NULL;
|
||||||
|
}
|
||||||
|
if (net_st->mitm_pending.ids)
|
||||||
|
{
|
||||||
|
free(net_st->mitm_pending.ids);
|
||||||
|
net_st->mitm_pending.ids = NULL;
|
||||||
|
}
|
||||||
|
if (net_st->mitm_pending.timeouts)
|
||||||
|
{
|
||||||
|
free(net_st->mitm_pending.timeouts);
|
||||||
|
net_st->mitm_pending.timeouts = NULL;
|
||||||
|
}
|
||||||
core_unset_netplay_callbacks();
|
core_unset_netplay_callbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user