/* * 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 /* Common declarations for all RPC runtime */ #include /* Public common communications services */ #include /* Common protocol services */ #include /* Common network address family services */ #include /* 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; }