/*
    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
*/

/* Issue a sequence of calls on a connection.  */

#include <assert.h>

#include <httperf.h>
#include <call.h>
#include <core.h>
#include <event.h>
#include <conn.h>

#define CONN_PRIVATE_DATA(c) \
  ((Conn_Private_Data *) ((char *)(c) + conn_private_data_offset))

#define MIN(a,b)	((a) < (b) ? (a) : (b))

typedef struct Conn_Private_Data
  {
    int num_calls;
    int num_completed;
    int num_destroyed;
  }
Conn_Private_Data;

static size_t conn_private_data_offset;

static void
issue_calls (Conn *conn)
{
  Conn_Private_Data *priv;
  Call *call;
  int i;

  priv = CONN_PRIVATE_DATA (conn);
  priv->num_completed = 0;
  priv->num_destroyed = 0;

  for (i = 0; i < param.burst_len; ++i)
    if (priv->num_calls++ < param.num_calls)
      {
	call = call_new ();
	if (call)
	  {
	    core_send (conn, call);
	    call_dec_ref (call);
	  }
      }
}

static void
conn_connected (Event_Type et, Conn *conn)
{
  assert (et == EV_CONN_CONNECTED && object_is_conn (conn));

  issue_calls (conn);
}

static void
call_done (Event_Type et, Call *call)
{
  Conn *conn = call->conn;
  Conn_Private_Data *priv;

  assert (et == EV_CALL_RECV_STOP && conn && object_is_conn (conn));

  priv = CONN_PRIVATE_DATA (conn);
  ++priv->num_completed;
}

static void
call_destroyed (Event_Type et, Call *call)
{
  Conn_Private_Data *priv;
  Conn *conn;

  assert (et == EV_CALL_DESTROYED && object_is_call (call));

  conn = call->conn;
  priv = CONN_PRIVATE_DATA (conn);

  if (++priv->num_destroyed >= MIN (param.burst_len, param.num_calls))
    {
      if (priv->num_completed == priv->num_destroyed
	  && priv->num_calls < param.num_calls)
	issue_calls (conn);
      else
	core_close (conn);
    }
}

static void
init (void)
{
  Any_Type arg;

  conn_private_data_offset = object_expand (OBJ_CONN,
					    sizeof (Conn_Private_Data));

  arg.l = 0;
  event_register_handler (EV_CONN_CONNECTED, (Event_Handler) conn_connected,
			  arg);
  event_register_handler (EV_CALL_RECV_STOP, (Event_Handler) call_done, arg);
  event_register_handler (EV_CALL_DESTROYED, (Event_Handler) call_destroyed,
			  arg);
}

Load_Generator call_seq =
  {
    "performs a sequence of calls on a connection",
    init,
    no_op,
    no_op
  };


syntax highlighted by Code2HTML, v. 0.9.1