2 * Acess2 POSIX Sockets Library
3 * - By John Hodge (thePowersGang)
6 * - getaddrinfo/freeaddrinfo/getnameinfo/gai_strerror
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>
18 struct addrinfo **ret_p;
22 struct addrinfo *int_new_addrinfo(int af, const void *addrdata);
23 int int_getaddinfo_lookupcb(void *info, int addr_type, const void *addr);
31 } caLocalServices[] = {
32 {"telnet", SOCK_STREAM, 0, 23},
33 {"http", SOCK_STREAM, 0, 80},
35 static const int ciNumLocalServices = sizeof(caLocalServices)/sizeof(caLocalServices[0]);
38 int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
40 static const struct addrinfo defhints = {
41 .ai_family = AF_UNSPEC,
42 .ai_flags = AI_V4MAPPED | AI_ADDRCONFIG
44 struct addrinfo *ret = NULL;
46 _SysDebug("getaddrinfo('%s','%s',%p,%p)", node, service, hints, res);
49 if( !node && !service ) return EAI_NONAME;
56 if( !(hints->ai_flags & AI_PASSIVE) )
63 // 1. Check if the node is an IP address
66 int type = Net_ParseAddress(node, addrdata);
69 case NET_ADDRTYPE_NULL:
71 case NET_ADDRTYPE_IPV4:
72 ret = int_new_addrinfo(AF_INET, addrdata);
74 case NET_ADDRTYPE_IPV6:
75 ret = int_new_addrinfo(AF_INET6, addrdata);
78 _SysDebug("getaddrinfo: Unknown address type %i", type);
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) )
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 = {
93 if( Net_Lookup_Addrs(node, &info, int_getaddinfo_lookupcb) ) {
94 // Lookup failed, quick return
99 // 3. No Match, return sad
106 int default_socktype = hints->ai_socktype;
107 int default_protocol = hints->ai_protocol;
108 int default_port = 0;
111 if( default_protocol == 0 )
113 switch(default_socktype)
121 // Convert `node` into types
126 default_port = strtol(service, (char**)&end, 0);
127 if( *end != '\0' && (hints->ai_flags & AI_NUMERICSERV) )
134 // TODO: Read something like /Acess/Conf/services
135 for( int i = 0; i < ciNumLocalServices; i ++ )
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;
149 _SysDebug("getaddrinfo: TODO Service translation");
153 for( struct addrinfo *ai = ret; ai; ai = ai->ai_next)
155 struct sockaddr_in *in = (void*)ai->ai_addr;
156 struct sockaddr_in6 *in6 = (void*)ai->ai_addr;
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;
165 switch(ai->ai_family)
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);
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);
182 _SysDebug("getaddrinfo: Unknown address family %i (setting port)", ai->ai_family);
192 * \brief Allocate a new zeroed addrinfo for the specified address
194 struct addrinfo *int_new_addrinfo(int af, const void *addrdata)
200 addrlen = sizeof(struct sockaddr_in);
203 addrlen = sizeof(struct sockaddr_in6);
206 _SysDebug("int_new_addrinfo: ERROR - Unknown AF %i", af);
209 struct addrinfo* ret = malloc(sizeof(struct addrinfo) + addrlen);
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;
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 );
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 );
230 _SysDebug("int_new_addrinfo: BUGCHECK - Unhandled AF %i", af);
236 // Callback for getaddrinfo's call to Net_Lookup_Addrs
237 int int_getaddinfo_lookupcb(void *info_v, int addr_type, const void *addr)
239 struct sLookupInfo *info = info_v;
240 struct addrinfo *ent;
243 case NET_ADDRTYPE_IPV4:
244 ent = int_new_addrinfo(AF_INET, addr);
246 case NET_ADDRTYPE_IPV6:
247 ent = int_new_addrinfo(AF_INET6, addr);
250 // Huh... unknown address type, just ignore it
253 ent->ai_next = *info->ret_p;
258 void freeaddrinfo(struct addrinfo *res)
262 struct addrinfo *next = res->ai_next;
268 int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
270 // Determine hostname
276 if( !(flags & NI_NUMERICHOST) )
280 // Numeric hostname or the hostname was unresolvable
281 if( host[0] == '\0' )
283 if( (flags & NI_NAMEREQD) )
288 // Determine service name
294 if( !(flags & NI_NUMERICSERV) )
298 if( serv[0] == '\0' )
307 const char *gai_strerror(int errnum)
311 case EAI_SUCCESS: return "No error";
312 case EAI_FAIL: return "Permanent resolution failure";
313 default: return "UNKNOWN";
317 struct hostent *gethostbyname(const char *name)