source: trunk/essentials/net-misc/wget/src/connect.c

Last change on this file was 3440, checked in by bird, 18 years ago

wget 1.10.2

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