2016-03-02 23:09:09 +01:00
|
|
|
/* Copyright (C) 2010-2016 The RetroArch team
|
2015-01-23 06:29:36 +01:00
|
|
|
*
|
2016-03-02 23:09:09 +01:00
|
|
|
* ---------------------------------------------------------------------------------------
|
|
|
|
* The following license statement only applies to this file (net_compat.c).
|
|
|
|
* ---------------------------------------------------------------------------------------
|
2015-01-23 06:29:36 +01:00
|
|
|
*
|
2016-03-02 23:09:09 +01:00
|
|
|
* Permission is hereby granted, free of charge,
|
|
|
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
|
|
|
* to deal in the Software without restriction, including without limitation the rights to
|
|
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
|
|
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
2015-01-23 06:29:36 +01:00
|
|
|
*
|
2016-03-02 23:09:09 +01:00
|
|
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
|
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
2015-01-23 06:29:36 +01:00
|
|
|
*/
|
|
|
|
|
2015-03-20 22:23:08 +01:00
|
|
|
#include <stdint.h>
|
2015-03-23 23:55:43 +01:00
|
|
|
#include <sys/types.h>
|
2015-01-23 06:29:36 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2015-09-05 21:13:58 +02:00
|
|
|
#include <net/net_compat.h>
|
2015-09-29 02:41:41 +02:00
|
|
|
#include <compat/strl.h>
|
2015-09-05 21:13:58 +02:00
|
|
|
|
2015-09-29 00:40:53 +02:00
|
|
|
#if 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;
|
|
|
|
|
2015-09-29 02:41:41 +02:00
|
|
|
struct in_addr
|
|
|
|
{
|
2015-09-29 00:40:53 +02:00
|
|
|
in_addr_t s_addr;
|
|
|
|
};
|
|
|
|
|
|
|
|
char *inet_ntoa(struct SceNetInAddr in)
|
|
|
|
{
|
2015-09-29 02:41:41 +02:00
|
|
|
static char ip_addr[INET_ADDRSTRLEN + 1];
|
2015-09-29 00:40:53 +02:00
|
|
|
|
|
|
|
if(sceNetInetNtop(AF_INET, &in, ip_addr, INET_ADDRSTRLEN) == NULL)
|
2015-09-29 02:41:41 +02:00
|
|
|
strlcpy(ip_addr, "Invalid", sizeof(ip_addr));
|
2015-09-29 00:40:53 +02:00
|
|
|
|
|
|
|
return ip_addr;
|
|
|
|
}
|
|
|
|
|
2015-09-29 02:41:41 +02:00
|
|
|
struct SceNetInAddr inet_aton(const char *ip_addr)
|
2015-09-29 00:40:53 +02:00
|
|
|
{
|
2015-09-29 02:41:41 +02:00
|
|
|
SceNetInAddr inaddr;
|
2015-09-29 00:40:53 +02:00
|
|
|
|
2015-09-29 02:41:41 +02:00
|
|
|
sceNetInetPton(AF_INET, ip_addr, &inaddr);
|
|
|
|
return inaddr;
|
2015-09-29 00:40:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int inet_addr(const char *cp)
|
|
|
|
{
|
2015-09-29 02:41:41 +02:00
|
|
|
return inet_aton(cp).s_addr;
|
2015-09-29 00:40:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct hostent *gethostbyname(const char *name)
|
|
|
|
{
|
2015-09-29 02:41:41 +02:00
|
|
|
int err;
|
|
|
|
static struct hostent ent;
|
|
|
|
static char sname[MAX_NAME] = "";
|
|
|
|
static struct SceNetInAddr saddr = { 0 };
|
|
|
|
static char *addrlist[2] = { (char *) &saddr, NULL };
|
|
|
|
int rid = sceNetResolverCreate("resolver", NULL, 0);
|
|
|
|
|
|
|
|
if(rid < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
err = sceNetResolverStartNtoa(rid, name, &saddr, 0,0,0);
|
|
|
|
sceNetResolverDestroy(rid);
|
|
|
|
if(err < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
addrlist[0] = inet_ntoa(saddr);
|
|
|
|
ent.h_name = sname;
|
|
|
|
ent.h_aliases = 0;
|
|
|
|
ent.h_addrtype = AF_INET;
|
|
|
|
ent.h_length = sizeof(struct in_addr);
|
|
|
|
ent.h_addr_list = addrlist;
|
|
|
|
ent.h_addr = addrlist[0];
|
|
|
|
|
|
|
|
return &ent;
|
2015-09-29 00:40:53 +02:00
|
|
|
}
|
|
|
|
|
2015-10-26 03:18:13 +01:00
|
|
|
int retro_epoll_fd;
|
2015-09-29 00:40:53 +02:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2015-10-26 03:18:13 +01:00
|
|
|
int getaddrinfo_retro(const char *node, const char *service,
|
2015-01-23 06:29:36 +01:00
|
|
|
const struct addrinfo *hints,
|
|
|
|
struct addrinfo **res)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_SOCKET_LEGACY
|
2015-02-02 19:15:59 +01:00
|
|
|
struct sockaddr_in *in_addr = NULL;
|
2015-01-23 06:29:36 +01:00
|
|
|
struct addrinfo *info = (struct addrinfo*)calloc(1, sizeof(*info));
|
|
|
|
if (!info)
|
2015-02-02 19:15:59 +01:00
|
|
|
goto error;
|
2015-01-23 06:29:36 +01:00
|
|
|
|
|
|
|
info->ai_family = AF_INET;
|
|
|
|
info->ai_socktype = hints->ai_socktype;
|
|
|
|
|
|
|
|
in_addr = (struct sockaddr_in*)calloc(1, sizeof(*in_addr));
|
|
|
|
|
|
|
|
if (!in_addr)
|
2015-02-02 19:15:59 +01:00
|
|
|
goto error;
|
2015-01-23 06:29:36 +01:00
|
|
|
|
2015-02-02 19:15:59 +01:00
|
|
|
info->ai_addrlen = sizeof(*in_addr);
|
2015-01-23 06:29:36 +01:00
|
|
|
in_addr->sin_family = AF_INET;
|
2015-02-02 19:15:59 +01:00
|
|
|
in_addr->sin_port = htons(strtoul(service, NULL, 0));
|
2015-01-23 06:29:36 +01:00
|
|
|
|
|
|
|
if (!node && (hints->ai_flags & AI_PASSIVE))
|
|
|
|
in_addr->sin_addr.s_addr = INADDR_ANY;
|
|
|
|
else if (node && isdigit(*node))
|
|
|
|
in_addr->sin_addr.s_addr = inet_addr(node);
|
|
|
|
else if (node && !isdigit(*node))
|
|
|
|
{
|
2015-02-02 19:15:59 +01:00
|
|
|
struct hostent *host = (struct hostent*)gethostbyname(node);
|
|
|
|
|
2015-01-23 06:29:36 +01:00
|
|
|
if (!host || !host->h_addr_list[0])
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
in_addr->sin_addr.s_addr = inet_addr(host->h_addr_list[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
info->ai_addr = (struct sockaddr*)in_addr;
|
|
|
|
*res = info;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2015-02-02 19:15:59 +01:00
|
|
|
if (in_addr)
|
|
|
|
free(in_addr);
|
|
|
|
if (info)
|
|
|
|
free(info);
|
2015-01-23 06:29:36 +01:00
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
return getaddrinfo(node, service, hints, res);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-10-26 03:18:13 +01:00
|
|
|
void freeaddrinfo_retro(struct addrinfo *res)
|
2015-01-23 06:29:36 +01:00
|
|
|
{
|
|
|
|
#ifdef HAVE_SOCKET_LEGACY
|
|
|
|
free(res->ai_addr);
|
|
|
|
free(res);
|
|
|
|
#else
|
|
|
|
freeaddrinfo(res);
|
|
|
|
#endif
|
|
|
|
}
|
2015-01-23 11:11:22 +01:00
|
|
|
|
|
|
|
bool socket_nonblock(int fd)
|
|
|
|
{
|
2015-09-29 00:40:53 +02:00
|
|
|
#if defined(__CELLOS_LV2__) || defined(VITA)
|
2015-01-23 11:11:22 +01:00
|
|
|
int i = 1;
|
|
|
|
setsockopt(fd, SOL_SOCKET, SO_NBIO, &i, sizeof(int));
|
|
|
|
return true;
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
u_long mode = 1;
|
|
|
|
return ioctlsocket(fd, FIONBIO, &mode) == 0;
|
|
|
|
#else
|
|
|
|
return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == 0;
|
|
|
|
#endif
|
|
|
|
}
|
2015-01-23 11:36:45 +01:00
|
|
|
|
|
|
|
int socket_close(int fd)
|
|
|
|
{
|
|
|
|
#if defined(_WIN32) && !defined(_XBOX360)
|
|
|
|
/* WinSock has headers from the stone age. */
|
|
|
|
return closesocket(fd);
|
|
|
|
#elif defined(__CELLOS_LV2__)
|
|
|
|
return socketclose(fd);
|
2015-09-29 00:40:53 +02:00
|
|
|
#elif defined(VITA)
|
|
|
|
return sceNetSocketClose(fd);
|
2015-01-23 11:36:45 +01:00
|
|
|
#else
|
|
|
|
return close(fd);
|
|
|
|
#endif
|
|
|
|
}
|
2015-01-23 11:44:13 +01:00
|
|
|
|
|
|
|
int socket_select(int nfds, fd_set *readfs, fd_set *writefds,
|
|
|
|
fd_set *errorfds, struct timeval *timeout)
|
|
|
|
{
|
|
|
|
#if defined(__CELLOS_LV2__)
|
|
|
|
return socketselect(nfds, readfs, writefds, errorfds, timeout);
|
2015-09-29 00:40:53 +02:00
|
|
|
#elif defined(VITA)
|
2015-09-29 02:41:41 +02:00
|
|
|
SceNetEpollEvent ev = {0};
|
|
|
|
|
|
|
|
ev.events = PSP2_NET_EPOLLIN | PSP2_NET_EPOLLHUP;
|
|
|
|
ev.data.fd = nfds;
|
|
|
|
|
2015-10-26 03:18:13 +01:00
|
|
|
if((sceNetEpollControl(retro_epoll_fd, PSP2_NET_EPOLL_CTL_ADD, nfds, &ev)))
|
2015-09-29 02:41:41 +02:00
|
|
|
{
|
2015-10-26 03:18:13 +01:00
|
|
|
int ret = sceNetEpollWait(retro_epoll_fd, &ev, 1, 0);
|
|
|
|
sceNetEpollControl(retro_epoll_fd, PSP2_NET_EPOLL_CTL_DEL, nfds, NULL);
|
2015-09-29 02:41:41 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return 0;
|
2015-01-23 11:44:13 +01:00
|
|
|
#else
|
|
|
|
return select(nfds, readfs, writefds, errorfds, timeout);
|
|
|
|
#endif
|
|
|
|
}
|
2015-01-23 19:43:40 +01:00
|
|
|
|
|
|
|
int socket_send_all_blocking(int fd, const void *data_, size_t size)
|
|
|
|
{
|
|
|
|
const uint8_t *data = (const uint8_t*)data_;
|
|
|
|
|
|
|
|
while (size)
|
|
|
|
{
|
|
|
|
ssize_t ret = send(fd, (const char*)data, size, 0);
|
|
|
|
if (ret <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
data += ret;
|
|
|
|
size -= ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int socket_receive_all_blocking(int fd, void *data_, size_t size)
|
|
|
|
{
|
|
|
|
const uint8_t *data = (const uint8_t*)data_;
|
|
|
|
|
|
|
|
while (size)
|
|
|
|
{
|
|
|
|
ssize_t ret = recv(fd, (char*)data, size, 0);
|
|
|
|
if (ret <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
data += ret;
|
|
|
|
size -= ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2015-01-28 08:55:02 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* network_init:
|
|
|
|
*
|
|
|
|
* Platform specific socket library initialization.
|
|
|
|
*
|
|
|
|
* Returns: true (1) if successful, otherwise false (0).
|
|
|
|
**/
|
|
|
|
bool network_init(void)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
WSADATA wsaData;
|
|
|
|
#endif
|
|
|
|
static bool inited = false;
|
|
|
|
if (inited)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
|
|
|
|
{
|
|
|
|
network_deinit();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
|
|
|
cellSysmoduleLoadModule(CELL_SYSMODULE_NET);
|
|
|
|
sys_net_initialize_network();
|
2015-09-29 00:40:53 +02:00
|
|
|
#elif defined(VITA)
|
|
|
|
SceNetInitParam initparam;
|
|
|
|
/* Init Net */
|
2015-09-29 02:41:41 +02:00
|
|
|
if (sceNetShowNetstat() == PSP2_NET_ERROR_ENOTINIT)
|
|
|
|
{
|
|
|
|
_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);
|
|
|
|
//printf("sceNetInit(): 0x%08X\n", ret);
|
|
|
|
|
|
|
|
/* Init NetCtl */
|
|
|
|
sceNetCtlInit();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//printf("Net is already initialized.\n");
|
2015-09-29 00:40:53 +02:00
|
|
|
}
|
|
|
|
|
2015-10-26 03:18:13 +01:00
|
|
|
retro_epoll_fd = sceNetEpollCreate("epoll", 0);
|
|
|
|
//printf("Epoll %x\n",retro_epoll_fd);
|
2015-01-28 08:55:02 +01:00
|
|
|
#else
|
|
|
|
signal(SIGPIPE, SIG_IGN); /* Do not like SIGPIPE killing our app. */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
inited = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* network_deinit:
|
|
|
|
*
|
|
|
|
* Deinitialize platform specific socket libraries.
|
|
|
|
**/
|
|
|
|
void network_deinit(void)
|
|
|
|
{
|
|
|
|
#if defined(_WIN32)
|
|
|
|
WSACleanup();
|
|
|
|
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
|
|
|
sys_net_finalize_network();
|
|
|
|
cellSysmoduleUnloadModule(CELL_SYSMODULE_NET);
|
2015-09-29 00:40:53 +02:00
|
|
|
#elif defined(VITA)
|
2015-09-29 02:41:41 +02:00
|
|
|
sceNetCtlTerm();
|
|
|
|
sceNetTerm();
|
2015-09-29 00:40:53 +02:00
|
|
|
|
2015-09-29 02:41:41 +02:00
|
|
|
if (_net_compat_net_memory)
|
|
|
|
{
|
|
|
|
free(_net_compat_net_memory);
|
|
|
|
_net_compat_net_memory = NULL;
|
|
|
|
}
|
2015-01-28 08:55:02 +01:00
|
|
|
#endif
|
|
|
|
}
|