mirror of
https://github.com/libretro/RetroArch
synced 2025-01-29 18:32:44 +00:00
(Network) poll support
This commit is contained in:
parent
9fbf1c846f
commit
d4324d9a0d
@ -20,8 +20,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBRETRO_SDK_NETPLAY_COMPAT_H__
|
||||
#define LIBRETRO_SDK_NETPLAY_COMPAT_H__
|
||||
#ifndef LIBRETRO_SDK_NET_COMPAT_H__
|
||||
#define LIBRETRO_SDK_NET_COMPAT_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
@ -46,73 +46,114 @@
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
#elif defined(_XBOX)
|
||||
#if _WIN32_WINNT >= 0x0600
|
||||
#define NETWORK_HAVE_POLL 1
|
||||
#endif
|
||||
|
||||
#elif defined(_XBOX)
|
||||
#define NOD3D
|
||||
#include <xtl.h>
|
||||
#include <io.h>
|
||||
|
||||
#elif defined(GEKKO)
|
||||
|
||||
#include <network.h>
|
||||
|
||||
#define sendto(s, msg, len, flags, addr, tolen) net_sendto(s, msg, len, 0, addr, 8)
|
||||
#define socket(domain, type, protocol) net_socket(domain, type, protocol)
|
||||
#define bind(s, name, namelen) net_bind(s, name, namelen)
|
||||
#define listen(s, backlog) net_listen(s, backlog)
|
||||
#define accept(s, addr, addrlen) net_accept(s, addr, addrlen)
|
||||
#define connect(s, addr, addrlen) net_connect(s, addr, addrlen)
|
||||
#define send(s, data, size, flags) net_send(s, data, size, flags)
|
||||
#define recv(s, mem, len, flags) net_recv(s, mem, len, flags)
|
||||
#define recvfrom(s, mem, len, flags, from, fromlen) net_recvfrom(s, mem, len, flags, from, fromlen)
|
||||
#define select(maxfdp1, readset, writeset, exceptset, timeout) net_select(maxfdp1, readset, writeset, exceptset, timeout)
|
||||
#define NETWORK_HAVE_POLL 1
|
||||
|
||||
#define pollfd pollsd
|
||||
|
||||
#define socket net_socket
|
||||
#define getsockopt net_getsockopt
|
||||
#define setsockopt net_setsockopt
|
||||
#define bind net_bind
|
||||
#define listen net_listen
|
||||
#define accept net_accept
|
||||
#define connect net_connect
|
||||
#define send net_send
|
||||
#define sendto net_sendto
|
||||
#define recv net_recv
|
||||
#define recvfrom net_recvfrom
|
||||
#define select net_select
|
||||
#define poll net_poll
|
||||
|
||||
#elif defined(VITA)
|
||||
|
||||
#include <psp2/net/net.h>
|
||||
#include <psp2/net/netctl.h>
|
||||
|
||||
#define sockaddr_in SceNetSockaddrIn
|
||||
#define sockaddr SceNetSockaddr
|
||||
#define sendto sceNetSendto
|
||||
#define recvfrom sceNetRecvfrom
|
||||
#define socket(a,b,c) sceNetSocket("unknown",a,b,c)
|
||||
#define bind sceNetBind
|
||||
#define accept sceNetAccept
|
||||
#define getsockopt sceNetGetsockopt
|
||||
#define setsockopt sceNetSetsockopt
|
||||
#define connect sceNetConnect
|
||||
#define listen sceNetListen
|
||||
#define send sceNetSend
|
||||
#define recv sceNetRecv
|
||||
#define MSG_DONTWAIT SCE_NET_MSG_DONTWAIT
|
||||
#define AF_INET SCE_NET_AF_INET
|
||||
#define NETWORK_HAVE_POLL 1
|
||||
|
||||
#define AF_UNSPEC 0
|
||||
#define INADDR_ANY SCE_NET_INADDR_ANY
|
||||
#define INADDR_NONE 0xffffffff
|
||||
#define AF_INET SCE_NET_AF_INET
|
||||
|
||||
#define SOCK_STREAM SCE_NET_SOCK_STREAM
|
||||
#define SOCK_DGRAM SCE_NET_SOCK_DGRAM
|
||||
|
||||
#define INADDR_ANY SCE_NET_INADDR_ANY
|
||||
#define INADDR_NONE 0xFFFFFFFF
|
||||
|
||||
#define SOL_SOCKET SCE_NET_SOL_SOCKET
|
||||
#define SO_REUSEADDR SCE_NET_SO_REUSEADDR
|
||||
#define SO_KEEPALIVE SCE_NET_SO_KEEPALIVE
|
||||
#define SO_BROADCAST SCE_NET_SO_BROADCAST
|
||||
#define SO_SNDBUF SCE_NET_SO_SNDBUF
|
||||
#define SO_RCVBUF SCE_NET_SO_RCVBUF
|
||||
#define SO_SNDTIMEO SCE_NET_SO_SNDTIMEO
|
||||
#define SO_RCVTIMEO SCE_NET_SO_RCVTIMEO
|
||||
#define SO_ERROR SCE_NET_SO_ERROR
|
||||
#define SO_NBIO SCE_NET_SO_NBIO
|
||||
|
||||
#define IPPROTO_IP SCE_NET_IPPROTO_IP
|
||||
#define IP_MULTICAST_TTL SCE_NET_IP_MULTICAST_TTL
|
||||
|
||||
#define IPPROTO_TCP SCE_NET_IPPROTO_TCP
|
||||
#define TCP_NODELAY SCE_NET_TCP_NODELAY
|
||||
|
||||
#define IPPROTO_UDP SCE_NET_IPPROTO_UDP
|
||||
|
||||
#define MSG_DONTWAIT SCE_NET_MSG_DONTWAIT
|
||||
|
||||
#define POLLIN SCE_NET_EPOLLIN
|
||||
#define POLLOUT SCE_NET_EPOLLOUT
|
||||
#define POLLERR SCE_NET_EPOLLERR
|
||||
#define POLLHUP SCE_NET_EPOLLHUP
|
||||
#define POLLNVAL 0
|
||||
|
||||
#define sockaddr_in SceNetSockaddrIn
|
||||
#define sockaddr SceNetSockaddr
|
||||
#define socklen_t unsigned int
|
||||
|
||||
#define socket(a,b,c) sceNetSocket("unknown",a,b,c)
|
||||
#define getsockopt sceNetGetsockopt
|
||||
#define setsockopt sceNetSetsockopt
|
||||
#define bind sceNetBind
|
||||
#define listen sceNetListen
|
||||
#define accept sceNetAccept
|
||||
#define connect sceNetConnect
|
||||
#define send sceNetSend
|
||||
#define sendto sceNetSendto
|
||||
#define recv sceNetRecv
|
||||
#define recvfrom sceNetRecvfrom
|
||||
#define htonl sceNetHtonl
|
||||
#define ntohl sceNetNtohl
|
||||
#define htons sceNetHtons
|
||||
#define ntohs sceNetNtohs
|
||||
#define socklen_t unsigned int
|
||||
|
||||
struct pollfd
|
||||
{
|
||||
int fd;
|
||||
unsigned events;
|
||||
unsigned revents;
|
||||
unsigned __pad; /* Align to 64-bits boundary */
|
||||
};
|
||||
|
||||
struct hostent
|
||||
{
|
||||
char *h_name;
|
||||
char **h_aliases;
|
||||
int h_addrtype;
|
||||
int h_length;
|
||||
char **h_addr_list;
|
||||
char *h_addr;
|
||||
char *h_name;
|
||||
char **h_aliases;
|
||||
int h_addrtype;
|
||||
int h_length;
|
||||
char **h_addr_list;
|
||||
char *h_addr;
|
||||
};
|
||||
|
||||
struct SceNetInAddr inet_aton(const char *ip_addr);
|
||||
@ -138,6 +179,18 @@ struct SceNetInAddr inet_aton(const char *ip_addr);
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__PSL1GHT__)
|
||||
#include <net/poll.h>
|
||||
|
||||
#define NETWORK_HAVE_POLL 1
|
||||
|
||||
#elif !defined(WIIU) && !defined(__PS3__)
|
||||
#include <poll.h>
|
||||
|
||||
#define NETWORK_HAVE_POLL 1
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
@ -198,6 +251,16 @@ static INLINE bool isinprogress(int bytes)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef NETWORK_HAVE_POLL
|
||||
#ifdef GEKKO
|
||||
#define NET_POLL_FD(sockfd, sockfds) (sockfds)->socket = (sockfd)
|
||||
#else
|
||||
#define NET_POLL_FD(sockfd, sockfds) (sockfds)->fd = (sockfd)
|
||||
#endif
|
||||
#define NET_POLL_EVENT(sockev, sockfds) (sockfds)->events |= (sockev)
|
||||
#define NET_POLL_HAS_EVENT(sockev, sockfds) ((sockfds)->revents & (sockev))
|
||||
#endif
|
||||
|
||||
/* Compatibility layer for legacy or incomplete BSD socket implementations.
|
||||
* Only for IPv4. Mostly useful for the consoles which do not support
|
||||
* anything reasonably modern on the socket API side of things. */
|
||||
|
@ -23,9 +23,9 @@
|
||||
#ifndef _LIBRETRO_SDK_NET_SOCKET_H
|
||||
#define _LIBRETRO_SDK_NET_SOCKET_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <boolean.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <net/net_compat.h>
|
||||
|
||||
@ -71,9 +71,15 @@ bool socket_set_block(int fd, bool block);
|
||||
/* TODO: all callers should be converted to socket_set_block() */
|
||||
bool socket_nonblock(int fd);
|
||||
|
||||
int socket_select(int nfds, fd_set *readfs, fd_set *writefds,
|
||||
int socket_select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *errorfds, struct timeval *timeout);
|
||||
|
||||
#ifdef NETWORK_HAVE_POLL
|
||||
int socket_poll(struct pollfd *fds, unsigned nfds, int timeout);
|
||||
#endif
|
||||
|
||||
bool socket_wait(int fd, bool *rd, bool *wr, int timeout);
|
||||
|
||||
bool socket_send_all_blocking(int fd, const void *data_, size_t size, bool no_signal);
|
||||
|
||||
bool socket_send_all_blocking_with_timeout(int fd,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
/* Copyright (C) 2010-2022 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (net_compat.c).
|
||||
@ -80,9 +80,7 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
#elif defined(VITA)
|
||||
static void *_net_compat_net_memory = NULL;
|
||||
#define COMPAT_NET_INIT_SIZE 512*1024
|
||||
#define INET_ADDRSTRLEN sizeof(struct sockaddr_in)
|
||||
#define MAX_NAME 512
|
||||
|
||||
typedef uint32_t in_addr_t;
|
||||
@ -92,14 +90,17 @@ struct in_addr
|
||||
in_addr_t s_addr;
|
||||
};
|
||||
|
||||
static void *_net_compat_net_memory = NULL;
|
||||
int retro_epoll_fd = -1;
|
||||
|
||||
char *inet_ntoa(struct SceNetInAddr in)
|
||||
{
|
||||
static char ip_addr[INET_ADDRSTRLEN + 1];
|
||||
static char ip_addr[16];
|
||||
|
||||
if (!inet_ntop_compat(AF_INET, &in, ip_addr, INET_ADDRSTRLEN))
|
||||
strlcpy(ip_addr, "Invalid", sizeof(ip_addr));
|
||||
if (!inet_ntop_compat(AF_INET, &in, ip_addr, sizeof(ip_addr)))
|
||||
strlcpy(ip_addr, "Invalid", sizeof(ip_addr));
|
||||
|
||||
return ip_addr;
|
||||
return ip_addr;
|
||||
}
|
||||
|
||||
struct SceNetInAddr inet_aton(const char *ip_addr)
|
||||
@ -107,6 +108,7 @@ struct SceNetInAddr inet_aton(const char *ip_addr)
|
||||
SceNetInAddr inaddr;
|
||||
|
||||
inet_ptrton(AF_INET, ip_addr, &inaddr);
|
||||
|
||||
return inaddr;
|
||||
}
|
||||
|
||||
@ -143,14 +145,15 @@ struct hostent *gethostbyname(const char *name)
|
||||
return &ent;
|
||||
}
|
||||
|
||||
int retro_epoll_fd;
|
||||
#elif defined(_3DS)
|
||||
#include <malloc.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/services/soc.h>
|
||||
|
||||
#define SOC_ALIGN 0x1000
|
||||
#define SOC_BUFFERSIZE 0x100000
|
||||
static u32* _net_compat_net_memory;
|
||||
|
||||
static u32* _net_compat_net_memory = NULL;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
@ -259,8 +262,11 @@ error:
|
||||
void freeaddrinfo_retro(struct addrinfo *res)
|
||||
{
|
||||
#ifdef HAVE_SOCKET_LEGACY
|
||||
free(res->ai_addr);
|
||||
free(res);
|
||||
if (res)
|
||||
{
|
||||
free(res->ai_addr);
|
||||
free(res);
|
||||
}
|
||||
#else
|
||||
freeaddrinfo(res);
|
||||
#endif
|
||||
@ -270,10 +276,14 @@ void freeaddrinfo_retro(struct addrinfo *res)
|
||||
#include <malloc.h>
|
||||
|
||||
static OSThread wiiu_net_cmpt_thread;
|
||||
static void wiiu_net_cmpt_thread_cleanup(OSThread *thread, void *stack) {
|
||||
|
||||
static void wiiu_net_cmpt_thread_cleanup(OSThread *thread, void *stack)
|
||||
{
|
||||
free(stack);
|
||||
}
|
||||
static int wiiu_net_cmpt_thread_entry(int argc, const char** argv) {
|
||||
|
||||
static int wiiu_net_cmpt_thread_entry(int argc, const char** argv)
|
||||
{
|
||||
const int buf_size = WIIU_RCVBUF + WIIU_SNDBUF;
|
||||
void* buf = memalign(128, buf_size);
|
||||
if (!buf) return -1;
|
||||
@ -300,89 +310,107 @@ static char netmask[16] = {0};
|
||||
**/
|
||||
bool network_init(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
#endif
|
||||
static bool inited = false;
|
||||
|
||||
#if defined(_WIN32)
|
||||
WSADATA wsaData;
|
||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||
int timeout_count = 10;
|
||||
#elif defined(WIIU)
|
||||
void* stack;
|
||||
#endif
|
||||
|
||||
if (inited)
|
||||
return true;
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
|
||||
{
|
||||
network_deinit();
|
||||
return false;
|
||||
}
|
||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||
int timeout_count = 10;
|
||||
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
|
||||
goto failure;
|
||||
#elif defined(__PSL1GHT__) || defined(__PS3__)
|
||||
sysModuleLoad(SYSMODULE_NET);
|
||||
netInitialize();
|
||||
|
||||
if (netCtlInit() < 0)
|
||||
return false;
|
||||
goto failure;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int state;
|
||||
if (netCtlGetState(&state) < 0)
|
||||
return false;
|
||||
|
||||
if (netCtlGetState(&state) < 0)
|
||||
goto failure;
|
||||
if (state == NET_CTL_STATE_IPObtained)
|
||||
break;
|
||||
|
||||
if (!(timeout_count--))
|
||||
goto failure;
|
||||
|
||||
retro_sleep(500);
|
||||
timeout_count--;
|
||||
if (timeout_count < 0)
|
||||
return 0;
|
||||
}
|
||||
#elif defined(VITA)
|
||||
SceNetInitParam initparam;
|
||||
|
||||
if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT)
|
||||
{
|
||||
SceNetInitParam param;
|
||||
|
||||
_net_compat_net_memory = malloc(COMPAT_NET_INIT_SIZE);
|
||||
|
||||
initparam.memory = _net_compat_net_memory;
|
||||
initparam.size = COMPAT_NET_INIT_SIZE;
|
||||
initparam.flags = 0;
|
||||
|
||||
sceNetInit(&initparam);
|
||||
param.memory = _net_compat_net_memory;
|
||||
param.size = COMPAT_NET_INIT_SIZE;
|
||||
param.flags = 0;
|
||||
if (sceNetInit(¶m) < 0)
|
||||
goto failure;
|
||||
|
||||
sceNetCtlInit();
|
||||
}
|
||||
|
||||
retro_epoll_fd = sceNetEpollCreate("epoll", 0);
|
||||
retro_epoll_fd = sceNetEpollCreate("epoll", 0);
|
||||
if (retro_epoll_fd < 0)
|
||||
goto failure;
|
||||
}
|
||||
#elif defined(GEKKO)
|
||||
if (if_config(localip, netmask, gateway, true, 10) < 0)
|
||||
return false;
|
||||
goto failure;
|
||||
#elif defined(WIIU)
|
||||
stack = malloc(4096);
|
||||
if (!stack)
|
||||
goto failure;
|
||||
|
||||
socket_lib_init();
|
||||
|
||||
const int stack_size = 4096;
|
||||
void* stack = malloc(stack_size);
|
||||
if (stack && OSCreateThread(&wiiu_net_cmpt_thread,
|
||||
wiiu_net_cmpt_thread_entry, 0, NULL, stack+stack_size, stack_size,
|
||||
3, OS_THREAD_ATTRIB_AFFINITY_ANY)) {
|
||||
|
||||
if (OSCreateThread(&wiiu_net_cmpt_thread, wiiu_net_cmpt_thread_entry,
|
||||
0, NULL, stack+4096, 4096, 3,
|
||||
OS_THREAD_ATTRIB_AFFINITY_ANY))
|
||||
{
|
||||
OSSetThreadName(&wiiu_net_cmpt_thread, "Network compat thread");
|
||||
OSSetThreadDeallocator(&wiiu_net_cmpt_thread,
|
||||
wiiu_net_cmpt_thread_cleanup);
|
||||
OSResumeThread(&wiiu_net_cmpt_thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(stack);
|
||||
goto failure;
|
||||
}
|
||||
#elif defined(_3DS)
|
||||
_net_compat_net_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
|
||||
if (!_net_compat_net_memory)
|
||||
return false;
|
||||
Result ret = socInit(_net_compat_net_memory, SOC_BUFFERSIZE);//WIFI init
|
||||
if (ret != 0)
|
||||
return false;
|
||||
_net_compat_net_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
|
||||
if (!_net_compat_net_memory)
|
||||
goto failure;
|
||||
|
||||
/* WIFI init */
|
||||
if (socInit(_net_compat_net_memory, SOC_BUFFERSIZE))
|
||||
goto failure;
|
||||
#else
|
||||
signal(SIGPIPE, SIG_IGN); /* Do not like SIGPIPE killing our app. */
|
||||
#endif
|
||||
|
||||
inited = true;
|
||||
|
||||
return true;
|
||||
|
||||
#if defined(_WIN32) || defined(__PSL1GHT__) || defined(__PS3__) || defined(VITA) || defined(GEKKO) || defined(WIIU) || defined(_3DS)
|
||||
failure:
|
||||
network_deinit();
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -399,24 +427,24 @@ void network_deinit(void)
|
||||
netFinalizeNetwork();
|
||||
sysModuleUnload(SYSMODULE_NET);
|
||||
#elif defined(VITA)
|
||||
if (retro_epoll_fd >= 0)
|
||||
{
|
||||
sceNetEpollDestroy(retro_epoll_fd);
|
||||
retro_epoll_fd = -1;
|
||||
}
|
||||
|
||||
sceNetCtlTerm();
|
||||
sceNetTerm();
|
||||
|
||||
if (_net_compat_net_memory)
|
||||
{
|
||||
free(_net_compat_net_memory);
|
||||
_net_compat_net_memory = NULL;
|
||||
}
|
||||
free(_net_compat_net_memory);
|
||||
_net_compat_net_memory = NULL;
|
||||
#elif defined(GEKKO) && !defined(HW_DOL)
|
||||
net_deinit();
|
||||
#elif defined(_3DS)
|
||||
socExit();
|
||||
|
||||
if(_net_compat_net_memory)
|
||||
{
|
||||
free(_net_compat_net_memory);
|
||||
_net_compat_net_memory = NULL;
|
||||
}
|
||||
free(_net_compat_net_memory);
|
||||
_net_compat_net_memory = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,9 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <compat/msvc.h>
|
||||
@ -37,13 +38,13 @@
|
||||
|
||||
int socket_init(void **address, uint16_t port, const char *server, enum socket_type type)
|
||||
{
|
||||
char port_buf[16];
|
||||
struct addrinfo hints = {0};
|
||||
char port_buf[6];
|
||||
struct addrinfo hints = {0};
|
||||
struct addrinfo **addrinfo = (struct addrinfo**)address;
|
||||
struct addrinfo *addr = NULL;
|
||||
struct addrinfo *addr = NULL;
|
||||
|
||||
if (!network_init())
|
||||
goto error;
|
||||
return -1;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -61,31 +62,27 @@ int socket_init(void **address, uint16_t port, const char *server, enum socket_t
|
||||
if (!server)
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
port_buf[0] = '\0';
|
||||
|
||||
snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);
|
||||
|
||||
if (getaddrinfo_retro(server, port_buf, &hints, addrinfo) != 0)
|
||||
goto error;
|
||||
|
||||
addr = (struct addrinfo*)*addrinfo;
|
||||
if (getaddrinfo_retro(server, port_buf, &hints, addrinfo))
|
||||
return -1;
|
||||
|
||||
addr = *addrinfo;
|
||||
if (!addr)
|
||||
goto error;
|
||||
return -1;
|
||||
|
||||
return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int socket_next(void **addrinfo)
|
||||
int socket_next(void **address)
|
||||
{
|
||||
struct addrinfo *addr = (struct addrinfo*)*addrinfo;
|
||||
struct addrinfo **addrinfo = (struct addrinfo**)address;
|
||||
struct addrinfo *addr = *addrinfo;
|
||||
|
||||
if ((*addrinfo = addr = addr->ai_next))
|
||||
return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
else
|
||||
return -1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t socket_receive_all_nonblocking(int fd, bool *error,
|
||||
@ -181,18 +178,27 @@ bool socket_receive_all_blocking_with_timeout(int fd,
|
||||
|
||||
bool socket_set_block(int fd, bool block)
|
||||
{
|
||||
#if !defined(__PSL1GHT__) && defined(__PS3__) || defined(VITA) || defined(WIIU)
|
||||
#if defined(_WIN32)
|
||||
u_long i = !block;
|
||||
|
||||
return !ioctlsocket(fd, FIONBIO, &i);
|
||||
#elif !defined(__PSL1GHT__) && defined(__PS3__) || defined(VITA) || defined(WIIU)
|
||||
int i = !block;
|
||||
setsockopt(fd, SOL_SOCKET, SO_NBIO, &i, sizeof(int));
|
||||
return true;
|
||||
#elif defined(_WIN32)
|
||||
u_long mode = !block;
|
||||
return ioctlsocket(fd, FIONBIO, &mode) == 0;
|
||||
|
||||
return !setsockopt(fd, SOL_SOCKET, SO_NBIO, &i, sizeof(i));
|
||||
#elif defined(GEKKO)
|
||||
u32 set = block;
|
||||
return net_ioctl(fd, FIONBIO, &set) >= 0;
|
||||
u32 i = !block;
|
||||
|
||||
return !net_ioctl(fd, FIONBIO, &i);
|
||||
#else
|
||||
return fcntl(fd, F_SETFL, (fcntl(fd, F_GETFL) & ~O_NONBLOCK) | (block ? 0 : O_NONBLOCK)) == 0;
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
|
||||
if (block)
|
||||
flags &= ~O_NONBLOCK;
|
||||
else
|
||||
flags |= O_NONBLOCK;
|
||||
|
||||
return !fcntl(fd, F_SETFL, flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -215,27 +221,318 @@ int socket_close(int fd)
|
||||
#endif
|
||||
}
|
||||
|
||||
int socket_select(int nfds, fd_set *readfs, fd_set *writefds,
|
||||
int socket_select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *errorfds, struct timeval *timeout)
|
||||
{
|
||||
#if !defined(__PSL1GHT__) && defined(__PS3__)
|
||||
return socketselect(nfds, readfs, writefds, errorfds, timeout);
|
||||
return socketselect(nfds, readfds, writefds, errorfds, timeout);
|
||||
#elif defined(VITA)
|
||||
extern int retro_epoll_fd;
|
||||
SceNetEpollEvent ev = {0};
|
||||
int i, j;
|
||||
fd_set rfds, wfds, efds;
|
||||
int epoll_fd;
|
||||
SceNetEpollEvent *events = NULL;
|
||||
int event_count = 0;
|
||||
int timeout_ms = -1;
|
||||
int ret = -1;
|
||||
|
||||
ev.events = SCE_NET_EPOLLIN | SCE_NET_EPOLLHUP;
|
||||
ev.data.fd = nfds;
|
||||
if (nfds < 0 || nfds > 1024)
|
||||
return SCE_NET_ERROR_EINVAL;
|
||||
if (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))
|
||||
return SCE_NET_ERROR_EINVAL;
|
||||
|
||||
if((sceNetEpollControl(retro_epoll_fd, SCE_NET_EPOLL_CTL_ADD, nfds, &ev)))
|
||||
epoll_fd = sceNetEpollCreate("socket_select", 0);
|
||||
if (epoll_fd < 0)
|
||||
return SCE_NET_ERROR_ENOMEM;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_ZERO(&efds);
|
||||
|
||||
for (i = 0; i < nfds; i++)
|
||||
{
|
||||
int ret = sceNetEpollWait(retro_epoll_fd, &ev, 1, 0);
|
||||
sceNetEpollControl(retro_epoll_fd, SCE_NET_EPOLL_CTL_DEL, nfds, NULL);
|
||||
return ret;
|
||||
if (readfds && FD_ISSET(i, readfds))
|
||||
event_count++;
|
||||
else if (writefds && FD_ISSET(i, writefds))
|
||||
event_count++;
|
||||
else if (errorfds && FD_ISSET(i, errorfds))
|
||||
event_count++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
#define ALLOC_EVENTS(count) \
|
||||
events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \
|
||||
if (!events) \
|
||||
{ \
|
||||
ret = SCE_NET_ERROR_ENOMEM; \
|
||||
goto done; \
|
||||
}
|
||||
|
||||
if (event_count)
|
||||
{
|
||||
ALLOC_EVENTS(event_count)
|
||||
|
||||
for (i = 0, j = 0; i < nfds && j < event_count; i++)
|
||||
{
|
||||
SceNetEpollEvent *event = &events[j];
|
||||
|
||||
if (readfds && FD_ISSET(i, readfds))
|
||||
event->events |= SCE_NET_EPOLLIN;
|
||||
if (writefds && FD_ISSET(i, writefds))
|
||||
event->events |= SCE_NET_EPOLLOUT;
|
||||
|
||||
if (event->events || (errorfds && FD_ISSET(i, errorfds)))
|
||||
{
|
||||
event->data.fd = i;
|
||||
|
||||
ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,
|
||||
i, event);
|
||||
if (ret < 0)
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
case SCE_NET_ERROR_EBADF:
|
||||
case SCE_NET_ERROR_ENOMEM:
|
||||
break;
|
||||
default:
|
||||
ret = SCE_NET_ERROR_EBADF;
|
||||
break;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
memset(events, 0, event_count * sizeof(*events));
|
||||
|
||||
/* Keep a copy of the original sets for lookup later. */
|
||||
if (readfds)
|
||||
memcpy(&rfds, readfds, sizeof(rfds));
|
||||
if (writefds)
|
||||
memcpy(&wfds, writefds, sizeof(wfds));
|
||||
if (errorfds)
|
||||
memcpy(&efds, errorfds, sizeof(efds))
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Necessary to work with epoll wait. */
|
||||
event_count = 1;
|
||||
ALLOC_EVENTS(1)
|
||||
}
|
||||
|
||||
#undef ALLOC_EVENTS
|
||||
|
||||
if (readfds)
|
||||
FD_ZERO(readfds);
|
||||
if (writefds)
|
||||
FD_ZERO(writefds);
|
||||
if (errorfds)
|
||||
FD_ZERO(errorfds);
|
||||
|
||||
if (timeout)
|
||||
timeout_ms = (int)((timeout->tv_usec / 1000) + (timeout->tv_sec * 1000));
|
||||
|
||||
ret = sceNetEpollWait(epoll_fd, events, event_count, timeout_ms);
|
||||
if (ret <= 0)
|
||||
goto done;
|
||||
|
||||
#define EPOLL_FD_SET(op, in_set, out_set) \
|
||||
if ((event->events & (op)) && FD_ISSET(event->data.fd, (in_set))) \
|
||||
{ \
|
||||
FD_SET(event->data.fd, (out_set)); \
|
||||
j++; \
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < ret; i++)
|
||||
{
|
||||
SceNetEpollEvent *event = &events[i];
|
||||
|
||||
/* Sanity check */
|
||||
if (event->data.fd < 0 || event->data.fd >= nfds)
|
||||
continue;
|
||||
|
||||
EPOLL_FD_SET(SCE_NET_EPOLLIN, &rfds, readfds)
|
||||
EPOLL_FD_SET(SCE_NET_EPOLLOUT, &wfds, writefds)
|
||||
EPOLL_FD_SET(SCE_NET_EPOLLERR, &efds, errorfds)
|
||||
}
|
||||
|
||||
ret = j;
|
||||
|
||||
#undef EPOLL_FD_SET
|
||||
|
||||
done:
|
||||
free(events);
|
||||
sceNetEpollDestroy(epoll_fd);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return select(nfds, readfs, writefds, errorfds, timeout);
|
||||
return select(nfds, readfds, writefds, errorfds, timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef NETWORK_HAVE_POLL
|
||||
int socket_poll(struct pollfd *fds, unsigned nfds, int timeout)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return WSAPoll(fds, nfds, timeout);
|
||||
#elif defined(VITA)
|
||||
int i, j;
|
||||
int epoll_fd;
|
||||
SceNetEpollEvent *events = NULL;
|
||||
int event_count = (int)nfds;
|
||||
int ret = -1;
|
||||
|
||||
if (event_count < 0)
|
||||
return SCE_NET_ERROR_EINVAL;
|
||||
|
||||
epoll_fd = sceNetEpollCreate("socket_poll", 0);
|
||||
if (epoll_fd < 0)
|
||||
return SCE_NET_ERROR_ENOMEM;
|
||||
|
||||
#define ALLOC_EVENTS(count) \
|
||||
events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \
|
||||
if (!events) \
|
||||
{ \
|
||||
ret = SCE_NET_ERROR_ENOMEM; \
|
||||
goto done; \
|
||||
}
|
||||
|
||||
if (event_count)
|
||||
{
|
||||
ALLOC_EVENTS(event_count)
|
||||
|
||||
for (i = 0; i < event_count; i++)
|
||||
{
|
||||
struct pollfd *fd = &fds[i];
|
||||
SceNetEpollEvent *event = &events[i];
|
||||
|
||||
fd->revents = 0;
|
||||
|
||||
if (fd->fd < 0)
|
||||
continue;
|
||||
|
||||
event->events = fd->events;
|
||||
event->data.fd = fd->fd;
|
||||
|
||||
ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,
|
||||
fd->fd, event);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
memset(events, 0, event_count * sizeof(*events));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Necessary to work with epoll wait. */
|
||||
event_count = 1;
|
||||
ALLOC_EVENTS(1)
|
||||
}
|
||||
|
||||
#undef ALLOC_EVENTS
|
||||
|
||||
ret = sceNetEpollWait(epoll_fd, events, event_count, timeout);
|
||||
if (ret <= 0)
|
||||
goto done;
|
||||
|
||||
for (i = 0, j = 0; i < ret; i++)
|
||||
{
|
||||
unsigned k;
|
||||
SceNetEpollEvent *event = &events[i];
|
||||
|
||||
/* Sanity check */
|
||||
if (event->data.fd < 0)
|
||||
continue;
|
||||
|
||||
for (k = 0; k < nfds; k++)
|
||||
{
|
||||
struct pollfd *fd = &fds[k];
|
||||
|
||||
if (fd->fd == event->data.fd)
|
||||
{
|
||||
fd->revents = event->events;
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = j;
|
||||
|
||||
done:
|
||||
free(events);
|
||||
sceNetEpollDestroy(epoll_fd);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return poll(fds, nfds, timeout);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
bool socket_wait(int fd, bool *rd, bool *wr, int timeout)
|
||||
{
|
||||
#ifdef NETWORK_HAVE_POLL
|
||||
struct pollfd fds = {0};
|
||||
|
||||
NET_POLL_FD(fd, &fds);
|
||||
|
||||
if (rd && *rd)
|
||||
{
|
||||
NET_POLL_EVENT(POLLIN, &fds);
|
||||
*rd = false;
|
||||
}
|
||||
if (wr && *wr)
|
||||
{
|
||||
NET_POLL_EVENT(POLLOUT, &fds);
|
||||
*wr = false;
|
||||
}
|
||||
|
||||
if (socket_poll(&fds, 1, timeout) < 0)
|
||||
return false;
|
||||
|
||||
if (rd && NET_POLL_HAS_EVENT(POLLIN, &fds))
|
||||
*rd = true;
|
||||
if (wr && NET_POLL_HAS_EVENT(POLLOUT, &fds))
|
||||
*wr = true;
|
||||
|
||||
return !NET_POLL_HAS_EVENT((POLLERR | POLLNVAL), &fds);
|
||||
#else
|
||||
fd_set rfd, wfd, efd;
|
||||
struct timeval tv, *ptv = NULL;
|
||||
|
||||
FD_ZERO(&rfd);
|
||||
FD_ZERO(&wfd);
|
||||
FD_ZERO(&efd);
|
||||
|
||||
if (rd && *rd)
|
||||
{
|
||||
FD_SET(fd, &rfd);
|
||||
*rd = false;
|
||||
}
|
||||
if (wr && *wr)
|
||||
{
|
||||
FD_SET(fd, &wfd);
|
||||
*wr = false;
|
||||
}
|
||||
FD_SET(fd, &efd);
|
||||
|
||||
if (timeout >= 0)
|
||||
{
|
||||
tv.tv_sec = (unsigned)timeout / 1000;
|
||||
tv.tv_usec = ((unsigned)timeout % 1000) * 1000;
|
||||
ptv = &tv;
|
||||
}
|
||||
|
||||
if (socket_select(fd + 1, &rfd, &wfd, &efd, ptv) < 0)
|
||||
return false;
|
||||
|
||||
if (rd && FD_ISSET(fd, &rfd))
|
||||
*rd = true;
|
||||
if (wr && FD_ISSET(fd, &wfd))
|
||||
*wr = true;
|
||||
|
||||
return !FD_ISSET(fd, &efd);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -350,25 +647,23 @@ ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t size,
|
||||
|
||||
bool socket_bind(int fd, void *data)
|
||||
{
|
||||
int yes = 1;
|
||||
struct addrinfo *res = (struct addrinfo*)data;
|
||||
#ifdef GEKKO
|
||||
net_setsockopt(fd, SOL_SOCKET,
|
||||
SO_REUSEADDR, (const char*)&yes, sizeof(int));
|
||||
#else
|
||||
setsockopt(fd, SOL_SOCKET,
|
||||
SO_REUSEADDR, (const char*)&yes, sizeof(int));
|
||||
#endif
|
||||
if (bind(fd, res->ai_addr, res->ai_addrlen) < 0)
|
||||
return false;
|
||||
return true;
|
||||
struct addrinfo *addr = (struct addrinfo*)data;
|
||||
|
||||
{
|
||||
int on = 1;
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char*)&on, sizeof(on));
|
||||
}
|
||||
|
||||
return !bind(fd, addr->ai_addr, addr->ai_addrlen);
|
||||
}
|
||||
|
||||
int socket_connect(int fd, void *data, bool timeout_enable)
|
||||
{
|
||||
struct addrinfo *addr = (struct addrinfo*)data;
|
||||
|
||||
#if !defined(_WIN32) && !defined(VITA) && !defined(WIIU) && !defined(_3DS) && !defined(GEKKO)
|
||||
#if !defined(_WIN32) && !defined(VITA) && !defined(WIIU) && !defined(_3DS)
|
||||
if (timeout_enable)
|
||||
{
|
||||
struct timeval timeout;
|
||||
@ -377,15 +672,6 @@ int socket_connect(int fd, void *data, bool timeout_enable)
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
|
||||
}
|
||||
#elif defined(GEKKO) && !defined(WIIU)
|
||||
if (timeout_enable)
|
||||
{
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 4;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
net_setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIIU
|
||||
@ -471,62 +757,25 @@ bool socket_connect_with_timeout(int fd, void *data, unsigned timeout)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int domain_get(enum socket_domain type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case SOCKET_DOMAIN_INET:
|
||||
#ifdef VITA
|
||||
return SCE_NET_AF_INET;
|
||||
#else
|
||||
return AF_INET;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_create(
|
||||
const char *name,
|
||||
enum socket_domain domain_type,
|
||||
enum socket_type socket_type,
|
||||
enum socket_protocol protocol_type)
|
||||
{
|
||||
int domain = 0;
|
||||
int type = 0;
|
||||
int protocol = 0;
|
||||
int domain = domain_get(domain_type);
|
||||
#ifdef VITA
|
||||
|
||||
switch (socket_type)
|
||||
switch (domain_type)
|
||||
{
|
||||
case SOCKET_TYPE_DATAGRAM:
|
||||
type = SCE_NET_SOCK_DGRAM;
|
||||
case SOCKET_DOMAIN_INET:
|
||||
domain = AF_INET;
|
||||
break;
|
||||
case SOCKET_TYPE_STREAM:
|
||||
type = SCE_NET_SOCK_STREAM;
|
||||
break;
|
||||
case SOCKET_TYPE_SEQPACKET:
|
||||
/* TODO/FIXME - implement */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (protocol_type)
|
||||
{
|
||||
case SOCKET_PROTOCOL_NONE:
|
||||
protocol = 0;
|
||||
break;
|
||||
case SOCKET_PROTOCOL_TCP:
|
||||
protocol = SCE_NET_IPPROTO_TCP;
|
||||
break;
|
||||
case SOCKET_PROTOCOL_UDP:
|
||||
protocol = SCE_NET_IPPROTO_UDP;
|
||||
break;
|
||||
}
|
||||
|
||||
return sceNetSocket(name, domain, type, protocol);
|
||||
#else
|
||||
switch (socket_type)
|
||||
{
|
||||
case SOCKET_TYPE_DATAGRAM:
|
||||
@ -536,23 +785,27 @@ int socket_create(
|
||||
type = SOCK_STREAM;
|
||||
break;
|
||||
case SOCKET_TYPE_SEQPACKET:
|
||||
default:
|
||||
/* TODO/FIXME - implement */
|
||||
break;
|
||||
}
|
||||
|
||||
switch (protocol_type)
|
||||
{
|
||||
case SOCKET_PROTOCOL_NONE:
|
||||
protocol = 0;
|
||||
break;
|
||||
case SOCKET_PROTOCOL_TCP:
|
||||
protocol = IPPROTO_TCP;
|
||||
break;
|
||||
case SOCKET_PROTOCOL_UDP:
|
||||
protocol = IPPROTO_UDP;
|
||||
break;
|
||||
case SOCKET_PROTOCOL_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VITA
|
||||
return sceNetSocket(name, domain, type, protocol);
|
||||
#else
|
||||
return socket(domain, type, protocol);
|
||||
#endif
|
||||
}
|
||||
@ -561,16 +814,22 @@ void socket_set_target(void *data, socket_target_t *in_addr)
|
||||
{
|
||||
struct sockaddr_in *out_target = (struct sockaddr_in*)data;
|
||||
|
||||
out_target->sin_port = inet_htons(in_addr->port);
|
||||
out_target->sin_family = domain_get(in_addr->domain);
|
||||
#ifdef VITA
|
||||
out_target->sin_addr = inet_aton(in_addr->server);
|
||||
#else
|
||||
switch (in_addr->domain)
|
||||
{
|
||||
case SOCKET_DOMAIN_INET:
|
||||
out_target->sin_family = AF_INET;
|
||||
break;
|
||||
default:
|
||||
out_target->sin_family = 0;
|
||||
break;
|
||||
}
|
||||
#ifndef VITA
|
||||
#ifdef GEKKO
|
||||
out_target->sin_len = 8;
|
||||
out_target->sin_len = 8;
|
||||
#endif
|
||||
|
||||
inet_ptrton(AF_INET, in_addr->server, &out_target->sin_addr);
|
||||
|
||||
#else
|
||||
out_target->sin_addr = inet_aton(in_addr->server);
|
||||
#endif
|
||||
out_target->sin_port = inet_htons(in_addr->port);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user