Added Netplay discovery code (not yet in menu)
This commit is contained in:
parent
addff325d0
commit
4c18cec752
|
@ -1121,6 +1121,7 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||||
OBJ += network/netplay/netplay_net.o \
|
OBJ += network/netplay/netplay_net.o \
|
||||||
network/netplay/netplay_spectate.o \
|
network/netplay/netplay_spectate.o \
|
||||||
network/netplay/netplay_common.o \
|
network/netplay/netplay_common.o \
|
||||||
|
network/netplay/netplay_discovery.o \
|
||||||
network/netplay/netplay.o
|
network/netplay/netplay.o
|
||||||
|
|
||||||
# Retro Achievements (also depends on threads)
|
# Retro Achievements (also depends on threads)
|
||||||
|
|
|
@ -54,9 +54,6 @@ enum
|
||||||
static bool netplay_enabled = false;
|
static bool netplay_enabled = false;
|
||||||
static bool netplay_is_client = false;
|
static bool netplay_is_client = false;
|
||||||
|
|
||||||
/* Used to advertise or request advertisement of Netplay */
|
|
||||||
static int netplay_ad_fd = -1;
|
|
||||||
|
|
||||||
/* Used while Netplay is running */
|
/* Used while Netplay is running */
|
||||||
static netplay_t *netplay_data = NULL;
|
static netplay_t *netplay_data = NULL;
|
||||||
|
|
||||||
|
@ -204,28 +201,6 @@ static void init_nat_traversal(netplay_t *netplay)
|
||||||
announce_nat_traversal(netplay);
|
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);
|
|
||||||
|
|
||||||
if (fd < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!socket_bind(fd, (void*)netplay->addr))
|
|
||||||
{
|
|
||||||
socket_close(fd);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
netplay_ad_fd = fd;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
error:
|
|
||||||
RARCH_ERR("Failed to initialize netplay advertisement socket.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool init_socket(netplay_t *netplay, const char *server, uint16_t port)
|
static bool init_socket(netplay_t *netplay, const char *server, uint16_t port)
|
||||||
{
|
{
|
||||||
if (!network_init())
|
if (!network_init())
|
||||||
|
@ -1446,9 +1421,8 @@ bool netplay_pre_frame(netplay_t *netplay)
|
||||||
|
|
||||||
if (netplay->is_server)
|
if (netplay->is_server)
|
||||||
{
|
{
|
||||||
/* Advertise our server if applicable */
|
/* Advertise our server */
|
||||||
if (netplay_ad_fd >= 0 || init_ad_socket(netplay, RARCH_DEFAULT_PORT))
|
netplay_lan_ad_server(netplay);
|
||||||
netplay_ad_server(netplay, netplay_ad_fd);
|
|
||||||
|
|
||||||
/* NAT traversal if applicable */
|
/* NAT traversal if applicable */
|
||||||
if (netplay->nat_traversal &&
|
if (netplay->nat_traversal &&
|
||||||
|
|
|
@ -420,104 +420,3 @@ uint32_t netplay_delta_frame_crc(netplay_t *netplay, struct delta_frame *delta)
|
||||||
return 0;
|
return 0;
|
||||||
return encoding_crc32(0L, (const unsigned char*)delta->state, netplay->state_size);
|
return encoding_crc32(0L, (const unsigned char*)delta->state, netplay->state_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* AD PACKET FORMAT:
|
|
||||||
*
|
|
||||||
* Request:
|
|
||||||
* 1 word: RANQ (RetroArch Netplay Query)
|
|
||||||
* 1 word: Netplay protocol version
|
|
||||||
*
|
|
||||||
* Reply:
|
|
||||||
* 1 word : RANS (RetroArch Netplay Server)
|
|
||||||
* 1 word : Netplay protocol version
|
|
||||||
* 1 word : Port
|
|
||||||
* 8 words: RetroArch version
|
|
||||||
* 8 words: Nick
|
|
||||||
* 8 words: Core name
|
|
||||||
* 8 words: Core version
|
|
||||||
* 8 words: Content name (currently always blank)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define AD_PACKET_MAX_SIZE 512
|
|
||||||
#define AD_PACKET_STRING_SIZE 32
|
|
||||||
#define AD_PACKET_STRING_WORDS (AD_PACKET_STRING_SIZE/sizeof(uint32_t))
|
|
||||||
static uint32_t *ad_packet_buffer = NULL;
|
|
||||||
|
|
||||||
bool netplay_ad_server(netplay_t *netplay, int ad_fd)
|
|
||||||
{
|
|
||||||
fd_set fds;
|
|
||||||
struct timeval tmp_tv = {0};
|
|
||||||
struct sockaddr their_addr;
|
|
||||||
socklen_t addr_size;
|
|
||||||
rarch_system_info_t *info = NULL;
|
|
||||||
size_t bufloc;
|
|
||||||
|
|
||||||
if (!ad_packet_buffer)
|
|
||||||
{
|
|
||||||
ad_packet_buffer = (uint32_t *) malloc(AD_PACKET_MAX_SIZE);
|
|
||||||
if (!ad_packet_buffer)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for any ad queries */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(ad_fd, &fds);
|
|
||||||
if (socket_select(ad_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
|
|
||||||
break;
|
|
||||||
if (!FD_ISSET(ad_fd, &fds))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Somebody queried, so check that it's valid */
|
|
||||||
addr_size = sizeof(their_addr);
|
|
||||||
if (recvfrom(ad_fd, (char*)ad_packet_buffer, AD_PACKET_MAX_SIZE, 0,
|
|
||||||
&their_addr, &addr_size) >= (ssize_t) (2*sizeof(uint32_t)))
|
|
||||||
{
|
|
||||||
/* Make sure it's a valid query */
|
|
||||||
if (memcmp(ad_packet_buffer, "RANQ", 4))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* For this version */
|
|
||||||
if (ntohl(ad_packet_buffer[1]) != NETPLAY_PROTOCOL_VERSION)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &info);
|
|
||||||
|
|
||||||
/* Now build our response */
|
|
||||||
memset(ad_packet_buffer, 0, AD_PACKET_MAX_SIZE);
|
|
||||||
memcpy(ad_packet_buffer, "RANS", 4);
|
|
||||||
ad_packet_buffer[1] = htonl(NETPLAY_PROTOCOL_VERSION);
|
|
||||||
ad_packet_buffer[2] = htonl(netplay->tcp_port);
|
|
||||||
bufloc = 3;
|
|
||||||
strncpy((char *) (ad_packet_buffer + bufloc),
|
|
||||||
PACKAGE_VERSION, AD_PACKET_STRING_SIZE);
|
|
||||||
bufloc += AD_PACKET_STRING_WORDS;
|
|
||||||
strncpy((char *) (ad_packet_buffer + bufloc),
|
|
||||||
netplay->nick, AD_PACKET_STRING_SIZE);
|
|
||||||
bufloc += AD_PACKET_STRING_WORDS;
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
strncpy((char *) (ad_packet_buffer + bufloc),
|
|
||||||
info->info.library_name, AD_PACKET_STRING_SIZE);
|
|
||||||
bufloc += AD_PACKET_STRING_WORDS;
|
|
||||||
strncpy((char *) (ad_packet_buffer + bufloc),
|
|
||||||
info->info.library_version, AD_PACKET_STRING_SIZE);
|
|
||||||
bufloc += AD_PACKET_STRING_WORDS;
|
|
||||||
/* Blank content */
|
|
||||||
bufloc += AD_PACKET_STRING_WORDS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bufloc += 3*AD_PACKET_STRING_WORDS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* And send it */
|
|
||||||
sendto(ad_fd, (const char*)ad_packet_buffer, bufloc*sizeof(uint32_t), 0,
|
|
||||||
&their_addr, addr_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,321 @@
|
||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2016 - Gregor Richards
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AD PACKET FORMAT:
|
||||||
|
*
|
||||||
|
* Request:
|
||||||
|
* 1 word: RANQ (RetroArch Netplay Query)
|
||||||
|
* 1 word: Netplay protocol version
|
||||||
|
*
|
||||||
|
* Reply:
|
||||||
|
* 1 word : RANS (RetroArch Netplay Server)
|
||||||
|
* 1 word : Netplay protocol version
|
||||||
|
* 1 word : Port
|
||||||
|
* 8 words: RetroArch version
|
||||||
|
* 8 words: Nick
|
||||||
|
* 8 words: Core name
|
||||||
|
* 8 words: Core version
|
||||||
|
* 8 words: Content name (currently always blank)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <net/net_compat.h>
|
||||||
|
|
||||||
|
#include "../../runloop.h"
|
||||||
|
#include "../../version.h"
|
||||||
|
#include "netplay.h"
|
||||||
|
#include "netplay_discovery.h"
|
||||||
|
#include "netplay_private.h"
|
||||||
|
|
||||||
|
struct ad_packet
|
||||||
|
{
|
||||||
|
uint32_t header;
|
||||||
|
uint32_t protocol_version;
|
||||||
|
uint32_t port;
|
||||||
|
char retroarch_version[NETPLAY_HOST_STR_LEN];
|
||||||
|
char nick[NETPLAY_HOST_STR_LEN];
|
||||||
|
char core[NETPLAY_HOST_STR_LEN];
|
||||||
|
char core_version[NETPLAY_HOST_STR_LEN];
|
||||||
|
char content[NETPLAY_HOST_STR_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
bool netplay_lan_ad_client(void);
|
||||||
|
|
||||||
|
/* LAN discovery sockets */
|
||||||
|
static int lan_ad_server_fd = -1;
|
||||||
|
static int lan_ad_client_fd = -1;
|
||||||
|
|
||||||
|
/* Packet buffer for advertisement and responses */
|
||||||
|
static struct ad_packet ad_packet_buffer;
|
||||||
|
|
||||||
|
/* List of discovered hosts */
|
||||||
|
static struct netplay_host_list discovered_hosts;
|
||||||
|
static size_t discovered_hosts_allocated;
|
||||||
|
|
||||||
|
/** Initialize Netplay discovery (client) */
|
||||||
|
bool init_netplay_discovery(void)
|
||||||
|
{
|
||||||
|
struct addrinfo *addr = NULL;
|
||||||
|
int fd = socket_init((void **) &addr, 0, NULL, SOCKET_TYPE_DATAGRAM);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!socket_bind(fd, (void*)addr))
|
||||||
|
{
|
||||||
|
socket_close(fd);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
lan_ad_client_fd = fd;
|
||||||
|
freeaddrinfo_retro(addr);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (addr)
|
||||||
|
freeaddrinfo_retro(addr);
|
||||||
|
RARCH_ERR("Failed to initialize netplay advertisement client socket.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deinitialize and free Netplay discovery */
|
||||||
|
void deinit_netplay_discovery(void)
|
||||||
|
{
|
||||||
|
if (lan_ad_client_fd >= 0)
|
||||||
|
{
|
||||||
|
socket_close(lan_ad_client_fd);
|
||||||
|
lan_ad_client_fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Discovery control */
|
||||||
|
bool netplay_discovery_driver_ctl(enum rarch_netplay_discovery_ctl_state state, void *data)
|
||||||
|
{
|
||||||
|
char port_str[6];
|
||||||
|
|
||||||
|
if (lan_ad_client_fd < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case RARCH_NETPLAY_DISCOVERY_CTL_LAN_SEND_QUERY:
|
||||||
|
{
|
||||||
|
struct addrinfo hints = {0}, *addr;
|
||||||
|
|
||||||
|
/* Get the broadcast address (IPv4 only for now) */
|
||||||
|
snprintf(port_str, 6, "%hu", RARCH_DEFAULT_PORT);
|
||||||
|
if (getaddrinfo_retro("255.255.255.255", port_str, &hints, &addr) < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Put together the request */
|
||||||
|
memcpy((void *) &ad_packet_buffer, "RANQ", 4);
|
||||||
|
ad_packet_buffer.protocol_version = htonl(NETPLAY_PROTOCOL_VERSION);
|
||||||
|
|
||||||
|
/* And send it off */
|
||||||
|
sendto(lan_ad_client_fd, &ad_packet_buffer, 2*sizeof(uint32_t), 0,
|
||||||
|
addr->ai_addr, addr->ai_addrlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RARCH_NETPLAY_DISCOVERY_CTL_LAN_GET_RESPONSES:
|
||||||
|
return netplay_lan_ad_client();
|
||||||
|
|
||||||
|
case RARCH_NETPLAY_DISCOVERY_CTL_LAN_CLEAR_RESPONSES:
|
||||||
|
discovered_hosts.size = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool init_lan_ad_server_socket(netplay_t *netplay, uint16_t port)
|
||||||
|
{
|
||||||
|
struct addrinfo *addr = NULL;
|
||||||
|
int fd = socket_init((void **) &addr, port, NULL, SOCKET_TYPE_DATAGRAM);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!socket_bind(fd, (void*)addr))
|
||||||
|
{
|
||||||
|
socket_close(fd);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
lan_ad_server_fd = fd;
|
||||||
|
freeaddrinfo_retro(addr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (addr)
|
||||||
|
freeaddrinfo_retro(addr);
|
||||||
|
RARCH_ERR("Failed to initialize netplay advertisement socket.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool netplay_lan_ad_server(netplay_t *netplay)
|
||||||
|
{
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval tmp_tv = {0};
|
||||||
|
struct sockaddr their_addr;
|
||||||
|
socklen_t addr_size;
|
||||||
|
rarch_system_info_t *info = NULL;
|
||||||
|
size_t bufloc;
|
||||||
|
|
||||||
|
if (lan_ad_server_fd < 0 && !init_lan_ad_server_socket(netplay, RARCH_DEFAULT_PORT))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check for any ad queries */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(lan_ad_server_fd, &fds);
|
||||||
|
if (socket_select(lan_ad_server_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
|
||||||
|
break;
|
||||||
|
if (!FD_ISSET(lan_ad_server_fd, &fds))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Somebody queried, so check that it's valid */
|
||||||
|
addr_size = sizeof(their_addr);
|
||||||
|
if (recvfrom(lan_ad_server_fd, (char*)&ad_packet_buffer,
|
||||||
|
sizeof(struct ad_packet), 0, &their_addr, &addr_size) >=
|
||||||
|
(ssize_t) (2*sizeof(uint32_t)))
|
||||||
|
{
|
||||||
|
/* Make sure it's a valid query */
|
||||||
|
if (memcmp((void *) &ad_packet_buffer, "RANQ", 4))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* For this version */
|
||||||
|
if (ntohl(ad_packet_buffer.protocol_version) !=
|
||||||
|
NETPLAY_PROTOCOL_VERSION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &info);
|
||||||
|
|
||||||
|
/* Now build our response */
|
||||||
|
memset(&ad_packet_buffer, 0, sizeof(struct ad_packet));
|
||||||
|
memcpy(&ad_packet_buffer, "RANS", 4);
|
||||||
|
ad_packet_buffer.protocol_version =
|
||||||
|
htonl(NETPLAY_PROTOCOL_VERSION);
|
||||||
|
ad_packet_buffer.port = htonl(netplay->tcp_port);
|
||||||
|
strncpy(ad_packet_buffer.retroarch_version, PACKAGE_VERSION,
|
||||||
|
NETPLAY_HOST_STR_LEN);
|
||||||
|
strncpy(ad_packet_buffer.nick, netplay->nick, NETPLAY_HOST_STR_LEN);
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
strncpy(ad_packet_buffer.core, info->info.library_name,
|
||||||
|
NETPLAY_HOST_STR_LEN);
|
||||||
|
strncpy(ad_packet_buffer.core_version, info->info.library_version,
|
||||||
|
NETPLAY_HOST_STR_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And send it */
|
||||||
|
sendto(lan_ad_server_fd, (const char*)&ad_packet_buffer,
|
||||||
|
sizeof(struct ad_packet), 0, &their_addr, addr_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool netplay_lan_ad_client(void)
|
||||||
|
{
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval tmp_tv = {0};
|
||||||
|
struct sockaddr their_addr;
|
||||||
|
socklen_t addr_size;
|
||||||
|
rarch_system_info_t *info = NULL;
|
||||||
|
size_t bufloc;
|
||||||
|
|
||||||
|
if (lan_ad_client_fd < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check for any ad queries */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(lan_ad_client_fd, &fds);
|
||||||
|
if (socket_select(lan_ad_client_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
|
||||||
|
break;
|
||||||
|
if (!FD_ISSET(lan_ad_client_fd, &fds))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Somebody queried, so check that it's valid */
|
||||||
|
addr_size = sizeof(their_addr);
|
||||||
|
if (recvfrom(lan_ad_client_fd, (char*)&ad_packet_buffer,
|
||||||
|
sizeof(struct ad_packet), 0, &their_addr, &addr_size) >=
|
||||||
|
sizeof(struct ad_packet))
|
||||||
|
{
|
||||||
|
struct netplay_host *host;
|
||||||
|
|
||||||
|
/* Make sure it's a valid response */
|
||||||
|
if (memcmp((void *) &ad_packet_buffer, "RANS", 4))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* For this version */
|
||||||
|
if (ntohl(ad_packet_buffer.protocol_version) != NETPLAY_PROTOCOL_VERSION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Allocate space for it */
|
||||||
|
if (discovered_hosts.size >= discovered_hosts_allocated)
|
||||||
|
{
|
||||||
|
size_t allocated = discovered_hosts_allocated;
|
||||||
|
struct netplay_host *new_hosts;
|
||||||
|
|
||||||
|
if (allocated == 0) allocated = 2;
|
||||||
|
else allocated *= 2;
|
||||||
|
|
||||||
|
if (discovered_hosts.hosts)
|
||||||
|
new_hosts = realloc(discovered_hosts.hosts, allocated * sizeof(struct netplay_host));
|
||||||
|
else
|
||||||
|
/* Should be equivalent to realloc, but I don't trust screwy libcs */
|
||||||
|
new_hosts = malloc(allocated * sizeof(struct netplay_host));
|
||||||
|
|
||||||
|
if (!new_hosts)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
discovered_hosts.hosts = new_hosts;
|
||||||
|
discovered_hosts_allocated = allocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get our host structure */
|
||||||
|
host = &discovered_hosts.hosts[discovered_hosts.size++];
|
||||||
|
|
||||||
|
/* Copy in the response */
|
||||||
|
memset(host, 0, sizeof(struct netplay_host));
|
||||||
|
host->addr = their_addr;
|
||||||
|
host->addrlen = addr_size;
|
||||||
|
strncpy(host->nick, ad_packet_buffer.nick, NETPLAY_HOST_STR_LEN);
|
||||||
|
strncpy(host->core, ad_packet_buffer.core, NETPLAY_HOST_STR_LEN);
|
||||||
|
strncpy(host->core_version, ad_packet_buffer.core_version,
|
||||||
|
NETPLAY_HOST_STR_LEN);
|
||||||
|
strncpy(host->content, ad_packet_buffer.content,
|
||||||
|
NETPLAY_HOST_STR_LEN);
|
||||||
|
host->nick[NETPLAY_HOST_STR_LEN-1] =
|
||||||
|
host->core[NETPLAY_HOST_STR_LEN-1] =
|
||||||
|
host->core_version[NETPLAY_HOST_STR_LEN-1] =
|
||||||
|
host->content[NETPLAY_HOST_STR_LEN-1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -258,6 +258,8 @@ bool netplay_cmd_crc(netplay_t *netplay, struct delta_frame *delta);
|
||||||
|
|
||||||
bool netplay_cmd_request_savestate(netplay_t *netplay);
|
bool netplay_cmd_request_savestate(netplay_t *netplay);
|
||||||
|
|
||||||
bool netplay_ad_server(netplay_t *netplay, int ad_fd);
|
/* DISCOVERY: */
|
||||||
|
|
||||||
|
bool netplay_lan_ad_server(netplay_t *netplay);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue