Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
Copyright (C) 2000, 2001  Internet Software Consortium.
See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.

$Id: dispatch,v 1.6 2004/03/05 05:04:46 marka Exp $

UDP receive:

/*
 * General flow:
 *
 * If I/O result == CANCELED, free the buffer and notify everyone as
 * the various queues drain.
 *
 * If I/O is error (not canceled and not success) log it, free the buffer,
 * and restart.
 *
 * If query:
 *	if no listeners: free the buffer, restart.
 *	if listener: allocate event, fill in details.
 *		If cannot allocate, free buffer, restart.
 *	if rq event queue is not empty, queue.  else, send.
 *	restart.
 *
 * If response:
 *	Allocate event, fill in details.
 *		If cannot allocate, free buffer, restart.
 *	find target.  If not found, free buffer, restart.
 *	if event queue is not empty, queue.  else, send.
 *	restart.
 */


UDP restart:

/*
 * If too many recv()'s are already running, just return.
 *
 * If noone is attached to us, just return.
 *
 * Allocate a new buffer to receive into.
 * If no more buffers:
 *	If there are buffers handed out: wait for one to come back.
 *	If there are no buffers handed out:
 *		If there are responses attached to us, just return.
 *		If there are queries only, send one an error event.
 *
 *
 * start recv() on socket.  If this fails:
 *	Free buffer.
 *	Set dispatch state to "shutting down" and why to "socket error"
 *	Start failsafe shutdown.
 */


Adding a response:

/*
 * If shutting down, return error.
 *
 * Allocate an unique messageid and return it.  If none can be allocated,
 * return that.
 *
 * Allocate a new structure and fill it in.  If no memory, return that.
 *
 * Insert into the correct linked list.
 *
 * If the receiver is not running, try to start it.
 */

Adding a request:

/*
 * If shutting down, return error.
 *
 * Allocate new structure and fill it in.  If no memory, return that.
 *
 * Insert it into the linked list.
 *
 * If the incoming query packet queue is not empty, pull an item off and
 * send that event to this task.
 *
 * If the receiver is not running, try to start it.
 */

Detaching a response:

/*
 * decrement dispatch reference count by one.  If zero, remember to kill it
 * later.
 *
 * unlink the response from the hashed list.
 *
 * Free any buffers and events attached to the response structure.
 *
 * Free the response structure.
 *
 * If an event is also being returned, jump to "internal event free" below.
 *
 * If the ref count became zero above, destroy this dispatch fully, and return.
 *
 * If the receiver is not running, try to start it.
 */

Detaching a request:

/*
 * decrement dispatch ref count by one.  If zero, remember to kill it later.
 *
 * unlink from the request list.
 *
 * Free the response structure.
 *
 * If an event is also being returned, jump to "internal event free" below.
 *
 * If the ref count became zero above, destroy the dispatch fully, and return.
 *
 * If the receiver is not running, try to start it.
 */

Internal event free (from library space):

/*
 * If it is the failsafe event, send it to the next response/request on the
 * dispatcher, and return.
 *
 * Free buffer.
 *
 * Free event.
 */

Returning an event (from application space):

/*
 * If it is the failsafe event, die.
 *
 * Free associated buffer.
 *
 * Free event.
 *
 * If response:  do next response on this response's queue, if any.
 * If request:  do next request on this dispatcher's queue, if any.
 *
 * If the receiver is not running, try to start it.
 */

