[PATCH] Add simple splice-fromnet example
authorJens Axboe <jens.axboe@oracle.com>
Fri, 22 Dec 2006 12:44:32 +0000 (13:44 +0100)
committerJens Axboe <jens.axboe@oracle.com>
Fri, 22 Dec 2006 12:44:32 +0000 (13:44 +0100)
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Makefile
README
splice-fromnet.c [new file with mode: 0644]
splice-net.c [deleted file]
splice-tonet.c [new file with mode: 0644]

index a83dd24c9cdc8feb0b1b20cec724cc73b69f3c2c..20255ed110a9595104e2f7459a26abf75e89f7f2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 CC     = gcc
 CFLAGS = -Wall -O2 -g -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
-PROGS  = ktee ktee-net splice-cp splice-in splice-out splice-net splice-test4c splice-test4s vmsplice splice-bench vmsplice2
+PROGS  = ktee ktee-net splice-cp splice-in splice-out splice-tonet splice-fromnet splice-test4c splice-test4s vmsplice splice-bench vmsplice2
 MANS   = splice.2 tee.2 vmsplice.2
 
 all: depend $(PROGS)
diff --git a/README b/README
index 21bfa765f25e46e62b1cd1f66db55c7e6e8d707a..5a6e42a3b06aa27f26cf781f296e5ef84ae02c67 100644 (file)
--- a/README
+++ b/README
@@ -16,7 +16,9 @@ splice-cp:    Splice input file to output file, basically copying the
 
 splice-in:     Splice given file to stdout.
 
-splice-net:    Splice given file to network host.
+splice-tonet:  Splice stdin network host.
+
+splice-fromnet:        Splice from network stdout.
 
 splice-out:    Splice stdin to given file.
 
diff --git a/splice-fromnet.c b/splice-fromnet.c
new file mode 100644 (file)
index 0000000..5968266
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Splice from network to pipe. Currently splicing from a socket is not
+ * supported, so this test case demonstrates how to use read + vmsplice/splice
+ * to achieve the desired effect. This still involves a copy, so it's
+ * not as fast as real splice from socket would be.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "splice.h"
+
+#define PSIZE  4096
+#define MASK   (PSIZE - 1)
+
+#define ALIGN(buf)     (void *) (((unsigned long) (buf) + MASK) & ~MASK)
+
+static int splice_flags;
+
+static int usage(char *name)
+{
+       fprintf(stderr, "%s: [-g] port\n", name);
+       return 1;
+}
+
+static unsigned long mtime_since(struct timeval *s, struct timeval *e)
+{
+       double sec, usec;
+
+       sec = e->tv_sec - s->tv_sec;
+       usec = e->tv_usec - s->tv_usec;
+       if (sec > 0 && usec < 0) {
+               sec--;
+               usec += 1000000;
+       }
+
+       sec *= (double) 1000;
+       usec /= (double) 1000;
+
+       return sec + usec;
+}
+
+static unsigned long mtime_since_now(struct timeval *s)
+{
+       struct timeval t;
+
+       gettimeofday(&t, NULL);
+       return mtime_since(s, &t);
+}
+
+static int recv_loop(int fd, char *buf)
+{
+       unsigned long kb_recv = 0, spent;
+       struct timeval s;
+       struct iovec iov;
+       int idx = 0;
+
+       gettimeofday(&s, NULL);
+
+       do {
+               char *ptr = buf + idx * SPLICE_SIZE;
+               int ret;
+
+               ret = recv(fd, ptr, SPLICE_SIZE, MSG_WAITALL);
+               if (ret < 0) {
+                       perror("recv");
+                       return 1;
+               } else if (ret != SPLICE_SIZE)
+                       break;
+
+               iov.iov_base = ptr;
+               iov.iov_len = SPLICE_SIZE;
+               ret = vmsplice(STDOUT_FILENO, &iov, 1, splice_flags);
+               if (ret < 0) {
+                       perror("vmsplice");
+                       return 1;
+               } else if (ret != SPLICE_SIZE) {
+                       fprintf(stderr, "bad vmsplice %d\n", ret);
+                       return 1;
+               }
+               idx = (idx + 1) & 0x01;
+               kb_recv += (SPLICE_SIZE / 1024);
+       } while (1);
+
+       spent = mtime_since_now(&s);
+       fprintf(stderr, "%lu MiB/sec (%luKiB in %lu msec)\n", kb_recv / spent, kb_recv, spent);
+
+       return 0;
+}
+
+static int parse_options(int argc, char *argv[])
+{
+       int c, index = 1;
+
+       while ((c = getopt(argc, argv, "g")) != -1) {
+               switch (c) {
+               case 'g':
+                       splice_flags = SPLICE_F_GIFT;
+                       index++;
+                       break;
+               default:
+                       return -1;
+               }
+       }
+
+       return index;
+}
+
+int main(int argc, char *argv[])
+{
+       struct sockaddr_in addr;
+       unsigned short port;
+       unsigned int len;
+       int fd, opt, sk, index;
+       char *buf;
+
+       if (check_output_pipe())
+               return usage(argv[0]);
+
+       index = parse_options(argc, argv);
+       if (index == -1 || index + 1 > argc)
+               return usage(argv[0]);
+
+       port = atoi(argv[index]);
+
+       fd = socket(PF_INET, SOCK_STREAM, 0);
+       if (fd < 0)
+               return error("socket");
+
+       opt = 1;
+       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
+               return error("setsockopt");
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sin_addr.s_addr = htonl(INADDR_ANY);
+       addr.sin_port = htons(port);
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+               return error("bind");
+
+       if (listen(fd, 1) < 0)
+               return error("listen");
+
+       len = sizeof(addr);
+       sk = accept(fd, &addr, &len);
+       if (sk < 0)
+               return error("accept");
+
+       fprintf(stderr, "Connected\n");
+
+       buf = ALIGN(malloc(2 * SPLICE_SIZE - 1));
+
+       return recv_loop(sk, buf);
+
+       close(fd);
+       return 0;
+}
diff --git a/splice-net.c b/splice-net.c
deleted file mode 100644 (file)
index 2c117d9..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Splice stdin to net
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <sys/time.h>
-#include <errno.h>
-
-#include "splice.h"
-
-static int usage(char *name)
-{
-       fprintf(stderr, "%s: target port\n", name);
-       return 1;
-}
-
-int main(int argc, char *argv[])
-{
-       struct sockaddr_in addr;
-       unsigned short port;
-       int fd, ret;
-
-       if (argc < 3)
-               return usage(argv[0]);
-
-       if (check_input_pipe())
-               return usage(argv[0]);
-
-       port = atoi(argv[2]);
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-       addr.sin_port = htons(port);
-
-       if (inet_aton(argv[1], &addr.sin_addr) != 1) {
-               struct hostent *hent = gethostbyname(argv[1]);
-
-               if (!hent)
-                       return error("gethostbyname");
-
-               memcpy(&addr.sin_addr, hent->h_addr, 4);
-       }
-
-       printf("Connecting to %s/%d\n", argv[1], port);
-
-       fd = socket(AF_INET, SOCK_STREAM, 0);
-       if (fd < 0)
-               return error("socket");
-
-       if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
-               return error("connect");
-
-       do {
-               ret = splice(STDIN_FILENO, NULL, fd, NULL, SPLICE_SIZE, SPLICE_F_NONBLOCK);
-               if (ret < 0) {
-                       if (errno == EAGAIN) {
-                               usleep(100);
-                               continue;
-                       }
-                       return error("splice");
-               } else if (!ret)
-                       break;
-       } while (1);
-
-       close(fd);
-       return 0;
-}
diff --git a/splice-tonet.c b/splice-tonet.c
new file mode 100644 (file)
index 0000000..2c117d9
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Splice stdin to net
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "splice.h"
+
+static int usage(char *name)
+{
+       fprintf(stderr, "%s: target port\n", name);
+       return 1;
+}
+
+int main(int argc, char *argv[])
+{
+       struct sockaddr_in addr;
+       unsigned short port;
+       int fd, ret;
+
+       if (argc < 3)
+               return usage(argv[0]);
+
+       if (check_input_pipe())
+               return usage(argv[0]);
+
+       port = atoi(argv[2]);
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(port);
+
+       if (inet_aton(argv[1], &addr.sin_addr) != 1) {
+               struct hostent *hent = gethostbyname(argv[1]);
+
+               if (!hent)
+                       return error("gethostbyname");
+
+               memcpy(&addr.sin_addr, hent->h_addr, 4);
+       }
+
+       printf("Connecting to %s/%d\n", argv[1], port);
+
+       fd = socket(AF_INET, SOCK_STREAM, 0);
+       if (fd < 0)
+               return error("socket");
+
+       if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+               return error("connect");
+
+       do {
+               ret = splice(STDIN_FILENO, NULL, fd, NULL, SPLICE_SIZE, SPLICE_F_NONBLOCK);
+               if (ret < 0) {
+                       if (errno == EAGAIN) {
+                               usleep(100);
+                               continue;
+                       }
+                       return error("splice");
+               } else if (!ret)
+                       break;
+       } while (1);
+
+       close(fd);
+       return 0;
+}