mirror of
https://github.com/libretro/RetroArch
synced 2025-03-30 07:20:36 +00:00
NAT traversal in Netplay
For the time being, if NAT traversal is successful it simply announces it as an OSD message. In the future it will be used to inform a matchmaking server of the public port. This patch also included minor fixes to the NAT traversal implementation to make the select it demands actually doable.
This commit is contained in:
parent
48240c2806
commit
42da0a0184
@ -22,6 +22,10 @@ MSG_HASH(
|
||||
MSG_GOT_CONNECTION_FROM,
|
||||
"Got connection from"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_PUBLIC_ADDRESS,
|
||||
"Public address"
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN,
|
||||
"No arguments supplied and no menu builtin, displaying help..."
|
||||
|
@ -27,9 +27,15 @@
|
||||
#include <net/net_socket.h>
|
||||
|
||||
struct natt_status {
|
||||
/** nfds for select when checking for input */
|
||||
int nfds;
|
||||
|
||||
/** The fdset to be selected upon to check for responses */
|
||||
fd_set fds;
|
||||
|
||||
/** True if there might be a request outstanding */
|
||||
bool request_outstanding;
|
||||
|
||||
/** True if we've resolved an external IPv4 address */
|
||||
bool have_inet4;
|
||||
|
||||
|
@ -173,6 +173,7 @@ enum msg_hash_enums
|
||||
MSG_NO_STATE_HAS_BEEN_LOADED_YET,
|
||||
MSG_GOT_CONNECTION_FROM,
|
||||
MSG_CONNECTION_SLOT,
|
||||
MSG_PUBLIC_ADDRESS,
|
||||
MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET,
|
||||
MSG_CANNOT_INFER_NEW_CONFIG_PATH,
|
||||
MSG_UNDID_LOAD_STATE,
|
||||
|
@ -63,6 +63,8 @@ static netplay_t *netplay_data = NULL;
|
||||
/* Used to avoid recursive netplay calls */
|
||||
static bool in_netplay = false;
|
||||
|
||||
static void announce_nat_traversal(netplay_t *netplay);
|
||||
|
||||
static int init_tcp_connection(const struct addrinfo *res,
|
||||
bool server, bool spectate,
|
||||
struct sockaddr *other_addr, socklen_t addr_size)
|
||||
@ -172,6 +174,22 @@ static bool init_tcp_socket(netplay_t *netplay, const char *server,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void 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);
|
||||
|
||||
if (!netplay->nat_traversal_state.request_outstanding)
|
||||
announce_nat_traversal(netplay);
|
||||
}
|
||||
|
||||
static bool init_ad_socket(netplay_t *netplay, uint16_t port)
|
||||
{
|
||||
int fd = socket_init((void**)&netplay->addr, port, NULL, SOCKET_TYPE_DATAGRAM);
|
||||
@ -202,6 +220,9 @@ static bool init_socket(netplay_t *netplay, const char *server, uint16_t port)
|
||||
if (!init_tcp_socket(netplay, server, port, netplay->spectate.enabled))
|
||||
return false;
|
||||
|
||||
if (netplay->is_server && netplay->nat_traversal)
|
||||
init_nat_traversal(netplay);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1047,6 +1068,36 @@ void netplay_log_connection(const struct sockaddr_storage *their_addr,
|
||||
|
||||
#endif
|
||||
|
||||
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, 0) != 0)
|
||||
return;
|
||||
|
||||
}
|
||||
#ifdef AF_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, 0) != 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);
|
||||
}
|
||||
|
||||
|
||||
bool netplay_try_init_serialization(netplay_t *netplay)
|
||||
@ -1166,6 +1217,7 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames)
|
||||
* @check_frames : Frequency with which to check CRCs.
|
||||
* @cb : Libretro callbacks.
|
||||
* @spectate : If true, enable spectator mode.
|
||||
* @nat_traversal : If true, attempt NAT traversal.
|
||||
* @nick : Nickname of user.
|
||||
* @quirks : Netplay quirks required for this session.
|
||||
*
|
||||
@ -1174,10 +1226,9 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames)
|
||||
*
|
||||
* Returns: new netplay handle.
|
||||
**/
|
||||
netplay_t *netplay_new(const char *server, uint16_t port,
|
||||
unsigned frames, unsigned check_frames,
|
||||
const struct retro_callbacks *cb,
|
||||
bool spectate, const char *nick, uint64_t quirks)
|
||||
netplay_t *netplay_new(const char *server, uint16_t port, unsigned frames,
|
||||
unsigned check_frames, const struct retro_callbacks *cb, bool spectate,
|
||||
bool nat_traversal, const char *nick, uint64_t quirks)
|
||||
{
|
||||
netplay_t *netplay = (netplay_t*)calloc(1, sizeof(*netplay));
|
||||
if (!netplay)
|
||||
@ -1189,6 +1240,7 @@ netplay_t *netplay_new(const char *server, uint16_t port,
|
||||
netplay->port = server ? 0 : 1;
|
||||
netplay->spectate.enabled = spectate;
|
||||
netplay->is_server = server == NULL;
|
||||
netplay->nat_traversal = netplay->is_server ? nat_traversal : false;
|
||||
netplay->stall_frames = frames;
|
||||
netplay->check_frames = check_frames;
|
||||
netplay->quirks = quirks;
|
||||
@ -1324,6 +1376,9 @@ void netplay_free(netplay_t *netplay)
|
||||
free(netplay->spectate.input);
|
||||
}
|
||||
|
||||
if (netplay->nat_traversal)
|
||||
natt_free(&netplay->nat_traversal_state);
|
||||
|
||||
if (netplay->buffer)
|
||||
{
|
||||
for (i = 0; i < netplay->buffer_size; i++)
|
||||
@ -1369,11 +1424,26 @@ bool netplay_pre_frame(netplay_t *netplay)
|
||||
netplay_try_init_serialization(netplay);
|
||||
}
|
||||
|
||||
/* Advertise our server if applicable */
|
||||
if (netplay->is_server)
|
||||
{
|
||||
/* Advertise our server if applicable */
|
||||
if (netplay_ad_fd >= 0 || init_ad_socket(netplay, RARCH_DEFAULT_PORT))
|
||||
netplay_ad_server(netplay, netplay_ad_fd);
|
||||
|
||||
/* NAT traversal if applicable */
|
||||
if (netplay->nat_traversal &&
|
||||
netplay->nat_traversal_state.request_outstanding &&
|
||||
!netplay->nat_traversal_state.have_inet4)
|
||||
{
|
||||
struct timeval tmptv = {0};
|
||||
fd_set fds = netplay->nat_traversal_state.fds;
|
||||
if (socket_select(netplay->nat_traversal_state.nfds, &fds, NULL, NULL, &tmptv) > 0)
|
||||
natt_read(&netplay->nat_traversal_state);
|
||||
|
||||
if (!netplay->nat_traversal_state.request_outstanding ||
|
||||
netplay->nat_traversal_state.have_inet4)
|
||||
announce_nat_traversal(netplay);
|
||||
}
|
||||
}
|
||||
|
||||
if (!netplay->net_cbs->pre_frame(netplay))
|
||||
@ -1599,7 +1669,8 @@ bool init_netplay(bool is_spectate, const char *server, unsigned port)
|
||||
netplay_is_client ? server : NULL,
|
||||
port ? port : RARCH_DEFAULT_PORT,
|
||||
settings->netplay.sync_frames, settings->netplay.check_frames, &cbs,
|
||||
is_spectate, settings->username, quirks);
|
||||
is_spectate, settings->netplay.nat_traversal, settings->username,
|
||||
quirks);
|
||||
|
||||
if (netplay_data)
|
||||
return true;
|
||||
|
@ -137,6 +137,7 @@ size_t audio_sample_batch_net(const int16_t *data, size_t frames);
|
||||
* @check_frames : Frequency with which to check CRCs.
|
||||
* @cb : Libretro callbacks.
|
||||
* @spectate : If true, enable spectator mode.
|
||||
* @nat_traversal : If true, attempt NAT traversal.
|
||||
* @nick : Nickname of user.
|
||||
* @quirks : Netplay quirks.
|
||||
*
|
||||
@ -147,7 +148,7 @@ size_t audio_sample_batch_net(const int16_t *data, size_t frames);
|
||||
**/
|
||||
netplay_t *netplay_new(const char *server,
|
||||
uint16_t port, unsigned frames, unsigned check_frames,
|
||||
const struct retro_callbacks *cb, bool spectate,
|
||||
const struct retro_callbacks *cb, bool spectate, bool nat_traversal,
|
||||
const char *nick, uint64_t quirks);
|
||||
|
||||
/**
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <net/net_compat.h>
|
||||
#include <net/net_socket.h>
|
||||
#include <net/net_natt.h>
|
||||
|
||||
#include "netplay_private.h"
|
||||
|
||||
@ -337,6 +338,19 @@ static bool netplay_net_info_cb(netplay_t* netplay, unsigned frames)
|
||||
netplay->has_connection = true;
|
||||
}
|
||||
|
||||
{
|
||||
struct natt_status status;
|
||||
natt_init();
|
||||
if (natt_new(&status) && natt_open_port_any(&status, netplay->tcp_port, SOCKET_PROTOCOL_TCP))
|
||||
{
|
||||
fprintf(stderr, "Forwarded to %d!\n", status.ext_inet4_addr.sin_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Forwarding failed :(\n");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "netplay.h"
|
||||
|
||||
#include <net/net_compat.h>
|
||||
#include <net/net_natt.h>
|
||||
#include <features/features_cpu.h>
|
||||
#include <streams/trans_stream.h>
|
||||
#include <retro_endianness.h>
|
||||
@ -124,6 +125,9 @@ struct netplay
|
||||
int fd;
|
||||
/* TCP port (if serving) */
|
||||
uint16_t tcp_port;
|
||||
/* NAT traversal info (if NAT traversal is used and serving) */
|
||||
bool nat_traversal;
|
||||
struct natt_status nat_traversal_state;
|
||||
/* Which port is governed by netplay (other user)? */
|
||||
unsigned port;
|
||||
bool has_connection;
|
||||
|
Loading…
x
Reference in New Issue
Block a user