Merge pull request #14001 from Cthulhu-throwaway/poll

(Network) poll support
This commit is contained in:
LibretroAdmin 2022-06-10 06:47:20 +01:00 committed by GitHub
commit 332074df40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 575 additions and 219 deletions

View File

@ -20,8 +20,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef LIBRETRO_SDK_NETPLAY_COMPAT_H__ #ifndef LIBRETRO_SDK_NET_COMPAT_H__
#define LIBRETRO_SDK_NETPLAY_COMPAT_H__ #define LIBRETRO_SDK_NET_COMPAT_H__
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
@ -46,73 +46,114 @@
#define MSG_NOSIGNAL 0 #define MSG_NOSIGNAL 0
#endif #endif
#elif defined(_XBOX) #if _WIN32_WINNT >= 0x0600
#define NETWORK_HAVE_POLL 1
#endif
#elif defined(_XBOX)
#define NOD3D #define NOD3D
#include <xtl.h> #include <xtl.h>
#include <io.h> #include <io.h>
#elif defined(GEKKO) #elif defined(GEKKO)
#include <network.h> #include <network.h>
#define sendto(s, msg, len, flags, addr, tolen) net_sendto(s, msg, len, 0, addr, 8) #define NETWORK_HAVE_POLL 1
#define socket(domain, type, protocol) net_socket(domain, type, protocol)
#define bind(s, name, namelen) net_bind(s, name, namelen) #define pollfd pollsd
#define listen(s, backlog) net_listen(s, backlog)
#define accept(s, addr, addrlen) net_accept(s, addr, addrlen) #define socket net_socket
#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 getsockopt net_getsockopt #define getsockopt net_getsockopt
#define setsockopt net_setsockopt #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) #elif defined(VITA)
#include <psp2/net/net.h> #include <psp2/net/net.h>
#include <psp2/net/netctl.h> #include <psp2/net/netctl.h>
#define sockaddr_in SceNetSockaddrIn #define NETWORK_HAVE_POLL 1
#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 AF_UNSPEC 0 #define AF_UNSPEC 0
#define INADDR_ANY SCE_NET_INADDR_ANY #define AF_INET SCE_NET_AF_INET
#define INADDR_NONE 0xffffffff
#define SOCK_STREAM SCE_NET_SOCK_STREAM #define SOCK_STREAM SCE_NET_SOCK_STREAM
#define SOCK_DGRAM SCE_NET_SOCK_DGRAM #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 SOL_SOCKET SCE_NET_SOL_SOCKET
#define SO_REUSEADDR SCE_NET_SO_REUSEADDR #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_SNDBUF SCE_NET_SO_SNDBUF
#define SO_RCVBUF SCE_NET_SO_RCVBUF
#define SO_SNDTIMEO SCE_NET_SO_SNDTIMEO #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 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 htonl sceNetHtonl
#define ntohl sceNetNtohl #define ntohl sceNetNtohl
#define htons sceNetHtons #define htons sceNetHtons
#define ntohs sceNetNtohs #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 struct hostent
{ {
char *h_name; char *h_name;
char **h_aliases; char **h_aliases;
int h_addrtype; int h_addrtype;
int h_length; int h_length;
char **h_addr_list; char **h_addr_list;
char *h_addr; char *h_addr;
}; };
struct SceNetInAddr inet_aton(const char *ip_addr); struct SceNetInAddr inet_aton(const char *ip_addr);
@ -138,6 +179,18 @@ struct SceNetInAddr inet_aton(const char *ip_addr);
#include <signal.h> #include <signal.h>
#endif #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 #endif
#include <errno.h> #include <errno.h>
@ -198,6 +251,16 @@ static INLINE bool isinprogress(int bytes)
#include <unistd.h> #include <unistd.h>
#endif #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. /* Compatibility layer for legacy or incomplete BSD socket implementations.
* Only for IPv4. Mostly useful for the consoles which do not support * Only for IPv4. Mostly useful for the consoles which do not support
* anything reasonably modern on the socket API side of things. */ * anything reasonably modern on the socket API side of things. */

View File

@ -23,9 +23,9 @@
#ifndef _LIBRETRO_SDK_NET_SOCKET_H #ifndef _LIBRETRO_SDK_NET_SOCKET_H
#define _LIBRETRO_SDK_NET_SOCKET_H #define _LIBRETRO_SDK_NET_SOCKET_H
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <boolean.h> #include <boolean.h>
#include <string.h>
#include <net/net_compat.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() */ /* TODO: all callers should be converted to socket_set_block() */
bool socket_nonblock(int fd); 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); 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(int fd, const void *data_, size_t size, bool no_signal);
bool socket_send_all_blocking_with_timeout(int fd, bool socket_send_all_blocking_with_timeout(int fd,

View File

@ -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). * The following license statement only applies to this file (net_compat.c).
@ -80,9 +80,7 @@ error:
return NULL; return NULL;
} }
#elif defined(VITA) #elif defined(VITA)
static void *_net_compat_net_memory = NULL;
#define COMPAT_NET_INIT_SIZE 512*1024 #define COMPAT_NET_INIT_SIZE 512*1024
#define INET_ADDRSTRLEN sizeof(struct sockaddr_in)
#define MAX_NAME 512 #define MAX_NAME 512
typedef uint32_t in_addr_t; typedef uint32_t in_addr_t;
@ -92,14 +90,17 @@ struct in_addr
in_addr_t s_addr; in_addr_t s_addr;
}; };
static void *_net_compat_net_memory = NULL;
int retro_epoll_fd = -1;
char *inet_ntoa(struct SceNetInAddr in) 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)) if (!inet_ntop_compat(AF_INET, &in, ip_addr, sizeof(ip_addr)))
strlcpy(ip_addr, "Invalid", sizeof(ip_addr)); strlcpy(ip_addr, "Invalid", sizeof(ip_addr));
return ip_addr; return ip_addr;
} }
struct SceNetInAddr inet_aton(const char *ip_addr) struct SceNetInAddr inet_aton(const char *ip_addr)
@ -107,6 +108,7 @@ struct SceNetInAddr inet_aton(const char *ip_addr)
SceNetInAddr inaddr; SceNetInAddr inaddr;
inet_ptrton(AF_INET, ip_addr, &inaddr); inet_ptrton(AF_INET, ip_addr, &inaddr);
return inaddr; return inaddr;
} }
@ -143,14 +145,15 @@ struct hostent *gethostbyname(const char *name)
return &ent; return &ent;
} }
int retro_epoll_fd;
#elif defined(_3DS) #elif defined(_3DS)
#include <malloc.h> #include <malloc.h>
#include <3ds/types.h> #include <3ds/types.h>
#include <3ds/services/soc.h> #include <3ds/services/soc.h>
#define SOC_ALIGN 0x1000 #define SOC_ALIGN 0x1000
#define SOC_BUFFERSIZE 0x100000 #define SOC_BUFFERSIZE 0x100000
static u32* _net_compat_net_memory;
static u32* _net_compat_net_memory = NULL;
#endif #endif
#if defined(_WIN32) #if defined(_WIN32)
@ -259,8 +262,11 @@ error:
void freeaddrinfo_retro(struct addrinfo *res) void freeaddrinfo_retro(struct addrinfo *res)
{ {
#ifdef HAVE_SOCKET_LEGACY #ifdef HAVE_SOCKET_LEGACY
free(res->ai_addr); if (res)
free(res); {
free(res->ai_addr);
free(res);
}
#else #else
freeaddrinfo(res); freeaddrinfo(res);
#endif #endif
@ -270,10 +276,14 @@ void freeaddrinfo_retro(struct addrinfo *res)
#include <malloc.h> #include <malloc.h>
static OSThread wiiu_net_cmpt_thread; 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); 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; const int buf_size = WIIU_RCVBUF + WIIU_SNDBUF;
void* buf = memalign(128, buf_size); void* buf = memalign(128, buf_size);
if (!buf) return -1; if (!buf) return -1;
@ -300,89 +310,107 @@ static char netmask[16] = {0};
**/ **/
bool network_init(void) bool network_init(void)
{ {
#ifdef _WIN32
WSADATA wsaData;
#endif
static bool inited = false; 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) if (inited)
return true; return true;
#if defined(_WIN32) #if defined(_WIN32)
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) if (WSAStartup(MAKEWORD(2, 2), &wsaData))
{ goto failure;
network_deinit(); #elif defined(__PSL1GHT__) || defined(__PS3__)
return false;
}
#elif defined(__PSL1GHT__) || defined(__PS3__)
int timeout_count = 10;
sysModuleLoad(SYSMODULE_NET); sysModuleLoad(SYSMODULE_NET);
netInitialize(); netInitialize();
if (netCtlInit() < 0) if (netCtlInit() < 0)
return false; goto failure;
for (;;) for (;;)
{ {
int state; int state;
if (netCtlGetState(&state) < 0)
return false;
if (netCtlGetState(&state) < 0)
goto failure;
if (state == NET_CTL_STATE_IPObtained) if (state == NET_CTL_STATE_IPObtained)
break; break;
if (!(timeout_count--))
goto failure;
retro_sleep(500); retro_sleep(500);
timeout_count--;
if (timeout_count < 0)
return 0;
} }
#elif defined(VITA) #elif defined(VITA)
SceNetInitParam initparam;
if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT) if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT)
{ {
SceNetInitParam param;
_net_compat_net_memory = malloc(COMPAT_NET_INIT_SIZE); _net_compat_net_memory = malloc(COMPAT_NET_INIT_SIZE);
initparam.memory = _net_compat_net_memory; param.memory = _net_compat_net_memory;
initparam.size = COMPAT_NET_INIT_SIZE; param.size = COMPAT_NET_INIT_SIZE;
initparam.flags = 0; param.flags = 0;
if (sceNetInit(&param) < 0)
sceNetInit(&initparam); goto failure;
sceNetCtlInit(); sceNetCtlInit();
}
retro_epoll_fd = sceNetEpollCreate("epoll", 0); retro_epoll_fd = sceNetEpollCreate("epoll", 0);
if (retro_epoll_fd < 0)
goto failure;
}
#elif defined(GEKKO) #elif defined(GEKKO)
if (if_config(localip, netmask, gateway, true, 10) < 0) if (if_config(localip, netmask, gateway, true, 10) < 0)
return false; goto failure;
#elif defined(WIIU) #elif defined(WIIU)
stack = malloc(4096);
if (!stack)
goto failure;
socket_lib_init(); socket_lib_init();
const int stack_size = 4096; if (OSCreateThread(&wiiu_net_cmpt_thread, wiiu_net_cmpt_thread_entry,
void* stack = malloc(stack_size); 0, NULL, stack+4096, 4096, 3,
if (stack && OSCreateThread(&wiiu_net_cmpt_thread, OS_THREAD_ATTRIB_AFFINITY_ANY))
wiiu_net_cmpt_thread_entry, 0, NULL, stack+stack_size, stack_size, {
3, OS_THREAD_ATTRIB_AFFINITY_ANY)) {
OSSetThreadName(&wiiu_net_cmpt_thread, "Network compat thread"); OSSetThreadName(&wiiu_net_cmpt_thread, "Network compat thread");
OSSetThreadDeallocator(&wiiu_net_cmpt_thread, OSSetThreadDeallocator(&wiiu_net_cmpt_thread,
wiiu_net_cmpt_thread_cleanup); wiiu_net_cmpt_thread_cleanup);
OSResumeThread(&wiiu_net_cmpt_thread); OSResumeThread(&wiiu_net_cmpt_thread);
} }
else
{
free(stack);
goto failure;
}
#elif defined(_3DS) #elif defined(_3DS)
_net_compat_net_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE); _net_compat_net_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
if (!_net_compat_net_memory) if (!_net_compat_net_memory)
return false; goto failure;
Result ret = socInit(_net_compat_net_memory, SOC_BUFFERSIZE);//WIFI init
if (ret != 0) /* WIFI init */
return false; if (socInit(_net_compat_net_memory, SOC_BUFFERSIZE))
goto failure;
#else #else
signal(SIGPIPE, SIG_IGN); /* Do not like SIGPIPE killing our app. */ signal(SIGPIPE, SIG_IGN); /* Do not like SIGPIPE killing our app. */
#endif #endif
inited = true; inited = true;
return 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(); netFinalizeNetwork();
sysModuleUnload(SYSMODULE_NET); sysModuleUnload(SYSMODULE_NET);
#elif defined(VITA) #elif defined(VITA)
if (retro_epoll_fd >= 0)
{
sceNetEpollDestroy(retro_epoll_fd);
retro_epoll_fd = -1;
}
sceNetCtlTerm(); sceNetCtlTerm();
sceNetTerm(); 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) #elif defined(GEKKO) && !defined(HW_DOL)
net_deinit(); net_deinit();
#elif defined(_3DS) #elif defined(_3DS)
socExit(); 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 #endif
} }

