2 * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * $FreeBSD: src/lib/libfetch/common.c,v 1.56 2008/04/15 23:29:51 cperciva Exp $
29 * $DragonFly: src/lib/libfetch/common.c,v 1.5 2008/04/02 14:46:37 joerg Exp $
32 #include <sys/param.h>
33 #include <sys/socket.h>
37 #include <netinet/in.h>
53 /*** Local data **************************************************************/
56 * Error messages for resolver errors
58 static struct fetcherr netdb_errlist
[] = {
60 { EAI_NODATA
, FETCH_RESOLV
, "Host not found" },
62 { EAI_AGAIN
, FETCH_TEMP
, "Transient resolver failure" },
63 { EAI_FAIL
, FETCH_RESOLV
, "Non-recoverable resolver failure" },
64 { EAI_NONAME
, FETCH_RESOLV
, "No address record" },
65 { -1, FETCH_UNKNOWN
, "Unknown resolver error" }
69 static const char ENDL
[2] = "\r\n";
72 /*** Error-reporting functions ***********************************************/
75 * Map error code to string
77 static struct fetcherr
*
78 fetch_finderr(struct fetcherr
*p
, int e
)
80 while (p
->num
!= -1 && p
->num
!= e
)
89 fetch_seterr(struct fetcherr
*p
, int e
)
91 p
= fetch_finderr(p
, e
);
92 fetchLastErrCode
= p
->cat
;
93 snprintf(fetchLastErrString
, MAXERRSTRING
, "%s", p
->string
);
97 * Set error code according to errno
104 fetchLastErrCode
= FETCH_OK
;
111 fetchLastErrCode
= FETCH_AUTH
;
114 case EISDIR
: /* XXX */
115 fetchLastErrCode
= FETCH_UNAVAIL
;
118 fetchLastErrCode
= FETCH_MEMORY
;
122 fetchLastErrCode
= FETCH_TEMP
;
125 fetchLastErrCode
= FETCH_EXISTS
;
128 fetchLastErrCode
= FETCH_FULL
;
136 fetchLastErrCode
= FETCH_NETWORK
;
140 fetchLastErrCode
= FETCH_ABORT
;
143 fetchLastErrCode
= FETCH_TIMEOUT
;
147 fetchLastErrCode
= FETCH_DOWN
;
150 fetchLastErrCode
= FETCH_UNKNOWN
;
152 snprintf(fetchLastErrString
, MAXERRSTRING
, "%s", strerror(errno
));
157 * Emit status message
160 fetch_info(const char *fmt
, ...)
165 vfprintf(stderr
, fmt
, ap
);
171 /*** Network-related utility functions ***************************************/
174 * Return the default port for a scheme
177 fetch_default_port(const char *scheme
)
181 if ((se
= getservbyname(scheme
, "tcp")) != NULL
)
182 return (ntohs(se
->s_port
));
183 if (strcasecmp(scheme
, SCHEME_FTP
) == 0)
184 return (FTP_DEFAULT_PORT
);
185 if (strcasecmp(scheme
, SCHEME_HTTP
) == 0)
186 return (HTTP_DEFAULT_PORT
);
191 * Return the default proxy port for a scheme
194 fetch_default_proxy_port(const char *scheme
)
196 if (strcasecmp(scheme
, SCHEME_FTP
) == 0)
197 return (FTP_DEFAULT_PROXY_PORT
);
198 if (strcasecmp(scheme
, SCHEME_HTTP
) == 0)
199 return (HTTP_DEFAULT_PROXY_PORT
);
205 * Create a connection for an existing descriptor.
212 /* allocate and fill connection structure */
213 if ((conn
= calloc(1, sizeof(*conn
))) == NULL
)
222 * Bump a connection's reference count.
225 fetch_ref(conn_t
*conn
)
234 * Bind a socket to a specific local address
237 fetch_bind(int sd
, int af
, const char *addr
)
239 struct addrinfo hints
, *res
, *res0
;
242 memset(&hints
, 0, sizeof(hints
));
243 hints
.ai_family
= af
;
244 hints
.ai_socktype
= SOCK_STREAM
;
245 hints
.ai_protocol
= 0;
246 if ((err
= getaddrinfo(addr
, NULL
, &hints
, &res0
)) != 0)
248 for (res
= res0
; res
; res
= res
->ai_next
)
249 if (bind(sd
, res
->ai_addr
, res
->ai_addrlen
) == 0)
256 * Establish a TCP connection to the specified port on the specified host.
259 fetch_connect(const char *host
, int port
, int af
, int verbose
)
263 const char *bindaddr
;
264 struct addrinfo hints
, *res
, *res0
;
267 DEBUG(fprintf(stderr
, "---> %s:%d\n", host
, port
));
270 fetch_info("looking up %s", host
);
272 /* look up host name and set up socket address structure */
273 snprintf(pbuf
, sizeof(pbuf
), "%d", port
);
274 memset(&hints
, 0, sizeof(hints
));
275 hints
.ai_family
= af
;
276 hints
.ai_socktype
= SOCK_STREAM
;
277 hints
.ai_protocol
= 0;
278 if ((err
= getaddrinfo(host
, pbuf
, &hints
, &res0
)) != 0) {
282 bindaddr
= getenv("FETCH_BIND_ADDRESS");
285 fetch_info("connecting to %s:%d", host
, port
);
288 for (sd
= -1, res
= res0
; res
; sd
= -1, res
= res
->ai_next
) {
289 if ((sd
= socket(res
->ai_family
, res
->ai_socktype
,
290 res
->ai_protocol
)) == -1)
292 if (bindaddr
!= NULL
&& *bindaddr
!= '\0' &&
293 fetch_bind(sd
, res
->ai_family
, bindaddr
) != 0) {
294 fetch_info("failed to bind to '%s'", bindaddr
);
298 if (connect(sd
, res
->ai_addr
, res
->ai_addrlen
) == 0)
308 if ((conn
= fetch_reopen(sd
)) == NULL
) {
317 * Enable SSL on a connection.
320 fetch_ssl(conn_t
*conn
, int verbose
)
324 /* Init the SSL library and context */
325 if (!SSL_library_init()){
326 fprintf(stderr
, "SSL library init failed\n");
330 SSL_load_error_strings();
332 conn
->ssl_meth
= SSLv23_client_method();
333 conn
->ssl_ctx
= SSL_CTX_new(conn
->ssl_meth
);
334 SSL_CTX_set_mode(conn
->ssl_ctx
, SSL_MODE_AUTO_RETRY
);
336 conn
->ssl
= SSL_new(conn
->ssl_ctx
);
337 if (conn
->ssl
== NULL
){
338 fprintf(stderr
, "SSL context creation failed\n");
341 SSL_set_fd(conn
->ssl
, conn
->sd
);
342 if (SSL_connect(conn
->ssl
) == -1){
343 ERR_print_errors_fp(stderr
);
351 fprintf(stderr
, "SSL connection established using %s\n",
352 SSL_get_cipher(conn
->ssl
));
353 conn
->ssl_cert
= SSL_get_peer_certificate(conn
->ssl
);
354 name
= X509_get_subject_name(conn
->ssl_cert
);
355 str
= X509_NAME_oneline(name
, 0, 0);
356 printf("Certificate subject: %s\n", str
);
358 name
= X509_get_issuer_name(conn
->ssl_cert
);
359 str
= X509_NAME_oneline(name
, 0, 0);
360 printf("Certificate issuer: %s\n", str
);
368 fprintf(stderr
, "SSL support disabled\n");
375 * Read a character from a connection w/ timeout
378 fetch_read(conn_t
*conn
, char *buf
, size_t len
)
380 struct timeval now
, timeout
, delta
;
387 gettimeofday(&timeout
, NULL
);
388 timeout
.tv_sec
+= fetchTimeout
;
393 while (fetchTimeout
&& !FD_ISSET(conn
->sd
, &readfds
)) {
394 FD_SET(conn
->sd
, &readfds
);
395 gettimeofday(&now
, NULL
);
396 delta
.tv_sec
= timeout
.tv_sec
- now
.tv_sec
;
397 delta
.tv_usec
= timeout
.tv_usec
- now
.tv_usec
;
398 if (delta
.tv_usec
< 0) {
399 delta
.tv_usec
+= 1000000;
402 if (delta
.tv_sec
< 0) {
408 r
= select(conn
->sd
+ 1, &readfds
, NULL
, NULL
, &delta
);
410 if (errno
== EINTR
&& fetchRestartCalls
)
417 if (conn
->ssl
!= NULL
)
418 rlen
= SSL_read(conn
->ssl
, buf
, len
);
421 rlen
= read(conn
->sd
, buf
, len
);
425 if (errno
== EINTR
&& fetchRestartCalls
)
438 * Read a line of text from a connection w/ timeout
440 #define MIN_BUF_SIZE 1024
443 fetch_getln(conn_t
*conn
)
450 if (conn
->buf
== NULL
) {
451 if ((conn
->buf
= malloc(MIN_BUF_SIZE
)) == NULL
) {
455 conn
->bufsize
= MIN_BUF_SIZE
;
462 len
= fetch_read(conn
, &c
, 1);
467 conn
->buf
[conn
->buflen
++] = c
;
468 if (conn
->buflen
== conn
->bufsize
) {
470 tmpsize
= conn
->bufsize
* 2 + 1;
471 if ((tmp
= realloc(tmp
, tmpsize
)) == NULL
) {
476 conn
->bufsize
= tmpsize
;
480 conn
->buf
[conn
->buflen
] = '\0';
481 DEBUG(fprintf(stderr
, "<<< %s", conn
->buf
));
487 * Write to a connection w/ timeout
490 fetch_write(conn_t
*conn
, const char *buf
, size_t len
)
494 iov
.iov_base
= __DECONST(char *, buf
);
496 return fetch_writev(conn
, &iov
, 1);
500 * Write a vector to a connection w/ timeout
501 * Note: can modify the iovec.
504 fetch_writev(conn_t
*conn
, struct iovec
*iov
, int iovcnt
)
506 struct timeval now
, timeout
, delta
;
513 gettimeofday(&timeout
, NULL
);
514 timeout
.tv_sec
+= fetchTimeout
;
519 while (fetchTimeout
&& !FD_ISSET(conn
->sd
, &writefds
)) {
520 FD_SET(conn
->sd
, &writefds
);
521 gettimeofday(&now
, NULL
);
522 delta
.tv_sec
= timeout
.tv_sec
- now
.tv_sec
;
523 delta
.tv_usec
= timeout
.tv_usec
- now
.tv_usec
;
524 if (delta
.tv_usec
< 0) {
525 delta
.tv_usec
+= 1000000;
528 if (delta
.tv_sec
< 0) {
534 r
= select(conn
->sd
+ 1, NULL
, &writefds
, NULL
, &delta
);
536 if (errno
== EINTR
&& fetchRestartCalls
)
543 if (conn
->ssl
!= NULL
)
544 wlen
= SSL_write(conn
->ssl
,
545 iov
->iov_base
, iov
->iov_len
);
548 wlen
= writev(conn
->sd
, iov
, iovcnt
);
550 /* we consider a short write a failure */
556 if (errno
== EINTR
&& fetchRestartCalls
)
561 while (iovcnt
> 0 && wlen
>= (ssize_t
)iov
->iov_len
) {
562 wlen
-= iov
->iov_len
;
567 iov
->iov_len
-= wlen
;
568 iov
->iov_base
= __DECONST(char *, iov
->iov_base
) + wlen
;
576 * Write a line of text to a connection w/ timeout
579 fetch_putln(conn_t
*conn
, const char *str
, size_t len
)
584 DEBUG(fprintf(stderr
, ">>> %s\n", str
));
585 iov
[0].iov_base
= __DECONST(char *, str
);
586 iov
[0].iov_len
= len
;
587 iov
[1].iov_base
= __DECONST(char *, ENDL
);
588 iov
[1].iov_len
= sizeof(ENDL
);
590 ret
= fetch_writev(conn
, &iov
[1], 1);
592 ret
= fetch_writev(conn
, iov
, 2);
603 fetch_close(conn_t
*conn
)
609 ret
= close(conn
->sd
);
616 /*** Directory-related utility functions *************************************/
619 fetch_add_entry(struct url_ent
**p
, int *size
, int *len
,
620 const char *name
, struct url_stat
*us
)
629 if (*len
>= *size
- 1) {
630 tmp
= realloc(*p
, (*size
* 2 + 1) * sizeof(**p
));
636 *size
= (*size
* 2 + 1);
641 snprintf(tmp
->name
, PATH_MAX
, "%s", name
);
642 memcpy(&tmp
->stat
, us
, sizeof(*us
));
645 (++tmp
)->name
[0] = 0;
651 /*** Authentication-related utility functions ********************************/
654 fetch_read_word(FILE *f
)
656 static char word
[1024];
658 if (fscanf(f
, " %1023s ", word
) != 1)
664 * Get authentication data for a URL from .netrc
667 fetch_netrc_auth(struct url
*url
)
674 if ((p
= getenv("NETRC")) != NULL
) {
675 if (snprintf(fn
, sizeof(fn
), "%s", p
) >= (int)sizeof(fn
)) {
676 fetch_info("$NETRC specifies a file name "
677 "longer than PATH_MAX");
681 if ((p
= getenv("HOME")) != NULL
) {
684 if ((pwd
= getpwuid(getuid())) == NULL
||
685 (p
= pwd
->pw_dir
) == NULL
)
688 if (snprintf(fn
, sizeof(fn
), "%s/.netrc", p
) >= (int)sizeof(fn
))
692 if ((f
= fopen(fn
, "r")) == NULL
)
694 while ((word
= fetch_read_word(f
)) != NULL
) {
695 if (strcmp(word
, "default") == 0) {
696 DEBUG(fetch_info("Using default .netrc settings"));
699 if (strcmp(word
, "machine") == 0 &&
700 (word
= fetch_read_word(f
)) != NULL
&&
701 strcasecmp(word
, url
->host
) == 0) {
702 DEBUG(fetch_info("Using .netrc settings for %s", word
));
708 while ((word
= fetch_read_word(f
)) != NULL
) {
709 if (strcmp(word
, "login") == 0) {
710 if ((word
= fetch_read_word(f
)) == NULL
)
712 if (snprintf(url
->user
, sizeof(url
->user
),
713 "%s", word
) > (int)sizeof(url
->user
)) {
714 fetch_info("login name in .netrc is too long");
717 } else if (strcmp(word
, "password") == 0) {
718 if ((word
= fetch_read_word(f
)) == NULL
)
720 if (snprintf(url
->pwd
, sizeof(url
->pwd
),
721 "%s", word
) > (int)sizeof(url
->pwd
)) {
722 fetch_info("password in .netrc is too long");
725 } else if (strcmp(word
, "account") == 0) {
726 if ((word
= fetch_read_word(f
)) == NULL
)
728 /* XXX not supported! */
741 * The no_proxy environment variable specifies a set of domains for
742 * which the proxy should not be consulted; the contents is a comma-,
743 * or space-separated list of domain names. A single asterisk will
744 * override all proxy variables and no transactions will be proxied
745 * (for compatability with lynx and curl, see the discussion at
746 * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>).
749 fetch_no_proxy_match(const char *host
)
751 const char *no_proxy
, *p
, *q
;
754 if ((no_proxy
= getenv("NO_PROXY")) == NULL
&&
755 (no_proxy
= getenv("no_proxy")) == NULL
)
758 /* asterisk matches any hostname */
759 if (strcmp(no_proxy
, "*") == 0)
762 h_len
= strlen(host
);
765 /* position p at the beginning of a domain suffix */
766 while (*p
== ',' || isspace((unsigned char)*p
))
769 /* position q at the first separator character */
771 if (*q
== ',' || isspace((unsigned char)*q
))
775 if (d_len
> 0 && h_len
> d_len
&&
776 strncasecmp(host
+ h_len
- d_len
,
778 /* domain name matches */