(Network) poll support

This commit is contained in:
Cthulhu-throwaway 2022-06-02 05:17:04 -03:00
parent 9fbf1c846f
commit d4324d9a0d
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.
*/
#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. */

View File

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

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).
@ -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(&param) < 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
}

View File

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