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**      ctxeectx.c
82**
83**  FACILITY:
84**
85**      IDL Stub Runtime Support
86**
87**  ABSTRACT:
88**
89**      Maintain callee stub's table of contexts
90**
91**
92*/
93#if HAVE_CONFIG_H
94#include <config.h>
95#endif
96
97/* The ordering of the following 3 includes should NOT be changed! */
98#include <dce/rpc.h>
99#include <dce/stubbase.h>
100#include <lsysdep.h>
101
102#include <dce/uuid.h>
103
104#include <ctxeertl.h>
105
106#ifndef DEBUG_VERBOSE
107#   define NDEBUG
108#endif
109#include <assert.h>
110
111#ifdef PERFMON
112#include <dce/idl_log.h>
113#endif
114
115#ifdef CTXEETEST
116#   include <stdio.h>
117#   define DPRINT(ARGS) printf ARGS
118#else
119#   define DPRINT(ARGS)
120#endif
121
122/******************************************************************************/
123/*                                                                            */
124/*    Set up CMA machinery required by context tables                         */
125/*                                                                            */
126/******************************************************************************/
127
128ndr_boolean rpc_ss_context_is_set_up = ndr_false;
129
130static RPC_SS_THREADS_ONCE_T context_once = RPC_SS_THREADS_ONCE_INIT;
131
132RPC_SS_THREADS_MUTEX_T rpc_ss_context_table_mutex;
133
134static void rpc_ss_init_context(
135    void
136)
137{
138    /* Create mutex for context handle tables */
139    RPC_SS_THREADS_MUTEX_CREATE( &rpc_ss_context_table_mutex );
140    /* And initialize the tables */
141    rpc_ss_init_callee_ctx_tables();
142}
143
144void rpc_ss_init_context_once(
145    void
146)
147{
148    RPC_SS_THREADS_INIT;
149    RPC_SS_THREADS_ONCE( &context_once, rpc_ss_init_context );
150    rpc_ss_context_is_set_up = ndr_true;
151}
152
153/*  Number of context slots in hash table.
154*/
155#define CALLEE_CONTEXT_TABLE_SIZE 256
156
157static callee_context_entry_t *context_table = NULL;
158
159/*  Allocate and initialize callee context and client lookup tables.
160*/
161void rpc_ss_init_callee_ctx_tables(
162    void
163)
164{
165
166#ifdef PERFMON
167    RPC_SS_INIT_CALLEE_CTX_TABLES_N;
168#endif
169
170    assert(!context_table);     /* Must not be called more than once. */
171
172    context_table = (callee_context_entry_t *)malloc(
173        CALLEE_CONTEXT_TABLE_SIZE * sizeof(callee_context_entry_t)
174    );
175
176    if (!context_table)
177        DCETHREAD_RAISE(rpc_x_no_memory);
178
179/*****************
180**
181** The memset below has the same effect as this more descriptive loop.
182**
183**     for (i = 0; i < CALLEE_CONTEXT_TABLE_SIZE; i++) {
184**         uuid_create_nil(&context_table[i].uuid, &status);
185**         context_table[i].next_context = NULL;
186**     }
187**
188******************/
189
190    memset (context_table, 0,
191            CALLEE_CONTEXT_TABLE_SIZE * sizeof(callee_context_entry_t));
192    rpc_ss_init_callee_client_table();
193
194#ifdef PERFMON
195    RPC_SS_INIT_CALLEE_CTX_TABLES_X;
196#endif
197
198}
199
200/******************************************************************************/
201/*                                                                            */
202/*    Add an entry to the callee context lookup table                         */
203/*                                                                            */
204/******************************************************************************/
205void rpc_ss_create_callee_context
206(
207    rpc_ss_context_t callee_context,/* The user's local form of the context */
208    idl_uuid_t    *p_uuid,              /* Pointer to the equivalent UUID */
209    handle_t h,                     /* Binding handle */
210    ctx_rundown_fn_p_t ctx_rundown, /* Pointer to context rundown routine */
211    error_status_t *result     /* Function result */
212)
213{
214    rpc_client_handle_t  ctx_client;         /* ID of client owning context */
215    callee_context_entry_t *this_link, *next_link, * volatile new_link;
216    ndr_boolean is_new_client;
217
218    //DO_NOT_CLOBBER(new_link);
219
220#ifdef PERFMON
221    RPC_SS_CREATE_CALLEE_CONTEXT_N;
222#endif
223
224    /* If this is the first context to be created, initialization is needed */
225    RPC_SS_INIT_CONTEXT
226
227    rpc_binding_inq_client(h, &ctx_client, (error_status_t *) result);
228    if (*result != error_status_ok) return;
229
230    RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex);
231    DPRINT(("Seized context tables\n"));
232    this_link = &context_table[uuid_hash(p_uuid,(error_status_t *)result)
233                                               % CALLEE_CONTEXT_TABLE_SIZE];
234    if ( uuid_is_nil(&this_link->uuid, (error_status_t *)result) )
235    {
236        /* Home slot in the hash table is empty */
237        new_link = this_link;
238        next_link = NULL;
239    }
240    else
241    {
242        /* Put the new item at the head of the overflow chain */
243        new_link = (callee_context_entry_t *)
244                             malloc(sizeof(callee_context_entry_t));
245        if (new_link == NULL)
246        {
247            RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
248            DPRINT(("Released context tables\n"));
249            DCETHREAD_RAISE( rpc_x_no_memory );
250        }
251        next_link = this_link->next_context;
252        this_link->next_context = new_link;
253    }
254
255    /* Fill in fields of context entry */
256    memcpy(
257        (char *)&new_link->uuid,
258        (char *)p_uuid,
259        sizeof(idl_uuid_t)
260    );
261    new_link->user_context = callee_context;
262    new_link->rundown = ctx_rundown;
263    new_link->next_context = next_link;
264
265    DCETHREAD_TRY
266    rpc_ss_add_to_callee_client(ctx_client,new_link,&is_new_client,
267                                result);
268    DCETHREAD_FINALLY
269    RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
270    DPRINT(("Released context tables\n"));
271    DCETHREAD_ENDTRY
272    if ((*result == error_status_ok) && is_new_client)
273    {
274        rpc_network_monitor_liveness( h, ctx_client,
275                             rpc_ss_rundown_client,
276                             (error_status_t *) result );
277#ifdef PERFMON
278    RPC_SS_CREATE_CALLEE_CONTEXT_X;
279#endif
280    }
281}
282
283/******************************************************************************/
284/*                                                                            */
285/*  Update an entry in the callee context lookup table                        */
286/*  *result is error_status_ok unless the UUID is not in the lookup table.    */
287/*                                                                            */
288/******************************************************************************/
289void rpc_ss_update_callee_context
290(
291    rpc_ss_context_t    callee_context, /* The user's local form of the context */
292    idl_uuid_t              *p_uuid,        /* Pointer to the equivalent UUID */
293    error_status_t      *result         /* Function result */
294)
295{
296    callee_context_entry_t *this_link;
297
298#ifdef PERFMON
299    RPC_SS_UPDATE_CALLEE_CONTEXT_N;
300#endif
301
302    RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex);
303    DPRINT(("Seized context tables\n"));
304    this_link = &context_table[uuid_hash(p_uuid,result)
305                                               % CALLEE_CONTEXT_TABLE_SIZE];
306    while ( ! uuid_equal(p_uuid,&this_link->uuid,result) )
307    {
308        this_link = this_link->next_context;
309        if (this_link == NULL)
310        {
311            RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
312            DPRINT(("Released context tables\n"));
313            DCETHREAD_RAISE( rpc_x_ss_context_mismatch);
314        }
315    }
316    this_link->user_context = callee_context;
317    RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
318    DPRINT(("Released context tables\n"));
319    *result = error_status_ok;
320
321#ifdef PERFMON
322    RPC_SS_UPDATE_CALLEE_CONTEXT_X;
323#endif
324
325}
326
327/******************************************************************************/
328/*                                                                            */
329/*    Find the local context that corresponds to a supplied UUID              */
330/*                                                                            */
331/*  ENTRY POINT INTO LIBIDL FROM STUB                                         */
332/*                                                                            */
333/******************************************************************************/
334void rpc_ss_ee_ctx_from_wire
335(
336    ndr_context_handle      *p_wire_context,
337    rpc_ss_context_t        *p_context,         /* The application context */
338    volatile error_status_t *p_st
339)
340{
341    idl_uuid_t *p_uuid;    /* Pointer to the UUID that has come off the wire */
342    callee_context_entry_t *this_link;
343
344#ifdef PERFMON
345    RPC_SS_EE_CTX_FROM_WIRE_N;
346#endif
347
348    p_uuid = &p_wire_context->context_handle_uuid;
349
350#ifdef DEBUGCTX
351    debug_context_lookup(p_uuid);
352    debug_context_table();
353#endif
354
355    *p_st = error_status_ok;
356    if ( uuid_is_nil(p_uuid, (error_status_t *)p_st) )
357    {
358        *p_context = NULL;
359
360#ifdef PERFMON
361        RPC_SS_EE_CTX_FROM_WIRE_X;
362#endif
363
364        return;
365    }
366    RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex);
367    DPRINT(("Seized context tables\n"));
368    this_link = &context_table[uuid_hash(p_uuid, (error_status_t *)p_st)
369                                               % CALLEE_CONTEXT_TABLE_SIZE];
370    while ( ! uuid_equal(p_uuid,&this_link->uuid, (error_status_t *)p_st) )
371    {
372        this_link = this_link->next_context;
373        if (this_link == NULL)
374        {
375            RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
376            DPRINT(("Released context tables\n"));
377
378#ifdef PERFMON
379            RPC_SS_EE_CTX_FROM_WIRE_X;
380#endif
381
382            DCETHREAD_RAISE( rpc_x_ss_context_mismatch );
383            return;
384        }
385    }
386    *p_context = this_link->user_context;
387    RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
388    DPRINT(("Released context tables\n"));
389
390#ifdef PERFMON
391    RPC_SS_EE_CTX_FROM_WIRE_X;
392#endif
393
394    return;
395}
396
397/******************************************************************************/
398/*                                                                            */
399/*    Take a lock on the context tables and destroy a context entry           */
400/*                                                                            */
401/******************************************************************************/
402void rpc_ss_destroy_callee_context
403(
404    idl_uuid_t *p_uuid,             /* Pointer to UUID of context to be destroyed */
405    handle_t  h,                /* Binding handle */
406    error_status_t *result /* Function result */
407)    /* Returns error_status_ok unless the UUID is not in the lookup table */
408{
409    rpc_client_handle_t close_client;   /* NULL or client to stop monitoring */
410
411#ifdef PERFMON
412    RPC_SS_DESTROY_CALLEE_CONTEXT_N;
413#endif
414
415    RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex);
416    DPRINT(("Seized context tables\n"));
417    rpc_ss_lkddest_callee_context(p_uuid,&close_client,result);
418    RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
419    DPRINT(("Released context tables\n"));
420    if ((*result == error_status_ok) && (close_client != NULL))
421    {
422        rpc_network_stop_monitoring(h, close_client, (error_status_t *) result);
423    }
424#ifdef PERFMON
425    RPC_SS_DESTROY_CALLEE_CONTEXT_X;
426#endif
427}
428
429/******************************************************************************/
430/*                                                                            */
431/*    Destroy an entry in the context table                                   */
432/*                                                                            */
433/*  Assumes that the context table mutex is locked                            */
434/*                                                                            */
435/******************************************************************************/
436void rpc_ss_lkddest_callee_context
437(
438    idl_uuid_t *p_uuid,    /* Pointer to UUID of context to be destroyed */
439    rpc_client_handle_t *p_close_client,
440                                /* Ptr to NULL or client to stop monitoring */
441    error_status_t *result /* Function result */
442)    /* Returns error_status_ok unless the UUID is not in the lookup table */
443{
444    callee_context_entry_t *this_link, *next_link, *last_link;
445
446#ifdef PERFMON
447    RPC_SS_LKDDEST_CALLEE_CONTEXT_N;
448#endif
449
450    this_link = &context_table[uuid_hash(p_uuid,(error_status_t *) result)
451                                               % CALLEE_CONTEXT_TABLE_SIZE];
452    next_link = this_link->next_context;
453    if ( uuid_equal(p_uuid,&this_link->uuid, (error_status_t *) result) )
454    {
455        /* Context to be destroyed is in home slot */
456        rpc_ss_take_from_callee_client(this_link,p_close_client,result);
457        if (next_link == NULL)
458        {
459            /* There is no chain from the home slot */
460            uuid_create_nil(&this_link->uuid, (error_status_t *) result);
461        }
462        else
463        {
464            /* Move the second item in the chain to the home slot */
465            memcpy(
466                (char *)&this_link->uuid,
467                (char *)&next_link->uuid,
468                sizeof(idl_uuid_t)
469            );
470            this_link->user_context = next_link->user_context;
471            this_link->rundown = next_link->rundown;
472            this_link->p_client_entry = next_link->p_client_entry;
473            this_link->prev_in_client = next_link->prev_in_client;
474            if (this_link->prev_in_client == NULL)
475            {
476                (this_link->p_client_entry)->first_context = this_link;
477            }
478            else
479            {
480                (this_link->prev_in_client)->next_in_client = this_link;
481            }
482            this_link->next_in_client = next_link->next_in_client;
483            if (this_link->next_in_client == NULL)
484            {
485                (this_link->p_client_entry)->last_context = this_link;
486            }
487            else
488            {
489                (this_link->next_in_client)->prev_in_client = this_link;
490            }
491            this_link->next_context = next_link->next_context;
492            /* And release the memory it was in */
493            free((char_p_t)next_link);
494        }
495
496#ifdef PERFMON
497        RPC_SS_LKDDEST_CALLEE_CONTEXT_X;
498#endif
499
500        return;
501    }
502    else    /* Context is further down chain */
503    {
504        while (next_link != NULL)
505        {
506            last_link = this_link;
507            this_link = next_link;
508            next_link = this_link->next_context;
509            if ( uuid_equal(p_uuid,&this_link->uuid,(error_status_t *)result) )
510            {
511                rpc_ss_take_from_callee_client(this_link,p_close_client,result);
512                /* Relink chain to omit found entry */
513                last_link->next_context = next_link;
514                /* And free the memory it occupied */
515                free((char_p_t)this_link);
516
517#ifdef PERFMON
518                RPC_SS_LKDDEST_CALLEE_CONTEXT_X;
519#endif
520
521                return;
522            }
523        }
524        RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
525        DPRINT(("Released context tables\n"));
526        DCETHREAD_RAISE( rpc_x_ss_context_mismatch);
527    }
528}
529
530#ifdef CTXEETEST
531void dump_context_table()
532{
533    int i;
534    callee_context_entry_t *this_link;
535    callee_client_entry_t *this_client;
536    error_status_t status;
537
538    for (i=0; i<CALLEE_CONTEXT_TABLE_SIZE; i++)
539    {
540        if ( ! uuid_is_nil(&context_table[i].uuid, &status) )
541        {
542            this_link = &context_table[i];
543            printf("Context chain for context_slot %d\n",i);
544            while (this_link != NULL)
545            {
546                printf("\t %s %lx ",
547                        &this_link->uuid,
548                        this_link->user_context);
549                this_client = this_link->p_client_entry;
550                printf("Client %lx %d\n",
551                        this_client->client,
552                        this_client->count);
553                this_link = this_link->next_context;
554            }
555        }
556    }
557}
558#endif
559
560#ifdef DEBUGCTX
561static ndr_boolean debug_file_open = ndr_false;
562static char *debug_file = "ctxee.dmp";
563static FILE *debug_fid;
564
565static int debug_context_lookup(uuid_p)
566    unsigned char *uuid_p;
567{
568    int j;
569    unsigned long k;
570
571    if (!debug_file_open)
572    {
573        debug_fid = fopen(debug_file, "w");
574        debug_file_open = ndr_true;
575    }
576
577    fprintf(debug_fid, "L");
578    for (j=0; j<sizeof(idl_uuid_t); j++)
579    {
580        k = *uuid_p++;
581        fprintf(debug_fid, " %02x", k);
582    }
583    fprintf(debug_fid, "\n");
584}
585
586static int debug_context_add(user_context)
587    long user_context;
588{
589    if (!debug_file_open)
590    {
591        debug_fid = fopen(debug_file, "w");
592        debug_file_open = ndr_true;
593    }
594
595    fprintf(debug_fid, "N %lx\n", user_context);
596}
597
598static int debug_context_table()
599{
600    int i, j;
601    unsigned long k;
602    ndr_boolean at_home;
603    unsigned char *uuid_p;
604    callee_context_entry_t *this_link;
605    callee_client_entry_t *this_client;
606    error_status_t status;
607
608    if (!debug_file_open)
609    {
610        debug_fid = fopen(debug_file, "w");
611        debug_file_open = ndr_true;
612    }
613
614    for (i=0; i<CALLEE_CONTEXT_TABLE_SIZE; i++)
615    {
616        if ( ! uuid_is_nil(&context_table[i].uuid, &status) )
617        {
618            at_home = ndr_true;
619            this_link = &context_table[i];
620            while (this_link != NULL)
621            {
622                if (at_home)
623                {
624                    at_home = ndr_false;
625                    fprintf(debug_fid, "%4d:", i);
626                }
627                else
628                    fprintf(debug_fid, "   C:", i);
629                uuid_p = (unsigned char *)&this_link->uuid;
630                for (j=0; j<sizeof(this_link->uuid); j++)
631                {
632                    k = *uuid_p++;
633                    fprintf(debug_fid, " %02x", k);
634                }
635                this_client = this_link->p_client_entry;
636                fprintf(debug_fid, " client %lx %d\n",
637                        this_client->client,
638                        this_client->count);
639                this_link = this_link->next_context;
640            }
641        }
642    }
643}
644#endif
645
646/******************************************************************************/
647/*                                                                            */
648/*    Routine to be called when a callee argument of type  context_t  is to   */
649/*    be marshalled                                                           */
650/*                                                                            */
651/*  ENTRY POINT INTO LIBIDL FROM STUB                                         */
652/*                                                                            */
653/******************************************************************************/
654void rpc_ss_ee_ctx_to_wire
655(
656    rpc_ss_context_t        callee_context,   /* The application context */
657    ndr_context_handle      *p_wire_context,  /* Pointer to wire form of context */
658    handle_t                h,                /* Binding handle */
659    ctx_rundown_fn_p_t      ctx_rundown,      /* Pointer to context rundown routine */
660    ndr_boolean             in_out,           /* TRUE for [in,out], FALSE for [out] */
661    volatile error_status_t *p_st
662)
663{
664#ifdef DEBUGCTX
665    debug_context_add(callee_context);
666#endif
667
668    int wire, context;
669    p_wire_context->context_handle_attributes = 0;  /* Only defined value. */
670
671    /*  Boolean conditions are
672     *      wire:    UUID from wire is valid (not nil) -- in_out must be true.
673     *      context: callee context from manager is valid (not NULL).
674     *      in_out:  context handle parameter is [in,out] (not just [out]).
675     *  Mapping of conditions onto actions implemented in the following switch.
676     *      wire  context  in_out  condition  Action
677     *       0       0       0         0      create nil UUID
678     *       0       0       1         1      do nothing -- use old (nil) UUID
679     *       0       1       0         2      create new UUID and new context
680     *       0       1       1         3      create new UUID and new context
681     *       1       0       0         4      impossible
682     *       1       0       1         5      destroy existing context, make UUID nil
683     *       1       1       0         6      impossible
684     *       1       1       1         7      update existing context
685     */
686
687#ifdef PERFMON
688    RPC_SS_EE_CTX_TO_WIRE_N;
689#endif
690
691    wire    = in_out && !uuid_is_nil(
692                &p_wire_context->context_handle_uuid, (error_status_t *)p_st
693            )? 4: 0;
694    context = callee_context? 2: 0;
695    in_out  = in_out? 1: 0;
696
697    switch (wire | context | in_out) {
698    case 0:
699        uuid_create_nil(
700            &p_wire_context->context_handle_uuid, (error_status_t *)p_st
701        );
702        break;
703    case 1:
704        *p_st = error_status_ok;
705        break;
706    case 2:
707    case 3:
708        uuid_create(
709            &p_wire_context->context_handle_uuid, (error_status_t *)p_st
710        );
711        rpc_ss_create_callee_context(
712            callee_context, &p_wire_context->context_handle_uuid, h,
713            ctx_rundown, (error_status_t *)p_st
714        );
715        break;
716    case 5:
717        rpc_ss_destroy_callee_context(
718            &p_wire_context->context_handle_uuid, h, (error_status_t *)p_st
719        );
720        if (*p_st != error_status_ok) break;
721        uuid_create_nil(
722            &p_wire_context->context_handle_uuid, (error_status_t *)p_st
723        );
724        break;
725    case 7:
726        rpc_ss_update_callee_context(
727            callee_context, &p_wire_context->context_handle_uuid,
728            (error_status_t *)p_st
729        );
730        break;
731    default:    /* All invalid conditions evaluate true. */
732        assert(!(wire | context | in_out));
733        break;
734    }
735
736#ifdef DEBUGCTX
737    debug_context_table();
738#endif
739
740#ifdef PERFMON
741    RPC_SS_EE_CTX_TO_WIRE_X;
742#endif
743
744}
745