Cobalt Configuration Client Library
$Id: CeeCee3.spec.txt,v 1.1 2000/03/16 00:23:27 jmayer Exp $
Copyright Cobalt Networks 2000.

OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE                                                       OBSOLETE
OBSOLETE              This document is obsolete.               OBSOLETE
OBSOLETE            see ClientLib.spec.txt instead.            OBSOLETE
OBSOLETE                                                       OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE
OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE OBSOLETE

0. Contents
1. Name
2. Terms
3. Overview
 3.1 Low Level Overview
 3.2 Mid Level Overview
 3.3 High Level Overview

Appendix
  1. Objects.
  2. Functions.

1. Name

  CCC Lib: Cobalt Configuration Client Library.
  
  It's a silly name, but it disambiguates nicely from everything else
  in CCE.

  In terms of name space this library lives in cce_* as it is the only library
  that will be directly accessed by the end user.

2.0 Terms

  Client:
    A program using the library to request or change information.

  Actuator, Handler:
    A program being called by CCE to effect a change.

3.0 Overview

  The CCC Lib provides a simplified API to access the CCE back end.  Direct
  access to the CSCP commands is provided, along with a set of toolkit
  functions that simplify common configuration tasks.
  
  The CCC Lib is meant to be used for all communications with the CCE
  library (ie. communication from either user interface clients or from
  event handler clients).

/**
  The general overview of cce interaction from the point of view of a client
  or an actuator is for the most part a process of generating a
  command/request (struct CscpLine) which is passed to the CCE, the results
  are then parsed into a result (struct CscpResult) and returned to the user.
  
  All interaction is done through a CceConnection object which provides little
  more than the connection to the socket and the state of the connection.
  
  Once the connection has been created it is assumed that all CCE data will
  only come in response to an client request. Out of bounds data will have to
  wait until later. CSCP spec seems to say that the only data that is sent
  without client request is the version string.
  
  A higher level library is built on top of this V. basic protocol level
  one (Which will still be exposed to the end user.). Levels basically
  devolve from the highest level to the lowest in terms of knowledge of
  the underling system and evolve in the other direction in terms of
  flexibility.  All three levels should be exposed.
**/

3.1 Low Level API

  The low level of the c6 library gives direct access to the CSCP 
  protocol and response.

  Four data structures are introduced:
    cscp_conn_t  - a handle for the connection to the back end
    cscp_cmnd_t  - a cscp command, in parsed format
    cscp_resp_t - a cscp command response
    cscp_line_t - a line of a cscp command response
    
  Functions for manipulating the cscp_conn_t structure:
    cscp_conn_t * cscp_conn_new(void);
    void          cscp_conn_destroy(cscp_conn_t *);
    int           cscp_conn_auth(cscp_conn_t*, char *username, char *password);
    cscp_resp_t * cscp_conn_do(cscp_conn_t*, cscp_cmnd_t*);
    int           cscp_conn_poll(cscp_conn_t*);
	/* Checks to see if the connection is ready for more commands */
	int           cscp_conn_is_finished(cscp_conn_t*);
    
  (cscp_conn_poll is used to poll for asynchronous messages in Status state,
   as well as being used internally to fetch results.)

  Functions for manipulating the cscp_cmnd_t structure:
    cscp_cmnd_t * cscp_cmnd_new();
    void         cscp_cmnd_destroy(cscp_cmnd_t*);
    void         cscp_cmnd_setcmnd(cscp_cmnd_t*, int cmnd);
    int          cscp_cmnd_getcmnd(cscp_cmnd_t*);
    void         cscp_cmnd_addscalar(cscp_cmnd_t*, cce_scalar *scalar); /*copy*/
    void         cscp_cmnd_addstr(cscp_cmnd_t*, char *str); /*copy*/
    cce_scalar * cscp_cmnd_getparam(cscp_cmnd_t*, int pos);
    int          cscp_cmnd_getnumparams(cscp_cmnd_t*);
	char *       cscp_cmnd_serialise(cscp_cmnd_t*);

  Functions for manipulating the cscp_resp_t structure:
    cscp_resp_t * cscp_resp_new();
    void          cscp_resp_destroy(cscp_resp_t*);
    int           cscp_resp_add_line( cscp_resp_t *t, cscp_line_t *t);
    int           cscp_resp_is_success(cscp_resp_t*);
	void          cscp_resp_rewind(cscp_resp_t*);
    cscp_line_t * cscp_resp_nextline(cscp_resp_t*);
	cscp_line_t * cscp_resp_lastline(cscp_resp_t*);
	int           cscp_resp_is_finished(cscp_resp_t *);

  Functions for manipulating the cscp_line_t structure:
    cscp_line_t * cscp_line_new();
    void          cscp_line_destroy(cscp_line_t*);
    int           cscp_line_parse(cscp_line_t*, char*);
    int           cscp_line_getcode(cscp_line_t*);
    char*         cscp_line_getparam(cscp_line_t*,int pos);

  Notes:
  
    Style rule 1: prefer copy over reference.  For example, in 
      cscp_cmnd_addscalar, add a copy of the scalar object to the
      cmnd object, rather than reference the original.  The tradeoff
      is that we're sacrificing some memory consumption for
      much simpler memory management (one pointer for each data).

  Example of use:
  
    cscp_conn_t *con;
    cscp_cmnd_t *cmnd;
    cscp_resp_t *resp;
    
    /* connect and authenticate */
    con = cscp_conn_new();
    if (!cscp_conn_auth(con, username, password)) {
      ... failed to connect/authenticate ...
    }
    
    /* construct a set command */
    cmnd = cscp_cmnd_new();
    cscp_cmnd_setcmnd(cmnd, CSCP_CMD_SET);
    cscp_cmnd_addstr(cmnd, "00000001");
    cscp_cmnd_addstr(cmnd, "property");
    cscp_cmnd_addscalar(cmnd, value_sc);
    
    /* execute command */
    resp = cscp_conn_do (con, cmnd);
    
    /* evaluate response */
    if (!cscp_resp_is_success(resp)) {
      ... handle failure ...
    }
  

