udp tcp epoll serv
[socket_samples.git] / sockevent.c
blob66600c89df21682cf84488939bfdd68c1704e62c
1 /* sockevent.c
2 * create TCP socket and store then in a epoll file descriptor
3 * build with : gcc -O3 -g -falign-functions=4 -falign-jumps -falign-loops -Wall -o sockevent sockevent.c
4 */
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12 #include <netdb.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <sys/epoll.h>
16 #include <fcntl.h>
17 #include <signal.h>
18 #include <sys/time.h>
19 #include <pthread.h>
22 /* catch SIGINT and set stop to signal_id
24 int stop;
25 void interrupt(int signal_id)
27 stop = signal_id;
30 // init struct for statistics
31 struct statistics
33 int reqsent;
34 int bytessent;
35 int reprecv;
36 int bytesrecv;
37 int error;
38 int nbsock;
41 void printstats(struct statistics *stats)
43 struct statistics previous;
44 previous.reqsent = 0;
45 previous.reprecv = 0;
46 int banner = 0;
48 printf("\nreprecv\tbytes\t^hit\treqsent\tbytes\t^req\tErrors\tActive\n");
50 for(;;)
52 sleep(1);
53 if(banner == 10)
55 printf("\nreprecv\tbytes\t^hit\treqsent\tbytes\t^req\tErrors\tActive\n");
56 banner = 0;
58 else
59 banner++;
62 printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", stats->reprecv, stats->bytesrecv, stats->reprecv - previous.reprecv,stats->reqsent, stats->bytessent, stats->reqsent - previous.reqsent, stats->error, stats->nbsock);
64 previous.reqsent = stats->reqsent;
65 previous.reprecv = stats->reprecv;
71 /* WT (inject29) function to convert a ip:port chain into a sockaddr struct */
72 struct sockaddr_in str2sa(char *str)
74 static struct sockaddr_in sa;
75 char *c;
76 int port;
78 bzero(&sa, sizeof(sa));
79 str=strdup(str);
80 if ((c=strrchr(str,':')) != NULL) {
81 *c++=0;
82 port=atol(c);
84 else
85 port=0;
87 if (!inet_aton(str, &sa.sin_addr)) {
88 struct hostent *he;
90 if ((he = gethostbyname(str)) == NULL)
91 fprintf(stderr,"[NetTools] Invalid server name: %s\n",str);
92 else
93 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
95 sa.sin_port=htons(port);
96 sa.sin_family=AF_INET;
98 free(str);
99 return sa;
102 /* create a TCP socket with non blocking options and connect it to the target
103 * if succeed, add the socket in the epoll list and exit with 0
105 int create_and_connect( struct sockaddr_in target , int *epfd)
107 int yes = 1;
108 int sock;
110 // epoll mask that contain the list of epoll events attached to a network socket
111 static struct epoll_event Edgvent;
114 if( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
116 perror("socket");
117 exit(1);
120 // set socket to non blocking and allow port reuse
121 if ( (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) ||
122 fcntl(sock, F_SETFL, O_NONBLOCK)) == -1)
124 perror("setsockopt || fcntl");
125 exit(1);
128 if( connect(sock, (struct sockaddr *)&target, sizeof(struct sockaddr)) == -1
129 && errno != EINPROGRESS)
131 // connect doesn't work, are we running out of available ports ? if yes, destruct the socket
132 if (errno == EAGAIN)
134 perror("connect is EAGAIN");
135 close(sock);
136 exit(1);
139 else
141 /* epoll will wake up for the following events :
143 * EPOLLIN : The associated file is available for read(2) operations.
145 * EPOLLOUT : The associated file is available for write(2) operations.
147 * EPOLLRDHUP : Stream socket peer closed connection, or shut down writing
148 * half of connection. (This flag is especially useful for writing simple
149 * code to detect peer shutdown when using Edge Triggered monitoring.)
151 * EPOLLERR : Error condition happened on the associated file descriptor.
152 * epoll_wait(2) will always wait for this event; it is not necessary to set it in events.
154 Edgvent.events = EPOLLOUT | EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLET ;
155 //Edgvent.events = EPOLLOUT | EPOLLIN | EPOLLRDHUP | EPOLLERR;
157 Edgvent.data.fd = sock;
159 // add the socket to the epoll file descriptors
160 if(epoll_ctl((int)epfd, EPOLL_CTL_ADD, sock, &Edgvent) != 0)
162 perror("epoll_ctl, adding socket\n");
163 exit(1);
167 return 0;
173 /* reading waiting errors on the socket
174 * return 0 if there's no, 1 otherwise
176 int socket_check(int fd)
178 int ret;
179 int code;
180 size_t len = sizeof(int);
182 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &code, &len);
184 if ((ret || code)!= 0)
185 return 1;
187 return 0;
193 int main(int argc, char *argv[])
196 if(argc!=3)
198 printf("gatlinject <ip:port> <num socket>\n");
199 exit(1);
202 struct sockaddr_in target = str2sa((char *) argv[1]); // convert target information
203 int maxconn = atoi(argv[2]); //number of sockets to connect to the target
205 // internal variables definition
206 int i, count, datacount;
208 char message[] = "hello\n\n";
209 int messagelength = strlen(message);
211 char buffer[1500];
212 int buffersize = strlen(buffer);
214 struct statistics stats;
215 memset(&stats,0x0,6 * sizeof(int));
216 pthread_t Statsthread;
219 // time
220 struct timeval start;
221 struct timeval current;
222 float elapsedtime;
224 // catch SIGINT to exit in a clean way
225 struct sigaction sa;
226 memset(&sa, 0, sizeof(struct sigaction *));
227 sa.sa_handler = interrupt;
228 sa.sa_flags = 0;
229 sigemptyset (&(sa.sa_mask));
230 if(sigaction (SIGINT, &sa, NULL)!= 0)
232 perror("sigaction failed");
233 exit(1);
236 // the epoll file descriptor
237 int epfd;
239 // epoll structure that will contain the current network socket and event when epoll wakes up
240 static struct epoll_event *events;
241 static struct epoll_event event_mask;
243 // create the special epoll file descriptor
244 epfd = epoll_create(maxconn);
246 // allocate enough memory to store all the events in the "events" structure
247 if (NULL == (events = calloc(maxconn, sizeof(struct epoll_event))))
249 perror("calloc events");
250 exit(1);
253 // create and connect as much as needed
254 for(i=0;i<maxconn;i++)
255 if(create_and_connect(target, (int *) epfd) != 0)
257 perror("create and connect");
258 exit(1);
260 else
261 stats.nbsock++;
263 // start the thread that prints the statistics
264 if( 0!= pthread_create (&Statsthread, NULL, (void *)printstats, &stats) ){
265 perror("stats thread");
266 exit(1);
269 gettimeofday(&start, NULL);
273 /* wait for events on the file descriptors added into epfd
275 * if one of the socket that's contained into epfd is available for reading, writing,
276 * is closed or have an error, this socket will be return in events[i].data.fd
277 * and events[i].events will be set to the corresponding event
279 * count contain the number of returned events
281 count = epoll_wait(epfd, events, maxconn, 1000);
283 for(i=0;i<count;i++)
285 if (events[i].events & EPOLLOUT) //socket is ready for writing
287 // verify the socket is connected and doesn't return an error
288 if(socket_check(events[i].data.fd) != 0)
290 perror("write socket_check");
291 continue;
293 else
295 if((datacount = send(events[i].data.fd, message, messagelength, 0)) < 0)
297 stats.error++;
298 perror("send failed");
299 continue;
301 else
303 /* we just wrote on this socket, we don't want to write on it anymore
304 * but we still want to read on it, so we modify the event mask to
305 * remove EPOLLOUT from the events list
307 event_mask.events = EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLET;
308 event_mask.data.fd = events[i].data.fd;
310 if(epoll_ctl(epfd, EPOLL_CTL_MOD, events[i].data.fd, &event_mask) != 0)
312 perror("epoll_ctl, modify socket\n");
313 exit(1);
316 stats.reqsent++;
317 stats.bytessent += datacount;
322 if (events[i].events & EPOLLIN) //socket is ready for writing
324 // verify the socket is connected and doesn't return an error
325 if(socket_check(events[i].data.fd) != 0)
327 perror("read socket_check");
328 continue;
330 else
332 memset(buffer,0x0,buffersize);
334 if((datacount = recv(events[i].data.fd, buffer, buffersize, 0)) < 0)
336 stats.error++;
337 perror("recv failed");
338 continue;
340 else
342 stats.bytesrecv += datacount;
343 stats.reprecv++;
349 if (events[i].events & (EPOLLRDHUP | EPOLLHUP)) //socket closed, delete and create a new one
351 // socket is closed, remove the socket from epoll and create a new one
352 epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
354 if(close(events[i].data.fd)!=0)
356 perror("close");
357 continue;
359 else
360 stats.nbsock--;
362 if(create_and_connect(target, (int *) epfd) != 0)
364 perror("create and connect");
365 continue;
367 else
368 stats.nbsock++;
370 if (events[i].events & EPOLLERR)
372 perror("epoll");
373 continue;
376 } while(!stop);
378 gettimeofday(&current, NULL);
380 elapsedtime = (current.tv_sec * 1000000 + current.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec);
382 printf("\n\nTime: %4.6f\nRequests sent: %d\nBytes sent: %d\nReponses received: %d\nBytes received: %d\nRates out: %4.6freq/s, %4.6fbytes/s\nRates in : %4.6frep/s, %4.6fbytes/s\nErrors: %d\n", elapsedtime/1000000, stats.reqsent, stats.bytessent, stats.reprecv, stats.bytesrecv, stats.reqsent/(elapsedtime/1000000), stats.bytessent/(elapsedtime/1000000), stats.reprecv/(elapsedtime/1000000), stats.bytesrecv/(elapsedtime/1000000), stats.error);
384 return 0;