warnings: fix some 'conversion may lose significant bits' compiler warnings
[platform/upstream/c-ares.git] / ares__get_hostent.c
1
2 /* Copyright 1998, 2011 by the Massachusetts Institute of Technology.
3  *
4  * Permission to use, copy, modify, and distribute this
5  * software and its documentation for any purpose and without
6  * fee is hereby granted, provided that the above copyright
7  * notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting
9  * documentation, and that the name of M.I.T. not be used in
10  * advertising or publicity pertaining to distribution of the
11  * software without specific, written prior permission.
12  * M.I.T. makes no representations about the suitability of
13  * this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  */
16
17 #include "ares_setup.h"
18
19 #ifdef HAVE_SYS_SOCKET_H
20 #  include <sys/socket.h>
21 #endif
22 #ifdef HAVE_NETINET_IN_H
23 #  include <netinet/in.h>
24 #endif
25 #ifdef HAVE_NETDB_H
26 #  include <netdb.h>
27 #endif
28 #ifdef HAVE_ARPA_INET_H
29 #  include <arpa/inet.h>
30 #endif
31
32 #include "ares.h"
33 #include "inet_net_pton.h"
34 #include "ares_nowarn.h"
35 #include "ares_private.h"
36
37 int ares__get_hostent(FILE *fp, int family, struct hostent **host)
38 {
39   char *line = NULL, *p, *q, **alias;
40   char *txtaddr, *txthost, *txtalias;
41   int status;
42   size_t addrlen, linesize, naliases;
43   struct ares_addr addr;
44   struct hostent *hostent = NULL;
45
46   *host = NULL; /* Assume failure */
47
48   /* Validate family */
49   switch (family) {
50     case AF_INET:
51     case AF_INET6:
52     case AF_UNSPEC:
53       break;
54     default:
55       return ARES_EBADFAMILY;
56   }
57
58   while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
59     {
60
61       /* Trim line comment. */
62       p = line;
63       while (*p && (*p != '#'))
64         p++;
65       *p = '\0';
66
67       /* Trim trailing whitespace. */
68       q = p - 1;
69       while ((q >= line) && ISSPACE(*q))
70         q--;
71       *++q = '\0';
72
73       /* Skip leading whitespace. */
74       p = line;
75       while (*p && ISSPACE(*p))
76         p++;
77       if (!*p)
78         /* Ignore line if empty. */
79         continue;
80
81       /* Pointer to start of IPv4 or IPv6 address part. */
82       txtaddr = p;
83
84       /* Advance past address part. */
85       while (*p && !ISSPACE(*p))
86         p++;
87       if (!*p)
88         /* Ignore line if reached end of line. */
89         continue;
90
91       /* Null terminate address part. */
92       *p = '\0';
93
94       /* Advance to host name */
95       p++;
96       while (*p && ISSPACE(*p))
97         p++;
98       if (!*p)
99         /* Ignore line if reached end of line. */
100         continue;
101
102       /* Pointer to start of host name. */
103       txthost = p;
104
105       /* Advance past host name. */
106       while (*p && !ISSPACE(*p))
107         p++;
108
109       /* Pointer to start of first alias. */
110       txtalias = NULL;
111       if (*p)
112         {
113           q = p + 1;
114           while (*q && ISSPACE(*q))
115             q++;
116           if (*q)
117             txtalias = q;
118         }
119
120       /* Null terminate host name. */
121       *p = '\0';
122
123       /* find out number of aliases. */
124       naliases = 0;
125       if (txtalias)
126         {
127           p = txtalias;
128           while (*p)
129             {
130               while (*p && !ISSPACE(*p))
131                 p++;
132               while (*p && ISSPACE(*p))
133                 p++;
134               naliases++;
135             }
136         }
137
138       /* Convert address string to network address for the requested family. */
139       addrlen = 0;
140       addr.family = AF_UNSPEC;
141       addr.addrV4.s_addr = INADDR_NONE;
142       if ((family == AF_INET) || (family == AF_UNSPEC))
143         {
144           addr.addrV4.s_addr = inet_addr(txtaddr);
145           if (addr.addrV4.s_addr != INADDR_NONE)
146             {
147               /* Actual network address family and length. */
148               addr.family = AF_INET;
149               addrlen = sizeof(addr.addrV4);
150             }
151         }
152       if ((family == AF_INET6) || ((family == AF_UNSPEC) && (!addrlen)))
153         {
154           if (ares_inet_pton(AF_INET6, txtaddr, &addr.addrV6) > 0)
155             {
156               /* Actual network address family and length. */
157               addr.family = AF_INET6;
158               addrlen = sizeof(addr.addrV6);
159             }
160         }
161       if (!addrlen)
162         /* Ignore line if invalid address string for the requested family. */
163         continue;
164
165       /*
166       ** Actual address family possible values are AF_INET and AF_INET6 only.
167       */
168
169       /* Allocate memory for the hostent structure. */
170       hostent = malloc(sizeof(struct hostent));
171       if (!hostent)
172         break;
173
174       /* Initialize fields for out of memory condition. */
175       hostent->h_aliases = NULL;
176       hostent->h_addr_list = NULL;
177
178       /* Copy official host name. */
179       hostent->h_name = strdup(txthost);
180       if (!hostent->h_name)
181         break;
182
183       /* Copy network address. */
184       hostent->h_addr_list = malloc(2 * sizeof(char *));
185       if (!hostent->h_addr_list)
186         break;
187       hostent->h_addr_list[1] = NULL;
188       hostent->h_addr_list[0] = malloc(addrlen);
189       if (!hostent->h_addr_list[0])
190         break;
191       if (addr.family == AF_INET)
192         memcpy(hostent->h_addr_list[0], &addr.addrV4, sizeof(addr.addrV4));
193       else
194         memcpy(hostent->h_addr_list[0], &addr.addrV6, sizeof(addr.addrV6));
195
196       /* Copy aliases. */
197       hostent->h_aliases = malloc((naliases + 1) * sizeof(char *));
198       if (!hostent->h_aliases)
199         break;
200       alias = hostent->h_aliases;
201       while (naliases)
202         *(alias + naliases--) = NULL;
203       *alias = NULL;
204       while (txtalias)
205         {
206           p = txtalias;
207           while (*p && !ISSPACE(*p))
208             p++;
209           q = p;
210           while (*q && ISSPACE(*q))
211             q++;
212           *p = '\0';
213           if ((*alias = strdup(txtalias)) == NULL)
214             break;
215           alias++;
216           txtalias = *q ? q : NULL;
217         }
218       if (txtalias)
219         /* Alias memory allocation failure. */
220         break;
221
222       /* Copy actual network address family and length. */
223       hostent->h_addrtype = aresx_sitoss(addr.family);
224       hostent->h_length = aresx_uztoss(addrlen);
225
226       /* Free line buffer. */
227       free(line);
228
229       /* Return hostent successfully */
230       *host = hostent;
231       return ARES_SUCCESS;
232
233     }
234
235   /* If allocated, free line buffer. */
236   if (line)
237     free(line);
238
239   if (status == ARES_SUCCESS)
240     {
241       /* Memory allocation failure; clean up. */
242       if (hostent)
243         {
244           if (hostent->h_name)
245             free((char *) hostent->h_name);
246           if (hostent->h_aliases)
247             {
248               for (alias = hostent->h_aliases; *alias; alias++)
249                 free(*alias);
250               free(hostent->h_aliases);
251             }
252           if (hostent->h_addr_list)
253             {
254               if (hostent->h_addr_list[0])
255                 free(hostent->h_addr_list[0]);
256               free(hostent->h_addr_list);
257             }
258           free(hostent);
259         }
260       return ARES_ENOMEM;
261     }
262
263   return status;
264 }