[PATCH] splice-net: make it look like the other tools
[splice.git] / splice-net.c
1 /*
2  * Splice stdin to net
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <netdb.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
13 #include <string.h>
14 #include <sys/time.h>
15 #include <sys/stat.h>
16 #include <errno.h>
17
18 #include "splice.h"
19
20 static struct timeval start_time;
21 static unsigned long long kb_sent;
22
23 static unsigned long mtime_since(struct timeval *s, struct timeval *e)
24 {
25         double sec, usec;
26
27         sec = e->tv_sec - s->tv_sec;
28         usec = e->tv_usec - s->tv_usec;
29         if (sec > 0 && usec < 0) {
30                 sec--;
31                 usec += 1000000;
32         }
33
34         sec *= (double) 1000;
35         usec /= (double) 1000;
36
37         return sec + usec;
38 }
39
40 static unsigned long mtime_since_now(struct timeval *s)
41 {
42         struct timeval t;
43
44         gettimeofday(&t, NULL);
45         return mtime_since(s, &t);
46 }
47
48 void show_rate(int sig)
49 {
50         unsigned long msecs = mtime_since_now(&start_time);
51
52         if (!msecs)
53                 msecs = 1;
54
55         printf("Throughput: %LuMiB/sec (%Lu MiB in %lu msecs)\n", kb_sent / msecs, kb_sent, msecs);
56 }
57
58 int main(int argc, char *argv[])
59 {
60         struct sockaddr_in addr;
61         unsigned short port;
62         int fd, ret;
63         struct stat sb;
64
65         if (argc < 3) {
66                 printf("%s: target port\n", argv[0]);
67                 return 1;
68         }
69
70         if (fstat(STDIN_FILENO, &sb) < 0)
71                 return error("stat");
72         if (!S_ISFIFO(sb.st_mode)) {
73                 fprintf(stderr, "stdin must be a pipe\n");
74                 return 1;
75         }
76
77         port = atoi(argv[2]);
78
79         memset(&addr, 0, sizeof(addr));
80         addr.sin_family = AF_INET;
81         addr.sin_port = htons(port);
82
83         if (inet_aton(argv[1], &addr.sin_addr) != 1) {
84                 struct hostent *hent = gethostbyname(argv[1]);
85
86                 if (!hent)
87                         return error("gethostbyname");
88
89                 memcpy(&addr.sin_addr, hent->h_addr, 4);
90         }
91
92         printf("Connecting to %s/%d\n", argv[1], port);
93
94         fd = socket(AF_INET, SOCK_STREAM, 0);
95         if (fd < 0)
96                 return error("socket");
97
98         if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
99                 return error("connect");
100
101         signal(SIGINT, show_rate);
102         gettimeofday(&start_time, NULL);
103
104         do {
105                 ret = splice(STDIN_FILENO, NULL, fd, NULL, SPLICE_SIZE, SPLICE_F_NONBLOCK);
106                 if (ret < 0) {
107                         if (errno == EAGAIN) {
108                                 usleep(100);
109                                 continue;
110                         }
111                         return error("splice");
112                 } else if (!ret)
113                         break;
114
115                 kb_sent += ret >> 10;
116         } while (1);
117
118         show_rate(0);
119         close(fd);
120         return 0;
121 }