mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-26 17:50:56 +00:00
Merge pull request #13987 from Cthulhu-throwaway/master
(Netplay) Enforce a timeout during connection
This commit is contained in:
commit
5e258eb8f0
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
/* Copyright (C) 2010-2022 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (net_socket.h).
|
||||
@ -72,12 +72,20 @@ bool socket_nonblock(int fd);
|
||||
int socket_select(int nfds, fd_set *readfs, fd_set *writefds,
|
||||
fd_set *errorfds, struct timeval *timeout);
|
||||
|
||||
int socket_send_all_blocking(int fd, const void *data_, size_t size, bool no_signal);
|
||||
bool socket_send_all_blocking(int fd, const void *data_, size_t size, bool no_signal);
|
||||
|
||||
bool socket_send_all_blocking_with_timeout(int fd,
|
||||
const void *data_, size_t size,
|
||||
unsigned timeout, bool no_signal);
|
||||
|
||||
ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t size,
|
||||
bool no_signal);
|
||||
|
||||
int socket_receive_all_blocking(int fd, void *data_, size_t size);
|
||||
bool socket_receive_all_blocking(int fd, void *data_, size_t size);
|
||||
|
||||
bool socket_receive_all_blocking_with_timeout(int fd,
|
||||
void *data_, size_t size,
|
||||
unsigned timeout);
|
||||
|
||||
ssize_t socket_receive_all_nonblocking(int fd, bool *error,
|
||||
void *data_, size_t size);
|
||||
@ -86,6 +94,8 @@ bool socket_bind(int fd, void *data);
|
||||
|
||||
int socket_connect(int fd, void *data, bool timeout_enable);
|
||||
|
||||
bool socket_connect_with_timeout(int fd, void *data, unsigned timeout);
|
||||
|
||||
int socket_create(
|
||||
const char *name,
|
||||
enum socket_domain domain_type,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
/* Copyright (C) 2010-2022 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (net_socket.c).
|
||||
@ -31,6 +31,8 @@
|
||||
#include <network.h>
|
||||
#endif
|
||||
|
||||
#include <features/features_cpu.h>
|
||||
|
||||
#include <net/net_compat.h>
|
||||
#include <net/net_socket.h>
|
||||
|
||||
@ -90,38 +92,89 @@ int socket_next(void **addrinfo)
|
||||
ssize_t socket_receive_all_nonblocking(int fd, bool *error,
|
||||
void *data_, size_t size)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t*)data_;
|
||||
ssize_t ret = recv(fd, (char*)data, size, 0);
|
||||
ssize_t ret = recv(fd, (char*)data_, size, 0);
|
||||
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
/* Socket closed */
|
||||
*error = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (isagain((int)ret))
|
||||
if (ret < 0 && isagain((int)ret))
|
||||
return 0;
|
||||
|
||||
*error = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int socket_receive_all_blocking(int fd, void *data_, size_t size)
|
||||
bool socket_receive_all_blocking(int fd, void *data_, size_t size)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t*)data_;
|
||||
|
||||
while (size)
|
||||
{
|
||||
ssize_t ret = recv(fd, (char*)data, size, 0);
|
||||
if (ret <= 0)
|
||||
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
data += ret;
|
||||
size -= ret;
|
||||
if (ret < 0)
|
||||
{
|
||||
if (!isagain((int)ret))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data += ret;
|
||||
size -= ret;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool socket_receive_all_blocking_with_timeout(int fd,
|
||||
void *data_, size_t size,
|
||||
unsigned timeout)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t*)data_;
|
||||
retro_time_t deadline = cpu_features_get_time_usec();
|
||||
|
||||
if (timeout)
|
||||
deadline += (retro_time_t)timeout * 1000000;
|
||||
else
|
||||
deadline += 5000000;
|
||||
|
||||
while (size)
|
||||
{
|
||||
ssize_t ret = recv(fd, (char*)data, size, 0);
|
||||
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
retro_time_t time_delta;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
|
||||
if (!isagain((int)ret))
|
||||
return false;
|
||||
|
||||
time_delta = deadline - cpu_features_get_time_usec();
|
||||
|
||||
if (time_delta <= 0)
|
||||
return false;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
tv.tv_sec = (unsigned)(time_delta / 1000000);
|
||||
tv.tv_usec = (unsigned)(time_delta % 1000000);
|
||||
if (socket_select(fd + 1, &fds, NULL, NULL, &tv) <= 0)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data += ret;
|
||||
size -= ret;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -187,25 +240,80 @@ int socket_select(int nfds, fd_set *readfs, fd_set *writefds,
|
||||
#endif
|
||||
}
|
||||
|
||||
int socket_send_all_blocking(int fd, const void *data_, size_t size,
|
||||
bool socket_send_all_blocking(int fd, const void *data_, size_t size,
|
||||
bool no_signal)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t*)data_;
|
||||
int flags = no_signal ? MSG_NOSIGNAL : 0;
|
||||
|
||||
while (size)
|
||||
{
|
||||
ssize_t ret = send(fd, (const char*)data, size,
|
||||
no_signal ? MSG_NOSIGNAL : 0);
|
||||
if (ret <= 0)
|
||||
ssize_t ret = send(fd, (const char*)data, size, flags);
|
||||
|
||||
if (!ret)
|
||||
continue;
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
if (isagain((int)ret))
|
||||
continue;
|
||||
|
||||
return false;
|
||||
if (!isagain((int)ret))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data += ret;
|
||||
size -= ret;
|
||||
}
|
||||
}
|
||||
|
||||
data += ret;
|
||||
size -= ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool socket_send_all_blocking_with_timeout(int fd,
|
||||
const void *data_, size_t size,
|
||||
unsigned timeout, bool no_signal)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t*)data_;
|
||||
int flags = no_signal ? MSG_NOSIGNAL : 0;
|
||||
retro_time_t deadline = cpu_features_get_time_usec();
|
||||
|
||||
if (timeout)
|
||||
deadline += (retro_time_t)timeout * 1000000;
|
||||
else
|
||||
deadline += 5000000;
|
||||
|
||||
while (size)
|
||||
{
|
||||
ssize_t ret = send(fd, (const char*)data, size, flags);
|
||||
|
||||
if (!ret)
|
||||
continue;
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
retro_time_t time_delta;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
|
||||
if (!isagain((int)ret))
|
||||
return false;
|
||||
|
||||
time_delta = deadline - cpu_features_get_time_usec();
|
||||
|
||||
if (time_delta <= 0)
|
||||
return false;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
tv.tv_sec = (unsigned)(time_delta / 1000000);
|
||||
tv.tv_usec = (unsigned)(time_delta % 1000000);
|
||||
if (socket_select(fd + 1, NULL, &fds, NULL, &tv) <= 0)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data += ret;
|
||||
size -= ret;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -215,12 +323,15 @@ ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t size,
|
||||
bool no_signal)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t*)data_;
|
||||
ssize_t sent = 0;
|
||||
int flags = no_signal ? MSG_NOSIGNAL : 0;
|
||||
|
||||
while (size)
|
||||
{
|
||||
ssize_t ret = send(fd, (const char*)data, size,
|
||||
no_signal ? MSG_NOSIGNAL : 0);
|
||||
ssize_t ret = send(fd, (const char*)data, size, flags);
|
||||
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
if (isagain((int)ret))
|
||||
@ -228,15 +339,14 @@ ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t size,
|
||||
|
||||
return -1;
|
||||
}
|
||||
else if (ret == 0)
|
||||
break;
|
||||
|
||||
data += ret;
|
||||
size -= ret;
|
||||
sent += ret;
|
||||
else
|
||||
{
|
||||
data += ret;
|
||||
size -= ret;
|
||||
}
|
||||
}
|
||||
|
||||
return sent;
|
||||
return (ssize_t)((size_t)data - (size_t)data_);
|
||||
}
|
||||
|
||||
bool socket_bind(int fd, void *data)
|
||||
@ -266,37 +376,106 @@ int socket_connect(int fd, void *data, bool timeout_enable)
|
||||
timeout.tv_sec = 4;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof timeout);
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
|
||||
}
|
||||
#endif
|
||||
#if defined(GEKKO) && !defined(WIIU)
|
||||
#elif defined(GEKKO) && !defined(WIIU)
|
||||
if (timeout_enable)
|
||||
{
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 4;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
net_setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof timeout);
|
||||
net_setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
|
||||
}
|
||||
#endif
|
||||
#if defined(WIIU)
|
||||
int op = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op));
|
||||
if (addr->ai_socktype == SOCK_STREAM) {
|
||||
setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op));
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, 0x10000, &op, sizeof(op));
|
||||
int recvsz = WIIU_RCVBUF;
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz));
|
||||
int sendsz = WIIU_SNDBUF;
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz));
|
||||
#ifdef WIIU
|
||||
{
|
||||
int op = 1;
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op));
|
||||
|
||||
if (addr->ai_socktype == SOCK_STREAM)
|
||||
{
|
||||
int recvsz = WIIU_RCVBUF;
|
||||
int sendsz = WIIU_SNDBUF;
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op));
|
||||
setsockopt(fd, SOL_SOCKET, 0x10000, &op, sizeof(op));
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz));
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return connect(fd, addr->ai_addr, addr->ai_addrlen);
|
||||
}
|
||||
|
||||
bool socket_connect_with_timeout(int fd, void *data, unsigned timeout)
|
||||
{
|
||||
int res;
|
||||
struct addrinfo *addr = (struct addrinfo*)data;
|
||||
|
||||
if (!socket_nonblock(fd))
|
||||
return false;
|
||||
|
||||
#ifdef WIIU
|
||||
{
|
||||
int op = 1;
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op));
|
||||
|
||||
if (addr->ai_socktype == SOCK_STREAM)
|
||||
{
|
||||
int recvsz = WIIU_RCVBUF;
|
||||
int sendsz = WIIU_SNDBUF;
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op));
|
||||
setsockopt(fd, SOL_SOCKET, 0x10000, &op, sizeof(op));
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz));
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
res = connect(fd, addr->ai_addr, addr->ai_addrlen);
|
||||
if (res)
|
||||
{
|
||||
fd_set wfd, efd;
|
||||
struct timeval tv = {0};
|
||||
|
||||
if (!isagain(res))
|
||||
#if !defined(_WIN32) && defined(EINPROGRESS)
|
||||
if (errno != EINPROGRESS)
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
FD_ZERO(&wfd);
|
||||
FD_ZERO(&efd);
|
||||
FD_SET(fd, &wfd);
|
||||
FD_SET(fd, &efd);
|
||||
tv.tv_sec = timeout ? timeout : 5;
|
||||
if (socket_select(fd + 1, NULL, &wfd, &efd, &tv) <= 0)
|
||||
return false;
|
||||
if (FD_ISSET(fd, &efd))
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef SO_ERROR
|
||||
{
|
||||
int error = -1;
|
||||
socklen_t errsz = sizeof(error);
|
||||
|
||||
getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &errsz);
|
||||
if (error)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int domain_get(enum socket_domain type)
|
||||
{
|
||||
switch (type)
|
||||
|
@ -6396,7 +6396,7 @@ void netplay_deinit_nat_traversal(void)
|
||||
task_push_netplay_nat_close(&net_st->nat_traversal_request);
|
||||
}
|
||||
|
||||
static int init_tcp_connection(netplay_t *netplay, const struct addrinfo *res,
|
||||
static int init_tcp_connection(netplay_t *netplay, const struct addrinfo *addr,
|
||||
bool is_server, bool is_mitm)
|
||||
{
|
||||
#ifndef HAVE_SOCKET_LEGACY
|
||||
@ -6404,8 +6404,8 @@ static int init_tcp_connection(netplay_t *netplay, const struct addrinfo *res,
|
||||
char host[256], port[6];
|
||||
#endif
|
||||
const char *dmsg = NULL;
|
||||
int fd = socket(res->ai_family, res->ai_socktype,
|
||||
res->ai_protocol);
|
||||
int fd = socket(addr->ai_family, addr->ai_socktype,
|
||||
addr->ai_protocol);
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
@ -6415,17 +6415,19 @@ static int init_tcp_connection(netplay_t *netplay, const struct addrinfo *res,
|
||||
|
||||
if (!is_server)
|
||||
{
|
||||
if (!socket_connect(fd, (void*)res, false))
|
||||
if (socket_connect_with_timeout(fd, (void*)addr, 10))
|
||||
{
|
||||
/* If we are connecting to a tunnel server,
|
||||
we must also send our session linking request. */
|
||||
if (!netplay->mitm_session_id.magic || socket_send_all_blocking(fd,
|
||||
&netplay->mitm_session_id, sizeof(netplay->mitm_session_id), true))
|
||||
if (!netplay->mitm_session_id.magic ||
|
||||
socket_send_all_blocking_with_timeout(fd,
|
||||
&netplay->mitm_session_id, sizeof(netplay->mitm_session_id),
|
||||
5, true))
|
||||
return fd;
|
||||
}
|
||||
|
||||
#ifndef HAVE_SOCKET_LEGACY
|
||||
if (!getnameinfo(res->ai_addr, res->ai_addrlen,
|
||||
if (!getnameinfo(addr->ai_addr, addr->ai_addrlen,
|
||||
host, sizeof(host), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV))
|
||||
{
|
||||
@ -6440,32 +6442,36 @@ static int init_tcp_connection(netplay_t *netplay, const struct addrinfo *res,
|
||||
}
|
||||
else if (is_mitm)
|
||||
{
|
||||
if (!socket_connect(fd, (void*)res, false))
|
||||
if (socket_connect_with_timeout(fd, (void*)addr, 10))
|
||||
{
|
||||
mitm_id_t new_session = {0};
|
||||
mitm_id_t invalid_session = {0};
|
||||
mitm_id_t new_session = {0};
|
||||
|
||||
/* To request a new session,
|
||||
we send the magic with the rest of the ID zeroed. */
|
||||
new_session.magic = htonl(MITM_SESSION_MAGIC);
|
||||
|
||||
/* Tunnel server should provide us with our session ID. */
|
||||
if (socket_send_all_blocking(fd,
|
||||
&new_session, sizeof(new_session), true) &&
|
||||
socket_receive_all_blocking(fd,
|
||||
&netplay->mitm_session_id, sizeof(netplay->mitm_session_id)) &&
|
||||
ntohl(netplay->mitm_session_id.magic) == MITM_SESSION_MAGIC &&
|
||||
memcmp(netplay->mitm_session_id.unique, invalid_session.unique,
|
||||
sizeof(netplay->mitm_session_id.unique)))
|
||||
if (socket_send_all_blocking_with_timeout(fd,
|
||||
&new_session, sizeof(new_session), 5, true) &&
|
||||
socket_receive_all_blocking_with_timeout(fd,
|
||||
&netplay->mitm_session_id, sizeof(netplay->mitm_session_id),
|
||||
5))
|
||||
{
|
||||
/* Initialize data for handling tunneled client connections. */
|
||||
netplay->mitm_pending = (struct netplay_mitm_pending*)calloc(1, sizeof(*netplay->mitm_pending));
|
||||
if (netplay->mitm_pending)
|
||||
if (ntohl(netplay->mitm_session_id.magic) == MITM_SESSION_MAGIC &&
|
||||
memcmp(netplay->mitm_session_id.unique, new_session.unique,
|
||||
sizeof(netplay->mitm_session_id.unique)))
|
||||
{
|
||||
memset(netplay->mitm_pending->fds, -1,
|
||||
sizeof(netplay->mitm_pending->fds));
|
||||
netplay->mitm_pending->addr = res;
|
||||
return fd;
|
||||
/* Initialize data for handling tunneled client connections. */
|
||||
netplay->mitm_pending = (struct netplay_mitm_pending*)
|
||||
calloc(1, sizeof(*netplay->mitm_pending));
|
||||
if (netplay->mitm_pending)
|
||||
{
|
||||
memset(netplay->mitm_pending->fds, -1,
|
||||
sizeof(netplay->mitm_pending->fds));
|
||||
netplay->mitm_pending->addr = addr;
|
||||
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6474,7 +6480,7 @@ static int init_tcp_connection(netplay_t *netplay, const struct addrinfo *res,
|
||||
else
|
||||
{
|
||||
#ifndef HAVE_SOCKET_LEGACY
|
||||
if (!getnameinfo(res->ai_addr, res->ai_addrlen,
|
||||
if (!getnameinfo(addr->ai_addr, addr->ai_addrlen,
|
||||
host, sizeof(host), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV))
|
||||
{
|
||||
@ -6492,7 +6498,7 @@ static int init_tcp_connection(netplay_t *netplay, const struct addrinfo *res,
|
||||
{
|
||||
#if defined(HAVE_INET6) && defined(IPV6_V6ONLY)
|
||||
/* Make sure we accept connections on both IPv6 and IPv4 */
|
||||
if (res->ai_family == AF_INET6)
|
||||
if (addr->ai_family == AF_INET6)
|
||||
{
|
||||
int on = 0;
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
@ -6500,15 +6506,16 @@ static int init_tcp_connection(netplay_t *netplay, const struct addrinfo *res,
|
||||
RARCH_WARN("[Netplay] Failed to listen on both IPv6 and IPv4.\n");
|
||||
}
|
||||
#endif
|
||||
if (socket_bind(fd, (void*)res))
|
||||
|
||||
if (socket_bind(fd, (void*)addr))
|
||||
{
|
||||
if (!listen(fd, 64))
|
||||
if (!listen(fd, 64) && socket_nonblock(fd))
|
||||
return fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef HAVE_SOCKET_LEGACY
|
||||
if (!getnameinfo(res->ai_addr, res->ai_addrlen,
|
||||
if (!getnameinfo(addr->ai_addr, addr->ai_addrlen,
|
||||
NULL, 0, port, sizeof(port), NI_NUMERICSERV))
|
||||
{
|
||||
snprintf(msg, sizeof(msg),
|
||||
@ -6533,13 +6540,16 @@ static int init_tcp_connection(netplay_t *netplay, const struct addrinfo *res,
|
||||
static bool init_tcp_socket(netplay_t *netplay,
|
||||
const char *server, const char *mitm, uint16_t port)
|
||||
{
|
||||
struct addrinfo *res;
|
||||
const struct addrinfo *tmp_info;
|
||||
char port_buf[6];
|
||||
const struct addrinfo *tmp_info;
|
||||
struct addrinfo *addr = NULL;
|
||||
struct addrinfo hints = {0};
|
||||
bool is_mitm = !server && mitm;
|
||||
int fd = -1;
|
||||
|
||||
if (!network_init())
|
||||
return false;
|
||||
|
||||
if (!server)
|
||||
{
|
||||
if (!is_mitm)
|
||||
@ -6563,7 +6573,7 @@ static bool init_tcp_socket(netplay_t *netplay,
|
||||
snprintf(port_buf, sizeof(port_buf), "%hu", port);
|
||||
|
||||
if (getaddrinfo_retro(is_mitm ? mitm : server, port_buf,
|
||||
&hints, &res))
|
||||
&hints, &addr))
|
||||
{
|
||||
if (!server && !is_mitm)
|
||||
{
|
||||
@ -6571,7 +6581,7 @@ static bool init_tcp_socket(netplay_t *netplay,
|
||||
try_ipv4:
|
||||
/* Didn't work with IPv6, try IPv4 */
|
||||
hints.ai_family = AF_INET;
|
||||
if (getaddrinfo_retro(server, port_buf, &hints, &res))
|
||||
if (getaddrinfo_retro(server, port_buf, &hints, &addr))
|
||||
#endif
|
||||
{
|
||||
RARCH_ERR("[Netplay] Failed to set a hosting address.\n");
|
||||
@ -6580,20 +6590,22 @@ try_ipv4:
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_ERR("[Netplay] Failed to resolve host: %s\n", is_mitm ? mitm : server);
|
||||
RARCH_ERR("[Netplay] Failed to resolve host: %s\n",
|
||||
is_mitm ? mitm : server);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!res)
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
/* If we're serving on IPv6, make sure we accept all connections, including
|
||||
* IPv4 */
|
||||
#ifdef HAVE_INET6
|
||||
if (!server && !is_mitm && res->ai_family == AF_INET6)
|
||||
if (!server && !is_mitm && addr->ai_family == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) res->ai_addr;
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr->ai_addr;
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
IN6ADDR_SETANY(sin6);
|
||||
#else
|
||||
@ -6604,7 +6616,7 @@ try_ipv4:
|
||||
|
||||
/* If "localhost" is used, it is important to check every possible
|
||||
* address for IPv4/IPv6. */
|
||||
tmp_info = res;
|
||||
tmp_info = addr;
|
||||
|
||||
do
|
||||
{
|
||||
@ -6614,10 +6626,10 @@ try_ipv4:
|
||||
} while ((tmp_info = tmp_info->ai_next));
|
||||
|
||||
if (netplay->mitm_pending && netplay->mitm_pending->addr)
|
||||
netplay->mitm_pending->base_addr = res;
|
||||
netplay->mitm_pending->base_addr = addr;
|
||||
else
|
||||
freeaddrinfo_retro(res);
|
||||
res = NULL;
|
||||
freeaddrinfo_retro(addr);
|
||||
addr = NULL;
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
@ -6629,18 +6641,10 @@ try_ipv4:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!socket_nonblock(fd))
|
||||
{
|
||||
socket_close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (server)
|
||||
{
|
||||
netplay->connections[0].active = true;
|
||||
netplay->connections[0].fd = fd;
|
||||
memset(&netplay->connections[0].addr, 0,
|
||||
sizeof(netplay->connections[0].addr));
|
||||
}
|
||||
else
|
||||
netplay->listen_fd = fd;
|
||||
@ -6648,21 +6652,6 @@ try_ipv4:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool init_socket(netplay_t *netplay,
|
||||
const char *server, const char *mitm, uint16_t port)
|
||||
{
|
||||
if (!network_init())
|
||||
return false;
|
||||
|
||||
if (!init_tcp_socket(netplay, server, mitm, port))
|
||||
return false;
|
||||
|
||||
if (netplay->is_server && netplay->nat_traversal)
|
||||
netplay_init_nat_traversal(netplay);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool netplay_init_socket_buffers(netplay_t *netplay)
|
||||
{
|
||||
/* Make our packet buffer big enough for a save state and stall-frames-many
|
||||
@ -6863,26 +6852,20 @@ netplay_t *netplay_new(const char *server, const char *mitm, uint16_t port,
|
||||
netplay->ext_tcp_port = port;
|
||||
netplay->cbs = *cb;
|
||||
netplay->is_server = !server;
|
||||
netplay->is_connected = false;
|
||||
netplay->nat_traversal = (!server && !mitm) ? nat_traversal : false;
|
||||
netplay->stateless_mode = stateless_mode;
|
||||
netplay->check_frames = check_frames;
|
||||
netplay->crc_validity_checked = false;
|
||||
netplay->crcs_valid = true;
|
||||
netplay->quirks = quirks;
|
||||
netplay->simple_rand_next = 1;
|
||||
netplay->self_mode = netplay->is_server ?
|
||||
NETPLAY_CONNECTION_SPECTATING :
|
||||
NETPLAY_CONNECTION_NONE;
|
||||
NETPLAY_CONNECTION_SPECTATING : NETPLAY_CONNECTION_NONE;
|
||||
|
||||
if (netplay->stateless_mode)
|
||||
netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES;
|
||||
|
||||
if (netplay->is_server)
|
||||
{
|
||||
netplay->connections = NULL;
|
||||
netplay->connections_size = 0;
|
||||
|
||||
netplay->allow_pausing =
|
||||
settings->bools.netplay_allow_pausing;
|
||||
netplay->input_latency_frames_min =
|
||||
@ -6902,10 +6885,10 @@ netplay_t *netplay_new(const char *server, const char *mitm, uint16_t port,
|
||||
|
||||
if (!string_is_empty(mitm_session))
|
||||
{
|
||||
int flen;
|
||||
unsigned char *buf;
|
||||
int flen = 0;
|
||||
unsigned char *buf =
|
||||
unbase64(mitm_session, strlen(mitm_session), &flen);
|
||||
|
||||
buf = unbase64(mitm_session, strlen(mitm_session), &flen);
|
||||
if (!buf)
|
||||
goto failure;
|
||||
if (flen != sizeof(netplay->mitm_session_id.unique))
|
||||
@ -6922,11 +6905,11 @@ netplay_t *netplay_new(const char *server, const char *mitm, uint16_t port,
|
||||
netplay->allow_pausing = true;
|
||||
}
|
||||
|
||||
strlcpy(netplay->nick, !string_is_empty(nick)
|
||||
? nick : RARCH_DEFAULT_NICK,
|
||||
sizeof(netplay->nick));
|
||||
strlcpy(netplay->nick,
|
||||
!string_is_empty(nick) ? nick : RARCH_DEFAULT_NICK,
|
||||
sizeof(netplay->nick));
|
||||
|
||||
if (!init_socket(netplay, server, mitm, port) ||
|
||||
if (!init_tcp_socket(netplay, server, mitm, port) ||
|
||||
!netplay_init_buffers(netplay))
|
||||
goto failure;
|
||||
|
||||
@ -6936,33 +6919,38 @@ netplay_t *netplay_new(const char *server, const char *mitm, uint16_t port,
|
||||
|
||||
if (netplay->mitm_session_id.magic)
|
||||
{
|
||||
int flen;
|
||||
char *buf;
|
||||
net_driver_state_t *net_st = &networking_driver_st;
|
||||
net_driver_state_t *net_st = &networking_driver_st;
|
||||
struct netplay_room *host_room = &net_st->host_room;
|
||||
|
||||
buf = base64(netplay->mitm_session_id.unique,
|
||||
int flen = 0;
|
||||
char *buf = base64(netplay->mitm_session_id.unique,
|
||||
sizeof(netplay->mitm_session_id.unique), &flen);
|
||||
|
||||
if (!buf)
|
||||
goto failure;
|
||||
|
||||
strlcpy(host_room->mitm_session, buf,
|
||||
sizeof(host_room->mitm_session));
|
||||
free(buf);
|
||||
}
|
||||
else if (netplay->nat_traversal)
|
||||
netplay_init_nat_traversal(netplay);
|
||||
|
||||
/* Clients get device info from the server */
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
uint32_t dtype = input_config_get_device(i);
|
||||
|
||||
netplay->config_devices[i] = dtype;
|
||||
if ((dtype&RETRO_DEVICE_MASK) == RETRO_DEVICE_KEYBOARD)
|
||||
|
||||
if ((dtype & RETRO_DEVICE_MASK) == RETRO_DEVICE_KEYBOARD)
|
||||
{
|
||||
netplay->have_updown_device = true;
|
||||
netplay_key_hton_init();
|
||||
}
|
||||
if (dtype != RETRO_DEVICE_NONE && !netplay_expected_input_size(netplay, 1<<i))
|
||||
RARCH_WARN("[Netplay] Netplay does not support input device %u\n", i+1);
|
||||
|
||||
if (dtype != RETRO_DEVICE_NONE &&
|
||||
!netplay_expected_input_size(netplay, 1 << i))
|
||||
RARCH_WARN("[Netplay] Netplay does not support input device %u\n",
|
||||
i + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -6979,6 +6967,7 @@ netplay_t *netplay_new(const char *server, const char *mitm, uint16_t port,
|
||||
|
||||
failure:
|
||||
netplay_free(netplay);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user