From fenner@fee.attlabs.att.com  Tue Oct 15 14:51:32 2002
Return-Path: <fenner@fee.attlabs.att.com>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 1DEFF37B401
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 15 Oct 2002 14:51:32 -0700 (PDT)
Received: from fee.attlabs.att.com (mpfg.attlabs.net [12.106.35.2])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 3DB9743E65
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 15 Oct 2002 14:51:31 -0700 (PDT)
	(envelope-from fenner@fee.attlabs.att.com)
Received: from fee.attlabs.att.com (localhost [127.0.0.1])
	by fee.attlabs.att.com (8.12.6/8.12.6) with ESMTP id g9FLo6tm070086
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 15 Oct 2002 14:50:06 -0700 (PDT)
	(envelope-from fenner@fee.attlabs.att.com)
Received: (from fenner@localhost)
	by fee.attlabs.att.com (8.12.6/8.12.6/Submit) id g9FLo3WR070072;
	Tue, 15 Oct 2002 14:50:03 -0700 (PDT)
	(envelope-from fenner)
Message-Id: <200210152150.g9FLo3WR070072@fee.attlabs.att.com>
Date: Tue, 15 Oct 2002 14:50:03 -0700 (PDT)
From: Bill Fenner <fenner@fee.attlabs.att.com>
Reply-To: Bill Fenner <fenner@fee.attlabs.att.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: libfetch sends CRLF in seperate packet
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         44123
>Category:       bin
>Synopsis:       libfetch sends CRLF in seperate packet
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    des
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Oct 15 15:00:11 PDT 2002
>Closed-Date:    Wed Nov 27 07:45:56 PST 2002
>Last-Modified:  Wed Nov 27 07:45:56 PST 2002
>Originator:     Bill Fenner
>Release:        FreeBSD 5.0-CURRENT sparc64
>Organization:
AT&T Labs - Research
>Environment:
System: FreeBSD fee.attlabs.att.com 5.0-CURRENT FreeBSD 5.0-CURRENT #0: Fri Oct 4 22:01:02 PDT 2002 root@fee.attlabs.att.com:/usr/obj/usr/src/sys/FEE sparc64


	
>Description:
	
The introduction of SSL caused libfetch to switch to two individual
write() calls to send the command and associated CRLF.  This causes
two problems:

1. Nagle causes the transmission of the CRLF to wait for the ACK of the
   command.  This means an extra RTT + delayed-ack-delay to get an individual
   line through.
2. Filtering firewalls such as the Checkpoint Firewall/1 that enforce
   that the FTP port carries FTP commands do not allow command packets
   that do not carry CRLF.  This, of course, is somewhat silly since
   there's nothing that says that the CRLF must be in the same packet,
   but is certainly a big usability issue.

>How-To-Repeat:
	
Run fetch, watch what it puts on the network.  Or inspect the code.
Or run it behind a Checkpoint Firewall/1 and see all of your connection
attempts get reset before the authentication.

>Fix:

	

Introduce _fetch_writev() and use it in _fetch_putln().

Note: the partial write recovery code is untested.  It's required
for SSL use, since there is no SSL_writev.

cvs diff: Diffing .
Index: common.c
===================================================================
RCS file: /net/wilson/usr/home/ncvs/src/lib/libfetch/common.c,v
retrieving revision 1.33
diff -u -r1.33 common.c
--- common.c	20 Sep 2002 21:50:57 -0000	1.33
+++ common.c	15 Oct 2002 21:45:25 -0000
@@ -450,6 +450,20 @@
 ssize_t
 _fetch_write(conn_t *conn, const char *buf, size_t len)
 {
+	struct iovec iov;
+
+	iov.iov_base = (char *)buf;
+	iov.iov_len = len;
+	return _fetch_writev(conn, &iov, 1);
+}
+
+/*
+ * Writev to a connection w/ timeout
+ * Can modify iovec; callers should be aware.
+ */
+ssize_t
+_fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
+{
 	struct timeval now, timeout, wait;
 	fd_set writefds;
 	ssize_t wlen, total;
@@ -461,7 +475,7 @@
 		timeout.tv_sec += fetchTimeout;
 	}
 
