⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 core.c

📁 一个WEB服务器的性能测试工具
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    httperf -- a tool for measuring web server performance    Copyright (C) 2000  Hewlett-Packard Company    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>    This file is part of httperf, a web server performance measurment    tool.    This program is free software; you can redistribute it and/or    modify it under the terms of the GNU General Public License as    published by the Free Software Foundation; either version 2 of the    License, or (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA    02111-1307 USA*/#include "config.h"#include <assert.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <netdb.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/types.h>#include <sys/resource.h>	/* grrr, must come after sys/types.h for BSD */#include <netinet/in.h>#include <netinet/tcp.h>#include <arpa/inet.h>#include <httperf.h>#include <call.h>#include <core.h>#include <event.h>#include <http.h>#include <conn.h>#define HASH_TABLE_SIZE	1024	/* can't have more than this many servers */#define MIN_IP_PORT	IPPORT_RESERVED#define MAX_IP_PORT	65535#define BITSPERLONG	(8*sizeof (u_long))static int running = 1;static int iteration;static u_long max_burst_len;static fd_set rdfds, wrfds;static int min_sd = 0x7fffffff, max_sd = 0, alloced_sd_to_conn = 0;static struct timeval select_timeout;static struct sockaddr_in myaddr;Conn **sd_to_conn;static u_long port_free_map[((MAX_IP_PORT - MIN_IP_PORT + BITSPERLONG)			     / BITSPERLONG)];static char http10req[] =  " HTTP/1.0\r\nUser-Agent: httperf/"VERSION"\r\nHost: ";static char http11req[] =  " HTTP/1.1\r\nUser-Agent: httperf/"VERSION"\r\nHost: ";static char http10req_nohost[] =  " HTTP/1.0\r\nUser-Agent: httperf/"VERSION"\r\n";static char http11req_nohost[] =  " HTTP/1.1\r\nUser-Agent: httperf/"VERSION"\r\n";#ifndef SOL_TCP# define SOL_TCP 6	/* probably ought to do getprotlbyname () */#endif#ifdef TIME_SYSCALLS# define SYSCALL(n,s)							\  {									\    Time start, stop;							\    do									\      {									\	errno = 0;							\	start = timer_now_forced ();					\	s;				 /* execute the syscall */	\	stop = timer_now_forced ();					\	syscall_time[SC_##n] += stop - start;				\	++syscall_count[SC_##n];					\      }									\    while (errno == EINTR);						\  }  enum Syscalls    {      SC_BIND, SC_CONNECT, SC_READ, SC_SELECT, SC_SOCKET, SC_WRITEV,      SC_SSL_READ, SC_SSL_WRITEV,      SC_NUM_SYSCALLS    };  static const char * const syscall_name[SC_NUM_SYSCALLS] =    {      "bind", "connct", "read", "select", "socket", "writev",      "ssl_read", "ssl_writev"    };  static Time syscall_time[SC_NUM_SYSCALLS];  static u_int syscall_count[SC_NUM_SYSCALLS];#else# define SYSCALL(n,s)				\  {						\    do						\      {						\	errno = 0;				\	s;					\      }						\    while (errno == EINTR);			\  }#endifstruct hash_entry  {    const char *hostname;    int port;    struct sockaddr_in sin;  }hash_table[HASH_TABLE_SIZE];static inthash_code (const char *server, size_t server_len, int port){  u_char *cp = (u_char *) server;  u_long h = port;  u_long g;  int ch;  /* Basically the ELF hash algorithm: */  while ((ch = *cp++) != '\0')    {      h = (h << 4) + ch;      if ((g = (h & 0xf0000000)) != 0)        {          h ^= g >> 24;          h &= ~g;        }    }  return h;}static struct hash_entry*hash_enter (const char *server, size_t server_len, int port,	    struct sockaddr_in *sin){  struct hash_entry *he;  int index = hash_code (server, server_len, port) % HASH_TABLE_SIZE;  while (hash_table[index].hostname)    {      ++index;      if (index >= HASH_TABLE_SIZE)	index = 0;    }  he = hash_table + index;  he->hostname = server;  he->port = port;  he->sin = *sin;  return he;}static struct sockaddr_in*hash_lookup (const char *server, size_t server_len, int port){  int index, start_index;  index = start_index = hash_code (server, server_len, port) % HASH_TABLE_SIZE;  while (hash_table[index].hostname)    {      if (hash_table[index].port == port	  && strcmp (hash_table[index].hostname, server) == 0)	return &hash_table[index].sin;      ++index;      if (index >= HASH_TABLE_SIZE)	index = 0;      if (index == start_index)	break;    }  return 0;}static intlffs (long w){  int r;  if (sizeof (w) == sizeof (int))    r = ffs (w);  else    {      r = ffs (w);#if SIZEOF_LONG > 4      if (r == 0)	{	  r = ffs (w >> (8*sizeof (int)));	  if (r > 0)	    r += 8*sizeof (int);	}#endif    }  return r;}static voidport_put (int port){  int i, bit;  port -= MIN_IP_PORT;  i   = port / BITSPERLONG;  bit = port % BITSPERLONG;  port_free_map[i] |= (1UL << bit);}static intport_get (void){  static u_long mask = ~0UL;  static int previous = 0;  int port, bit, i;  i = previous;  if ((port_free_map[i] & mask) == 0)    {      do	{	  ++i;	  if (i >= NELEMS (port_free_map))	    i = 0;	  if (i == previous)	    {	      if (DBG > 0)		fprintf (stderr,			 "%s.port_get: Yikes! I'm out of port numbers!\n",			 prog_name);	      return -1;	    }	}      while (port_free_map[i] == 0);      mask = ~0UL;    }  previous = i;  bit = lffs (port_free_map[i] & mask) - 1;  if (bit >= BITSPERLONG - 1)    mask = 0;  else    mask = ~((1UL << (bit + 1)) - 1);  port_free_map[i] &= ~(1UL << bit);  port = bit + i*BITSPERLONG + MIN_IP_PORT;  return port;}static voidconn_failure (Conn *s, int err){  Any_Type arg;  arg.l = err;  event_signal (EV_CONN_FAILED, (Object *) s, arg);  core_close (s);}static voidconn_timeout (Timer *t, Any_Type arg){  Conn *s = arg.vp;  Time now;  Call *c;  assert (object_is_conn (s));  s->watchdog = 0;  if (DBG > 0)    {      c = 0;      if (s->sd >= 0)	{	  now = timer_now ();	  if (FD_ISSET (s->sd, &rdfds)	      && s->recvq && now >= s->recvq->timeout)	    c = s->recvq;	  else if (FD_ISSET (s->sd, &wrfds)		   && s->sendq && now >= s->sendq->timeout)	    c = s->sendq;	}      if (DBG > 0)	{	  fprintf (stderr, "connection_timeout");	  if (c)	    fprintf (stderr, ".%lu", c->id);	  fprintf (stderr, ": t=%p, connection=%p\n", t, s);	}    }  arg.l = 0;  event_signal (EV_CONN_TIMEOUT, (Object *) s, arg);  core_close (s);}static voidset_active (Conn *s, fd_set *fdset){  int sd = s->sd;  Any_Type arg;  Time timeout;  FD_SET (sd, fdset);  if (sd < min_sd)    min_sd = sd;  if (sd >= max_sd)    max_sd = sd;  if (s->watchdog)    return;  timeout = 0.0;  if (s->sendq)    timeout = s->sendq->timeout;  if (s->recvq && (timeout == 0.0 || timeout > s->recvq->timeout))    timeout = s->recvq->timeout;  if (timeout > 0.0)    {      arg.vp = s;      s->watchdog = timer_schedule (conn_timeout, arg,				    timeout - timer_now ());    }}static voiddo_send (Conn *conn){  int async_errno, len;  struct iovec *iovp;  int sd = conn->sd;  ssize_t nsent = 0;  Any_Type arg;  Call *call;  while (1)    {      call = conn->sendq;      assert (call);      arg.l = 0;      event_signal (EV_CALL_SEND_RAW_DATA, (Object *) call, arg);#ifdef HAVE_SSL      if (param.use_ssl)	{	  extern ssize_t SSL_writev (SSL *, const struct iovec *, int);	  SYSCALL (SSL_WRITEV,		   nsent = SSL_writev(conn->ssl,				      call->req.iov + call->req.iov_index,				      (NELEMS (call->req.iov)				       - call->req.iov_index)));	}      else#endif	{	  SYSCALL (WRITEV,		   nsent = writev (sd, call->req.iov + call->req.iov_index,				   (NELEMS (call->req.iov)				    - call->req.iov_index)));	}      if (DBG > 0)	fprintf (stderr, "do_send.%lu: wrote %ld bytes on %p\n", call->id,		 (long) nsent, conn);      if (nsent < 0)	{	  if (errno == EAGAIN)	    return;	  len = sizeof (async_errno);	  if (getsockopt (sd, SOL_SOCKET, SO_ERROR, &async_errno, &len) == 0	      && async_errno != 0)	    errno = async_errno;	  if (DBG > 0)	    fprintf (stderr, "%s.do_send: writev() failed: %s\n",		     prog_name, strerror (errno));	  conn_failure (conn, errno);	  return;	}      call->req.size += nsent;      iovp = call->req.iov + call->req.iov_index;      while (iovp < call->req.iov + NELEMS (call->req.iov))	{	  if (nsent < iovp->iov_len)	    {	      iovp->iov_len -= nsent;	      iovp->iov_base = (caddr_t) ((char *) iovp->iov_base + nsent);	      break;	    }	  else	    {	      /* we're done with this fragment: */	      nsent -= iovp->iov_len;	      *iovp = call->req.iov_saved;	      ++iovp;	      call->req.iov_saved = *iovp;	    }	}      call->req.iov_index = iovp - call->req.iov;      if (call->req.iov_index < NELEMS (call->req.iov))	{	  /* there are more header bytes to write */	  call->timeout = param.timeout ? timer_now () + param.timeout : 0.0;	  set_active (conn, &wrfds);	  return;	}      /* we're done with sending this request */      conn->sendq = call->sendq_next;      if (!conn->sendq)	{	  conn->sendq_tail = 0;	  FD_CLR (sd, &wrfds);	}      arg.l = 0;      event_signal (EV_CALL_SEND_STOP, (Object *) call, arg);      if (conn->state >= S_CLOSING)	{	  call_dec_ref (call);	  return;	}      /* get ready to receive matching reply (note that we implicitly         pass on the reference to the call from the sendq to the         recvq): */      call->recvq_next = 0;      if (!conn->recvq)	conn->recvq = conn->recvq_tail = call;      else	{	  conn->recvq_tail->recvq_next = call;	  conn->recvq_tail = call;	}      call->timeout = param.timeout + param.think_timeout;      if (call->timeout > 0.0)	call->timeout += timer_now ();      set_active (conn, &rdfds);      if (conn->state < S_REPLY_STATUS)	conn->state = S_REPLY_STATUS;	/* expecting reply status */      if (!conn->sendq)	return;      arg.l = 0;      event_signal (EV_CALL_SEND_START, (Object *) conn->sendq, arg);      if (conn->state >= S_CLOSING)	return;    }}static voidrecv_done (Call *call){  Conn *conn = call->conn;  Any_Type arg;  conn->recvq = call->recvq_next;  if (!conn->recvq)    {      FD_CLR (conn->sd, &rdfds);      conn->recvq_tail = 0;    }  /* we're done with receiving this request */  arg.l = 0;  event_signal (EV_CALL_RECV_STOP, (Object *) call, arg);  call_dec_ref (call);}static voiddo_recv (Conn *s){  char *cp, buf[8193];  Call *c = s->recvq;  int i, saved_errno;  ssize_t nread = 0;  size_t buf_len;  assert (c);#ifdef HAVE_SSL  if (param.use_ssl)    {      SYSCALL (SSL_READ,	       nread = SSL_read (s->ssl, buf, sizeof (buf) - 1));    }  else#endif    {      SYSCALL (READ,	       nread = read (s->sd, buf, sizeof (buf) - 1));    }  saved_errno = errno;  if (nread <= 0)    {      if (DBG > 0)	{	  fprintf (stderr, "do_recv.%lu: received %lu reply bytes on %p\n",		   c->id,		   (u_long) (c->reply.header_bytes + c->reply.content_bytes),		   s);	  if (nread < 0)	    fprintf (stderr, "%s.do_recv: read() failed: %s\n",		     prog_name, strerror (saved_errno));	}      if (nread < 0)	{	  if (saved_errno != EAGAIN)	    conn_failure (s, saved_errno);	}      else if (s->state != S_REPLY_DATA)	conn_failure (s, ECONNRESET);      else	{	  if (s->state < S_CLOSING)	    s->state = S_REPLY_DONE;	  recv_done (c);	}      return;    }  buf[nread] = '\0';	/* ensure buffer is '\0' terminated */  if (DBG > 3)    {      /* dump received data in hex & ascii: */      fprintf (stderr, "do_recv.%lu: received reply data:\n", c->id);      for (cp = buf; cp < buf + nread; )	{	  fprintf (stderr, "  %04x:",		   (int) (c->reply.header_bytes + c->reply.content_bytes			  + (cp - buf)));	  for (i = 0; i < 16 && i < buf + nread - cp; ++i)	    fprintf (stderr, " %02x", cp[i] & 0xff);	  i *= 3;	  while (i++ < 50)	    fputc (' ', stderr);	  for (i = 0; i < 16 && cp < buf + nread; ++i, ++cp)	    fprintf (stderr, "%c", isprint (*cp) ? *cp : '.');	  fprintf (stderr, "\n");	}    }  /* process the replies in this buffer: */  buf_len = nread;  cp = buf;  do    {      c = s->recvq;      assert (c);      http_process_reply_bytes (c, &cp, &buf_len);      if (s->state == S_REPLY_DONE)	{	  recv_done (c);	  if (s->state >= S_CLOSING)	    return;	  s->state = S_REPLY_STATUS;	}    }  while (buf_len > 0);  if (s->recvq)    set_active (c->conn, &rdfds);}struct sockaddr_in*core_addr_intern (const char *server, size_t server_len, int port){  struct sockaddr_in sin;  struct hash_entry *h;  struct hostent *he;  Any_Type arg;    memset (&sin, 0, sizeof (sin));  sin.sin_family = AF_INET;  sin.sin_port = htons (port);  arg.cvp = server;  event_signal (EV_HOSTNAME_LOOKUP_START, 0, arg);  he = gethostbyname (server);  event_signal (EV_HOSTNAME_LOOKUP_STOP, 0, arg);  if (he)    {      if (he->h_addrtype != AF_INET	  || he->h_length != sizeof (sin.sin_addr))	{	  fprintf (stderr, "%s: can't deal with addr family %d or size %d\n",		   prog_name, he->h_addrtype, he->h_length);	  exit (1);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -