]> Chaos Git - corbenik/ctrulib.git/commitdiff
added SOC:u getaddrinfo
authorLectem <lectem@gmail.com>
Wed, 13 Jan 2016 17:20:33 +0000 (12:20 -0500)
committerLectem <lectem@gmail.com>
Thu, 14 Jan 2016 23:30:55 +0000 (18:30 -0500)
libctru/include/netdb.h
libctru/source/services/soc/soc_getaddrinfo.c [new file with mode: 0644]

index 5840deb5ec662891cdef6a2f7ad915339d72d9ae..e3259b09289fd3c4a07d262e6eaf83184ec63359 100644 (file)
@@ -17,6 +17,16 @@ struct hostent {
        char    *h_addr;
 };
 
+
+#define AI_PASSIVE     0x01
+#define AI_CANONNAME   0x02
+#define AI_NUMERICHOST 0x04
+#define AI_NUMERICSERV 0x00 /* probably 0x08 but services names are never resolved */
+
+// doesn't apply to 3ds
+#define AI_ADDRCONFIG  0x00
+
+
 #define NI_MAXHOST     1025
 #define NI_MAXSERV       32
 
@@ -31,6 +41,16 @@ struct hostent {
 #define EAI_NONAME   (-305)
 #define EAI_SOCKTYPE (-307)
 
+struct addrinfo {
+       int             ai_flags;
+       int             ai_family;
+       int             ai_socktype;
+       int             ai_protocol;
+       socklen_t       ai_addrlen;
+       char            *ai_canonname;
+       struct sockaddr *ai_addr;
+       struct addrinfo *ai_next;
+};
 
 #ifdef __cplusplus
 extern "C" {
@@ -46,6 +66,12 @@ extern "C" {
                char *host, socklen_t hostlen,
                char *serv, socklen_t servlen, int flags);
 
+       int getaddrinfo(const char *node, const char *service,
+               const struct addrinfo *hints,
+               struct addrinfo **res);
+
+       void freeaddrinfo(struct addrinfo *ai);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libctru/source/services/soc/soc_getaddrinfo.c b/libctru/source/services/soc/soc_getaddrinfo.c
new file mode 100644 (file)
index 0000000..11c8634
--- /dev/null
@@ -0,0 +1,162 @@
+#include "soc_common.h"
+#include <netdb.h>
+#include <3ds/ipc.h>
+#include <3ds/result.h>
+#include <stdlib.h>
+
+#define DEFAULT_NUM_ADDRINFO 4
+
+typedef struct addrinfo_3ds_t addrinfo_3ds_t;
+struct addrinfo_3ds_t
+{
+       s32                     ai_flags;
+       s32                     ai_family;
+       s32                     ai_socktype;
+       s32                     ai_protocol;
+       u32                     ai_addrlen;
+       char                    ai_canonname[256];
+       struct sockaddr_storage ai_addr;
+};
+
+void freeaddrinfo(struct addrinfo *ai)
+{
+       struct addrinfo *next_ai = ai;
+       while(ai != NULL)
+       {
+               next_ai = ai->ai_next;
+               free(ai);
+               ai = next_ai;
+       }
+}
+
+static struct addrinfo * buffer2addrinfo(addrinfo_3ds_t * entry)
+{
+       int ai_canonname_len = strnlen(entry->ai_canonname, sizeof(entry->ai_canonname));
+       struct addrinfo *ai;
+       size_t          len = sizeof(*ai)
+                           + sizeof(struct sockaddr_storage)
+                           + ai_canonname_len
+                           + 1;
+
+       ai = (struct addrinfo*)calloc(1,len);
+       if(ai != NULL)
+       {
+               ai->ai_canonname = (char*)ai + sizeof(*ai) + sizeof(struct sockaddr_storage);
+               ai->ai_addr      = (struct sockaddr*)((char*)ai + sizeof(*ai));
+
+               ai->ai_flags    = entry->ai_flags;
+               ai->ai_family   = entry->ai_family;
+               ai->ai_socktype = entry->ai_socktype;
+               ai->ai_protocol = entry->ai_protocol;
+               ai->ai_addrlen  = entry->ai_addrlen;
+
+               memcpy(ai->ai_canonname, entry->ai_canonname, ai_canonname_len);
+               memcpy(ai->ai_addr, &entry->ai_addr, ai->ai_addrlen);
+       }
+       return ai;
+}
+
+
+static int getaddrinfo_detail(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res, addrinfo_3ds_t *info, s32 info_count, s32 * count)
+{
+       int            i;
+       u32            *cmdbuf = getThreadCommandBuffer();
+       u32            saved_threadstorage[2];
+
+       if(node == NULL && service == NULL)
+       {
+               return EAI_NONAME;
+       }
+
+       cmdbuf[ 0] = IPC_MakeHeader(0xF,4,6); // 0x00F0106
+       cmdbuf[ 1] = node    == NULL ? 0 : strlen(node)+1;
+       cmdbuf[ 2] = service == NULL ? 0 : strlen(service)+1;
+       cmdbuf[ 3] = hints   == NULL ? 0 : sizeof(*hints);
+       cmdbuf[ 4] = sizeof(addrinfo_3ds_t) * info_count;
+       cmdbuf[ 5] = IPC_Desc_StaticBuffer(cmdbuf[1], 5);
+       cmdbuf[ 6] = (u32)node;
+       cmdbuf[ 7] = IPC_Desc_StaticBuffer(cmdbuf[2], 6);
+       cmdbuf[ 8] = (u32)service;
+       cmdbuf[ 9] = IPC_Desc_StaticBuffer(cmdbuf[3], 7);
+       cmdbuf[10] = (u32)hints;
+
+       u32 * staticbufs = getThreadStaticBuffers();
+
+       // Save the thread storage values
+       for(i = 0 ; i < 2 ; ++i)
+               saved_threadstorage[i] = staticbufs[i];
+
+       staticbufs[0] = IPC_Desc_StaticBuffer(sizeof(addrinfo_3ds_t) * info_count, 0);
+       staticbufs[1] = (u32)info;
+
+       int ret = svcSendSyncRequest(SOCU_handle);
+
+       // Restore the thread storage values
+       for(i = 0 ; i < 2 ; ++i)
+               staticbufs[i] = saved_threadstorage[i];
+
+       if(R_FAILED(ret)) {
+               errno = SYNC_ERROR;
+               return ret;
+       }
+
+       ret = cmdbuf[1];
+       if(R_FAILED(ret)) {
+               errno = SYNC_ERROR;
+               return ret;
+       }
+       if(cmdbuf[2] != 0)
+       {
+               return cmdbuf[2];
+       }
+
+       *count = cmdbuf[3];
+       if(*count <= 0)
+               *res = NULL;
+       else if(*count <= info_count)
+       {
+               struct addrinfo **ptr = res;
+               for(i = 0; i < *count; ++i)
+               {
+                       *ptr = buffer2addrinfo(&info[i]);
+                       if(*ptr == NULL)
+                       {
+                               freeaddrinfo(*res);
+                               *res = NULL;
+                               return EAI_MEMORY;
+                       }
+                       ptr = &(*ptr)->ai_next;
+               }
+               *ptr = NULL;
+       }
+
+       return 0;
+}
+
+int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
+{
+       Result ret;
+       addrinfo_3ds_t *info = NULL, *tmp;
+       s32            count = DEFAULT_NUM_ADDRINFO, info_count;
+       
+       if(node == NULL && service == NULL)
+       {
+               return EAI_NONAME;
+       }
+
+       do
+       {
+               info_count = count;
+               tmp = (addrinfo_3ds_t*)realloc(info, sizeof(addrinfo_3ds_t) * info_count);
+               if(tmp == NULL)
+               {
+                       free(info);
+                       return EAI_MEMORY;
+               }
+               info = tmp;
+               ret = getaddrinfo_detail(node,service,hints,res,info,info_count,&count);
+       } while(count > info_count && R_SUCCEEDED(ret));
+
+       free(info);
+       return ret;
+}