/*

  silcprotocol.h
 
  Author: Pekka Riikonen <priikone@silcnet.org>
 
  Copyright (C) 1997 - 2005 Pekka Riikonen
 
  The contents of this file are subject to one of the Licenses specified 
  in the COPYING file;  You may not use this file except in compliance 
  with the License.
 
  The software distributed under the License is distributed on an "AS IS"
  basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
  KIND, either expressed or implied.  See the COPYING file for more
  information.

*/

/****h* silccore/SILC Protocol Interface
 *
 * DESCRIPTION
 *
 * Implementation of the protocol handling routines for SILC applications.
 * These routines allow execution of arbitrary protocols in the application.
 * New protocols may be registered by type and allocated later by that
 * type for the execution. The protocols implements a state machine style
 * execution where each state is executed one after the other. The
 * application controls these states and their order of execution.
 * 
 * After the protocol has been executed, an final callback is called
 * which the application may use to do post-protocol work or to start
 * perhaps other protocols. These routines are generic and the actual
 * protocols, their types, callback and final callbacks functions must
 * be implemented in the application.
 *
 ***/

#ifndef SILCPROTOCOL_H
#define SILCPROTOCOL_H

/****d* silccore/SilcProtocolAPI/SilcProtocolType
 *
 * NAME
 * 
 *    typedef unsigned char SilcProtocolType;
 *
 * DESCRIPTION
 *
 *    Protocol type definition. The protocol types are application
 *    specific and this is just a generic type for them.
 *
 ***/
typedef unsigned char SilcProtocolType;

/****d* silccore/SilcProtocolAPI/SilcProtocolState
 *
 * NAME
 * 
 *    typedef unsigned char SilcProtocolState;
 *
 * DESCRIPTION
 *
 *    Protocol state definition and the defined protocol states. These
 *    states are the generic states. However, each protocol actually
 *    implements the states. The state after SILC_PROTOCOL_STATE_START
 *    would be state 2 in the application. These states can be easily
 *    used for example inside switch() statement.
 *
 * EXAMPLE
 *
 *    switch (protocol->state) {
 *    case SILC_PROTOCOL_STATE_START:
 *      protocol_starts_here();
 *    case 2:
 *      ...
 *    case 3:
 *      ...
 *    case SILC_PROTOCOL_STATE_END:
 *      protocol_ends_here();
 *    case SILC_PROTOCOL_STATE_FAILURE:
 *      remote_end_sent_failure();
 *    case SILC_PROTOCOL_STATE_ERROR:
 *      local_error_during_protocol();
 *    }
 *
 * SOURCE
 */
typedef unsigned char SilcProtocolState;

/* Protocol states. Do NOT change the values of these states, especially
   the START state or you break every protocol. */
#define SILC_PROTOCOL_STATE_UNKNOWN 0
#define SILC_PROTOCOL_STATE_START 1
#define SILC_PROTOCOL_STATE_END 252
#define SILC_PROTOCOL_STATE_FAILURE 253	 /* Received failure from remote */
#define SILC_PROTOCOL_STATE_ERROR 254    /* Local error at our end */
/***/

/* Type definition for authentication protocol's auth methods. */
/* XXX strictly speaking this belongs to application */
typedef unsigned char SilcProtocolAuthMeth;

/****f* silccore/SilcProtocolAPI/SilcProtocolCallback
 *
 * SYNOPSIS
 *
 *    typedef SilcTaskCallback SilcProtocolCallback;
 *
 * DESCRIPTION
 *
 *    Protocol callback. This callback is set when registering new
 *    protocol. The callback is called everytime the protocol is executed.
 *    The `context' delivered to this callback function is the SilcProtocol
 *    context and needs to be explicitly type casted to SilcProtocol in
 *    the callback function.
 *
 ***/
typedef SilcTaskCallback SilcProtocolCallback;

/****f* silccore/SilcProtocolAPI/SilcProtocolFinalCallback
 *
 * SYNOPSIS
 *
 *    typedef SilcTaskCallback SilcProtocolFinalCallback;
 *
 * DESCRIPTION
 *
 *    Final protocol callback. This callback is set when allocating
 *    protocol for execution. This is called when the protocol has ended.
 *    The `context' delivered to this callback function is the SilcProtocol
 *    context and needs to be explicitly type casted to SilcProtocol in
 *    the callback function.
 *
 ***/
typedef SilcTaskCallback SilcProtocolFinalCallback;

/****s* silccore/SilcProtocolAPI/SilcProtocolObject
 *
 * NAME
 * 
 *    typedef struct SilcProtocolObjectStruct { ... } SilcProtocolObject;
 *
 * DESCRIPTION
 *
 *    The object for one protocol. This hold the information of one
 *    registered protocol. Application must not allocate this type
 *    directly. It is used by the protocol routines.
 *
 *    Short description of the field following:
 *  
 *    SilcProtocolType type
 *
 *      Protocol type.
 * 
 *    SilcProtocolCallback callback;
 *
 *      Callback function for the protocol. This is SilcTaskCallback function
 *      pointer as the protocols in SILC are executed as timeout tasks.
 *
 *    struct SilcProtocolObjectStruct *next;
 *
 *      Pointer to the next protocol.
 *
 ***/
typedef struct SilcProtocolObjectStruct {
  SilcProtocolType type;
  SilcProtocolCallback callback;
  struct SilcProtocolObjectStruct *next;
} SilcProtocolObject;

