Add newlib wrapper for sockets...

... fix several bugs, etc.
This commit is contained in:
TuxSH 2018-01-30 23:59:56 +01:00 committed by plutoo
parent 88dbc66d01
commit 0b92bb76b0
10 changed files with 884 additions and 81 deletions

View File

@ -36,7 +36,7 @@ extern "C" {
#include "switch/services/apm.h" #include "switch/services/apm.h"
#include "switch/services/applet.h" #include "switch/services/applet.h"
#include "switch/services/audout.h" #include "switch/services/audout.h"
#include "switch/services/bsd.h" //#include "switch/services/bsd.h" Use switch/runtime/devices/socket.h instead
#include "switch/services/fatal.h" #include "switch/services/fatal.h"
#include "switch/services/time.h" #include "switch/services/time.h"
#include "switch/services/usb.h" #include "switch/services/usb.h"
@ -63,6 +63,7 @@ extern "C" {
#include "switch/runtime/devices/usb_comms.h" #include "switch/runtime/devices/usb_comms.h"
#include "switch/runtime/devices/fs_dev.h" #include "switch/runtime/devices/fs_dev.h"
#include "switch/runtime/devices/romfs_dev.h" #include "switch/runtime/devices/romfs_dev.h"
#include "switch/runtime/devices/socket.h"
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -14,8 +14,6 @@
/// IPC output header magic /// IPC output header magic
#define SFCO_MAGIC 0x4f434653 #define SFCO_MAGIC 0x4f434653
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
///@name IPC request building ///@name IPC request building
///@{ ///@{
@ -47,16 +45,7 @@ typedef struct {
* @param cmd IPC command structure. * @param cmd IPC command structure.
*/ */
static inline void ipcInitialize(IpcCommand* cmd) { static inline void ipcInitialize(IpcCommand* cmd) {
cmd->NumSend = 0; *cmd = (IpcCommand){0};
cmd->NumRecv = 0;
cmd->NumTransfer = 0;
cmd->NumStaticIn = 0;
cmd->NumStaticOut = 0;
cmd->SendPid = false;
cmd->NumHandlesCopy = 0;
cmd->NumHandlesMove = 0;
} }
/// IPC buffer descriptor. /// IPC buffer descriptor.

View File

@ -65,6 +65,7 @@ enum {
LibnxError_WeirdKernel, LibnxError_WeirdKernel,
LibnxError_IncompatSysVer, LibnxError_IncompatSysVer,
LibnxError_InitFail_Time, LibnxError_InitFail_Time,
LibnxError_TooManyDevOpTabs,
}; };
/// libnx nvidia error codes /// libnx nvidia error codes

View File

@ -0,0 +1,29 @@
#pragma once
#include "../../types.h"
/// Configuration structure for socketInitalize
typedef struct {
u32 bsdsockets_version; ///< Observed 1 on 2.0 LibAppletWeb, 2 on 3.0.
u32 tcp_tx_buf_size; ///< Size of the TCP transfer (send) buffer (initial or fixed).
u32 tcp_rx_buf_size; ///< Size of the TCP recieve buffer (initial or fixed).
u32 tcp_tx_buf_max_size; ///< Maximum size of the TCP transfer (send) buffer. If it is 0, the size of the buffer is fixed to its initial value.
u32 tcp_rx_buf_max_size; ///< Maximum size of the TCP receive buffer. If it is 0, the size of the buffer is fixed to its initial value.
u32 udp_tx_buf_size; ///< Size of the UDP transfer (send) buffer (typically 0x2400 bytes).
u32 udp_rx_buf_size; ///< Size of the UDP receive buffer (typically 0xA500 bytes).
u32 sb_efficiency; ///< Number of buffers for each socket (standard values range from 1 to 8).
} SocketInitConfig;
const SocketInitConfig *socketGetDefaultInitConfig(void);
Result socketInitialize(const SocketInitConfig *config);
Result socketGetLastResult(void);
void socketExit(void);
static inline Result socketInitializeDefault(void)
{
return socketInitialize(socketGetDefaultInitConfig());
}

View File

@ -27,13 +27,13 @@ typedef struct {
u32 udp_rx_buf_size; ///< Size of the UDP receive buffer (typically 0xA500 bytes). u32 udp_rx_buf_size; ///< Size of the UDP receive buffer (typically 0xA500 bytes).
u32 sb_efficiency; ///< Number of buffers for each socket (standard values range from 1 to 8). u32 sb_efficiency; ///< Number of buffers for each socket (standard values range from 1 to 8).
} BsdBufferConfig; } BsdInitConfig;
__thread Result t_bsdResult; ///< Last Switch "result", per-thread extern __thread Result g_bsdResult; ///< Last Switch "result", per-thread
__thread int t_bsdErrno; ///< Last errno, per-thread extern __thread int g_bsdErrno; ///< Last errno, per-thread
const BsdBufferConfig *bsdGetDefaultBufferConfig(void); const BsdInitConfig *bsdGetDefaultConfig(void);
Result bsdInitialize(const BsdBufferConfig *config); Result bsdInitialize(const BsdInitConfig *config);
void bsdExit(void); void bsdExit(void);
int bsdSocket(int domain, int type, int protocol); int bsdSocket(int domain, int type, int protocol);
@ -46,16 +46,16 @@ ssize_t bsdRecv(int sockfd, void *buf, size_t len, int flags);
ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags); ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags);
ssize_t bsdSendTo(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); ssize_t bsdSendTo(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
int bsdAccept(int sockfd, struct sockaddr *address, socklen_t *addrlen); int bsdAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int bsdConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); int bsdConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int bsdGetPeerName(int sockfd, struct sockaddr *address, socklen_t *addrlen); int bsdGetPeerName(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int bsdGetSockName(int sockfd, struct sockaddr *address, socklen_t *addrlen); int bsdGetSockName(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int bsdGetSockOpt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int bsdGetSockOpt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int bsdListen(int sockfd, int backlog); int bsdListen(int sockfd, int backlog);
// The following two functions are supposed to be variadic // The following two functions are supposed to be variadic
int bsdIoctl(int fd, int request, void *data); int bsdIoctl(int fd, int request, void *data);
int bsdFnctl(int fd, int cmd, int flags); int bsdFcntl(int fd, int cmd, int flags);
int bsdSetSockOpt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); int bsdSetSockOpt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
int bsdShutdown(int sockfd, int how); int bsdShutdown(int sockfd, int how);
int bsdShutdownAllSockets(int how); int bsdShutdownAllSockets(int how);
@ -68,5 +68,5 @@ int bsdDuplicateSocket(int sockfd);
static inline Result bsdInitializeDefault(void) static inline Result bsdInitializeDefault(void)
{ {
return bsdInitialize(bsdGetDefaultBufferConfig()); return bsdInitialize(bsdGetDefaultConfig());
} }

View File

@ -67,7 +67,8 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__BEGIN_DECLS __BEGIN_DECLS
int ioctl(int, unsigned long, ...); // Modified declaration
int ioctl(int fd, int request, ...);
__END_DECLS __END_DECLS
#endif /* !_SYS_IOCCOM_H_ */ #endif /* !_SYS_IOCCOM_H_ */

View File

@ -544,11 +544,11 @@ ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t send(int sockfd, const void* buf, size_t len, int flags); ssize_t send(int sockfd, const void* buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
int accept(int sockfd, struct sockaddr *address, socklen_t *addrlen); int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int getpeername(int sockfd, struct sockaddr *address, socklen_t *addrlen); int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int getsockname(int sockfd, struct sockaddr *address, socklen_t *addrlen); int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int listen(int sockfd, int backlog); int listen(int sockfd, int backlog);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

View File

@ -1,4 +1,5 @@
// TuxSH: removed definitions under _KERNEL ifdef blocks, modify the prototype of some functions, some other cleanup, etc. // TuxSH: removed definitions under _KERNEL ifdef blocks, modify the prototype of some functions, some other cleanup, etc.
// Note: I didn't provide <vm/vm_param.h>
#ifndef __BSD_VISIBLE #ifndef __BSD_VISIBLE
#define __BSD_VISIBLE #define __BSD_VISIBLE
#endif #endif
@ -311,7 +312,7 @@ struct ctlname {
// Modified: added arg names, etc // Modified: added arg names, etc
__BEGIN_DECLS __BEGIN_DECLS
int sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp, const void *newp, size_t newlen); int sysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp, const void *newp, size_t newlen);
int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, const void *newp, size_t newlen); int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, const void *newp, size_t newlen);
int sysctlnametomib(const char *name, int *mibp, size_t *sizep); int sysctlnametomib(const char *name, int *mibp, size_t *sizep);
__END_DECLS __END_DECLS

