kern/120948: sendfile(2) doesn't send trailers

Dan Nelson dnelson at allantgroup.com
Thu Feb 21 16:00:06 UTC 2008


>Number:         120948
>Category:       kern
>Synopsis:       sendfile(2) doesn't send trailers
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Feb 21 16:00:05 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Dan Nelson
>Release:        FreeBSD 7.0-PRERELEASE i386
>Organization:
The Allant Group
>Environment:
System: FreeBSD dan.emsphone.com 7.0-PRERELEASE FreeBSD 7.0-PRERELEASE #534: Thu Feb 21 09:24:12 CST 2008 zsh at dan.emsphone.com:/usr/src-7/sys/i386/compile/DANSMP i386


	
>Description:

rev 1.240 of uipc_syscalls.c converted the "send file" part of
sendfile(2) from a counted for-loop to an infinite loop, but the code
for breaking out of the loop jumps to the wrong place on success, and
the code for sending the trailer is never called.

	
>How-To-Repeat:
	

Try the following program.  Example of correct output:

Should receive 48 bytes:
rv=0, count=48
rv=48, data=<[this is header]FreeBSD 7.0-PRER[this is trailr]>



#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

int main(void)
{
	int socks[3];
	int fd;
	unsigned int len;
	int rv;
	char buffer[8192];
	off_t count = 0;
	struct sockaddr_in sin;
	struct iovec h, t;
	struct sf_hdtr hdtr;

	printf("Should receive 48 bytes:\n");
	memset(socks, 0, sizeof(socks));
	socks[0] = socket(PF_INET, SOCK_STREAM, 0);
	socks[1] = socket(PF_INET, SOCK_STREAM, 0);
	sin.sin_len = sizeof(sin);
	sin.sin_family = AF_INET;
	inet_aton("0.0.0.0", &sin.sin_addr);
	sin.sin_port = 0;
	bind(socks[0], &sin, sizeof(sin));
	listen(socks[0], 16);
	len = sizeof(sin);
	getsockname(socks[0], &sin, &len);
	connect(socks[1], &sin, sizeof(sin));
	socks[2] = accept(socks[0], NULL, 0);

	/* send 3 16-byte chunks: header, file, trailer */

	h.iov_base = "[this is header]";
	h.iov_len = strlen(h.iov_base);
	t.iov_base = "[this is trailr]";
	t.iov_len = strlen(t.iov_base);
	hdtr.headers = &h;
	hdtr.hdr_cnt = 1;
	hdtr.trailers = &t;
	hdtr.trl_cnt = 1;

	fd = open("/etc/motd", O_RDONLY);
	rv = sendfile(fd, socks[1], 0, 16, &hdtr, &count, 0); 
	printf("rv=%d, count=%lld\n", rv, count);
	sleep(1);
	memset(buffer, 0, 8192);
	rv = read(socks[2], &buffer, 8192);
	printf("rv=%d, data=<%s>\n", rv, buffer);
	return 0;
}


>Fix:

	

This works for me:

Index: uipc_syscalls.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.259.2.2
diff -u -r1.259.2.2 uipc_syscalls.c
--- uipc_syscalls.c	14 Feb 2008 11:44:59 -0000	1.259.2.2
+++ uipc_syscalls.c	21 Feb 2008 15:11:24 -0000
@@ -2172,7 +2172,9 @@
 		}
 
 		/* Quit outer loop on error or when we're done. */
-		if (error || done)
+		if (done) 
+			break;
+		if (error)
 			goto done;
 	}
 


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list