mirror of
https://github.com/CTCaer/RetroArch.git
synced 2025-02-21 03:50:28 +00:00
commit
bb499b70be
@ -1086,6 +1086,7 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/net/net_compat.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_http.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_socket.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_natt.o \
|
||||
network/net_http_special.o \
|
||||
tasks/task_http.o
|
||||
|
||||
@ -1123,6 +1124,10 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
OBJ += input/input_remote.o \
|
||||
cores/libretro-net-retropad/net_retropad_core.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_MINIUPNPC), 1)
|
||||
LIBS += -lminiupnpc
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(findstring Win32,$(OS)),)
|
||||
|
@ -800,6 +800,7 @@ static int populate_settings_bool(settings_t *settings, struct config_bool_setti
|
||||
#endif
|
||||
#ifdef HAVE_NETWORKING
|
||||
SETTING_BOOL("netplay_spectator_mode_enable",&settings->netplay.is_spectate, false, false /* TODO */, false);
|
||||
SETTING_BOOL("netplay_nat_traversal", &settings->netplay.nat_traversal, true, true, false);
|
||||
#endif
|
||||
SETTING_BOOL("block_sram_overwrite", &settings->block_sram_overwrite, true, block_sram_overwrite, false);
|
||||
SETTING_BOOL("savestate_auto_index", &settings->savestate_auto_index, true, savestate_auto_index, false);
|
||||
@ -922,7 +923,7 @@ static int populate_settings_int(settings_t *settings, struct config_int_setting
|
||||
#ifdef HAVE_NETWORKING
|
||||
SETTING_INT("netplay_ip_port", &settings->netplay.port, false, 0 /* TODO */, false);
|
||||
SETTING_INT("netplay_delay_frames", &settings->netplay.sync_frames, true, 16, false);
|
||||
SETTING_INT("netplay_check_frames", &settings->netplay.check_frames, false, 30, false);
|
||||
SETTING_INT("netplay_check_frames", &settings->netplay.check_frames, true, 30, false);
|
||||
#endif
|
||||
#ifdef HAVE_LANGEXTRA
|
||||
SETTING_INT("user_language", &settings->user_language, true, RETRO_LANGUAGE_ENGLISH, false);
|
||||
|
@ -403,6 +403,7 @@ typedef struct settings
|
||||
unsigned check_frames;
|
||||
bool is_spectate;
|
||||
bool swap_input;
|
||||
bool nat_traversal;
|
||||
} netplay;
|
||||
#endif
|
||||
|
||||
|
@ -879,6 +879,7 @@ NETPLAY
|
||||
#include "../libretro-common/net/net_compat.c"
|
||||
#include "../libretro-common/net/net_socket.c"
|
||||
#include "../libretro-common/net/net_http.c"
|
||||
#include "../libretro-common/net/net_natt.c"
|
||||
#ifndef HAVE_SOCKET_LEGACY
|
||||
#include "../libretro-common/net/net_ifinfo.c"
|
||||
#endif
|
||||
|
@ -1558,6 +1558,12 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len)
|
||||
"no checks. This value is only used on the \n"
|
||||
"netplay host. \n");
|
||||
break;
|
||||
case MENU_ENUM_LABEL_NETPLAY_NAT_TRAVERSAL:
|
||||
snprintf(s, len,
|
||||
"When hosting, attempt to listen for\n"
|
||||
"connections from the public internet, using\n"
|
||||
"UPnP or similar technologies to escape LANs. \n");
|
||||
break;
|
||||
case MENU_ENUM_LABEL_VIDEO_MAX_SWAPCHAIN_IMAGES:
|
||||
snprintf(s, len,
|
||||
"Maximum amount of swapchain images. This \n"
|
||||
|
@ -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..."
|
||||
@ -922,6 +926,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE,
|
||||
"Netplay Spectator Enable")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT,
|
||||
"Netplay TCP/UDP Port")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL,
|
||||
"Netplay NAT Traversal")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE,
|
||||
"Network Commands")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT,
|
||||
|
83
libretro-common/include/net/net_natt.h
Normal file
83
libretro-common/include/net/net_natt.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* Copyright (C) 2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (net_natt.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_SDK_NET_NATT_H
|
||||
#define _LIBRETRO_SDK_NET_NATT_H
|
||||
|
||||
#include <net/net_compat.h>
|
||||
#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;
|
||||
|
||||
/** External IPv4 address */
|
||||
struct sockaddr_in ext_inet4_addr;
|
||||
|
||||
/** True if we've resolved an external IPv6 address */
|
||||
bool have_inet6;
|
||||
|
||||
#ifdef AF_INET6
|
||||
/** External IPv6 address */
|
||||
struct sockaddr_in6 ext_inet6_addr;
|
||||
#endif
|
||||
|
||||
/** Internal status (currently unused) */
|
||||
void *internal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize global NAT traversal structures (must be called once to use other
|
||||
* functions) */
|
||||
void natt_init(void);
|
||||
|
||||
/** Initialize a NAT traversal status object */
|
||||
bool natt_new(struct natt_status *status);
|
||||
|
||||
/** Free a NAT traversal status object */
|
||||
void natt_free(struct natt_status *status);
|
||||
|
||||
/**
|
||||
* Make a port forwarding request. This may finish immediately or just send a
|
||||
* request to the network. */
|
||||
bool natt_open_port(struct natt_status *status, struct sockaddr *addr,
|
||||
socklen_t addrlen, enum socket_protocol proto);
|
||||
|
||||
/**
|
||||
* Make a port forwarding request when only the port is known. Forwards any
|
||||
* address it can find. */
|
||||
bool natt_open_port_any(struct natt_status *status, uint16_t port,
|
||||
enum socket_protocol proto);
|
||||
|
||||
/** Check for port forwarding responses */
|
||||
bool natt_read(struct natt_status *status);
|
||||
|
||||
#endif
|
221
libretro-common/net/net_natt.c
Normal file
221
libretro-common/net/net_natt.c
Normal file
@ -0,0 +1,221 @@
|
||||
/* Copyright (C) 2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (net_natt.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <net/net_compat.h>
|
||||
#include <net/net_ifinfo.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
#include <net/net_natt.h>
|
||||
|
||||
#if HAVE_MINIUPNPC
|
||||
#include <miniupnpc/miniwget.h>
|
||||
#include <miniupnpc/miniupnpc.h>
|
||||
#include <miniupnpc/upnpcommands.h>
|
||||
|
||||
static struct UPNPUrls urls;
|
||||
static struct IGDdatas data;
|
||||
#endif
|
||||
|
||||
void natt_init(void)
|
||||
{
|
||||
#if HAVE_MINIUPNPC
|
||||
struct UPNPDev * devlist;
|
||||
struct UPNPDev * dev;
|
||||
char * descXML;
|
||||
int descXMLsize = 0;
|
||||
int upnperror = 0;
|
||||
memset(&urls, 0, sizeof(struct UPNPUrls));
|
||||
memset(&data, 0, sizeof(struct IGDdatas));
|
||||
devlist = upnpDiscover(2000, NULL, NULL, 0, 0, &upnperror);
|
||||
if (devlist)
|
||||
{
|
||||
dev = devlist;
|
||||
while (dev)
|
||||
{
|
||||
if (strstr (dev->st, "InternetGatewayDevice"))
|
||||
break;
|
||||
dev = dev->pNext;
|
||||
}
|
||||
if (!dev)
|
||||
dev = devlist;
|
||||
|
||||
descXML = (char *) miniwget(dev->descURL, &descXMLsize, 0);
|
||||
if (descXML)
|
||||
{
|
||||
parserootdesc (descXML, descXMLsize, &data);
|
||||
free (descXML); descXML = 0;
|
||||
GetUPNPUrls (&urls, &data, dev->descURL, 0);
|
||||
}
|
||||
freeUPNPDevlist(devlist);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool natt_new(struct natt_status *status)
|
||||
{
|
||||
memset(status, 0, sizeof(struct natt_status));
|
||||
return true;
|
||||
}
|
||||
|
||||
void natt_free(struct natt_status *status)
|
||||
{
|
||||
/* Nothing */
|
||||
}
|
||||
|
||||
bool natt_open_port(struct natt_status *status, struct sockaddr *addr, socklen_t addrlen, enum socket_protocol proto)
|
||||
{
|
||||
#if HAVE_MINIUPNPC
|
||||
char host[PATH_MAX_LENGTH], ext_host[PATH_MAX_LENGTH],
|
||||
port_str[6], ext_port_str[6];
|
||||
const char *proto_str;
|
||||
struct addrinfo hints = {0}, *ext_addrinfo;
|
||||
int r;
|
||||
|
||||
/* if NAT traversal is uninitialized or unavailable, oh well */
|
||||
if (!urls.controlURL[0])
|
||||
return false;
|
||||
|
||||
/* figure out the internal info */
|
||||
if (getnameinfo(addr, addrlen, host, PATH_MAX_LENGTH, port_str, 6, NI_NUMERICHOST|NI_NUMERICSERV) != 0)
|
||||
return false;
|
||||
proto_str = (proto == SOCKET_PROTOCOL_UDP) ? "UDP" : "TCP";
|
||||
|
||||
/* add the port mapping */
|
||||
r = UPNP_AddAnyPortMapping(urls.controlURL, data.first.servicetype, port_str,
|
||||
port_str, host, "retroarch", proto_str, NULL, "3600", ext_port_str);
|
||||
if (r == 501 /* Action Failed */)
|
||||
{
|
||||
/* try the older AddPortMapping */
|
||||
memcpy(ext_port_str, port_str, 6);
|
||||
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port_str,
|
||||
port_str, host, "retroarch", proto_str, NULL, "3600");
|
||||
}
|
||||
if (r != 0)
|
||||
return false;
|
||||
|
||||
/* get the external IP */
|
||||
r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, ext_host);
|
||||
if (r != 0)
|
||||
return false;
|
||||
|
||||
/* update the status */
|
||||
if (getaddrinfo_retro(ext_host, ext_port_str, &hints, &ext_addrinfo) != 0)
|
||||
return false;
|
||||
|
||||
if (ext_addrinfo->ai_family == AF_INET &&
|
||||
ext_addrinfo->ai_addrlen >= sizeof(struct sockaddr_in))
|
||||
{
|
||||
status->have_inet4 = true;
|
||||
status->ext_inet4_addr = *((struct sockaddr_in *) ext_addrinfo->ai_addr);
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
else if (ext_addrinfo->ai_family == AF_INET6 &&
|
||||
ext_addrinfo->ai_addrlen >= sizeof(struct sockaddr_in6))
|
||||
{
|
||||
status->have_inet6 = true;
|
||||
status->ext_inet6_addr = *((struct sockaddr_in6 *) ext_addrinfo->ai_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
freeaddrinfo_retro(ext_addrinfo);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool natt_open_port_any(struct natt_status *status, uint16_t port, enum socket_protocol proto)
|
||||
{
|
||||
struct net_ifinfo *list;
|
||||
bool ret = false;
|
||||
size_t i;
|
||||
struct addrinfo hints = {0}, *addr;
|
||||
char port_str[6];
|
||||
|
||||
sprintf(port_str, "%hu", port);
|
||||
|
||||
/* get our interfaces */
|
||||
if ((list = (struct net_ifinfo *) calloc(1, sizeof(struct net_ifinfo))) == NULL)
|
||||
return false;
|
||||
if (!net_ifinfo_new(list))
|
||||
{
|
||||
free(list);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* loop through them */
|
||||
for (i = 0; i < list->size; i++)
|
||||
{
|
||||
struct net_ifinfo_entry *entry = list->entries + i;
|
||||
|
||||
/* ignore localhost */
|
||||
if (!strcmp(entry->host, "127.0.0.1") || !strcmp(entry->host, "::1"))
|
||||
continue;
|
||||
|
||||
/* make a request for this host */
|
||||
if (getaddrinfo_retro(entry->host, port_str, &hints, &addr) == 0)
|
||||
{
|
||||
ret = natt_open_port(status, addr->ai_addr, addr->ai_addrlen, proto) || ret;
|
||||
freeaddrinfo_retro(addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* This really shouldn't free list, but does */
|
||||
net_ifinfo_free(list);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool natt_read(struct natt_status *status)
|
||||
{
|
||||
/* MiniUPNPC is always synchronous, so there's nothing to read here.
|
||||
* Reserved for future backends. */
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* If we want to remove redirects in the future, this is a sample of how to do
|
||||
* that */
|
||||
void upnp_rem_redir (int port)
|
||||
{
|
||||
char port_str[16];
|
||||
int t;
|
||||
printf("TB : upnp_rem_redir (%d)\n", port);
|
||||
if(urls.controlURL[0] == '\0')
|
||||
{
|
||||
printf("TB : the init was not done !\n");
|
||||
return;
|
||||
}
|
||||
sprintf(port_str, "%d", port);
|
||||
UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port_str, "TCP", NULL);
|
||||
}
|
||||
#endif
|
@ -4942,6 +4942,10 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data)
|
||||
MENU_ENUM_LABEL_NETPLAY_CLIENT_SWAP_INPUT,
|
||||
PARSE_ONLY_BOOL, false) != -1)
|
||||
count++;
|
||||
if (menu_displaylist_parse_settings_enum(menu, info,
|
||||
MENU_ENUM_LABEL_NETPLAY_NAT_TRAVERSAL,
|
||||
PARSE_ONLY_BOOL, false) != -1)
|
||||
count++;
|
||||
if (menu_displaylist_parse_settings_enum(menu, info,
|
||||
MENU_ENUM_LABEL_NETWORK_CMD_ENABLE,
|
||||
PARSE_ONLY_BOOL, false) != -1)
|
||||
|
@ -5589,6 +5589,21 @@ static bool setting_append_list(
|
||||
general_read_handler,
|
||||
SD_FLAG_NONE);
|
||||
|
||||
CONFIG_BOOL(
|
||||
list, list_info,
|
||||
&settings->netplay.is_spectate,
|
||||
MENU_ENUM_LABEL_NETPLAY_NAT_TRAVERSAL,
|
||||
MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL,
|
||||
false,
|
||||
MENU_ENUM_LABEL_VALUE_OFF,
|
||||
MENU_ENUM_LABEL_VALUE_ON,
|
||||
&group_info,
|
||||
&subgroup_info,
|
||||
parent_group,
|
||||
general_write_handler,
|
||||
general_read_handler,
|
||||
SD_FLAG_NONE);
|
||||
|
||||
CONFIG_BOOL(
|
||||
list, list_info,
|
||||
&settings->netplay.swap_input,
|
||||
|
@ -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,
|
||||
@ -975,6 +976,7 @@ enum msg_hash_enums
|
||||
MENU_LABEL(NETPLAY_CHECK_FRAMES),
|
||||
MENU_LABEL(NETPLAY_SPECTATOR_MODE_ENABLE),
|
||||
MENU_LABEL(NETPLAY_TCP_UDP_PORT),
|
||||
MENU_LABEL(NETPLAY_NAT_TRAVERSAL),
|
||||
MENU_LABEL(SORT_SAVEFILES_ENABLE),
|
||||
MENU_LABEL(SORT_SAVESTATES_ENABLE),
|
||||
MENU_LABEL(NETPLAY_IP_ADDRESS),
|
||||
|
@ -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)
|
||||
@ -186,6 +188,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);
|
||||
@ -216,6 +234,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;
|
||||
}
|
||||
|
||||
@ -1061,6 +1082,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, NI_NUMERICHOST|NI_NUMERICSERV) != 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, 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);
|
||||
}
|
||||
|
||||
|
||||
bool netplay_try_init_serialization(netplay_t *netplay)
|
||||
@ -1180,6 +1231,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.
|
||||
*
|
||||
@ -1188,10 +1240,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)
|
||||
@ -1203,6 +1254,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;
|
||||
@ -1338,6 +1390,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++)
|
||||
@ -1383,11 +1438,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))
|
||||
@ -1613,7 +1683,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;
|
||||
|
@ -182,6 +182,10 @@ if [ "$HAVE_NETWORKING" = 'yes' ]; then
|
||||
fi
|
||||
HAVE_NETWORK_CMD=yes
|
||||
HAVE_NETWORKGAMEPAD=yes
|
||||
|
||||
if [ "$HAVE_MINIUPNPC" != "no" ]; then
|
||||
check_lib MINIUPNPC "-lminiupnpc"
|
||||
fi
|
||||
else
|
||||
echo "Warning: All networking features have been disabled."
|
||||
HAVE_NETWORK_CMD='no'
|
||||
|
@ -28,6 +28,7 @@ HAVE_DYLIB=auto # Dynamic loading support
|
||||
HAVE_NETWORKING=auto # Networking features (recommended)
|
||||
HAVE_NETWORKGAMEPAD=auto # Networked game pad (plus baked-in core)
|
||||
C89_NETWORKGAMEPAD=no
|
||||
HAVE_MINIUPNPC=auto # Mini UPnP client library (for NAT traversal)
|
||||
HAVE_D3D9=yes # Direct3D 9 support
|
||||
HAVE_OPENGL=auto # OpenGL support
|
||||
HAVE_MALI_FBDEV=no # Mali fbdev context support
|
||||
|
Loading…
x
Reference in New Issue
Block a user