1 /* $NetBSD: common.c,v 1.2 2011/06/25 20:27:01 christos Exp $ */
3 * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
4 * Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in this position and unchanged.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $
40 #include <sys/types.h>
41 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
50 #if defined(HAVE_INTTYPES_H) || defined(NETBSD)
54 #include <nbcompat/netdb.h>
72 /*** Local data **************************************************************/
75 * Error messages for resolver errors
77 static struct fetcherr netdb_errlist
[] = {
79 { EAI_NODATA
, FETCH_RESOLV
, "Host not found" },
81 { EAI_AGAIN
, FETCH_TEMP
, "Transient resolver failure" },
82 { EAI_FAIL
, FETCH_RESOLV
, "Non-recoverable resolver failure" },
83 { EAI_NONAME
, FETCH_RESOLV
, "No address record" },
84 { -1, FETCH_UNKNOWN
, "Unknown resolver error" }
87 /*** Error-reporting functions ***********************************************/
90 * Map error code to string
92 static struct fetcherr
*
93 fetch_finderr(struct fetcherr
*p
, int e
)
95 while (p
->num
!= -1 && p
->num
!= e
)
104 fetch_seterr(struct fetcherr
*p
, int e
)
106 p
= fetch_finderr(p
, e
);
107 fetchLastErrCode
= p
->cat
;
108 snprintf(fetchLastErrString
, MAXERRSTRING
, "%s", p
->string
);
112 * Set error code according to errno
119 fetchLastErrCode
= FETCH_OK
;
130 fetchLastErrCode
= FETCH_AUTH
;
133 case EISDIR
: /* XXX */
134 fetchLastErrCode
= FETCH_UNAVAIL
;
137 fetchLastErrCode
= FETCH_MEMORY
;
141 fetchLastErrCode
= FETCH_TEMP
;
144 fetchLastErrCode
= FETCH_EXISTS
;
147 fetchLastErrCode
= FETCH_FULL
;
155 fetchLastErrCode
= FETCH_NETWORK
;
159 fetchLastErrCode
= FETCH_ABORT
;
162 fetchLastErrCode
= FETCH_TIMEOUT
;
166 fetchLastErrCode
= FETCH_DOWN
;
169 fetchLastErrCode
= FETCH_UNKNOWN
;
171 snprintf(fetchLastErrString
, MAXERRSTRING
, "%s", strerror(errno
));
176 * Emit status message
179 fetch_info(const char *fmt
, ...)
184 vfprintf(stderr
, fmt
, ap
);
190 /*** Network-related utility functions ***************************************/
193 * Return the default port for a scheme
196 fetch_default_port(const char *scheme
)
200 if ((se
= getservbyname(scheme
, "tcp")) != NULL
)
201 return (ntohs(se
->s_port
));
202 if (strcasecmp(scheme
, SCHEME_FTP
) == 0)
203 return (FTP_DEFAULT_PORT
);
204 if (strcasecmp(scheme
, SCHEME_HTTP
) == 0)
205 return (HTTP_DEFAULT_PORT
);
210 * Return the default proxy port for a scheme
213 fetch_default_proxy_port(const char *scheme
)
215 if (strcasecmp(scheme
, SCHEME_FTP
) == 0)
216 return (FTP_DEFAULT_PROXY_PORT
);
217 if (strcasecmp(scheme
, SCHEME_HTTP
) == 0)
218 return (HTTP_DEFAULT_PROXY_PORT
);
224 * Create a connection for an existing descriptor.
231 /* allocate and fill connection structure */
232 if ((conn
= calloc(1, sizeof(*conn
))) == NULL
)
234 conn
->ftp_home
= NULL
;
235 conn
->cache_url
= NULL
;
236 conn
->next_buf
= NULL
;
244 * Bind a socket to a specific local address
247 fetch_bind(int sd
, int af
, const char *addr
)
249 struct addrinfo hints
, *res
, *res0
;
251 memset(&hints
, 0, sizeof(hints
));
252 hints
.ai_family
= af
;
253 hints
.ai_socktype
= SOCK_STREAM
;
254 hints
.ai_protocol
= 0;
255 if (getaddrinfo(addr
, NULL
, &hints
, &res0
))
257 for (res
= res0
; res
; res
= res
->ai_next
) {
258 if (bind(sd
, res
->ai_addr
, res
->ai_addrlen
) == 0)
266 * Establish a TCP connection to the specified port on the specified host.
269 fetch_connect(struct url
*url
, int af
, int verbose
)
273 const char *bindaddr
;
274 struct addrinfo hints
, *res
, *res0
;
278 fetch_info("looking up %s", url
->host
);
280 /* look up host name and set up socket address structure */
281 snprintf(pbuf
, sizeof(pbuf
), "%d", url
->port
);
282 memset(&hints
, 0, sizeof(hints
));
283 hints
.ai_family
= af
;
284 hints
.ai_socktype
= SOCK_STREAM
;
285 hints
.ai_protocol
= 0;
286 if ((error
= getaddrinfo(url
->host
, pbuf
, &hints
, &res0
)) != 0) {
290 bindaddr
= getenv("FETCH_BIND_ADDRESS");
293 fetch_info("connecting to %s:%d", url
->host
, url
->port
);
296 for (sd
= -1, res
= res0
; res
; sd
= -1, res
= res
->ai_next
) {
297 if ((sd
= socket(res
->ai_family
, res
->ai_socktype
,
298 res
->ai_protocol
)) == -1)
300 if (bindaddr
!= NULL
&& *bindaddr
!= '\0' &&
301 fetch_bind(sd
, res
->ai_family
, bindaddr
) != 0) {
302 fetch_info("failed to bind to '%s'", bindaddr
);
306 if (connect(sd
, res
->ai_addr
, res
->ai_addrlen
) == 0)
316 if ((conn
= fetch_reopen(sd
)) == NULL
) {
320 conn
->cache_url
= fetchCopyURL(url
);
325 static conn_t
*connection_cache
;
326 static int cache_global_limit
= 0;
327 static int cache_per_host_limit
= 0;
330 * Initialise cache with the given limits.
333 fetchConnectionCacheInit(int global_limit
, int per_host_limit
)
336 if (global_limit
< 0)
337 cache_global_limit
= INT_MAX
;
338 else if (per_host_limit
> global_limit
)
339 cache_global_limit
= per_host_limit
;
341 cache_global_limit
= global_limit
;
342 if (per_host_limit
< 0)
343 cache_per_host_limit
= INT_MAX
;
345 cache_per_host_limit
= per_host_limit
;
349 * Flush cache and free all associated resources.
352 fetchConnectionCacheClose(void)
356 while ((conn
= connection_cache
) != NULL
) {
357 connection_cache
= conn
->next_cached
;
358 (*conn
->cache_close
)(conn
);
363 * Check connection cache for an existing entry matching
364 * protocol/host/port/user/password/family.
367 fetch_cache_get(const struct url
*url
, int af
)
369 conn_t
*conn
, *last_conn
= NULL
;
371 for (conn
= connection_cache
; conn
; conn
= conn
->next_cached
) {
372 if (conn
->cache_url
->port
== url
->port
&&
373 strcmp(conn
->cache_url
->scheme
, url
->scheme
) == 0 &&
374 strcmp(conn
->cache_url
->host
, url
->host
) == 0 &&
375 strcmp(conn
->cache_url
->user
, url
->user
) == 0 &&
376 strcmp(conn
->cache_url
->pwd
, url
->pwd
) == 0 &&
377 (conn
->cache_af
== AF_UNSPEC
|| af
== AF_UNSPEC
||
378 conn
->cache_af
== af
)) {
379 if (last_conn
!= NULL
)
380 last_conn
->next_cached
= conn
->next_cached
;
382 connection_cache
= conn
->next_cached
;
391 * Put the connection back into the cache for reuse.
392 * If the connection is freed due to LRU or if the cache
393 * is explicitly closed, the given callback is called.
396 fetch_cache_put(conn_t
*conn
, int (*closecb
)(conn_t
*))
399 int global_count
, host_count
;
401 if (conn
->cache_url
== NULL
|| cache_global_limit
== 0) {
406 global_count
= host_count
= 0;
408 for (iter
= connection_cache
; iter
;
409 last
= iter
, iter
= iter
->next_cached
) {
411 if (strcmp(conn
->cache_url
->host
, iter
->cache_url
->host
) == 0)
413 if (global_count
< cache_global_limit
&&
414 host_count
< cache_per_host_limit
)
418 last
->next_cached
= iter
->next_cached
;
420 connection_cache
= iter
->next_cached
;
421 (*iter
->cache_close
)(iter
);
424 conn
->cache_close
= closecb
;
425 conn
->next_cached
= connection_cache
;
426 connection_cache
= conn
;
430 * Enable SSL on a connection.
433 fetch_ssl(conn_t
*conn
, int verbose
)
437 /* Init the SSL library and context */
438 if (!SSL_library_init()){
439 fprintf(stderr
, "SSL library init failed\n");
443 SSL_load_error_strings();
445 conn
->ssl_meth
= SSLv23_client_method();
446 conn
->ssl_ctx
= SSL_CTX_new(conn
->ssl_meth
);
447 SSL_CTX_set_mode(conn
->ssl_ctx
, SSL_MODE_AUTO_RETRY
);
449 conn
->ssl
= SSL_new(conn
->ssl_ctx
);
450 if (conn
->ssl
== NULL
){
451 fprintf(stderr
, "SSL context creation failed\n");
454 SSL_set_fd(conn
->ssl
, conn
->sd
);
455 if (SSL_connect(conn
->ssl
) == -1){
456 ERR_print_errors_fp(stderr
);
464 fprintf(stderr
, "SSL connection established using %s\n",
465 SSL_get_cipher(conn
->ssl
));
466 conn
->ssl_cert
= SSL_get_peer_certificate(conn
->ssl
);
467 name
= X509_get_subject_name(conn
->ssl_cert
);
468 str
= X509_NAME_oneline(name
, 0, 0);
469 printf("Certificate subject: %s\n", str
);
471 name
= X509_get_issuer_name(conn
->ssl_cert
);
472 str
= X509_NAME_oneline(name
, 0, 0);
473 printf("Certificate issuer: %s\n", str
);
481 fprintf(stderr
, "SSL support disabled\n");
488 * Read a character from a connection w/ timeout
491 fetch_read(conn_t
*conn
, char *buf
, size_t len
)
493 struct timeval now
, timeout
, waittv
;
501 if (conn
->next_len
!= 0) {
502 if (conn
->next_len
< len
)
503 len
= conn
->next_len
;
504 memmove(buf
, conn
->next_buf
, len
);
505 conn
->next_len
-= len
;
506 conn
->next_buf
+= len
;
512 gettimeofday(&timeout
, NULL
);
513 timeout
.tv_sec
+= fetchTimeout
;
517 while (fetchTimeout
&& !FD_ISSET(conn
->sd
, &readfds
)) {
518 FD_SET(conn
->sd
, &readfds
);
519 gettimeofday(&now
, NULL
);
520 waittv
.tv_sec
= timeout
.tv_sec
- now
.tv_sec
;
521 waittv
.tv_usec
= timeout
.tv_usec
- now
.tv_usec
;
522 if (waittv
.tv_usec
< 0) {
523 waittv
.tv_usec
+= 1000000;
526 if (waittv
.tv_sec
< 0) {
532 r
= select(conn
->sd
+ 1, &readfds
, NULL
, NULL
, &waittv
);
534 if (errno
== EINTR
&& fetchRestartCalls
)
541 if (conn
->ssl
!= NULL
)
542 rlen
= SSL_read(conn
->ssl
, buf
, (int)len
);
545 rlen
= read(conn
->sd
, buf
, len
);
549 if (errno
!= EINTR
|| !fetchRestartCalls
)
557 * Read a line of text from a connection w/ timeout
559 #define MIN_BUF_SIZE 1024
562 fetch_getln(conn_t
*conn
)
568 if (conn
->buf
== NULL
) {
569 if ((conn
->buf
= malloc(MIN_BUF_SIZE
)) == NULL
) {
573 conn
->bufsize
= MIN_BUF_SIZE
;
581 * conn->bufsize != conn->buflen at this point,
582 * so the buffer can be NUL-terminated below for
583 * the case of len == 0.
585 len
= fetch_read(conn
, conn
->buf
+ conn
->buflen
,
586 conn
->bufsize
- conn
->buflen
);
591 next
= memchr(conn
->buf
+ conn
->buflen
, '\n', (size_t)len
);
593 if (conn
->buflen
== conn
->bufsize
&& next
== NULL
) {
595 tmpsize
= conn
->bufsize
* 2;
596 if (tmpsize
< conn
->bufsize
) {
600 if ((tmp
= realloc(tmp
, tmpsize
)) == NULL
) {
605 conn
->bufsize
= tmpsize
;
607 } while (next
== NULL
);
611 conn
->next_buf
= next
+ 1;
612 conn
->next_len
= conn
->buflen
- (conn
->next_buf
- conn
->buf
);
613 conn
->buflen
= next
- conn
->buf
;
615 conn
->buf
[conn
->buflen
] = '\0';
622 * Write a vector to a connection w/ timeout
623 * Note: can modify the iovec.
626 fetch_write(conn_t
*conn
, const void *buf
, size_t len
)
628 struct timeval now
, timeout
, waittv
;
633 static int killed_sigpipe
;
637 if (!killed_sigpipe
) {
638 signal(SIGPIPE
, SIG_IGN
);
646 gettimeofday(&timeout
, NULL
);
647 timeout
.tv_sec
+= fetchTimeout
;
652 while (fetchTimeout
&& !FD_ISSET(conn
->sd
, &writefds
)) {
653 FD_SET(conn
->sd
, &writefds
);
654 gettimeofday(&now
, NULL
);
655 waittv
.tv_sec
= timeout
.tv_sec
- now
.tv_sec
;
656 waittv
.tv_usec
= timeout
.tv_usec
- now
.tv_usec
;
657 if (waittv
.tv_usec
< 0) {
658 waittv
.tv_usec
+= 1000000;
661 if (waittv
.tv_sec
< 0) {
667 r
= select(conn
->sd
+ 1, NULL
, &writefds
, NULL
, &waittv
);
669 if (errno
== EINTR
&& fetchRestartCalls
)
676 if (conn
->ssl
!= NULL
)
677 wlen
= SSL_write(conn
->ssl
, buf
, (int)len
);
681 wlen
= send(conn
->sd
, buf
, len
, 0);
683 wlen
= send(conn
->sd
, buf
, len
, MSG_NOSIGNAL
);
686 /* we consider a short write a failure */
692 if (errno
== EINTR
&& fetchRestartCalls
)
697 buf
= (const char *)buf
+ wlen
;
708 fetch_close(conn_t
*conn
)
712 ret
= close(conn
->sd
);
714 fetchFreeURL(conn
->cache_url
);
715 free(conn
->ftp_home
);
722 /*** Directory-related utility functions *************************************/
725 fetch_add_entry(struct url_list
*ue
, struct url
*base
, const char *name
,
730 size_t base_doc_len
, name_len
, i
;
733 if (strchr(name
, '/') != NULL
||
734 strcmp(name
, "..") == 0 ||
735 strcmp(name
, ".") == 0)
738 if (strcmp(base
->doc
, "/") == 0)
741 base_doc_len
= strlen(base
->doc
);
744 for (i
= 0; name
[i
] != '\0'; ++i
) {
745 if ((!pre_quoted
&& name
[i
] == '%') ||
746 !fetch_urlpath_safe(name
[i
]))
752 tmp_name
= malloc( base_doc_len
+ name_len
+ 1);
753 if (tmp_name
== NULL
) {
759 if (ue
->length
+ 1 >= ue
->alloc_size
) {
760 tmp
= realloc(ue
->urls
, (ue
->alloc_size
* 2 + 1) * sizeof(*tmp
));
767 ue
->alloc_size
= ue
->alloc_size
* 2 + 1;
771 tmp
= ue
->urls
+ ue
->length
;
772 strcpy(tmp
->scheme
, base
->scheme
);
773 strcpy(tmp
->user
, base
->user
);
774 strcpy(tmp
->pwd
, base
->pwd
);
775 strcpy(tmp
->host
, base
->host
);
776 tmp
->port
= base
->port
;
778 memcpy(tmp
->doc
, base
->doc
, base_doc_len
);
779 tmp
->doc
[base_doc_len
] = '/';
781 for (i
= base_doc_len
+ 1; *name
!= '\0'; ++name
) {
782 if ((!pre_quoted
&& *name
== '%') ||
783 !fetch_urlpath_safe(*name
)) {
785 c
= (unsigned char)*name
/ 16;
787 tmp
->doc
[i
++] = '0' + c
;
789 tmp
->doc
[i
++] = 'a' - 10 + c
;
790 c
= (unsigned char)*name
% 16;
792 tmp
->doc
[i
++] = '0' + c
;
794 tmp
->doc
[i
++] = 'a' - 10 + c
;
796 tmp
->doc
[i
++] = *name
;
803 tmp
->last_modified
= -1;
811 fetchInitURLList(struct url_list
*ue
)
813 ue
->length
= ue
->alloc_size
= 0;
818 fetchAppendURLList(struct url_list
*dst
, const struct url_list
*src
)
822 len
= dst
->length
+ src
->length
;
823 if (len
> dst
->alloc_size
) {
826 tmp
= realloc(dst
->urls
, len
* sizeof(*tmp
));
832 dst
->alloc_size
= len
;
836 for (i
= 0, j
= dst
->length
; i
< src
->length
; ++i
, ++j
) {
837 dst
->urls
[j
] = src
->urls
[i
];
838 dst
->urls
[j
].doc
= strdup(src
->urls
[i
].doc
);
839 if (dst
->urls
[j
].doc
== NULL
) {
841 free(dst
->urls
[j
].doc
);
852 fetchFreeURLList(struct url_list
*ue
)
856 for (i
= 0; i
< ue
->length
; ++i
)
857 free(ue
->urls
[i
].doc
);
859 ue
->length
= ue
->alloc_size
= 0;
863 /*** Authentication-related utility functions ********************************/
866 fetch_read_word(FILE *f
)
868 static char word
[1024];
870 if (fscanf(f
, " %1023s ", word
) != 1)
876 * Get authentication data for a URL from .netrc
879 fetch_netrc_auth(struct url
*url
)
886 if ((p
= getenv("NETRC")) != NULL
) {
887 if (snprintf(fn
, sizeof(fn
), "%s", p
) >= (int)sizeof(fn
)) {
888 fetch_info("$NETRC specifies a file name "
889 "longer than PATH_MAX");
893 if ((p
= getenv("HOME")) != NULL
) {
896 if ((pwd
= getpwuid(getuid())) == NULL
||
897 (p
= pwd
->pw_dir
) == NULL
)
900 if (snprintf(fn
, sizeof(fn
), "%s/.netrc", p
) >= (int)sizeof(fn
))
904 if ((f
= fopen(fn
, "r")) == NULL
)
906 while ((word
= fetch_read_word(f
)) != NULL
) {
907 if (strcmp(word
, "default") == 0)
909 if (strcmp(word
, "machine") == 0 &&
910 (word
= fetch_read_word(f
)) != NULL
&&
911 strcasecmp(word
, url
->host
) == 0) {
917 while ((word
= fetch_read_word(f
)) != NULL
) {
918 if (strcmp(word
, "login") == 0) {
919 if ((word
= fetch_read_word(f
)) == NULL
)
921 if (snprintf(url
->user
, sizeof(url
->user
),
922 "%s", word
) > (int)sizeof(url
->user
)) {
923 fetch_info("login name in .netrc is too long");
926 } else if (strcmp(word
, "password") == 0) {
927 if ((word
= fetch_read_word(f
)) == NULL
)
929 if (snprintf(url
->pwd
, sizeof(url
->pwd
),
930 "%s", word
) > (int)sizeof(url
->pwd
)) {
931 fetch_info("password in .netrc is too long");
934 } else if (strcmp(word
, "account") == 0) {
935 if ((word
= fetch_read_word(f
)) == NULL
)
937 /* XXX not supported! */
950 * The no_proxy environment variable specifies a set of domains for
951 * which the proxy should not be consulted; the contents is a comma-,
952 * or space-separated list of domain names. A single asterisk will
953 * override all proxy variables and no transactions will be proxied
954 * (for compatability with lynx and curl, see the discussion at
955 * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>).
958 fetch_no_proxy_match(const char *host
)
960 const char *no_proxy
, *p
, *q
;
963 if ((no_proxy
= getenv("NO_PROXY")) == NULL
&&
964 (no_proxy
= getenv("no_proxy")) == NULL
)
967 /* asterisk matches any hostname */
968 if (strcmp(no_proxy
, "*") == 0)
971 h_len
= strlen(host
);
974 /* position p at the beginning of a domain suffix */
975 while (*p
== ',' || isspace((unsigned char)*p
))
978 /* position q at the first separator character */
980 if (*q
== ',' || isspace((unsigned char)*q
))
984 if (d_len
> 0 && h_len
> d_len
&&
985 strncasecmp(host
+ h_len
- d_len
,
987 /* domain name matches */
999 ssize_t (*io_read
)(void *, void *, size_t);
1000 ssize_t (*io_write
)(void *, const void *, size_t);
1001 void (*io_close
)(void *);
1005 fetchIO_close(fetchIO
*f
)
1007 if (f
->io_close
!= NULL
)
1008 (*f
->io_close
)(f
->io_cookie
);
1014 fetchIO_unopen(void *io_cookie
, ssize_t (*io_read
)(void *, void *, size_t),
1015 ssize_t (*io_write
)(void *, const void *, size_t),
1016 void (*io_close
)(void *))
1020 f
= malloc(sizeof(*f
));
1024 f
->io_cookie
= io_cookie
;
1025 f
->io_read
= io_read
;
1026 f
->io_write
= io_write
;
1027 f
->io_close
= io_close
;
1033 fetchIO_read(fetchIO
*f
, void *buf
, size_t len
)
1035 if (f
->io_read
== NULL
)
1037 return (*f
->io_read
)(f
->io_cookie
, buf
, len
);
1041 fetchIO_write(fetchIO
*f
, const void *buf
, size_t len
)
1043 if (f
->io_read
== NULL
)
1045 return (*f
->io_write
)(f
->io_cookie
, buf
, len
);