Usermode/libpsocket - Constify and bugfix
[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 static const struct {
17         const char *Name;
18          int    SockType;
19          int    Protocol;
20          int    Port;
21 } caLocalServices[] = {
22         {"telnet", SOCK_STREAM, 0, 23},
23         {"http", SOCK_STREAM, 0, 80},
24 };
25 static const int ciNumLocalServices = sizeof(caLocalServices)/sizeof(caLocalServices[0]);
26
27 // === CODE ===
28 int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
29 {
30         static const struct addrinfo    defhints = {
31                 .ai_family = AF_UNSPEC,
32                 .ai_flags = AI_V4MAPPED | AI_ADDRCONFIG
33                 };
34         struct addrinfo *ret = NULL;
35
36         _SysDebug("getaddrinfo('%s','%s',%p,%p)", node, service, hints, res);
37
38         // Error checks
39         if( !node && !service ) return EAI_NONAME;
40         
41         if( !hints )
42                 hints = &defhints;
43
44         if( !node )
45         {
46                 if( !(hints->ai_flags & AI_PASSIVE) )
47                         ;       // Use localhost
48                 else
49                         ;       // Use wildcard
50         }
51         else
52         {
53                 // 1. Check if the node is an IP address
54                 {
55                          int    type;
56                         char    addrdata[16];
57                         type = Net_ParseAddress(node, addrdata);
58                         switch(type)
59                         {
60                         case 0:
61                                 break;
62                         case 4: // IPv4
63                                 ret = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
64                                 ret->ai_family = AF_INET;
65                                 ret->ai_socktype = 0;
66                                 ret->ai_protocol = 0;
67                                 ret->ai_addrlen = sizeof(struct in_addr);
68                                 ret->ai_addr = (void*)( ret + 1 );
69                                 ret->ai_canonname = 0;
70                                 ret->ai_next = 0;
71                                 ((struct sockaddr_in*)ret->ai_addr)->sin_family = AF_INET;
72                                 ((struct sockaddr_in*)ret->ai_addr)->sin_port = 0;
73                                 memcpy( &((struct sockaddr_in*)ret->ai_addr)->sin_addr, addrdata, 4 );
74                                 break;
75                         default:
76                                 _SysDebug("getaddrinfo: Unknown address family %i", type);
77                                 return 1;
78                         }
79                 }
80                 
81                 // 2. Check for a DNS name
82                 // - No luck with above, and hints->ai_flags doesn't have AI_NUMERICHOST set
83                 if( !ret && !(hints->ai_flags & AI_NUMERICHOST) )
84                 {
85                         _SysDebug("getaddrinfo: TODO DNS Lookups");
86                         // TODO: DNS Lookups
87                         // ? /Acess/Conf/Nameservers
88                         // ? /Acess/Conf/Hosts
89                 }
90                 
91                 // 3. No Match, chuck sad
92                 if( !ret )
93                 {
94                         return EAI_NONAME;
95                 }
96         }
97
98         int default_socktype = hints->ai_socktype;
99         int default_protocol = hints->ai_protocol;
100         int default_port = 0;
101         
102         #if 0
103         if( default_protocol == 0 )
104         {
105                 switch(default_socktype)
106                 {
107                 case SOCK_DGRAM:
108                         default_protocol = 
109                 }
110         }
111         #endif
112         
113         // Convert `node` into types
114         if( service )
115         {
116                 const char *end;
117                 
118                 default_port = strtol(service, (char**)&end, 0);
119                 if( *end != '\0' && (hints->ai_flags & AI_NUMERICSERV) )
120                 {
121                         return EAI_NONAME;
122                 }
123                 
124                 if( *end != '\0' )
125                 {
126                         // TODO: Read something like /Acess/Conf/services
127                         for( int i = 0; i < ciNumLocalServices; i ++ )
128                         {
129                                 if( strcmp(service, caLocalServices[i].Name) == 0 ) {
130                                         end = service + strlen(service);
131                                         default_socktype = caLocalServices[i].SockType;
132                                         default_protocol = caLocalServices[i].Protocol;
133                                         default_port = caLocalServices[i].Port;
134                                         break;
135                                 }
136                         }
137                 }
138                 
139                 if( *end != '\0' )
140                 {
141                         _SysDebug("getaddrinfo: TODO Service translation");
142                 }
143         }
144
145         struct addrinfo *ai;
146         for( ai = ret; ai; ai = ai->ai_next)
147         {
148                 struct sockaddr_in      *in = (void*)ai->ai_addr;
149                 struct sockaddr_in6     *in6 = (void*)ai->ai_addr;
150                 
151                 // Check ai_socktype/ai_protocol
152                 // TODO: Do both of these need to be zero for defaults to apply?
153                 if( ai->ai_socktype == 0 )
154                         ai->ai_socktype = default_socktype;
155                 if( ai->ai_protocol == 0 )
156                         ai->ai_protocol = default_protocol;
157                 
158                 switch(ai->ai_family)
159                 {
160                 case AF_INET:
161                         if( in->sin_port == 0 )
162                                 in->sin_port = default_port;
163                         _SysDebug("%p: IPv4 [%s]:%i %i,%i",
164                                 ai, Net_PrintAddress(4, &in->sin_addr),
165                                 in->sin_port, ai->ai_socktype, ai->ai_protocol);
166                         break;
167                 case AF_INET6:
168                         if( in6->sin6_port == 0 )
169                                 in6->sin6_port = default_port;
170                         _SysDebug("%p: IPv6 [%s]:%i %i,%i",
171                                 ai, Net_PrintAddress(6, &in6->sin6_addr),
172                                 in6->sin6_port, ai->ai_socktype, ai->ai_protocol);
173                         break;
174                 default:
175                         _SysDebug("getaddrinfo: Unknown address family %i (setting port)", ai->ai_family);
176                         return 1;
177                 }
178         }
179
180         *res = ret;
181         return 0;
182 }
183
184 void freeaddrinfo(struct addrinfo *res)
185 {
186         
187 }
188
189 int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
190 {
191         // Determine hostname
192         if( host )
193         {
194                 if( hostlen == 0 )
195                         return EAI_OVERFLOW;
196                 host[0] = '\0';
197                 if( !(flags & NI_NUMERICHOST) )
198                 {
199                         // Handle NI_NOFQDN
200                 }
201                 // Numeric hostname or the hostname was unresolvable
202                 if( host[0] == '\0' )
203                 {
204                         if( (flags & NI_NAMEREQD) )
205                                 return EAI_NONAME;
206                 }
207         }
208         
209         // Determine service name
210         if( serv )
211         {
212                 if( servlen == 0 )
213                         return EAI_OVERFLOW;
214                 serv[0] = '\0';
215                 if( !(flags & NI_NUMERICSERV) )
216                 {
217                         // Handle NI_DGRAM
218                 }
219                 if( serv[0] == '\0' )
220                 {
221                         
222                 }
223         }
224         return EAI_SUCCESS;
225 }
226
227
228 const char *gai_strerror(int errnum)
229 {
230         switch(errnum)
231         {
232         case EAI_SUCCESS:       return "No error";
233         case EAI_FAIL:          return "Permanent resolution failure";
234         default:        return "UNKNOWN";
235         }
236 }
237

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