Add nettest/ tools
[splice.git] / nettest / sf.c
1 /*
2  * sendfile() a file
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 <netinet/in.h>
11 #include <arpa/inet.h>
12 #include <string.h>
13 #include <sys/time.h>
14 #include <sys/sendfile.h>
15 #include <sys/stat.h>
16 #include <errno.h>
17
18 static int loop;
19
20 static inline int error(const char *n)
21 {
22         perror(n);
23         return -1;
24 }
25
26 static int usage(char *name)
27 {
28         fprintf(stderr, "%s: file target port\n", name);
29         return 1;
30 }
31
32 static int do_sf(int filefd, int sockfd)
33 {
34         struct stat sb;
35         int ret;
36
37         if (fstat(filefd, &sb) < 0)
38                 return error("stat input file");
39         if (!sb.st_size)
40                 return -1;
41
42         if (lseek(filefd, 0, SEEK_SET) < 0)
43                 return error("lseek");
44
45         while (sb.st_size) {
46                 ret = sendfile(sockfd, filefd, NULL, sb.st_size);
47                 if (ret < 0)
48                         return error("sendfile");
49                 else if (!ret)
50                         break;
51
52                 sb.st_size -= ret;
53         }
54
55         return 0;
56 }
57
58 static int parse_options(int argc, char *argv[])
59 {
60         int c, index = 1;
61
62         while ((c = getopt(argc, argv, "l")) != -1) {
63                 switch (c) {
64                 case 'l':
65                         loop = 1;
66                         index++;
67                         break;
68                 default:
69                         return -1;
70                 }
71         }
72
73         return index;
74 }
75
76 int main(int argc, char *argv[])
77 {
78         struct sockaddr_in addr;
79         unsigned short port;
80         int fd, filefd, index;
81
82         if (argc < 4)
83                 return usage(argv[0]);
84
85         index = parse_options(argc, argv);
86         if (index == -1 || index + 1 > argc)
87                 return usage(argv[0]);
88
89         filefd = open(argv[index], O_RDONLY);
90         if (filefd < 0)
91                 return error("open input file");
92
93         port = atoi(argv[index + 2]);
94
95         memset(&addr, 0, sizeof(addr));
96         addr.sin_family = AF_INET;
97         addr.sin_port = htons(port);
98
99         if (inet_aton(argv[index + 1], &addr.sin_addr) != 1) {
100                 struct hostent *hent = gethostbyname(argv[index + 1]);
101
102                 if (!hent)
103                         return error("gethostbyname");
104
105                 memcpy(&addr.sin_addr, hent->h_addr, 4);
106         }
107
108         printf("Connecting to %s/%d\n", argv[index + 1], port);
109
110         fd = socket(AF_INET, SOCK_STREAM, 0);
111         if (fd < 0)
112                 return error("socket");
113
114         if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
115                 return error("connect");
116
117         do {
118                 if (do_sf(filefd, fd))
119                         break;
120         } while (loop);
121
122         close(fd);
123         close(filefd);
124         return 0;
125 }