Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 11 May 2011 09:46:36 +0000 (UTC)
From:      Dag-Erling Smorgrav <des@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r221765 - stable/7/lib/libfetch
Message-ID:  <201105110946.p4B9kaTL083669@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: des
Date: Wed May 11 09:46:36 2011
New Revision: 221765
URL: http://svn.freebsd.org/changeset/base/221765

Log:
  Sync with head: proxy authentication, SSL hang, cached connection crash.

Modified:
  stable/7/lib/libfetch/Makefile
  stable/7/lib/libfetch/common.c
  stable/7/lib/libfetch/ftp.c
  stable/7/lib/libfetch/http.c
Directory Properties:
  stable/7/lib/libfetch/   (props changed)

Modified: stable/7/lib/libfetch/Makefile
==============================================================================
--- stable/7/lib/libfetch/Makefile	Wed May 11 09:42:40 2011	(r221764)
+++ stable/7/lib/libfetch/Makefile	Wed May 11 09:46:36 2011	(r221765)
@@ -28,7 +28,7 @@ CFLAGS+=	-DFTP_COMBINE_CWDS
 CSTD?=		c99
 WARNS?=		2
 
-SHLIB_MAJOR=    5
+SHLIB_MAJOR=    6
 
 ftperr.h: ftp.errors ${.CURDIR}/Makefile
 	@echo "static struct fetcherr ftp_errlist[] = {" > ${.TARGET}

Modified: stable/7/lib/libfetch/common.c
==============================================================================
--- stable/7/lib/libfetch/common.c	Wed May 11 09:42:40 2011	(r221764)
+++ stable/7/lib/libfetch/common.c	Wed May 11 09:46:36 2011	(r221765)
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 
 #include <ctype.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <stdarg.h>
@@ -295,7 +296,8 @@ fetch_connect(const char *host, int port
 			close(sd);
 			continue;
 		}
-		if (connect(sd, res->ai_addr, res->ai_addrlen) == 0)
+		if (connect(sd, res->ai_addr, res->ai_addrlen) == 0 &&
+		    fcntl(sd, F_SETFL, O_NONBLOCK) == 0)
 			break;
 		close(sd);
 	}
