Ticket #1174: sendfile_test.c

File sendfile_test.c, 6.2 KB (added by pokotilenko@…, 10 years ago)

Direct epoll/sendfile test

Line 
1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
5#include <errno.h>
6#include <fcntl.h>
7#include <sys/epoll.h>
8#include <sys/sendfile.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11#include <sys/stat.h>
12#include <netdb.h>
13#include <netinet/in.h>
14#include <netinet/tcp.h>
15
16/* ****************************************************************** */
17int create_listener(char *host, char *port) {
18
19 int fd;
20
21 struct addrinfo hints;
22 struct addrinfo *result, *rp;
23 int s;
24
25 memset(&hints, 0, sizeof(struct addrinfo));
26 hints.ai_family = AF_UNSPEC;
27 hints.ai_socktype = SOCK_STREAM;
28 hints.ai_flags = AI_PASSIVE;
29 hints.ai_protocol = 0;
30
31 if((s = getaddrinfo(host, port, &hints, &result))) {
32 printf("getaddrinfo: %s\n", gai_strerror(s));
33 return(-1);
34 }
35
36 for(rp=result; rp; rp=rp->ai_next) {
37 if(0>(fd=socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))) {
38 printf("socket\n");
39 continue;
40 }
41
42 int yes=1;
43 if(0>setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))) {
44 printf("setsockopt\n");
45 continue;
46 }
47
48 if(0>bind(fd, rp->ai_addr, rp->ai_addrlen)) {
49 printf("could not bind socket to address\n");
50 close(fd);
51 continue;
52 }
53 break;
54 }
55
56 if(!rp) { /* No address succeeded */
57 fprintf(stderr, "Could not connect\n");
58 return(-1);
59 }
60
61 freeaddrinfo(result); /* No longer needed */
62
63 /* set socket to listen for incoming connections */
64 /* allow a queue of 5 */
65 if(0>listen(fd, 5)) {
66 printf("listen error\n");
67 return(-1);
68 }
69
70 return(fd);
71}
72
73/* ****************************************************************** */
74int do_use_fd(int fd_in, off_t *offset, size_t *size_left, int fd_out) {
75
76 ssize_t n;
77
78 if(-1==(n=sendfile(fd_out, fd_in, offset, *size_left))) {
79 printf("Sendfile: failed: %s (%d)\n", strerror(errno), errno);
80 return(-1);
81 }
82 if(!n) {
83 printf("Sendfile: short send: %s (%d)\n", strerror(errno), errno);
84 return(-2);
85 }
86 *size_left-=n;
87
88 return(!(*size_left));
89}
90
91/* ****************************************************************** */
92int main(int argc, char **argv) {
93
94 char *host;
95 char *port;
96 char *fname;
97 int fd_in;
98 int n;
99 int r;
100
101 off_t offset;
102 size_t size_left;
103 struct stat st;
104
105 struct sockaddr_in local;
106 socklen_t addrlen;
107
108 if(argc!=4) {
109 printf("Usage: %s bind_addr bind_port file_name\n", argv[0]);
110 return(1);
111 }
112
113 host=argv[1];
114 port=argv[2];
115 fname=argv[3];
116
117#define MAX_EVENTS 10
118 struct epoll_event ev, events[MAX_EVENTS];
119 int listen_sock, conn_sock, nfds, epollfd;
120
121 /* Set up listening socket, 'listen_sock' (socket(),
122 bind(), listen()) */
123
124 if(-1==(listen_sock=create_listener(host, port))) {
125 printf("create_listener(): failed\n");
126 return(1);
127 }
128
129
130 epollfd = epoll_create(10);
131 if (epollfd == -1) {
132 printf("epoll_create\n");
133 return(2);
134 }
135
136 ev.events = EPOLLIN;
137 ev.data.fd = listen_sock;
138 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
139 printf("epoll_ctl: listen_sock\n");
140 return(3);
141 }
142
143 for (;;) {
144 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 5000);
145 printf("epoll event: nfds: %d\n", nfds);
146 if (nfds == -1) {
147 printf("epoll_pwait\n");
148 return(4);
149 }
150
151 for (n = 0; n < nfds; ++n) {
152 if (events[n].data.fd == listen_sock) {
153
154 conn_sock = accept(listen_sock,
155 (struct sockaddr *) &local, &addrlen);
156 if (conn_sock == -1) {
157 printf("accept\n");
158 return(5);
159 }
160
161 fcntl(conn_sock, F_SETFL, O_NONBLOCK);
162
163 int yes=1;
164 if(0>setsockopt(conn_sock, SOL_TCP, TCP_NODELAY, &yes, sizeof(int))) {
165 printf("setsockopt\n");
166 continue;
167 }
168 if(0>setsockopt(conn_sock, SOL_TCP, TCP_CORK, &yes, sizeof(int))) {
169 printf("setsockopt\n");
170 return(6);
171 }
172
173 ev.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP;
174 //ev.events = EPOLLIN | EPOLLOUT;
175 ev.data.fd = conn_sock;
176 printf("epoll_ctl(add): events: %08X\n", ev.events);
177 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
178 &ev) == -1) {
179 printf("epoll_ctl: conn_sock\n");
180 return(7);
181 }
182
183 if(-1==(fd_in=open(fname, O_RDONLY)) || fstat(fd_in, &st)) {
184 printf("%s: %s (%d)\n", fname, strerror(errno), errno);
185 return(8);
186 }
187 offset=0;
188 size_left=st.st_size;
189
190 } else {
191 if(events[n].events & (EPOLLHUP|EPOLLRDHUP)) {
192 // Disconnect
193 printf("disconnect\n");
194 close(events[n].data.fd);
195 close(fd_in);
196 } else if(events[n].events & (EPOLLIN)) {
197 // Input
198 printf("got input, not supported\n");
199 } else if(events[n].events & (EPOLLOUT)) {
200 // Output
201 printf("can output: events: %08X\n", events[n].events);
202
203 if(0<(r=do_use_fd(fd_in, &offset, &size_left, events[n].data.fd))) {
204 // Finished
205 printf("Finished: sent: %d, left: %d\n", offset, size_left);
206 close(events[n].data.fd);
207 close(fd_in);
208 } else if(!n) {
209 // Need more send
210 printf("Need more send: sent: %d, left: %d\n", offset, size_left);
211 } else {
212 // Error
213 printf("Sending file failed\n");
214 return(9);
215 }
216 } else {
217 // Other
218 }
219 }
220 }
221 }
222}