From 7a5d01108af50daca091905244a3aafe2dcdc3cc Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sun, 4 May 2014 21:55:59 -0400 Subject: [PATCH] Added SOC error conversion, and implemented getsockopt, setsockopt, fcntl, sockatmark, gethostid, getsockname, and getpeername. --- libctru/source/SOC.c | 329 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 318 insertions(+), 11 deletions(-) diff --git a/libctru/source/SOC.c b/libctru/source/SOC.c index 2ebddac..e9f5472 100644 --- a/libctru/source/SOC.c +++ b/libctru/source/SOC.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -9,10 +10,104 @@ #include #include #include +#include +#include +#include Handle SOCU_handle = 0; static int SOCU_errno = 0; +#define NET_UNKNOWN_ERROR_OFFSET -10000//This is from libogc network_wii.c. + +static u8 _net_error_code_map[] = { //This is based on the array from libogc network_wii.c. + 0, // 0 + E2BIG, + EACCES, + EADDRINUSE, + EADDRNOTAVAIL, + EAFNOSUPPORT, // 5 + EAGAIN, + EALREADY, + EBADF, + EBADMSG, + EBUSY, // 10 + ECANCELED, + ECHILD, + ECONNABORTED, + ECONNREFUSED, + ECONNRESET, // 15 + EDEADLK, + EDESTADDRREQ, + EDOM, + EDQUOT, + EEXIST, // 20 + EFAULT, + EFBIG, + EHOSTUNREACH, + EIDRM, + EILSEQ, // 25 + EINPROGRESS, + EINTR, + EINVAL, + EIO, + EISCONN, // 30 + EISDIR, + ELOOP, + EMFILE, + EMLINK, + EMSGSIZE, // 35 + EMULTIHOP, + ENAMETOOLONG, + ENETDOWN, + ENETRESET, + ENETUNREACH, // 40 + ENFILE, + ENOBUFS, + ENODATA, + ENODEV, + ENOENT, // 45 + ENOEXEC, + ENOLCK, + ENOLINK, + ENOMEM, + ENOMSG, // 50 + ENOPROTOOPT, + ENOSPC, + ENOSR, + ENOSTR, + ENOSYS, // 55 + ENOTCONN, + ENOTDIR, + ENOTEMPTY, + ENOTSOCK, + ENOTSUP, // 60 + ENOTTY, + ENXIO, + EOPNOTSUPP, + EOVERFLOW, + EPERM, // 65 + EPIPE, + EPROTO, + EPROTONOSUPPORT, + EPROTOTYPE, + ERANGE, // 70 + EROFS, + ESPIPE, + ESRCH, + ESTALE, + ETIME, // 75 + ETIMEDOUT, +}; + +static s32 _net_convert_error(s32 sock_retval)//This is based on the function from libogc network_wii.c. +{ + if (sock_retval >= 0) return sock_retval; + if (sock_retval < -sizeof(_net_error_code_map) + || !_net_error_code_map[-sock_retval]) + return NET_UNKNOWN_ERROR_OFFSET + sock_retval; + return -_net_error_code_map[-sock_retval]; +} + Result socu_cmd1(Handle memhandle, u32 memsize) { Result ret=0; @@ -78,7 +173,7 @@ int socket(int domain, int type, int protocol) SOCU_errno = ret; if(ret!=0)return -1; - return (int)cmdbuf[2]; + return _net_convert_error(cmdbuf[2]); } int closesocket(int sockfd) @@ -93,7 +188,7 @@ int closesocket(int sockfd) if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret =_net_convert_error(cmdbuf[2]); SOCU_errno = ret; if(ret!=0)return -1; @@ -113,7 +208,7 @@ int shutdown(int sockfd, int shutdown_type) if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); SOCU_errno = ret; if(ret!=0)return -1; @@ -133,7 +228,7 @@ int listen(int sockfd, int max_connections) if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); SOCU_errno = ret; if(ret!=0)return -1; @@ -167,7 +262,7 @@ int accept(int sockfd, struct sockaddr *addr, int *addrlen) cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); if(ret<0)SOCU_errno = ret; if(ret>=0 && addr!=NULL) @@ -204,7 +299,7 @@ int bind(int sockfd, const struct sockaddr *addr, int addrlen) if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); SOCU_errno = ret; if(ret<0)return -1; @@ -233,7 +328,7 @@ int connect(int sockfd, const struct sockaddr *addr, int addrlen) if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); SOCU_errno = ret; if(ret<0)return -1; @@ -271,7 +366,7 @@ int socuipc_cmd7(int sockfd, void *buf, int len, int flags, struct sockaddr *src cmdbuf[0x104>>2] = saved_threadstorage[1]; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); if(ret<0)SOCU_errno = ret; if(ret<0)return -1; @@ -313,7 +408,7 @@ int socuipc_cmd8(int sockfd, void *buf, int len, int flags, struct sockaddr *src cmdbuf[0x10c>>2] = saved_threadstorage[3]; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); if(ret<0)SOCU_errno = ret; if(ret<0)return -1; @@ -343,7 +438,7 @@ int socuipc_cmd9(int sockfd, const void *buf, int len, int flags, const struct s if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); if(ret<0)SOCU_errno = ret; if(ret<0)return -1; @@ -373,7 +468,7 @@ int socuipc_cmda(int sockfd, const void *buf, int len, int flags, const struct s if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; ret = (int)cmdbuf[1]; - if(ret==0)ret = (int)cmdbuf[2]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); if(ret<0)SOCU_errno = ret; if(ret<0)return -1; @@ -402,3 +497,215 @@ int send(int sockfd, const void *buf, int len, int flags) return sendto(sockfd, buf, len, flags, NULL, 0); } +int getsockopt(int sockfd, int level, int option_name, void * data, int * data_len) +{ + int ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 saved_threadstorage[2]; + + cmdbuf[0] = 0x00110102; + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = (u32)level; + cmdbuf[3] = (u32)option_name; + cmdbuf[4] = (u32)*data_len; + cmdbuf[5] = 0x20; + + saved_threadstorage[0] = cmdbuf[0x100>>2]; + saved_threadstorage[1] = cmdbuf[0x104>>2]; + + cmdbuf[0x100>>2] = ((*data_len)<<14) | 2; + cmdbuf[0x104>>2] = (u32)data; + + if((ret = svc_sendSyncRequest(SOCU_handle))!=0)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)*data_len = cmdbuf[3]; + + if(ret<0)return -1; + return ret; +} + +int setsockopt(int sockfd, int level, int option_name, const void * data, int data_len) +{ + int ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00120104; + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = (u32)level; + cmdbuf[3] = (u32)option_name; + cmdbuf[4] = (u32)data_len; + cmdbuf[5] = 0x20; + cmdbuf[7] = (data_len<<14) | 0x2402; + cmdbuf[8] = (u32)data; + + if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; + + ret = (int)cmdbuf[1]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); + if(ret<0)SOCU_errno = ret; + + if(ret<0)return -1; + return ret; +} + +int fcntl(int sockfd, int cmd, ...) +{ + int ret=0; + int arg=0; + u32 *cmdbuf = getThreadCommandBuffer(); + + va_list args; + va_start(args, cmd); + + if(cmd!=F_GETFL && cmd!=F_SETFL) + { + SOCU_errno = -EINVAL; + return -1; + } + + if(cmd==F_SETFL) + { + arg = va_arg(args, int); + + if(arg && arg!=O_NONBLOCK) + { + SOCU_errno = -EINVAL; + return -1; + } + + if(arg==O_NONBLOCK)arg = 0x4; + } + + cmdbuf[0] = 0x001300C2; + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = (u32)cmd; + cmdbuf[3] = (u32)arg; + cmdbuf[4] = 0x20; + + if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; + + ret = (int)cmdbuf[1]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); + if(ret<0)SOCU_errno = ret; + + if(ret<0)return -1; + return ret; +} + +int sockatmark(int sockfd) +{ + int ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00150042; + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = 0x20; + + if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; + + ret = (int)cmdbuf[1]; + if(ret==0)ret = _net_convert_error(cmdbuf[2]); + if(ret<0)SOCU_errno = ret; + + if(ret<0)return -1; + return ret; +} + +long gethostid() +{ + int ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00160000; + + if((ret = svc_sendSyncRequest(SOCU_handle))!=0)return ret; + + ret = (int)cmdbuf[1]; + if(ret==0)ret = cmdbuf[2]; + + return ret; +} + +int getsockname(int sockfd, struct sockaddr *addr, int * addr_len) +{ + int ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 saved_threadstorage[2]; + u8 tmpaddr[0x1c]; + + cmdbuf[0] = 0x00170082; + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = 0x1c; + cmdbuf[3] = 0x20; + + saved_threadstorage[0] = cmdbuf[0x100>>2]; + saved_threadstorage[1] = cmdbuf[0x104>>2]; + + cmdbuf[0x100>>2] = (0x1c<<14) | 2; + cmdbuf[0x104>>2] = (u32)tmpaddr; + + if((ret = svc_sendSyncRequest(SOCU_handle))!=0)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) + { + addr->sa_family = tmpaddr[1]; + if(*addr_len > tmpaddr[0])*addr_len = tmpaddr[0]; + memcpy(addr->sa_data, &tmpaddr[2], *addr_len - 2); + } + + if(ret<0)return -1; + return ret; +} + +int getpeername(int sockfd, struct sockaddr *addr, int * addr_len) +{ + int ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 saved_threadstorage[2]; + u8 tmpaddr[0x1c]; + + cmdbuf[0] = 0x00180082; + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = 0x1c; + cmdbuf[3] = 0x20; + + saved_threadstorage[0] = cmdbuf[0x100>>2]; + saved_threadstorage[1] = cmdbuf[0x104>>2]; + + cmdbuf[0x100>>2] = (0x1c<<14) | 2; + cmdbuf[0x104>>2] = (u32)tmpaddr; + + if((ret = svc_sendSyncRequest(SOCU_handle))!=0)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) + { + addr->sa_family = tmpaddr[1]; + if(*addr_len > tmpaddr[0])*addr_len = tmpaddr[0]; + memcpy(addr->sa_data, &tmpaddr[2], *addr_len - 2); + } + + if(ret<0)return -1; + return ret; +} +