#include #include #include #include #include #include #include /* XXX TODO FIXME */ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo **tmp; int family; tmp=res; *res=0; if (hints) { if (hints->ai_family && hints->ai_family != PF_INET6 && hints->ai_family != PF_INET) return EAI_FAMILY; if (hints->ai_socktype && hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM) return EAI_SOCKTYPE; } for (family=PF_INET6; ; family=PF_INET) { if (!hints || hints->ai_family==family || hints->ai_family==AF_UNSPEC) { /* IPv6 addresses are OK */ struct hostent h; struct hostent *H; int herrno=0; char buf[4096]; int lookupok=0; h.h_addr_list=(char**)buf+16; if (node) { if (inet_pton(family,node,buf)>0) { h.h_name=(char*)node; h.h_addr_list[0]=buf; lookupok=1; } else if ((!hints || !(hints->ai_flags&AI_NUMERICHOST)) && !gethostbyname2_r(node,family,&h,buf,4096,&H,&herrno)) { lookupok=1; } else { if (herrno==TRY_AGAIN) { freeaddrinfo(*res); return EAI_AGAIN; } } } else { h.h_name=0; h.h_addr_list[0]=buf; memset(buf,0,16); if (!hints || !(hints->ai_flags&AI_PASSIVE)) { if (family==AF_INET) { buf[0]=127; buf[3]=1; } else buf[15]=1; } lookupok=1; } if (lookupok) { struct ai_v6 { struct addrinfo ai; union { struct sockaddr_in6 ip6; struct sockaddr_in ip4; } ip; char name[1]; } *foo; unsigned short port; int len=sizeof(struct ai_v6)+(h.h_name?strlen(h.h_name):0); if (!(foo=malloc(len))) goto error; foo->ai.ai_next=0; foo->ai.ai_socktype=SOCK_STREAM; foo->ai.ai_protocol=IPPROTO_TCP; foo->ai.ai_addrlen=family==PF_INET6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in); foo->ai.ai_addr=(struct sockaddr*)&foo->ip; if (family==PF_INET6) { memset(&foo->ip,0,sizeof(foo->ip)); memmove(&foo->ip.ip6.sin6_addr,h.h_addr_list[0],16); } else { memmove(&foo->ip.ip4.sin_addr,h.h_addr_list[0],4); } foo->ip.ip6.sin6_family=foo->ai.ai_family=family; if (h.h_name) { foo->ai.ai_canonname=foo->name; memmove(foo->name,h.h_name,strlen(h.h_name)+1); } else foo->ai.ai_canonname=0; if (!hints || hints->ai_socktype!=SOCK_DGRAM) { /* TCP is OK */ char *x; port=htons(strtol(service?service:"0",&x,0)); if (*x) { /* service is not numeric :-( */ struct servent* se; if ((se=getservbyname(service,"tcp"))) { /* found a service. */ port=se->s_port; blah1: if (family==PF_INET6) foo->ip.ip6.sin6_port=port; else foo->ip.ip4.sin_port=port; if (!*tmp) *tmp=&(foo->ai); else (*tmp)->ai_next=&(foo->ai); if (!(foo=malloc(len))) goto error; memmove(foo,*tmp,len); tmp=&(*tmp)->ai_next; foo->ai.ai_addr=(struct sockaddr*)&foo->ip; if (foo->ai.ai_canonname) foo->ai.ai_canonname=foo->name; } else { freeaddrinfo(*res); return EAI_SERVICE; } } else goto blah1; } foo->ai.ai_socktype=SOCK_DGRAM; foo->ai.ai_protocol=IPPROTO_UDP; if (!hints || hints->ai_socktype!=SOCK_STREAM) { /* UDP is OK */ char *x; port=htons(strtol(service?service:"0",&x,0)); if (*x) { /* service is not numeric :-( */ struct servent* se; if ((se=getservbyname(service,"udp"))) { /* found a service. */ port=se->s_port; blah2: if (family==PF_INET6) foo->ip.ip6.sin6_port=port; else foo->ip.ip4.sin_port=port; if (!*tmp) *tmp=&(foo->ai); else (*tmp)->ai_next=&(foo->ai); if (!(foo=malloc(len))) goto error; memmove(foo,*tmp,len); tmp=&(*tmp)->ai_next; foo->ai.ai_addr=(struct sockaddr*)&foo->ip; foo->ai.ai_canonname=foo->name; } else { freeaddrinfo(*res); return EAI_SERVICE; } } else goto blah2; } free(foo); } } if (family==PF_INET) break; } if (*res==0) return EAI_NONAME; /* kludge kludge... */ return 0; error: freeaddrinfo(*res); return EAI_MEMORY; }