Initial commit.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl / hostares.c
blob1f37921e6cac043ca2476041b63e94254a08062b
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: hostares.c,v 1.2 2007/03/15 19:22:13 andy Exp $
22 ***************************************************************************/
24 #include "setup.h"
26 #include <string.h>
28 #ifdef 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
58 #ifdef HAVE_SETJMP_H
59 #include <setjmp.h>
60 #endif
62 #ifdef HAVE_PROCESS_H
63 #include <process.h>
64 #endif
66 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
67 #undef in_addr_t
68 #define in_addr_t unsigned long
69 #endif
71 #include "urldata.h"
72 #include "sendf.h"
73 #include "hostip.h"
74 #include "hash.h"
75 #include "share.h"
76 #include "strerror.h"
77 #include "url.h"
78 #include "multiif.h"
79 #include "connect.h" /* for the Curl_sockerrno() proto */
81 #define _MPRINTF_REPLACE /* use our functions only */
82 #include <curl/mprintf.h>
84 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
85 #include "inet_ntoa_r.h"
86 #endif
88 #include "memory.h"
90 /* The last #include file should be: */
91 #include "memdebug.h"
93 /***********************************************************************
94 * Only for ares-enabled builds
95 **********************************************************************/
97 #ifdef CURLRES_ARES
100 * Curl_resolv_fdset() is called when someone from the outside world (using
101 * curl_multi_fdset()) wants to get our fd_set setup and we're talking with
102 * ares. The caller must make sure that this function is only called when we
103 * have a working ares channel.
105 * Returns: CURLE_OK always!
108 int Curl_resolv_getsock(struct connectdata *conn,
109 curl_socket_t *socks,
110 int numsocks)
113 struct timeval maxtime;
114 struct timeval timeout;
115 int max = ares_getsock(conn->data->state.areschannel,
116 (int *)socks, numsocks);
119 maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
120 maxtime.tv_usec = 0;
122 ares_timeout(conn->data->state.areschannel, &maxtime, &timeout);
124 Curl_expire(conn->data,
125 (timeout.tv_sec * 1000) + (timeout.tv_usec/1000) );
127 return max;
131 * Curl_is_resolved() is called repeatedly to check if a previous name resolve
132 * request has completed. It should also make sure to time-out if the
133 * operation seems to take too long.
135 * Returns normal CURLcode errors.
137 CURLcode Curl_is_resolved(struct connectdata *conn,
138 struct Curl_dns_entry **dns)
140 fd_set read_fds, write_fds;
141 struct timeval tv={0,0};
142 struct SessionHandle *data = conn->data;
143 int nfds;
145 FD_ZERO(&read_fds);
146 FD_ZERO(&write_fds);
148 nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
150 (void)select(nfds, &read_fds, &write_fds, NULL,
151 (struct timeval *)&tv);
153 /* Call ares_process() unconditonally here, even if we simply timed out
154 above, as otherwise the ares name resolve won't timeout! */
155 ares_process(data->state.areschannel, &read_fds, &write_fds);
157 *dns = NULL;
159 if(conn->async.done) {
160 /* we're done, kill the ares handle */
161 if(!conn->async.dns) {
162 failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
163 ares_strerror(conn->async.status));
164 return CURLE_COULDNT_RESOLVE_HOST;
166 *dns = conn->async.dns;
169 return CURLE_OK;
173 * Curl_wait_for_resolv() waits for a resolve to finish. This function should
174 * be avoided since using this risk getting the multi interface to "hang".
176 * If 'entry' is non-NULL, make it point to the resolved dns entry
178 * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
179 * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
181 CURLcode Curl_wait_for_resolv(struct connectdata *conn,
182 struct Curl_dns_entry **entry)
184 CURLcode rc=CURLE_OK;
185 struct SessionHandle *data = conn->data;
186 long timeout = CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */
188 /* now, see if there's a connect timeout or a regular timeout to
189 use instead of the default one */
190 if(conn->data->set.connecttimeout)
191 timeout = conn->data->set.connecttimeout;
192 else if(conn->data->set.timeout)
193 timeout = conn->data->set.timeout;
195 /* We convert the number of seconds into number of milliseconds here: */
196 if(timeout < 2147483)
197 /* maximum amount of seconds that can be multiplied with 1000 and
198 still fit within 31 bits */
199 timeout *= 1000;
200 else
201 timeout = 0x7fffffff; /* ridiculous amount of time anyway */
203 /* Wait for the name resolve query to complete. */
204 while (1) {
205 int nfds=0;
206 fd_set read_fds, write_fds;
207 struct timeval *tvp, tv, store;
208 int count;
209 struct timeval now = Curl_tvnow();
210 long timediff;
212 store.tv_sec = (int)timeout/1000;
213 store.tv_usec = (timeout%1000)*1000;
215 FD_ZERO(&read_fds);
216 FD_ZERO(&write_fds);
217 nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
218 if (nfds == 0)
219 /* no file descriptors means we're done waiting */
220 break;
221 tvp = ares_timeout(data->state.areschannel, &store, &tv);
222 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
223 if (count < 0 && Curl_sockerrno() != EINVAL)
224 break;
226 ares_process(data->state.areschannel, &read_fds, &write_fds);
228 timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */
229 timeout -= timediff?timediff:1; /* always deduct at least 1 */
230 if (timeout < 0) {
231 /* our timeout, so we cancel the ares operation */
232 ares_cancel(data->state.areschannel);
233 break;
237 /* Operation complete, if the lookup was successful we now have the entry
238 in the cache. */
240 if(entry)
241 *entry = conn->async.dns;
243 if(!conn->async.dns) {
244 /* a name was not resolved */
245 if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
246 failf(data, "Resolving host timed out: %s", conn->host.dispname);
247 rc = CURLE_OPERATION_TIMEDOUT;
249 else if(conn->async.done) {
250 failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
251 ares_strerror(conn->async.status));
252 rc = CURLE_COULDNT_RESOLVE_HOST;
254 else
255 rc = CURLE_OPERATION_TIMEDOUT;
257 /* close the connection, since we can't return failure here without
258 cleaning up this connection properly */
259 conn->bits.close = TRUE;
262 return rc;
266 * Curl_getaddrinfo() - when using ares
268 * Returns name information about the given hostname and port number. If
269 * successful, the 'hostent' is returned and the forth argument will point to
270 * memory we need to free after use. That memory *MUST* be freed with
271 * Curl_freeaddrinfo(), nothing else.
273 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
274 const char *hostname,
275 int port,
276 int *waitp)
278 char *bufp;
279 struct SessionHandle *data = conn->data;
280 in_addr_t in = inet_addr(hostname);
282 *waitp = FALSE;
284 if (in != CURL_INADDR_NONE) {
285 /* This is a dotted IP address 123.123.123.123-style */
286 return Curl_ip2addr(in, hostname, port);
289 bufp = strdup(hostname);
291 if(bufp) {
292 Curl_safefree(conn->async.hostname);
293 conn->async.hostname = bufp;
294 conn->async.port = port;
295 conn->async.done = FALSE; /* not done */
296 conn->async.status = 0; /* clear */
297 conn->async.dns = NULL; /* clear */
299 /* areschannel is already setup in the Curl_open() function */
300 ares_gethostbyname(data->state.areschannel, hostname, PF_INET,
301 (ares_host_callback)Curl_addrinfo4_callback, conn);
303 *waitp = TRUE; /* please wait for the response */
305 return NULL; /* no struct yet */
307 #endif /* CURLRES_ARES */