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