3.2 Protocol Level API ("Mid Level")

  This middle level of the library provides wrappers around the low-level
  functions to implement the CSCP protocol.  There is more or less a
  1:1 mapping of CSCP commands to Protocol Level functions.
  
  The set of protocol level functions is defined here.  In general,
  functions that return type "int" return a 0 for success, and some
  negative number to indicate some command-specific failure condition.
  
  int cce_auth_cmnd(cscp_conn_t*, char *username, char *password);
  int cce_bye_cmnd(cscp_conn_t*);

  int cce_new_cmnd(cscp_conn_t*, char *class, cce_oid *oid);

  int cce_destroy_cmnd(cscp_conn_t*, cce_oid *oid, char *property);

  int cce_set_cmnd(cscp_conn_t*, cce_oid *oid, char *prop, char *val);
    NOTE: if val is NULL, this is equivalent to the unset fn. 

  int cce_unset_cmnd(cscp_conn_t*, cce_oid *oid, char *prop);

  int cce_touch_cmnd(cscp_conn_t*, cce_oid *oid, char *prop);

  int cce_listadd_cmnd(cscp_conn_t*, cce_oid *oid, char *prop, cce_oid *oid2);
  int cce_listadd_before_cmnd(cscp_conn_t*, 
      cce_oid *oid, char *prop, cce_oid *newoid, cce_oid *beforeoid);
  int cce_listadd_after_cmnd(cscp_conn_t*, 
      cce_oid *oid, char *prop, cce_oid *newoid, cce_oid *afteroid);

  int cce_listrm_cmnd (cscp_conn_t*, cce_oid *oid, char *prop, cce_oid *rmoid);
  
  int cce_begin_cmnd(cscp_conn_t*, int lock);

  int cce_commit_cmnd(cscp_conn_t*, cscp_txn_id_t* txn_id);

  int cce_check_cmnd(cscp_conn_t*, cscp_txn_id_t* txn_id);

  int cce_cancel(cscp_conn_t*, cscp_txn_id_t* txn_id);
    if txn_id is NULL, the current transaction is canceled.

  int cce_lock(cscp_conn_t*, time_t timeout, GSList *oids);
  int cce_unlock(cscp_conn_t, cce_oid *oid);
    if oid is NULL, all locked objects are unlocked.

  int cce_find_cmnd(cscp_conn_t*, cce_oid *from, cce_criteria*, 
    char *report, int start, int stop);

    Runs the actual find command, but the results are cached
    inside the cscp_conn_t object.
    If "from" is NULL, the whole object database is searched.
    returns 0 on failure, else returns number of objects that matched.

  int cce_list_cmnd(cscp_conn_t*, cce_oid *oid, char *prop, 
    char *report, int start, int stop);

    Runs the actual list command, but the results are cached
    inside the cscp_conn_t object.

  int cce_result_first(cscp_conn_t*, cce_oid *oid, GSList *params);
  int cce_result__next(cscp_conn_t*, cce_oid *oid, GSList *params);
    These two funtions are used to iterate through the results of the
    most recent find or list command.

  int cce_oidof_cmnd(cscp_conn_t*, char *objectpath, cce_oid *oid);  

  int cce_get_cmnd(cscp_conn_t*, cce_oid *oid, char *prop, char **result);
  
  int cce_bg_cmnd(cscp_conn_t*);

  int cce_whoami_cmnd(cscp_conn_t*, char **username);
  int cce_mychanges_cmnd(cscp_conn_t*, GSList *changes);
  int cce_allchanges_cmnd(cscp_conn_t*, GSList *changes);
  int cce_info_cmnd(cscp_conn_t*, char *text);
  int cce_warn_cmnd(cscp_conn_t*, char *text);
  int cce_log_cmnd(cscp_conn_t*, char *text);
  int cce_success_cmnd(cscp_conn_t*); /* EXIT OK */
  int cce_reschedule_cmnd(cscp_conn_t*); /* EXIT RESCHEDULE */
  int cce_fail_cmnd(cscp_conn_t*); /* EXIT FAIL */

  MISSING COMMANDS:
    classlist - more thinking required here
    type - not a high priority
    
