/* 
 * $Id: idrp_events.c,v 1.3 1995/08/01 20:25:31 sjr Exp $
 * Merit IDRP release 1.1 (gated 3.5.4).  Copyright (c) 1994 by Merit Network, Inc. 
 */

#define DROP_PACKET (drop_packet())
/* #define DROP_PACKET (FALSE) */

#include "include.h"
#include "iso.h"
#include "idrp.h"
#include <stdio.h>



/* idrp_events.c
 *  
 *  Events - 	idrp events
 *	idrp_start_event(peer)  - start event to BIS peer 
 *	idrp_stop_event(peer)   - stop event to BIS peer
 *      idrp_event_closetimer(timer *tip, time_t interval)
 *	idrp_event_holdtimetimer
 *	idrp_event_keepalivetimer
 * 	idrp_event_rexmittimer
 *	idrp_event_starttimer
 * 	idrp_event_opensenttimer
 *	idrp_event_echotimer
 */ 
  
 

void 
idrp_start_event(peer)
idrpPeer *peer;
{

	/* called from idrp_event_start timer
	 * - so it has it's peer structure all ready
	 * 
	 * set hold timer for now until get new start timer frmo
	 * revision to IDRP code
	 */
 
	task_timer_set(peer->idrp_hold_timer, peer->hold_time, (time_t) 0);


	task_timer_reset(peer->idrp_closestay_timer);

	/* data structure initialization - just before start
	 * skh - Any more needed (2/26/93 - check on this again 
	 * skh - before first release) 
	 */

	peer->pdu_maxsendsize = IDRP_PKTSIZE;	/* Ditto. %% */
	peer->rcv_seq_expected = 1;
	peer->upper_window_edge = peer->send_next + 1;	/* So we can send an open */
	peer->send_unack = peer->send_next;
	peer->rcved_credit_avail = 1;		/* Until we receive a real one. */
	peer->cred_avail_zero_seq = 0;
	peer->cred_avail_zero_seq_last = 0;
	idrp_sm(peer,IDRP_START_EVENT);		/* does SM functions and sends open */
}

/* idrp_stop_event is not called from 
 * timer routes.  Most other events are
 * called from gated timer routes and so have tip,interval
 * calling routines
 */
 
void 
idrp_stop_event(peer)
idrpPeer *peer;
{
	begin_close(peer);
	idrp_sm(peer,IDRP_STOP_EVENT);
}

void 
idrp_event_closetimer(tip, interval)
task_timer *tip;
time_t interval; /* NOTUSED but required for GateD */
{
	idrpPeer *peer;

	peer = (idrpPeer *) tip->task_timer_task->task_data;
	trace_tf (idrp_trace_options, TR_TIMER|TR_NORMAL, 0, ("IDRP close timer expired peer %s",peer->name));
	idrp_sm(peer,IDRP_CLOSE_TIMEOUT);
}

void 
idrp_event_holdtimetimer(tip, interval)
task_timer *tip;
time_t interval; /* NOTUSED but required for GateD */
{
	idrpPeer *peer;

	peer = (idrpPeer *) tip->task_timer_task->task_data;
	trace_tf(idrp_trace_options, TR_TIMER|TR_NORMAL, 0, ("IDRP %s hold timer expired", peer->name));
	idrp_sm(peer,IDRP_HOLDTIME_TIMEOUT);
}

void 
idrp_event_keepalivetimer(tip, interval)
task_timer *tip; 
time_t interval; /* NOTUSED but required for GateD */
{
	idrpPeer *peer;

	peer = (idrpPeer *) tip->task_timer_task->task_data;
	send_keepalive(peer);
}
		
/*
 * Retransmission timer expired.  Repost everything on the retransmission queue.
 * If nothing there and the peer is flow blocked, retransmit a keepalive.
 */
void 
idrp_event_rexmittimer(tip, interval)
task_timer *tip;
time_t interval; /* NOTUSED but required for GateD */
{
	idrpPeer *peer;

	peer = (idrpPeer *) tip->task_timer_task->task_data;
	trace_tf(idrp_trace_options, TR_TIMER|TR_NORMAL, 0, ("IDRP %s rexmit timer expired", peer->name));
	if (peer->rexmit_queue_head) {
		if (peer->rexmit_queue_head->seq != peer->send_unack) {
			trace_log_tf(idrp_trace_options, 0, LOG_ERR, ("IDRP %s rexmit queue broken", peer->name));
		}
		peer->send_next = peer->send_unack;

		*peer->rexmit_queue_tail = peer->xmit_queue_head;
		peer->xmit_queue_head = peer->rexmit_queue_head;
		peer->rexmit_queue_head = NULL;
		peer->rexmit_queue_tail = &peer->rexmit_queue_head;
		kill_rexmit_timer(peer);
		post_enqueued_pdus(peer);
	} else {
		if (peer->cred_avail_zero_seq_last) {	/* We want to retransmit keepalives */
			send_keepalive(peer);
		} else {	/* We don't want to retransmit keepalives */
			kill_rexmit_timer(peer);
		}
	}
}
		
void 
idrp_event_starttimer(tip, interval)
task_timer *tip;
time_t interval; /* NOTUSED but required for GateD */
{
	idrpPeer *peer;

	peer = (idrpPeer *) tip->task_timer_task->task_data;
	peer->start_timer_running = FALSE;
	trace_tf(idrp_trace_options, TR_TIMER|TR_NORMAL, 0, ("IDRP %s start timer expired", peer->name));
	task_timer_reset(peer->idrp_start_timer);
	idrp_start_event(peer);
}
		
void 
idrp_event_opensenttimer(tip, interval)
task_timer *tip;
time_t interval; /* NOTUSED but required for GateD */
{
	idrpPeer *peer;

	peer = (idrpPeer *) tip->task_timer_task->task_data;
	if (peer->open_sent > peer->max_open_sent)
		{
		/* close connection - set holdtime timeout as input to sm */
		begin_close(peer);
		idrp_sm(peer,IDRP_HOLDTIME_TIMEOUT);
		}
	else
		{
		/* increment count of open pdus sent */ 
		peer->open_sent++;
		send_open(peer,FALSE);
		}
}

#ifdef ECHOKLUDGE
void 
idrp_event_echotimer(tip, interval)
task_timer *tip;
time_t interval; /* NOTUSED but required for GateD */
{
	int echocount;
	idrpPeer *peer;

	echocount = rand() % ECHO_MAX;
	peer = (idrpPeer *) tip->task_timer_task->task_data;
	if (peer->state != IDRP_ESTABLISHED)
		return;
	while (echocount--) {
		send_echo(peer);
	}
}
#endif /* ECHOKLUDGE */

void 
idrp_event_closestaytimer(tip, interval)
task_timer *tip;
time_t interval; /* NOTUSED but required for GateD */
{

        idrpPeer *peer;

        peer = (idrpPeer *) tip->task_timer_task->task_data;
	trace_tf(idrp_trace_options, TR_TIMER|TR_NORMAL, 0, ("IDRP %s close stay timer expired", peer->name));
	task_timer_reset(peer->idrp_closestay_timer);
	IDRP_FLAG_BIT_TEST(peer,IDRPF_IDLED)
		{
		return;
		}
	task_timer_set(peer->idrp_hold_timer, peer->hold_time, (time_t) 0);
	idrp_start_event(peer);
}