/****s* silccore/SilcProtocolAPI/SilcProtocol
 *
 * NAME
 * 
 *    typedef struct SilcProtocolStruct { ... } *SilcProtocol;
 *
 * DESCRIPTION
 *
 *    The actual protocol object. This is allocated by the silc_protocol_alloc
 *    and holds the information about the current protocol. Information
 *    such as the current state, execution callback and final callback.
 *    The context is freed by silc_protocol_free function.
 *
 *    Short description of the field following:
 *
 *    SilcProtocolObject *protocol
 *
 *      This is the pointer to the SilcProtocolObject and holds the
 *      protocol specific information.
 *
 *    SilcProtocolState state
 *
 *      Protocol state. The state of the protocol can be changed in the
 *      callback function.
 *
 *    void *context
 *
 *      Context to be sent for the callback function. This is usually 
 *      object for either SILC client or server. However, this abstraction 
 *      makes it possible that this pointer could be some other object as
 *      well. Note that the context is not delivered in any callback 
 *      function. Application can access it through this context.
 *
 *    SilcProtocolFinalCallback final_callback;
 *
 *      This is a callback function that is called with timeout _after_ the
 *      protocol has finished or error occurs. If this is NULL, naturally 
 *      nothing will be executed. Protocol should call this function only at 
 *      SILC_PROTOCOL_STATE_END and SILC_PROTOCOL_STATE_ERROR states.
 *
 ***/
typedef struct SilcProtocolStruct {
  SilcProtocolObject *protocol;
  SilcProtocolState state;
  void *context;
  SilcProtocolFinalCallback final_callback;
} *SilcProtocol;

/* Prototypes */

/****f* silccore/SilcProtocolAPI/silc_protocol_register
 *
 * SYNOPSIS
 *
 *    void silc_protocol_register(SilcProtocolType type,
 *                                SilcProtocolCallback callback);
 *
 * DESCRIPTION
 *
 *    Dynamically registers new protocol. The protocol is added into protocol
 *    list and can be unregistered with silc_protocol_unregister. The
 *    `type' is the type of the protocol and is used to identify the
 *    protocol when allocating it with silc_protocol_alloc. The `callback'
 *    is the actual protocol function that is called when protocol is
 *    executed (and it performes the actual protocol). The protocol
 *    is unregistered by silc_protocol_unregister function.
 *
 ***/
void silc_protocol_register(SilcProtocolType type,
			    SilcProtocolCallback callback);

/****f* silccore/SilcProtocolAPI/silc_protocol_unregister
 *
 * SYNOPSIS
 *
 *    void silc_protocol_unregister(SilcProtocolType type,
 *                                  SilcProtocolCallback callback);
 *
 * DESCRIPTION
 *
 *    Unregisters protocol. The unregistering is done by both protocol type
 *    and the protocol callback. Every registered protocol must be 
 *    unregistered using this function.
 *
 ***/
void silc_protocol_unregister(SilcProtocolType type,
                              SilcProtocolCallback callback);

/****f* silccore/SilcProtocolAPI/silc_protocol_alloc
 *
 * SYNOPSIS
 *
 *    void silc_protocol_alloc(SilcProtocolType type, 
 *                             SilcProtocol *new_protocol,
 *                             void *context, 
 *                             SilcProtocolFinalCallback callback);
 *
 * DESCRIPTION
 *
 *    Allocates a new protocol. The new allocated and initialized 
 *    protocol is returned to the `new_protocol' argument. The argument
 *    context `context' is the context to be sent as argument for the
 *    protocol callback function. The `callback' argument is the function
 *    to be called after the protocol has finished.
 *
 ***/
void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
			 void *context, SilcProtocolFinalCallback callback);

/****f* silccore/SilcProtocolAPI/silc_protocol_free
 *
 * SYNOPSIS
 *
 *    void silc_protocol_free(SilcProtocol protocol);
 *
 * DESCRIPTION
 *
 *    Frees the protocol context. This must be called for all allocated
 *    protocols.
 *
 ***/
void silc_protocol_free(SilcProtocol protocol);

/****f* silccore/SilcProtocolAPI/silc_protocol_execute
 *
 * SYNOPSIS
 *
 *    void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
 *                               long secs, long usecs);
 *
 * DESCRIPTION
 *
 *    Executes the protocol. This calls the state that has been set.
 *    The state must be set before calling this function. This is then
 *    also used to call always the next state after changing the state
 *    of the protocol. The `schedule' is the application's scheduler.
 *    It is passed to the protocol callback functions. The `secs' and 
 *    `usecs' are the timeout before the protocol is executed. If both 
 *    zero the protocol is executed immediately.
 *
 ***/
void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
			   long secs, long usecs);

/****f* silccore/SilcProtocolAPI/silc_protocol_execute_final
 *
 * SYNOPSIS
 *
 *    void 
 *    silc_protocol_execute_final(SilcProtocol protocol, 
 *                               SilcSchedule schedule);
 *
 * DESCRIPTION
 *
 *    Executes the final callback for the protocol. The `schedule' is
 *    the application's scheduler.. It is passed to the protocol callback
 *    functions. The final callback is executed immediately.
 *
 ***/
void silc_protocol_execute_final(SilcProtocol protocol, SilcSchedule schedule);

/****f* silccore/SilcProtocolAPI/silc_protocol_cancel
 *
 * SYNOPSIS
 *
 *    void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule);
 *
 * DESCRIPTION
 *
 *    Cancels the execution of the next state of the protocol. This has
 *    effect only if the silc_protocol_execute was called with timeout.
 *    It is guaranteed that if the protocol is cancelled before the timeout
 *    has elapsed the protocol callback won't be called.
 *
 ***/
void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule);

#endif
