]> sjero.net Git - wget/blob - src/connect.c
[svn] Expect existence of C89 functions, as well as of select and gettimeofday.
[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 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <assert.h>
38
39 #ifndef WINDOWS
40 # include <sys/socket.h>
41 # include <netdb.h>
42 # include <netinet/in.h>
43 # ifndef __BEOS__
44 #  include <arpa/inet.h>
45 # endif
46 #endif /* not WINDOWS */
47
48 #include <errno.h>
49 #include <string.h>
50 #ifdef HAVE_SYS_SELECT_H
51 # include <sys/select.h>
52 #endif /* HAVE_SYS_SELECT_H */
53
54 #include "wget.h"
55 #include "utils.h"
56 #include "host.h"
57 #include "connect.h"
58 #include "hash.h"
59
60 /* Define sockaddr_storage where unavailable (presumably on IPv4-only
61    hosts).  */
62
63 #ifndef ENABLE_IPV6
64 # ifndef HAVE_STRUCT_SOCKADDR_STORAGE
65 #  define sockaddr_storage sockaddr_in
66 # endif
67 #endif /* ENABLE_IPV6 */
68
69 /* Fill SA as per the data in IP and PORT.  SA shoult point to struct
70    sockaddr_storage if ENABLE_IPV6 is defined, to struct sockaddr_in
71    otherwise.  */
72
73 static void
74 sockaddr_set_data (struct sockaddr *sa, const ip_address *ip, int port)
75 {
76   switch (ip->type)
77     {
78     case IPV4_ADDRESS:
79       {
80         struct sockaddr_in *sin = (struct sockaddr_in *)sa;
81         xzero (*sin);
82         sin->sin_family = AF_INET;
83         sin->sin_port = htons (port);
84         sin->sin_addr = ADDRESS_IPV4_IN_ADDR (ip);
85         break;
86       }
87 #ifdef ENABLE_IPV6
88     case IPV6_ADDRESS:
89       {
90         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
91         xzero (*sin6);
92         sin6->sin6_family = AF_INET6;
93         sin6->sin6_port = htons (port);
94         sin6->sin6_addr = ADDRESS_IPV6_IN6_ADDR (ip);
95 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
96         sin6->sin6_scope_id = ADDRESS_IPV6_SCOPE (ip);
97 #endif
98         break;
99       }
100 #endif /* ENABLE_IPV6 */
101     default:
102       abort ();
103     }
104 }
105
106 /* Get the data of SA, specifically the IP address and the port.  If
107    you're not interested in one or the other information, pass NULL as
108    the pointer.  */
109
110 static void
111 sockaddr_get_data (const struct sockaddr *sa, ip_address *ip, int *port)
112 {
113   switch (sa->sa_family)
114     {
115     case AF_INET:
116       {
117         struct sockaddr_in *sin = (struct sockaddr_in *)sa;
118         if (ip)
119           {
120             ip->type = IPV4_ADDRESS;
121             ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr;
122           }
123         if (port)
124           *port = ntohs (sin->sin_port);
125         break;
126       }
127 #ifdef ENABLE_IPV6
128     case AF_INET6:
129       {
130         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
131         if (ip)
132           {
133             ip->type = IPV6_ADDRESS;
134             ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr;
135 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
136             ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id;
137 #endif
138           }
139         if (port)
140           *port = ntohs (sin6->sin6_port);
141         break;
142       }
143 #endif
144     default:
145       abort ();
146     }
147 }
148
149 /* Return the size of the sockaddr structure depending on its
150    family.  */
151
152 static socklen_t
153 sockaddr_size (const struct sockaddr *sa)
154 {
155   switch (sa->sa_family)
156     {
157     case AF_INET:
158       return sizeof (struct sockaddr_in);
159 #ifdef ENABLE_IPV6
160     case AF_INET6:
161       return sizeof (struct sockaddr_in6);
162 #endif
163     default:
164       abort ();
165     }
166 }
167 \f
168 static int
169 resolve_bind_address (struct sockaddr *sa)
170 {
171   struct address_list *al;
172
173   /* Make sure this is called only once.  opt.bind_address doesn't
174      change during a Wget run.  */
175   static int called, should_bind;
176   static ip_address ip;
177   if (called)
178     {
179       if (should_bind)
180         sockaddr_set_data (sa, &ip, 0);
181       return should_bind;
182     }
183   called = 1;
184
185   al = lookup_host (opt.bind_address, LH_BIND | LH_SILENT);
186   if (!al)
187     {
188       /* #### We should be able to print the error message here. */
189       logprintf (LOG_NOTQUIET,
190                  _("%s: unable to resolve bind address `%s'; disabling bind.\n"),
191                  exec_name, opt.bind_address);
192       should_bind = 0;
193       return 0;
194     }
195
196   /* Pick the first address in the list and use it as bind address.
197      Perhaps we should try multiple addresses in succession, but I
198      don't think that's necessary in practice.  */
199   ip = *address_list_address_at (al, 0);
200   address_list_release (al);
201
202   sockaddr_set_data (sa, &ip, 0);
203   should_bind = 1;
204   return 1;
205 }
206 \f
207 struct cwt_context {
208   int fd;
209   const struct sockaddr *addr;
210   socklen_t addrlen;
211   int result;
212 };
213
214 static void
215 connect_with_timeout_callback (void *arg)
216 {
217   struct cwt_context *ctx = (struct cwt_context *)arg;
218   ctx->result = connect (ctx->fd, ctx->addr, ctx->addrlen);
219 }
220
221 /* Like connect, but specifies a timeout.  If connecting takes longer
222    than TIMEOUT seconds, -1 is returned and errno is set to
223    ETIMEDOUT.  */
224
225 static int
226 connect_with_timeout (int fd, const struct sockaddr *addr, socklen_t addrlen,
227                       double timeout)
228 {
229   struct cwt_context ctx;
230   ctx.fd = fd;
231   ctx.addr = addr;
232   ctx.addrlen = addrlen;
233
234   if (run_with_timeout (timeout, connect_with_timeout_callback, &ctx))
235     {
236       errno = ETIMEDOUT;
237       return -1;
238     }
239   if (ctx.result == -1 && errno == EINTR)
240     errno = ETIMEDOUT;
241   return ctx.result;
242 }
243 \f
244 /* Connect via TCP to the specified address and port.
245
246    If PRINT is non-NULL, it is the host name to print that we're
247    connecting to.  */
248
249 int
250 connect_to_ip (const ip_address *ip, int port, const char *print)
251 {
252   struct sockaddr_storage ss;
253   struct sockaddr *sa = (struct sockaddr *)&ss;
254   int sock;
255
256   /* If PRINT is non-NULL, print the "Connecting to..." line, with
257      PRINT being the host name we're connecting to.  */
258   if (print)
259     {
260       const char *txt_addr = pretty_print_address (ip);
261       if (print && 0 != strcmp (print, txt_addr))
262         logprintf (LOG_VERBOSE, _("Connecting to %s|%s|:%d... "),
263                    escnonprint (print), txt_addr, port);
264       else
265         logprintf (LOG_VERBOSE, _("Connecting to %s:%d... "), txt_addr, port);
266     }
267
268   /* Store the sockaddr info to SA.  */
269   sockaddr_set_data (sa, ip, port);
270
271   /* Create the socket of the family appropriate for the address.  */
272   sock = socket (sa->sa_family, SOCK_STREAM, 0);
273   if (sock < 0)
274     goto err;
275
276 #if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY)
277   if (opt.ipv6_only) {
278     int on = 1;
279     /* In case of error, we will go on anyway... */
280     int err = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on));
281 #ifdef ENABLE_DEBUG
282     if (err < 0) 
283       DEBUGP (("Failed setting IPV6_V6ONLY: %s", strerror (errno)));
284 #endif
285   }
286 #endif
287
288   /* For very small rate limits, set the buffer size (and hence,
289      hopefully, the kernel's TCP window size) to the per-second limit.
290      That way we should never have to sleep for more than 1s between
291      network reads.  */
292   if (opt.limit_rate && opt.limit_rate < 8192)
293     {
294       int bufsize = opt.limit_rate;
295       if (bufsize < 512)
296         bufsize = 512;          /* avoid pathologically small values */
297 #ifdef SO_RCVBUF
298       setsockopt (sock, SOL_SOCKET, SO_RCVBUF,
299                   (void *)&bufsize, (socklen_t)sizeof (bufsize));
300 #endif
301       /* When we add limit_rate support for writing, which is useful
302          for POST, we should also set SO_SNDBUF here.  */
303     }
304
305   if (opt.bind_address)
306     {
307       /* Bind the client side of the socket to the requested
308          address.  */
309       struct sockaddr_storage bind_ss;
310       struct sockaddr *bind_sa = (struct sockaddr *)&bind_ss;
311       if (resolve_bind_address (bind_sa))
312         {
313           if (bind (sock, bind_sa, sockaddr_size (bind_sa)) < 0)
314             goto err;
315         }
316     }
317
318   /* Connect the socket to the remote endpoint.  */
319   if (connect_with_timeout (sock, sa, sockaddr_size (sa),
320                             opt.connect_timeout) < 0)
321     goto err;
322
323   /* Success. */
324   assert (sock >= 0);
325   if (print)
326     logprintf (LOG_VERBOSE, _("connected.\n"));
327   DEBUGP (("Created socket %d.\n", sock));
328   return sock;
329
330  err:
331   {
332     /* Protect errno from possible modifications by close and
333        logprintf.  */
334     int save_errno = errno;
335     if (sock >= 0)
336       fd_close (sock);
337     if (print)
338       logprintf (LOG_VERBOSE, _("failed: %s.\n"), strerror (errno));
339     errno = save_errno;
340     return -1;
341   }
342 }
343
344 /* Connect via TCP to a remote host on the specified port.
345
346    HOST is resolved as an Internet host name.  If HOST resolves to
347    more than one IP address, they are tried in the order returned by
348    DNS until connecting to one of them succeeds.  */
349
350 int
351 connect_to_host (const char *host, int port)
352 {
353   int i, start, end;
354   int sock;
355
356   struct address_list *al = lookup_host (host, 0);
357
358  retry:
359   if (!al)
360     return E_HOST;
361
362   address_list_get_bounds (al, &start, &end);
363   for (i = start; i < end; i++)
364     {
365       const ip_address *ip = address_list_address_at (al, i);
366       sock = connect_to_ip (ip, port, host);
367       if (sock >= 0)
368         {
369           /* Success. */
370           address_list_set_connected (al);
371           address_list_release (al);
372           return sock;
373         }
374
375       /* The attempt to connect has failed.  Continue with the loop
376          and try next address. */
377
378       address_list_set_faulty (al, i);
379     }
380
381   /* Failed to connect to any of the addresses in AL. */
382
383   if (address_list_connected_p (al))
384     {
385       /* We connected to AL before, but cannot do so now.  That might
386          indicate that our DNS cache entry for HOST has expired.  */
387       address_list_release (al);
388       al = lookup_host (host, LH_REFRESH);
389       goto retry;
390     }
391   address_list_release (al);
392
393   return -1;
394 }
395 \f
396 /* Create a socket, bind it to local interface BIND_ADDRESS on port
397    *PORT, set up a listen backlog, and return the resulting socket, or
398    -1 in case of error.
399
400    BIND_ADDRESS is the address of the interface to bind to.  If it is
401    NULL, the socket is bound to the default address.  PORT should
402    point to the port number that will be used for the binding.  If
403    that number is 0, the system will choose a suitable port, and the
404    chosen value will be written to *PORT.
405
406    Calling accept() on such a socket waits for and accepts incoming
407    TCP connections.  */
408
409 int
410 bind_local (const ip_address *bind_address, int *port)
411 {
412   int sock;
413   int family = AF_INET;
414   struct sockaddr_storage ss;
415   struct sockaddr *sa = (struct sockaddr *)&ss;
416
417   /* For setting options with setsockopt. */
418   int setopt_val = 1;
419   void *setopt_ptr = (void *)&setopt_val;
420   socklen_t setopt_size = sizeof (setopt_val);
421
422 #ifdef ENABLE_IPV6
423   if (bind_address->type == IPV6_ADDRESS) 
424     family = AF_INET6;
425 #endif
426
427   sock = socket (family, SOCK_STREAM, 0);
428   if (sock < 0)
429     return -1;
430
431 #ifdef SO_REUSEADDR
432   setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, setopt_ptr, setopt_size);
433 #endif
434
435   xzero (ss);
436   sockaddr_set_data (sa, bind_address, *port);
437   if (bind (sock, sa, sockaddr_size (sa)) < 0)
438     {
439       fd_close (sock);
440       return -1;
441     }
442   DEBUGP (("Local socket fd %d bound.\n", sock));
443
444   /* If *PORT is 0, find out which port we've bound to.  */
445   if (*port == 0)
446     {
447       socklen_t addrlen = sockaddr_size (sa);
448       if (getsockname (sock, sa, &addrlen) < 0)
449         {
450           /* If we can't find out the socket's local address ("name"),
451              something is seriously wrong with the socket, and it's
452              unusable for us anyway because we must know the chosen
453              port.  */
454           fd_close (sock);
455           return -1;
456         }
457       sockaddr_get_data (sa, NULL, port);
458       DEBUGP (("binding to address %s using port %i.\n", 
459                pretty_print_address (bind_address), *port));
460     }
461   if (listen (sock, 1) < 0)
462     {
463       fd_close (sock);
464       return -1;
465     }
466   return sock;
467 }
468
469 /* Like a call to accept(), but with the added check for timeout.
470
471    In other words, accept a client connection on LOCAL_SOCK, and
472    return the new socket used for communication with the client.
473    LOCAL_SOCK should have been bound, e.g. using bind_local().
474
475    The caller is blocked until a connection is established.  If no
476    connection is established for opt.connect_timeout seconds, the
477    function exits with an error status.  */
478
479 int
480 accept_connection (int local_sock)
481 {
482   int sock;
483
484   /* We don't need the values provided by accept, but accept
485      apparently requires them to be present.  */
486   struct sockaddr_storage ss;
487   struct sockaddr *sa = (struct sockaddr *)&ss;
488   socklen_t addrlen = sizeof (ss);
489
490   if (opt.connect_timeout)
491     {
492       int test = select_fd (local_sock, opt.connect_timeout, WAIT_FOR_READ);
493       if (test == 0)
494         errno = ETIMEDOUT;
495       if (test <= 0)
496         return -1;
497     }
498   sock = accept (local_sock, sa, &addrlen);
499   DEBUGP (("Accepted client at socket %d.\n", sock));
500   return sock;
501 }
502
503 /* Get the IP address associated with the connection on FD and store
504    it to IP.  Return 1 on success, 0 otherwise.
505
506    If ENDPOINT is ENDPOINT_LOCAL, it returns the address of the local
507    (client) side of the socket.  Else if ENDPOINT is ENDPOINT_PEER, it
508    returns the address of the remote (peer's) side of the socket.  */
509
510 int
511 socket_ip_address (int sock, ip_address *ip, int endpoint)
512 {
513   struct sockaddr_storage storage;
514   struct sockaddr *sockaddr = (struct sockaddr *)&storage;
515   socklen_t addrlen = sizeof (storage);
516   int ret;
517
518   if (endpoint == ENDPOINT_LOCAL)
519     ret = getsockname (sock, sockaddr, &addrlen);
520   else if (endpoint == ENDPOINT_PEER)
521     ret = getpeername (sock, sockaddr, &addrlen);
522   else
523     abort ();
524   if (ret < 0)
525     return 0;
526
527   switch (sockaddr->sa_family)
528     {
529 #ifdef ENABLE_IPV6
530     case AF_INET6:
531       {
532         struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&storage;
533         ip->type = IPV6_ADDRESS;
534         ADDRESS_IPV6_IN6_ADDR (ip) = sa6->sin6_addr;
535 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
536         ADDRESS_IPV6_SCOPE (ip) = sa6->sin6_scope_id;
537 #endif
538         DEBUGP (("conaddr is: %s\n", pretty_print_address (ip)));
539         return 1;
540       }
541 #endif
542     case AF_INET:
543       {
544         struct sockaddr_in *sa = (struct sockaddr_in *)&storage;
545         ip->type = IPV4_ADDRESS;
546         ADDRESS_IPV4_IN_ADDR (ip) = sa->sin_addr;
547         DEBUGP (("conaddr is: %s\n", pretty_print_address (ip)));
548         return 1;
549       }
550     default:
551       abort ();
552     }
553 }
554
555 /* Return non-zero if the error from the connect code can be
556    considered retryable.  Wget normally retries after errors, but the
557    exception are the "unsupported protocol" type errors (possible on
558    IPv4/IPv6 dual family systems) and "connection refused".  */
559
560 int
561 retryable_socket_connect_error (int err)
562 {
563   /* Have to guard against some of these values not being defined.
564      Cannot use a switch statement because some of the values might be
565      equal.  */
566   if (0
567 #ifdef EAFNOSUPPORT
568       || err == EAFNOSUPPORT
569 #endif
570 #ifdef EPFNOSUPPORT
571       || err == EPFNOSUPPORT
572 #endif
573 #ifdef ESOCKTNOSUPPORT          /* no, "sockt" is not a typo! */
574       || err == ESOCKTNOSUPPORT
575 #endif
576 #ifdef EPROTONOSUPPORT
577       || err == EPROTONOSUPPORT
578 #endif
579 #ifdef ENOPROTOOPT
580       || err == ENOPROTOOPT
581 #endif
582       /* Apparently, older versions of Linux and BSD used EINVAL
583          instead of EAFNOSUPPORT and such.  */
584       || err == EINVAL
585       )
586     return 0;
587
588   if (!opt.retry_connrefused)
589     if (err == ECONNREFUSED
590 #ifdef ENETUNREACH
591         || err == ENETUNREACH   /* network is unreachable */
592 #endif
593 #ifdef EHOSTUNREACH
594         || err == EHOSTUNREACH  /* host is unreachable */
595 #endif
596         )
597       return 0;
598
599   return 1;
600 }
601
602 /* Wait for a single descriptor to become available, timing out after
603    MAXTIME seconds.  Returns 1 if FD is available, 0 for timeout and
604    -1 for error.  The argument WAIT_FOR can be a combination of
605    WAIT_FOR_READ and WAIT_FOR_WRITE.
606
607    This is a mere convenience wrapper around the select call, and
608    should be taken as such (for example, it doesn't implement Wget's
609    0-timeout-means-no-timeout semantics.)  */
610
611 int
612 select_fd (int fd, double maxtime, int wait_for)
613 {
614   fd_set fdset;
615   fd_set *rd = NULL, *wr = NULL;
616   struct timeval tmout;
617   int result;
618
619   FD_ZERO (&fdset);
620   FD_SET (fd, &fdset);
621   if (wait_for & WAIT_FOR_READ)
622     rd = &fdset;
623   if (wait_for & WAIT_FOR_WRITE)
624     wr = &fdset;
625
626   tmout.tv_sec = (long) maxtime;
627   tmout.tv_usec = 1000000 * (maxtime - (long) maxtime);
628
629   do
630     result = select (fd + 1, rd, wr, NULL, &tmout);
631   while (result < 0 && errno == EINTR);
632
633   return result;
634 }
635
636 int
637 test_socket_open (int sock)
638 {
639   fd_set check_set;
640   struct timeval to;
641
642   /* Check if we still have a valid (non-EOF) connection.  From Andrew
643    * Maholski's code in the Unix Socket FAQ.  */
644
645   FD_ZERO (&check_set);
646   FD_SET (sock, &check_set);
647
648   /* Wait one microsecond */
649   to.tv_sec = 0;
650   to.tv_usec = 1;
651
652   /* If we get a timeout, then that means still connected */
653   if (select (sock + 1, &check_set, NULL, NULL, &to) == 0)
654     {
655       /* Connection is valid (not EOF), so continue */
656       return 1;
657     }
658   else
659     return 0;
660 }
661 \f
662 /* Basic socket operations, mostly EINTR wrappers.  */
663
664 #ifdef WINDOWS
665 # define read(fd, buf, cnt) recv (fd, buf, cnt, 0)
666 # define write(fd, buf, cnt) send (fd, buf, cnt, 0)
667 # define close(fd) closesocket (fd)
668 #endif
669
670 #ifdef __BEOS__
671 # define read(fd, buf, cnt) recv (fd, buf, cnt, 0)
672 # define write(fd, buf, cnt) send (fd, buf, cnt, 0)
673 #endif
674
675 static int
676 sock_read (int fd, char *buf, int bufsize)
677 {
678   int res;
679   do
680     res = read (fd, buf, bufsize);
681   while (res == -1 && errno == EINTR);
682   return res;
683 }
684
685 static int
686 sock_write (int fd, char *buf, int bufsize)
687 {
688   int res;
689   do
690     res = write (fd, buf, bufsize);
691   while (res == -1 && errno == EINTR);
692   return res;
693 }
694
695 static int
696 sock_poll (int fd, double timeout, int wait_for)
697 {
698   return select_fd (fd, timeout, wait_for);
699 }
700
701 static int
702 sock_peek (int fd, char *buf, int bufsize)
703 {
704   int res;
705   do
706     res = recv (fd, buf, bufsize, MSG_PEEK);
707   while (res == -1 && errno == EINTR);
708   return res;
709 }
710
711 static void
712 sock_close (int fd)
713 {
714   close (fd);
715   DEBUGP (("Closed fd %d\n", fd));
716 }
717 #undef read
718 #undef write
719 #undef close
720 \f
721 /* Reading and writing from the network.  We build around the socket
722    (file descriptor) API, but support "extended" operations for things
723    that are not mere file descriptors under the hood, such as SSL
724    sockets.
725
726    That way the user code can call fd_read(fd, ...) and we'll run read
727    or SSL_read or whatever is necessary.  */
728
729 static struct hash_table *transport_map;
730 static int transport_map_modified_tick;
731
732 struct transport_info {
733   fd_reader_t reader;
734   fd_writer_t writer;
735   fd_poller_t poller;
736   fd_peeker_t peeker;
737   fd_closer_t closer;
738   void *ctx;
739 };
740
741 /* Register the transport layer operations that will be used when
742    reading, writing, and polling FD.
743
744    This should be used for transport layers like SSL that piggyback on
745    sockets.  FD should otherwise be a real socket, on which you can
746    call getpeername, etc.  */
747
748 void
749 fd_register_transport (int fd, fd_reader_t reader, fd_writer_t writer,
750                        fd_poller_t poller, fd_peeker_t peeker,
751                        fd_closer_t closer, void *ctx)
752 {
753   struct transport_info *info;
754
755   /* The file descriptor must be non-negative to be registered.
756      Negative values are ignored by fd_close(), and -1 cannot be used as
757      hash key.  */
758   assert (fd >= 0);
759
760   info = xnew (struct transport_info);
761   info->reader = reader;
762   info->writer = writer;
763   info->poller = poller;
764   info->peeker = peeker;
765   info->closer = closer;
766   info->ctx = ctx;
767   if (!transport_map)
768     transport_map = hash_table_new (0, NULL, NULL);
769   hash_table_put (transport_map, (void *) fd, info);
770   ++transport_map_modified_tick;
771 }
772
773 /* Return context of the transport registered with
774    fd_register_transport.  This assumes fd_register_transport was
775    previously called on FD.  */
776
777 void *
778 fd_transport_context (int fd)
779 {
780   struct transport_info *info = hash_table_get (transport_map, (void *) fd);
781   return info->ctx;
782 }
783
784 /* When fd_read/fd_write are called multiple times in a loop, they should
785    remember the INFO pointer instead of fetching it every time.  It is
786    not enough to compare FD to LAST_FD because FD might have been
787    closed and reopened.  modified_tick ensures that changes to
788    transport_map will not be unnoticed.
789
790    This is a macro because we want the static storage variables to be
791    per-function.  */
792
793 #define LAZY_RETRIEVE_INFO(info) do {                                   \
794   static struct transport_info *last_info;                              \
795   static int last_fd = -1, last_tick;                                   \
796   if (!transport_map)                                                   \
797     info = NULL;                                                        \
798   else if (last_fd == fd && last_tick == transport_map_modified_tick)   \
799     info = last_info;                                                   \
800   else                                                                  \
801     {                                                                   \
802       info = hash_table_get (transport_map, (void *) fd);               \
803       last_fd = fd;                                                     \
804       last_info = info;                                                 \
805       last_tick = transport_map_modified_tick;                          \
806     }                                                                   \
807 } while (0)
808
809 static int
810 poll_internal (int fd, struct transport_info *info, int wf, double timeout)
811 {
812   if (timeout == -1)
813     timeout = opt.read_timeout;
814   if (timeout)
815     {
816       int test;
817       if (info && info->poller)
818         test = info->poller (fd, timeout, wf, info->ctx);
819       else
820         test = sock_poll (fd, timeout, wf);
821       if (test == 0)
822         errno = ETIMEDOUT;
823       if (test <= 0)
824         return 0;
825     }
826   return 1;
827 }
828
829 /* Read no more than BUFSIZE bytes of data from FD, storing them to
830    BUF.  If TIMEOUT is non-zero, the operation aborts if no data is
831    received after that many seconds.  If TIMEOUT is -1, the value of
832    opt.timeout is used for TIMEOUT.  */
833
834 int
835 fd_read (int fd, char *buf, int bufsize, double timeout)
836 {
837   struct transport_info *info;
838   LAZY_RETRIEVE_INFO (info);
839   if (!poll_internal (fd, info, WAIT_FOR_READ, timeout))
840     return -1;
841   if (info && info->reader)
842     return info->reader (fd, buf, bufsize, info->ctx);
843   else
844     return sock_read (fd, buf, bufsize);
845 }
846
847 /* Like fd_read, except it provides a "preview" of the data that will
848    be read by subsequent calls to fd_read.  Specifically, it copies no
849    more than BUFSIZE bytes of the currently available data to BUF and
850    returns the number of bytes copied.  Return values and timeout
851    semantics are the same as those of fd_read.
852
853    CAVEAT: Do not assume that the first subsequent call to fd_read
854    will retrieve the same amount of data.  Reading can return more or
855    less data, depending on the TCP implementation and other
856    circumstances.  However, barring an error, it can be expected that
857    all the peeked data will eventually be read by fd_read.  */
858
859 int
860 fd_peek (int fd, char *buf, int bufsize, double timeout)
861 {
862   struct transport_info *info;
863   LAZY_RETRIEVE_INFO (info);
864   if (!poll_internal (fd, info, WAIT_FOR_READ, timeout))
865     return -1;
866   if (info && info->peeker)
867     return info->peeker (fd, buf, bufsize, info->ctx);
868   else
869     return sock_peek (fd, buf, bufsize);
870 }
871
872 /* Write the entire contents of BUF to FD.  If TIMEOUT is non-zero,
873    the operation aborts if no data is received after that many
874    seconds.  If TIMEOUT is -1, the value of opt.timeout is used for
875    TIMEOUT.  */
876
877 int
878 fd_write (int fd, char *buf, int bufsize, double timeout)
879 {
880   int res;
881   struct transport_info *info;
882   LAZY_RETRIEVE_INFO (info);
883
884   /* `write' may write less than LEN bytes, thus the loop keeps trying
885      it until all was written, or an error occurred.  */
886   res = 0;
887   while (bufsize > 0)
888     {
889       if (!poll_internal (fd, info, WAIT_FOR_WRITE, timeout))
890         return -1;
891       if (info && info->writer)
892         res = info->writer (fd, buf, bufsize, info->ctx);
893       else
894         res = sock_write (fd, buf, bufsize);
895       if (res <= 0)
896         break;
897       buf += res;
898       bufsize -= res;
899     }
900   return res;
901 }
902
903 /* Close the file descriptor FD.  */
904
905 void
906 fd_close (int fd)
907 {
908   struct transport_info *info;
909   if (fd < 0)
910     return;
911
912   /* Don't use LAZY_RETRIEVE_INFO because fd_close() is only called once
913      per socket, so that particular optimization wouldn't work.  */
914   info = NULL;
915   if (transport_map)
916     info = hash_table_get (transport_map, (void *) fd);
917
918   if (info && info->closer)
919     info->closer (fd, info->ctx);
920   else
921     sock_close (fd);
922
923   if (info)
924     {
925       hash_table_remove (transport_map, (void *) fd);
926       xfree (info);
927       ++transport_map_modified_tick;
928     }
929 }