View File

@ -0,0 +1,787 @@
#include <stdarg.h>
#include <errno.h>
#include <ctype.h>
//#include <stdlib.h>
#include <string.h>
#include <malloc.h>
//#include <sys/dirent.h>
#include <sys/iosupport.h>
#include <sys/param.h>
#include <unistd.h>
#include <sys/select.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <net/bpf.h>
#include <arpa/inet.h>
#include "runtime/devices/socket.h"
#include "services/bsd.h"
#include "result.h"
static int _socketOpen(struct _reent *r, void *fdptr, const char *path, int flags, int mode);
static int _socketClose(struct _reent *r, void *fdptr);
static ssize_t _socketWrite(struct _reent *r, void *fdptr, const char *buf, size_t count);
static ssize_t _socketRead(struct _reent *r, void *fdptr, char *buf, size_t count);
static const devoptab_t g_socketDevoptab = {
.name = "soc",
.structSize = sizeof(int),
.open_r = _socketOpen,
.close_r = _socketClose,
.write_r = _socketWrite,
.read_r = _socketRead,
.seek_r = NULL,
.fstat_r = NULL,
.stat_r = NULL,
.link_r = NULL,
.unlink_r = NULL,
.chdir_r = NULL,
.rename_r = NULL,
.mkdir_r = NULL,
.dirStateSize = 0,
.diropen_r = NULL,
.dirreset_r = NULL,
.dirnext_r = NULL,
.dirclose_r = NULL,
.statvfs_r = NULL,
.ftruncate_r = NULL,
.fsync_r = NULL,
.deviceData = 0,
.chmod_r = NULL,
.fchmod_r = NULL,
.rmdir_r = NULL,
};
static const SocketInitConfig g_defaultSocketInitConfig = {
.bsdsockets_version = 1,
.tcp_tx_buf_size = 0x8000,
.tcp_rx_buf_size = 0x10000,
.tcp_tx_buf_max_size = 0x40000,
.tcp_rx_buf_max_size = 0x40000,
.udp_tx_buf_size = 0x2400,
.udp_rx_buf_size = 0xA500,
.sb_efficiency = 4,
};
static int _socketParseBsdResult(struct _reent *r, int ret) {
int errno_;
if(ret != -1)
return ret; // Nothing to do
else {
if(g_bsdErrno == -1) {
// We're using -1 to signal Switch error codes.
// Note: all of the bsd:u/s handlers return 0.
switch(g_bsdResult) {
case 0xD201:
errno_ = ENFILE;
case 0xD401:
errno_ = EFAULT;
break;
case 0x10601:
errno_ = EBUSY;
break;
default:
errno_ = EPIPE;
break;
}
}
else
errno_ = g_bsdErrno; // Nintendo actually used the Linux errno definitions for their FreeBSD build :)
}
if(r == NULL)
errno = errno_;
else
r->_errno = errno_;
return -1;
}
static int _socketGetFd(int fd) {
__handle *handle = __get_handle(fd);
if(handle == NULL) {
errno = EBADF;
return -1;
}
if(strcmp(devoptab_list[handle->device]->name, "soc") != 0) {
errno = ENOTSOCK;
return -1;
}
return *(int *)handle->fileStruct;
}
static int _socketOpen(struct _reent *r, void *fdptr, const char *path, int flags, int mode) {
(void)mode;
int ret = _socketParseBsdResult(r, bsdOpen(path, flags));
if(ret == -1)
return ret;
*(int *)fdptr = ret;
return 0;
}
static int _socketClose(struct _reent *r, void *fdptr) {
int fd = *(int *)fdptr;
return _socketParseBsdResult(r, bsdClose(fd));
}
static ssize_t _socketWrite(struct _reent *r, void *fdptr, const char *buf, size_t count) {
int fd = *(int *)fdptr;
ssize_t ret = bsdWrite(fd, buf, count);
_socketParseBsdResult(r, (int)ret);
return ret;
}
static ssize_t _socketRead(struct _reent *r, void *fdptr, char *buf, size_t count) {
int fd = *(int *)fdptr;
ssize_t ret = bsdRead(fd, buf, count);
_socketParseBsdResult(r, (int)ret);
return ret;
}
// Adapted from ctrulib
static int _socketInetAtonDetail(int *outBase, size_t *outNumBytes, const char *cp, struct in_addr *inp) {
int base;
u32 val;
int c;
char bytes[4];
size_t num_bytes = 0;
c = *cp;
for(;;) {
if(!isdigit(c)) return 0;
val = 0;
base = 10;
if(c == '0') {
c = *++cp;
if(c == 'x' || c == 'X') {
base = 16;
c = *++cp;
}
else base = 8;
}
for(;;) {
if(isdigit(c)) {
if(base == 8 && c >= '8') return 0;
val *= base;
val += c - '0';
c = *++cp;
}
else if(base == 16 && isxdigit(c)) {
val *= base;
val += c + 10 - (islower(c) ? 'a' : 'A');
c = *++cp;
}
else break;
}
if(c == '.') {
if(num_bytes > 3) return 0;
if(val > 0xFF) return 0;
bytes[num_bytes++] = val;
c = *++cp;
}
else break;
}
if(c != 0) {
*outNumBytes = num_bytes;
*outBase = base;
return 0;
}
switch(num_bytes) {
case 0:
break;
case 1:
if(val > 0xFFFFFF) return 0;
val |= bytes[0] << 24;
break;
case 2:
if(val > 0xFFFF) return 0;
val |= bytes[0] << 24;
val |= bytes[1] << 16;
break;
case 3:
if(val > 0xFF) return 0;
val |= bytes[0] << 24;
val |= bytes[1] << 16;
val |= bytes[2] << 8;
break;
}
if(inp)
inp->s_addr = htonl(val);
*outNumBytes = num_bytes;
*outBase = base;
return 1;
}
const SocketInitConfig *socketGetDefaultInitConfig(void) {
return &g_defaultSocketInitConfig;
}
Result socketInitialize(const SocketInitConfig *config) {
Result ret = 0;
BsdInitConfig bcfg = {
.version = config->bsdsockets_version,
.tcp_tx_buf_size = config->tcp_tx_buf_size,
.tcp_rx_buf_size = config->tcp_rx_buf_size,
.tcp_tx_buf_max_size = config->tcp_tx_buf_max_size,
.tcp_rx_buf_max_size = config->tcp_rx_buf_max_size,
.udp_tx_buf_size = config->udp_tx_buf_size,
.udp_rx_buf_size = config->udp_rx_buf_size,
.sb_efficiency = config->sb_efficiency,
};
int dev = FindDevice("soc:");
if(dev != -1)
return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
ret = bsdInitialize(&bcfg);
if(R_SUCCEEDED(ret))
dev = AddDevice(&g_socketDevoptab);
if(dev == -1) {
socketExit();
return MAKERESULT(Module_Libnx, LibnxError_TooManyDevOpTabs);
}
return ret;
}
void socketExit(void) {
RemoveDevice("soc:");
bsdExit();
}
Result socketGetLastResult(void) {
return g_bsdResult;
}
/*
It is way too complicated and inefficient to use devoptab with bsdSelect.
We're therefore implementing select with poll.
Code copied from libctru.
*/
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
struct pollfd *pollinfo;
nfds_t numfds = 0;
size_t i, j;
int rc, found;
if(nfds >= FD_SETSIZE || nfds < 0) {
errno = EINVAL;
return -1;
}
for(i = 0; i < nfds; ++i) {
if((readfds && FD_ISSET(i, readfds))
|| (writefds && FD_ISSET(i, writefds))
|| (exceptfds && FD_ISSET(i, exceptfds)))
++numfds;
}
pollinfo = (struct pollfd*)malloc(numfds * sizeof(struct pollfd));
if(pollinfo == NULL) {
errno = ENOMEM;
return -1;
}
for(i = 0, j = 0; i < nfds; ++i) {
if((readfds && FD_ISSET(i, readfds))
|| (writefds && FD_ISSET(i, writefds))
|| (exceptfds && FD_ISSET(i, exceptfds))) {
pollinfo[j].fd = i;
pollinfo[j].events = 0;
pollinfo[j].revents = 0;
if(readfds && FD_ISSET(i, readfds))
pollinfo[j].events |= POLLIN;
if(writefds && FD_ISSET(i, writefds))
pollinfo[j].events |= POLLOUT;
++j;
}
}
if(timeout)
rc = poll(pollinfo, numfds, timeout->tv_sec*1000 + timeout->tv_usec/1000);
else
rc = poll(pollinfo, numfds, -1);
if(rc < 0) {
free(pollinfo);
return rc;
}
for(i = 0, j = 0, rc = 0; i < nfds; ++i) {
found = 0;
if((readfds && FD_ISSET(i, readfds))
|| (writefds && FD_ISSET(i, writefds))
|| (exceptfds && FD_ISSET(i, exceptfds))) {
if(readfds && FD_ISSET(i, readfds)) {
if(pollinfo[j].events & (POLLIN|POLLHUP))
found = 1;
else
FD_CLR(i, readfds);
}
if(writefds && FD_ISSET(i, writefds)) {
if(pollinfo[j].events & (POLLOUT|POLLHUP))
found = 1;
else
FD_CLR(i, writefds);
}
if(exceptfds && FD_ISSET(i, exceptfds)) {
if(pollinfo[j].events & POLLERR)
found = 1;
else
FD_CLR(i, exceptfds);
}
if(found)
++rc;
++j;
}
}
free(pollinfo);
return rc;
}
// This is much saner than select.
int poll(struct pollfd *fds, nfds_t nfds, int timeout) {
struct pollfd *fds2;
int ret = 0;
if(fds == NULL) {
errno = EFAULT;
return -1;
}
fds2 = (struct pollfd *)malloc(nfds * sizeof(struct pollfd));
if(fds2 == NULL) {
errno = ENOMEM;
return -1;
}
for(nfds_t i = 0; i < nfds; i++) {
fds2[i].events = fds[i].events;
fds2[i].revents = fds[i].revents;
fds2[i].fd = _socketGetFd(fds[i].fd);
if(fds2[i].fd == -1) {
ret = -1;
break;
}
}
if(ret != -1)
ret = _socketParseBsdResult(NULL, bsdPoll(fds2, nfds, timeout));
if(ret != -1) {
for(nfds_t i = 0; i < nfds; i++) {
fds[i].events = fds2[i].events;
fds[i].revents = fds2[i].revents;
}
}
free(fds2);
return ret;
}
int sysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp, const void *newp, size_t newlen) {
return _socketParseBsdResult(NULL, bsdSysctl(name, namelen, oldp, oldlenp, newp, newlen));
}
int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, const void *newp, size_t newlen) {
int mib[CTL_MAXNAME + 2]; // +2 because most of the relevant code I've seen uses +2 as well
size_t miblen = CTL_MAXNAME + 2;
if(sysctlnametomib(name, mib, &miblen) == -1)
return -1;
return sysctl(mib, miblen, oldp, oldlenp, newp, newlen);
}
int sysctlnametomib(const char *name, int *mibp, size_t *sizep) {
int oid[2] = {0, 3}; // sysctl.name2oid
int ret;
size_t oldlenp;
if(name == NULL || mibp == NULL || sizep == NULL) {
errno = EFAULT;
return -1;
}
oldlenp = 4 * (*sizep);
ret = sysctl(oid, 2, mibp, &oldlenp, name, strlen(name));
*sizep = oldlenp / 4;
return ret;
}
int socket(int domain, int type, int protocol) {
int ret, fd, dev;
dev = FindDevice("soc:");
if(dev == -1)
return -1;
fd = __alloc_handle(dev);
if(fd == -1)
return -1;
ret = _socketParseBsdResult(NULL, bsdSocket(domain, type, protocol));
if(ret == -1) {
__release_handle(fd);
return -1;
}
else {
*(int *)__get_handle(fd)->fileStruct = ret;
return fd;
}
}
ssize_t recv(int sockfd, void *buf, size_t len, int flags) {
ssize_t ret;
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
ret = bsdRecv(sockfd, buf, len, flags);
return _socketParseBsdResult(NULL, (int)ret);
}
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) {
ssize_t ret;
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
ret = bsdRecvFrom(sockfd, buf, len, flags, src_addr, addrlen);
return _socketParseBsdResult(NULL, (int)ret);
}
ssize_t send(int sockfd, const void* buf, size_t len, int flags) {
ssize_t ret;
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
ret = bsdSend(sockfd, buf, len, flags);
return _socketParseBsdResult(NULL, (int)ret);
}
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
ssize_t ret;
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
ret = bsdSendTo(sockfd, buf, len, flags, dest_addr, addrlen);
return _socketParseBsdResult(NULL, (int)ret);
}
int accept(int sockfd, struct sockaddr *address, socklen_t *addrlen) {
int ret, fd, dev;
fd = _socketGetFd(sockfd);
if(fd == -1)
return -1;
dev = __get_handle(sockfd)->device;
sockfd = fd;
fd = __alloc_handle(dev);
if(fd == -1)
return -1;
ret = _socketParseBsdResult(NULL, bsdAccept(sockfd, address, addrlen));
if(ret == -1) {
__release_handle(fd);
return -1;
}
else {
*(int *)__get_handle(fd)->fileStruct = ret;
return fd;
}
}
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
return _socketParseBsdResult(NULL, bsdBind(sockfd, addr, addrlen));
}
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
return _socketParseBsdResult(NULL, bsdConnect(sockfd, addr, addrlen));
}
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
return _socketParseBsdResult(NULL, bsdGetPeerName(sockfd, addr, addrlen));
}
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
return _socketParseBsdResult(NULL, bsdGetSockName(sockfd, addr, addrlen));
}
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) {
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
return _socketParseBsdResult(NULL, bsdGetSockOpt(sockfd, level, optname, optval, optlen));
}
int listen(int sockfd, int backlog) {
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
return _socketParseBsdResult(NULL, bsdListen(sockfd, backlog));
}
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) {
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
return _socketParseBsdResult(NULL, bsdSetSockOpt(sockfd, level, optname, optval, optlen));
}
int ioctl(int fd, int request, ...) {
void *data;
va_list args;
va_start(args, request);
data = (request & IOC_INOUT) ? va_arg(args, void *) : NULL;
va_end(args);
if(data == NULL && (request & IOC_INOUT) && IOCPARM_LEN(request) != 0) {
errno = EFAULT;
return -1;
}
fd = request != FIONBIO ? _socketGetFd(fd) : fd;
if(fd == -1)
return -1;
switch(request) {
case FIONBIO: {
// See note in fcntl (below)
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
return -1;
flags = *(int *)data != 0 ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK);
return fcntl(fd, F_SETFL, 0);
}
case BIOCSETF:
case BIOCSETWF:
case BIOCSETFNR: {
int ret;
struct bpf_program *prog = (struct bpf_program *)data;
if(prog->bf_len > BPF_MAXBUFSIZE) {
errno = EINVAL;
return -1;
}
struct bpf_program_serialized *prog_ser = (struct bpf_program_serialized *)malloc(sizeof(struct bpf_program_serialized));
if(prog_ser == NULL) {
errno = ENOMEM;
return -1;
}
prog_ser->bf_len = prog->bf_len;
memcpy(prog_ser->bf_insns, prog->bf_insns, prog->bf_len);
request = _IOC(request & IOC_DIRMASK, IOCGROUP(request), IOCBASECMD(request), sizeof(struct bpf_program_serialized));
ret = bsdIoctl(fd, request, prog_ser);
free(prog_ser);
return _socketParseBsdResult(NULL, ret);
}
default:
return _socketParseBsdResult(NULL, bsdIoctl(fd, request, data));
}
}
int fcntl(int fd, int cmd, ...) {
va_list args;
int flags;
/*
bsd:u/s only supports F_GETFL and F_SETFL with the O_NONBLOCK flag (or 0).
F_GETFL is implemented using a custom, non-whitelisted IOCTL, whereas
F_SETFL is implemented using FIONBIO.
*/
if(cmd != F_GETFL && cmd != F_SETFL)
return EOPNOTSUPP;
va_start(args, cmd);
flags = va_arg(args, int);
va_end(args);
fd = _socketGetFd(fd);
if(fd == -1)
return -1;
return _socketParseBsdResult(NULL, bsdFcntl(fd, cmd, flags));
}
int shutdown(int sockfd, int how) {
sockfd = _socketGetFd(sockfd);
if(sockfd == -1)
return -1;
return _socketParseBsdResult(NULL, bsdShutdown(sockfd, how));
}
int sockatmark(int sockfd) {
int atmark;
return ioctl(sockfd, SIOCATMARK, &atmark) == -1 ? -1 : atmark;
}
int socketpair(int domain, int type, int protocol, int sv[2]) {
// Unimplementable, function definition written for compliance
errno = ENOSYS;
return -1;
}
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) {
if(msg == NULL) {
errno = EFAULT;
return -1;
}
struct mmsghdr msgvec = {
.msg_hdr = *msg,
.msg_len = 1,
};
return recvmmsg(sockfd, &msgvec, 1, flags, NULL);
}
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) {
if(msg == NULL) {
errno = EFAULT;
return -1;
}
struct mmsghdr msgvec = {
.msg_hdr = *msg,
.msg_len = 1,
};
return sendmmsg(sockfd, &msgvec, 1, flags);
}
int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags) {
//TODO: do the necessary RE & implement it
errno = ENOSYS;
return -1;
}
int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) {
//TODO: do the necessary RE & implement it
errno = ENOSYS;
return -1;
}
// Adapted from ctrulib
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) {
const u8 *ip = src;
char *p;
size_t i;
unsigned int n;
if(af == AF_INET) {
errno = EAFNOSUPPORT;
return NULL;
}
if(size < INET_ADDRSTRLEN) {
errno = ENOSPC;
return NULL;
}
for(p = dst, i = 0; i < 4; ++i) {
if(i > 0) *p++ = '.';
n = ip[i];
if(n >= 100) {
*p++ = n/100 + '0';
n %= 100;
}
if(n >= 10 || ip[i] >= 100) {
*p++ = n/10 + '0';
n %= 10;
}
*p++ = n + '0';
}
*p = 0;
return dst;
}
int inet_pton(int af, const char *src, void *dst) {
int base;
size_t numBytes;
int ret = _socketInetAtonDetail(&base, &numBytes, src, (struct in_addr *)dst);
return (ret == 1 && base == 10 && numBytes == 4) ? 1 : 0;
}
char *inet_ntoa(struct in_addr in) {
static char buffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &in.s_addr, buffer, INET_ADDRSTRLEN);
return buffer;
}
int inet_aton(const char *cp, struct in_addr *inp) {
int base;
size_t numBytes;
return _socketInetAtonDetail(&base, &numBytes, cp, inp);
}
in_addr_t inet_addr(const char *cp) {
struct in_addr addr = { .s_addr = INADDR_BROADCAST };
inet_aton(cp, &addr);
return addr.s_addr;
}
long gethostid(void) {
return INADDR_LOOPBACK; //FIXME
}
int gethostname(char *name, size_t namelen)
{
//FIXME
long hostid = gethostid();
const char *hostname = inet_ntop(AF_INET, &hostid, name, namelen);
return hostname == NULL ? -1 : 0;
}

