From owner-svn-src-all@FreeBSD.ORG Wed Feb 24 23:00:16 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id DD17D106564A; Wed, 24 Feb 2010 23:00:16 +0000 (UTC) (envelope-from brucec@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id CBA198FC12; Wed, 24 Feb 2010 23:00:16 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o1ON0G7P030437; Wed, 24 Feb 2010 23:00:16 GMT (envelope-from brucec@svn.freebsd.org) Received: (from brucec@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o1ON0GVW030434; Wed, 24 Feb 2010 23:00:16 GMT (envelope-from brucec@svn.freebsd.org) Message-Id: <201002242300.o1ON0GVW030434@svn.freebsd.org> From: Bruce Cran Date: Wed, 24 Feb 2010 23:00:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r204294 - head/tools/regression/sockets/sendfile X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Feb 2010 23:00:17 -0000 Author: brucec Date: Wed Feb 24 23:00:16 2010 New Revision: 204294 URL: http://svn.freebsd.org/changeset/base/204294 Log: Update the sendfile regression test so that it outputs results in the TAP format. Add a checksum to verify that the data hasn't been corrupted between being read from disk and being received. Approved by: rrs (mentor) Modified: head/tools/regression/sockets/sendfile/Makefile head/tools/regression/sockets/sendfile/sendfile.c Modified: head/tools/regression/sockets/sendfile/Makefile ============================================================================== --- head/tools/regression/sockets/sendfile/Makefile Wed Feb 24 22:16:16 2010 (r204293) +++ head/tools/regression/sockets/sendfile/Makefile Wed Feb 24 23:00:16 2010 (r204294) @@ -5,5 +5,6 @@ PROG= sendfile NO_MAN= WARNS?= 6 +LDADD = -lmd .include Modified: head/tools/regression/sockets/sendfile/sendfile.c ============================================================================== --- head/tools/regression/sockets/sendfile/sendfile.c Wed Feb 24 22:16:16 2010 (r204293) +++ head/tools/regression/sockets/sendfile/sendfile.c Wed Feb 24 23:00:16 2010 (r204294) @@ -29,11 +29,14 @@ #include #include #include +#include #include #include +#include #include +#include #include #include #include @@ -47,113 +50,192 @@ * 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 listen_socket; +int accept_socket; + +static int test_th(struct test_header *th, uint32_t *header_length, + uint32_t *offset, uint32_t *length); +static void signal_alarm(int signum); +static void setup_alarm(int seconds); +static void cancel_alarm(void); +static int receive_test(void); +static void run_child(void); +static int new_test_socket(int *connect_socket); +static void init_th(struct test_header *th, uint32_t header_length, + uint32_t offset, uint32_t length); +static int send_test(int connect_socket, struct sendfile_test); +static void run_parent(void); +static 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"); + + if (accept_socket > 0) + close(accept_socket); + if (listen_socket > 0) + close(listen_socket); + + _exit(-1); } 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) - errx(1, "test_th: bad"); + if (test_th(&th, &header_length, &offset, &length) != 0) + return (-1); + + 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) { - int accept_socket; + struct sockaddr_in sin; + int rc = 0; - while (1) { + listen_socket = socket(PF_INET, SOCK_STREAM, 0); + if (listen_socket < 0) { + printf("# socket: %s\n", strerror(errno)); + rc = -1; + } + + if (!rc) { + 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)); + rc = -1; + } + } + + if (!rc && listen(listen_socket, -1) < 0) { + printf("# listen: %s\n", strerror(errno)); + rc = -1; + } + + if (!rc) { accept_socket = accept(listen_socket, NULL, NULL); setup_alarm(TEST_SECONDS); - receive_test(accept_socket); - cancel_alarm(); - close(accept_socket); + if (receive_test() != 0) + rc = -1; } + + cancel_alarm(); + if (accept_socket > 0) + close(accept_socket); + if (listen_socket > 0) + close(listen_socket); + + _exit(rc); } 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 +243,65 @@ new_test_socket(void) 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 +312,130 @@ send_test(int connect_socket, u_int32_t 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; + int status; + int test_num; + int pid; + + 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++) { + + pid = fork(); + if (pid == -1) { + printf("not ok %d\n", test_num); + continue; + } + + if (pid == 0) + run_child(); + + usleep(250000); + + if (new_test_socket(&connect_socket) != 0) { + printf("not ok %d\n", test_num); + kill(pid, SIGALRM); + close(connect_socket); + continue; + } + + if (send_test(connect_socket, tests[test_num-1]) != 0) { + printf("not ok %d\n", test_num); + kill(pid, SIGALRM); + close(connect_socket); + continue; + } + + close(connect_socket); + if (waitpid(pid, &status, 0) == pid) { + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + printf("%s %d\n", "ok", test_num); + else + printf("%s %d\n", "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); +static 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); }