• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  EpollTest by Davide Libenzi ( Epoll functionality tester )
3  *  Copyright (C) 2003  Davide Libenzi
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Davide Libenzi <davidel@xmailserver.org>
20  *
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <limits.h>
32 #include <ctype.h>
33 #include <time.h>
34 #include <errno.h>
35 #include <signal.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <sys/socket.h>
40 #include <sched.h>
41 #include <sys/file.h>
42 #include <sys/ioctl.h>
43 #include <sys/mman.h>
44 #include <sys/select.h>
45 #include <sys/wait.h>
46 #include <netinet/in.h>
47 #include <netinet/tcp.h>
48 #include <arpa/inet.h>
49 #include <arpa/nameser.h>
50 #include <netdb.h>
51 #include <syslog.h>
52 #include <glob.h>
53 #include <semaphore.h>
54 
55 /*
56  * You need the Portable Coroutine Library (PCL) to build this source.
57  * You can find a copy of PCL source code at :
58  *
59  *             http://www.xmailserver.org/libpcl.html
60  */
61 #include <pcl.h>
62 
63 #include "epoll.h"
64 #include "dbllist.h"
65 
66 #define CO_STD_STACK_SIZE		(2 * 4096)
67 #define STD_SCHED_TIMEOUT		1000
68 /* you might need to increase "net.ipv4.tcp_max_syn_backlog" to use this value */
69 #define STD_LISTEN_SIZE			2048
70 #define DATA_BUFFER_SIZE		2048
71 #define MIN_AHEAD_SPACE			(DATA_BUFFER_SIZE / 12)
72 #define STD_MESSAGE_SIZE		128
73 #define STD_SERVER_PORT			8080
74 #define MAX_DEFAULT_FDS			20000
75 
76 struct eph_conn {
77 	struct list_head lnk;
78 	int sfd;
79 	unsigned int events, revents;
80 	coroutine_t co;
81 	int nbytes, rindex;
82 	char buffer[DATA_BUFFER_SIZE];
83 };
84 
85 static int kdpfd;
86 static struct list_head close_list;
87 static struct epoll_event *events;
88 static int maxfds, numfds = 0;
89 static int chash_size;
90 static struct list_head *chash;
91 static int msgsize = STD_MESSAGE_SIZE, port = STD_SERVER_PORT,
92     maxsfd = MAX_DEFAULT_FDS, stksize = CO_STD_STACK_SIZE;
93 struct sockaddr_in saddr;
94 static volatile unsigned long httpresp = 0;
95 static int nreqsess = 1;
96 static char httpreq[512] = "";
97 
eph_socket(int domain,int type,int protocol)98 int eph_socket(int domain, int type, int protocol)
99 {
100 	int sfd = socket(domain, type, protocol), flags = 1;
101 
102 	if (sfd == -1)
103 		return -1;
104 	if (ioctl(sfd, FIONBIO, &flags) &&
105 	    ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
106 	     fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0)) {
107 		close(sfd);
108 		return -1;
109 	}
110 	return sfd;
111 }
112 
eph_close(int sfd)113 int eph_close(int sfd)
114 {
115 	close(sfd);
116 	return 0;
117 }
118 
eph_new_conn(int sfd,void * func)119 static int eph_new_conn(int sfd, void *func)
120 {
121 	struct eph_conn *conn = malloc(sizeof(struct eph_conn));
122 	struct epoll_event ev;
123 
124 	if (!conn)
125 		return -1;
126 
127 	memset(conn, 0, sizeof(*conn));
128 	DBL_INIT_LIST_HEAD(&conn->lnk);
129 	conn->sfd = sfd;
130 	conn->events = 0;
131 	conn->revents = 0;
132 	conn->nbytes = conn->rindex = 0;
133 	if (!(conn->co = co_create(func, conn, NULL, stksize))) {
134 		free(conn);
135 		return -1;
136 	}
137 
138 	DBL_LIST_ADDT(&conn->lnk, &chash[sfd % chash_size]);
139 
140 	ev.events = 0;
141 	ev.data.ptr = conn;
142 	if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, sfd, &ev) < 0) {
143 		fprintf(stderr, "epoll set insertion error: fd=%d\n", sfd);
144 
145 		DBL_LIST_DEL(&conn->lnk);
146 		co_delete(conn->co);
147 		free(conn);
148 		return -1;
149 	}
150 
151 	++numfds;
152 
153 	co_call(conn->co);
154 
155 	return 0;
156 }
157 
eph_exit_conn(struct eph_conn * conn)158 static void eph_exit_conn(struct eph_conn *conn)
159 {
160 	struct epoll_event ev;
161 
162 	if (epoll_ctl(kdpfd, EPOLL_CTL_DEL, conn->sfd, &ev) < 0) {
163 		fprintf(stderr, "epoll set deletion error: fd=%d\n", conn->sfd);
164 
165 	}
166 
167 	DBL_LIST_DEL(&conn->lnk);
168 	DBL_LIST_ADDT(&conn->lnk, &close_list);
169 
170 	eph_close(conn->sfd);
171 	conn->sfd = -1;
172 
173 	--numfds;
174 
175 	co_exit();
176 }
177 
eph_free_conns(void)178 static void eph_free_conns(void)
179 {
180 	struct eph_conn *conn;
181 
182 	while (!DBL_LIST_EMTPY(&close_list)) {
183 		conn = DBL_LIST_ENTRY(close_list.pNext, struct eph_conn, lnk);
184 
185 		DBL_LIST_DEL(&conn->lnk);
186 		free(conn);
187 	}
188 }
189 
eph_mod_conn(struct eph_conn * conn,unsigned int events)190 static int eph_mod_conn(struct eph_conn *conn, unsigned int events)
191 {
192 	struct epoll_event ev;
193 
194 	ev.events = events;
195 	ev.data.ptr = conn;
196 	if (epoll_ctl(kdpfd, EPOLL_CTL_MOD, conn->sfd, &ev) < 0) {
197 		fprintf(stderr, "epoll set modify error: fd=%d\n", conn->sfd);
198 		return -1;
199 	}
200 	return 0;
201 }
202 
eph_connect(struct eph_conn * conn,const struct sockaddr * serv_addr,socklen_t addrlen)203 int eph_connect(struct eph_conn *conn, const struct sockaddr *serv_addr,
204 		socklen_t addrlen)
205 {
206 
207 	if (connect(conn->sfd, serv_addr, addrlen) == -1) {
208 		if (errno != EWOULDBLOCK && errno != EINPROGRESS)
209 			return -1;
210 		if (!(conn->events & EPOLLOUT)) {
211 			conn->events = EPOLLOUT | EPOLLERR | EPOLLHUP;
212 			if (eph_mod_conn(conn, conn->events) < 0)
213 				return -1;
214 		}
215 		co_resume();
216 		if (conn->revents & (EPOLLERR | EPOLLHUP))
217 			return -1;
218 	}
219 	return 0;
220 }
221 
eph_read(struct eph_conn * conn,char * buf,int nbyte)222 int eph_read(struct eph_conn *conn, char *buf, int nbyte)
223 {
224 	int n;
225 
226 	while ((n = read(conn->sfd, buf, nbyte)) < 0) {
227 		if (errno == EINTR)
228 			continue;
229 		if (errno != EAGAIN && errno != EWOULDBLOCK)
230 			return -1;
231 		if (!(conn->events & EPOLLIN)) {
232 			conn->events = EPOLLIN | EPOLLERR | EPOLLHUP;
233 			if (eph_mod_conn(conn, conn->events) < 0)
234 				return -1;
235 		}
236 		co_resume();
237 	}
238 	return n;
239 }
240 
eph_write(struct eph_conn * conn,char const * buf,int nbyte)241 int eph_write(struct eph_conn *conn, char const *buf, int nbyte)
242 {
243 	int n;
244 
245 	while ((n = write(conn->sfd, buf, nbyte)) < 0) {
246 		if (errno == EINTR)
247 			continue;
248 		if (errno != EAGAIN && errno != EWOULDBLOCK)
249 			return -1;
250 		if (!(conn->events & EPOLLOUT)) {
251 			conn->events = EPOLLOUT | EPOLLERR | EPOLLHUP;
252 			if (eph_mod_conn(conn, conn->events) < 0)
253 				return -1;
254 		}
255 		co_resume();
256 	}
257 	return n;
258 }
259 
eph_accept(struct eph_conn * conn,struct sockaddr * addr,int * addrlen)260 int eph_accept(struct eph_conn *conn, struct sockaddr *addr, int *addrlen)
261 {
262 	int sfd, flags = 1;
263 
264 	while ((sfd = accept(conn->sfd, addr, (socklen_t *) addrlen)) < 0) {
265 		if (errno == EINTR)
266 			continue;
267 		if (errno != EAGAIN && errno != EWOULDBLOCK)
268 			return -1;
269 		if (!(conn->events & EPOLLIN)) {
270 			conn->events = EPOLLIN | EPOLLERR | EPOLLHUP;
271 			if (eph_mod_conn(conn, conn->events) < 0)
272 				return -1;
273 		}
274 		co_resume();
275 	}
276 	if (ioctl(sfd, FIONBIO, &flags) &&
277 	    ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
278 	     fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0)) {
279 		close(sfd);
280 		return -1;
281 	}
282 	return sfd;
283 }
284 
eph_create_conn(int domain,int type,int protocol,void * func)285 static int eph_create_conn(int domain, int type, int protocol, void *func)
286 {
287 	int sfd = eph_socket(domain, type, protocol);
288 
289 	return sfd != -1 ? eph_new_conn(sfd, func) : -1;
290 }
291 
eph_read_data(struct eph_conn * conn)292 static int eph_read_data(struct eph_conn *conn)
293 {
294 	int nbytes;
295 
296 	if (conn->rindex && conn->rindex < conn->nbytes) {
297 		memmove(conn->buffer, conn->buffer + conn->rindex,
298 			conn->nbytes - conn->rindex);
299 		conn->nbytes -= conn->rindex;
300 	} else
301 		conn->nbytes = 0;
302 
303 	conn->rindex = 0;
304 
305 	if ((nbytes = eph_read(conn, conn->buffer + conn->nbytes,
306 			       sizeof(conn->buffer) - conn->nbytes)) <= 0)
307 		return -1;
308 
309 	conn->nbytes += nbytes;
310 
311 	return 0;
312 }
313 
eph_write_data(struct eph_conn * conn,char const * buf,int nbyte)314 static int eph_write_data(struct eph_conn *conn, char const *buf, int nbyte)
315 {
316 	int wbytes, wcurr;
317 
318 	for (wbytes = 0; wbytes < nbyte;) {
319 		if ((wcurr = eph_write(conn, buf + wbytes, nbyte - wbytes)) < 0)
320 			break;
321 		wbytes += wcurr;
322 	}
323 
324 	return wbytes;
325 }
326 
eph_read_line(struct eph_conn * conn)327 static char *eph_read_line(struct eph_conn *conn)
328 {
329 	char *nline, *line;
330 
331 	for (;;) {
332 		if (conn->nbytes > conn->rindex) {
333 			if ((nline = memchr(conn->buffer + conn->rindex, '\n',
334 					    conn->nbytes - conn->rindex))) {
335 				line = conn->buffer + conn->rindex;
336 				conn->rindex += (nline - line) + 1;
337 				for (; nline > line && nline[-1] == '\r';
338 				     nline--) ;
339 				*nline = '\0';
340 				return line;
341 			}
342 		}
343 		if (eph_read_data(conn) < 0)
344 			break;
345 	}
346 	return NULL;
347 }
348 
eph_parse_request(struct eph_conn * conn)349 static int eph_parse_request(struct eph_conn *conn)
350 {
351 	char *line;
352 
353 	if (!(line = eph_read_line(conn)))
354 		return -1;
355 
356 	for (;;) {
357 		if (!(line = eph_read_line(conn)))
358 			return -1;
359 
360 		if (*line == '\0')
361 			break;
362 	}
363 
364 	return 0;
365 }
366 
eph_send_response(struct eph_conn * conn)367 static int eph_send_response(struct eph_conn *conn)
368 {
369 	static int resplen = -1;
370 	static char *resp = NULL;
371 
372 	if (resp == NULL) {
373 		msgsize = ((msgsize + 63) / 64) * 64;
374 
375 		resp = malloc(msgsize + 256);
376 
377 		sprintf(resp,
378 			"HTTP/1.1 200 OK\r\n"
379 			"Server: dp server\r\n"
380 			"Content-Type: text/plain\r\n"
381 			"Content-Length: %d\r\n" "\r\n", msgsize);
382 
383 		while (msgsize > 0) {
384 			strcat(resp,
385 			       "01234567890123\r\n"
386 			       "01234567890123\r\n"
387 			       "01234567890123\r\n" "01234567890123\r\n");
388 			msgsize -= 64;
389 		}
390 
391 		resplen = strlen(resp);
392 	}
393 
394 	if (eph_write_data(conn, resp, resplen) != resplen)
395 		return -1;
396 
397 	return 0;
398 }
399 
eph_httpd(void * data)400 static void *eph_httpd(void *data)
401 {
402 	struct eph_conn *conn = (struct eph_conn *)data;
403 
404 	while (eph_parse_request(conn) == 0) {
405 		eph_send_response(conn);
406 
407 	}
408 
409 	eph_exit_conn(conn);
410 	return data;
411 }
412 
eph_acceptor(void * data)413 static void *eph_acceptor(void *data)
414 {
415 	struct eph_conn *conn = (struct eph_conn *)data;
416 	struct sockaddr_in addr;
417 	int sfd, addrlen = sizeof(addr);
418 
419 	while ((sfd =
420 		eph_accept(conn, (struct sockaddr *)&addr, &addrlen)) != -1) {
421 		if (eph_new_conn(sfd, eph_httpd) < 0) {
422 			eph_close(sfd);
423 
424 		}
425 	}
426 	eph_exit_conn(conn);
427 	return data;
428 }
429 
eph_find(int sfd)430 static struct eph_conn *eph_find(int sfd)
431 {
432 	struct list_head *head = &chash[sfd % chash_size], *lnk;
433 	struct eph_conn *conn;
434 
435 	DBL_LIST_FOR_EACH(lnk, head) {
436 		conn = DBL_LIST_ENTRY(lnk, struct eph_conn, lnk);
437 
438 		if (conn->sfd == sfd)
439 			return conn;
440 	}
441 	return NULL;
442 }
443 
eph_runqueue(void)444 static int eph_runqueue(void)
445 {
446 	int i;
447 	struct list_head *head, *lnk;
448 	struct eph_conn *conn;
449 
450 	for (i = 0; i < chash_size; i++) {
451 		head = &chash[i];
452 		for (lnk = head->pNext; lnk != head;) {
453 			conn = DBL_LIST_ENTRY(lnk, struct eph_conn, lnk);
454 
455 			lnk = lnk->pNext;
456 			co_call(conn->co);
457 		}
458 	}
459 	return 0;
460 }
461 
eph_mstics(void)462 unsigned long long eph_mstics(void)
463 {
464 
465 	struct timeval tv;
466 
467 	if (gettimeofday(&tv, NULL) != 0)
468 		return (0);
469 
470 	return (1000 * (unsigned long long)tv.tv_sec +
471 		(unsigned long long)tv.tv_usec / 1000);
472 
473 }
474 
eph_init(void)475 int eph_init(void)
476 {
477 	int i;
478 
479 	if (!
480 	    (events = malloc(maxsfd * sizeof(struct epoll_event)))) {
481 		perror("malloc()");
482 		return -1;
483 	}
484 
485 	if ((kdpfd = epoll_create(maxsfd)) < 0) {
486 		perror("epoll_create");
487 		return -1;
488 	}
489 
490 	if (!
491 	    (chash = malloc(maxsfd * sizeof(struct list_head)))) {
492 		perror("malloc()");
493 		free(events);
494 		close(kdpfd);
495 		return -1;
496 	}
497 
498 	maxfds = maxsfd;
499 	chash_size = maxfds;
500 	for (i = 0; i < maxfds; i++)
501 		DBL_INIT_LIST_HEAD(&chash[i]);
502 
503 	DBL_INIT_LIST_HEAD(&close_list);
504 
505 	return 0;
506 }
507 
eph_cleanup(void)508 int eph_cleanup(void)
509 {
510 
511 	free(events);
512 	free(chash);
513 	close(kdpfd);
514 	return 0;
515 }
516 
eph_scheduler(int loop,unsigned int timeout)517 static int eph_scheduler(int loop, unsigned int timeout)
518 {
519 	int i, nfds;
520 	struct eph_conn *conn;
521 	struct epoll_event *cevents;
522 
523 	do {
524 		nfds = epoll_wait(kdpfd, events, maxfds, timeout);
525 
526 		for (i = 0, cevents = events; i < nfds; i++, cevents++) {
527 			conn = cevents->data.ptr;
528 			if (conn->sfd != -1) {
529 				conn->revents = cevents->events;
530 
531 				if (conn->revents & conn->events)
532 					co_call(conn->co);
533 			}
534 		}
535 #if 0
536 		if (nfds <= 0)
537 			eph_runqueue();
538 #endif
539 		eph_free_conns();
540 	} while (loop);
541 
542 	return 0;
543 }
544 
545 #if defined(DPHTTPD)
546 
eph_usage(char const * prgname)547 void eph_usage(char const *prgname)
548 {
549 
550 	fprintf(stderr,
551 		"use: %s [--msgsize nbytes (%d)] [--port nbr (%d)] [--maxfds nfds (%d)]\n\t[--stksize bytes (%d)]\n",
552 		prgname, msgsize, port, maxsfd, stksize);
553 
554 }
555 
main(int argc,char * argv[])556 int main(int argc, char *argv[])
557 {
558 	int i, sfd, flags = 1;
559 	struct linger ling = { 0, 0 };
560 	struct sockaddr_in addr;
561 
562 	for (i = 1; i < argc; i++) {
563 		if (strcmp(argv[i], "--msgsize") == 0) {
564 			if (++i < argc)
565 				msgsize = atoi(argv[i]);
566 			continue;
567 		}
568 		if (strcmp(argv[i], "--port") == 0) {
569 			if (++i < argc)
570 				port = atoi(argv[i]);
571 			continue;
572 		}
573 		if (strcmp(argv[i], "--maxfds") == 0) {
574 			if (++i < argc)
575 				maxsfd = atoi(argv[i]);
576 			continue;
577 		}
578 		if (strcmp(argv[i], "--stksize") == 0) {
579 			if (++i < argc)
580 				stksize = atoi(argv[i]);
581 			continue;
582 		}
583 
584 		eph_usage(argv[0]);
585 		return 1;
586 	}
587 
588 	if (eph_init() == -1) {
589 
590 		return 2;
591 	}
592 
593 	if ((sfd = eph_socket(AF_INET, SOCK_STREAM, 0)) == -1) {
594 
595 		eph_cleanup();
596 		return 3;
597 	}
598 
599 	setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
600 	setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
601 	setsockopt(sfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
602 
603 	addr.sin_family = AF_INET;
604 	addr.sin_port = htons(port);
605 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
606 	if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
607 
608 		eph_close(sfd);
609 		eph_cleanup();
610 		return 4;
611 	}
612 
613 	listen(sfd, STD_LISTEN_SIZE);
614 
615 	if (eph_new_conn(sfd, (void *)eph_acceptor) == -1) {
616 
617 		eph_close(sfd);
618 		eph_cleanup();
619 		return 5;
620 	}
621 
622 	do {
623 		eph_scheduler(0, STD_SCHED_TIMEOUT);
624 	} while (numfds);
625 
626 	eph_cleanup();
627 	return 0;
628 }
629 
630 #endif /* #if defined(DPHTTPD) */
631 
632 #if defined(HTTP_BLASTER)
633 
eph_http_session(void * data)634 static void *eph_http_session(void *data)
635 {
636 	int i, rlen = strlen(httpreq), ava;
637 	struct eph_conn *conn = (struct eph_conn *)data;
638 
639 	if (eph_connect(conn, (struct sockaddr *)&saddr, sizeof(saddr)) == 0) {
640 		for (i = 0; i < nreqsess; i++) {
641 			if (eph_write_data(conn, httpreq, rlen) == rlen) {
642 				static char const *clent = "Content-Length:";
643 				int length = -1, clens = strlen(clent);
644 				char *line;
645 				static char buf[2048];
646 
647 				while ((line = eph_read_line(conn))) {
648 					if (*line == '\0')
649 						break;
650 					if (strncasecmp(line, clent, clens) ==
651 					    0) {
652 						for (line += clens;
653 						     *line == ' '; line++) ;
654 						length = atoi(line);
655 					}
656 				}
657 				if (length < 0)
658 					goto sess_out;
659 				if ((ava = conn->nbytes - conn->rindex) > 0) {
660 					if (ava > length)
661 						ava = length;
662 					length -= ava;
663 					conn->rindex += ava;
664 				}
665 				++httpresp;
666 				while (length > 0) {
667 					int rsiz =
668 					    length >
669 					    sizeof(buf) ? sizeof(buf) : length;
670 
671 					if ((rsiz =
672 					     eph_read(conn, buf, rsiz)) <= 0)
673 						goto sess_out;
674 					length -= rsiz;
675 				}
676 			} else
677 				goto sess_out;
678 		}
679 	}
680 sess_out:
681 	eph_exit_conn(conn);
682 	return data;
683 }
684 
eph_usage(char const * prgname)685 void eph_usage(char const *prgname)
686 {
687 
688 	fprintf(stderr,
689 		"use: %s  --server serv	 --port nprt  --numconns ncon  [--nreq nreq (%d)]\n"
690 		"[--maxconns ncon] [--url url ('/')] [--stksize bytes (%d)]\n",
691 		prgname, nreqsess, stksize);
692 
693 }
694 
main(int argc,char * argv[])695 int main(int argc, char *argv[])
696 {
697 	int i, nconns = 0, totconns = 0, maxconns = 0;
698 	unsigned long resplast;
699 	unsigned long long tinit, tlast, tcurr;
700 	struct hostent *he;
701 	char const *server = NULL, *url = "/";
702 	struct in_addr inadr;
703 
704 	for (i = 1; i < argc; i++) {
705 		if (strcmp(argv[i], "--server") == 0) {
706 			if (++i < argc)
707 				server = argv[i];
708 			continue;
709 		}
710 		if (strcmp(argv[i], "--port") == 0) {
711 			if (++i < argc)
712 				port = atoi(argv[i]);
713 			continue;
714 		}
715 		if (strcmp(argv[i], "--maxconns") == 0) {
716 			if (++i < argc)
717 				maxconns = atoi(argv[i]);
718 			continue;
719 		}
720 		if (strcmp(argv[i], "--numconns") == 0) {
721 			if (++i < argc) {
722 				nconns = atoi(argv[i]);
723 				if (nconns > maxsfd)
724 					maxsfd = nconns + nconns >> 1 + 1;
725 			}
726 			continue;
727 		}
728 		if (strcmp(argv[i], "--nreq") == 0) {
729 			if (++i < argc)
730 				nreqsess = atoi(argv[i]);
731 			continue;
732 		}
733 		if (strcmp(argv[i], "--url") == 0) {
734 			if (++i < argc)
735 				url = argv[i];
736 			continue;
737 		}
738 		if (strcmp(argv[i], "--stksize") == 0) {
739 			if (++i < argc)
740 				stksize = atoi(argv[i]);
741 			continue;
742 		}
743 
744 		eph_usage(argv[0]);
745 		return 1;
746 	}
747 
748 	if (!server || !nconns) {
749 		eph_usage(argv[0]);
750 		return 2;
751 	}
752 
753 	sprintf(httpreq,
754 		"GET %s HTTP/1.1\r\n"
755 		"Host: %s\r\n" "Connection: keepalive\r\n" "\r\n", url, server);
756 
757 	if (inet_aton(server, &inadr) == 0) {
758 		if ((he = gethostbyname(server)) == NULL) {
759 			fprintf(stderr, "unable to resolve: %s\n", server);
760 			return (-1);
761 		}
762 
763 		memcpy(&inadr.s_addr, he->h_addr_list[0], he->h_length);
764 	}
765 	saddr.sin_family = AF_INET;
766 	saddr.sin_port = htons(port);
767 	memcpy(&saddr.sin_addr, &inadr.s_addr, 4);
768 
769 	if (eph_init() == -1) {
770 
771 		return 2;
772 	}
773 
774 	resplast = 0;
775 	tinit = tlast = eph_mstics();
776 
777 	for (; numfds || (!maxconns || totconns < maxconns);) {
778 		int nfds = numfds, errs = 0, diffconns = nconns - numfds;
779 
780 		while (numfds < nconns && (!maxconns || totconns < maxconns)) {
781 			eph_create_conn(AF_INET, SOCK_STREAM, 0,
782 					eph_http_session);
783 			if (nfds == numfds) {
784 				++errs;
785 				if (errs > 32) {
786 					fprintf(stderr,
787 						"unable to connect: server=%s errors=%d\n",
788 						server, errs);
789 					goto main_exit;
790 				}
791 			} else
792 				++totconns;
793 			nfds = numfds;
794 		}
795 
796 		eph_scheduler(0, STD_SCHED_TIMEOUT);
797 
798 		tcurr = eph_mstics();
799 		if ((tcurr - tlast) >= 1000) {
800 			printf
801 			    ("rate = %lu  avg = %lu  totconns = %d  diff = %d  resp = %ld  nfds = %d\n",
802 			     (unsigned long)((1000 * (httpresp - resplast)) /
803 					     (tcurr - tlast)),
804 			     (unsigned long)((1000 * httpresp) /
805 					     (tcurr - tinit)), totconns,
806 			     diffconns, httpresp, numfds);
807 
808 			tlast = tcurr;
809 			resplast = httpresp;
810 		}
811 	}
812 
813 main_exit:
814 	eph_cleanup();
815 	return 0;
816 }
817 
818 #endif /* #if defined(HTTP_BLASTER) */
819 
820 #if defined(PIPETESTER)
821 
eph_createcgi(char ** args,void * func)822 int eph_createcgi(char **args, void *func)
823 {
824 	int fds[2], flags = 1;
825 	pid_t chpid;
826 
827 	if (pipe(fds)) {
828 		perror("pipe");
829 		return -1;
830 	}
831 	chpid = fork();
832 	if (chpid == -1) {
833 		perror("fork");
834 		close(fds[0]), close(fds[1]);
835 		return -1;
836 	} else if (chpid == 0) {
837 		close(fds[0]);
838 		dup2(fds[1], 1);
839 		close(fds[1]);
840 		execvp(args[0], args);
841 		perror("exec");
842 		exit(1);
843 	}
844 	close(fds[1]);
845 	if (ioctl(fds[0], FIONBIO, &flags) &&
846 	    ((flags = fcntl(fds[0], F_GETFL, 0)) < 0 ||
847 	     fcntl(fds[0], F_SETFL, flags | O_NONBLOCK) < 0)) {
848 		close(fds[0]);
849 		return -1;
850 	}
851 	fprintf(stdout, "child-run=%d  fd=%d\n", chpid, fds[0]), fflush(stdout);
852 	return eph_new_conn(fds[0], func);
853 }
854 
eph_createpipetest(int size,int tsleep,int ttime,void * func)855 int eph_createpipetest(int size, int tsleep, int ttime, void *func)
856 {
857 	int fds[2], flags = 1;
858 	pid_t chpid;
859 
860 	if (pipe(fds)) {
861 		perror("pipe");
862 		return -1;
863 	}
864 	chpid = fork();
865 	if (chpid == -1) {
866 		perror("fork");
867 		close(fds[0]), close(fds[1]);
868 		return -1;
869 	} else if (chpid == 0) {
870 		int i;
871 		char *buff = malloc(size + 1);
872 		close(fds[0]);
873 		dup2(fds[1], 1);
874 		close(fds[1]);
875 
876 		srand(getpid() * time(NULL));
877 		for (i = 0; i < (size - 1); i++) {
878 			if (i && !(i % 64))
879 				buff[i] = '\n';
880 			else
881 				buff[i] = '0' + (rand() % 10);
882 		}
883 		buff[i++] = '\n';
884 		buff[i] = '\0';
885 		ttime += (ttime * rand()) / RAND_MAX - (ttime >> 1);
886 		ttime *= 1000;
887 		while (ttime > 0) {
888 			usleep(tsleep * 1000);
889 			fputs(buff, stdout), fflush(stdout);
890 			ttime -= tsleep;
891 		}
892 		free(buff);
893 		exit(0);
894 	}
895 	close(fds[1]);
896 	if (ioctl(fds[0], FIONBIO, &flags) &&
897 	    ((flags = fcntl(fds[0], F_GETFL, 0)) < 0 ||
898 	     fcntl(fds[0], F_SETFL, flags | O_NONBLOCK) < 0)) {
899 		close(fds[0]);
900 		return -1;
901 	}
902 	fprintf(stdout, "child-run=%d  fd=%d\n", chpid, fds[0]), fflush(stdout);
903 	return eph_new_conn(fds[0], func);
904 }
905 
eph_pipe_session(void * data)906 static void *eph_pipe_session(void *data)
907 {
908 	struct eph_conn *conn = (struct eph_conn *)data;
909 	int nbytes, totbytes = 0;
910 	char buff[257];
911 
912 	while ((nbytes = eph_read(conn, buff, sizeof(buff))) > 0) {
913 		fprintf(stdout, "[%p] %d bytes readed\n", conn, nbytes),
914 		    fflush(stdout);
915 		totbytes += nbytes;
916 	}
917 	fprintf(stdout, "[%p] exit - totbytes=%d\n", conn, totbytes),
918 	    fflush(stdout);
919 	eph_exit_conn(conn);
920 	return data;
921 }
922 
eph_sigchld(int sig)923 void eph_sigchld(int sig)
924 {
925 	int status;
926 	pid_t pid;
927 
928 	while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
929 		fprintf(stdout, "child-dead=%d\n", pid), fflush(stdout);
930 	}
931 	signal(SIGCHLD, eph_sigchld);
932 }
933 
eph_usage(char const * prgname)934 void eph_usage(char const *prgname)
935 {
936 
937 	fprintf(stderr,
938 		"use: %s  [--ncgis ncgi]  [--cgi cgi] [--stksize bytes (%d)]\n",
939 		prgname, stksize);
940 
941 }
942 
main(int argc,char * argv[])943 int main(int argc, char *argv[])
944 {
945 	int i, ncgis = 8;
946 	char *cgi = NULL;
947 	char *args[16];
948 
949 	for (i = 1; i < argc; i++) {
950 		if (strcmp(argv[i], "--ncgis") == 0) {
951 			if (++i < argc)
952 				ncgis = atoi(argv[i]);
953 			continue;
954 		}
955 		if (strcmp(argv[i], "--cgi") == 0) {
956 			if (++i < argc)
957 				cgi = argv[i];
958 			continue;
959 		}
960 		if (strcmp(argv[i], "--stksize") == 0) {
961 			if (++i < argc)
962 				stksize = atoi(argv[i]);
963 			continue;
964 		}
965 
966 		eph_usage(argv[0]);
967 		return 1;
968 	}
969 
970 	signal(SIGCHLD, eph_sigchld);
971 	signal(SIGPIPE, SIG_IGN);
972 
973 	if (eph_init() == -1) {
974 
975 		return 2;
976 	}
977 
978 	if (cgi) {
979 		args[0] = cgi;
980 		args[1] = NULL;
981 
982 		for (i = 0; i < ncgis; i++)
983 			eph_createcgi(args, eph_pipe_session);
984 	} else {
985 		for (i = 0; i < ncgis; i++)
986 			eph_createpipetest(256, 250, 8, eph_pipe_session);
987 	}
988 
989 	while (numfds > 0)
990 		eph_scheduler(0, STD_SCHED_TIMEOUT);
991 
992 	eph_cleanup();
993 	return 0;
994 }
995 
996 #endif /* #if defined(PIPETESTER) */
997