Import upstream 2.3.14
[packages/xinetd.git] / libs / src / portable / fake-getaddrinfo.c
1 #include "fake-getaddrinfo.h"
2 /*
3  * fake library for ssh
4  *
5  * This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
6  * These funtions are defined in rfc2133.
7  *
8  * But these functions are not implemented correctly. The minimum subset
9  * is implemented for ssh use only. For exapmle, this routine assumes
10  * that ai_family is AF_INET. Don't use it for another purpose.
11  */
12
13 #ifndef HAVE_GAI_STRERROR
14 char *gai_strerror(int ecode)
15 {
16         switch (ecode) {
17                 case EAI_NODATA:
18                         return "no address associated with hostname.";
19                 case EAI_MEMORY:
20                         return "memory allocation failure.";
21                 default:
22                         return "unknown error.";
23         }
24 }    
25 #endif /* !HAVE_GAI_STRERROR */
26
27 #ifndef HAVE_FREEADDRINFO
28 void freeaddrinfo(struct addrinfo *ai)
29 {
30         struct addrinfo *next;
31
32         do {
33                 next = ai->ai_next;
34                 free(ai);
35         } while (NULL != (ai = next));
36 }
37 #endif /* !HAVE_FREEADDRINFO */
38
39 #ifndef HAVE_GETADDRINFO
40 static struct addrinfo *malloc_ai(int port, u_long addr)
41 {
42         struct addrinfo *ai;
43
44         ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
45         if (ai == NULL)
46                 return(NULL);
47         
48         memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
49         
50         ai->ai_addr = (struct sockaddr *)(ai + 1);
51         /* XXX -- ssh doesn't use sa_len */
52         ai->ai_addrlen = sizeof(struct sockaddr_in);
53         ai->ai_addr->sa_family = ai->ai_family = AF_INET;
54
55         ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
56         ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
57         
58         return(ai);
59 }
60
61 int getaddrinfo(const char *hostname, const char *servname, 
62                 const struct addrinfo *hints, struct addrinfo **res)
63 {
64         struct addrinfo *cur, *prev = NULL;
65         struct hostent *hp;
66         struct in_addr in;
67         int i, port;
68
69         if (servname)
70                 port = htons(atoi(servname));
71         else
72                 port = 0;
73
74         if (hints && hints->ai_flags & AI_PASSIVE) {
75                 if (NULL != (*res = malloc_ai(port, htonl(0x00000000))))
76                         return 0;
77                 else
78                         return EAI_MEMORY;
79         }
80                 
81         if (!hostname) {
82                 if (NULL != (*res = malloc_ai(port, htonl(0x7f000001))))
83                         return 0;
84                 else
85                         return EAI_MEMORY;
86         }
87         
88         if (inet_aton(hostname, &in)) {
89                 if (NULL != (*res = malloc_ai(port, in.s_addr)))
90                         return 0;
91                 else
92                         return EAI_MEMORY;
93         }
94         
95         hp = gethostbyname(hostname);
96         if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
97                 for (i = 0; hp->h_addr_list[i]; i++) {
98                         cur = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
99                         if (cur == NULL) {
100                                 if (*res)
101                                         freeaddrinfo(*res);
102                                 return EAI_MEMORY;
103                         }
104                         
105                         if (prev)
106                                 prev->ai_next = cur;
107                         else
108                                 *res = cur;
109
110                         prev = cur;
111                 }
112                 return 0;
113         }
114         
115         return EAI_NODATA;
116 }
117 #endif /* !HAVE_GETADDRINFO */