PageRenderTime 40ms CodeModel.GetById 12ms app.highlight 22ms RepoModel.GetById 2ms app.codeStats 0ms

/src/ares/ares__get_hostent.c

http://github.com/joyent/libuv
C | 263 lines | 181 code | 34 blank | 48 comment | 67 complexity | d21d660bc27e5c08be30fdad222c76af MD5 | raw file
  1
  2/* Copyright 1998, 2010 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_private.h"
 35
 36int ares__get_hostent(FILE *fp, int family, struct hostent **host)
 37{
 38  char *line = NULL, *p, *q, **alias;
 39  char *txtaddr, *txthost, *txtalias;
 40  int status;
 41  size_t addrlen, linesize, naliases;
 42  struct ares_addr addr;
 43  struct hostent *hostent = NULL;
 44
 45  *host = NULL; /* Assume failure */
 46
 47  /* Validate family */
 48  switch (family) {
 49    case AF_INET:
 50    case AF_INET6:
 51    case AF_UNSPEC:
 52      break;
 53    default:
 54      return ARES_EBADFAMILY;
 55  }
 56
 57  while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
 58    {
 59
 60      /* Trim line comment. */
 61      p = line;
 62      while (*p && (*p != '#'))
 63        p++;
 64      *p = '\0';
 65
 66      /* Trim trailing whitespace. */
 67      q = p - 1;
 68      while ((q >= line) && ISSPACE(*q))
 69        q--;
 70      *++q = '\0';
 71
 72      /* Skip leading whitespace. */
 73      p = line;
 74      while (*p && ISSPACE(*p))
 75        p++;
 76      if (!*p)
 77        /* Ignore line if empty. */
 78        continue;
 79
 80      /* Pointer to start of IPv4 or IPv6 address part. */
 81      txtaddr = p;
 82
 83      /* Advance past address part. */
 84      while (*p && !ISSPACE(*p))
 85        p++;
 86      if (!*p)
 87        /* Ignore line if reached end of line. */
 88        continue;
 89
 90      /* Null terminate address part. */
 91      *p = '\0';
 92
 93      /* Advance to host name */
 94      p++;
 95      while (*p && ISSPACE(*p))
 96        p++;
 97      if (!*p)
 98        /* Ignore line if reached end of line. */
 99        continue;
100
101      /* Pointer to start of host name. */
102      txthost = p;
103
104      /* Advance past host name. */
105      while (*p && !ISSPACE(*p))
106        p++;
107
108      /* Pointer to start of first alias. */
109      txtalias = NULL;
110      if (*p)
111        {
112          q = p + 1;
113          while (*q && ISSPACE(*q))
114            q++;
115          if (*q)
116            txtalias = q;
117        }
118
119      /* Null terminate host name. */
120      *p = '\0';
121
122      /* find out number of aliases. */
123      naliases = 0;
124      if (txtalias)
125        {
126          p = txtalias;
127          while (*p)
128            {
129              while (*p && !ISSPACE(*p))
130                p++;
131              while (*p && ISSPACE(*p))
132                p++;
133              naliases++;
134            }
135        }
136
137      /* Convert address string to network address for the requested family. */
138      addrlen = 0;
139      addr.family = AF_UNSPEC;
140      addr.addrV4.s_addr = INADDR_NONE;
141      if ((family == AF_INET) || (family == AF_UNSPEC))
142        {
143          addr.addrV4.s_addr = inet_addr(txtaddr);
144          if (addr.addrV4.s_addr != INADDR_NONE)
145            {
146              /* Actual network address family and length. */
147              addr.family = AF_INET;
148              addrlen = sizeof(addr.addrV4);
149            }
150        }
151      if ((family == AF_INET6) || ((family == AF_UNSPEC) && (!addrlen)))
152        {
153          if (ares_inet_pton(AF_INET6, txtaddr, &addr.addrV6) > 0)
154            {
155              /* Actual network address family and length. */
156              addr.family = AF_INET6;
157              addrlen = sizeof(addr.addrV6);
158            }
159        }
160      if (!addrlen)
161        /* Ignore line if invalid address string for the requested family. */
162        continue;
163
164      /*
165      ** Actual address family possible values are AF_INET and AF_INET6 only.
166      */
167
168      /* Allocate memory for the hostent structure. */
169      hostent = malloc(sizeof(struct hostent));
170      if (!hostent)
171        break;
172
173      /* Initialize fields for out of memory condition. */
174      hostent->h_aliases = NULL;
175      hostent->h_addr_list = NULL;
176
177      /* Copy official host name. */
178      hostent->h_name = strdup(txthost);
179      if (!hostent->h_name)
180        break;
181
182      /* Copy network address. */
183      hostent->h_addr_list = malloc(2 * sizeof(char *));
184      if (!hostent->h_addr_list)
185        break;
186      hostent->h_addr_list[1] = NULL;
187      hostent->h_addr_list[0] = malloc(addrlen);
188      if (!hostent->h_addr_list[0])
189        break;
190      if (addr.family == AF_INET)
191        memcpy(hostent->h_addr_list[0], &addr.addrV4, sizeof(addr.addrV4));
192      else
193        memcpy(hostent->h_addr_list[0], &addr.addrV6, sizeof(addr.addrV6));
194
195      /* Copy aliases. */
196      hostent->h_aliases = malloc((naliases + 1) * sizeof(char *));
197      if (!hostent->h_aliases)
198        break;
199      alias = hostent->h_aliases;
200      while (naliases)
201        *(alias + naliases--) = NULL;
202      *alias = NULL;
203      while (txtalias)
204        {
205          p = txtalias;
206          while (*p && !ISSPACE(*p))
207            p++;
208          q = p;
209          while (*q && ISSPACE(*q))
210            q++;
211          *p = '\0';
212          if ((*alias = strdup(txtalias)) == NULL)
213            break;
214          alias++;
215          txtalias = *q ? q : NULL;
216        }
217      if (txtalias)
218        /* Alias memory allocation failure. */
219        break;
220
221      /* Copy actual network address family and length. */
222      hostent->h_addrtype = addr.family;
223      hostent->h_length = (int)addrlen;
224
225      /* Free line buffer. */
226      free(line);
227
228      /* Return hostent successfully */
229      *host = hostent;
230      return ARES_SUCCESS;
231
232    }
233
234  /* If allocated, free line buffer. */
235  if (line)
236    free(line);
237
238  if (status == ARES_SUCCESS)
239    {
240      /* Memory allocation failure; clean up. */
241      if (hostent)
242        {
243          if (hostent->h_name)
244            free((char *) hostent->h_name);
245          if (hostent->h_aliases)
246            {
247              for (alias = hostent->h_aliases; *alias; alias++)
248                free(*alias);
249              free(hostent->h_aliases);
250            }
251          if (hostent->h_addr_list)
252            {
253              if (hostent->h_addr_list[0])
254                free(hostent->h_addr_list[0]);
255              free(hostent->h_addr_list);
256            }
257          free(hostent);
258        }
259      return ARES_ENOMEM;
260    }
261
262  return status;
263}