3.3 High Level Overview

  The very highest level functions are bassically macros that are
  independant of the underlying protocol and data organisation
  completely. They include such behemoths as "add user". They are
  analogous to the current functions that exist in special sauce. Except
  that there will be far less of them (4 or so.)

  cce_adduser(char *username, char *firstname, char *lastname, ... );
  cce_rmuser(char *username);
  cce_addsite(...)
  cce_rmsite(...)
  cce_addgroup(...)
  cce_rmgroup(...)

  These functions should make object manipulations more intuitive, and
  remove the overhead of having to do memory mgmt in php3:
  
        cce_object * cce_object_fetch (cce_conn_t*, char *object-path);
                - finds the OID specified by object-path
                - makes sure the OID is valid
                - if this object has already been fetched, return
                  a pointer to the existing cce_object object.
                  Otherwise, create a new cce_object object that
                  contains the OID, a ref to the cce_conn_t* thing,
                  and an empty data cache.

        cce_object * cce_object_create (cce_conn_t*, char *class);
                - performs a NEW operation
                - fetches the newly created object.

        char * cce_object_get(cce_object *, char *prop);
                - if property has already been read, return a ptr to
                  the internally cached string.
                - if it hasn't been read, read it from the CODB and
                  cache it in the cce_object object.

        int cce_object_set(cce_object *, char *prop, char *val);
                - pretty self-explanitory
                - performs the CSCP "set" command.

        int cce_object_list(cce_object *, char *prop, GSList *objects);
                - equivalent to a "cce_object_fetch" one every object
                  referenced by the list property.
                - the cce_object objects are returned in a GSList
                  container.

        int cce_object_listadd(cce_object *, char *prop,
                cce_object *addme);
        int cce_object_listadd_before(cce_object *, char *prop,
                cce_object *addme, cce_object *beforeme);
        int cce_object_listadd_after(cce_object *, char *prop,
                cce_object *addme, cce_object *afterme);

        int cce_object_unlink(cce_object *, char *prop,
                cce_object *killme);

APPENDIX 1 Objects

Objects should be opaque to the end user.

/**
 *
 * Object Handle
 *
 * The object handle is probably going to be the main handle to be used.
 */
struct CceObj {
	cscp_conn_t *conn; /* Pointer to our parent connection here for
	                    * convenience may not be used FIXME: decide */
	GHashTable *attributes; /* The objects attributes */
	int state; /* Is the object fresh from the db or have we changed it. */
}

/**
 * CCE Connection
 *
 * This object is created to hold the connection, handle tear up and tear
 * down, authentication is included in the tear up state.
 *
 * All operations to do with actual communication with CCE will go through
 * here.
 */
struct CceConn {
	enum state; /* Current state */
	int version[2]; /* Protocol Version */
	int socket; /* Actual socket connection */
	cscp_resp_t *resp; /* The last received response */
	int txn; /* Current transaction number */
}

/**
 * CSCP Command
 *
 * This is a struct form of a CSCP command. Bassically just the command
 * type and a list of args.
 *
 */
struct CscpCmnd {
	char  *cmnd;
	GList *args;
}

/**
 *
 * CSCP Line
 *
 * This is just a single line returned by the CCE. A numerical code
 * and a linked list of following data.
 *
 * Args is a linked list of strings generated by splitting on spaces all the
 * argument to this line.
 *
 */
struct CscpLine {
  int code;
  GSList *args;
}

/**
 *
 * CCE Response
 *
 * A final boolean result for convenience.
 * A linked list of all warning message, one for informational,
 * and one list for them all. All point to the same set of messages.
 *
 * Warn and info GSList are just for convenience, possibly to be removed.
 *
 */
typedef CscpResp {
	int result; /* True for success, false for failure */
	GSList *messages; /* Linked list of all messages */
	GSList *curr; /* Pointer to where the user is currently in the list
                   * see cscp_resp_nextline(); */
	cscp_line_t *result; /* Final success or failure line ((2|4)???) */
}
