/****************************************************************************
 * Copyright (C) 1998 WIDE Project. All rights reserved.
 * Copyright (C) 1999,2000,2001,2002 University of Tromso. All rights reserved.
 * Copyright (C) 2002 Invenia Innovation AS. All rights reserved.
 *
 * Author: Feike W. Dillema, feico@pasta.cs.uit.no.
 *         based on newbie code by Yusuke DOI, Keio Univ. Murai Lab.
 ****************************************************************************/

/*
 * <$Id: ev_timeout.c,v 3.27 2002/12/11 16:39:49 dillema Exp $>
 */

#include "totd.h"

static Q_Set *ev_to_queue;

int ev_to_init (void) {

	if (ev_to_queue)
		return -1;

	ev_to_queue = queue_create ();
	if (!ev_to_queue)
		return -1;

	return 0;
}

int ev_to_register (Ev_TO_Data *td) {
	char *fn = "ev_to_register()";
	G_Queue *gq_new, *gq_tmp, *gq_prev;

	gq_new = malloc (sizeof (G_Queue));
	if (!gq_new)
        	syslog (LOG_ERR, "%s: Cannot allocate memory", fn);
	else {
		gq_prev = NULL;
		/* find place insertion sort style */
		for (gq_tmp = ev_to_queue->head; gq_tmp->next && 
		     ((Ev_TO_Data *) (gq_tmp->p))->at < td->at; 
		     gq_tmp = gq_tmp->next)
			gq_prev = gq_tmp;	/* just skip */

		if (!gq_prev) {
			if (T.debug > 3)
				syslog (LOG_DEBUG, "%s: add event to head", fn);
			gq_new->p = (void *) td;
			gq_new->next = ev_to_queue->head;
			ev_to_queue->head = gq_new;
		} else {
			while (gq_tmp->p &&
			       (((Ev_TO_Data *) (gq_tmp->p))->at == td->at)) {
				gq_prev = gq_tmp;
				gq_tmp = gq_tmp->next;
			}

			if (!gq_tmp->p) {
				if (T.debug > 3)
					syslog (LOG_DEBUG, "%s: add to tail",
						fn);
				ev_to_queue->tail->p = (void *) td;
				ev_to_queue->tail->next = gq_new;
				gq_new->p = NULL;
				gq_new->next = NULL;
				ev_to_queue->tail = gq_new;
			} else {
				if (T.debug > 3)
					syslog (LOG_DEBUG, "%s: add to middle",
						fn);
				gq_new->p = (void *) td;
				gq_prev->next = gq_new;
				gq_new->next = gq_tmp;
			}
		}
		/* SUCCESS */
		return 0;
	}

	/* FAILURE */
	return -1;
}

time_t ev_timeout_process (void) {
	char *fn = "ev_timeout_process()";
	Ev_TO_Data *td_tmp;

	while ((td_tmp = (Ev_TO_Data *) queue_peek (ev_to_queue))
	       && (td_tmp->at <= time (NULL))) {
		/* process the event */
		td_tmp = dequeue (ev_to_queue);
		/* call timeout handler, if any */
		if (td_tmp->handler) {
			if (T.debug > 3)
				syslog (LOG_DEBUG, "%s: call timeout handler",
					fn);
			(td_tmp->handler) (td_tmp);
		} else
			if (T.debug > 3)
				syslog (LOG_DEBUG, "%s: cancel timeout event",
					fn);
		ev_to_data_free (td_tmp);
	}

	td_tmp = (Ev_TO_Data *) queue_peek (ev_to_queue);
	if (td_tmp)
		return td_tmp->at;	/* next event scheduled time */
	else
		return 0;	/* no event scheduled */
}

void ev_to_data_free (Ev_TO_Data *td) {
	char *fn = "ev_to_data_free()";

	switch (td->type) {
	case EV_TIMEOUT_NULL:
		if (td->data.p)
			free (td->data.p);
		break;
	case EV_TIMEOUT_CONTEXT:
		/*
		 * don't free td->data.cont because transaction itself will
		 * free its context
		 */
		break;
	default:
		syslog (LOG_CRIT, "%s: unknown type for timeout event", fn);
		break;
	}

	free (td);
}

void ev_to_data_free_v (void *td_v) {
	ev_to_data_free ((Ev_TO_Data *) td_v);
}

void ev_to_finish (void) {
	queue_destroy (ev_to_queue, ev_to_data_free_v);
}

void ev_to_flush (int type) {
	G_Queue *gqp;
	Ev_TO_Data *etdp;

	/* check one by one */
	for (gqp = ev_to_queue->head; gqp->next; gqp = gqp->next) {
		if (gqp->p) {
			etdp = (Ev_TO_Data *) (gqp->p);
			if (etdp->type == type) {
				if (etdp->handler)
					(etdp->handler) (etdp);
				etdp->handler = NULL;	/* disable the queue */
			}
		}
	}
	return;
}

int ev_to_register_ifcheck (void) {
	char *fn = "ev_to_register_ifcheck()";
	Ev_TO_Data *td_new;

	if (T.debug > 2)
		syslog (LOG_DEBUG, "%s: start", fn);

	if (!ev_to_queue)
		return -1;

	td_new = malloc (sizeof (Ev_TO_Data));
	if (!td_new) {
		syslog (LOG_ERR, "%s: can't allocate new event", fn);
		return -1;
	}
	td_new->at = time (NULL) + IF_CHECK_INTERVAL;
	td_new->handler = ev_to_handler_ifcheck;
	td_new->type = EV_TIMEOUT_NULL;
	td_new->data.p = NULL;

	ev_to_register (td_new);
	return 0;
}

int ev_to_handler_ifcheck (Ev_TO_Data *td) {
	char *fn = "ev_to_handler_ifcheck()";

	if (T.debug > 2)
		syslog (LOG_DEBUG, "%s: start", fn);

	if (td) {
		switch (net_reinit_socketlist (T.port, 0)) {
		case 0:
			/* no change */
			syslog (LOG_DEBUG, "%s: Socket List still the same", fn);
			break;
		case 1:
			/* change, bound new sockets */
			syslog (LOG_DEBUG, "%s: Socket List updated", fn);
			break;
		default:
			syslog (LOG_ERR, "%s: Can't get new socket list!", fn);
		}
	}

	/* (re-) register my event */
	return (ev_to_register_ifcheck());
}


syntax highlighted by Code2HTML, v. 0.9.1