mirror of
https://github.com/CTCaer/RetroArch.git
synced 2025-01-30 08:02:22 +00:00
Merge branch 'master' of ssh://github.com/terry1994/RetroArch
This commit is contained in:
commit
86c7afdd7c
@ -1086,8 +1086,10 @@ 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
|
||||
tasks/task_http.o \
|
||||
tasks/task_wifi.o
|
||||
|
||||
ifneq ($(HAVE_SOCKET_LEGACY),1)
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/net/net_ifinfo.o
|
||||
@ -1123,6 +1125,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)),)
|
||||
|
@ -437,7 +437,7 @@ static const bool load_dummy_on_core_shutdown = false;
|
||||
#else
|
||||
static const bool load_dummy_on_core_shutdown = true;
|
||||
#endif
|
||||
static const bool check_firmware_before_loading = true;
|
||||
static const bool check_firmware_before_loading = false;
|
||||
/* Forcibly disable composition.
|
||||
* Only valid on Windows Vista/7/8 for now. */
|
||||
static const bool disable_composition = false;
|
||||
|
@ -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,10 +879,12 @@ 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
|
||||
#include "../tasks/task_http.c"
|
||||
#include "../tasks/task_wifi.c"
|
||||
#endif
|
||||
|
||||
/*============================================================
|
||||
|
@ -160,15 +160,13 @@ static void udev_poll_pad(struct udev_joypad *pad, unsigned p)
|
||||
}
|
||||
}
|
||||
|
||||
static bool udev_hotplug_available(void)
|
||||
static INLINE bool udev_hotplug_available(void)
|
||||
{
|
||||
struct pollfd fds = {0};
|
||||
struct pollfd fds;
|
||||
|
||||
if (!g_udev_mon)
|
||||
return false;
|
||||
|
||||
fds.fd = udev_monitor_get_fd(g_udev_mon);
|
||||
fds.events = POLLIN;
|
||||
fds.fd = udev_monitor_get_fd(g_udev_mon);
|
||||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
|
||||
return (poll(&fds, 1, 0) == 1) && (fds.revents & POLLIN);
|
||||
}
|
||||
@ -420,18 +418,11 @@ static void udev_joypad_destroy(void)
|
||||
g_udev = NULL;
|
||||
}
|
||||
|
||||
static void udev_joypad_handle_hotplug(void)
|
||||
static void udev_joypad_handle_hotplug(struct udev_device *dev)
|
||||
{
|
||||
struct udev_device *dev = udev_monitor_receive_device(g_udev_mon);
|
||||
const char *val;
|
||||
const char *action;
|
||||
const char *devnode;
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
val = udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
|
||||
action = udev_device_get_action(dev);
|
||||
devnode = udev_device_get_devnode(dev);
|
||||
const char *val = udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
|
||||
const char *action = udev_device_get_action(dev);
|
||||
const char *devnode = udev_device_get_devnode(dev);
|
||||
|
||||
if (!val || !string_is_equal(val, "1") || !devnode)
|
||||
goto end;
|
||||
@ -523,8 +514,13 @@ static bool udev_set_rumble(unsigned i, enum retro_rumble_effect effect, uint16_
|
||||
static void udev_joypad_poll(void)
|
||||
{
|
||||
unsigned i;
|
||||
while (udev_hotplug_available())
|
||||
udev_joypad_handle_hotplug();
|
||||
|
||||
while (g_udev_mon && udev_hotplug_available())
|
||||
{
|
||||
struct udev_device *dev = udev_monitor_receive_device(g_udev_mon);
|
||||
if (dev)
|
||||
udev_joypad_handle_hotplug(dev);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
udev_poll_pad(&udev_pads[i], i);
|
||||
|
@ -322,19 +322,6 @@ error:
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct retro_keybind *input_get_auto_bind(unsigned port, unsigned id)
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
unsigned joy_idx = 0;
|
||||
|
||||
if (settings)
|
||||
joy_idx = settings->input.joypad_map[port];
|
||||
|
||||
if (joy_idx < MAX_USERS)
|
||||
return &settings->input.autoconf_binds[joy_idx][id];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void input_config_autoconfigure_disconnect(unsigned i, const char *ident)
|
||||
{
|
||||
char msg[255];
|
||||
|
@ -32,9 +32,6 @@ typedef struct autoconfig_params
|
||||
int32_t pid;
|
||||
} autoconfig_params_t;
|
||||
|
||||
const struct retro_keybind *input_get_auto_bind(unsigned port,
|
||||
unsigned id);
|
||||
|
||||
bool input_config_autoconfigure_joypad(autoconfig_params_t *params);
|
||||
|
||||
void input_config_autoconfigure_disconnect(unsigned i, const char *ident);
|
||||
|
@ -470,3 +470,16 @@ void input_config_get_bind_string(char *buf, const struct retro_keybind *bind,
|
||||
strlcat(buf, keybuf, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct retro_keybind *input_config_get_bind_auto(unsigned port, unsigned id)
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
unsigned joy_idx = 0;
|
||||
|
||||
if (settings)
|
||||
joy_idx = settings->input.joypad_map[port];
|
||||
|
||||
if (joy_idx < MAX_USERS)
|
||||
return &settings->input.autoconf_binds[joy_idx][id];
|
||||
return NULL;
|
||||
}
|
||||
|
@ -69,4 +69,6 @@ void input_config_parse_joy_button(config_file_t *conf, const char *prefix,
|
||||
void input_config_parse_joy_axis(config_file_t *conf, const char *prefix,
|
||||
const char *axis, struct retro_keybind *bind);
|
||||
|
||||
const struct retro_keybind *input_config_get_bind_auto(unsigned port, unsigned id);
|
||||
|
||||
#endif
|
||||
|
@ -524,31 +524,29 @@ int16_t input_state(unsigned port, unsigned device,
|
||||
|
||||
/**
|
||||
* check_input_driver_block_hotkey:
|
||||
* @enable_hotkey : Is hotkey enable key enabled?
|
||||
*
|
||||
* Checks if 'hotkey enable' key is pressed.
|
||||
**/
|
||||
static bool check_input_driver_block_hotkey(bool enable_hotkey)
|
||||
static bool check_input_driver_block_hotkey(void)
|
||||
{
|
||||
bool use_hotkey_enable = false;
|
||||
settings_t *settings = config_get_ptr();
|
||||
const struct retro_keybind *bind =
|
||||
&settings->input.binds[0][RARCH_ENABLE_HOTKEY];
|
||||
const struct retro_keybind *autoconf_bind =
|
||||
&settings->input.autoconf_binds[0][RARCH_ENABLE_HOTKEY];
|
||||
bool kb_mapping_is_blocked = current_input->keyboard_mapping_is_blocked &&
|
||||
current_input->keyboard_mapping_is_blocked(current_input_data);
|
||||
|
||||
/* Don't block the check to RARCH_ENABLE_HOTKEY
|
||||
* unless we're really supposed to. */
|
||||
if (kb_mapping_is_blocked)
|
||||
if (current_input->keyboard_mapping_is_blocked &&
|
||||
current_input->keyboard_mapping_is_blocked(current_input_data))
|
||||
input_driver_block_hotkey = true;
|
||||
else
|
||||
input_driver_block_hotkey = false;
|
||||
|
||||
/* If we haven't bound anything to this,
|
||||
* always allow hotkeys. */
|
||||
use_hotkey_enable =
|
||||
|
||||
/* If we hold ENABLE_HOTKEY button, block all libretro input to allow
|
||||
* hotkeys to be bound to same keys as RetroPad. */
|
||||
return
|
||||
(bind->key != RETROK_UNKNOWN)
|
||||
|| (bind->joykey != NO_BTN)
|
||||
|| (bind->joyaxis != AXIS_NONE)
|
||||
@ -556,14 +554,6 @@ static bool check_input_driver_block_hotkey(bool enable_hotkey)
|
||||
|| (autoconf_bind->joykey != NO_BTN)
|
||||
|| (autoconf_bind->joyaxis != AXIS_NONE);
|
||||
|
||||
if (kb_mapping_is_blocked || (use_hotkey_enable && !enable_hotkey))
|
||||
input_driver_block_hotkey = true;
|
||||
else
|
||||
input_driver_block_hotkey = false;
|
||||
|
||||
/* If we hold ENABLE_HOTKEY button, block all libretro input to allow
|
||||
* hotkeys to be bound to same keys as RetroPad. */
|
||||
return (use_hotkey_enable && enable_hotkey);
|
||||
}
|
||||
|
||||
static const unsigned buttons[] = {
|
||||
@ -680,17 +670,21 @@ static INLINE bool input_keys_pressed_internal(unsigned i,
|
||||
uint64_t input_keys_pressed(void)
|
||||
{
|
||||
unsigned i;
|
||||
uint64_t ret = 0;
|
||||
settings_t *settings = config_get_ptr();
|
||||
uint64_t ret = 0;
|
||||
settings_t *settings = config_get_ptr();
|
||||
const struct retro_keybind *binds = settings->input.binds[0];
|
||||
|
||||
if (
|
||||
check_input_driver_block_hotkey(
|
||||
current_input->input_state(current_input_data, &binds, 0,
|
||||
RETRO_DEVICE_JOYPAD, 0, RARCH_ENABLE_HOTKEY)))
|
||||
input_driver_block_libretro_input = true;
|
||||
else
|
||||
input_driver_block_libretro_input = false;
|
||||
input_driver_block_libretro_input = false;
|
||||
input_driver_block_hotkey = false;
|
||||
|
||||
if (check_input_driver_block_hotkey())
|
||||
{
|
||||
if (current_input->input_state(current_input_data, &binds, 0,
|
||||
RETRO_DEVICE_JOYPAD, 0, RARCH_ENABLE_HOTKEY))
|
||||
input_driver_block_libretro_input = true;
|
||||
else
|
||||
input_driver_block_hotkey = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < RARCH_BIND_LIST_END; i++)
|
||||
{
|
||||
@ -797,14 +791,17 @@ uint64_t input_menu_keys_pressed(void)
|
||||
input_push_analog_dpad(settings->input.autoconf_binds[i],
|
||||
ANALOG_DPAD_LSTICK);
|
||||
|
||||
if (
|
||||
check_input_driver_block_hotkey(
|
||||
current_input->input_state(current_input_data, &binds[0], 0,
|
||||
RETRO_DEVICE_JOYPAD, 0, RARCH_ENABLE_HOTKEY)))
|
||||
input_driver_block_libretro_input = true;
|
||||
else
|
||||
input_driver_block_libretro_input = false;
|
||||
input_driver_block_libretro_input = false;
|
||||
input_driver_block_hotkey = false;
|
||||
|
||||
if (check_input_driver_block_hotkey())
|
||||
{
|
||||
if (current_input->input_state(current_input_data, &binds[0], 0,
|
||||
RETRO_DEVICE_JOYPAD, 0, RARCH_ENABLE_HOTKEY))
|
||||
input_driver_block_libretro_input = true;
|
||||
else
|
||||
input_driver_block_hotkey = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < RARCH_BIND_LIST_END; i++)
|
||||
{
|
||||
|
@ -624,6 +624,8 @@ MSG_HASH(MENU_ENUM_LABEL_NO_HISTORY_AVAILABLE,
|
||||
"no_history")
|
||||
MSG_HASH(MENU_ENUM_LABEL_NO_ITEMS,
|
||||
"no_items")
|
||||
MSG_HASH(MENU_ENUM_LABEL_NO_NETWORKS_FOUND,
|
||||
"no_networks_found")
|
||||
MSG_HASH(MENU_ENUM_LABEL_NO_PERFORMANCE_COUNTERS,
|
||||
"no_performance_counters")
|
||||
MSG_HASH(MENU_ENUM_LABEL_NO_PLAYLISTS,
|
||||
|
@ -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,
|
||||
@ -958,6 +964,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE,
|
||||
"No information is available.")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ITEMS,
|
||||
"No items.")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND,
|
||||
"No networks found.")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS,
|
||||
"No performance counters.")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS,
|
||||
@ -2233,3 +2241,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING,
|
||||
"Database - Filter : Edge Magazine Rating")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO,
|
||||
"Database Info")
|
||||
MSG_HASH(MSG_WIFI_SCAN_COMPLETE,
|
||||
"Wi-Fi scan complete.")
|
||||
MSG_HASH(MSG_SCANNING_WIRELESS_NETWORKS,
|
||||
"Scanning wireless networks...")
|
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
|
@ -65,7 +65,6 @@ void net_ifinfo_free(net_ifinfo_t *list)
|
||||
ptr->host = NULL;
|
||||
}
|
||||
free(list->entries);
|
||||
free(list);
|
||||
}
|
||||
|
||||
bool net_ifinfo_new(net_ifinfo_t *list)
|
||||
@ -82,6 +81,8 @@ bool net_ifinfo_new(net_ifinfo_t *list)
|
||||
|
||||
rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, adapter_addresses, &size);
|
||||
|
||||
memset(list, 0, sizeof(net_ifinfo_t));
|
||||
|
||||
if (rv != ERROR_SUCCESS)
|
||||
goto error;
|
||||
|
||||
@ -122,6 +123,8 @@ bool net_ifinfo_new(net_ifinfo_t *list)
|
||||
struct ifaddrs *ifa = NULL;
|
||||
struct ifaddrs *ifaddr = NULL;
|
||||
|
||||
memset(list, 0, sizeof(net_ifinfo_t));
|
||||
|
||||
if (getifaddrs(&ifaddr) == -1)
|
||||
goto error;
|
||||
|
||||
|
223
libretro-common/net/net_natt.c
Normal file
223
libretro-common/net/net_natt.c
Normal file
@ -0,0 +1,223 @@
|
||||
/* 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));
|
||||
#if MINIUPNPC_API_VERSION < 16
|
||||
devlist = upnpDiscover(2000, NULL, NULL, 0, 0, &upnperror);
|
||||
#else
|
||||
devlist = upnpDiscover(2000, NULL, NULL, 0, 0, 2, &upnperror);
|
||||
#endif
|
||||
if (devlist)
|
||||
{
|
||||
dev = devlist;
|
||||
while (dev)
|
||||
{
|
||||
if (strstr (dev->st, "InternetGatewayDevice"))
|
||||
break;
|
||||
dev = dev->pNext;
|
||||
}
|
||||
if (!dev)
|
||||
dev = devlist;
|
||||
|
||||
#if MINIUPNPC_API_VERSION < 16
|
||||
descXML = (char *) miniwget(dev->descURL, &descXMLsize, 0);
|
||||
#else
|
||||
descXML = (char *) miniwget(dev->descURL, &descXMLsize, 0, NULL);
|
||||
#endif
|
||||
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 (!net_ifinfo_new(&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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
@ -29,21 +29,17 @@
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
unsigned k = 0;
|
||||
net_ifinfo_t *list =
|
||||
(net_ifinfo_t*)calloc(1, sizeof(*list));
|
||||
net_ifinfo_t list;
|
||||
|
||||
if (!list)
|
||||
if (!net_ifinfo_new(&list))
|
||||
return -1;
|
||||
|
||||
if (!net_ifinfo_new(list))
|
||||
return -1;
|
||||
|
||||
for (k = 0; k < list->size; k++)
|
||||
for (k = 0; k < list.size; k++)
|
||||
{
|
||||
printf("%s:%s\n", list->entries[k].name, list->entries[k].host);
|
||||
printf("%s:%s\n", list.entries[k].name, list.entries[k].host);
|
||||
}
|
||||
|
||||
net_ifinfo_free(list);
|
||||
net_ifinfo_free(&list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -475,7 +475,7 @@ static void menu_action_setting_disp_set_label_input_desc(
|
||||
keybind = (const struct retro_keybind*)
|
||||
&settings->input.binds[inp_desc_user][remap_id];
|
||||
auto_bind = (const struct retro_keybind*)
|
||||
input_get_auto_bind(inp_desc_user, remap_id);
|
||||
input_config_get_bind_auto(inp_desc_user, remap_id);
|
||||
|
||||
input_config_get_bind_string(descriptor,
|
||||
keybind, auto_bind, sizeof(descriptor));
|
||||
|
@ -70,6 +70,7 @@
|
||||
#include "../performance_counters.h"
|
||||
#include "../core_info.h"
|
||||
#include "../wifi/wifi_driver.h"
|
||||
#include "../tasks/tasks_internal.h"
|
||||
|
||||
#ifdef HAVE_NETWORKING
|
||||
static void print_buf_lines(file_list_t *list, char *buf,
|
||||
@ -429,16 +430,12 @@ static int menu_displaylist_parse_core_info(menu_displaylist_info_t *info)
|
||||
static int menu_displaylist_parse_network_info(menu_displaylist_info_t *info)
|
||||
{
|
||||
unsigned k = 0;
|
||||
net_ifinfo_t *list =
|
||||
(net_ifinfo_t*)calloc(1, sizeof(*list));
|
||||
net_ifinfo_t list;
|
||||
|
||||
if (!list)
|
||||
if (!net_ifinfo_new(&list))
|
||||
return -1;
|
||||
|
||||
if (!net_ifinfo_new(list))
|
||||
return -1;
|
||||
|
||||
for (k = 0; k < list->size; k++)
|
||||
for (k = 0; k < list.size; k++)
|
||||
{
|
||||
char tmp[255];
|
||||
|
||||
@ -446,12 +443,12 @@ static int menu_displaylist_parse_network_info(menu_displaylist_info_t *info)
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%s (%s) : %s\n",
|
||||
msg_hash_to_str(MSG_INTERFACE),
|
||||
list->entries[k].name, list->entries[k].host);
|
||||
list.entries[k].name, list.entries[k].host);
|
||||
menu_entries_append_enum(info->list, tmp, "",
|
||||
MENU_ENUM_LABEL_NETWORK_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0);
|
||||
}
|
||||
|
||||
net_ifinfo_free(list);
|
||||
net_ifinfo_free(&list);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@ -4887,27 +4884,47 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data)
|
||||
case DISPLAYLIST_WIFI_SETTINGS_LIST:
|
||||
if (string_is_equal(settings->wifi.driver, "null"))
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_SETTINGS_FOUND),
|
||||
MENU_ENUM_LABEL_NO_SETTINGS_FOUND,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_NETWORKS_FOUND),
|
||||
MENU_ENUM_LABEL_NO_NETWORKS_FOUND,
|
||||
0, 0, 0);
|
||||
#ifdef HAVE_NETWORKING
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
struct string_list *ssid_list = string_list_new();
|
||||
driver_wifi_scan();
|
||||
driver_wifi_get_ssids(ssid_list);
|
||||
|
||||
for (i = 0; i < ssid_list->size; i++)
|
||||
if (ssid_list->size == 0)
|
||||
{
|
||||
const char *ssid = ssid_list->elems[i].data;
|
||||
task_push_wifi_scan();
|
||||
|
||||
menu_entries_append_enum(info->list,
|
||||
ssid,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_CONNECT_WIFI),
|
||||
MENU_ENUM_LABEL_CONNECT_WIFI,
|
||||
MENU_WIFI, 0, 0);
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_NETWORKS_FOUND),
|
||||
MENU_ENUM_LABEL_NO_NETWORKS_FOUND,
|
||||
0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ssid_list->size; i++)
|
||||
{
|
||||
const char *ssid = ssid_list->elems[i].data;
|
||||
menu_entries_append_enum(info->list,
|
||||
ssid,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_CONNECT_WIFI),
|
||||
MENU_ENUM_LABEL_CONNECT_WIFI,
|
||||
MENU_WIFI, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_NETWORKS_FOUND),
|
||||
MENU_ENUM_LABEL_NO_NETWORKS_FOUND,
|
||||
0, 0, 0);
|
||||
#endif
|
||||
|
||||
info->need_refresh = true;
|
||||
info->need_push = true;
|
||||
@ -4942,6 +4959,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,
|
||||
|
@ -111,7 +111,7 @@ int menu_dialog_iterate(char *s, size_t len, const char *label)
|
||||
&settings->input.binds[0][binds[i]];
|
||||
const struct retro_keybind *auto_bind =
|
||||
(const struct retro_keybind*)
|
||||
input_get_auto_bind(0, binds[i]);
|
||||
input_config_get_bind_auto(0, binds[i]);
|
||||
|
||||
input_config_get_bind_string(desc[i],
|
||||
keybind, auto_bind, sizeof(desc[i]));
|
||||
|
@ -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,
|
||||
@ -277,6 +278,8 @@ enum msg_hash_enums
|
||||
MSG_MOVIE_RECORD_STOPPED,
|
||||
MSG_MOVIE_PLAYBACK_ENDED,
|
||||
MSG_TAKING_SCREENSHOT,
|
||||
MSG_WIFI_SCAN_COMPLETE,
|
||||
MSG_SCANNING_WIRELESS_NETWORKS,
|
||||
MSG_FAILED_TO_TAKE_SCREENSHOT,
|
||||
MSG_CUSTOM_TIMING_GIVEN,
|
||||
MSG_SAVING_STATE,
|
||||
@ -861,6 +864,7 @@ enum msg_hash_enums
|
||||
MENU_LABEL(CONTENT_SETTINGS),
|
||||
MENU_LABEL(LOAD_CONTENT_LIST),
|
||||
MENU_LABEL(NO_SETTINGS_FOUND),
|
||||
MENU_LABEL(NO_NETWORKS_FOUND),
|
||||
MENU_LABEL(NO_PERFORMANCE_COUNTERS),
|
||||
MENU_LABEL(FRAME_THROTTLE_SETTINGS),
|
||||
MENU_LABEL(FRAME_THROTTLE_ENABLE),
|
||||
@ -975,6 +979,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,53 @@ 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];
|
||||
|
||||
#ifndef HAVE_SOCKET_LEGACY
|
||||
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;
|
||||
|
||||
#else
|
||||
if (netplay->nat_traversal_state.have_inet4)
|
||||
{
|
||||
strncpy(host,
|
||||
inet_ntoa(netplay->nat_traversal_state.ext_inet4_addr.sin_addr),
|
||||
PATH_MAX_LENGTH);
|
||||
host[PATH_MAX_LENGTH-1] = '\0';
|
||||
snprintf(port, 6, "%hu",
|
||||
ntohs(netplay->nat_traversal_state.ext_inet4_addr.sin_port));
|
||||
port[5] = '\0';
|
||||
|
||||
}
|
||||
else return;
|
||||
|
||||
#endif
|
||||
|
||||
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 +1248,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 +1257,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 +1271,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 +1407,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 +1455,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 +1700,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
|
||||
|
@ -497,14 +497,15 @@
|
||||
# input_player1_r3_btn =
|
||||
|
||||
# Menu buttons.
|
||||
# menu_ok_btn =
|
||||
# menu_cancel_btn =
|
||||
# menu_search_btn =
|
||||
# menu_info_btn =
|
||||
# menu_default_btn =
|
||||
# menu_scroll_down_btn =
|
||||
# menu_scroll_up_btn =
|
||||
|
||||
# Swap buttons for OK/Cancel
|
||||
# menu_swap_ok_cancel = false
|
||||
|
||||
# Axis for RetroArch D-Pad.
|
||||
# Needs to be either '+' or '-' in the first character signaling either positive or negative direction of the axis, then the axis number.
|
||||
# Do note that every other input option has the corresponding _btn and _axis binds as well; they are omitted here for clarity.
|
||||
|
@ -610,7 +610,7 @@ static void setting_get_string_representation_st_bind(void *data,
|
||||
index_offset = setting->index_offset;
|
||||
keybind = (const struct retro_keybind*)setting->value.target.keybind;
|
||||
auto_bind = (const struct retro_keybind*)
|
||||
input_get_auto_bind(index_offset, keybind->id);
|
||||
input_config_get_bind_auto(index_offset, keybind->id);
|
||||
|
||||
input_config_get_bind_string(s, keybind, auto_bind, len);
|
||||
}
|
||||
|
@ -1221,6 +1221,8 @@ bool task_push_content_load_default(
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
RARCH_LOG("MODE: %d\n", mode);
|
||||
/* Load content */
|
||||
switch (mode)
|
||||
{
|
||||
|
112
tasks/task_wifi.c
Normal file
112
tasks/task_wifi.c
Normal file
@ -0,0 +1,112 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2016 - Jean-André Santoni
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <file/nbio.h>
|
||||
#include <formats/image.h>
|
||||
#include <compat/strl.h>
|
||||
#include <retro_assert.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <rhash.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#include "tasks_internal.h"
|
||||
#include "../verbosity.h"
|
||||
#include "../runloop.h"
|
||||
#include "../wifi/wifi_driver.h"
|
||||
#include "../menu/menu_entries.h"
|
||||
#include "../menu/menu_driver.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct string_list *ssid_list;
|
||||
} wifi_handle_t;
|
||||
|
||||
static void wifi_scan_callback(void *task_data,
|
||||
void *user_data, const char *error)
|
||||
{
|
||||
unsigned menu_type = 0;
|
||||
const char *path = NULL;
|
||||
const char *label = NULL;
|
||||
enum msg_hash_enums enum_idx = MSG_UNKNOWN;
|
||||
|
||||
menu_entries_get_last_stack(&path, &label, &menu_type, &enum_idx, NULL);
|
||||
|
||||
/* Don't push the results if we left the wifi menu */
|
||||
if (!string_is_equal(label,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_WIFI_SETTINGS_LIST)))
|
||||
return;
|
||||
|
||||
file_list_t *file_list = menu_entries_get_selection_buf_ptr(0);
|
||||
|
||||
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, file_list);
|
||||
|
||||
struct string_list *ssid_list = string_list_new();
|
||||
driver_wifi_get_ssids(ssid_list);
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < ssid_list->size; i++)
|
||||
{
|
||||
const char *ssid = ssid_list->elems[i].data;
|
||||
menu_entries_append_enum(file_list,
|
||||
ssid,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_CONNECT_WIFI),
|
||||
MENU_ENUM_LABEL_CONNECT_WIFI,
|
||||
MENU_WIFI, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void task_wifi_scan_handler(retro_task_t *task)
|
||||
{
|
||||
driver_wifi_scan();
|
||||
|
||||
task->progress = 100;
|
||||
task->title = strdup(msg_hash_to_str(MSG_WIFI_SCAN_COMPLETE));
|
||||
task->finished = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool task_push_wifi_scan(void)
|
||||
{
|
||||
retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task));
|
||||
wifi_handle_t *state = (wifi_handle_t*)calloc(1, sizeof(*state));
|
||||
|
||||
if (!task || !state)
|
||||
goto error;
|
||||
|
||||
state->ssid_list = string_list_new();
|
||||
|
||||
/* blocking means no other task can run while this one is running, which is the default */
|
||||
task->type = TASK_TYPE_BLOCKING;
|
||||
task->state = state;
|
||||
task->handler = task_wifi_scan_handler;
|
||||
task->callback = wifi_scan_callback;
|
||||
task->title = strdup(msg_hash_to_str(MSG_SCANNING_WIRELESS_NETWORKS));
|
||||
|
||||
task_queue_ctl(TASK_QUEUE_CTL_PUSH, task);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
if (state)
|
||||
free(state);
|
||||
if (task)
|
||||
free(task);
|
||||
|
||||
return false;
|
||||
}
|
@ -83,6 +83,9 @@ void *task_push_http_transfer(const char *url, bool mute, const char *type,
|
||||
retro_task_callback_t cb, void *userdata);
|
||||
|
||||
task_retriever_info_t *http_task_get_transfer_list(void);
|
||||
|
||||
bool task_push_wifi_scan(void);
|
||||
|
||||
#endif
|
||||
|
||||
bool task_push_image_load(const char *fullpath,
|
||||
|
@ -81,6 +81,9 @@ static void connmanctl_get_ssids(struct string_list* ssids)
|
||||
union string_list_elem_attr attr;
|
||||
attr.i = RARCH_FILETYPE_UNSET;
|
||||
|
||||
if (!lines)
|
||||
return;
|
||||
|
||||
for (i = 0; i < lines->size; i++)
|
||||
{
|
||||
char ssid[20];
|
||||
|
Loading…
x
Reference in New Issue
Block a user