Moved potential inclusion of system's malloc.h and memory.h header files to
[platform/upstream/curl.git] / lib / curl_addrinfo.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id$
22  ***************************************************************************/
23
24 #include "setup.h"
25
26 #include <curl/curl.h>
27
28 #ifdef HAVE_SYS_SOCKET_H
29 #  include <sys/socket.h>
30 #endif
31 #ifdef HAVE_NETINET_IN_H
32 #  include <netinet/in.h>
33 #endif
34 #ifdef HAVE_NETDB_H
35 #  include <netdb.h>
36 #endif
37 #ifdef HAVE_ARPA_INET_H
38 #  include <arpa/inet.h>
39 #endif
40
41 #ifdef  VMS
42 #  include <in.h>
43 #  include <inet.h>
44 #  include <stdlib.h>
45 #endif
46
47 #if defined(NETWARE) && defined(__NOVELL_LIBC__)
48 #  undef  in_addr_t
49 #  define in_addr_t unsigned long
50 #endif
51
52 #include "curl_addrinfo.h"
53
54 #define _MPRINTF_REPLACE /* use our functions only */
55 #include <curl/mprintf.h>
56
57 #include "memory.h"
58 /* The last #include file should be: */
59 #include "memdebug.h"
60
61
62 /*
63  * Curl_freeaddrinfo()
64  *
65  * This is used to free a linked list of Curl_addrinfo structs along
66  * with all its associated allocated storage. This function should be
67  * called once for each successful call to Curl_getaddrinfo_ex() or to
68  * any function call which actually allocates a Curl_addrinfo struct.
69  */
70
71 void
72 Curl_freeaddrinfo(Curl_addrinfo *cahead)
73 {
74 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
75     defined(__unix__) &&  defined(__i386__)
76   /* workaround icc 9.1 optimizer issue */
77   volatile Curl_addrinfo * volatile ca;
78   volatile Curl_addrinfo * volatile canext;
79 #else
80   Curl_addrinfo *ca, *canext;
81 #endif
82
83   for(ca = cahead; ca != NULL; ca = canext) {
84
85     if(ca->ai_addr)
86       free(ca->ai_addr);
87
88     if(ca->ai_canonname)
89       free(ca->ai_canonname);
90
91     canext = ca->ai_next;
92
93     free(ca);
94   }
95 }
96
97
98 #ifdef HAVE_GETADDRINFO
99 /*
100  * Curl_getaddrinfo_ex()
101  *
102  * This is a wrapper function around system's getaddrinfo(), with
103  * the only difference that instead of returning a linked list of
104  * addrinfo structs this one returns a linked list of Curl_addrinfo
105  * ones. The memory allocated by this function *MUST* be free'd with
106  * Curl_freeaddrinfo().  For each successful call to this function
107  * there must be an associated call later to Curl_freeaddrinfo().
108  *
109  * There should be no single call to system's getaddrinfo() in the
110  * whole library, any such call should be 'routed' through this one.
111  */
112
113 int
114 Curl_getaddrinfo_ex(const char *nodename,
115                     const char *servname,
116                     const struct addrinfo *hints,
117                     Curl_addrinfo **result)
118 {
119   const struct addrinfo *ainext;
120   const struct addrinfo *ai;
121   struct addrinfo *aihead;
122   Curl_addrinfo *cafirst = NULL;
123   Curl_addrinfo *calast = NULL;
124   Curl_addrinfo *ca;
125   int error;
126
127   *result = NULL; /* assume failure */
128
129   error = getaddrinfo(nodename, servname, hints, &aihead);
130   if(error)
131     return error;
132
133   for(ai = aihead; ai != NULL; ai = ainext) {
134
135     if((ca = malloc(sizeof(Curl_addrinfo))) == NULL) {
136       error = EAI_MEMORY;
137       break;
138     }
139
140     /* copy each structure member individually, member ordering, */
141     /* size, or padding might be different for each structure.   */
142
143     ca->ai_flags     = ai->ai_flags;
144     ca->ai_family    = ai->ai_family;
145     ca->ai_socktype  = ai->ai_socktype;
146     ca->ai_protocol  = ai->ai_protocol;
147     ca->ai_addrlen   = 0;
148     ca->ai_addr      = NULL;
149     ca->ai_canonname = NULL;
150     ca->ai_next      = NULL;
151
152     if((ai->ai_addrlen > 0) && (ai->ai_addr != NULL)) {
153       ca->ai_addrlen  = ai->ai_addrlen;
154       if((ca->ai_addr = malloc(ca->ai_addrlen)) == NULL) {
155         error = EAI_MEMORY;
156         free(ca);
157         break;
158       }
159       memcpy(ca->ai_addr, ai->ai_addr, ca->ai_addrlen);
160     }
161
162     if(ai->ai_canonname != NULL) {
163       if((ca->ai_canonname = strdup(ai->ai_canonname)) == NULL) {
164         error = EAI_MEMORY;
165         if(ca->ai_addr)
166           free(ca->ai_addr);
167         free(ca);
168         break;
169       }
170     }
171
172     /* if the return list is empty, this becomes the first element */
173     if(!cafirst)
174       cafirst = ca;
175
176     /* add this element last in the return list */
177     if(calast)
178       calast->ai_next = ca;
179     calast = ca;
180
181     /* fetch next element fom the addrinfo list */
182     ainext = ai->ai_next;
183   }
184
185   /* destroy the addrinfo list */
186   if(aihead)
187     freeaddrinfo(aihead);
188
189   /* if we failed, also destroy the Curl_addrinfo list */
190   if(error) {
191     Curl_freeaddrinfo(cafirst);
192     cafirst = NULL;
193   }
194
195   *result = cafirst;
196
197   /* This is not a CURLcode */
198   return error;
199 }
200 #endif /* HAVE_GETADDRINFO */
201
202
203 /*
204  * Curl_he2ai()
205  *
206  * This function returns a pointer to the first element of a newly allocated
207  * Curl_addrinfo struct linked list filled with the data of a given hostent.
208  * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
209  * stack, but usable also for IPv4, all hosts and environments.
210  *
211  * The memory allocated by this function *MUST* be free'd later on calling
212  * Curl_freeaddrinfo().  For each successful call to this function there
213  * must be an associated call later to Curl_freeaddrinfo().
214  *
215  *   Curl_addrinfo defined in "lib/curl_addrinfo.h"
216  *
217  *     struct Curl_addrinfo {
218  *       int                   ai_flags;
219  *       int                   ai_family;
220  *       int                   ai_socktype;
221  *       int                   ai_protocol;
222  *       socklen_t             ai_addrlen;   * Follow rfc3493 struct addrinfo *
223  *       char                 *ai_canonname;
224  *       struct sockaddr      *ai_addr;
225  *       struct Curl_addrinfo *ai_next;
226  *     };
227  *     typedef struct Curl_addrinfo Curl_addrinfo;
228  *
229  *   hostent defined in <netdb.h>
230  *
231  *     struct hostent {
232  *       char    *h_name;
233  *       char    **h_aliases;
234  *       int     h_addrtype;
235  *       int     h_length;
236  *       char    **h_addr_list;
237  *     };
238  *
239  *   for backward compatibility:
240  *
241  *     #define h_addr  h_addr_list[0]
242  */
243
244 Curl_addrinfo *
245 Curl_he2ai(const struct hostent *he, int port)
246 {
247   Curl_addrinfo *ai;
248   Curl_addrinfo *prevai = NULL;
249   Curl_addrinfo *firstai = NULL;
250   struct sockaddr_in *addr;
251 #ifdef ENABLE_IPV6
252   struct sockaddr_in6 *addr6;
253 #endif
254   CURLcode result = CURLE_OK;
255   int i;
256   char *curr;
257
258   if(!he)
259     /* no input == no output! */
260     return NULL;
261
262   DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
263
264   for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) {
265
266     size_t ss_size;
267 #ifdef ENABLE_IPV6
268     if (he->h_addrtype == AF_INET6)
269       ss_size = sizeof (struct sockaddr_in6);
270     else
271 #endif
272       ss_size = sizeof (struct sockaddr_in);
273
274     if((ai = calloc(1, sizeof(Curl_addrinfo))) == NULL) {
275       result = CURLE_OUT_OF_MEMORY;
276       break;
277     }
278     if((ai->ai_canonname = strdup(he->h_name)) == NULL) {
279       result = CURLE_OUT_OF_MEMORY;
280       free(ai);
281       break;
282     }
283     if((ai->ai_addr = calloc(1, ss_size)) == NULL) {
284       result = CURLE_OUT_OF_MEMORY;
285       free(ai->ai_canonname);
286       free(ai);
287       break;
288     }
289
290     if(!firstai)
291       /* store the pointer we want to return from this function */
292       firstai = ai;
293
294     if(prevai)
295       /* make the previous entry point to this */
296       prevai->ai_next = ai;
297
298     ai->ai_family = he->h_addrtype;
299
300     /* we return all names as STREAM, so when using this address for TFTP
301        the type must be ignored and conn->socktype be used instead! */
302     ai->ai_socktype = SOCK_STREAM;
303
304     ai->ai_addrlen = (int)ss_size;
305
306     /* leave the rest of the struct filled with zero */
307
308     switch (ai->ai_family) {
309     case AF_INET:
310       addr = (void *)ai->ai_addr; /* storage area for this info */
311
312       memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
313       addr->sin_family = (unsigned short)(he->h_addrtype);
314       addr->sin_port = htons((unsigned short)port);
315       break;
316
317 #ifdef ENABLE_IPV6
318     case AF_INET6:
319       addr6 = (void *)ai->ai_addr; /* storage area for this info */
320
321       memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
322       addr6->sin6_family = (unsigned short)(he->h_addrtype);
323       addr6->sin6_port = htons((unsigned short)port);
324       break;
325 #endif
326     }
327
328     prevai = ai;
329   }
330
331   if(result != CURLE_OK) {
332     Curl_freeaddrinfo(firstai);
333     firstai = NULL;
334   }
335
336   return firstai;
337 }
338
339
340 struct namebuff {
341   struct hostent hostentry;
342   union {
343     struct in_addr  ina4;
344 #ifdef ENABLE_IPV6
345     struct in6_addr ina6;
346 #endif
347   } addrentry;
348   char *h_addr_list[2];
349 };
350
351
352 /*
353  * Curl_ip2addr()
354  *
355  * This function takes an internet address, in binary form, as input parameter
356  * along with its address family and the string version of the address, and it
357  * returns a Curl_addrinfo chain filled in correctly with information for the
358  * given address/host
359  */
360
361 Curl_addrinfo *
362 Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
363 {
364   Curl_addrinfo *ai;
365
366 #if defined(VMS) && \
367     defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
368 #pragma pointer_size save
369 #pragma pointer_size short
370 #pragma message disable PTRMISMATCH
371 #endif
372
373   struct hostent  *h;
374   struct namebuff *buf;
375   char  *addrentry;
376   char  *hoststr;
377   size_t addrsize;
378
379   DEBUGASSERT(inaddr && hostname);
380
381   buf = malloc(sizeof(struct namebuff));
382   if(!buf)
383     return NULL;
384
385   hoststr = strdup(hostname);
386   if(!hoststr) {
387     free(buf);
388     return NULL;
389   }
390
391   switch(af) {
392   case AF_INET:
393     addrsize = sizeof(struct in_addr);
394     addrentry = (void *)&buf->addrentry.ina4;
395     memcpy(addrentry, inaddr, sizeof(struct in_addr));
396     break;
397 #ifdef ENABLE_IPV6
398   case AF_INET6:
399     addrsize = sizeof(struct in6_addr);
400     addrentry = (void *)&buf->addrentry.ina6;
401     memcpy(addrentry, inaddr, sizeof(struct in6_addr));
402     break;
403 #endif
404   default:
405     free(hoststr);
406     free(buf);
407     return NULL;
408   }
409
410   h = &buf->hostentry;
411   h->h_name = hoststr;
412   h->h_aliases = NULL;
413   h->h_addrtype = (short)af;
414   h->h_length = (short)addrsize;
415   h->h_addr_list = &buf->h_addr_list[0];
416   h->h_addr_list[0] = addrentry;
417   h->h_addr_list[1] = NULL; /* terminate list of entries */
418
419 #if defined(VMS) && \
420     defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
421 #pragma pointer_size restore
422 #pragma message enable PTRMISMATCH
423 #endif
424
425   ai = Curl_he2ai(h, port);
426
427   free(hoststr);
428   free(buf);
429
430   return ai;
431 }
432
433
434 #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
435 /*
436  * curl_dofreeaddrinfo()
437  *
438  * This is strictly for memory tracing and are using the same style as the
439  * family otherwise present in memdebug.c. I put these ones here since they
440  * require a bunch of structs I didn't wanna include in memdebug.c
441  */
442
443 void
444 curl_dofreeaddrinfo(struct addrinfo *freethis,
445                     int line, const char *source)
446 {
447   (freeaddrinfo)(freethis);
448   if(logfile)
449     fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
450             source, line, (void *)freethis);
451 }
452 #endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
453
454
455 #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
456 /*
457  * curl_dogetaddrinfo()
458  *
459  * This is strictly for memory tracing and are using the same style as the
460  * family otherwise present in memdebug.c. I put these ones here since they
461  * require a bunch of structs I didn't wanna include in memdebug.c
462  */
463
464 int
465 curl_dogetaddrinfo(const char *hostname,
466                    const char *service,
467                    const struct addrinfo *hints,
468                    struct addrinfo **result,
469                    int line, const char *source)
470 {
471   int res=(getaddrinfo)(hostname, service, hints, result);
472   if(0 == res) {
473     /* success */
474     if(logfile)
475       fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
476               source, line, (void *)*result);
477   }
478   else {
479     if(logfile)
480       fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n",
481               source, line);
482   }
483   return res;
484 }
485 #endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
486