@@ -319,8 +321,9 @@ fetch_connect(const char *host, int port
 int
 fetch_ssl(conn_t *conn, int verbose)
 {
-
 #ifdef WITH_SSL
+	int ret, ssl_err;
+
 	/* Init the SSL library and context */
 	if (!SSL_library_init()){
 		fprintf(stderr, "SSL library init failed\n");
@@ -339,9 +342,13 @@ fetch_ssl(conn_t *conn, int verbose)
 		return (-1);
 	}
 	SSL_set_fd(conn->ssl, conn->sd);
-	if (SSL_connect(conn->ssl) == -1){
-		ERR_print_errors_fp(stderr);
-		return (-1);
+	while ((ret = SSL_connect(conn->ssl)) == -1) {
+		ssl_err = SSL_get_error(conn->ssl, ret);
+		if (ssl_err != SSL_ERROR_WANT_READ &&
+		    ssl_err != SSL_ERROR_WANT_WRITE) {
+			ERR_print_errors_fp(stderr);
+			return (-1);
+		}
 	}
 
 	if (verbose) {
@@ -370,6 +377,46 @@ fetch_ssl(conn_t *conn, int verbose)
 #endif
 }
 
+#define FETCH_READ_WAIT		-2
+#define FETCH_READ_ERROR	-1
+#define FETCH_READ_DONE		 0
+
+#ifdef WITH_SSL
+static ssize_t
+fetch_ssl_read(SSL *ssl, char *buf, size_t len)
+{
+	ssize_t rlen;
+	int ssl_err;
+
+	rlen = SSL_read(ssl, buf, len);
+	if (rlen < 0) {
+		ssl_err = SSL_get_error(ssl, rlen);
+		if (ssl_err == SSL_ERROR_WANT_READ ||
+		    ssl_err == SSL_ERROR_WANT_WRITE) {
+			return (FETCH_READ_WAIT);
+		} else {
+			ERR_print_errors_fp(stderr);
+			return (FETCH_READ_ERROR);
+		}
+	}
+	return (rlen);
+}
+#endif
+
+static ssize_t
+fetch_socket_read(int sd, char *buf, size_t len)
+{
+	ssize_t rlen;
+
+	rlen = read(sd, buf, len);
+	if (rlen < 0) {
+		if (errno == EAGAIN || (errno == EINTR && fetchRestartCalls))
+			return (FETCH_READ_WAIT);
+		else
+			return (FETCH_READ_ERROR);
+	}
+	return (rlen);
+}
 
 /*
  * Read a character from a connection w/ timeout
@@ -390,6 +437,43 @@ fetch_read(conn_t *conn, char *buf, size
 
 	total = 0;
 	while (len > 0) {
+		/*
+		 * The socket is non-blocking.  Instead of the canonical
+		 * select() -> read(), we do the following:
+		 *
+		 * 1) call read() or SSL_read().
+		 * 2) if an error occurred, return -1.
+		 * 3) if we received data but we still expect more,
+		 *    update our counters and loop.
+		 * 4) if read() or SSL_read() signaled EOF, return.
+		 * 5) if we did not receive any data but we're not at EOF,
+		 *    call select().
+		 *
+		 * In the SSL case, this is necessary because if we
+		 * receive a close notification, we have to call
+		 * SSL_read() one additional time after we've read
+		 * everything we received.
+		 *
+		 * In the non-SSL case, it may improve performance (very
+		 * slightly) when reading small amounts of data.
+		 */
+#ifdef WITH_SSL
+		if (conn->ssl != NULL)
+			rlen = fetch_ssl_read(conn->ssl, buf, len);
+		else
+#endif
+			rlen = fetch_socket_read(conn->sd, buf, len);
+		if (rlen == 0) {
+			break;
+		} else if (rlen > 0) {
+			len -= rlen;
+			buf += rlen;
+			total += rlen;
+			continue;
+		} else if (rlen == FETCH_READ_ERROR) {
+			return (-1);
+		}
+		// assert(rlen == FETCH_READ_WAIT);
 		while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) {
 			FD_SET(conn->sd, &readfds);
 			gettimeofday(&now, NULL);
@@ -413,22 +497,6 @@ fetch_read(conn_t *conn, char *buf, size
 				return (-1);
 			}
 		}
-#ifdef WITH_SSL
-		if (conn->ssl != NULL)
-			rlen = SSL_read(conn->ssl, buf, len);
-		else
-#endif
-			rlen = read(conn->sd, buf, len);
-		if (rlen == 0)
-			break;
-		if (rlen < 0) {
-			if (errno == EINTR && fetchRestartCalls)
-				continue;
-			return (-1);
-		}
-		len -= rlen;
-		buf += rlen;
-		total += rlen;
 	}
 	return (total);
 }
@@ -548,6 +616,7 @@ fetch_writev(conn_t *conn, struct iovec 
 			wlen = writev(conn->sd, iov, iovcnt);
 		if (wlen == 0) {
 			/* we consider a short write a failure */
+			/* XXX perhaps we shouldn't in the SSL case */
 			errno = EPIPE;
 			fetch_syserr();
 			return (-1);

Modified: stable/7/lib/libfetch/ftp.c
==============================================================================
--- stable/7/lib/libfetch/ftp.c	Wed May 11 09:42:40 2011	(r221764)
+++ stable/7/lib/libfetch/ftp.c	Wed May 11 09:46:36 2011	(r221765)
@@ -1132,6 +1132,7 @@ ftp_request(struct url *url, const char 
 
 	/* just a stat */
 	if (strcmp(op, "STAT") == 0) {
+		--conn->ref;
 		ftp_disconnect(conn);
 		return (FILE *)1; /* bogus return value */
 	}

Modified: stable/7/lib/libfetch/http.c
==============================================================================
--- stable/7/lib/libfetch/http.c	Wed May 11 09:42:40 2011	(r221764)
+++ stable/7/lib/libfetch/http.c	Wed May 11 09:46:36 2011	(r221765)
@@ -1786,12 +1786,14 @@ http_request(struct url *URL, const char
 			case hdr_www_authenticate:
 				if (conn->err != HTTP_NEED_AUTH)
 					break;
-				http_parse_authenticate(p, &server_challenges);
+				if (http_parse_authenticate(p, &server_challenges) == 0)
+					++n;
 				break;
 			case hdr_proxy_authenticate:
 				if (conn->err != HTTP_NEED_PROXY_AUTH)
 					break;
-				http_parse_authenticate(p, &proxy_challenges);
+				if (http_parse_authenticate(p, &proxy_challenges) == 0)
+					++n;
 				break;
 			case hdr_end:
 				/* fall through */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105110946.p4B9kaTL083669>