Usermode/libc - Fix strchr and strrchr behavior
[tpg/acess2.git] / Usermode / Libraries / libpsocket.so_src / getaddrinfo.c
1 /*
2  * Acess2 POSIX Sockets Library
3  * - By John Hodge (thePowersGang)
4  *
5  * getaddrinfo.c
6  * - getaddrinfo/freeaddrinfo/getnameinfo/gai_strerror
7  */
8 #include <netdb.h>
9 #include <netinet/in.h>
10 #include <net.h>        // Net_ParseAddress
11 #include <stdlib.h>     // malloc
12 #include <string.h>     // memcpy
13 #include <stdlib.h>     // strtol
14 #include <acess/sys.h>
15
16 // === TYPES ===
17 struct sLookupInfo {
18         struct addrinfo **ret_p;
19 };
20
21 // === PROTOTYPES ===
22 struct addrinfo *int_new_addrinfo(int af, const void *addrdata);
23 int int_getaddinfo_lookupcb(void *info, int addr_type, const void *addr);
24
25 // === GLOBALS ===
26 static const struct {
27         const char *Name;
28          int    SockType;
29          int    Protocol;
30          int    Port;
31 } caLocalServices[] = {
32         {"telnet", SOCK_STREAM, 0, 23},
33         {"http", SOCK_STREAM, 0, 80},
34 };
35 static const int ciNumLocalServices = sizeof(caLocalServices)/sizeof(caLocalServices[0]);
36
37 // === CODE ===
38 int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
39 {
40         static const struct addrinfo    defhints = {
41                 .ai_family = AF_UNSPEC,
42                 .ai_flags = AI_V4MAPPED | AI_ADDRCONFIG
43                 };
44         struct addrinfo *ret = NULL;
45
46         _SysDebug("getaddrinfo('%s','%s',%p,%p)", node, service, hints, res);
47
48         // Error checks
49         if( !node && !service ) return EAI_NONAME;
50         
51         if( !hints )
52                 hints = &defhints;
53
54         if( !node )
55         {
56                 if( !(hints->ai_flags & AI_PASSIVE) )
57                         ;       // Use localhost
58                 else
59                         ;       // Use wildcard
60         }
61         else
62         {
63                 // 1. Check if the node is an IP address
64                 {
65                         char    addrdata[16];
66                         int type = Net_ParseAddress(node, addrdata);
67                         switch(type)
68                         {
69                         case NET_ADDRTYPE_NULL:
70                                 break;
71                         case NET_ADDRTYPE_IPV4:
72                                 ret = int_new_addrinfo(AF_INET, addrdata);
73                                 break;
74                         case NET_ADDRTYPE_IPV6:
75                                 ret = int_new_addrinfo(AF_INET6, addrdata);
76                                 break;
77                         default:
78                                 _SysDebug("getaddrinfo: Unknown address type %i", type);
79                                 return 1;
80                         }
81                 }
82                 
83                 // 2. Check for a DNS name
84                 // - No luck with above, and hints->ai_flags doesn't have AI_NUMERICHOST set
85                 if( !ret && !(hints->ai_flags & AI_NUMERICHOST) )
86                 {
87                         // Just does a basic A record lookup
88                         // TODO: Support SRV records
89                         // TODO: Ensure that CNAMEs are handled correctly
90                         struct sLookupInfo info = {
91                                 .ret_p = &ret,
92                                 };
93                         if( Net_Lookup_Addrs(node, &info, int_getaddinfo_lookupcb) ) {
94                                 // Lookup failed, quick return
95                                 return EAI_NONAME;
96                         }
97                 }
98                 
99                 // 3. No Match, return sad
100                 if( !ret )
101                 {
102                         return EAI_NONAME;
103                 }
104         }
105
106         int default_socktype = hints->ai_socktype;
107         int default_protocol = hints->ai_protocol;
108         int default_port = 0;
109         
110         #if 0
111         if( default_protocol == 0 )
112         {
113                 switch(default_socktype)
114                 {
115                 case SOCK_DGRAM:
116                         default_protocol = 
117                 }
118         }
119         #endif
120         
121         // Convert `node` into types
122         if( service )
123         {
124                 const char *end;
125                 
126                 default_port = strtol(service, (char**)&end, 0);
127                 if( *end != '\0' && (hints->ai_flags & AI_NUMERICSERV) )
128                 {
129                         return EAI_NONAME;
130                 }
131                 
132                 if( *end != '\0' )
133                 {
134                         // TODO: Read something like /Acess/Conf/services
135                         for( int i = 0; i < ciNumLocalServices; i ++ )
136                         {
137                                 if( strcmp(service, caLocalServices[i].Name) == 0 ) {
138                                         end = service + strlen(service);
139                                         default_socktype = caLocalServices[i].SockType;
140                                         default_protocol = caLocalServices[i].Protocol;
141                                         default_port = caLocalServices[i].Port;
142                                         break;
143                                 }
144                         }
145                 }
146                 
147                 if( *end != '\0' )
148                 {
149                         _SysDebug("getaddrinfo: TODO Service translation");
150                 }
151         }
152
153         for( struct addrinfo *ai = ret; ai; ai = ai->ai_next)
154         {
155                 struct sockaddr_in      *in = (void*)ai->ai_addr;
156                 struct sockaddr_in6     *in6 = (void*)ai->ai_addr;
157                 
158                 // Check ai_socktype/ai_protocol
159                 // TODO: Do both of these need to be zero for defaults to apply?
160                 if( ai->ai_socktype == 0 )
161                         ai->ai_socktype = default_socktype;
162                 if( ai->ai_protocol == 0 )
163                         ai->ai_protocol = default_protocol;
164                 
165                 switch(ai->ai_family)
166                 {
167                 case AF_INET:
168                         if( in->sin_port == 0 )
169                                 in->sin_port = default_port;
170                         _SysDebug("%p: IPv4 [%s]:%i %i,%i",
171                                 ai, Net_PrintAddress(4, &in->sin_addr),
172                                 in->sin_port, ai->ai_socktype, ai->ai_protocol);
173                         break;
174                 case AF_INET6:
175                         if( in6->sin6_port == 0 )
176                                 in6->sin6_port = default_port;
177                         _SysDebug("%p: IPv6 [%s]:%i %i,%i",
178                                 ai, Net_PrintAddress(6, &in6->sin6_addr),
179                                 in6->sin6_port, ai->ai_socktype, ai->ai_protocol);
180                         break;
181                 default:
182                         _SysDebug("getaddrinfo: Unknown address family %i (setting port)", ai->ai_family);
183                         return 1;
184                 }
185         }
186
187         *res = ret;
188         return 0;
189 }
190
191 /**
192  * \brief Allocate a new zeroed addrinfo for the specified address
193  */
194 struct addrinfo *int_new_addrinfo(int af, const void *addrdata)
195 {
196         size_t  addrlen = 0;
197         switch(af)
198         {
199         case AF_INET:
200                 addrlen = sizeof(struct sockaddr_in);
201                 break;
202         case AF_INET6:
203                 addrlen = sizeof(struct sockaddr_in6);
204                 break;
205         default:
206                 _SysDebug("int_new_addrinfo: ERROR - Unknown AF %i", af);
207                 return NULL;
208         }
209         struct addrinfo* ret = malloc(sizeof(struct addrinfo) + addrlen);
210         ret->ai_family = af;
211         ret->ai_socktype = 0;
212         ret->ai_protocol = 0;
213         ret->ai_addrlen = addrlen;
214         ret->ai_addr = (void*)( ret + 1 );
215         ret->ai_canonname = 0;
216         ret->ai_next = 0;
217         switch(af)
218         {
219         case AF_INET:
220                 ((struct sockaddr_in*)ret->ai_addr)->sin_family = AF_INET;
221                 ((struct sockaddr_in*)ret->ai_addr)->sin_port = 0;
222                 memcpy( &((struct sockaddr_in*)ret->ai_addr)->sin_addr, addrdata, 4 );
223                 break;
224         case AF_INET6:
225                 ((struct sockaddr_in6*)ret->ai_addr)->sin6_family = AF_INET6;
226                 ((struct sockaddr_in6*)ret->ai_addr)->sin6_port = 0;
227                 memcpy( &((struct sockaddr_in6*)ret->ai_addr)->sin6_addr, addrdata, 16 );
228                 break;
229         default:
230                 _SysDebug("int_new_addrinfo: BUGCHECK - Unhandled AF %i", af);
231                 return NULL;
232         }
233         return ret;
234 }
235
236 // Callback for getaddrinfo's call to Net_Lookup_Addrs
237 int int_getaddinfo_lookupcb(void *info_v, int addr_type, const void *addr)
238 {
239         struct sLookupInfo *info = info_v;
240         struct addrinfo *ent;
241         switch( addr_type )
242         {
243         case NET_ADDRTYPE_IPV4:
244                 ent = int_new_addrinfo(AF_INET, addr);
245                 break;
246         case NET_ADDRTYPE_IPV6:
247                 ent = int_new_addrinfo(AF_INET6, addr);
248                 break;
249         default:
250                 // Huh... unknown address type, just ignore it
251                 return 0;
252         }
253         ent->ai_next = *info->ret_p;
254         *info->ret_p = ent;
255         return 0;
256 }
257
258 void freeaddrinfo(struct addrinfo *res)
259 {
260         while( res )
261         {
262                 struct addrinfo *next = res->ai_next;
263                 free(res);
264                 res = next;
265         }
266 }
267
268 int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
269 {
270         // Determine hostname
271         if( host )
272         {
273                 if( hostlen == 0 )
274                         return EAI_OVERFLOW;
275                 host[0] = '\0';
276                 if( !(flags & NI_NUMERICHOST) )
277                 {
278                         // Handle NI_NOFQDN
279                 }
280                 // Numeric hostname or the hostname was unresolvable
281                 if( host[0] == '\0' )
282                 {
283                         if( (flags & NI_NAMEREQD) )
284                                 return EAI_NONAME;
285                 }
286         }
287         
288         // Determine service name
289         if( serv )
290         {
291                 if( servlen == 0 )
292                         return EAI_OVERFLOW;
293                 serv[0] = '\0';
294                 if( !(flags & NI_NUMERICSERV) )
295                 {
296                         // Handle NI_DGRAM
297                 }
298                 if( serv[0] == '\0' )
299                 {
300                         
301                 }
302         }
303         return EAI_SUCCESS;
304 }
305
306
307 const char *gai_strerror(int errnum)
308 {
309         switch(errnum)
310         {
311         case EAI_SUCCESS:       return "No error";
312         case EAI_FAIL:          return "Permanent resolution failure";
313         default:        return "UNKNOWN";
314         }
315 }
316
317 struct hostent *gethostbyname(const char *name)
318 {
319         return NULL;
320 }
321

UCC git Repository :: git.ucc.asn.au