View File

@ -20,8 +20,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#include <compat/msvc.h> #include <compat/msvc.h>
@ -37,13 +38,13 @@
int socket_init(void **address, uint16_t port, const char *server, enum socket_type type) int socket_init(void **address, uint16_t port, const char *server, enum socket_type type)
{ {
char port_buf[16]; char port_buf[6];
struct addrinfo hints = {0}; struct addrinfo hints = {0};
struct addrinfo **addrinfo = (struct addrinfo**)address; struct addrinfo **addrinfo = (struct addrinfo**)address;
struct addrinfo *addr = NULL; struct addrinfo *addr = NULL;
if (!network_init()) if (!network_init())
goto error; return -1;
switch (type) switch (type)
{ {
@ -61,31 +62,27 @@ int socket_init(void **address, uint16_t port, const char *server, enum socket_t
if (!server) if (!server)
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
port_buf[0] = '\0';
snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port); snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);
if (getaddrinfo_retro(server, port_buf, &hints, addrinfo) != 0) if (getaddrinfo_retro(server, port_buf, &hints, addrinfo))
goto error; return -1;
addr = (struct addrinfo*)*addrinfo;
addr = *addrinfo;
if (!addr) if (!addr)
goto error; return -1;
return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); 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)) if ((*addrinfo = addr = addr->ai_next))
return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); 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, 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) 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; int i = !block;
setsockopt(fd, SOL_SOCKET, SO_NBIO, &i, sizeof(int));
return true; return !setsockopt(fd, SOL_SOCKET, SO_NBIO, &i, sizeof(i));
#elif defined(_WIN32)
u_long mode = !block;
return ioctlsocket(fd, FIONBIO, &mode) == 0;
#elif defined(GEKKO) #elif defined(GEKKO)
u32 set = block; u32 i = !block;
return net_ioctl(fd, FIONBIO, &set) >= 0;
return !net_ioctl(fd, FIONBIO, &i);
#else #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 #endif
} }
@ -215,27 +221,318 @@ int socket_close(int fd)
#endif #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) fd_set *errorfds, struct timeval *timeout)
{ {
#if !defined(__PSL1GHT__) && defined(__PS3__) #if !defined(__PSL1GHT__) && defined(__PS3__)
return socketselect(nfds, readfs, writefds, errorfds, timeout); return socketselect(nfds, readfds, writefds, errorfds, timeout);
#elif defined(VITA) #elif defined(VITA)
extern int retro_epoll_fd; int i, j;
SceNetEpollEvent ev = {0}; 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; if (nfds < 0 || nfds > 1024)
ev.data.fd = nfds; 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); if (readfds && FD_ISSET(i, readfds))
sceNetEpollControl(retro_epoll_fd, SCE_NET_EPOLL_CTL_DEL, nfds, NULL); event_count++;
return ret; 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 #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 #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) bool socket_bind(int fd, void *data)
{ {
int yes = 1; struct addrinfo *addr = (struct addrinfo*)data;
struct addrinfo *res = (struct addrinfo*)data;
#ifdef GEKKO {
net_setsockopt(fd, SOL_SOCKET, int on = 1;
SO_REUSEADDR, (const char*)&yes, sizeof(int));
#else setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
setsockopt(fd, SOL_SOCKET, (char*)&on, sizeof(on));
SO_REUSEADDR, (const char*)&yes, sizeof(int)); }
#endif
if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) return !bind(fd, addr->ai_addr, addr->ai_addrlen);
return false;
return true;
} }
int socket_connect(int fd, void *data, bool timeout_enable) int socket_connect(int fd, void *data, bool timeout_enable)
{ {
struct addrinfo *addr = (struct addrinfo*)data; 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) if (timeout_enable)
{ {
struct timeval timeout; 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)); 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 #endif
#ifdef WIIU #ifdef WIIU
@ -471,62 +757,25 @@ bool socket_connect_with_timeout(int fd, void *data, unsigned timeout)
return true; 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( int socket_create(
const char *name, const char *name,
enum socket_domain domain_type, enum socket_domain domain_type,
enum socket_type socket_type, enum socket_type socket_type,
enum socket_protocol protocol_type) enum socket_protocol protocol_type)
{ {
int domain = 0;
int type = 0; int type = 0;
int protocol = 0; int protocol = 0;
int domain = domain_get(domain_type);
#ifdef VITA
switch (socket_type) switch (domain_type)
{ {
case SOCKET_TYPE_DATAGRAM: case SOCKET_DOMAIN_INET:
type = SCE_NET_SOCK_DGRAM; domain = AF_INET;
break; break;
case SOCKET_TYPE_STREAM: default:
type = SCE_NET_SOCK_STREAM;
break;
case SOCKET_TYPE_SEQPACKET:
/* TODO/FIXME - implement */
break; 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) switch (socket_type)
{ {
case SOCKET_TYPE_DATAGRAM: case SOCKET_TYPE_DATAGRAM:
@ -536,23 +785,27 @@ int socket_create(
type = SOCK_STREAM; type = SOCK_STREAM;
break; break;
case SOCKET_TYPE_SEQPACKET: case SOCKET_TYPE_SEQPACKET:
default:
/* TODO/FIXME - implement */ /* TODO/FIXME - implement */
break; break;
} }
switch (protocol_type) switch (protocol_type)
{ {
case SOCKET_PROTOCOL_NONE:
protocol = 0;
break;
case SOCKET_PROTOCOL_TCP: case SOCKET_PROTOCOL_TCP:
protocol = IPPROTO_TCP; protocol = IPPROTO_TCP;
break; break;
case SOCKET_PROTOCOL_UDP: case SOCKET_PROTOCOL_UDP:
protocol = IPPROTO_UDP; protocol = IPPROTO_UDP;
break; break;
case SOCKET_PROTOCOL_NONE:
default:
break;
} }
#ifdef VITA
return sceNetSocket(name, domain, type, protocol);
#else
return socket(domain, type, protocol); return socket(domain, type, protocol);
#endif #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; struct sockaddr_in *out_target = (struct sockaddr_in*)data;
out_target->sin_port = inet_htons(in_addr->port); switch (in_addr->domain)
out_target->sin_family = domain_get(in_addr->domain); {
#ifdef VITA case SOCKET_DOMAIN_INET:
out_target->sin_addr = inet_aton(in_addr->server); out_target->sin_family = AF_INET;
#else break;
default:
out_target->sin_family = 0;
break;
}
#ifndef VITA
#ifdef GEKKO #ifdef GEKKO
out_target->sin_len = 8; out_target->sin_len = 8;
#endif #endif
inet_ptrton(AF_INET, in_addr->server, &out_target->sin_addr); inet_ptrton(AF_INET, in_addr->server, &out_target->sin_addr);
#else
out_target->sin_addr = inet_aton(in_addr->server);
#endif #endif
out_target->sin_port = inet_htons(in_addr->port);
} }