/* @(#)07    1.14  src/examples/type_mgr/server_setup_object.c, examples.src, os2dce21.dss, 960602a.1 1/11/96 10:21:43 */
/*
 * COMPONENT_NAME:  examples.src
 *
 * FUNCTIONS:
 *
 * ORIGINS: 27
 *
 * (C) COPYRIGHT International Business Machines Corp. 1992, 1994
 * All Rights Reserved
 * Licensed Materials - Property of IBM
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *
 */

/*********************************************************************
 *  File      :  server_setup_object.c
 *********************************************************************
 *                                                                   *
 *  Functions :  server_setup_object()
 *                                                                   *
 *  Comments  :  Routines that control the manner in which a server  *
 *               process initializes itself, and exports information *
 *               to the name service and endpoint map.               *
 *                                                                   *
 *********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#ifdef IBMOS2
# include <os2def.h>
#endif
#include <dce/dce_error.h>
#include <dce/rpc.h>
#include "type_mgr.h"
#include "cust_if.h"
#include <util.h>
#include "server_object_db.h"
#include "server.h"
#include "server_util.h"


/*********************************************************************
 *   Function    :  server_setup()                                   *
 *********************************************************************
 *                                                                   *
 *   Description :  Initialize server process for the customer       *
 *                    object managament interface.                     *
 *                                                                   *
 *   Returns     :  (0) success, or appropriate error code.          *
 *                                                                   *
 *********************************************************************/

