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
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
15 #include <sys/epoll.h>
22 /* catch SIGINT and set stop to signal_id
25 void interrupt(int signal_id
)
30 // init struct for statistics
41 void printstats(struct statistics
*stats
)
43 struct statistics previous
;
48 printf("\nreprecv\tbytes\t^hit\treqsent\tbytes\t^req\tErrors\tActive\n");
55 printf("\nreprecv\tbytes\t^hit\treqsent\tbytes\t^req\tErrors\tActive\n");
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
;
78 bzero(&sa
, sizeof(sa
));
80 if ((c
=strrchr(str
,':')) != NULL
) {
87 if (!inet_aton(str
, &sa
.sin_addr
)) {
90 if ((he
= gethostbyname(str
)) == NULL
)
91 fprintf(stderr
,"[NetTools] Invalid server name: %s\n",str
);
93 sa
.sin_addr
= *(struct in_addr
*) *(he
->h_addr_list
);
95 sa
.sin_port
=htons(port
);
96 sa
.sin_family
=AF_INET
;
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
)
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)
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");
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
134 perror("connect is EAGAIN");
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");
173 /* reading waiting errors on the socket
174 * return 0 if there's no, 1 otherwise
176 int socket_check(int fd
)
180 size_t len
= sizeof(int);
182 ret
= getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &code
, &len
);
184 if ((ret
|| code
)!= 0)
193 int main(int argc
, char *argv
[])
198 printf("gatlinject <ip:port> <num socket>\n");
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
);
212 int buffersize
= strlen(buffer
);
214 struct statistics stats
;
215 memset(&stats
,0x0,6 * sizeof(int));
216 pthread_t Statsthread
;
220 struct timeval start
;
221 struct timeval current
;
224 // catch SIGINT to exit in a clean way
226 memset(&sa
, 0, sizeof(struct sigaction
*));
227 sa
.sa_handler
= interrupt
;
229 sigemptyset (&(sa
.sa_mask
));
230 if(sigaction (SIGINT
, &sa
, NULL
)!= 0)
232 perror("sigaction failed");
236 // the epoll file descriptor
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");
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");
263 // start the thread that prints the statistics
264 if( 0!= pthread_create (&Statsthread
, NULL
, (void *)printstats
, &stats
) ){
265 perror("stats thread");
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);
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");
295 if((datacount
= send(events
[i
].data
.fd
, message
, messagelength
, 0)) < 0)
298 perror("send failed");
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");
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");
332 memset(buffer
,0x0,buffersize
);
334 if((datacount
= recv(events
[i
].data
.fd
, buffer
, buffersize
, 0)) < 0)
337 perror("recv failed");
342 stats
.bytesrecv
+= datacount
;
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)
362 if(create_and_connect(target
, (int *) epfd
) != 0)
364 perror("create and connect");
370 if (events
[i
].events
& EPOLLERR
)
378 gettimeofday(¤t
, 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
);