include <malloc.h> only if HAVE_MALLOC_H and NEED_MALLOC_H are both defined.
[platform/upstream/curl.git] / lib / hostip6.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2005, 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 <string.h>
27
28 #if defined(HAVE_MALLOC_H) && defined(NEED_MALLOC_H)
29 #include <malloc.h>
30 #endif
31 #ifdef HAVE_SYS_TYPES_H
32 #include <sys/types.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40 #ifdef HAVE_NETDB_H
41 #include <netdb.h>
42 #endif
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
45 #endif
46 #ifdef HAVE_STDLIB_H
47 #include <stdlib.h>     /* required for free() prototypes */
48 #endif
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>     /* for the close() proto */
51 #endif
52 #ifdef  VMS
53 #include <in.h>
54 #include <inet.h>
55 #include <stdlib.h>
56 #endif
57
58 #ifdef HAVE_SETJMP_H
59 #include <setjmp.h>
60 #endif
61
62 #ifdef HAVE_PROCESS_H
63 #include <process.h>
64 #endif
65
66 #include "urldata.h"
67 #include "sendf.h"
68 #include "hostip.h"
69 #include "hash.h"
70 #include "share.h"
71 #include "strerror.h"
72 #include "url.h"
73 #include "inet_pton.h"
74 #include "connect.h"
75
76 #define _MPRINTF_REPLACE /* use our functions only */
77 #include <curl/mprintf.h>
78
79 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
80 #include "inet_ntoa_r.h"
81 #endif
82
83 #include "memory.h"
84 /* The last #include file should be: */
85 #include "memdebug.h"
86
87 /***********************************************************************
88  * Only for ipv6-enabled builds
89  **********************************************************************/
90 #ifdef CURLRES_IPV6
91 /*
92  * This is a wrapper function for freeing name information in a protocol
93  * independent way. This takes care of using the appropriate underlaying
94  * function.
95  */
96 void Curl_freeaddrinfo(Curl_addrinfo *p)
97 {
98   freeaddrinfo(p);
99 }
100
101 #ifdef CURLRES_ASYNCH
102 /*
103  * Curl_addrinfo_copy() is used by the asynch callback to copy a given
104  * address. But this is an ipv6 build and then we don't copy the address, we
105  * just return the same pointer!
106  */
107 Curl_addrinfo *Curl_addrinfo_copy(void *source, int port)
108 {
109   (void) port;
110   return source;
111 }
112 #endif
113
114 #ifdef CURLDEBUG
115 /* These are strictly for memory tracing and are using the same style as the
116  * family otherwise present in memdebug.c. I put these ones here since they
117  * require a bunch of structs I didn't wanna include in memdebug.c
118  */
119 int curl_dogetaddrinfo(char *hostname, char *service,
120                        struct addrinfo *hints,
121                        struct addrinfo **result,
122                        int line, const char *source)
123 {
124   int res=(getaddrinfo)(hostname, service, hints, result);
125   if(0 == res) {
126     /* success */
127     if(logfile)
128       fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
129               source, line, (void *)*result);
130   }
131   else {
132     if(logfile)
133       fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n",
134               source, line);
135   }
136   return res;
137 }
138
139 #ifdef HAVE_GETNAMEINFO
140 int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
141                        GETNAMEINFO_TYPE_ARG2 salen,
142                        char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
143                        char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
144                        GETNAMEINFO_TYPE_ARG7 flags,
145                        int line, const char *source)
146 {
147   int res = (getnameinfo)(sa, salen,
148                           host, hostlen,
149                           serv, servlen,
150                           flags);
151   if(0 == res) {
152     /* success */
153     if(logfile)
154       fprintf(logfile, "GETNAME %s:%d getnameinfo()\n",
155               source, line);
156   }
157   else {
158     if(logfile)
159       fprintf(logfile, "GETNAME %s:%d getnameinfo() failed = %d\n",
160               source, line, res);
161   }
162   return res;
163 }
164 #endif
165
166 void curl_dofreeaddrinfo(struct addrinfo *freethis,
167                          int line, const char *source)
168 {
169   (freeaddrinfo)(freethis);
170   if(logfile)
171     fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
172             source, line, (void *)freethis);
173 }
174
175 #endif
176
177 /*
178  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
179  * been set and returns TRUE if they are OK.
180  */
181 bool Curl_ipvalid(struct SessionHandle *data)
182 {
183   if(data->set.ip_version == CURL_IPRESOLVE_V6) {
184     /* see if we have an IPv6 stack */
185     curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
186     if (s == CURL_SOCKET_BAD)
187       /* an ipv6 address was requested and we can't get/use one */
188       return FALSE;
189     sclose(s);
190   }
191   return TRUE;
192 }
193
194 #ifndef USE_THREADING_GETADDRINFO
195
196 #ifdef DEBUG_ADDRINFO
197 static void dump_addrinfo(struct connectdata *conn, const struct addrinfo *ai)
198 {
199   printf("dump_addrinfo:\n");
200   for ( ; ai; ai = ai->ai_next) {
201     char  buf[INET6_ADDRSTRLEN];
202
203     printf("    fam %2d, CNAME %s, ",
204            ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
205     if (Curl_printable_address(ai, buf, sizeof(buf)))
206       printf("%s\n", buf);
207     else
208       printf("failed; %s\n", Curl_strerror(conn, Curl_sockerrno()));
209   }
210 }
211 #else
212 #define dump_addrinfo(x,y)
213 #endif
214
215 /*
216  * Curl_getaddrinfo() when built ipv6-enabled (non-threading version).
217  *
218  * Returns name information about the given hostname and port number. If
219  * successful, the 'addrinfo' is returned and the forth argument will point to
220  * memory we need to free after use. That memory *MUST* be freed with
221  * Curl_freeaddrinfo(), nothing else.
222  */
223 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
224                                 char *hostname,
225                                 int port,
226                                 int *waitp)
227 {
228   struct addrinfo hints, *res;
229   int error;
230   char sbuf[NI_MAXSERV];
231   char *sbufptr = NULL;
232   char addrbuf[128];
233   curl_socket_t s;
234   int pf;
235   struct SessionHandle *data = conn->data;
236
237   *waitp=0; /* don't wait, we have the response now */
238
239   /* see if we have an IPv6 stack */
240   s = socket(PF_INET6, SOCK_DGRAM, 0);
241   if (s < 0) {
242     /* Some non-IPv6 stacks have been found to make very slow name resolves
243      * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
244      * the stack seems to be a non-ipv6 one. */
245
246     pf = PF_INET;
247   }
248   else {
249     /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
250      * possible checks. And close the socket again.
251      */
252     sclose(s);
253
254     /*
255      * Check if a more limited name resolve has been requested.
256      */
257     switch(data->set.ip_version) {
258     case CURL_IPRESOLVE_V4:
259       pf = PF_INET;
260       break;
261     case CURL_IPRESOLVE_V6:
262       pf = PF_INET6;
263       break;
264     default:
265       pf = PF_UNSPEC;
266       break;
267     }
268   }
269
270   memset(&hints, 0, sizeof(hints));
271   hints.ai_family = pf;
272   hints.ai_socktype = conn->socktype;
273
274   if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
275      (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
276     /* the given address is numerical only, prevent a reverse lookup */
277     hints.ai_flags = AI_NUMERICHOST;
278   }
279 #if 0 /* removed nov 8 2005 before 7.15.1 */
280   else
281     hints.ai_flags = AI_CANONNAME;
282 #endif
283
284   if(port) {
285     snprintf(sbuf, sizeof(sbuf), "%d", port);
286     sbufptr=sbuf;
287   }
288   error = getaddrinfo(hostname, sbufptr, &hints, &res);
289   if (error) {
290     infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
291     return NULL;
292   }
293
294   dump_addrinfo(conn, res);
295
296   return res;
297 }
298 #endif /* USE_THREADING_GETADDRINFO */
299 #endif /* ipv6 */
300