Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 8 Dec 2001 16:28:49 -0600
From:      Alfred Perlstein <bright@mu.org>
To:        hackers@freebsd.org
Cc:        dg@freebsd.org, jasone@freebsd.org
Subject:   sendfile libc_r fix.
Message-ID:  <20011208162849.H92148@elvis.mu.org>

next in thread | raw e-mail | index | archive | help
One of the apache guys recent got ahold of me with this bug in
the libc_r code that wraps sendfile.

Effectively what was happening was that the sf_hdr was only
partially succeeding, however then the code would spew the
contents of the file down the socket.

There was also the problem that libc_r wasn't emulating the
whacked out sendfile(2) semantics such that the amount of
data in the headers is subtracted from the amount of data
to be sent from the file.

David, any chance you can fix this?  I guess it's time to
make use of that 'flags' argument? :)

Here is a fix, it may have issues, but we're unsure of whether
my fix is buggy or if apache is buggy at this point.

Feedback would be appreciated.  I'd like to commit this as
an interm fix as it seems to make things better but not
perfect.

http://people.freebsd.org/~alfred/uthread_sf.diff

Index: uthread_sendfile.c
===================================================================
RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_sendfile.c,v
retrieving revision 1.5
diff -u -r1.5 uthread_sendfile.c
--- uthread_sendfile.c	10 Apr 2001 04:19:20 -0000	1.5
+++ uthread_sendfile.c	9 Dec 2001 00:00:32 -0000
@@ -48,13 +48,25 @@
 	ssize_t wvret, num = 0;
 	off_t	n, nwritten = 0;
 
-	/* Write the headers if any. */
+	/*
+	 * Write the headers if any.
+	 * If some data is written but not all we must return here.
+	 */
 	if ((hdtr != NULL) && (hdtr->headers != NULL)) {
 		if ((wvret = writev(s, hdtr->headers, hdtr->hdr_cnt)) == -1) {
 			ret = -1;
 			goto ERROR;
-		} else
+		} else {
+			int i;
+			ssize_t hdrtot;
+
 			nwritten += wvret;
+
+			for (i = 0, hdrtot = 0; i < hdtr->hdr_cnt; i++)
+				hdrtot += hdtr->headers[i].iov_len;
+			if (wvret < hdrtot)
+				goto SHORT_HEADER;
+		}
 	}
 	
 	/* Lock the descriptors. */
@@ -87,7 +99,18 @@
 
 	/* Check if file operations are to block */
 	blocking = ((_thread_fd_table[s]->flags & O_NONBLOCK) == 0);
-	
+
+	/*
+	 * Emulate sendfile(2) weirdness, sendfile doesn't actually send
+	 * nbytes of the file, it really sends (nbytes - headers_size) of
+	 * the file.  If (nbytes - headers_size) == 0 we just send trailers.
+	 */	
+	if (nbytes != 0) {
+		nbytes -= nwritten;
+		if (nbytes <= 0)
+			goto ERROR_2;
+	}
+
 	/*
 	 * Loop while no error occurs and until the expected number of bytes are
 	 * written.
@@ -144,6 +167,7 @@
 				nwritten += wvret;
 		}
 	}
+  SHORT_HEADER:
 	if (sbytes != NULL) {
 		/*
 		 * Number of bytes written in headers/trailers, plus in the main

-- 
-Alfred Perlstein [alfred@freebsd.org]
'Instead of asking why a piece of software is using "1970s technology,"
 start asking why software is ignoring 30 years of accumulated wisdom.'
                           http://www.morons.org/rants/gpl-harmful.php3

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




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