]> sjero.net Git - wget/blob - src/connect.c
[svn] Generalize connect_with_timeout into run_with_timeout.
[wget] / src / connect.c
1 /* Establishing and handling network connections.
2    Copyright (C) 1995, 1996, 1997, 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <sys/types.h>
24 #ifdef HAVE_UNISTD_H
25 # include <unistd.h>
26 #endif
27 #include <assert.h>
28
29 #ifdef WINDOWS
30 # include <winsock.h>
31 #else
32 # include <sys/socket.h>
33 # include <netdb.h>
34 # include <netinet/in.h>
35 #ifndef __BEOS__
36 # include <arpa/inet.h>
37 #endif
38 #endif /* WINDOWS */
39
40 #include <errno.h>
41 #ifdef HAVE_STRING_H
42 # include <string.h>
43 #else
44 # include <strings.h>
45 #endif /* HAVE_STRING_H */
46 #ifdef HAVE_SYS_SELECT_H
47 # include <sys/select.h>
48 #endif /* HAVE_SYS_SELECT_H */
49
50 #include "wget.h"
51 #include "utils.h"
52 #include "host.h"
53 #include "connect.h"
54
55 #ifndef errno
56 extern int errno;
57 #endif
58
59 /* Variables shared by bindport and acceptport: */
60 static int msock = -1;
61 static struct sockaddr *addr;
62
63 static ip_address bind_address;
64 static int bind_address_resolved;
65
66 static void
67 resolve_bind_address (void)
68 {
69   struct address_list *al;
70
71   if (bind_address_resolved || opt.bind_address == NULL)
72     /* Nothing to do. */
73     return;
74
75   al = lookup_host (opt.bind_address, 1);
76   if (!al)
77     {
78       logprintf (LOG_NOTQUIET,
79                  _("Unable to convert `%s' to a bind address.  Reverting to ANY.\n"),
80                  opt.bind_address);
81       return;
82     }
83
84   address_list_copy_one (al, 0, &bind_address);
85   address_list_release (al);
86   bind_address_resolved = 1;
87 }
88 \f
89 struct cwt_context {
90   int fd;
91   const struct sockaddr *addr;
92   int addrlen;
93   int result;
94 };
95
96 static void
97 connect_with_timeout_callback (void *arg)
98 {
99   struct cwt_context *ctx = (struct cwt_context *)arg;
100   ctx->result = connect (ctx->fd, ctx->addr, ctx->addrlen);
101 }
102
103 /* Like connect, but specifies a timeout.  If connecting takes longer
104    than TIMEOUT seconds, -1 is returned and errno is set to
105    ETIMEDOUT.  */
106
107 static int
108 connect_with_timeout (int fd, const struct sockaddr *addr, int addrlen,
109                       int timeout)
110 {
111   struct cwt_context ctx;
112   ctx.fd = fd;
113   ctx.addr = addr;
114   ctx.addrlen = addrlen;
115
116   if (run_with_timeout (timeout, connect_with_timeout_callback, &ctx))
117     {
118       errno = ETIMEDOUT;
119       return -1;
120     }
121   if (ctx.result == -1 && errno == EINTR)
122     errno = ETIMEDOUT;
123   return ctx.result;
124 }
125 \f
126 /* A kludge, but still better than passing the host name all the way
127    to connect_to_one.  */
128 static const char *connection_host_name;
129
130 void
131 set_connection_host_name (const char *host)
132 {
133   if (host)
134     assert (connection_host_name == NULL);
135   else
136     assert (connection_host_name != NULL);
137
138   connection_host_name = host;
139 }
140
141 /* Connect to a remote host whose address has been resolved. */
142 int
143 connect_to_one (ip_address *addr, unsigned short port, int silent)
144 {
145   wget_sockaddr sa;
146   int sock, save_errno;
147
148   /* Set port and protocol */
149   wget_sockaddr_set_address (&sa, ip_default_family, port, addr);
150
151   if (!silent)
152     {
153       char *pretty_addr = pretty_print_address (addr);
154       if (connection_host_name
155           && 0 != strcmp (connection_host_name, pretty_addr))
156         logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "),
157                    connection_host_name, pretty_addr, port);
158       else
159         logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "),
160                    pretty_addr, port);
161     }
162
163   /* Make an internet socket, stream type.  */
164   sock = socket (ip_default_family, SOCK_STREAM, 0);
165   if (sock < 0)
166     goto out;
167
168   resolve_bind_address ();
169   if (bind_address_resolved)
170     {
171       /* Bind the client side to the requested address. */
172       wget_sockaddr bsa;
173       wget_sockaddr_set_address (&bsa, ip_default_family, 0, &bind_address);
174       if (bind (sock, &bsa.sa, sockaddr_len ()))
175         {
176           close (sock);
177           sock = -1;
178           goto out;
179         }
180     }
181
182   /* Connect the socket to the remote host.  */
183   if (connect_with_timeout (sock, &sa.sa, sockaddr_len (), opt.timeout) < 0)
184     {
185       close (sock);
186       sock = -1;
187       goto out;
188     }
189
190  out:
191   if (sock >= 0)
192     {
193       /* Success. */
194       if (!silent)
195         logprintf (LOG_VERBOSE, _("connected.\n"));
196       DEBUGP (("Created socket %d.\n", sock));
197     }
198   else
199     {
200       save_errno = errno;
201       if (!silent)
202         logprintf (LOG_VERBOSE, "failed: %s.\n", strerror (errno));
203       errno = save_errno;
204     }
205
206   return sock;
207 }
208
209 /* Connect to a remote host whose address has been resolved. */
210 int
211 connect_to_many (struct address_list *al, unsigned short port, int silent)
212 {
213   int i, start, end;
214
215   address_list_get_bounds (al, &start, &end);
216   for (i = start; i < end; i++)
217     {
218       ip_address addr;
219       int sock;
220       address_list_copy_one (al, i, &addr);
221
222       sock = connect_to_one (&addr, port, silent);
223       if (sock >= 0)
224         /* Success. */
225         return sock;
226
227       address_list_set_faulty (al, i);
228
229       /* The attempt to connect has failed.  Continue with the loop
230          and try next address. */
231     }
232
233   return -1;
234 }
235
236 int
237 test_socket_open (int sock)
238 {
239 #ifdef HAVE_SELECT
240   fd_set check_set;
241   struct timeval to;
242
243   /* Check if we still have a valid (non-EOF) connection.  From Andrew
244    * Maholski's code in the Unix Socket FAQ.  */
245
246   FD_ZERO (&check_set);
247   FD_SET (sock, &check_set);
248
249   /* Wait one microsecond */
250   to.tv_sec = 0;
251   to.tv_usec = 1;
252
253   /* If we get a timeout, then that means still connected */
254   if (select (sock + 1, &check_set, NULL, NULL, &to) == 0)
255     {
256       /* Connection is valid (not EOF), so continue */
257       return 1;
258     }
259   else
260     return 0;
261 #else
262   /* Without select, it's hard to know for sure. */
263   return 1;
264 #endif
265 }
266
267 /* Bind the local port PORT.  This does all the necessary work, which
268    is creating a socket, setting SO_REUSEADDR option on it, then
269    calling bind() and listen().  If *PORT is 0, a random port is
270    chosen by the system, and its value is stored to *PORT.  The
271    internal variable MPORT is set to the value of the ensuing master
272    socket.  Call acceptport() to block for and accept a connection.  */
273 uerr_t
274 bindport (unsigned short *port, int family)
275 {
276   int optval = 1;
277   wget_sockaddr srv;
278   memset (&srv, 0, sizeof (wget_sockaddr));
279
280   msock = -1;
281
282   if ((msock = socket (family, SOCK_STREAM, 0)) < 0)
283     return CONSOCKERR;
284   if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR,
285                   (char *)&optval, sizeof (optval)) < 0)
286     return CONSOCKERR;
287
288   resolve_bind_address ();
289   wget_sockaddr_set_address (&srv, ip_default_family, htons (*port),
290                              bind_address_resolved ? &bind_address : NULL);
291   if (bind (msock, &srv.sa, sockaddr_len ()) < 0)
292     {
293       CLOSE (msock);
294       msock = -1;
295       return BINDERR;
296     }
297   DEBUGP (("Master socket fd %d bound.\n", msock));
298   if (!*port)
299     {
300       /* #### addrlen should be a 32-bit type, which int is not
301          guaranteed to be.  Oh, and don't try to make it a size_t,
302          because that can be 64-bit.  */
303       int sa_len = sockaddr_len ();
304       if (getsockname (msock, &srv.sa, &sa_len) < 0)
305         {
306           CLOSE (msock);
307           msock = -1;
308           return CONPORTERR;
309         }
310       *port = wget_sockaddr_get_port (&srv);
311       DEBUGP (("using port %i.\n", *port));
312     }
313   if (listen (msock, 1) < 0)
314     {
315       CLOSE (msock);
316       msock = -1;
317       return LISTENERR;
318     }
319   return BINDOK;
320 }
321
322 #ifdef HAVE_SELECT
323 /* Wait for file descriptor FD to be readable, MAXTIME being the
324    timeout in seconds.  If WRITEP is non-zero, checks for FD being
325    writable instead.
326
327    Returns 1 if FD is accessible, 0 for timeout and -1 for error in
328    select().  */
329 int
330 select_fd (int fd, int maxtime, int writep)
331 {
332   fd_set fds, exceptfds;
333   struct timeval timeout;
334
335   FD_ZERO (&fds);
336   FD_SET (fd, &fds);
337   FD_ZERO (&exceptfds);
338   FD_SET (fd, &exceptfds);
339   timeout.tv_sec = maxtime;
340   timeout.tv_usec = 0;
341   /* HPUX reportedly warns here.  What is the correct incantation?  */
342   return select (fd + 1, writep ? NULL : &fds, writep ? &fds : NULL,
343                  &exceptfds, &timeout);
344 }
345 #endif /* HAVE_SELECT */
346
347 /* Call accept() on MSOCK and store the result to *SOCK.  This assumes
348    that bindport() has been used to initialize MSOCK to a correct
349    value.  It blocks the caller until a connection is established.  If
350    no connection is established for OPT.TIMEOUT seconds, the function
351    exits with an error status.  */
352 uerr_t
353 acceptport (int *sock)
354 {
355   int addrlen = sockaddr_len ();
356
357 #ifdef HAVE_SELECT
358   if (select_fd (msock, opt.timeout, 0) <= 0)
359     return ACCEPTERR;
360 #endif
361   if ((*sock = accept (msock, addr, &addrlen)) < 0)
362     return ACCEPTERR;
363   DEBUGP (("Created socket fd %d.\n", *sock));
364   return ACCEPTOK;
365 }
366
367 /* Close SOCK, as well as the most recently remembered MSOCK, created
368    via bindport().  If SOCK is -1, close MSOCK only.  */
369 void
370 closeport (int sock)
371 {
372   /*shutdown (sock, 2);*/
373   if (sock != -1)
374     CLOSE (sock);
375   if (msock != -1)
376     CLOSE (msock);
377   msock = -1;
378 }
379
380 /* Return the local IP address associated with the connection on FD.  */
381
382 int
383 conaddr (int fd, ip_address *ip)
384 {
385   wget_sockaddr mysrv;
386
387   /* see bindport() for discussion of using `int' here. */
388   int addrlen = sizeof (mysrv); 
389
390   if (getsockname (fd, &mysrv.sa, (int *)&addrlen) < 0)
391     return 0;
392
393   switch (mysrv.sa.sa_family)
394     {
395 #ifdef INET6
396     case AF_INET6:
397       memcpy (ip, &mysrv.sin6.sin6_addr, 16);
398       return 1;
399 #endif
400     case AF_INET:
401       map_ipv4_to_ip ((ip4_address *)&mysrv.sin.sin_addr, ip);
402       return 1;
403     default:
404       abort ();
405     }
406   return 0;
407 }
408
409 /* Read at most LEN bytes from FD, storing them to BUF.  This is
410    virtually the same as read(), but takes care of EINTR braindamage
411    and uses select() to timeout the stale connections (a connection is
412    stale if more than OPT.TIMEOUT time is spent in select() or
413    read()).  */
414 int
415 iread (int fd, char *buf, int len)
416 {
417   int res;
418
419   do
420     {
421 #ifdef HAVE_SELECT
422       if (opt.timeout)
423         {
424           do
425             {
426               res = select_fd (fd, opt.timeout, 0);
427             }
428           while (res == -1 && errno == EINTR);
429           if (res <= 0)
430             {
431               /* Set errno to ETIMEDOUT on timeout.  */
432               if (res == 0)
433                 /* #### Potentially evil!  */
434                 errno = ETIMEDOUT;
435               return -1;
436             }
437         }
438 #endif
439       res = READ (fd, buf, len);
440     }
441   while (res == -1 && errno == EINTR);
442
443   return res;
444 }
445
446 /* Write LEN bytes from BUF to FD.  This is similar to iread(), but
447    doesn't bother with select().  Unlike iread(), it makes sure that
448    all of BUF is actually written to FD, so callers needn't bother
449    with checking that the return value equals to LEN.  Instead, you
450    should simply check for -1.  */
451 int
452 iwrite (int fd, char *buf, int len)
453 {
454   int res = 0;
455
456   /* `write' may write less than LEN bytes, thus the outward loop
457      keeps trying it until all was written, or an error occurred.  The
458      inner loop is reserved for the usual EINTR f*kage, and the
459      innermost loop deals with the same during select().  */
460   while (len > 0)
461     {
462       do
463         {
464 #ifdef HAVE_SELECT
465           if (opt.timeout)
466             {
467               do
468                 {
469                   res = select_fd (fd, opt.timeout, 1);
470                 }
471               while (res == -1 && errno == EINTR);
472               if (res <= 0)
473                 {
474                   /* Set errno to ETIMEDOUT on timeout.  */
475                   if (res == 0)
476                     /* #### Potentially evil!  */
477                     errno = ETIMEDOUT;
478                   return -1;
479                 }
480             }
481 #endif
482           res = WRITE (fd, buf, len);
483         }
484       while (res == -1 && errno == EINTR);
485       if (res <= 0)
486         break;
487       buf += res;
488       len -= res;
489     }
490   return res;
491 }