kern/138465: [tools] [patch] add data verification to tools/regression/sockets/sendfile

Bruce Cran bruce at cran.org.uk
Mon Sep 28 01:10:03 UTC 2009


The following reply was made to PR kern/138465; it has been noted by GNATS.

From: Bruce Cran <bruce at cran.org.uk>
To: bug-followup at FreeBSD.org, bruce at cran.org.uk
Cc:  
Subject: Re: kern/138465: [tools] [patch] add data verification to
 tools/regression/sockets/sendfile
Date: Mon, 28 Sep 2009 02:01:20 +0100

 --MP_/.1q49tsBheL/AS22++0B/uC
 Content-Type: text/plain; charset=US-ASCII
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline
 
 Attached is an updated patch which converts the sendfile test to output
 results in the TAP format and allow subsequent tests to run if one
 fails.
 --MP_/.1q49tsBheL/AS22++0B/uC
 Content-Type: text/plain
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment; filename=sendfile.diff.txt
 
 diff -r -U3 sendfile.orig/Makefile sendfile/Makefile
 --- sendfile.orig/Makefile	2009-09-28 02:48:19.000000000 +0100
 +++ sendfile/Makefile	2009-09-28 02:03:29.000000000 +0100
 @@ -5,5 +5,6 @@
  PROG=	sendfile
  NO_MAN=
  WARNS?=	6
 +LDADD = -lmd -pthread
  
  .include <bsd.prog.mk>
 diff -r -U3 sendfile.orig/sendfile.c sendfile/sendfile.c
 --- sendfile.orig/sendfile.c	2009-09-28 02:48:19.000000000 +0100
 +++ sendfile/sendfile.c	2009-09-28 02:46:29.000000000 +0100
 @@ -33,7 +33,10 @@
  #include <netinet/in.h>
  
  #include <err.h>
 +#include <errno.h>
  #include <limits.h>
 +#include <md5.h>
 +#include <pthread.h>
  #include <signal.h>
  #include <stdint.h>
  #include <stdio.h>
 @@ -47,113 +50,187 @@
   * of cases and performing limited validation.
   */
  
 +#define FAIL(msg)	{printf("# %s\n", msg); \
 +			return (-1);}
 +
 +#define FAIL_ERR(msg)	{printf("# %s: %s\n", msg, strerror(errno)); \
 +			return (-1);}
 +
  #define	TEST_PORT	5678
  #define	TEST_MAGIC	0x4440f7bb
  #define	TEST_PAGES	4
  #define	TEST_SECONDS	30
  
  struct test_header {
 -	u_int32_t	th_magic;
 -	u_int32_t	th_header_length;
 -	u_int32_t	th_offset;
 -	u_int32_t	th_length;
 +	uint32_t	th_magic;
 +	uint32_t	th_header_length;
 +	uint32_t	th_offset;
 +	uint32_t	th_length;
 +	char		th_md5[33];
 +};
 +
 +struct sendfile_test {
 +	uint32_t	hdr_length;
 +	uint32_t	offset;
 +	uint32_t	length;
  };
  
 -pid_t	child_pid, parent_pid;
 -int	listen_socket;
  int	file_fd;
 +char	path[PATH_MAX];
 +int	thread_exitcode;
 +int	listen_socket;
 +int	accept_socket;
 +
 +void cleanup(void);
  
  static int
 -test_th(struct test_header *th, u_int32_t *header_length, u_int32_t *offset,
 -    u_int32_t *length)
 +test_th(struct test_header *th, uint32_t *header_length, uint32_t *offset,
 +    uint32_t *length)
  {
  
  	if (th->th_magic != htonl(TEST_MAGIC))
 -		return (0);
 +		FAIL("magic number not found in header")
  	*header_length = ntohl(th->th_header_length);
  	*offset = ntohl(th->th_offset);
  	*length = ntohl(th->th_length);
 -	return (1);
 +	return (0);
  }
  
  static void
  signal_alarm(int signum)
  {
 -
  	(void)signum;
 +
 +	printf("# test timeout\n");
 +	thread_exitcode = -1;
 +
 +	if (accept_socket > 0)
 +		close(accept_socket);
 +	if (listen_socket > 0)
 +		close(listen_socket);
 +
 +	pthread_exit(&thread_exitcode);
  }
  
  static void
  setup_alarm(int seconds)
  {
 +	struct itimerval itv;
 +	bzero(&itv, sizeof(itv));
 +	(void)seconds;
 +	itv.it_value.tv_sec = seconds;
  
  	signal(SIGALRM, signal_alarm);
 -	alarm(seconds);
 +	setitimer(ITIMER_REAL, &itv, NULL);
  }
  
  static void
  cancel_alarm(void)
  {
 -
 -	alarm(0);
 -	signal(SIGALRM, SIG_DFL);
 +	struct itimerval itv;
 +	bzero(&itv, sizeof(itv));
 +	setitimer(ITIMER_REAL, &itv, NULL);
  }
  
 -static void
 -receive_test(int accept_socket)
 +static int
 +receive_test(void)
  {
 -	u_int32_t header_length, offset, length, counter;
 +	uint32_t header_length, offset, length, counter;
  	struct test_header th;
  	ssize_t len;
 -	char ch;
 +	char buf[10240];
 +	MD5_CTX md5ctx;
 +	char *rxmd5;
  
  	len = read(accept_socket, &th, sizeof(th));
 -	if (len < 0)
 -		err(1, "read");
 -	if ((size_t)len < sizeof(th))
 -		errx(1, "read: %zd", len);
 +	if (len < 0 || (size_t)len < sizeof(th))
 +		FAIL_ERR("read")
 +
 +	if (test_th(&th, &header_length, &offset, &length) != 0)
 +		return (-1);
  
 -	if (test_th(&th, &header_length, &offset, &length) == 0)
 -		errx(1, "test_th: bad");
 +	MD5Init(&md5ctx);
  
  	counter = 0;
  	while (1) {
 -		len = read(accept_socket, &ch, sizeof(ch));
 -		if (len < 0)
 -			err(1, "read");
 -		if (len == 0)
 +		len = read(accept_socket, buf, sizeof(buf));
 +		if (len < 0 || len == 0)
  			break;
 -		counter++;
 -		/* XXXRW: Validate byte here. */
 +		counter += len;
 +		MD5Update(&md5ctx, buf, len);
  	}
 -	if (counter != header_length + length)
 -		errx(1, "receive_test: expected (%d, %d) received %d",
 -		    header_length, length, counter);
 +
 +	rxmd5 = MD5End(&md5ctx, NULL);
 +	
 +	if ((counter != header_length+length) || 
 +			memcmp(th.th_md5, rxmd5, 33) != 0)
 +		FAIL("receive length mismatch")
 +
 +	free(rxmd5);
 +	return (0);
  }
  
 -static void
 -run_child(void)
 +static void*
 +run_child(void* arg)
  {
 -	int accept_socket;
 +	struct sockaddr_in sin;
  
 -	while (1) {
 -		accept_socket = accept(listen_socket, NULL, NULL);	
 -		setup_alarm(TEST_SECONDS);
 -		receive_test(accept_socket);
 -		cancel_alarm();
 -		close(accept_socket);
 +	(void)arg;
 +
 +	listen_socket = socket(PF_INET, SOCK_STREAM, 0);
 +	if (listen_socket < 0) {
 +		printf("# socket: %s\n", strerror(errno));
 +		goto error;
 +	}
 +
 +	bzero(&sin, sizeof(sin));
 +	sin.sin_len = sizeof(sin);
 +	sin.sin_family = AF_INET;
 +	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 +	sin.sin_port = htons(TEST_PORT);
 +
 +	if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
 +		printf("# bind: %s\n", strerror(errno));
 +		goto error;
  	}
 +	
 +	if (listen(listen_socket, -1) < 0) {
 +		printf("# listen: %s\n", strerror(errno));
 +		goto error;
 +	}
 +
 +	accept_socket = accept(listen_socket, NULL, NULL);	
 +	setup_alarm(TEST_SECONDS);
 +	if (receive_test() != 0)
 +		goto error;
 +
 +	thread_exitcode = 0;
 +	goto success;
 +
 +error:
 +	thread_exitcode = -1;
 +
 +success:
 +	cancel_alarm();
 +	if (accept_socket > 0)
 +		close(accept_socket);
 +	if (listen_socket > 0)
 +		close(listen_socket);
 +
 +	accept_socket = -1;
 +	listen_socket = -1;	
 +	pthread_exit(&thread_exitcode);
  }
  
  static int
 -new_test_socket(void)
 +new_test_socket(int *connect_socket)
  {
  	struct sockaddr_in sin;
 -	int connect_socket;
 +	int rc = 0;
  
 -	connect_socket = socket(PF_INET, SOCK_STREAM, 0);
 -	if (connect_socket < 0)
 -		err(1, "socket");
 +	*connect_socket = socket(PF_INET, SOCK_STREAM, 0);
 +	if (*connect_socket < 0)
 +		FAIL_ERR("socket")
  
  	bzero(&sin, sizeof(sin));
  	sin.sin_len = sizeof(sin);
 @@ -161,57 +238,65 @@
  	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  	sin.sin_port = htons(TEST_PORT);
  
 -	if (connect(connect_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0)
 -		err(1, "connect");
 +	if (connect(*connect_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0)
 +		FAIL_ERR("connect")
  
 -	return (connect_socket);
 +	return (rc);
  }
  
  static void
 -init_th(struct test_header *th, u_int32_t header_length, u_int32_t offset,
 -    u_int32_t length)
 +init_th(struct test_header *th, uint32_t header_length, uint32_t offset,
 +    uint32_t length)
  {
 -
  	bzero(th, sizeof(*th));
  	th->th_magic = htonl(TEST_MAGIC);
  	th->th_header_length = htonl(header_length);
  	th->th_offset = htonl(offset);
  	th->th_length = htonl(length);
 +
 +	MD5FileChunk(path, th->th_md5, offset, length);
  }
  
 -static void
 -send_test(int connect_socket, u_int32_t header_length, u_int32_t offset,
 -    u_int32_t length)
 +static int
 +send_test(int connect_socket, struct sendfile_test test)
  {
  	struct test_header th;
  	struct sf_hdtr hdtr, *hdtrp;
  	struct iovec headers;
  	char *header;
  	ssize_t len;
 +	int length;
  	off_t off;
  
  	len = lseek(file_fd, 0, SEEK_SET);
 -	if (len < 0)
 -		err(1, "lseek");
  	if (len != 0)
 -		errx(1, "lseek: %zd", len);
 +		FAIL_ERR("lseek")
  
 -	init_th(&th, header_length, offset, length);
 +	if (test.length == 0)
 +	{
 +		struct stat st;
 +		if (fstat(file_fd, &st) < 0)
 +			FAIL_ERR("fstat")
 +		length = st.st_size - test.offset;
 +	}
 +	else
 +		length = test.length;
 +
 +	init_th(&th, test.hdr_length, test.offset, length);
  
  	len = write(connect_socket, &th, sizeof(th));
 -	if (len < 0)
 -		err(1, "send");
  	if (len != sizeof(th))
 -		err(1, "send: %zd", len);
 +		return (-1);
  
 -	if (header_length != 0) {
 -		header = malloc(header_length);
 +	if (test.hdr_length != 0) {
 +		header = malloc(test.hdr_length);
  		if (header == NULL)
 -			err(1, "malloc");
 +			FAIL_ERR("malloc")
 +
  		hdtrp = &hdtr;
  		bzero(&headers, sizeof(headers));
  		headers.iov_base = header;
 -		headers.iov_len = header_length;
 +		headers.iov_len = test.hdr_length;
  		bzero(&hdtr, sizeof(hdtr));
  		hdtr.headers = &headers;
  		hdtr.hdr_cnt = 1;
 @@ -222,148 +307,124 @@
  		header = NULL;
  	}
  
 -	if (sendfile(file_fd, connect_socket, offset, length, hdtrp, &off,
 -	    0) < 0)
 -		err(1, "sendfile");
 +	if (sendfile(file_fd, connect_socket, test.offset, test.length, 
 +				hdtrp, &off, 0) < 0) {
 +		if (header != NULL)
 +			free(header);
 +		FAIL_ERR("sendfile")
 +	}
  
  	if (length == 0) {
  		struct stat sb;
  
 -		if (fstat(file_fd, &sb) < 0)
 -			err(1, "fstat");
 -		length = sb.st_size - offset;
 -	}
 -
 -	if (off != length) {
 -		errx(1, "sendfile: off(%ju) != length(%ju)",
 -		    (uintmax_t)off, (uintmax_t)length);
 +		if (fstat(file_fd, &sb) == 0)
 +			length = sb.st_size - test.offset;
  	}
  
  	if (header != NULL)
  		free(header);
 +
 +	if (off != length)
 +		FAIL("offset != length")
 +
 +	return (0);
  }
  
  static void
  run_parent(void)
  {
  	int connect_socket;
 +	pthread_t rxthr;
 +	void *rxthr_exitcode;
 +	int test_num;
 +
 +	const int pagesize = getpagesize();
 +
 +	struct sendfile_test tests[10] = {
 +		{ .hdr_length = 0, .offset = 0, .length = 1 },
 +		{ .hdr_length = 0, .offset = 0, .length = pagesize },
 +		{ .hdr_length = 0, .offset = 1, .length = 1 },
 +		{ .hdr_length = 0, .offset = 1, .length = pagesize },
 +		{ .hdr_length = 0, .offset = pagesize, .length = pagesize },
 +		{ .hdr_length = 0, .offset = 0, .length = 2*pagesize },
 +		{ .hdr_length = 0, .offset = 0, .length = 0 },
 +		{ .hdr_length = 0, .offset = pagesize, .length = 0 },
 +		{ .hdr_length = 0, .offset = 2*pagesize, .length = 0 },
 +		{ .hdr_length = 0, .offset = TEST_PAGES*pagesize, .length = 0 }
 +	};
 +
 +	printf("1..10\n");
 +
 +	for (test_num = 1; test_num <= 10; test_num++) {
 +
 +		if (pthread_create(&rxthr, NULL, run_child, NULL) != 0) {
 +			printf("not ok %d\n", test_num);
 +			continue;
 +		}
 +
 +		sleep(1);
 +
 +		if (new_test_socket(&connect_socket) != 0) {
 +			printf("not ok %d\n", test_num);
 +			close(connect_socket);
 +			pthread_kill(rxthr, SIGALRM);
 +			continue;
 +		}
 +
 +		if (send_test(connect_socket, tests[test_num-1]) != 0) {
 +			printf("not ok %d\n", test_num);
 +			pthread_kill(rxthr, SIGALRM);
 +			close(connect_socket);
 +			continue;
 +		}
 +
 +		close(connect_socket);
 +		if (pthread_join(rxthr, &rxthr_exitcode) == 0) {
 +			int *exitcode = (int*)rxthr_exitcode;
 +			printf("%s %d\n", (*exitcode == 0)?
 +					"ok" : "not ok", test_num);
 +		}
 +		else
 +			printf("not ok %d\n", test_num);
 +	}
 +}
  
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, 0, 1);
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, 0, getpagesize());
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, 1, 1);
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, 1, getpagesize());
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, getpagesize(), getpagesize());
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, 0, 2 * getpagesize());
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, 0, 0);
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, getpagesize(), 0);
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, 2 * getpagesize(), 0);
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	connect_socket = new_test_socket();
 -	send_test(connect_socket, 0, TEST_PAGES * getpagesize(), 0);
 -	close(connect_socket);
 -
 -	sleep(1);
 -
 -	(void)kill(child_pid, SIGKILL);
 +void
 +cleanup(void)
 +{
 +	if (*path != '\0')
 +		unlink(path);
  }
  
  int
  main(void)
  {
 -	char path[PATH_MAX], *page_buffer;
 -	struct sockaddr_in sin;
 +	char *page_buffer;
  	int pagesize;
  	ssize_t len;
  
 +	*path = '\0';
 +
  	pagesize = getpagesize();
  	page_buffer = malloc(TEST_PAGES * pagesize);
  	if (page_buffer == NULL)
 -		err(1, "malloc");
 +		FAIL_ERR("malloc")
  	bzero(page_buffer, TEST_PAGES * pagesize);
  
 -	listen_socket = socket(PF_INET, SOCK_STREAM, 0);
 -	if (listen_socket < 0)
 -		err(1, "socket");
 -
 -	bzero(&sin, sizeof(sin));
 -	sin.sin_len = sizeof(sin);
 -	sin.sin_family = AF_INET;
 -	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 -	sin.sin_port = htons(TEST_PORT);
 -
  	snprintf(path, PATH_MAX, "/tmp/sendfile.XXXXXXXXXXXX");
  	file_fd = mkstemp(path);
 -	(void)unlink(path);
 +	atexit(cleanup);
  
  	len = write(file_fd, page_buffer, TEST_PAGES * pagesize);
  	if (len < 0)
 -		err(1, "write");
 +		FAIL_ERR("write")
  
  	len = lseek(file_fd, 0, SEEK_SET);
  	if (len < 0)
 -		err(1, "lseek");
 +		FAIL_ERR("lseek")
  	if (len != 0)
 -		errx(1, "lseek: %zd", len);
 -
 -	if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0)
 -		err(1, "bind");
 -
 -	if (listen(listen_socket, -1) < 0)
 -		err(1, "listen");
 -
 -	parent_pid = getpid();
 -	child_pid = fork();
 -	if (child_pid < 0)
 -		err(1, "fork");
 -	if (child_pid == 0) {
 -		child_pid = getpid();
 -		run_child();
 -	} else
 -		run_parent();
 +		FAIL("len != 0")
  
 +	run_parent();
  	return (0);
  }
 Only in sendfile: sendfile.t
 
 --MP_/.1q49tsBheL/AS22++0B/uC
 Content-Type: text/plain
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment; filename=sendfile.t.txt
 
 # This is a shell archive.  Save it in a file, remove anything before
 # this line, and then unpack it by entering "sh file".  Note, it may
 # create directories; files and directories will be owned by you and
 # have default permissions.
 #
 # This archive contains:
 #
 #	sendfile.t
 #
 echo x - sendfile.t
 sed 's/^X//' >sendfile.t << 'b6d1360dd5883d0daea12ff60ad5ff0a'
 X#!/bin/sh
 X
 Xcd `dirname $0`
 X
 Xexecutable=`basename $0 .t`
 X
 Xmake $executable 2>&1 > /dev/null
 X
 Xexec ./$executable
 b6d1360dd5883d0daea12ff60ad5ff0a
 exit
 
 
 --MP_/.1q49tsBheL/AS22++0B/uC--


More information about the freebsd-bugs mailing list