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 <bsd.prog.mk>

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 <sys/types.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 
 #include <netinet/in.h>
 
 #include <err.h>
+#include <errno.h>
 #include <limits.h>
+#include <md5.h>
 #include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -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);
 }
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to