unsigned32
server_setup( void )
{
    unsigned32           status = SUCCESS, c_status;
    rpc_binding_vector_t *binding_vector_p;
    uuid_vector_t        obj_uuid_vector;
    char                 annotation[ENTRY_LEN];
    object_db_handle_t   object_db_context;

    TRACE("Starting Setup of Customer Interface\n");

    /*
     *  Build the type table.  This table contains all of the valid
     *  type uuids, which correspond to a management entry point vector.
     */

    g_type_table[0].name = g_type1_name;
    g_type_table[0].string_uuid = g_type1_uuid_str;

    uuid_from_string( g_type1_uuid_str,
              &g_type_table[0].uuid,
              &status );

    CHECK_STATUS( "uuid_from_string() [type 1]\n",
          status,
          RETURN );

    g_type_table[1].name = g_type2_name;
    g_type_table[1].string_uuid = g_type2_uuid_str;

    uuid_from_string( g_type2_uuid_str,
              &g_type_table[1].uuid,
              &status );

    CHECK_STATUS( "uuid_from_string() [type 2]\n",
          status,
          RETURN );

    /*
     *  register the type uuid and mepv for type 1.
     */

    rpc_server_register_if( type_mgr_v1_0_s_ifspec,
                            &g_type_table[0].uuid,
                            (rpc_mgr_epv_t) &type1_v1_0_manager_epv,
                            &status );

    CHECK_STATUS( "rpc_server_register_if() [type1]\n",
                  status,
                  RETURN );

    /*
     *  register the type uuid and mepv for type 2.
     */

    rpc_server_register_if( type_mgr_v1_0_s_ifspec,
                            &g_type_table[1].uuid,
                            (rpc_mgr_epv_t) &type2_v1_0_manager_epv,
                            &status );

    CHECK_STATUS( "rpc_server_register_if() [type2]\n",
                  status,
                  RETURN );


    /*
     *  The only protseq supported right now is Datagram (ncadg_ip_udp),
     *  but we'll register to use them all, so sometime in the future
     *  it will be able to handle clients over tcp/ip, etc...
     */

    rpc_server_use_all_protseqs( rpc_c_protseq_max_calls_default,
                                 &status );

    CHECK_STATUS( "rpc_server_use_all_protseqs()\n",
                  status,
                  RETURN );

    rpc_server_inq_bindings( &binding_vector_p,
                             &status );

    CHECK_STATUS( "rpc_server_inq_bindings()\n",
                  status,
                  RETURN );


    /*
     *  Read the object information from the local database, if it
     *  exists.  If so:
     *
     *    Inquire the object uuid from the namespace;
     *      Associate the object with a type in runtime;
     *      Register the {binding_vector_p X object_uuid} in the endpoint map.
     *
     */

    /*
     *  Since object_db_init is idempotent, it really doesn't matter
     *  if we call it from both the object setup and the admin setup.
     *  That is, it is better to call it than assume it has been called.
     */

    status = object_db_init();

    switch( status )
    {
        case OBJECT_DB_CREATED:
            status = SUCCESS;
            goto exit;
        case OBJECT_DB_INIT_UNDERWAY:
        case FAILURE:
            status = CODING_ERROR;
            goto exit;
        default:  /* OBJECT_DB_RESTARTED */
            break;
    }

    status = object_db_entry_inq_begin( &object_db_context );

    if( status != SUCCESS )
    {
        goto exit;
    }

    while( TRUE )
    {
        char  *object_name, *type_name, *object_entry_name;
        uuid_t object_uuid, type_uuid;

        status = object_db_entry_inq_next( &object_db_context,
                                           &object_name,
                                           &type_name );

    if( status == NO_MORE_ENTRIES )
    {
        status = SUCCESS;
        break;
    }

    if( status != SUCCESS )
    {
        free( object_name );
        free( type_name );
        goto exit;
    }

    TRACE("Setting up an existing object\n");

    /*
     *  Compose the object's full ns entry name.
     */

    status = ns_compose_object_entry_name( object_name,
                           &object_entry_name );

    if( status != SUCCESS )
    {
        free( object_name );
        free( type_name );
        goto exit;
    }

    /*
     *  Inquire the object uuid of the object name.  The actual
     *  ns entry name must be composed of the locally stored name
     *  and the installation defined (type_mgr.h) ns directory
     *  path.  The ns_get_object_uuid utility handles this.
     */

    status = ns_get_object_uuid( object_name, &object_uuid );

    /*
     *  There is a possibility that the object was deleted
     *  from the namespace but not the database (either
     *  via explicit DCE admin command or the fact that
     *  persistent database deletes may lag the tm_admin
     *  object deletion and not be completed prior to a
     *  server crash).
     */

    if( status != SUCCESS )
    {
        /*
         *  Should at least log this.  Some possibilities of additional
         *  action are to delete the object from the persistent
         *  database (pessimistic) or reexport the object back into
         *  the name space (optimistic).  At the moment, we do
         *  nothing.
         */

        free( object_name );
        free( type_name );
        free( object_entry_name );
        continue;
    }

    /*
     *  Associate the object uuid with a type uuid.
     *  Note that when an object UUID is associated with a type UUID,
     *  all you are doing is making the association in the RPC runtime.
     *  Neither object is altered in any way.
     */

    status = type_uuid_from_type_name( type_name, &type_uuid );

    /*
     * Should not have any bad types at this point.
     */

    if( status != SUCCESS )
    {
        free( object_name );
        free( type_name );
        free( object_entry_name );
        goto exit;
    }

        rpc_object_set_type( &object_uuid,
                 &type_uuid,
                             &status );

        CHECK_STATUS( "rpc_object_set_type()\n",
                      status,
                      RETURN );

    /*
     *  Register an endpoint that contains all of the currently existing
     *  object uuids.  These are the objects that the client will actually
     *  use when it wants to bind to the server process.
     *
     *  The objects' uuids could have been loaded into a uuid vector,
         *  and registered all in one go.  There is no functional
         *  difference between registering them all at once or one at
         *  a time.  The reason why these are added one at a time is
         *  so a unique annotation string can be added with each object
         *  that is registered.
         */

        sprintf( annotation,
         "Example Type Manager [ %s %s ]",
         object_name,
         type_name );

        obj_uuid_vector.count = 1 ;
        obj_uuid_vector.uuid[0] = &object_uuid;

        rpc_ep_register( type_mgr_v1_0_s_ifspec,
                         binding_vector_p,
                         &obj_uuid_vector,
                         (unsigned_char_t *) annotation,
                         &status );

    /*
     * really want to free the alloc'd storage and head for
     * the cleanup routines.
     */

        CHECK_STATUS( "rpc_ep_register()\n",
                      status,
                      RETURN );


    /*
     *  Re-export the binding information for the object into the
     *  objects NS entry. This call will add new bindings
     *  to the entry if they are different from the existing
     *  one(s).  An example of this would be the addition of
     *  a network interface on a server.  Old binding handles,
     *  that is, ones in the namespace but not in the binding
     *  vector, are NOT deleted.  Deleting unreachable bindings
     *  would be a nice feature to add here.
     */

    rpc_ns_binding_export( rpc_c_ns_syntax_default,
               object_entry_name,
               type_mgr_v1_0_s_ifspec,
               binding_vector_p,
               &obj_uuid_vector,
               &status );

    /*
     * really want to free the alloc'd storage and head for
     * the cleanup routines.
     */

        CHECK_STATUS( "rpc_ns_binding_export()\n",
                      status,
                      RETURN );

    /*
     *  Normal end of loop cleanup.
     */

    free( object_name );
    free( type_name );
    free( object_entry_name );

    } /* while( TRUE ) */

    status = object_db_entry_inq_done( &object_db_context );

 exit:
    /*
     *  Cleanup under error condition based on progress flags.
     */
    if( status != SUCCESS )
    {
    ;
    }

    /*
     * Cleanup routines use their own status to avoid corrupting
     * the actual setup status.
     */

    /*
     *  Free up the binding vector that was returned to us previously.
     */

    rpc_binding_vector_free( &binding_vector_p,
                             &c_status );

    CHECK_STATUS( "rpc_binding_vector_free()\n",
                  c_status,
                  RETURN );

    TRACE("Customer interface has been setup successfully\n");
    return( status );

} /* end server_setup() */

/*  server_setup_object.c */

