Merge branch 'master' of ssh://github.com/terry1994/RetroArch

This commit is contained in:
terry1994 2016-12-01 09:53:10 +01:00
commit 86c7afdd7c
35 changed files with 715 additions and 114 deletions

View File

@ -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)),)

View File

@ -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;

View File

@ -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);

View File

@ -403,6 +403,7 @@ typedef struct settings
unsigned check_frames;
bool is_spectate;
bool swap_input;
bool nat_traversal;
} netplay;
#endif

View File

@ -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
/*============================================================

View File

@ -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);

View File

@ -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];

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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++)
{

View File

@ -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,

View File

@ -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"

View File

@ -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...")

View 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

View File

@ -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;

View 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

View File

@ -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;
}

View File

@ -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));

View File

@ -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)

View File

@ -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,

View File

@ -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]));

View File

@ -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),

View File

@ -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;

View File

@ -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);
/**

View File

@ -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;
}

View File

@ -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;

View File

@ -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'

View File

@ -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

View File

@ -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.

View File

@ -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);
}

View File

@ -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
View 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;
}

View File

@ -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,

View File

@ -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];