View File

@ -20,8 +20,8 @@
#include <net/if.h> #include <net/if.h>
#include <net/if_media.h> #include <net/if_media.h>
__thread Result t_bsdResult; __thread Result g_bsdResult;
__thread int t_bsdErrno; __thread int g_bsdErrno;
static Service g_bsdSrv; static Service g_bsdSrv;
static Service g_bsdMonitor; static Service g_bsdMonitor;
@ -29,7 +29,7 @@ static u64 g_bsdClientPid = -1;
static TransferMemory g_bsdTmem; static TransferMemory g_bsdTmem;
static const BsdBufferConfig g_defaultBsdBufferConfig = { static const BsdInitConfig g_defaultBsdInitConfig = {
.version = 1, .version = 1,
.tcp_tx_buf_size = 0x8000, .tcp_tx_buf_size = 0x8000,
@ -48,8 +48,7 @@ static const BsdBufferConfig g_defaultBsdBufferConfig = {
Should the transfer memory be smaller than that, the BSD sockets service would only send Should the transfer memory be smaller than that, the BSD sockets service would only send
ZeroWindow packets (for TCP), resulting in a transfer rate not exceeding 1 byte/s. ZeroWindow packets (for TCP), resulting in a transfer rate not exceeding 1 byte/s.
*/ */
static size_t _bsdGetTransferMemSizeForConfig(const BsdBufferConfig *config) static size_t _bsdGetTransferMemSizeForConfig(const BsdInitConfig *config) {
{
u32 tcp_tx_buf_max_size = config->tcp_tx_buf_max_size != 0 ? config->tcp_tx_buf_max_size : config->tcp_tx_buf_size; u32 tcp_tx_buf_max_size = config->tcp_tx_buf_max_size != 0 ? config->tcp_tx_buf_max_size : config->tcp_tx_buf_size;
u32 tcp_rx_buf_max_size = config->tcp_rx_buf_max_size != 0 ? config->tcp_rx_buf_max_size : config->tcp_rx_buf_size; u32 tcp_rx_buf_max_size = config->tcp_rx_buf_max_size != 0 ? config->tcp_rx_buf_max_size : config->tcp_rx_buf_size;
u32 sum = tcp_tx_buf_max_size + tcp_rx_buf_max_size + config->udp_tx_buf_size + config->udp_rx_buf_size; u32 sum = tcp_tx_buf_max_size + tcp_rx_buf_max_size + config->udp_tx_buf_size + config->udp_rx_buf_size;
@ -58,7 +57,7 @@ static size_t _bsdGetTransferMemSizeForConfig(const BsdBufferConfig *config)
return (size_t)(config->sb_efficiency * sum); return (size_t)(config->sb_efficiency * sum);
} }
static Result _bsdRegisterClient(Service* srv, TransferMemory* tmem, const BsdBufferConfig *config, u64* pid_out) { static Result _bsdRegisterClient(Service* srv, TransferMemory* tmem, const BsdInitConfig *config, u64* pid_out) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcSendPid(&c); ipcSendPid(&c);
@ -67,7 +66,7 @@ static Result _bsdRegisterClient(Service* srv, TransferMemory* tmem, const BsdBu
struct { struct {
u64 magic; u64 magic;
u64 cmd_id; u64 cmd_id;
BsdBufferConfig config; BsdInitConfig config;
u64 pid_reserved; u64 pid_reserved;
u64 tmem_sz; u64 tmem_sz;
} *raw; } *raw;
@ -93,8 +92,8 @@ static Result _bsdRegisterClient(Service* srv, TransferMemory* tmem, const BsdBu
} *resp = r.Raw; } *resp = r.Raw;
*pid_out = resp->pid; *pid_out = resp->pid;
t_bsdResult = rc = resp->result; g_bsdResult = rc = resp->result;
t_bsdErrno = 0; g_bsdErrno = 0;
} }
return rc; return rc;
@ -128,8 +127,8 @@ static Result _bsdStartMonitor(Service* srv, u64 pid) {
u64 result; u64 result;
} *resp = r.Raw; } *resp = r.Raw;
t_bsdResult = rc = resp->result; g_bsdResult = rc = resp->result;
t_bsdErrno = 0; g_bsdErrno = 0;
} }
return rc; return rc;
@ -155,26 +154,25 @@ static int _bsdDispatchBasicCommand(IpcCommand *c, IpcParsedCommand *rOut) {
rc = resp->result; rc = resp->result;
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
t_bsdErrno = resp->errno_; ret = resp->ret;
t_bsdResult = rc = resp->ret; g_bsdErrno = (ret < 0) ? resp->errno_ : 0;
} }
} }
if (R_FAILED(rc)) if (R_FAILED(rc))
t_bsdErrno = -1; g_bsdErrno = -1;
if(rOut != NULL) if(rOut != NULL)
*rOut = r; *rOut = r;
g_bsdResult = rc;
return ret; return ret;
} }
static int _bsdDispatchCommandWithOutAddrlen(IpcCommand *c, socklen_t *addrlen) static int _bsdDispatchCommandWithOutAddrlen(IpcCommand *c, socklen_t *addrlen) {
{
IpcParsedCommand r; IpcParsedCommand r;
int ret = _bsdDispatchBasicCommand(c, &r); int ret = _bsdDispatchBasicCommand(c, &r);
if(ret != -1 && addrlen != NULL) if(ret != -1 && addrlen != NULL) {
{
struct { struct {
BsdIpcResponseBase bsd_resp; BsdIpcResponseBase bsd_resp;
socklen_t addrlen; socklen_t addrlen;
@ -231,11 +229,11 @@ static int _bsdSocketCreationCommand(u32 cmd_id, int domain, int type, int proto
return _bsdDispatchBasicCommand(&c, NULL); return _bsdDispatchBasicCommand(&c, NULL);
} }
const BsdBufferConfig *bsdGetDefaultBufferConfig(void) { const BsdInitConfig *bsdGetDefaultInitConfig(void) {
return &g_defaultBsdBufferConfig; return &g_defaultBsdInitConfig;
} }
Result bsdInitialize(const BsdBufferConfig *config) { Result bsdInitialize(const BsdInitConfig *config) {
const char* bsd_srv = "bsd:s"; const char* bsd_srv = "bsd:s";
if(serviceIsActive(&g_bsdSrv) || serviceIsActive(&g_bsdMonitor)) if(serviceIsActive(&g_bsdSrv) || serviceIsActive(&g_bsdMonitor))
@ -309,19 +307,19 @@ int bsdSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, st
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendBuffer(&c, readfds, sizeof(fd_set), 0); ipcAddSendBuffer(&c, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddSendStatic(&c, readfds, sizeof(fd_set), 0); ipcAddSendStatic(&c, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddSendBuffer(&c, writefds, sizeof(fd_set), 0); ipcAddSendBuffer(&c, writefds, writefds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddSendStatic(&c, writefds, sizeof(fd_set), 0); ipcAddSendStatic(&c, writefds, writefds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddSendBuffer(&c, exceptfds, sizeof(fd_set), 0); ipcAddSendBuffer(&c, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddSendStatic(&c, exceptfds, sizeof(fd_set), 0); ipcAddSendStatic(&c, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddRecvBuffer(&c, readfds, sizeof(fd_set), 0); ipcAddRecvBuffer(&c, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddRecvStatic(&c, readfds, sizeof(fd_set), 0); ipcAddRecvStatic(&c, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddRecvBuffer(&c, writefds, sizeof(fd_set), 0); ipcAddRecvBuffer(&c, writefds, writefds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddRecvStatic(&c, writefds, sizeof(fd_set), 0); ipcAddRecvStatic(&c, writefds, writefds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddRecvBuffer(&c, exceptfds, sizeof(fd_set), 0); ipcAddRecvBuffer(&c, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddRecvStatic(&c, exceptfds, sizeof(fd_set), 0); ipcAddRecvStatic(&c, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 0);
struct { struct {
u64 magic; u64 magic;
@ -346,11 +344,11 @@ int bsdPoll(struct pollfd *fds, nfds_t nfds, int timeout) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendBuffer(&c, fds, sizeof(struct pollfd), 0); ipcAddSendBuffer(&c, fds, nfds * sizeof(struct pollfd), 0);
ipcAddSendStatic(&c, fds, sizeof(struct pollfd), 0); ipcAddSendStatic(&c, fds, nfds * sizeof(struct pollfd), 0);
ipcAddRecvBuffer(&c, fds, sizeof(struct pollfd), 0); ipcAddRecvBuffer(&c, fds, nfds * sizeof(struct pollfd), 0);
ipcAddRecvStatic(&c, fds, sizeof(struct pollfd), 0); ipcAddRecvStatic(&c, fds, nfds * sizeof(struct pollfd), 0);
struct { struct {
u64 magic; u64 magic;
@ -395,8 +393,7 @@ int bsdSysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp
IpcParsedCommand r; IpcParsedCommand r;
int ret = _bsdDispatchBasicCommand(&c, &r); int ret = _bsdDispatchBasicCommand(&c, &r);
if(ret != -1 && oldlenp != NULL) if(ret != -1 && oldlenp != NULL) {
{
struct { struct {
BsdIpcResponseBase bsd_resp; BsdIpcResponseBase bsd_resp;
size_t oldlenp; size_t oldlenp;
@ -519,12 +516,14 @@ int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
struct { struct {
u64 magic; u64 magic;
u64 cmd_id; u64 cmd_id;
int sockfd;
} *raw; } *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 13; raw->cmd_id = 13;
raw->sockfd = sockfd;
return _bsdDispatchBasicCommand(&c, NULL); return _bsdDispatchBasicCommand(&c, NULL);
} }
@ -619,8 +618,7 @@ int bsdIoctl(int fd, int request, void *data) {
int bufcount = 1; int bufcount = 1;
switch(request) { switch(request) {
case SIOCGIFCONF: case SIOCGIFCONF: {
{
struct ifconf *data_ = (struct ifconf *)data; struct ifconf *data_ = (struct ifconf *)data;
in1 = out1 = data; in1 = out1 = data;
in1sz = out1sz = sizeof(struct ifconf); in1sz = out1sz = sizeof(struct ifconf);
@ -630,8 +628,7 @@ int bsdIoctl(int fd, int request, void *data) {
break; break;
} }
case SIOCGIFMEDIA: case SIOCGIFMEDIA:
case SIOCGIFXMEDIA: case SIOCGIFXMEDIA: {
{
struct ifmediareq *data_ = (struct ifmediareq *)data; struct ifmediareq *data_ = (struct ifmediareq *)data;
in1 = out1 = data; in1 = out1 = data;
in1sz = out1sz = sizeof(struct ifmediareq); in1sz = out1sz = sizeof(struct ifmediareq);
@ -641,18 +638,15 @@ int bsdIoctl(int fd, int request, void *data) {
break; break;
} }
// Generic ioctl // Generic ioctl
default: default: {
{
void *data_ = NULL; void *data_ = NULL;
if(request & IOC_INOUT) if(request & IOC_INOUT)
data_ = data; data_ = data;
if(request & IOC_IN) if(request & IOC_IN) {
{
in1 = data_; in1 = data_;
in1sz = IOCPARM_LEN(request); in1sz = IOCPARM_LEN(request);
} }
if(request & IOC_OUT) if(request & IOC_OUT) {
{
out1 = data_; out1 = data_;
out1sz = IOCPARM_LEN(request); out1sz = IOCPARM_LEN(request);
} }
@ -699,12 +693,12 @@ int bsdIoctl(int fd, int request, void *data) {
return _bsdDispatchBasicCommand(&c, NULL); return _bsdDispatchBasicCommand(&c, NULL);
} }
int bsdFnctl(int fd, int cmd, int flags) { int bsdFcntl(int fd, int cmd, int flags) {
IpcCommand c; IpcCommand c;
if(cmd == F_GETFL || cmd == F_SETFL) { if(cmd != F_GETFL && cmd != F_SETFL) {
t_bsdResult = 0; g_bsdResult = 0;
t_bsdErrno = EINVAL; g_bsdErrno = EOPNOTSUPP;
return -1; return -1;
} }