diff --git a/libctru/source/services/soc/soc_accept.c b/libctru/source/services/soc/soc_accept.c index 355a744..cf64863 100644 --- a/libctru/source/services/soc/soc_accept.c +++ b/libctru/source/services/soc/soc_accept.c @@ -3,12 +3,39 @@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - int ret=0; - int tmp_addrlen=0x1c; + int ret = 0; + int tmp_addrlen = 0x1c; + int fd, dev; + __handle *handle; u32 *cmdbuf = getThreadCommandBuffer(); u8 tmpaddr[0x1c]; u32 saved_threadstorage[2]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + + dev = FindDevice("soc:"); + if(dev < 0) + { + SOCU_errno = -ENODEV; + return -1; + } + + fd = __alloc_handle(sizeof(__handle) + sizeof(Handle)); + if(fd < 0) + { + SOCU_errno = -ENOMEM; + return -1; + } + + handle = __get_handle(fd); + handle->device = dev; + handle->fileStruct = ((void *)handle) + sizeof(__handle); + memset(tmpaddr, 0, 0x1c); cmdbuf[0] = 0x00040082; @@ -22,22 +49,37 @@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) cmdbuf[0x100>>2] = (tmp_addrlen<<14) | 2; cmdbuf[0x104>>2] = (u32)tmpaddr; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + if((ret = svcSendSyncRequest(SOCU_handle)) != 0) + { + __release_handle(fd); + return ret; + } cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = _net_convert_error(cmdbuf[2]); - if(ret<0)SOCU_errno = ret; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); - if(ret>=0 && addr!=NULL) + if(ret < 0) + SOCU_errno = ret; + + if(ret >= 0 && addr != NULL) { addr->sa_family = tmpaddr[1]; - if(*addrlen > tmpaddr[0])*addrlen = tmpaddr[0]; + if(*addrlen > tmpaddr[0]) + *addrlen = tmpaddr[0]; memcpy(addr->sa_data, &tmpaddr[2], *addrlen - 2); } - if(ret<0)return -1; - return ret; + if(ret < 0) + { + __release_handle(fd); + return -1; + } + else + *(Handle*)handle->fileStruct = ret; + + return fd; } diff --git a/libctru/source/services/soc/soc_bind.c b/libctru/source/services/soc/soc_bind.c index dba52e5..dd37f7e 100644 --- a/libctru/source/services/soc/soc_bind.c +++ b/libctru/source/services/soc/soc_bind.c @@ -9,6 +9,13 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) u32 *cmdbuf = getThreadCommandBuffer(); u8 tmpaddr[0x1c]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + memset(tmpaddr, 0, 0x1c); if(addr->sa_family == AF_INET) diff --git a/libctru/source/services/soc/soc_closesocket.c b/libctru/source/services/soc/soc_closesocket.c index 85dcd52..37e1923 100644 --- a/libctru/source/services/soc/soc_closesocket.c +++ b/libctru/source/services/soc/soc_closesocket.c @@ -3,19 +3,12 @@ int closesocket(int sockfd) { - int ret=0; - u32 *cmdbuf = getThreadCommandBuffer(); + int fd = soc_get_fd(sockfd); + if(fd < 0) + { + SOCU_errno = fd; + return -1; + } - cmdbuf[0] = 0x000B0042; - cmdbuf[1] = (u32)sockfd; - cmdbuf[2] = 0x20; - - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; - - ret = (int)cmdbuf[1]; - if(ret==0)ret =_net_convert_error(cmdbuf[2]); - SOCU_errno = ret; - - if(ret!=0)return -1; - return 0; + return close(sockfd); } diff --git a/libctru/source/services/soc/soc_common.c b/libctru/source/services/soc/soc_common.c index 8814453..c41491c 100644 --- a/libctru/source/services/soc/soc_common.c +++ b/libctru/source/services/soc/soc_common.c @@ -1,5 +1,6 @@ #include "soc_common.h" #include +#include Handle SOCU_handle = 0; int SOCU_errno = 0; diff --git a/libctru/source/services/soc/soc_common.h b/libctru/source/services/soc/soc_common.h index 5cf5dee..f325bf7 100644 --- a/libctru/source/services/soc/soc_common.h +++ b/libctru/source/services/soc/soc_common.h @@ -1,13 +1,30 @@ #pragma once +#include #include +#include #include <3ds/types.h> #include <3ds/svc.h> #include <3ds/srv.h> #include <3ds/services/soc.h> +int __alloc_handle(int size); +__handle *__get_handle(int fd); +void __release_handle(int fd); + extern Handle SOCU_handle; extern int SOCU_errno; extern Handle socMemhandle; +static inline int +soc_get_fd(int fd) +{ + __handle *handle = __get_handle(fd); + if(handle == NULL) + return -ENODEV; + if(strcmp(devoptab_list[handle->device]->name, "soc") != 0) + return -ENOTSOCK; + return *(Handle*)handle->fileStruct; +} + s32 _net_convert_error(s32 sock_retval); diff --git a/libctru/source/services/soc/soc_connect.c b/libctru/source/services/soc/soc_connect.c index 9577c77..cf01759 100644 --- a/libctru/source/services/soc/soc_connect.c +++ b/libctru/source/services/soc/soc_connect.c @@ -9,6 +9,13 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) u32 *cmdbuf = getThreadCommandBuffer(); u8 tmpaddr[0x1c]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + memset(tmpaddr, 0, 0x1c); if(addr->sa_family == AF_INET) diff --git a/libctru/source/services/soc/soc_fcntl.c b/libctru/source/services/soc/soc_fcntl.c index fcc873b..23b5f8a 100644 --- a/libctru/source/services/soc/soc_fcntl.c +++ b/libctru/source/services/soc/soc_fcntl.c @@ -28,7 +28,7 @@ static int to_3ds(int flags) return newflags; } -int fcntl(int fd, int cmd, ...) +int fcntl(int sockfd, int cmd, ...) { int ret = 0; int arg = 0; @@ -36,6 +36,13 @@ int fcntl(int fd, int cmd, ...) va_list args; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + if(cmd != F_GETFL && cmd != F_SETFL) { SOCU_errno = -EINVAL; @@ -60,7 +67,7 @@ int fcntl(int fd, int cmd, ...) va_end(args); cmdbuf[0] = 0x001300C2; - cmdbuf[1] = (u32)fd; + cmdbuf[1] = (u32)sockfd; cmdbuf[2] = (u32)cmd; cmdbuf[3] = (u32)arg; cmdbuf[4] = 0x20; diff --git a/libctru/source/services/soc/soc_getpeername.c b/libctru/source/services/soc/soc_getpeername.c index f20be86..80af375 100644 --- a/libctru/source/services/soc/soc_getpeername.c +++ b/libctru/source/services/soc/soc_getpeername.c @@ -8,6 +8,13 @@ int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) u32 saved_threadstorage[2]; u8 tmpaddr[0x1c]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + cmdbuf[0] = 0x00180082; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = 0x1c; diff --git a/libctru/source/services/soc/soc_getsockname.c b/libctru/source/services/soc/soc_getsockname.c index 80812af..dceda3a 100644 --- a/libctru/source/services/soc/soc_getsockname.c +++ b/libctru/source/services/soc/soc_getsockname.c @@ -8,6 +8,13 @@ int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) u32 saved_threadstorage[2]; u8 tmpaddr[0x1c]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + cmdbuf[0] = 0x00170082; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = 0x1c; diff --git a/libctru/source/services/soc/soc_getsockopt.c b/libctru/source/services/soc/soc_getsockopt.c index 20bf148..85d0d4a 100644 --- a/libctru/source/services/soc/soc_getsockopt.c +++ b/libctru/source/services/soc/soc_getsockopt.c @@ -7,6 +7,13 @@ int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optl u32 *cmdbuf = getThreadCommandBuffer(); u32 saved_threadstorage[2]; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + cmdbuf[0] = 0x00110102; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = (u32)level; diff --git a/libctru/source/services/soc/soc_init.c b/libctru/source/services/soc/soc_init.c index 2b961fa..1837da2 100644 --- a/libctru/source/services/soc/soc_init.c +++ b/libctru/source/services/soc/soc_init.c @@ -1,4 +1,41 @@ #include "soc_common.h" +#include + +static int soc_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); +static int soc_close(struct _reent *r, int fd); +static ssize_t soc_write(struct _reent *r, int fd, const char *ptr, size_t len); +static ssize_t soc_read(struct _reent *r, int fd, char *ptr, size_t len); + +static devoptab_t +soc_devoptab = +{ + .name = "soc", + .structSize = sizeof(Handle), + .open_r = soc_open, + .close_r = soc_close, + .write_r = soc_write, + .read_r = soc_read, + .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 = NULL, + .chmod_r = NULL, + .fchmod_r = NULL, +}; + static Result socu_cmd1(Handle memhandle, u32 memsize) { @@ -20,18 +57,43 @@ Result SOC_Initialize(u32 *context_addr, u32 context_size) { Result ret=0; + /* check that the "soc" device doesn't already exist */ + int dev = FindDevice("soc:"); + if(dev >= 0) + return -1; + + /* add the "soc" device */ + dev = AddDevice(&soc_devoptab); + if(dev < 0) + return dev; + ret = svcCreateMemoryBlock(&socMemhandle, (u32)context_addr, context_size, 0, 3); - if(ret!=0)return ret; + if(ret != 0) + { + RemoveDevice("soc"); + return ret; + } - if((ret = srvGetServiceHandle(&SOCU_handle, "soc:U"))!=0)return ret; + if((ret = srvGetServiceHandle(&SOCU_handle, "soc:U")) != 0) + { + RemoveDevice("soc"); + return ret; + } - return socu_cmd1(socMemhandle, context_size); + if((ret = socu_cmd1(socMemhandle, context_size)) != 0) + { + RemoveDevice("soc"); + return ret; + } + + return 0; } Result SOC_Shutdown(void) { Result ret=0; u32 *cmdbuf = getThreadCommandBuffer(); + int dev; cmdbuf[0] = 0x00190000; @@ -40,5 +102,62 @@ Result SOC_Shutdown(void) svcCloseHandle(SOCU_handle); svcCloseHandle(socMemhandle); + dev = FindDevice("soc:"); + if(dev >= 0) + RemoveDevice("soc"); + return cmdbuf[1]; } + +static int +soc_open(struct _reent *r, + void *fileStruct, + const char *path, + int flags, + int mode) +{ + return -1; +} + +static int +soc_close(struct _reent *r, + int fd) +{ + Handle sockfd = *(Handle*)fd; + + int ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x000B0042; + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = 0x20; + + if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + + ret = (int)cmdbuf[1]; + if(ret==0)ret =_net_convert_error(cmdbuf[2]); + SOCU_errno = ret; + + if(ret!=0)return -1; + return 0; +} + +static ssize_t +soc_write(struct _reent *r, + int fd, + const char *ptr, + size_t len) +{ + Handle sockfd = *(Handle*)fd; + return send(sockfd, ptr, len, 0); +} + +static ssize_t +soc_read(struct _reent *r, + int fd, + char *ptr, + size_t len) +{ + Handle sockfd = *(Handle*)fd; + return recv(sockfd, ptr, len, 0); +} diff --git a/libctru/source/services/soc/soc_ioctl.c b/libctru/source/services/soc/soc_ioctl.c index 4125646..6f01baa 100644 --- a/libctru/source/services/soc/soc_ioctl.c +++ b/libctru/source/services/soc/soc_ioctl.c @@ -4,13 +4,20 @@ #include #include -int ioctl(int fd, int request, ...) +int ioctl(int sockfd, int request, ...) { int ret; int flags; int *value; va_list ap; + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + va_start(ap, request); switch(request) { @@ -21,15 +28,15 @@ int ioctl(int fd, int request, ...) ret = -1; } - flags = fcntl(fd, F_GETFL, 0); + flags = fcntl(sockfd, F_GETFL, 0); if(flags == -1) { errno = SOC_GetErrno(); va_end(ap); return -1; } - if(*value) ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - else ret = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + if(*value) ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + else ret = fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK); if(ret != 0) errno = SOC_GetErrno(); diff --git a/libctru/source/services/soc/soc_listen.c b/libctru/source/services/soc/soc_listen.c index ce7ff05..41b73e4 100644 --- a/libctru/source/services/soc/soc_listen.c +++ b/libctru/source/services/soc/soc_listen.c @@ -6,6 +6,13 @@ int listen(int sockfd, int max_connections) int ret=0; u32 *cmdbuf = getThreadCommandBuffer(); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + cmdbuf[0] = 0x00030082; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = (u32)max_connections; diff --git a/libctru/source/services/soc/soc_poll.c b/libctru/source/services/soc/soc_poll.c index 8cf5b34..4bdbb2f 100644 --- a/libctru/source/services/soc/soc_poll.c +++ b/libctru/source/services/soc/soc_poll.c @@ -1,19 +1,47 @@ #include "soc_common.h" #include +#include -int poll(struct pollfd *fds, nfds_t nfsd, int timeout) +int poll(struct pollfd *fds, nfds_t nfds, int timeout) { int ret = 0; - u32 size = sizeof(struct pollfd)*nfsd; + nfds_t i; + u32 size = sizeof(struct pollfd)*nfds; u32 *cmdbuf = getThreadCommandBuffer(); u32 saved_threadstorage[2]; + if(nfds == 0) + { + SOCU_errno = -EINVAL; + return -1; + } + + struct pollfd *tmp_fds = (struct pollfd*)malloc(sizeof(struct pollfd) * nfds); + if(tmp_fds == NULL) + { + SOCU_errno = -ENOMEM; + return -1; + } + + memcpy(tmp_fds, fds, sizeof(struct pollfd) * nfds); + + for(i = 0; i < nfds; ++i) + { + tmp_fds[i].fd = soc_get_fd(fds[i].fd); + if(tmp_fds[i].fd < 0) + { + SOCU_errno = tmp_fds[i].fd; + free(tmp_fds); + return -1; + } + } + cmdbuf[0] = 0x00140084; - cmdbuf[1] = (u32)nfsd; + cmdbuf[1] = (u32)nfds; cmdbuf[2] = (u32)timeout; cmdbuf[3] = 0x20; cmdbuf[5] = (size<<14) | 0x2802; - cmdbuf[6] = (u32)fds; + cmdbuf[6] = (u32)tmp_fds; saved_threadstorage[0] = cmdbuf[0x100>>2]; saved_threadstorage[1] = cmdbuf[0x104>>2]; @@ -21,7 +49,13 @@ int poll(struct pollfd *fds, nfds_t nfsd, int timeout) cmdbuf[0x100>>2] = (size<<14) | 2; cmdbuf[0x104>>2] = (u32)fds; - if((ret = svcSendSyncRequest(SOCU_handle)) != 0)return ret; + if((ret = svcSendSyncRequest(SOCU_handle)) != 0) + { + free(tmp_fds); + return ret; + } + + free(tmp_fds); cmdbuf[0x100>>2] = saved_threadstorage[0]; cmdbuf[0x104>>2] = saved_threadstorage[1]; diff --git a/libctru/source/services/soc/soc_recvfrom.c b/libctru/source/services/soc/soc_recvfrom.c index df5c56c..3af3c1a 100644 --- a/libctru/source/services/soc/soc_recvfrom.c +++ b/libctru/source/services/soc/soc_recvfrom.c @@ -102,6 +102,13 @@ ssize_t socuipc_cmd8(int sockfd, void *buf, size_t len, int flags, struct sockad ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + if(len<0x2000)return socuipc_cmd8(sockfd, buf, len, flags, src_addr, addrlen); return socuipc_cmd7(sockfd, buf, len, flags, src_addr, addrlen); } diff --git a/libctru/source/services/soc/soc_sendto.c b/libctru/source/services/soc/soc_sendto.c index 9afd36a..64eeb9e 100644 --- a/libctru/source/services/soc/soc_sendto.c +++ b/libctru/source/services/soc/soc_sendto.c @@ -108,6 +108,13 @@ ssize_t socuipc_cmda(int sockfd, const void *buf, size_t len, int flags, const s ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + if(len<0x2000)return socuipc_cmda(sockfd, buf, len, flags, dest_addr, addrlen); return socuipc_cmd9(sockfd, buf, len, flags, (struct sockaddr*)dest_addr, addrlen); } diff --git a/libctru/source/services/soc/soc_shutdown.c b/libctru/source/services/soc/soc_shutdown.c index be86293..4dca8c4 100644 --- a/libctru/source/services/soc/soc_shutdown.c +++ b/libctru/source/services/soc/soc_shutdown.c @@ -6,6 +6,13 @@ int shutdown(int sockfd, int shutdown_type) int ret=0; u32 *cmdbuf = getThreadCommandBuffer(); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + cmdbuf[0] = 0x000C0082; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = (u32)shutdown_type; diff --git a/libctru/source/services/soc/soc_sockatmark.c b/libctru/source/services/soc/soc_sockatmark.c index d445fb8..4fbec75 100644 --- a/libctru/source/services/soc/soc_sockatmark.c +++ b/libctru/source/services/soc/soc_sockatmark.c @@ -6,6 +6,13 @@ int sockatmark(int sockfd) int ret=0; u32 *cmdbuf = getThreadCommandBuffer(); + sockfd = soc_get_fd(sockfd); + if(sockfd < 0) + { + SOCU_errno = sockfd; + return -1; + } + cmdbuf[0] = 0x00150042; cmdbuf[1] = (u32)sockfd; cmdbuf[2] = 0x20; diff --git a/libctru/source/services/soc/soc_socket.c b/libctru/source/services/soc/soc_socket.c index 628138b..94f2ad1 100644 --- a/libctru/source/services/soc/soc_socket.c +++ b/libctru/source/services/soc/soc_socket.c @@ -1,9 +1,13 @@ #include "soc_common.h" +#include +#include #include int socket(int domain, int type, int protocol) { int ret=0; + int fd, dev; + __handle *handle; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = 0x000200C2; @@ -12,11 +16,38 @@ int socket(int domain, int type, int protocol) cmdbuf[3] = protocol; cmdbuf[4] = 0x20; - if((ret = svcSendSyncRequest(SOCU_handle))!=0)return ret; + dev = FindDevice("soc:"); + if(dev < 0) + { + SOCU_errno = -ENODEV; + return -1; + } + + fd = __alloc_handle(sizeof(__handle) + sizeof(Handle)); + if(fd < 0) + { + SOCU_errno = -ENOMEM; + return -1; + } + + handle = __get_handle(fd); + handle->device = dev; + handle->fileStruct = ((void *)handle) + sizeof(__handle); + + if((ret = svcSendSyncRequest(SOCU_handle)) != 0) + { + __release_handle(fd); + return ret; + } ret = (int)cmdbuf[1]; - SOCU_errno = ret; + if(ret != 0) + { + SOCU_errno = _net_convert_error(cmdbuf[2]); + __release_handle(fd); + return -1; + } - if(ret!=0)return -1; - return _net_convert_error(cmdbuf[2]); + *(Handle*)handle->fileStruct = cmdbuf[2]; + return fd; }