1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**
79**  NAME
80**
81**      comobj.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  Definition of the Object Services for the Common Communication
90**  Services component. These routines are called by an application
91**  to register objects and object types with the runtime.
92**
93**
94*/
95
96#include <commonp.h>    /* Common declarations for all RPC runtime */
97#include <com.h>        /* Public common communications services */
98#include <comprot.h>    /* Common protocol services */
99#include <comnaf.h>     /* Common network address family services */
100#include <comp.h>       /* Private common communications services */
101
102/*
103 * the size of the object registry hash table
104 * - pick a prime number to avoid collisions
105 */
106#define RPC_C_OBJ_REGISTRY_SIZE         31
107
108/*
109 *  The Object Registry Table, where object/type pairs
110 *  are registered, and upon which the routines contained within
111 *  this module perform their actions.  Protected by "obj_mutex".
112 */
113INTERNAL rpc_list_t obj_registry[RPC_C_OBJ_REGISTRY_SIZE] = { {0,0} };
114INTERNAL rpc_mutex_t obj_mutex;
115
116/*
117 * an object registry list entry
118 */
119typedef struct
120{
121    rpc_list_t      link;
122    idl_uuid_t          object_uuid;
123    idl_uuid_t          type_uuid;
124} rpc_obj_rgy_entry_t, *rpc_obj_rgy_entry_p_t;
125
126/*
127 * Function registered by applicationthrough rpc_object_set_inq_fn.
128 */
129INTERNAL rpc_object_inq_fn_t inq_fn = NULL;
130
131
132/*
133**++
134**
135**  ROUTINE NAME:       rpc__obj_init
136**
137**  SCOPE:              PRIVATE - declared in com.h
138**
139**  DESCRIPTION:
140**
141**  Initializes this module.
142**
143**  INPUTS:             none
144**
145**  INPUTS/OUTPUTS:     none
146**
147**  OUTPUTS:
148**
149**      status          The result of the operation.
150**
151**  IMPLICIT INPUTS:    none
152**
153**  IMPLICIT OUTPUTS:   none
154**
155**  FUNCTION VALUE:     void
156**
157**  SIDE EFFECTS:       none
158**
159**--
160**/
161
162PRIVATE void rpc__obj_init
163(
164    unsigned32                  *status
165)
166{
167    CODING_ERROR (status);
168
169    RPC_MUTEX_INIT (obj_mutex);
170    *status = rpc_s_ok;
171}
172
173/*
174**++
175**
176**  ROUTINE NAME:       rpc__obj_fork_handler
177**
178**  SCOPE:              PRIVATE - declared in com.h
179**
180**  DESCRIPTION:
181**
182**  Initializes this module.
183**
184**  INPUTS:             stage   The stage of the fork we are
185**                              currently handling.
186**
187**  INPUTS/OUTPUTS:     none
188**
189**  OUTPUTS:            none
190**
191**  IMPLICIT INPUTS:    none
192**
193**  IMPLICIT OUTPUTS:   none
194**
195**  FUNCTION VALUE:     void
196**
197**  SIDE EFFECTS:       none
198**
199**--
200**/
201
202PRIVATE void rpc__obj_fork_handler
203(
204    rpc_fork_stage_id_t stage
205)
206{
207    unsigned32 i;
208
209    switch ((int)stage)
210    {
211        case RPC_C_PREFORK:
212                break;
213        case RPC_C_POSTFORK_PARENT:
214                break;
215        case RPC_C_POSTFORK_CHILD:
216
217                inq_fn = NULL;
218
219                /*
220                 * Empty the Object Registry Table
221                 */
222                for (i = 0; i < RPC_C_OBJ_REGISTRY_SIZE; i++)
223                {
224                    obj_registry[i].next = NULL;
225                    obj_registry[i].last = NULL;
226                }
227                break;
228    }
229}
230
231
232/*
233**++
234**
235**  ROUTINE NAME:       rpc_object_set_type
236**
237**  SCOPE:              PUBLIC - declared in rpc.idl
238**
239**  DESCRIPTION:
240**
241**  Register the type UUID of an object with the Common Communications
242**  Service. This routine is used in conjunction with rpc_server_register_if
243**  to allow a server to support multiple implementations of the same
244**  interface for different object types. Registering objects is required
245**  only when generic interfaces are declared (via "rpc_server_register_if").
246**  The Common Communications Service will dispatch to a specific
247**  implementation, contained in a manager Entry Point Vector, based on the
248**  object UUID contained in the binding of the RPC. The Common Communications
249**  Service, using the results of a call to this routine, will determine
250**  the type UUID of the object. A manager EPV for this type UUID can
251**  then be found using the results of a call to the rpc_server_register_if
252**  routine.
253**
254**  INPUTS:
255**
256**      object_uuid     The object to be registered.
257**
258**      type_uuid       The type of the object.
259**
260**  INPUTS/OUTPUTS:     none
261**
262**  OUTPUTS:
263**
264**      status          A value indicating the status of the routine.
265**
266**          rpc_s_ok
267**          rpc_s_coding_error
268**          rpc_s_invalid_object
269**          rpc_s_invalid_type
270**
271**  IMPLICIT INPUTS:    none
272**
273**  IMPLICIT OUTPUTS:   none
274**
275**  FUNCTION VALUE:     void
276**
277**  SIDE EFFECTS:       none
278**
279**--
280**/
281
282PUBLIC void rpc_object_set_type
283(
284    uuid_p_t                object_uuid,
285    uuid_p_t                type_uuid,
286    unsigned32              *status
287)
288{
289    rpc_obj_rgy_entry_p_t   obj_entry;
290    unsigned32              index;
291
292    CODING_ERROR (status);
293    RPC_VERIFY_INIT ();
294
295    /*
296     * check to see if this is a valid, non-null object UUIDs
297     */
298    if (UUID_IS_NIL (object_uuid, status))
299    {
300        *status = rpc_s_invalid_object;
301        return;
302    }
303
304    if (*status != uuid_s_ok)
305    {
306        *status = rpc_s_invalid_object;
307        return;
308    }
309
310    /*
311     * compute a hash value using the object uuid - check the status
312     * from uuid_hash to make sure the uuid has a valid format
313     */
314    index = (uuid_hash (object_uuid, status)) % RPC_C_OBJ_REGISTRY_SIZE;
315
316    if (*status != uuid_s_ok)
317    {
318        return;
319    }
320
321    /*
322     * take out a global lock on the object registry
323     */
324    RPC_MUTEX_LOCK (obj_mutex);
325
326    /*
327     * search the registry for a matching object
328     */
329    RPC_LIST_FIRST (obj_registry[index], obj_entry, rpc_obj_rgy_entry_p_t);
330
331    while (obj_entry != NULL)
332    {
333        if (uuid_equal (&(obj_entry->object_uuid), object_uuid, status))
334        {
335            break;
336        }
337
338        RPC_LIST_NEXT (obj_entry, obj_entry, rpc_obj_rgy_entry_p_t);
339    }
340
341    /*
342     * if the type UUID is the NIL UUID, remove the type entry
343     * for this object if it exists(this is basically an "unregister")
344     */
345    if (UUID_IS_NIL(type_uuid, status))
346    {
347        /*
348         * remove the object entry from the registry and free it
349         */
350        if (obj_entry != NULL)
351        {
352            RPC_LIST_REMOVE (obj_registry[index], obj_entry);
353            RPC_MEM_FREE (obj_entry, RPC_C_MEM_OBJ_RGY_ENTRY);
354        }
355    }
356    else
357    {
358        /*
359         * this is a register - if no entry was found, create one
360         */
361        if (obj_entry == NULL)
362        {
363            RPC_MEM_ALLOC (
364                obj_entry,
365                rpc_obj_rgy_entry_p_t,
366                sizeof (rpc_obj_rgy_entry_t),
367                RPC_C_MEM_OBJ_RGY_ENTRY,
368                RPC_C_MEM_WAITOK);
369
370            /*
371             * initialize the entry
372             */
373            obj_entry->object_uuid = *object_uuid;
374
375            /*
376             * put the object on the list for this hash index
377             */
378            RPC_LIST_ADD_TAIL
379                (obj_registry[index], obj_entry, rpc_obj_rgy_entry_p_t);
380        }
381        else
382        {
383            /*
384             * see if the type uuid matches the one specified
385             */
386            if (uuid_equal (&(obj_entry->type_uuid), type_uuid, status))
387            {
388                RPC_MUTEX_UNLOCK (obj_mutex);
389                *status = rpc_s_already_registered;
390                return;
391            }
392        }
393
394        /*
395         * set the type uuid for this object entry
396         */
397        obj_entry->type_uuid = *type_uuid;
398    }
399
400    RPC_MUTEX_UNLOCK (obj_mutex);
401    *status = rpc_s_ok;
402    return;
403}
404
405/*
406**++
407**
408**  ROUTINE NAME:       rpc_object_inq_type
409**
410**  SCOPE:              PUBLIC - declared in rpc.idl
411**
412**  DESCRIPTION:
413**
414**  Consult the object registry for the specified object's type.  If
415**  it is not found and the application has registered an inquiry function,
416**  call it.  Otherwise, if object is not registered, the type returned
417**  is nil_uuid.
418**
419**  Note: If a NULL value is passed for the type UUID argument the routine
420**  will execute, but the type UUID will not be returned. This can be
421**  useful to determine if an object is registered without requiring a
422**  return value to be supplied.
423**
424**  INPUTS:
425**
426**      object_uuid     The object being looked up.
427**
428**  INPUTS/OUTPUTS:     none
429**
430**  OUTPUTS:
431**
432**      type_uuid       The type of the object.
433**
434**      status          A value indicating the status of the routine.
435**
436**          rpc_s_ok
437**          rpc_s_object_not_found
438**          rpc_s_coding_error
439**
440**  IMPLICIT INPUTS:    none
441**
442**  IMPLICIT OUTPUTS:   none
443**
444**  FUNCTION VALUE:     void
445**
446**  SIDE EFFECTS:       none
447**
448**--
449**/
450
451PUBLIC void rpc_object_inq_type
452(
453    uuid_p_t                object_uuid,
454    idl_uuid_t                  *type_uuid,
455    unsigned32              *status
456)
457{
458    rpc_obj_rgy_entry_p_t   obj_entry;
459    unsigned32              index;
460
461    CODING_ERROR (status);
462    RPC_VERIFY_INIT ();
463
464    /*
465     * lookups on nil objects return nil types
466     */
467    if (UUID_IS_NIL (object_uuid, status))
468    {
469        UUID_CREATE_NIL (type_uuid);
470        *status = rpc_s_ok;
471        return;
472    }
473
474    /*
475     * compute a hash value using the object uuid - check the status
476     * from uuid_hash to make sure the uuid has a valid format
477     */
478    index = uuid_hash (object_uuid, status) % RPC_C_OBJ_REGISTRY_SIZE;
479
480    if (*status != uuid_s_ok)
481    {
482        return;
483    }
484
485    /*
486     * take out a lock to protect access to the object registry
487     */
488    RPC_MUTEX_LOCK (obj_mutex);
489
490    /*
491     * search the table for the specified object UUID
492     */
493    RPC_LIST_FIRST (obj_registry[index], obj_entry, rpc_obj_rgy_entry_p_t);
494
495    while (obj_entry != NULL)
496    {
497        if (uuid_equal (&(obj_entry->object_uuid), object_uuid, status))
498        {
499            /*
500             * if a type uuid is wanted, return it
501             */
502            if (type_uuid != NULL)
503            {
504                *type_uuid = obj_entry->type_uuid;
505            }
506
507            RPC_MUTEX_UNLOCK (obj_mutex);
508            *status = rpc_s_ok;
509            return;
510        }
511
512        RPC_LIST_NEXT (obj_entry, obj_entry, rpc_obj_rgy_entry_p_t);
513    }
514
515    /*
516     * If there's an application function to map object to type, call it now.
517     * Ensure that a object_not_found failure returns the nil-type.
518     */
519    if (inq_fn != NULL)
520    {
521        RPC_MUTEX_UNLOCK (obj_mutex);
522        (*inq_fn) (object_uuid, type_uuid, status);
523        if (*status == rpc_s_object_not_found)
524        {
525            UUID_CREATE_NIL (type_uuid);
526        }
527        return;
528    }
529
530    UUID_CREATE_NIL (type_uuid);
531
532    RPC_MUTEX_UNLOCK (obj_mutex);
533    *status = rpc_s_object_not_found;
534    return;
535}
536
537/*
538**++
539**
540**  ROUTINE NAME:       rpc_object_set_inq_fn
541**
542**  SCOPE:              PUBLIC - declared in rpc.idl
543**
544**  DESCRIPTION:
545**
546**  Supply a function that is called by the runtime to determine the type
547**  of objects that have not been set by "rpc_object_set_type".
548**
549**  INPUTS:
550**
551**      inq_fn          function that does the inquiry
552**
553**  INPUTS/OUTPUTS:     none
554**
555**  OUTPUTS:
556**
557**      status          A value indicating the status of the routine.
558**
559**  IMPLICIT INPUTS:    none
560**
561**  IMPLICIT OUTPUTS:   none
562**
563**  FUNCTION VALUE:     void
564**
565**  SIDE EFFECTS:       none
566**
567**--
568**/
569
570PUBLIC void rpc_object_set_inq_fn
571(
572    rpc_object_inq_fn_t     inq_fn_arg,
573    unsigned32              *status
574)
575{
576    CODING_ERROR (status);
577    RPC_VERIFY_INIT ();
578
579    inq_fn = inq_fn_arg;
580    *status = rpc_s_ok;
581}
582