Merge pull request #3769 from GregorR/netplay-ad-server

Add a netplay advertisement server for LAN netplay detection
This commit is contained in:
Twinaphex 2016-10-10 18:35:16 +02:00 committed by GitHub
commit 9627a6715a
3 changed files with 134 additions and 1 deletions

View File

@ -54,6 +54,9 @@ enum
static bool netplay_enabled = 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 */
static netplay_t *netplay_data = NULL;
@ -167,6 +170,28 @@ static bool init_tcp_socket(netplay_t *netplay, const char *server,
return ret;
}
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)
{
if (!network_init())
@ -1291,6 +1316,13 @@ bool netplay_pre_frame(netplay_t *netplay)
netplay_try_init_serialization(netplay);
}
/* Advertise our server if applicable */
if (netplay->is_server)
{
if (netplay_ad_fd >= 0 || init_ad_socket(netplay, RARCH_DEFAULT_PORT))
netplay_ad_server(netplay, netplay_ad_fd);
}
if (!netplay->net_cbs->pre_frame(netplay))
return false;
@ -1427,7 +1459,6 @@ void deinit_netplay(void)
if (netplay_data)
netplay_free(netplay_data);
netplay_data = NULL;
netplay_enabled = false;
}
/**

View File

@ -386,3 +386,103 @@ uint32_t netplay_delta_frame_crc(netplay_t *netplay, struct delta_frame *delta)
return 0;
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 */
if (recvfrom(ad_fd, 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, ad_packet_buffer, bufloc*sizeof(uint32_t), 0,
&their_addr, addr_size);
}
}
return true;
}

View File

@ -234,4 +234,6 @@ bool netplay_cmd_crc(netplay_t *netplay, struct delta_frame *delta);
bool netplay_cmd_request_savestate(netplay_t *netplay);
bool netplay_ad_server(netplay_t *netplay, int ad_fd);
#endif