"Fossies" - the Fresh Open Source Software Archive 
Member "httperf-0.9.0/src/core.c" (7 Apr 2007, 29565 Bytes) of package /linux/www/old/httperf-0.9.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "core.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 httperf -- a tool for measuring web server performance
3 Copyright 2000-2007 Hewlett-Packard Company and Contributors listed in
4 AUTHORS file. Originally contributed by David Mosberger-Tang
5
6 This file is part of httperf, a web server performance measurment
7 tool.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 In addition, as a special exception, the copyright holders give
15 permission to link the code of this work with the OpenSSL project's
16 "OpenSSL" library (or with modified versions of it that use the same
17 license as the "OpenSSL" library), and distribute linked combinations
18 including the two. You must obey the GNU General Public License in
19 all respects for all of the code used other than "OpenSSL". If you
20 modify this file, you may extend this exception to your version of the
21 file, but you are not obligated to do so. If you do not wish to do
22 so, delete this exception statement from your version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 02110-1301, USA
33 */
34
35 #include "config.h"
36
37 #include <assert.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <netdb.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include <sys/ioctl.h>
49 #include <sys/socket.h>
50 #include <sys/time.h>
51 #include <sys/types.h>
52 #include <sys/resource.h> /* grrr, must come after sys/types.h for BSD */
53 #ifdef HAVE_SYS_SELECT_H
54 #include <sys/select.h>
55 #endif
56
57 #include <netinet/in.h>
58 #include <netinet/tcp.h>
59 #include <arpa/inet.h>
60
61 #include <httperf.h>
62 #include <call.h>
63 #include <core.h>
64 #include <event.h>
65 #include <http.h>
66 #include <conn.h>
67
68 /*if we don't have GNU compatible realloc, fake it*/
69 #if HAVE_REALLOC == 0
70 void *rpl_realloc(void *ptr, size_t size)
71 {
72 if (ptr == NULL && size == 0)
73 {
74 return NULL;
75 }
76
77 if (size == 0)
78 {
79 free(ptr);
80 return NULL;
81 }
82
83 if (ptr == NULL)
84 {
85 return malloc(size);
86 }
87
88 #undef realloc
89 return realloc(ptr, size);
90 #define realloc rpl_realloc
91 }
92 #endif
93
94 #define HASH_TABLE_SIZE 1024 /* can't have more than this many servers */
95 #define MIN_IP_PORT IPPORT_RESERVED
96 #define MAX_IP_PORT 65535
97 #define BITSPERLONG (8*sizeof (u_long))
98
99 static int running = 1;
100 static int iteration;
101 static u_long max_burst_len;
102 static fd_set rdfds, wrfds;
103 static int min_sd = 0x7fffffff, max_sd = 0, alloced_sd_to_conn = 0;
104 static struct timeval select_timeout;
105 static struct sockaddr_in myaddr;
106 Conn **sd_to_conn;
107 static u_long port_free_map[((MAX_IP_PORT - MIN_IP_PORT + BITSPERLONG)
108 / BITSPERLONG)];
109 static char http10req[] =
110 " HTTP/1.0\r\nUser-Agent: httperf/"VERSION \
111 "\r\nConnection: keep-alive\r\nHost: ";
112 static char http11req[] =
113 " HTTP/1.1\r\nUser-Agent: httperf/"VERSION"\r\nHost: ";
114
115 static char http10req_nohost[] =
116 " HTTP/1.0\r\nUser-Agent: httperf/"VERSION \
117 "\r\nConnection: keep-alive\r\n";
118 static char http11req_nohost[] =
119 " HTTP/1.1\r\nUser-Agent: httperf/"VERSION"\r\n";
120
121 #ifndef SOL_TCP
122 # define SOL_TCP 6 /* probably ought to do getprotlbyname () */
123 #endif
124
125 #ifdef TIME_SYSCALLS
126 # define SYSCALL(n,s) \
127 { \
128 Time start, stop; \
129 do \
130 { \
131 errno = 0; \
132 start = timer_now_forced (); \
133 s; /* execute the syscall */ \
134 stop = timer_now_forced (); \
135 syscall_time[SC_##n] += stop - start; \
136 ++syscall_count[SC_##n]; \
137 } \
138 while (errno == EINTR); \
139 }
140
141 enum Syscalls
142 {
143 SC_BIND, SC_CONNECT, SC_READ, SC_SELECT, SC_SOCKET, SC_WRITEV,
144 SC_SSL_READ, SC_SSL_WRITEV,
145 SC_NUM_SYSCALLS
146 };
147
148 static const char * const syscall_name[SC_NUM_SYSCALLS] =
149 {
150 "bind", "connct", "read", "select", "socket", "writev",
151 "ssl_read", "ssl_writev"
152 };
153 static Time syscall_time[SC_NUM_SYSCALLS];
154 static u_int syscall_count[SC_NUM_SYSCALLS];
155 #else
156 # define SYSCALL(n,s) \
157 { \
158 do \
159 { \
160 errno = 0; \
161 s; \
162 } \
163 while (errno == EINTR); \
164 }
165 #endif
166
167 struct hash_entry
168 {
169 const char *hostname;
170 int port;
171 struct sockaddr_in sin;
172 }
173 hash_table[HASH_TABLE_SIZE];
174
175 static int
176 hash_code (const char *server, size_t server_len, int port)
177 {
178 u_char *cp = (u_char *) server;
179 u_long h = port;
180 u_long g;
181 int ch;
182
183 /* Basically the ELF hash algorithm: */
184
185 while ((ch = *cp++) != '\0')
186 {
187 h = (h << 4) + ch;
188 if ((g = (h & 0xf0000000)) != 0)
189 {
190 h ^= g >> 24;
191 h &= ~g;
192 }
193 }
194 return h;
195 }
196
197 static struct hash_entry*
198 hash_enter (const char *server, size_t server_len, int port,
199 struct sockaddr_in *sin)
200 {
201 struct hash_entry *he;
202
203 int index = hash_code (server, server_len, port) % HASH_TABLE_SIZE;
204
205 while (hash_table[index].hostname)
206 {
207 ++index;
208 if (index >= HASH_TABLE_SIZE)
209 index = 0;
210 }
211 he = hash_table + index;
212 he->hostname = server;
213 he->port = port;
214 he->sin = *sin;
215 return he;
216 }
217
218 static struct sockaddr_in*
219 hash_lookup (const char *server, size_t server_len, int port)
220 {
221 int index, start_index;
222
223 index = start_index = hash_code (server, server_len, port) % HASH_TABLE_SIZE;
224 while (hash_table[index].hostname)
225 {
226 if (hash_table[index].port == port
227 && strcmp (hash_table[index].hostname, server) == 0)
228 return &hash_table[index].sin;
229
230 ++index;
231 if (index >= HASH_TABLE_SIZE)
232 index = 0;
233 if (index == start_index)
234 break;
235 }
236 return 0;
237 }
238
239 static int
240 lffs (long w)
241 {
242 int r;
243
244 if (sizeof (w) == sizeof (int))
245 r = ffs (w);
246 else
247 {
248 r = ffs (w);
249 #if SIZEOF_LONG > 4
250 if (r == 0)
251 {
252 r = ffs (w >> (8*sizeof (int)));
253 if (r > 0)
254 r += 8*sizeof (int);
255 }
256 #endif
257 }
258 return r;
259 }
260
261 static void
262 port_put (int port)
263 {
264 int i, bit;
265
266 port -= MIN_IP_PORT;
267 i = port / BITSPERLONG;
268 bit = port % BITSPERLONG;
269 port_free_map[i] |= (1UL << bit);
270 }
271
272 static int
273 port_get (void)
274 {
275 static u_long mask = ~0UL;
276 static int previous = 0;
277 int port, bit, i;
278
279 i = previous;
280 if ((port_free_map[i] & mask) == 0)
281 {
282 do
283 {
284 ++i;
285 if (i >= NELEMS (port_free_map))
286 i = 0;
287 if (i == previous)
288 {
289 if (DBG > 0)
290 fprintf (stderr,
291 "%s.port_get: Yikes! I'm out of port numbers!\n",
292 prog_name);
293 return -1;
294 }
295 }
296 while (port_free_map[i] == 0);
297 mask = ~0UL;
298 }
299 previous = i;
300
301 bit = lffs (port_free_map[i] & mask) - 1;
302 if (bit >= BITSPERLONG - 1)
303 mask = 0;
304 else
305 mask = ~((1UL << (bit + 1)) - 1);
306 port_free_map[i] &= ~(1UL << bit);
307 port = bit + i*BITSPERLONG + MIN_IP_PORT;
308 return port;
309 }
310
311 static void
312 conn_failure (Conn *s, int err)
313 {
314 Any_Type arg;
315
316 arg.l = err;
317 event_signal (EV_CONN_FAILED, (Object *) s, arg);
318
319 core_close (s);
320 }
321
322 static void
323 conn_timeout (Timer *t, Any_Type arg)
324 {
325 Conn *s = arg.vp;
326 Time now;
327 Call *c;
328
329 assert (object_is_conn (s));
330 s->watchdog = 0;
331
332 if (DBG > 0)
333 {
334 c = 0;
335 if (s->sd >= 0)
336 {
337 now = timer_now ();
338 if (FD_ISSET (s->sd, &rdfds)
339 && s->recvq && now >= s->recvq->timeout)
340 c = s->recvq;
341 else if (FD_ISSET (s->sd, &wrfds)
342 && s->sendq && now >= s->sendq->timeout)
343 c = s->sendq;
344 }
345 if (DBG > 0)
346 {
347 fprintf (stderr, "connection_timeout");
348 if (c)
349 fprintf (stderr, ".%lu", c->id);
350 fprintf (stderr, ": t=%p, connection=%p\n", t, s);
351 }
352 }
353
354 arg.l = 0;
355 event_signal (EV_CONN_TIMEOUT, (Object *) s, arg);
356
357 core_close (s);
358 }
359
360 static void
361 set_active (Conn *s, fd_set *fdset)
362 {
363 int sd = s->sd;
364 Any_Type arg;
365 Time timeout;
366
367 FD_SET (sd, fdset);
368 if (sd < min_sd)
369 min_sd = sd;
370 if (sd >= max_sd)
371 max_sd = sd;
372
373 if (s->watchdog)
374 return;
375
376 timeout = 0.0;
377 if (s->sendq)
378 timeout = s->sendq->timeout;
379 if (s->recvq && (timeout == 0.0 || timeout > s->recvq->timeout))
380 timeout = s->recvq->timeout;
381
382 if (timeout > 0.0)
383 {
384 arg.vp = s;
385 s->watchdog = timer_schedule (conn_timeout, arg,
386 timeout - timer_now ());
387 }
388 }
389
390 static void
391 do_send (Conn *conn)
392 {
393 int async_errno;
394 socklen_t len;
395 struct iovec *iovp;
396 int sd = conn->sd;
397 ssize_t nsent = 0;
398 Any_Type arg;
399 Call *call;
400
401 while (1)
402 {
403 call = conn->sendq;
404 assert (call);
405
406 arg.l = 0;
407 event_signal (EV_CALL_SEND_RAW_DATA, (Object *) call, arg);
408
409 #ifdef HAVE_SSL
410 if (param.use_ssl)
411 {
412 extern ssize_t SSL_writev (SSL *, const struct iovec *, int);
413 SYSCALL (SSL_WRITEV,
414 nsent = SSL_writev(conn->ssl,
415 call->req.iov + call->req.iov_index,
416 (NELEMS (call->req.iov)
417 - call->req.iov_index)));
418 }
419 else
420 #endif
421 {
422 SYSCALL (WRITEV,
423 nsent = writev (sd, call->req.iov + call->req.iov_index,
424 (NELEMS (call->req.iov)
425 - call->req.iov_index)));
426 }
427
428 if (DBG > 0)
429 fprintf (stderr, "do_send.%lu: wrote %ld bytes on %p\n", call->id,
430 (long) nsent, conn);
431
432 if (nsent < 0)
433 {
434 if (errno == EAGAIN)
435 return;
436
437 len = sizeof (async_errno);
438 if (getsockopt (sd, SOL_SOCKET, SO_ERROR, &async_errno, &len) == 0
439 && async_errno != 0)
440 errno = async_errno;
441
442 if (DBG > 0)
443 fprintf (stderr, "%s.do_send: writev() failed: %s\n",
444 prog_name, strerror (errno));
445
446 conn_failure (conn, errno);
447 return;
448 }
449
450 call->req.size += nsent;
451
452 iovp = call->req.iov + call->req.iov_index;
453 while (iovp < call->req.iov + NELEMS (call->req.iov))
454 {
455 if (nsent < iovp->iov_len)
456 {
457 iovp->iov_len -= nsent;
458 iovp->iov_base = (caddr_t) ((char *) iovp->iov_base + nsent);
459 break;
460 }
461 else
462 {
463 /* we're done with this fragment: */
464 nsent -= iovp->iov_len;
465 *iovp = call->req.iov_saved;
466 ++iovp;
467 call->req.iov_saved = *iovp;
468 }
469 }
470 call->req.iov_index = iovp - call->req.iov;
471 if (call->req.iov_index < NELEMS (call->req.iov))
472 {
473 /* there are more header bytes to write */
474 call->timeout = param.timeout ? timer_now () + param.timeout : 0.0;
475 set_active (conn, &wrfds);
476 return;
477 }
478
479 /* we're done with sending this request */
480 conn->sendq = call->sendq_next;
481 if (!conn->sendq)
482 {
483 conn->sendq_tail = 0;
484 FD_CLR (sd, &wrfds);
485 }
486 arg.l = 0;
487 event_signal (EV_CALL_SEND_STOP, (Object *) call, arg);
488 if (conn->state >= S_CLOSING)
489 {
490 call_dec_ref (call);
491 return;
492 }
493
494 /* get ready to receive matching reply (note that we implicitly
495 pass on the reference to the call from the sendq to the
496 recvq): */
497 call->recvq_next = 0;
498 if (!conn->recvq)
499 conn->recvq = conn->recvq_tail = call;
500 else
501 {
502 conn->recvq_tail->recvq_next = call;
503 conn->recvq_tail = call;
504 }
505 call->timeout = param.timeout + param.think_timeout;
506 if (call->timeout > 0.0)
507 call->timeout += timer_now ();
508 set_active (conn, &rdfds);
509 if (conn->state < S_REPLY_STATUS)
510 conn->state = S_REPLY_STATUS; /* expecting reply status */
511
512 if (!conn->sendq)
513 return;
514
515 arg.l = 0;
516 event_signal (EV_CALL_SEND_START, (Object *) conn->sendq, arg);
517 if (conn->state >= S_CLOSING)
518 return;
519 }
520 }
521
522 static void
523 recv_done (Call *call)
524 {
525 Conn *conn = call->conn;
526 Any_Type arg;
527
528 conn->recvq = call->recvq_next;
529 if (!conn->recvq)
530 {
531 FD_CLR (conn->sd, &rdfds);
532 conn->recvq_tail = 0;
533 }
534 /* we're done with receiving this request */
535 arg.l = 0;
536 event_signal (EV_CALL_RECV_STOP, (Object *) call, arg);
537
538 call_dec_ref (call);
539 }
540
541 static void
542 do_recv (Conn *s)
543 {
544 char *cp, buf[8193];
545 Call *c = s->recvq;
546 int i, saved_errno;
547 ssize_t nread = 0;
548 size_t buf_len;
549
550 assert (c);
551
552 #ifdef HAVE_SSL
553 if (param.use_ssl)
554 {
555 SYSCALL (SSL_READ,
556 nread = SSL_read (s->ssl, buf, sizeof (buf) - 1));
557 }
558 else
559 #endif
560 {
561 SYSCALL (READ,
562 nread = read (s->sd, buf, sizeof (buf) - 1));
563 }
564 saved_errno = errno;
565 if (nread <= 0)
566 {
567 if (DBG > 0)
568 {
569 fprintf (stderr, "do_recv.%lu: received %lu reply bytes on %p\n",
570 c->id,
571 (u_long) (c->reply.header_bytes + c->reply.content_bytes),
572 s);
573 if (nread < 0)
574 fprintf (stderr, "%s.do_recv: read() failed: %s\n",
575 prog_name, strerror (saved_errno));
576 }
577 if (nread < 0)
578 {
579 if (saved_errno != EAGAIN)
580 conn_failure (s, saved_errno);
581 }
582 else if (s->state != S_REPLY_DATA)
583 conn_failure (s, ECONNRESET);
584 else
585 {
586 if (s->state < S_CLOSING)
587 s->state = S_REPLY_DONE;
588 recv_done (c);
589 }
590 return;
591 }
592 buf[nread] = '\0'; /* ensure buffer is '\0' terminated */
593
594 if (DBG > 3)
595 {
596 /* dump received data in hex & ascii: */
597
598 fprintf (stderr, "do_recv.%lu: received reply data:\n", c->id);
599 for (cp = buf; cp < buf + nread; )
600 {
601 fprintf (stderr, " %04x:",
602 (int) (c->reply.header_bytes + c->reply.content_bytes
603 + (cp - buf)));
604 for (i = 0; i < 16 && i < buf + nread - cp; ++i)
605 fprintf (stderr, " %02x", cp[i] & 0xff);
606 i *= 3;
607 while (i++ < 50)
608 fputc (' ', stderr);
609 for (i = 0; i < 16 && cp < buf + nread; ++i, ++cp)
610 fprintf (stderr, "%c", isprint (*cp) ? *cp : '.');
611 fprintf (stderr, "\n");
612 }
613 }
614
615 /* process the replies in this buffer: */
616
617 buf_len = nread;
618 cp = buf;
619 do
620 {
621 c = s->recvq;
622 assert (c);
623 /* sets right start time, but doesn't update each packet */
624 if(s->state == S_REPLY_STATUS)
625 {
626 c->timeout = param.timeout + param.think_timeout;
627 if (c->timeout > 0.0)
628 c->timeout += timer_now ();
629 }
630
631 http_process_reply_bytes (c, &cp, &buf_len);
632 if (s->state == S_REPLY_DONE)
633 {
634 recv_done (c);
635 if (s->state >= S_CLOSING)
636 return;
637
638 s->state = S_REPLY_STATUS;
639 }
640 }
641 while (buf_len > 0);
642
643 if (s->recvq)
644 set_active (c->conn, &rdfds);
645 }
646
647 struct sockaddr_in*
648 core_addr_intern (const char *server, size_t server_len, int port)
649 {
650 struct sockaddr_in sin;
651 struct hash_entry *h;
652 struct hostent *he;
653 Any_Type arg;
654
655 memset (&sin, 0, sizeof (sin));
656 sin.sin_family = AF_INET;
657 sin.sin_port = htons (port);
658
659 arg.cvp = server;
660 event_signal (EV_HOSTNAME_LOOKUP_START, 0, arg);
661 he = gethostbyname (server);
662 event_signal (EV_HOSTNAME_LOOKUP_STOP, 0, arg);
663 if (he)
664 {
665 if (he->h_addrtype != AF_INET
666 || he->h_length != sizeof (sin.sin_addr))
667 {
668 fprintf (stderr, "%s: can't deal with addr family %d or size %d\n",
669 prog_name, he->h_addrtype, he->h_length);
670 exit (1);
671 }
672 memcpy (&sin.sin_addr, he->h_addr_list[0], sizeof (sin.sin_addr));
673 }
674 else
675 {
676 if (!inet_aton (server, &sin.sin_addr))
677 {
678 fprintf (stderr, "%s.core_addr_intern: invalid server address %s\n",
679 prog_name, server);
680 exit (1);
681 }
682 }
683 h = hash_enter (server, server_len, port, &sin);
684 if (!h)
685 return 0;
686 return &h->sin;
687 }
688
689 void
690 core_init (void)
691 {
692 struct rlimit rlimit;
693
694 memset (&hash_table, 0, sizeof (hash_table));
695 memset (&rdfds, 0, sizeof (rdfds));
696 memset (&wrfds, 0, sizeof (wrfds));
697 memset (&myaddr, 0, sizeof (myaddr));
698 memset (&port_free_map, 0xff, sizeof (port_free_map));
699
700 /* Don't disturb just because a TCP connection closed on us... */
701 signal (SIGPIPE, SIG_IGN);
702
703 #ifdef DONT_POLL
704 /* This causes select() to take several milliseconds on both
705 Linux/x86 and HP-UX 10.20. */
706 select_timeout.tv_sec = (u_long) TIMER_INTERVAL;
707 select_timeout.tv_usec = (u_long) (TIMER_INTERVAL * 1e6);
708 #else
709 /* This causes httperf to become a CPU hog as it polls for
710 filedescriptors to become readable/writable. This is OK as long
711 as httperf is the only (interesting) user-level process that
712 executes on a machine. */
713 select_timeout.tv_sec = 0;
714 select_timeout.tv_usec = 0;
715 #endif
716
717 /* boost open file limit to the max: */
718 if (getrlimit (RLIMIT_NOFILE, &rlimit) < 0)
719 {
720 fprintf (stderr, "%s: failed to get number of open file limit: %s",
721 prog_name, strerror (errno));
722 exit (1);
723 }
724
725 if (rlimit.rlim_max > FD_SETSIZE)
726 {
727 fprintf (stderr, "%s: warning: open file limit > FD_SETSIZE; "
728 "limiting max. # of open files to FD_SETSIZE\n", prog_name);
729 rlimit.rlim_max = FD_SETSIZE;
730 }
731
732 rlimit.rlim_cur = rlimit.rlim_max;
733 if (setrlimit (RLIMIT_NOFILE, &rlimit) < 0)
734 {
735 fprintf (stderr, "%s: failed to increase number of open file limit: %s",
736 prog_name, strerror (errno));
737 exit (1);
738 }
739
740 if (verbose)
741 printf ("%s: maximum number of open descriptors = %ld\n",
742 prog_name, rlimit.rlim_max);
743
744 if (param.server)
745 core_addr_intern (param.server, strlen (param.server), param.port);
746 }
747
748 #ifdef HAVE_SSL
749
750 void
751 core_ssl_connect (Conn *s)
752 {
753 Any_Type arg;
754 int ssl_err;
755
756 if (DBG > 2)
757 fprintf (stderr, "core_ssl_connect(conn=%p)\n", (void *) s);
758
759 if (SSL_set_fd (s->ssl, s->sd) == 0)
760 {
761 ERR_print_errors_fp (stderr);
762 exit (-1);
763 }
764
765 ssl_err = SSL_connect (s->ssl);
766 if (ssl_err < 0)
767 {
768 int reason = SSL_get_error(s->ssl, ssl_err);
769
770 if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE)
771 {
772 if (DBG > 2)
773 fprintf (stderr, "core_ssl_connect: want to %s more...\n",
774 (reason == SSL_ERROR_WANT_READ) ? "read" : "write");
775 if (reason == SSL_ERROR_WANT_READ && !FD_ISSET (s->sd, &rdfds))
776 {
777 FD_CLR (s->sd, &wrfds);
778 set_active (s, &rdfds);
779 }
780 else if (reason == SSL_ERROR_WANT_WRITE && !FD_ISSET (s->sd, &wrfds))
781 {
782 FD_CLR (s->sd, &rdfds);
783 set_active (s, &wrfds);
784 }
785 return;
786 }
787 fprintf (stderr,
788 "%s: failed to connect to SSL server (err=%d, reason=%d)\n",
789 prog_name, ssl_err, reason);
790 ERR_print_errors_fp (stderr);
791 exit (-1);
792 }
793
794 s->state = S_CONNECTED;
795
796 if (DBG > 0)
797 fprintf (stderr, "core_ssl_connect: SSL is connected!\n");
798
799 if (DBG > 1)
800 {
801 SSL_CIPHER *ssl_cipher;
802
803 ssl_cipher = SSL_get_current_cipher (s->ssl);
804 if (!ssl_cipher)
805 fprintf (stderr, "core_ssl_connect: server refused all client cipher "
806 "suites!\n");
807 else
808 fprintf (stderr, "core_ssl_connect: cipher=%s, valid=%d, id=%lu\n",
809 ssl_cipher->name, ssl_cipher->valid, ssl_cipher->id);
810 }
811
812 arg.l = 0;
813 event_signal (EV_CONN_CONNECTED, (Object *) s, arg);
814 }
815
816 #endif /* HAVE_SSL */
817
818 int
819 core_connect (Conn *s)
820 {
821 int sd, result, async_errno;
822 socklen_t len;
823 struct sockaddr_in *sin;
824 struct linger linger;
825 int myport, optval;
826 Any_Type arg;
827 static int prev_iteration = -1;
828 static u_long burst_len;
829
830 if (iteration == prev_iteration)
831 ++burst_len;
832 else
833 {
834 if (burst_len > max_burst_len)
835 max_burst_len = burst_len;
836 burst_len = 1;
837 prev_iteration = iteration;
838 }
839
840 SYSCALL (SOCKET,
841 sd = socket (AF_INET, SOCK_STREAM, 0));
842 if (sd < 0)
843 {
844 if (DBG > 0)
845 fprintf (stderr, "%s.core_connect.socket: %s (max_sd=%d)\n",
846 prog_name, strerror (errno), max_sd);
847 goto failure;
848 }
849
850 if (fcntl (sd, F_SETFL, O_NONBLOCK) < 0)
851 {
852 fprintf (stderr, "%s.core_connect.fcntl: %s\n",
853 prog_name, strerror (errno));
854 goto failure;
855 }
856
857 if (param.close_with_reset)
858 {
859 linger.l_onoff = 1;
860 linger.l_linger = 0;
861 if (setsockopt (sd, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger)) < 0)
862 {
863 fprintf (stderr, "%s.core_connect.setsockopt(SO_LINGER): %s\n",
864 prog_name, strerror (errno));
865 goto failure;
866 }
867 }
868
869 /* Disable Nagle algorithm so we don't delay needlessly when
870 pipelining requests. */
871 optval = 1;
872 if (setsockopt (sd, SOL_TCP, TCP_NODELAY, &optval, sizeof (optval)) < 0)
873 {
874 fprintf (stderr, "%s.core_connect.setsockopt(SO_SNDBUF): %s\n",
875 prog_name, strerror (errno));
876 goto failure;
877 }
878
879 optval = param.send_buffer_size;
880 if (setsockopt (sd, SOL_SOCKET, SO_SNDBUF, &optval, sizeof (optval)) < 0)
881 {
882 fprintf (stderr, "%s.core_connect.setsockopt(SO_SNDBUF): %s\n",
883 prog_name, strerror (errno));
884 goto failure;
885 }
886
887 optval = param.recv_buffer_size;
888 if (setsockopt (sd, SOL_SOCKET, SO_RCVBUF, &optval, sizeof (optval)) < 0)
889 {
890 fprintf (stderr, "%s.core_connect.setsockopt(SO_SNDBUF): %s\n",
891 prog_name, strerror (errno));
892 goto failure;
893 }
894
895 s->sd = sd;
896 if (sd >= alloced_sd_to_conn)
897 {
898 size_t size, old_size;
899
900 old_size = alloced_sd_to_conn * sizeof (sd_to_conn[0]);
901 alloced_sd_to_conn += 2048;
902 size = alloced_sd_to_conn * sizeof (sd_to_conn[0]);
903 if (sd_to_conn)
904 sd_to_conn = realloc (sd_to_conn, size);
905 else
906 sd_to_conn = malloc (size);
907 if (!sd_to_conn)
908 {
909 if (DBG > 0)
910 fprintf (stderr, "%s.core_connect.realloc: %s\n",
911 prog_name, strerror (errno));
912 goto failure;
913 }
914 memset ((char *) sd_to_conn + old_size, 0, size - old_size);
915 }
916 assert (!sd_to_conn[sd]);
917 sd_to_conn[sd] = s;
918
919 sin = hash_lookup (s->hostname, s->hostname_len, s->port);
920 if (!sin)
921 {
922 if (DBG > 0)
923 fprintf (stderr, "%s.core_connect: unknown server/port %s:%d\n",
924 prog_name, s->hostname, s->port);
925 goto failure;
926 }
927
928 arg.l = 0;
929 event_signal (EV_CONN_CONNECTING, (Object *) s, arg);
930 if (s->state >= S_CLOSING)
931 goto failure;
932
933 if (param.hog)
934 {
935 while (1)
936 {
937 myport = port_get ();
938 if (myport < 0)
939 goto failure;
940
941 myaddr.sin_port = htons (myport);
942 SYSCALL (BIND,
943 result = bind (sd, (struct sockaddr *)&myaddr,
944 sizeof (myaddr)));
945 if (result == 0)
946 break;
947
948 if (errno != EADDRINUSE && errno == EADDRNOTAVAIL)
949 {
950 if (DBG > 0)
951 fprintf (stderr, "%s.core_connect.bind: %s\n",
952 prog_name, strerror (errno));
953 goto failure;
954 }
955 }
956 s->myport = myport;
957 }
958
959 SYSCALL (CONNECT,
960 result = connect (sd, (struct sockaddr *)sin, sizeof (*sin)));
961 if (result == 0)
962 {
963 #ifdef HAVE_SSL
964 if (param.use_ssl)
965 core_ssl_connect (s);
966 else
967 #endif
968 {
969 s->state = S_CONNECTED;
970 arg.l = 0;
971 event_signal (EV_CONN_CONNECTED, (Object *) s, arg);
972 }
973 }
974 else if (errno == EINPROGRESS)
975 {
976 /* The socket becomes writable only after the connection has
977 been established. Hence we wait for writability to
978 detect connection establishment. */
979 s->state = S_CONNECTING;
980 set_active (s, &wrfds);
981 if (param.timeout > 0.0)
982 {
983 arg.vp = s;
984 assert (!s->watchdog);
985 s->watchdog = timer_schedule (conn_timeout, arg, param.timeout);
986 }
987 }
988 else
989 {
990 len = sizeof (async_errno);
991 if (getsockopt (sd, SOL_SOCKET, SO_ERROR, &async_errno, &len) == 0
992 && async_errno != 0)
993 errno = async_errno;
994
995 if (DBG > 0)
996 fprintf (stderr, "%s.core_connect.connect: %s (max_sd=%d)\n",
997 prog_name, strerror (errno), max_sd);
998 goto failure;
999 }
1000 return 0;
1001
1002 failure:
1003 conn_failure (s, errno);
1004 return -1;
1005 }
1006
1007 int
1008 core_send (Conn *conn, Call *call)
1009 {
1010 Any_Type arg;
1011
1012 arg.l = 0;
1013 event_signal (EV_CALL_ISSUE, (Object *) call, arg);
1014
1015 call->conn = conn; /* NO refcounting here (see call.h). */
1016
1017 if (param.no_host_hdr)
1018 {
1019 call->req.iov[IE_HOST].iov_base = (caddr_t) "";
1020 call->req.iov[IE_HOST].iov_len = 0;
1021 }
1022 else if (!call->req.iov[IE_HOST].iov_base)
1023 {
1024 /* Default call's hostname to connection's hostname: */
1025 call->req.iov[IE_HOST].iov_base = (caddr_t) conn->fqdname;
1026 call->req.iov[IE_HOST].iov_len = conn->fqdname_len;
1027 }
1028
1029 /* NOTE: the protocol version indicates what the _client_ can
1030 understand. If we send HTTP/1.1, it doesn't mean that the server
1031 has to speak HTTP/1.1. In other words, sending an HTTP/1.1
1032 header leaves it up to the server whether it wants to reply with
1033 a 1.0 or 1.1 reply. */
1034 switch (call->req.version)
1035 {
1036 case 0x10000:
1037 if (param.no_host_hdr)
1038 {
1039 call->req.iov[IE_PROTL].iov_base = (caddr_t) http10req_nohost;
1040 call->req.iov[IE_PROTL].iov_len = sizeof (http10req_nohost) - 1;
1041 }
1042 else
1043 {
1044 call->req.iov[IE_PROTL].iov_base = (caddr_t) http10req;
1045 call->req.iov[IE_PROTL].iov_len = sizeof (http10req) - 1;
1046 }
1047 break;
1048
1049 case 0x10001:
1050 if (param.no_host_hdr)
1051 {
1052 call->req.iov[IE_PROTL].iov_base = http11req_nohost;
1053 call->req.iov[IE_PROTL].iov_len = sizeof (http11req_nohost) - 1;
1054 }
1055 else
1056 {
1057 call->req.iov[IE_PROTL].iov_base = http11req;
1058 call->req.iov[IE_PROTL].iov_len = sizeof (http11req) - 1;
1059 }
1060 break;
1061
1062 default:
1063 fprintf (stderr, "%s: unexpected version code %x\n",
1064 prog_name, call->req.version);
1065 exit (1);
1066 }
1067 call->req.iov_index = 0;
1068 call->req.iov_saved = call->req.iov[0];
1069
1070 /* insert call into connection's send queue: */
1071 call_inc_ref (call);
1072 call->sendq_next = 0;
1073 if (!conn->sendq)
1074 {
1075 conn->sendq = conn->sendq_tail = call;
1076 arg.l = 0;
1077 event_signal (EV_CALL_SEND_START, (Object *) call, arg);
1078 if (conn->state >= S_CLOSING)
1079 return -1;
1080 call->timeout = param.timeout ? timer_now () + param.timeout : 0.0;
1081 set_active (conn, &wrfds);
1082 }
1083 else
1084 {
1085 conn->sendq_tail->sendq_next = call;
1086 conn->sendq_tail = call;
1087 }
1088 return 0;
1089 }
1090
1091 void
1092 core_close (Conn *conn)
1093 {
1094 Call *call, *call_next;
1095 Any_Type arg;
1096 int sd;
1097
1098 if (conn->state >= S_CLOSING)
1099 return; /* guard against recursive calls */
1100 conn->state = S_CLOSING;
1101
1102 if (DBG >= 10)
1103 fprintf (stderr, "%s.core_close(conn=%p)\n", prog_name, conn);
1104
1105 if (conn->watchdog)
1106 {
1107 timer_cancel (conn->watchdog);
1108 conn->watchdog = 0;
1109 }
1110
1111 /* first, get rid of all pending calls: */
1112 for (call = conn->sendq; call; call = call_next)
1113 {
1114 call_next = call->sendq_next;
1115 call_dec_ref (call);
1116 }
1117 conn->sendq = 0;
1118
1119 for (call = conn->recvq; call; call = call_next)
1120 {
1121 call_next = call->recvq_next;
1122 call_dec_ref (call);
1123 }
1124 conn->recvq = 0;
1125
1126 sd = conn->sd;
1127 conn->sd = -1;
1128
1129 arg.l = 0;
1130 event_signal (EV_CONN_CLOSE, (Object *) conn, arg);
1131 assert (conn->state == S_CLOSING);
1132
1133 #ifdef HAVE_SSL
1134 if (param.use_ssl)
1135 SSL_shutdown (conn->ssl);
1136 #endif
1137
1138 if (sd >= 0)
1139 {
1140 close (sd);
1141 sd_to_conn[sd] = 0;
1142 FD_CLR (sd, &wrfds);
1143 FD_CLR (sd, &rdfds);
1144 }
1145 if (conn->myport > 0)
1146 port_put (conn->myport);
1147
1148 /* A connection that has been closed is not useful anymore, so we
1149 give up the reference obtained when creating the session. This
1150 normally initiates destruction of the connection. */
1151 conn_dec_ref (conn);
1152 }
1153
1154 void
1155 core_loop (void)
1156 {
1157 int is_readable, is_writable, n, sd, bit, min_i, max_i, i = 0;
1158 fd_set readable, writable;
1159 fd_mask mask;
1160 Any_Type arg;
1161 Conn *conn;
1162
1163 while (running)
1164 {
1165 struct timeval tv = select_timeout;
1166
1167 timer_tick ();
1168
1169 readable = rdfds;
1170 writable = wrfds;
1171 min_i = min_sd / NFDBITS;
1172 max_i = max_sd / NFDBITS;
1173
1174 SYSCALL (SELECT,
1175 n = select (max_sd + 1, &readable, &writable, 0, &tv));
1176
1177 ++iteration;
1178
1179 if (n <= 0)
1180 {
1181 if (n < 0)
1182 {
1183 fprintf (stderr, "%s.core_loop: select failed: %s\n",
1184 prog_name, strerror (errno));
1185 exit (1);
1186 }
1187 continue;
1188 }
1189
1190 while (n > 0)
1191 {
1192 /* find the index of the fdmask that has something going on: */
1193 do
1194 {
1195 ++i;
1196 if (i > max_i)
1197 i = min_i;
1198
1199 assert (i <= max_i);
1200 mask = readable.fds_bits[i] | writable.fds_bits[i];
1201 }
1202 while (!mask);
1203 bit = 0;
1204 sd = i*NFDBITS + bit;
1205 do
1206 {
1207 if (mask & 1)
1208 {
1209 --n;
1210
1211 is_readable =
1212 (FD_ISSET (sd, &readable) && FD_ISSET (sd, &rdfds));
1213 is_writable =
1214 (FD_ISSET (sd, &writable) && FD_ISSET (sd, &wrfds));
1215
1216 if (is_readable || is_writable)
1217 {
1218 /* only handle sockets that haven't timed out yet */
1219 conn = sd_to_conn[sd];
1220
1221 conn_inc_ref (conn);
1222
1223 if (conn->watchdog)
1224 {
1225 timer_cancel (conn->watchdog);
1226 conn->watchdog = 0;
1227 }
1228 if (conn->state == S_CONNECTING)
1229 {
1230 #ifdef HAVE_SSL
1231 if (param.use_ssl)
1232 core_ssl_connect (conn);
1233 else
1234 #endif
1235 if (is_writable)
1236 {
1237 FD_CLR (sd, &wrfds);
1238 conn->state = S_CONNECTED;
1239 arg.l = 0;
1240 event_signal (EV_CONN_CONNECTED,
1241 (Object *) conn, arg);
1242 }
1243 }
1244 else
1245 {
1246 if (is_writable && conn->sendq)
1247 do_send (conn);
1248 if (is_readable && conn->recvq)
1249 do_recv (conn);
1250 }
1251
1252 conn_dec_ref (conn);
1253
1254 if (n > 0)
1255 timer_tick ();
1256 }
1257 }
1258 mask = ((u_long) mask) >> 1;
1259 ++sd;
1260 }
1261 while (mask);
1262 }
1263 }
1264 }
1265
1266 void
1267 core_exit (void)
1268 {
1269 running = 0;
1270
1271 printf ("Maximum connect burst length: %lu\n", max_burst_len);
1272
1273 #ifdef TIME_SYSCALLS
1274 {
1275 u_int count;
1276 Time time;
1277 int i;
1278
1279 printf ("Average syscall execution times:\n");
1280 for (i = 0; i < NELEMS (syscall_name); ++i)
1281 {
1282 count = syscall_count[i];
1283 time = syscall_time[i];
1284 printf ("\t%s:\t%.3f ms/call (%.3fs total, %u calls)\n",
1285 syscall_name[i], count > 0 ? 1e3*time/count : 0, time, count);
1286
1287 }
1288 putchar ('\n');
1289 }
1290 #endif
1291 }