-	while (len > 0) {
+	while (iovcnt > 0) {
 		while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) {
 			FD_SET(conn->sd, &writefds);
 			gettimeofday(&now, NULL);
@@ -486,10 +500,10 @@
 		errno = 0;
 #ifdef WITH_SSL
 		if (conn->ssl != NULL)
-			wlen = SSL_write(conn->ssl, buf, len);
+			wlen = SSL_write(conn->ssl, iov->iov_base, iov->iov_len);
 		else
 #endif
-			wlen = write(conn->sd, buf, len);
+			wlen = writev(conn->sd, iov, iovcnt);
 		if (wlen == 0)
 			/* we consider a short write a failure */
 			return (-1);
@@ -498,9 +512,18 @@
 				continue;
 			return (-1);
 		}
-		len -= wlen;
-		buf += wlen;
 		total += wlen;
+		while (wlen > 0 && iovcnt > 0) {
+			if (wlen >= (ssize_t)iov->iov_len) {
+				wlen -= iov->iov_len;
+				iov++;
+				iovcnt--;
+			} else {
+				iov->iov_len -= wlen;
+				iov->iov_base = (char *)iov->iov_base + wlen;
+				wlen = 0;
+			}
+		}
 	}
 	return (total);
 }
@@ -512,10 +535,14 @@
 int
 _fetch_putln(conn_t *conn, const char *str, size_t len)
 {
+	struct iovec iov[2];
 
 	DEBUG(fprintf(stderr, ">>> %s\n", str));
-	if (_fetch_write(conn, str, len) == -1 ||
-	    _fetch_write(conn, ENDL, sizeof ENDL) == -1)
+	iov[0].iov_base = (char *)str;
+	iov[0].iov_len = len;
+	iov[1].iov_base = (char *)ENDL;
+	iov[1].iov_len = sizeof ENDL;
+	if (_fetch_writev(conn, iov, 2) == -1)
 		return (-1);
 	return (0);
 }
Index: common.h
===================================================================
RCS file: /net/wilson/usr/home/ncvs/src/lib/libfetch/common.h,v
retrieving revision 1.24
diff -u -r1.24 common.h
--- common.h	11 Jun 2002 11:27:28 -0000	1.24
+++ common.h	15 Oct 2002 21:43:08 -0000
@@ -68,6 +68,9 @@
 	const char	*string;
 };
 
+/* for _fetch_writev */
+struct iovec;
+
 void		 _fetch_seterr(struct fetcherr *, int);
 void		 _fetch_syserr(void);
 void		 _fetch_info(const char *, ...);
@@ -80,6 +83,7 @@
 ssize_t		 _fetch_read(conn_t *, char *, size_t);
 int		 _fetch_getln(conn_t *);
 ssize_t		 _fetch_write(conn_t *, const char *, size_t);
+ssize_t		 _fetch_writev(conn_t *, struct iovec *, int);
 int		 _fetch_putln(conn_t *, const char *, size_t);
 int		 _fetch_close(conn_t *);
 int		 _fetch_add_entry(struct url_ent **, int *, int *,
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->des 
Responsible-Changed-By: roam 
Responsible-Changed-When: Tue Oct 15 23:40:20 PDT 2002 
Responsible-Changed-Why:  
Over to the libfetch author/maintainer. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=44123 

From: "Peter Edwards" <pmedwards@eircom.net>
To: freebsd-gnats-submit@freebsd.org, fenner@fee.attlabs.att.com
Cc:  
Subject: Re: bin/44123: libfetch sends CRLF in separate packet
Date: Tue, 22 Oct 2002 19:11:56 +0100

 Doh!
 
 The "connection reset by peer" messages were bugged me into finding out
 what was going on also. I created a disturbingly similar patch to Bill's,
 and then discovered his PR before adding my own.
 
 I've attached my patch anyway: I think there's probably slightly less 
 condition checks in my _fetch_writev(), but its functionally equivalent.
 
 There are two other libfetch bugs that aren't addressed by Bill's patch 
 worth looking at it for, though.
 
 The "total" variable was not initialized in _fetch_write(): I think Bill's 
 patch carried this over: mine fixes it. Random stack garbage could cause
 spurious failures.
 
 Another issue in an unrelated area was that _http_growbuf doesn't explitly 
 return a value if it completes successfully.
 
 Patch attached:
 
 begin 644 libfetch.patch.gz
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
 J'1#0:"GFBZUY(DR,$4T/0^#WB](&%6GG32*:E&P_."?^#:'P#@$2$```
 `
 end
 
 -- 
 Peter Edwards.
 
State-Changed-From-To: open->feedback 
State-Changed-By: des 
State-Changed-When: Tue Oct 29 01:31:24 PST 2002 
State-Changed-Why:  
Fixed in -CURRENT, awaiting MFC. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=44123 
State-Changed-From-To: feedback->closed 
State-Changed-By: des 
State-Changed-When: Wed Nov 27 07:45:55 PST 2002 
State-Changed-Why:  
Fixed, thanks. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=44123 
>Unformatted:
