comobj.c   [plain text]


/*
 * Copyright (c) 2010 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Portions of this software have been released under the following terms:
 *
 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
 *
 * To anyone who acknowledges that this file is provided "AS IS"
 * without any express or implied warranty:
 * permission to use, copy, modify, and distribute this file for any
 * purpose is hereby granted without fee, provided that the above
 * copyright notices and this notice appears in all source code copies,
 * and that none of the names of Open Software Foundation, Inc., Hewlett-
 * Packard Company or Digital Equipment Corporation be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  Neither Open Software
 * Foundation, Inc., Hewlett-Packard Company nor Digital
 * Equipment Corporation makes any representations about the suitability
 * of this software for any purpose.
 *
 * Copyright (c) 2007, Novell, Inc. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Novell Inc. nor the names of its contributors
 *     may be used to endorse or promote products derived from this
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @APPLE_LICENSE_HEADER_END@
 */

/*
**
**  NAME
**
**      comobj.c
**
**  FACILITY:
**
**      Remote Procedure Call (RPC)
**
**  ABSTRACT:
**
**  Definition of the Object Services for the Common Communication
**  Services component. These routines are called by an application
**  to register objects and object types with the runtime.
**
**
*/

#include <commonp.h>    /* Common declarations for all RPC runtime */
#include <com.h>        /* Public common communications services */
#include <comprot.h>    /* Common protocol services */
#include <comnaf.h>     /* Common network address family services */
#include <comp.h>       /* Private common communications services */

/*
 * the size of the object registry hash table
 * - pick a prime number to avoid collisions
 */
#define RPC_C_OBJ_REGISTRY_SIZE         31

/*
 *  The Object Registry Table, where object/type pairs
 *  are registered, and upon which the routines contained within
 *  this module perform their actions.  Protected by "obj_mutex".
 */
INTERNAL rpc_list_t obj_registry[RPC_C_OBJ_REGISTRY_SIZE] = { {0,0} };
INTERNAL rpc_mutex_t obj_mutex;

/*
 * an object registry list entry
 */
typedef struct
{
    rpc_list_t      link;
    idl_uuid_t          object_uuid;
    idl_uuid_t          type_uuid;
} rpc_obj_rgy_entry_t, *rpc_obj_rgy_entry_p_t;

/*
 * Function registered by applicationthrough rpc_object_set_inq_fn.
 */
INTERNAL rpc_object_inq_fn_t inq_fn = NULL;


/*
**++
**
**  ROUTINE NAME:       rpc__obj_init
**
**  SCOPE:              PRIVATE - declared in com.h
**
**  DESCRIPTION:
**
**  Initializes this module.
**
**  INPUTS:             none
**
**  INPUTS/OUTPUTS:     none
**
**  OUTPUTS:
**
**      status          The result of the operation.
**
**  IMPLICIT INPUTS:    none
**
**  IMPLICIT OUTPUTS:   none
**
**  FUNCTION VALUE:     void
**
**  SIDE EFFECTS:       none
**
**--
**/

PRIVATE void rpc__obj_init
(
    unsigned32                  *status
)
{
    CODING_ERROR (status);

    RPC_MUTEX_INIT (obj_mutex);
    *status = rpc_s_ok;
}

/*
**++
**
**  ROUTINE NAME:       rpc__obj_fork_handler
**
**  SCOPE:              PRIVATE - declared in com.h
**
**  DESCRIPTION:
**
**  Initializes this module.
**
**  INPUTS:             stage   The stage of the fork we are
**                              currently handling.
**
**  INPUTS/OUTPUTS:     none
**
**  OUTPUTS:            none
**
**  IMPLICIT INPUTS:    none
**
**  IMPLICIT OUTPUTS:   none
**
**  FUNCTION VALUE:     void
**
**  SIDE EFFECTS:       none
**
**--
**/

PRIVATE void rpc__obj_fork_handler
(
    rpc_fork_stage_id_t stage
)
{
    unsigned32 i;

    switch ((int)stage)
    {
        case RPC_C_PREFORK:
                break;
        case RPC_C_POSTFORK_PARENT:
                break;
        case RPC_C_POSTFORK_CHILD:

                inq_fn = NULL;

                /*
                 * Empty the Object Registry Table
                 */
                for (i = 0; i < RPC_C_OBJ_REGISTRY_SIZE; i++)
                {
                    obj_registry[i].next = NULL;
                    obj_registry[i].last = NULL;
                }
                break;
    }
}


/*
**++
**
**  ROUTINE NAME:       rpc_object_set_type
**
**  SCOPE:              PUBLIC - declared in rpc.idl
**
**  DESCRIPTION:
**
**  Register the type UUID of an object with the Common Communications
**  Service. This routine is used in conjunction with rpc_server_register_if
**  to allow a server to support multiple implementations of the same
**  interface for different object types. Registering objects is required
**  only when generic interfaces are declared (via "rpc_server_register_if").
**  The Common Communications Service will dispatch to a specific
**  implementation, contained in a manager Entry Point Vector, based on the
**  object UUID contained in the binding of the RPC. The Common Communications
**  Service, using the results of a call to this routine, will determine
**  the type UUID of the object. A manager EPV for this type UUID can
**  then be found using the results of a call to the rpc_server_register_if
**  routine.
**
**  INPUTS:
**
**      object_uuid     The object to be registered.
**
**      type_uuid       The type of the object.
**
**  INPUTS/OUTPUTS:     none
**
**  OUTPUTS:
**
**      status          A value indicating the status of the routine.
**
**          rpc_s_ok
**          rpc_s_coding_error
**          rpc_s_invalid_object
**          rpc_s_invalid_type
**
**  IMPLICIT INPUTS:    none
**
**  IMPLICIT OUTPUTS:   none
**
**  FUNCTION VALUE:     void
**
**  SIDE EFFECTS:       none
**
**--
**/

PUBLIC void rpc_object_set_type
(
    uuid_p_t                object_uuid,
    uuid_p_t                type_uuid,
    unsigned32              *status
)
{
    rpc_obj_rgy_entry_p_t   obj_entry;
    unsigned32              index;

    CODING_ERROR (status);
    RPC_VERIFY_INIT ();

    /*
     * check to see if this is a valid, non-null object UUIDs
     */
    if (UUID_IS_NIL (object_uuid, status))
    {
        *status = rpc_s_invalid_object;
        return;
    }

    if (*status != uuid_s_ok)
    {
        *status = rpc_s_invalid_object;
        return;
    }

    /*
     * compute a hash value using the object uuid - check the status
     * from uuid_hash to make sure the uuid has a valid format
     */
    index = (uuid_hash (object_uuid, status)) % RPC_C_OBJ_REGISTRY_SIZE;

    if (*status != uuid_s_ok)
    {
        return;
    }

    /*
     * take out a global lock on the object registry
     */
    RPC_MUTEX_LOCK (obj_mutex);

    /*
     * search the registry for a matching object
     */
    RPC_LIST_FIRST (obj_registry[index], obj_entry, rpc_obj_rgy_entry_p_t);

    while (obj_entry != NULL)
    {
        if (uuid_equal (&(obj_entry->object_uuid), object_uuid, status))
        {
            break;
        }

        RPC_LIST_NEXT (obj_entry, obj_entry, rpc_obj_rgy_entry_p_t);
    }

    /*
     * if the type UUID is the NIL UUID, remove the type entry
     * for this object if it exists(this is basically an "unregister")
     */
    if (UUID_IS_NIL(type_uuid, status))
    {
        /*
         * remove the object entry from the registry and free it
         */
        if (obj_entry != NULL)
        {
            RPC_LIST_REMOVE (obj_registry[index], obj_entry);
            RPC_MEM_FREE (obj_entry, RPC_C_MEM_OBJ_RGY_ENTRY);
        }
    }
    else
    {
        /*
         * this is a register - if no entry was found, create one
         */
        if (obj_entry == NULL)
        {
            RPC_MEM_ALLOC (
                obj_entry,
                rpc_obj_rgy_entry_p_t,
                sizeof (rpc_obj_rgy_entry_t),
                RPC_C_MEM_OBJ_RGY_ENTRY,
                RPC_C_MEM_WAITOK);

            /*
             * initialize the entry
             */
            obj_entry->object_uuid = *object_uuid;

            /*
             * put the object on the list for this hash index
             */
            RPC_LIST_ADD_TAIL
                (obj_registry[index], obj_entry, rpc_obj_rgy_entry_p_t);
        }
        else
        {
            /*
             * see if the type uuid matches the one specified
             */
            if (uuid_equal (&(obj_entry->type_uuid), type_uuid, status))
            {
                RPC_MUTEX_UNLOCK (obj_mutex);
                *status = rpc_s_already_registered;
                return;
            }
        }

        /*
         * set the type uuid for this object entry
         */
        obj_entry->type_uuid = *type_uuid;
    }

    RPC_MUTEX_UNLOCK (obj_mutex);
    *status = rpc_s_ok;
    return;
}

/*
**++
**
**  ROUTINE NAME:       rpc_object_inq_type
**
**  SCOPE:              PUBLIC - declared in rpc.idl
**
**  DESCRIPTION:
**
**  Consult the object registry for the specified object's type.  If
**  it is not found and the application has registered an inquiry function,
**  call it.  Otherwise, if object is not registered, the type returned
**  is nil_uuid.
**
**  Note: If a NULL value is passed for the type UUID argument the routine
**  will execute, but the type UUID will not be returned. This can be
**  useful to determine if an object is registered without requiring a
**  return value to be supplied.
**
**  INPUTS:
**
**      object_uuid     The object being looked up.
**
**  INPUTS/OUTPUTS:     none
**
**  OUTPUTS:
**
**      type_uuid       The type of the object.
**
**      status          A value indicating the status of the routine.
**
**          rpc_s_ok
**          rpc_s_object_not_found
**          rpc_s_coding_error
**
**  IMPLICIT INPUTS:    none
**
**  IMPLICIT OUTPUTS:   none
**
**  FUNCTION VALUE:     void
**
**  SIDE EFFECTS:       none
**
**--
**/

PUBLIC void rpc_object_inq_type
(
    uuid_p_t                object_uuid,
    idl_uuid_t                  *type_uuid,
    unsigned32              *status
)
{
    rpc_obj_rgy_entry_p_t   obj_entry;
    unsigned32              index;

    CODING_ERROR (status);
    RPC_VERIFY_INIT ();

    /*
     * lookups on nil objects return nil types
     */
    if (UUID_IS_NIL (object_uuid, status))
    {
        UUID_CREATE_NIL (type_uuid);
        *status = rpc_s_ok;
        return;
    }

    /*
     * compute a hash value using the object uuid - check the status
     * from uuid_hash to make sure the uuid has a valid format
     */
    index = uuid_hash (object_uuid, status) % RPC_C_OBJ_REGISTRY_SIZE;

    if (*status != uuid_s_ok)
    {
        return;
    }

    /*
     * take out a lock to protect access to the object registry
     */
    RPC_MUTEX_LOCK (obj_mutex);

    /*
     * search the table for the specified object UUID
     */
    RPC_LIST_FIRST (obj_registry[index], obj_entry, rpc_obj_rgy_entry_p_t);

    while (obj_entry != NULL)
    {
        if (uuid_equal (&(obj_entry->object_uuid), object_uuid, status))
        {
            /*
             * if a type uuid is wanted, return it
             */
            if (type_uuid != NULL)
            {
                *type_uuid = obj_entry->type_uuid;
            }

            RPC_MUTEX_UNLOCK (obj_mutex);
            *status = rpc_s_ok;
            return;
        }

        RPC_LIST_NEXT (obj_entry, obj_entry, rpc_obj_rgy_entry_p_t);
    }

    /*
     * If there's an application function to map object to type, call it now.
     * Ensure that a object_not_found failure returns the nil-type.
     */
    if (inq_fn != NULL)
    {
        RPC_MUTEX_UNLOCK (obj_mutex);
        (*inq_fn) (object_uuid, type_uuid, status);
        if (*status == rpc_s_object_not_found)
        {
            UUID_CREATE_NIL (type_uuid);
        }
        return;
    }

    UUID_CREATE_NIL (type_uuid);

    RPC_MUTEX_UNLOCK (obj_mutex);
    *status = rpc_s_object_not_found;
    return;
}

/*
**++
**
**  ROUTINE NAME:       rpc_object_set_inq_fn
**
**  SCOPE:              PUBLIC - declared in rpc.idl
**
**  DESCRIPTION:
**
**  Supply a function that is called by the runtime to determine the type
**  of objects that have not been set by "rpc_object_set_type".
**
**  INPUTS:
**
**      inq_fn          function that does the inquiry
**
**  INPUTS/OUTPUTS:     none
**
**  OUTPUTS:
**
**      status          A value indicating the status of the routine.
**
**  IMPLICIT INPUTS:    none
**
**  IMPLICIT OUTPUTS:   none
**
**  FUNCTION VALUE:     void
**
**  SIDE EFFECTS:       none
**
**--
**/

PUBLIC void rpc_object_set_inq_fn
(
    rpc_object_inq_fn_t     inq_fn_arg,
    unsigned32              *status
)
{
    CODING_ERROR (status);
    RPC_VERIFY_INIT ();

    inq_fn = inq_fn_arg;
    *status = rpc_s_ok;
}