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