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