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**      cncall.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  The NCA Connection Protocol Service's Call Service.
90**
91**
92*/
93
94#include <commonp.h>    /* Common declarations for all RPC runtime */
95#include <com.h>        /* Common communications services */
96#include <comprot.h>    /* Common protocol services */
97#include <ndrglob.h>    /* NDR representation global declarations */
98#include <ndrp.h>       /* NDR system dependent definitions */
99#include <cnp.h>        /* NCA Connection private declarations */
100#include <cnbind.h>     /* NCA connection binding service */
101#include <cnsm.h>       /* NCA Connection generic state machine operations */
102#include <cnclsm.h>     /* NCA Connection client call state machine */
103#include <cnpkt.h>      /* NCA Connection protocol header */
104#include <cnassoc.h>    /* NCA Connection association services */
105#include <cnfbuf.h>     /* NCA Connection fragment buffer routines */
106#include <cnxfer.h>     /* NCA Connection data transfer routines */
107#include <comtwr.h>     /* Externals for Towers sub-component */
108#include <comtwrref.h>  /* tower defs for other RPC components */
109#include <dce/ep.h>     /* rpcd endpoint (ep) interface definitions */
110#include <cncall.h>
111
112/*
113 * Macro to test for a cancel every so often for a cancel. The
114 * num_pkts field of the call rep is cleared when the first frag is
115 * sent. It is incremented on every subsequent transmitted or received
116 * fragment.
117 */
118#define RPC_CN_CANCEL_CHECK_FREQ        8
119#define RPC_CN_CHECK_FOR_CANCEL(call_r) \
120{ \
121    if ((call_r)->num_pkts & RPC_CN_CANCEL_CHECK_FREQ) \
122    { \
123        rpc__cn_call_check_for_cancel (call_r);\
124    } \
125}
126
127/*
128 * Macro to forward, if the first frag has been sent, and queued
129 * cancels.
130 */
131#define RPC_CN_FORWARD_QUEUED_CANCELS(call_r, st) \
132{ \
133    if ((call_r)->u.client.cancel.local_count) \
134    { \
135        rpc__cn_call_forward_cancel (call_r, st); \
136    } \
137}
138
139/*
140 * Macro to check for a pending cancel and forward, if the first frag
141 * has been sent, that cancel and any queued cancels.
142 */
143#define RPC_CN_CHK_AND_FWD_CANCELS(call_r, st) \
144{ \
145    RPC_CN_CHECK_FOR_CANCEL (call_r); \
146    RPC_CN_FORWARD_QUEUED_CANCELS (call_r, st); \
147}
148
149INTERNAL unsigned32 rpc__cn_call_cvt_from_nca_st (
150        unsigned32      /*a_st*/
151    );
152
153INTERNAL unsigned32 rpc__cn_call_cvt_to_nca_st (
154        unsigned32      /*l_st*/
155    );
156
157INTERNAL void rpc__cn_call_check_for_cancel (
158        rpc_cn_call_rep_p_t     /*call_rep*/
159    );
160
161INTERNAL void rpc__cn_call_forward_cancel (
162        rpc_cn_call_rep_p_t     /*call_rep*/,
163        unsigned32              * /*status*/
164    );
165
166INTERNAL void rpc__cn_call_binding_serialize (
167        rpc_binding_rep_p_t     /*binding_r*/,
168        rpc_clock_t             /*cancel_timeout*/,
169        unsigned32              * /*cancel_cnt*/,
170        unsigned32              * /*st*/
171    );
172
173INTERNAL boolean rpc__cn_call_cancel_timer (
174        rpc_cn_call_rep_p_t     /*call_r*/
175    );
176
177/***********************************************************************/
178
179/*
180**++
181**
182**  ROUTINE NAME:       rpc__cn_call_start
183**
184**  SCOPE:              PRIVATE - declared in cncall.h
185**
186**  DESCRIPTION:
187**
188**  This is the NCA connection oriented protocol specific routine
189**  which begins a remote procedure call.  It returns the information
190**  needed to marshal input arguments.  This routine is intended
191**  for use by the client stub only.
192**
193**  INPUTS:
194**
195**      binding_r       The binding rep containing the location of
196**                      the server.
197**      call_options    The options pertaining to this RPC.
198**      ifspec_r        The interface specification rep data structure
199**                      describing the interface to which the RPC belongs.
200**      opnum           The operation number of the RPC in the
201**                      interface.
202**
203**  INPUTS/OUTPUTS:     none
204**
205**  OUTPUTS:
206**
207**      transfer_syntax The negotiated transfer syntax for this RPC.
208**
209**      st              The return status of this routine.
210**          rpc_s_ok                    The call was successful.
211**          rpc_s_invalid_call_opt      An invalid call option was specified.
212**
213**  IMPLICIT INPUTS:    none
214**
215**  IMPLICIT OUTPUTS:   none
216**
217**  FUNCTION VALUE:
218**
219**      call_rep        The call rep.
220**
221**  SIDE EFFECTS:       none
222**
223**--
224**/
225
226PRIVATE rpc_call_rep_t *rpc__cn_call_start
227(
228  rpc_binding_rep_p_t     binding_r,
229  unsigned32              call_options,
230  rpc_if_rep_p_t          ifspec_r,
231  unsigned32              opnum,
232  rpc_transfer_syntax_t   *transfer_syntax,
233  unsigned32              *st
234)
235{
236    rpc_cn_call_rep_t       *call_rep;
237    rpc_iovector_elt_p_t    iov_p;
238    rpc_cn_packet_p_t       header_p;
239    unsigned32              cancel_count = 0;
240    rpc_clock_t             cancel_timeout = 0;
241    unsigned32              temp_st;
242    dcethread*              current_thread_id;
243    boolean                 resolving_thread;
244
245    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_start);
246    RPC_LOG_CN_CALL_START_NTR;
247    CODING_ERROR (st);
248
249    /*
250     * If this call requires security, verify that the caller's
251     * credentials are valid right now. If they aren't, try to refresh
252     * them. If they can't be refreshed return an error. We do this
253     * now while there are no locks taken out. The CRED_REFRESH
254     * operation may make an RPC to the security server which will
255     * require the RPC locks to be taken out. This would result in a
256     * deadlock if we had any RPC locks taken out now.
257     *
258     * It is the responsibility of the authentication protocol to
259     * serialize access to the auth info structure. For example the
260     * Kerberos auth protocol uses a lock per auth_info structure to
261     * protect it (the krb_info_lock).
262     *
263     * XXX is there a deadlock here? See Transarc Defect 17575
264     * http://vcs.es.net/DCCC/DCEWG/DCE-1.1_Patch16.txt
265     */
266    if (RPC_CN_AUTH_REQUIRED (binding_r->auth_info))
267    {
268        /*
269         * The binding has an auth info structure hanging off it,
270         * which indicates this call is to be authenticated.
271         */
272        RPC_CN_AUTH_CRED_REFRESH (binding_r->auth_info,
273                                  st);
274        if (*st != rpc_s_ok)
275        {
276            return (NULL);
277        }
278    }
279
280    /*
281     * Acquire the CN global mutex to prevent other threads from
282     * running.
283     */
284    RPC_CN_LOCK ();
285
286    /*
287     * The broadcast call option and callbacks are not supported by the
288     * connection oriented protocol services.
289     * We detect callbacks by checking the binding to see if it is
290     * that of a server.
291     */
292    if (call_options & rpc_c_call_brdcst)
293    {
294        *st = rpc_s_invalid_call_opt;
295        RPC_CN_UNLOCK ();
296        return (NULL);
297    }
298
299    if (binding_r->is_server)
300    {
301        *st = rpc_s_wrong_kind_of_binding;
302        RPC_CN_UNLOCK ();
303        return (NULL);
304    }
305
306    /*
307     * Get the thread's cancel timeout value (so we don't block forever).
308     */
309    RPC_GET_CANCEL_TIMEOUT (cancel_timeout, st);
310    if (*st != rpc_s_ok)
311    {
312        RPC_CN_UNLOCK ();
313        return (NULL);
314    }
315
316    /*
317     * Check to see if we're currently resolving a binding.
318     */
319    if (((rpc_cn_binding_rep_t *)binding_r)->being_resolved)
320    {
321        current_thread_id = dcethread_self ();
322        resolving_thread = dcethread_equal
323            (((rpc_cn_binding_rep_t *)binding_r)->resolving_thread_id,
324             current_thread_id);
325        if (!resolving_thread)
326        {
327            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
328                    ("CN: call_rep->none waiting on binding resolution\n"));
329            /*
330             * Serialize calls on this binding handle until the handle
331             * has an endpoint.
332             */
333            RPC_BINDING_CALL_START ((rpc_binding_rep_t *) binding_r);
334
335            rpc__cn_call_binding_serialize (binding_r,
336                                            cancel_timeout,
337                                            &cancel_count,
338                                            st);
339            RPC_BINDING_CALL_END (binding_r);
340            if (*st != rpc_s_ok)
341            {
342                /*
343                * The cancel timeout probably expired.
344                */
345                RPC_CN_UNLOCK ();
346                return (NULL);
347            }
348        }
349    }
350    else
351    {
352        /*
353         * Check to see if we have a fully bound handle, i.e.,
354         * the endpoint information is present.
355         * If not, call rpc_ep_resolve_binding.
356         */
357        if (!binding_r->addr_has_endpoint)
358        {
359            /*
360             * The binding handle is partially bound. Prevent other
361             * threads from using it in a call until it is fully bound.
362             */
363            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
364                    ("CN: call_rep->none partially bound binding handle\n"));
365
366            RPC_BINDING_CALL_START ((rpc_binding_rep_t *) binding_r);
367            ((rpc_cn_binding_rep_t *)binding_r)->being_resolved = true;
368            ((rpc_cn_binding_rep_t *)binding_r)->resolving_thread_id = dcethread_self ();
369
370            RPC_CN_UNLOCK ();
371            rpc_ep_resolve_binding ((rpc_binding_handle_t) binding_r,
372                                    (rpc_if_handle_t) ifspec_r, st);
373            RPC_CN_LOCK ();
374            ((rpc_cn_binding_rep_t *)binding_r)->being_resolved = false;
375
376            /*
377             * Let other threads use the binding handle now.
378             */
379            RPC_BINDING_CALL_END (binding_r);
380            if (binding_r->calls_in_progress)
381            {
382                RPC_BINDING_COND_BROADCAST (0);
383            }
384
385            /*
386             * If the attempt to resolve the binding handle was
387             * unsuccessful return.
388             */
389            if (*st != rpc_s_ok)
390            {
391                RPC_CN_UNLOCK ();
392                return (NULL);
393            }
394        }
395    }
396
397    /*
398     * At this point, we have a fully-bound binding.
399     * We can now allocate a call_rep.
400     */
401    call_rep = (rpc_cn_call_rep_p_t)
402        rpc__list_element_alloc (&rpc_g_cn_call_lookaside_list, true);
403    if (call_rep == NULL)
404    {
405        RPC_CN_UNLOCK ();
406        *st = rpc_s_no_memory;
407        return (NULL);
408    }
409
410    /*
411     * Mark it as a client call rep.
412     */
413    call_rep->common.is_server = false;
414    call_rep->prot_tlr = NULL;
415
416    /*
417     * Clear out the io vectors
418     */
419    {
420        int i;
421        for( i=1; i<RPC_C_MAX_IOVEC_LEN; i++ ) {
422            call_rep->buffered_output.iov.elt[i].buff_addr = NULL;
423            call_rep->buffered_output.iov.elt[i].buff_dealloc = NULL;
424        }
425    }
426
427    /*
428     * Start off in the initial state.
429     */
430    rpc__cn_sm_init (rpc_g_cn_client_call_sm,
431                     rpc_g_cn_client_call_action_tbl,
432                     &(call_rep->call_state),
433		     rpc_c_cn_cl_call);
434    call_rep->call_state.cur_state = RPC_C_CLIENT_CALL_INIT;
435
436    /*
437     * Init security info
438     */
439    call_rep->sec = NULL;
440
441    /*
442     * Init the association in case allocating it later in this function
443     * fails.
444     */
445    call_rep->assoc = NULL;
446
447    /*
448     * Init some booleans.
449     */
450    call_rep->cn_call_status = rpc_s_ok;
451    call_rep->last_frag_received = false;
452    call_rep->call_executed = false;
453
454    /*
455     * Initialize some cancel state information.
456     */
457    call_rep->u.client.cancel.server_is_accepting = false;
458    call_rep->u.client.cancel.server_had_pending = false;
459    call_rep->u.client.cancel.server_count = 0;
460
461    /*
462     * Initialize the fault fragbuf pointer to NULL.
463     */
464    call_rep->u.client.fault_data = NULL;
465
466    /*
467     * Initialize alloc_hint to 0
468     */
469    call_rep->alloc_hint = 0;
470
471    /*
472     * Include any cancels detected while serializing access to the
473     * binding handle. These will be forwarded when the first
474     * request fragment is sent. The absolute cancel timeout time
475     * left for this thread was gotten by RPC_GET_CANCEL_TIMEOUT.
476     */
477    call_rep->u.client.cancel.local_count = cancel_count;
478    call_rep->u.client.cancel.timeout_time = cancel_timeout;
479    call_rep->u.client.cancel.timer_running = false;
480    if (cancel_count)
481    {
482        /*
483         * Start a cancel timer. We won't bother checking the status
484         * here because there is no timer running yet and no
485         * association set up yet.
486         */
487        rpc__cn_call_start_cancel_timer (call_rep, st);
488    }
489
490    /*
491     * Save the binding rep in the call rep for use in an action routine.
492     */
493    call_rep->binding_rep = binding_r;
494
495    /*
496     * Store the address of the fragment buffer in the
497     * call rep.
498     */
499    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep);
500
501    RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_REQUEST;
502    RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_FIRST_FRAG;
503    if (call_options & rpc_c_call_maybe)
504    {
505        RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_MAYBE;
506    }
507    RPC_CN_PKT_ALERT_COUNT(header_p) = 0;
508    RPC_CN_PKT_FRAG_LEN (header_p) = 0;
509    RPC_CN_PKT_CALL_ID (header_p) = rpc_g_cn_call_id++;
510    RPC_CN_PKT_OPNUM (header_p) = opnum;
511
512    /*
513     * Initialize the iovector in the call_rep to contain only
514     * one initial element, pointing to the protocol header.
515     * Also, update pointers to show that we can copy data into
516     * the stub data area.
517     */
518    RPC_CN_CREP_IOVLEN (call_rep) = 1;
519    RPC_CN_CREP_CUR_IOV_INDX (call_rep) = 0;
520    iov_p = &(RPC_CN_CREP_IOV (call_rep)[0]);
521
522    /*
523     * The start of stub data will depend upon whether the object
524     * UUID field is present.
525     */
526    if (memcmp (&binding_r->obj, &uuid_g_nil_uuid, sizeof (idl_uuid_t)) != 0)
527    {
528        /*
529         * A non-nil object UUID is present.
530         */
531        RPC_CN_PKT_OBJECT(header_p) = binding_r->obj;
532        RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_OBJECT_UUID;
533        RPC_CN_CREP_SIZEOF_HDR (call_rep) = RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ;
534        RPC_CN_CREP_FREE_BYTES (call_rep) =
535            RPC_C_CN_SMALL_FRAG_SIZE - RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ;
536        RPC_CN_CREP_ACC_BYTCNT (call_rep) = RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ;
537        RPC_CN_CREP_FREE_BYTE_PTR(call_rep) =
538        RPC_CN_PKT_RQST_STUB_DATA_W_OBJ (header_p);
539        iov_p->data_len = RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ;
540    }
541    else
542    {
543        /*
544         * There is no object UUID (it is nil) in the binding rep.
545         */
546        RPC_CN_CREP_SIZEOF_HDR (call_rep) = RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ;
547        RPC_CN_CREP_FREE_BYTES (call_rep) =
548            RPC_C_CN_SMALL_FRAG_SIZE - RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ;
549        RPC_CN_CREP_ACC_BYTCNT (call_rep) = RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ;
550        RPC_CN_CREP_FREE_BYTE_PTR(call_rep) =
551        RPC_CN_PKT_RQST_STUB_DATA_NO_OBJ (header_p);
552        iov_p->data_len = RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ;
553    }
554
555    /*
556     * Evaluate the RPC_REQUEST event.
557     * If we return successfully, an association should be allocated
558     * and we should be in the call_pending state.
559     */
560
561    RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_START_CALL,
562                            ifspec_r,
563                            call_rep,
564                            *st);
565
566    if (*st == rpc_s_ok)
567    {
568        /*
569         * Use the presentation context id in the call rep. This was
570         * placed there by the rpc__cn_assoc_alloc routine.
571         */
572        RPC_CN_PKT_PRES_CONT_ID (header_p) = call_rep->context_id;
573
574        /*
575         * Use the negotiated minor version number from the association.
576         */
577        RPC_CN_PKT_VERS_MINOR (header_p) = call_rep->assoc->assoc_vers_minor;
578
579        /*
580         * If security is requested for this call an auth trailer will
581         * be formatted here and included with every packet sent.
582         */
583        if (call_rep->sec != NULL)
584        {
585            rpc_cn_auth_tlr_t       *auth_tlr;
586            unsigned32              auth_value_len;
587
588            /*
589             * Allocate a small fragbuf to contain the authentication trailer.
590             */
591            RPC_CN_FRAGBUF_ALLOC (call_rep->prot_tlr, RPC_C_CN_SMALL_FRAG_SIZE, st);
592            call_rep->prot_tlr->fragbuf_dealloc = NULL;
593            auth_value_len = RPC_C_CN_SMALL_FRAG_SIZE;
594            auth_tlr = (rpc_cn_auth_tlr_t *)call_rep->prot_tlr->data_p;
595            auth_tlr->auth_type = RPC_CN_AUTH_CVT_ID_API_TO_WIRE (call_rep->sec->sec_info->authn_protocol, st);
596            auth_tlr->auth_level = call_rep->sec->sec_info->authn_level;
597            auth_tlr->key_id = call_rep->sec->sec_key_id;
598            auth_tlr->stub_pad_length = 0;
599            auth_tlr->reserved = 0;
600            RPC_CN_AUTH_PRE_CALL (RPC_CN_ASSOC_SECURITY (call_rep->assoc),
601                                  call_rep->sec,
602                                  (dce_pointer_t) auth_tlr->auth_value,
603                                  &auth_value_len,
604                                  st);
605            RPC_CN_CREP_ADJ_IOV_FOR_TLR (call_rep, header_p, auth_value_len);
606        }
607        else
608        {
609            RPC_CN_PKT_AUTH_LEN (header_p) = 0;
610        }
611
612        /*
613         * Return the negotiated transfer syntax placed in the call
614         * rep by rpc__cn_assoc_alloc.
615         */
616        *transfer_syntax = call_rep->transfer_syntax;
617    }
618    else
619    {
620        /*
621         * We had a problem. Clean-up using call-end.
622         */
623        RPC_CN_UNLOCK ();
624        rpc__cn_call_end ((rpc_call_rep_p_t *) &call_rep, &temp_st);
625        RPC_CN_LOCK ();
626    }
627
628    /*
629     * Release the CN global mutex to allow other threads to
630     * run.
631     */
632    RPC_CN_UNLOCK ();
633    RPC_LOG_CN_CALL_START_XIT;
634    return ((rpc_call_rep_p_t) call_rep);
635}
636
637
638/*
639**++
640**
641**  ROUTINE NAME:       rpc__cn_call_transmit
642**
643**  SCOPE:              PRIVATE - declared in cncall.h
644**
645**  DESCRIPTION:
646**
647**  This is the NCA connection oriented protocol specific routine
648**  to transmit a vector or marshalled arguments to the remote
649**  thread.  It uses the call rep as the identifier of the RPC
650**  being performed.  This routine is intended for use by the
651**  client or server stub only.
652**
653**  INPUTS:
654**
655**      call_r          The call rep containing information
656**                      pertaining to this RPC.
657**      call_args       A vector of buffers containing marshaled RPC
658**                      arguments.
659**
660**  INPUTS/OUTPUTS:     none
661**
662**  OUTPUTS:
663**
664**      st              The return status of this routine.
665**          rpc_s_ok        The call was successful.
666**          rpc_s_cancel_timeout
667**                          After forwarding a local alert, the
668**                          client timed out waiting for the
669**                          call to complete.
670**
671**  IMPLICIT INPUTS:    none
672**
673**  IMPLICIT OUTPUTS:   none
674**
675**  FUNCTION VALUE:     none
676**
677**  SIDE EFFECTS:       none
678**
679**--
680**/
681
682PRIVATE void rpc__cn_call_transmit
683(
684  rpc_call_rep_p_t        call_r,
685  rpc_iovector_p_t        call_args,
686  unsigned32              *st
687)
688{
689    rpc_cn_call_rep_t       *call_rep;
690    rpc_iovector_elt_p_t    iov_elt_p;
691    unsigned32              i;
692    rpc_cn_fragbuf_p_t      frag_buf;
693    rpc_cn_packet_p_t       header_p;
694    unsigned32              fault_code;
695    boolean                 valid_fragbuf;
696
697    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_transmit);
698    RPC_LOG_CN_CALL_TRANSMIT_NTR;
699    CODING_ERROR (st);
700
701    call_rep = (rpc_cn_call_rep_p_t) call_r;
702
703    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
704                    ("CN: call_rep->%p call transmit...\n",
705                     call_rep));
706
707    if (RPC_DBG2 (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT))
708    {
709        RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT,
710                        ("PACKET: call transmit args.num_elt->%d\n", call_args->num_elt));
711        for (i = 0; i < call_args->num_elt; i++)
712        {
713            RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT,
714                            ("        elt[%d]: elt.flags->%x args.buff_len->%d args.data_len->%d\n",
715                             i,
716                             call_args->elt[i].flags,
717                             call_args->elt[i].buff_len,
718                             call_args->elt[i].data_len));
719        }
720    }
721
722    /*
723     * Acquire the CN global mutex to prevent other threads from
724     * running.
725     */
726    RPC_CN_LOCK ();
727
728    /*
729     * The event call_send corresponds to transmit_req on
730     * the client side and rpc_resp on the server side.
731     *
732     * If the call has been orphaned, return rpc_s_call_orphaned
733     * and deallocate any input data.
734     */
735    if (call_rep->cn_call_status == rpc_s_call_orphaned)
736    {
737        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
738                        ("CN: call_rep->%p call orphaned...\n",
739                         call_rep));
740
741        iov_elt_p = call_args->elt;
742        for (i = 1; i <= call_args->num_elt; i++, iov_elt_p++)
743        {
744            if (iov_elt_p->buff_dealloc != NULL)
745            {
746                (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr);
747            }
748        }
749        *st = rpc_s_call_orphaned;
750    }
751    else
752    {
753        RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_SEND,
754                                call_args,
755                                call_rep,
756                                *st);
757        if (((call_rep->call_state.cur_state == RPC_C_CLIENT_CALL_CALL_FAILED)
758	    || (call_rep->call_state.cur_state == RPC_C_CLIENT_CALL_CFDNE))
759	    && ((call_rep->call_state.cur_event == RPC_C_CALL_SEND)
760		|| (call_rep->call_state.cur_event == RPC_C_CALL_TRANSMIT_REQ)
761		|| (call_rep->call_state.cur_event == RPC_C_CALL_LAST_TRANSMIT_REQ)))
762	{
763	    valid_fragbuf = false;
764	    while (!valid_fragbuf)
765	    {
766		rpc__cn_assoc_receive_frag(call_rep->assoc,
767					   &frag_buf,
768					   st);
769
770		if (*st != rpc_s_ok)
771		{
772		    RPC_CN_UNLOCK ();
773		    return;
774		}
775		if (frag_buf->data_p != NULL)
776		{
777		    valid_fragbuf = true;
778		}
779	    }
780	    /*
781	     * Now adjust data_p to point to just the stub data.
782	     * Note that data_size has already been adjusted by
783	     * raise_fault_action_rtn
784	     */
785	    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep);
786	    if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT)
787	    {
788
789		frag_buf->data_p = (dce_pointer_t)
790				   (RPC_CN_PKT_FAULT_STUB_DATA(header_p));
791
792		/*
793		 * We had conservatively assumed that the call has executed
794		 * as soon as the call started. We can now update that
795		 * information.
796		 */
797
798		if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_DID_NOT_EXECUTE)
799		{
800		    call_rep->call_executed = false;
801		}
802
803		/*
804		 * This can be either a call_reject or a call_fault.
805		 */
806
807		fault_code = RPC_CN_PKT_STATUS(header_p);
808		RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
809				("CN: call_rep->%p fault packet received st=%x\n",
810				  call_rep, fault_code));
811		if (fault_code)
812		{
813		    /*
814		     * Non-zero fault code implies a call_reject.
815		     */
816
817		    /*
818		     * Deallocate the fragment buffer since we won't be returning
819		     * it to the client stub.
820		     */
821
822		    (* frag_buf->fragbuf_dealloc) (frag_buf);
823		    /*
824		     * We translate the on-wire fault code into a local status
825		     * and return it.
826		     */
827		    *st = rpc__cn_call_cvt_from_nca_st(fault_code);
828
829		    /*
830		     * Release the CN global mutex to allow other threads to run
831		     */
832
833		    RPC_CN_UNLOCK ();
834		    return;
835		}
836		else
837		{
838		    /*
839		     * On a fault, we store the address of the fragment buffer
840		     * in the call_rep for later retrieval via
841		     * rpc__receive_fault.
842		     */
843
844		    call_rep->u.client.fault_data = frag_buf;
845		    *st = rpc_s_call_faulted;
846
847		    /*
848		     * Release the CN global mutex to allow other threads to
849		     * run.
850		     */
851
852		    RPC_CN_UNLOCK ();
853		    return;
854		}
855	    }
856	}
857
858        /*
859         * Check for any pending cancels just in case we're in a
860         * long marshalling loop and not calling any cancellable
861         * operations. Also, forward any cancels which may have been
862         * queued already before we were ready to forward them.
863         */
864        if (RPC_CALL_IS_CLIENT (call_r))
865        {
866            RPC_CN_CHK_AND_FWD_CANCELS (call_rep, st);
867        }
868    }
869
870    /*
871     * Release the CN global mutex to allow other threads to
872     * run.
873     */
874    RPC_CN_UNLOCK ();
875    RPC_LOG_CN_CALL_TRANSMIT_XIT;
876}
877
878
879/*
880**++
881**
882**  ROUTINE NAME:       rpc__cn_call_transceive
883**
884**  SCOPE:              PRIVATE - declared in cncall.h
885**
886**  DESCRIPTION:
887**
888**  This is the NCA connection oriented protocol specific routine
889**  to transmit a vector of marshalled arguments to the remote
890**  thread.  It uses the call rep as the identifier of the RPC
891**  being performed.  Block until the first buffer of marshalled
892**  output arguments has been received.  This routine is intended
893**  for use by the client stub only.
894**
895**  INPUTS:
896**
897**      call_r          The call rep containing information
898**                      pertaining to this RPC.
899**      in_call_args    A vector of buffers containing marshaled RPC
900**                      input arguments.
901**
902**  INPUTS/OUTPUTS:     none
903**
904**  OUTPUTS:
905**
906**      out_call_args   A buffer containing marshaled RPC output
907**                      arguments.
908**      remote_ndr_format The Network Data Representation of the
909**                      server machine.
910**      st              The return status of this routine.
911**          rpc_s_ok        The call was successful.
912**          rpc_s_call_faulted
913**                          A fault was received.
914**          rpc_s_cancel_timeout
915**                          After forwarding a local alert, the
916**                          client timed out waiting for the
917**                          call to complete.
918**
919**
920**  IMPLICIT INPUTS:    none
921**
922**  IMPLICIT OUTPUTS:   none
923**
924**  FUNCTION VALUE:     none
925**
926**  SIDE EFFECTS:       none
927**
928**--
929**/
930
931PRIVATE void rpc__cn_call_transceive
932(
933  rpc_call_rep_p_t        call_r,
934  rpc_iovector_p_t        in_call_args,
935  rpc_iovector_elt_t      *out_call_args,
936  ndr_format_t            *remote_ndr_format,
937  unsigned32              *st
938)
939{
940    rpc_cn_call_rep_p_t     call_rep;
941    rpc_cn_fragbuf_p_t      frag_buf;
942    rpc_cn_packet_p_t       header_p;
943    rpc_iovector_elt_p_t    iov_elt_p;
944    unsigned32              fault_code;
945    unsigned32              i;
946    boolean                 valid_fragbuf;
947    unsigned32              temp_status;
948
949    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_transceive);
950    RPC_LOG_CN_CALL_TRANSCEIVE_NTR;
951    CODING_ERROR (st);
952
953    call_rep = (rpc_cn_call_rep_p_t) call_r;
954
955    out_call_args->buff_dealloc = NULL;
956    out_call_args->data_addr = (byte_p_t) NULL;
957    out_call_args->data_len = 0;
958
959    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
960                    ("CN: call_rep->%p call transceive...\n",
961                     call_rep));
962
963    if (RPC_DBG2 (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT))
964    {
965        RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT,
966                        ("PACKET: call transceive in_args.num_elt->%d\n", in_call_args->num_elt));
967        for (i = 0; i < in_call_args->num_elt; i++)
968        {
969            RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT,
970                            ("        elt[%d]: elt.flags->%x in_args.buff_len->%d in_args.data_len->%d\n",
971                             i,
972                             in_call_args->elt[i].flags,
973                             in_call_args->elt[i].buff_len,
974                             in_call_args->elt[i].data_len));
975        }
976    }
977
978    /*
979     * Acquire the CN global mutex to prevent other threads from
980     * running.
981     */
982    RPC_CN_LOCK ();
983
984    rpc_g_cn_mgmt.calls_sent++;
985
986    /*
987     * If the call has been orphaned, return rpc_s_call_orphaned
988     * and deallocate any input data.
989     */
990    if (call_rep->cn_call_status == rpc_s_call_orphaned)
991    {
992        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
993                        ("CN: call_rep->%p call orphaned...\n",
994                         call_rep));
995
996        out_call_args->buff_dealloc = NULL;
997        out_call_args->data_addr = (byte_p_t) NULL;
998        out_call_args->data_len = 0;
999
1000        /*
1001         * Free the input args.
1002         */
1003        iov_elt_p = in_call_args->elt;
1004        for (i = 1; i <= in_call_args->num_elt; i++, iov_elt_p++)
1005        {
1006            if (iov_elt_p->buff_dealloc != NULL)
1007            {
1008                (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr);
1009            }
1010        }
1011        *st = rpc_s_call_orphaned;
1012
1013        /*
1014         * Release the CN global mutex to allow other threads to
1015         * run.
1016         */
1017        RPC_CN_UNLOCK ();
1018        return;
1019    }
1020
1021    /*
1022     * Transmit arguments to remote thread.
1023     * This is the last send fragment.
1024     * Note that we might get NULL data.
1025     */
1026    RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_LAST_TRANSMIT_REQ,
1027                           in_call_args,
1028                           call_rep,
1029                           temp_status);
1030
1031    if (call_rep->cn_call_status == rpc_s_ok)
1032    {
1033	/*
1034	 * Check for any pending cancels just in case we're in a
1035	 * long marshalling loop and not calling any cancellable
1036	 * operations. Also, forward any cancels which may have been
1037	 * queued already before we were ready to forward them.
1038	 */
1039	RPC_CN_CHK_AND_FWD_CANCELS (call_rep, &call_rep->cn_call_status);
1040
1041        /*
1042         * Do a receive if the call does not have maybe semantics.
1043         */
1044        header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep);
1045        if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE) == 0)
1046        {
1047            /*
1048             * If we have already received the last fragment,
1049             * return a null iovector element.
1050             */
1051            if (call_rep->last_frag_received)
1052            {
1053                out_call_args->buff_dealloc = NULL;
1054                out_call_args->data_addr = (byte_p_t) NULL;
1055                out_call_args->data_len = 0;
1056            }
1057            else
1058            {
1059                /*
1060                 * Receive a packet from the association.
1061                 * (The receive routine allocates the fragment buffer.)
1062                 * Make sure the fragbuf is not left over from an
1063                 * orphaned presentation negotiation.
1064                 */
1065                valid_fragbuf = false;
1066                while (!valid_fragbuf)
1067                {
1068                    rpc__cn_assoc_receive_frag (call_rep->assoc,
1069                                                &frag_buf,
1070                                                st);
1071
1072                    if (*st != rpc_s_ok)
1073                    {
1074                        out_call_args->buff_dealloc = NULL;
1075                        out_call_args->data_addr = (byte_p_t) NULL;
1076                        out_call_args->data_len = 0;
1077                        RPC_CN_UNLOCK ();
1078                        return;
1079                    }
1080                    if (frag_buf->data_p != NULL)
1081                    {
1082                        valid_fragbuf = true;
1083                    }
1084                }
1085
1086                /*
1087                 * Set call_rep->last_frag_received if this is the last fragment.
1088                 */
1089                header_p = (rpc_cn_packet_p_t) frag_buf->data_p;
1090                if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG)
1091                {
1092                    call_rep->last_frag_received = true;
1093                }
1094
1095                /* check to see if las_frag should have been set in this packet or not */
1096                if ((RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_REQUEST) ||
1097                    (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT) &&
1098                    (RPC_CN_PKT_ALLOC_HINT (header_p) != 0) )
1099                {
1100                    /* Request, responses and fault pkts have the alloc_hint that
1101                     we can use to check the validity of last frag flag.
1102                     Note:  alloc_hint field can be 0 */
1103                    if ( (RPC_CN_PKT_ALLOC_HINT (header_p) <= frag_buf->data_size) &&
1104                        !(RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) )
1105                    {
1106                        *st = rpc_s_call_faulted;
1107
1108                        /*
1109                         * Release the CN global mutex to allow other threads to
1110                         * run.
1111                         */
1112                        RPC_CN_UNLOCK ();
1113
1114                        /* since this is only called by the client side, abort the client
1115                         since the client did something invalid */
1116                        rpc_dce_svc_printf (
1117                            __FILE__, __LINE__,
1118                            "%s flags 0x%x call id %d alloc_hint %d rcvd data size %d",
1119                            rpc_svc_recv,
1120                            svc_c_sev_fatal | svc_c_action_abort,
1121                            rpc_s_protocol_error,
1122                            "rpc__cn_call_transceive - last frag should be set",
1123                            RPC_CN_PKT_FLAGS (header_p),
1124                            RPC_CN_PKT_CALL_ID (header_p),
1125                            RPC_CN_PKT_ALLOC_HINT (header_p),
1126                            frag_buf->data_size );
1127
1128                        return;
1129                    }
1130                }
1131
1132                /*
1133                 * Copy the drep field from the association
1134                 * (which is in the 4 byte wire format)
1135                 * to the output remote_ndr_format arg.
1136                 */
1137                *remote_ndr_format = RPC_CN_ASSOC_NDR_FORMAT (call_rep->assoc);
1138
1139                /*
1140                 * Now adjust data_p to point to just the stub data.
1141                 * Note that data_size has already been adjusted.
1142                 */
1143                if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_RESPONSE)
1144                {
1145                    frag_buf->data_p = (dce_pointer_t)
1146                                      (RPC_CN_PKT_RESP_STUB_DATA(header_p));
1147                }
1148                else if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT)
1149                {
1150                    frag_buf->data_p = (dce_pointer_t)
1151                        RPC_CN_PKT_FAULT_STUB_DATA (header_p);
1152                    /*
1153                     * We had conservatively assumed that the call
1154                     * has executed as soon as the call started.
1155                     * We can now update that information.
1156                     */
1157                    if (RPC_CN_PKT_FLAGS (header_p) &
1158                        RPC_C_CN_FLAGS_DID_NOT_EXECUTE)
1159                    {
1160                        call_rep->call_executed = false;
1161                    }
1162
1163                    /*
1164                     * This can be either a call_reject or a call_fault.
1165                     */
1166                    fault_code = RPC_CN_PKT_STATUS(header_p);
1167                    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1168                                    ("CN: call_rep->%p fault packet received st = %x\n",
1169                                     call_rep,
1170                                     fault_code));
1171                    if (fault_code)
1172                    {
1173                        /*
1174                         * Non-zero fault code implies a call_reject.
1175                         */
1176
1177                        /*
1178                         * Deallocate the fragment buffer since we
1179                         * won't be returning it to the client stub.
1180                         */
1181                        (* frag_buf->fragbuf_dealloc) (frag_buf);
1182
1183                        /*
1184                         * We translate the on-wire fault code into
1185                         * a local status code & return it.
1186                         */
1187                        *st = rpc__cn_call_cvt_from_nca_st (fault_code);
1188
1189                        /*
1190                         * Release the CN global mutex to allow other threads to
1191                         * run.
1192                         */
1193                        RPC_CN_UNLOCK ();
1194                        return;
1195                    }
1196                    else
1197                    {
1198                        /*
1199                         * On a fault, we store the address of the fragment
1200                         * buffer in the call_rep for later retrieval via
1201                         * rpc__receive_fault.
1202                         */
1203                        call_rep->u.client.fault_data = frag_buf;
1204                        *st = rpc_s_call_faulted;
1205
1206                        /*
1207                         * Release the CN global mutex to allow other threads to
1208                         * run.
1209                         */
1210                        RPC_CN_UNLOCK ();
1211                        return;
1212                    }
1213                }
1214                else
1215                {
1216                    /*
1217                     * This is a protocol error, just return the whole
1218                     * packet.
1219                     */
1220                    call_rep->cn_call_status = rpc_s_protocol_error;
1221                }
1222
1223                if (frag_buf->data_size > 0)
1224                {
1225                    /*
1226                     * Set up the iovector element to point to the received data.
1227                     */
1228                    out_call_args->buff_dealloc =
1229                        (rpc_buff_dealloc_fn_t)frag_buf->fragbuf_dealloc;
1230                    out_call_args->buff_addr = (byte_p_t) frag_buf;
1231                    out_call_args->buff_len = frag_buf->max_data_size;
1232                    out_call_args->data_addr = (byte_p_t) frag_buf->data_p;
1233                    out_call_args->data_len = frag_buf->data_size;
1234
1235                }
1236                else
1237                {
1238                    /*
1239                     * No stub data.
1240                     */
1241                    out_call_args->data_addr = (byte_p_t) NULL;
1242                    out_call_args->data_len = 0;
1243
1244                    /*
1245                     * We also deallocate the fragbuf now.
1246                     */
1247                    (* frag_buf->fragbuf_dealloc) (frag_buf);
1248                }
1249            }
1250        }
1251    }
1252    *st = call_rep->cn_call_status;
1253
1254    /*
1255     * Release the CN global mutex to allow other threads to
1256     * run.
1257     */
1258    RPC_CN_UNLOCK ();
1259
1260    RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT,
1261        ("PACKET: call transceive out_elt.flags->%x out_elt.buff_len->%d out_elt.data_len->%d\n",
1262        out_call_args->flags,
1263        out_call_args->buff_len,
1264        out_call_args->data_len));
1265    RPC_LOG_CN_CALL_TRANSCEIVE_XIT;
1266}
1267
1268
1269/*
1270**++
1271**
1272**  ROUTINE NAME:       rpc__cn_call_receive
1273**
1274**  SCOPE:              PRIVATE - declared in cncall.h
1275**
1276**  DESCRIPTION:
1277**
1278**  Return a buffer of marshalled arguments from the remote
1279**  thread.  This routine is intended for use by the client
1280**  or server stub only.
1281**
1282**  INPUTS:
1283**
1284**      call_r          The call rep containing information
1285**                      pertaining to this RPC.
1286**
1287**  INPUTS/OUTPUTS:     none
1288**
1289**  OUTPUTS:
1290**
1291**      call_args       A vector of buffers containing marshaled RPC
1292**                      arguments.
1293**      st              The return status of this routine.
1294**          rpc_s_ok        The call was successful.
1295**          rpc_s_call_orphaned
1296**          rpc_s_call_faulted
1297**          rpc_s_protocol_error
1298**
1299**
1300**  IMPLICIT INPUTS:    none
1301**
1302**  IMPLICIT OUTPUTS:   none
1303**
1304**  FUNCTION VALUE:     none
1305**
1306**  SIDE EFFECTS:       none
1307**
1308**--
1309**/
1310
1311PRIVATE void rpc__cn_call_receive
1312(
1313  rpc_call_rep_p_t        call_r,
1314  rpc_iovector_elt_p_t    call_args,
1315  unsigned32              *st
1316)
1317{
1318    rpc_cn_call_rep_t       *call_rep;
1319    rpc_cn_packet_p_t       header_p;
1320    rpc_cn_fragbuf_p_t      frag_buf;
1321    unsigned32              fault_code;
1322    boolean                 valid_fragbuf;
1323
1324    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_receive);
1325    RPC_LOG_CN_CALL_RECEIVE_NTR;
1326    CODING_ERROR (st);
1327
1328    call_rep = (rpc_cn_call_rep_p_t) call_r;
1329
1330    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1331                    ("CN: call_rep->%p call receive...\n",
1332                     call_rep));
1333
1334    /*
1335     * Acquire the CN global mutex to prevent other threads from
1336     * running.
1337     */
1338    RPC_CN_LOCK ();
1339
1340    /*
1341     * If the call has been orphaned, return rpc_s_call_orphaned.
1342     */
1343    if (call_rep->cn_call_status == rpc_s_call_orphaned)
1344    {
1345        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1346                        ("CN: call_rep->%p call orphaned...\n",
1347                         call_rep));
1348
1349        call_args->buff_dealloc = NULL;
1350        call_args->data_addr = (byte_p_t) NULL;
1351        call_args->data_len = 0;
1352        *st = rpc_s_call_orphaned;
1353
1354        /*
1355         * Release the CN global mutex to allow other threads to
1356         * run.
1357         */
1358        RPC_CN_UNLOCK ();
1359        return;
1360    }
1361
1362    /*
1363     * If we have already received the last fragment,
1364     * return a null iovector element.
1365     */
1366    if (call_rep->last_frag_received)
1367    {
1368        call_args->buff_dealloc = NULL;
1369        call_args->data_addr = (byte_p_t) NULL;
1370        call_args->data_len = 0;
1371        *st = rpc_s_ok;
1372
1373        /*
1374         * Release the CN global mutex to allow other threads to
1375         * run.
1376         */
1377        RPC_CN_UNLOCK ();
1378        RPC_LOG_CN_CALL_RECEIVE_XIT;
1379        return;
1380    }
1381
1382    /*
1383     * Receive a packet from the association.
1384     * (The receive routine allocates the fragment buffer.)
1385     * Make sure the fragbuf is not left over from an
1386     * orphaned presentation negotiation.
1387     */
1388    valid_fragbuf = false;
1389    while (!valid_fragbuf)
1390    {
1391        rpc__cn_assoc_receive_frag (call_rep->assoc,
1392                                    &frag_buf,
1393                                    st);
1394        if (*st != rpc_s_ok)
1395        {
1396            call_args->buff_dealloc = NULL;
1397            call_args->data_addr = (byte_p_t) NULL;
1398            call_args->data_len = 0;
1399            RPC_CN_UNLOCK ();
1400            return;
1401        }
1402        if (frag_buf->data_p != NULL)
1403        {
1404            valid_fragbuf = true;
1405        }
1406    }
1407
1408    /*
1409     * Set call_rep->last_frag_received if this is the last fragment.
1410     */
1411    header_p = (rpc_cn_packet_p_t) frag_buf->data_p;
1412    if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG)
1413    {
1414        call_rep->last_frag_received = true;
1415    }
1416
1417    /* check to see if las_frag should have been set in this packet or not */
1418    if ((RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_REQUEST) ||
1419        (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT) &&
1420        (RPC_CN_PKT_ALLOC_HINT (header_p) != 0) )
1421    {
1422        /* Request, responses and fault pkts have the alloc_hint that
1423         we can use to check the validity of last frag flag.
1424         Note:  alloc_hint field can be 0 */
1425        if ( (RPC_CN_PKT_ALLOC_HINT (header_p) <= frag_buf->data_size) &&
1426            !(RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) )
1427        {
1428            RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT,
1429                            ("PACKET: call receive last frag should have been set. flags 0x%x call id %d alloc_hint %d rcvd data size %d\n",
1430                             RPC_CN_PKT_FLAGS (header_p),
1431                             RPC_CN_PKT_CALL_ID (header_p),
1432                             RPC_CN_PKT_ALLOC_HINT (header_p),
1433                             frag_buf->data_size));
1434            *st = rpc_s_call_faulted;
1435
1436            /*
1437             * Release the CN global mutex to allow other threads to
1438             * run.
1439             */
1440            RPC_CN_UNLOCK ();
1441            return;
1442        }
1443    }
1444
1445    /*
1446     * Now adjust data_p to point to just the stub data.
1447     * Note that data_size has already been adjusted.
1448     * To do this properly, we have to check the packet
1449     * type.
1450     */
1451    if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_RESPONSE)
1452    {
1453        frag_buf->data_p = (dce_pointer_t)
1454                      (RPC_CN_PKT_RESP_STUB_DATA(header_p));
1455    }
1456    else if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_REQUEST)
1457    {
1458        if (RPC_CN_PKT_OBJ_UUID_PRESENT (header_p))
1459        {
1460                frag_buf->data_p = (dce_pointer_t)
1461                    RPC_CN_PKT_RQST_STUB_DATA_W_OBJ (header_p);
1462        }
1463        else
1464        {
1465            frag_buf->data_p = (dce_pointer_t)
1466                RPC_CN_PKT_RQST_STUB_DATA_NO_OBJ (header_p);
1467        }
1468    }
1469    else if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT)
1470    {
1471        frag_buf->data_p = (dce_pointer_t) RPC_CN_PKT_FAULT_STUB_DATA (header_p);
1472        /*
1473         * We had conservatively assumed that the call
1474         * has executed as soon as the call started.
1475         * We can now update that information.
1476         */
1477        if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_DID_NOT_EXECUTE)
1478        {
1479            call_rep->call_executed = false;
1480        }
1481
1482        /*
1483         * This can be either a call_reject or a call_fault.
1484         */
1485        fault_code = RPC_CN_PKT_STATUS(header_p);
1486        if (fault_code)
1487        {
1488            /*
1489             * Deallocate the fragment buffer since we
1490             * won't be returning it to the client stub.
1491             */
1492            (* frag_buf->fragbuf_dealloc) (frag_buf);
1493
1494            /*
1495             * Non-zero fault code implies a call_reject.
1496             *
1497             * We translate the on-wire fault code into
1498             * a local status code & return it.
1499             */
1500            *st = rpc__cn_call_cvt_from_nca_st (fault_code);
1501
1502            /*
1503             * Release the CN global mutex to allow other threads to
1504             * run.
1505             */
1506            RPC_CN_UNLOCK ();
1507            return;
1508        }
1509        else
1510        {
1511            /*
1512             * On a fault, we store the address of the fragment
1513             * buffer in the call_rep for later retrieval via
1514             * rpc__receive_fault.
1515             */
1516            call_rep->u.client.fault_data = frag_buf;
1517            *st = rpc_s_call_faulted;
1518
1519            /*
1520             * Release the CN global mutex to allow other threads to
1521             * run.
1522             */
1523            RPC_CN_UNLOCK ();
1524            return;
1525        }
1526    }
1527    else
1528    {
1529        /*
1530         * This is a protocol error, just return the whole
1531         * packet.
1532         */
1533        call_rep->cn_call_status = rpc_s_protocol_error;
1534    }
1535
1536    if (frag_buf->data_size > 0)
1537    {
1538        /*
1539         * Set up the iovector element to point to the received data.
1540         */
1541        call_args->buff_addr = (byte_p_t) frag_buf;
1542        call_args->buff_len = frag_buf->max_data_size;
1543        call_args->data_addr = (byte_p_t) frag_buf->data_p;
1544        call_args->data_len = frag_buf->data_size;
1545        call_args->buff_dealloc =
1546                (rpc_buff_dealloc_fn_t)frag_buf->fragbuf_dealloc;
1547    }
1548    else
1549    {
1550        /*
1551         * No stub data.
1552         */
1553        call_args->data_addr = (byte_p_t) NULL;
1554        call_args->data_len = 0;
1555
1556        /*
1557         * We also deallocate the fragbuf now.
1558         */
1559        (* frag_buf->fragbuf_dealloc) (frag_buf);
1560    }
1561
1562    /*
1563     * Check for any pending cancels just in case we're in a
1564     * long unmarshalling loop and not calling any cancellable
1565     * operations. Also, forward any cancels which may have been
1566     * queued already before we were ready to forward them.
1567     */
1568    if (RPC_CALL_IS_CLIENT (call_r))
1569    {
1570        RPC_CN_CHK_AND_FWD_CANCELS (call_rep, st);
1571    }
1572
1573    /*
1574     * Release the CN global mutex to allow other threads to
1575     * run.
1576     */
1577    *st = call_rep->cn_call_status;
1578    RPC_CN_UNLOCK ();
1579
1580    RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT,
1581        ("PACKET: call receive args.flags->%x args.buff_len->%d args.data_len->%d\n",
1582        call_args->flags,
1583        call_args->buff_len,
1584        call_args->data_len));
1585    RPC_LOG_CN_CALL_RECEIVE_XIT;
1586}
1587
1588
1589/*
1590**++
1591**
1592**  ROUTINE NAME:       rpc__cn_call_block_until_free
1593**
1594**  SCOPE:              PRIVATE - declared in cncall.h
1595**
1596**  DESCRIPTION:
1597**
1598**  This routine will block until all buffers given to the RPC
1599**  runtime by the stub containing marshaled RPC output arguments
1600**  are free.  It is provided for use by the server stub when
1601**  the marshaled arguments are contained in buffers which are
1602**  on stack.  The danger is that the server stub would return
1603**  to the RPC runtime thereby invalidating its stack and buffer
1604**  contents.  This routine is intended for use by the server
1605**  stub only.
1606**
1607**  INPUTS:
1608**
1609**      call_r          The call rep containing information
1610**                      pertaining to this RPC.
1611**
1612**  INPUTS/OUTPUTS:     none
1613**
1614**  OUTPUTS:
1615**
1616**      st              The return status of this routine.
1617**          rpc_s_ok        The call was successful.
1618**
1619**  IMPLICIT INPUTS:    none
1620**
1621**  IMPLICIT OUTPUTS:   none
1622**
1623**  FUNCTION VALUE:     none
1624**
1625**  SIDE EFFECTS:       none
1626**
1627**--
1628**/
1629
1630PRIVATE void rpc__cn_call_block_until_free
1631(
1632  rpc_call_rep_p_t        call_r,
1633  unsigned32              *st
1634)
1635{
1636    rpc_cn_call_rep_t       *call_rep;
1637
1638    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_block_until_free);
1639    CODING_ERROR (st);
1640
1641    call_rep = (rpc_cn_call_rep_p_t) call_r;
1642
1643    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1644                    ("CN: call_rep->%p call block until free...\n",
1645                     call_rep));
1646
1647    /*
1648     * Acquire the CN global mutex to prevent other threads from
1649     * running.
1650     */
1651    RPC_CN_LOCK ();
1652
1653    if (RPC_CN_CREP_ACC_BYTCNT (call_rep) >= RPC_CN_CREP_SIZEOF_HDR (call_rep))
1654    {
1655        rpc__cn_transmit_buffers (call_rep, st);
1656        rpc__cn_dealloc_buffered_data (call_rep);
1657        RPC_CN_FREE_ALL_EXCEPT_PROT_HDR (call_rep);
1658    }
1659
1660    /*
1661     * Release the CN global mutex to allow other threads to
1662     * run.
1663     */
1664    RPC_CN_UNLOCK ();
1665}
1666
1667
1668/*
1669**++
1670**
1671**  ROUTINE NAME:       rpc__cn_call_alert
1672**
1673**  SCOPE:              PRIVATE - declared in cncall.h
1674**
1675**  DESCRIPTION:
1676**
1677**  This routine forwards a local alert to the remote RPC thread
1678**  identified by the call rep provided.  This routine is intended
1679**  for use by the client stub only.
1680**
1681**  INPUTS:
1682**
1683**      call_r          The call rep containing information
1684**                      pertaining to this RPC.
1685**
1686**  INPUTS/OUTPUTS:     none
1687**
1688**  OUTPUTS:
1689**
1690**      st              The return status of this routine.
1691**          rpc_s_ok        The call was successful.
1692**          rpc_s_alert_failed
1693**
1694**  IMPLICIT INPUTS:    none
1695**
1696**  IMPLICIT OUTPUTS:   none
1697**
1698**  FUNCTION VALUE:     none
1699**
1700**  SIDE EFFECTS:       none
1701**
1702**--
1703**/
1704
1705PRIVATE void rpc__cn_call_alert
1706(
1707  rpc_call_rep_p_t        call_r,
1708  unsigned32              *st
1709)
1710{
1711    rpc_cn_call_rep_t   *call_rep;
1712    volatile boolean32  retry_op;
1713
1714    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_alert);
1715    CODING_ERROR (st);
1716
1717    call_rep = (rpc_cn_call_rep_p_t) call_r;
1718
1719    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1720                    ("CN: call_rep->%p call cancel...\n",
1721                     call_rep));
1722
1723    /*
1724     * Acquire the CN global mutex to prevent other threads from
1725     * running.
1726     */
1727    RPC_CN_LOCK ();
1728
1729    /*
1730     * The stub has detected a local cancel. Do the right thing
1731     * based on whether we're a client or server.
1732     */
1733    rpc__cn_call_local_cancel (call_rep, &retry_op, st);
1734
1735    /*
1736     * Release the CN global mutex to allow other threads to
1737     * run.
1738     */
1739    RPC_CN_UNLOCK ();
1740}
1741
1742
1743/*
1744**++
1745**
1746**  ROUTINE NAME:       rpc__cn_call_end
1747**
1748**  SCOPE:              PRIVATE - declared in cncall.h
1749**
1750**  DESCRIPTION:
1751**
1752**  Ends a remote procedure call.  This is the last in the sequence
1753**  of calls by the client or server stub.  This call is intended
1754**  for use by the client and server stubs only.
1755**
1756**  INPUTS:             none
1757**
1758**  INPUTS/OUTPUTS:
1759**
1760**      call_r          The call rep containing information
1761**                      pertaining to this RPC. A NULL will be
1762**                      returned if this call is successful.
1763**
1764**  OUTPUTS:
1765**
1766**      st              The return status of this routine.
1767**          rpc_s_ok        The call was successful.
1768**
1769**  IMPLICIT INPUTS:    none
1770**
1771**  IMPLICIT OUTPUTS:   none
1772**
1773**  FUNCTION VALUE:     none
1774**
1775**  SIDE EFFECTS:       none
1776**
1777**--
1778**/
1779
1780PRIVATE void rpc__cn_call_end
1781(
1782  rpc_call_rep_p_t        *call_r,
1783  unsigned32              *st
1784)
1785{
1786    rpc_cn_call_rep_t       *call_rep;
1787    unsigned32              cur_iov_index;
1788    rpc_cn_fragbuf_p_t      fault_fbp;
1789    rpc_cn_assoc_t          *assoc;
1790
1791    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_end);
1792    RPC_LOG_CN_CALL_END_NTR;
1793    CODING_ERROR (st);
1794
1795    /*
1796     * Acquire the CN global mutex to prevent other threads from
1797     * running.
1798     */
1799    RPC_CN_LOCK ();
1800
1801    call_rep = (rpc_cn_call_rep_p_t) *call_r;
1802
1803    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1804                    ("CN: call_rep->%p call end\n",
1805                     call_rep));
1806
1807    RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT,
1808                    ("PACKET: call end\n"));
1809
1810    if (call_rep != NULL)
1811    {
1812        /*
1813         * Evaluate the state machine with the call_end event
1814         */
1815        RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_END,
1816                                NULL,
1817                                call_rep,
1818                                *st);
1819
1820        /*
1821         * Need to hold on to the assoc in a local variable since
1822         * rpc__cn_assoc_pop_call is going to NULL call_rep->assoc.
1823         * We'll pass the local variable to rpc__cn_assoc_dealloc.
1824         */
1825        assoc = call_rep->assoc;
1826
1827        /*
1828         * Pop the call rep off the association.
1829         */
1830        rpc__cn_assoc_pop_call (call_rep->assoc, call_rep);
1831
1832        /*
1833         * Deallocate the association.
1834         */
1835        rpc__cn_assoc_dealloc (assoc, call_rep, st);
1836
1837        if (RPC_CALL_IS_CLIENT ((rpc_call_rep_p_t) call_rep))
1838        {
1839            /*
1840             * Free remaining fault data fragbufs.
1841             */
1842            if (call_rep->u.client.fault_data != NULL)
1843            {
1844                fault_fbp = (rpc_cn_fragbuf_p_t) (call_rep->u.client.fault_data);
1845                if (fault_fbp->fragbuf_dealloc != NULL)
1846                {
1847                    (*fault_fbp->fragbuf_dealloc) (fault_fbp);
1848                }
1849            }
1850
1851            /*
1852             * Cancel this thread if:
1853             *
1854             * 1) the call completed on the server with a cancel pending
1855             *    or the number of forwarded cancels is greater than the
1856             *    number of cancels received by the server. (Note that
1857             *    handle_recv_frag_action_rtn sets the server_had_pending
1858             *    flag if one of these conditions exist.)
1859             *
1860             * 2) we have caught cancels in this thread but not
1861             *    forwarded them yet.
1862             */
1863            if ((call_rep->u.client.cancel.server_had_pending) ||
1864                (call_rep->u.client.cancel.local_count > 0))
1865            {
1866                RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
1867                               ("(rpc__cn_call_end) call_rep->%p reposting cancel\n", call_rep));
1868                dcethread_interrupt_throw (dcethread_self());
1869            }
1870
1871            /*
1872             * Stop the cancel timer if one was running.
1873             */
1874            rpc__cn_call_stop_cancel_timer (call_rep);
1875        }
1876
1877        /*
1878         * If there are iovector elements in the call_rep,
1879         * free them all.  There would not be any in the case
1880         * of a maybe call.
1881         */
1882        if (RPC_CN_CREP_IOVLEN (call_rep) > 0)
1883        {
1884            for (cur_iov_index = 0;
1885                 cur_iov_index < RPC_CN_CREP_IOVLEN (call_rep);
1886                 cur_iov_index++)
1887            {
1888                if (RPC_CN_CREP_IOV (call_rep) [cur_iov_index].buff_dealloc !=
1889                    NULL)
1890                {
1891                    (RPC_CN_CREP_IOV (call_rep) [cur_iov_index].buff_dealloc)
1892                    (RPC_CN_CREP_IOV (call_rep) [cur_iov_index].buff_addr);
1893                }
1894                RPC_CN_CREP_IOV (call_rep) [cur_iov_index].buff_addr = NULL;
1895            }
1896        }
1897
1898        /*
1899         * If security was used on this call free the fragbuf used
1900         * for the authentication trailer.  We check to make sure
1901         * that the fragbuf actually exists because we do not allocate
1902         * one on the server side for maybe calls.
1903         */
1904        if ((call_rep->sec) && (call_rep->prot_tlr != NULL))
1905        {
1906            rpc__cn_smfragbuf_free (call_rep->prot_tlr);
1907        }
1908
1909        /*
1910         * Free the call_rep itself.
1911         */
1912        rpc__list_element_free (&rpc_g_cn_call_lookaside_list,
1913                                (dce_pointer_t) call_rep);
1914        *call_r = NULL;
1915    }
1916    else
1917    {
1918        *st = rpc_s_ok;
1919    }
1920
1921    /*
1922     * Release the CN global mutex to allow other threads to
1923     * run.
1924     */
1925    RPC_CN_UNLOCK ();
1926
1927    RPC_LOG_CN_CALL_END_XIT;
1928}
1929
1930
1931/*
1932**++
1933**
1934**  ROUTINE NAME:       rpc__cn_call_transmit_fault
1935**
1936**  SCOPE:              PRIVATE - declared in cncall.h
1937**
1938**  DESCRIPTION:
1939**
1940**  This routine forwards an exception to the remote RPC thread
1941**  identified by the call rep.  This routine is intended for
1942**  server stub use only.
1943**
1944**  INPUTS:
1945**
1946**      call_r          The call rep containing information
1947**                      pertaining to this RPC.
1948**      call_fault_info Marshaled fault information to be returned
1949**                      to the client.
1950**
1951**  INPUTS/OUTPUTS:     none
1952**
1953**  OUTPUTS:
1954**
1955**      st              The return status of this routine.
1956**          rpc_s_ok        The call was successful.
1957**
1958**  IMPLICIT INPUTS:    none
1959**
1960**  IMPLICIT OUTPUTS:   none
1961**
1962**  FUNCTION VALUE:     none
1963**
1964**  SIDE EFFECTS:       none
1965**
1966**--
1967**/
1968
1969PRIVATE void rpc__cn_call_transmit_fault
1970(
1971  rpc_call_rep_p_t        call_r,
1972  rpc_iovector_p_t        call_fault_info,
1973  unsigned32              *st
1974)
1975{
1976    rpc_cn_call_rep_p_t     call_rep;
1977    rpc_iovector_elt_p_t    iov_elt_p;
1978    unsigned32              i;
1979
1980    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_transmit_fault);
1981    CODING_ERROR (st);
1982
1983    call_rep = (rpc_cn_call_rep_p_t) call_r;
1984
1985    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
1986                    ("CN: call_rep->%p call transmit fault\n",
1987                     call_rep));
1988
1989    /*
1990     * Acquire the CN global mutex to prevent other threads from
1991     * running.
1992     */
1993    RPC_CN_LOCK ();
1994
1995    /*
1996     * If the call has been orphaned, return rpc_s_call_orphaned
1997     * and deallocate any input data.
1998     */
1999    if (call_rep->cn_call_status == rpc_s_call_orphaned)
2000    {
2001        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
2002                        ("CN: call_rep->%p call orphaned...\n",
2003                         call_rep));
2004
2005        iov_elt_p = call_fault_info->elt;
2006        for (i = 1; i <= call_fault_info->num_elt; i++, iov_elt_p++)
2007        {
2008            if (iov_elt_p->buff_dealloc != NULL)
2009            {
2010                (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr);
2011            }
2012        }
2013        *st = rpc_s_call_orphaned;
2014    }
2015    else
2016    {
2017        /*
2018         * Evaluate the state machine with the call_fault event.
2019         */
2020        RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_FAULT,
2021                                call_fault_info,
2022                                call_rep,
2023                                *st);
2024    }
2025
2026    /*
2027     * Release the CN global mutex to allow other threads to
2028     * run.
2029     */
2030    RPC_CN_UNLOCK ();
2031}
2032
2033
2034/*
2035**++
2036**
2037**  ROUTINE NAME:       rpc__cn_call_reject
2038**
2039**  SCOPE:              PRIVATE - declared in cncall.h
2040**
2041**  DESCRIPTION:
2042**
2043**  Map a local status code to an architected status code.
2044**  Send a call reject packet.  This is invoked after an
2045**  error has been discovered in the call executor or receiver
2046**  threads.
2047**
2048**  INPUTS:
2049**
2050**      call_r          The call rep containing information
2051**                      pertaining to this RPC.
2052**      l_st            The local status code which will be mapped
2053**                      to an architected status code to be sent back
2054**                      to the client.
2055**
2056**  INPUTS/OUTPUTS:     none
2057**
2058**  OUTPUTS:            none
2059**
2060**  IMPLICIT INPUTS:    This routine assumes that the prototype
2061**                      send header in the call_rep has been
2062**                      set up.
2063**
2064**  IMPLICIT OUTPUTS:   none
2065**
2066**  FUNCTION VALUE:     none.
2067**
2068**  SIDE EFFECTS:       none
2069**
2070**--
2071**/
2072
2073PRIVATE void rpc__cn_call_reject
2074(
2075  rpc_call_rep_p_t        call_r,
2076  unsigned32              l_st
2077)
2078{
2079    rpc_cn_call_rep_p_t         call_rep;
2080    unsigned32                  st;
2081
2082    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_reject);
2083
2084    call_rep = (rpc_cn_call_rep_p_t) call_r;
2085
2086    RPC_CN_LOCK_ASSERT ();
2087
2088    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
2089                    ("CN: call_rep->%p call rejected - reason = %x\n",
2090                     call_rep, l_st));
2091
2092    /*
2093     * Map the local status code to an appropriate architected
2094     * status code.
2095     */
2096    call_rep->cn_call_status = rpc__cn_call_cvt_to_nca_st (l_st);
2097
2098    /*
2099     * For a fault with an architected status, we pass the
2100     * architected status code in the call rep and pass a null
2101     * fault_data.
2102     */
2103    RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_FAULT_DNE,
2104                            NULL,
2105                            call_rep,
2106                            st);
2107}
2108
2109
2110/*
2111**++
2112**
2113**  ROUTINE NAME:       rpc__cn_call_receive_fault
2114**
2115**  SCOPE:              PRIVATE - declared in cncall.h
2116**
2117**  DESCRIPTION:
2118**
2119**  This routine will unmarshal a fault message from the remote
2120**  (server) thread.  It is intended for use by the client
2121**  stub only.
2122**
2123**  INPUTS:
2124**
2125**      call_r          The call rep containing information
2126**                      pertaining to this RPC.
2127**
2128**  INPUTS/OUTPUTS:     none
2129**
2130**  OUTPUTS:
2131**
2132**      remote_ndr_format  The Network Data Representation format of the remote
2133**                      machine. This is used by the stub to unmarshal
2134**                      arguments encoded using NDR as the trasnfer syntax.
2135**
2136**      call_fault_info A vector of buffers containing marshaled RPC
2137**                      fault information.
2138**
2139**      st              The return status of this routine.
2140**            rpc_s_ok          The call completed normally.
2141**            rpc_s_no_fault    No fault information available.
2142**
2143**
2144**  IMPLICIT INPUTS:    none
2145**
2146**  IMPLICIT OUTPUTS:   none
2147**
2148**  FUNCTION VALUE:     none
2149**
2150**  SIDE EFFECTS:       none
2151**
2152**--
2153**/
2154
2155PRIVATE void rpc__cn_call_receive_fault
2156(
2157  rpc_call_rep_p_t        call_r,
2158  rpc_iovector_elt_p_t    call_fault_info,
2159  ndr_format_t            *remote_ndr_format,
2160  unsigned32              *st
2161
2162)
2163{
2164    rpc_cn_call_rep_t       *call_rep;
2165    rpc_cn_fragbuf_p_t      fault_fragp;
2166
2167    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_receive_fault);
2168    CODING_ERROR (st);
2169
2170    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
2171                    ("CN: call_rep->%p call receive fault\n",
2172                     call_r));
2173
2174    /*
2175     * Acquire the CN global mutex to prevent other threads from
2176     * running.
2177     */
2178    RPC_CN_LOCK ();
2179
2180    /*
2181     * When a fault is received, the appropriate action routine
2182     * would unmarshal it (into a large fragment buffer) and store
2183     * its address in the callrep.
2184     */
2185    call_rep = (rpc_cn_call_rep_p_t) call_r;
2186    fault_fragp = (rpc_cn_fragbuf_p_t) (call_rep->u.client.fault_data);
2187    call_rep->u.client.fault_data = NULL;
2188
2189    if (fault_fragp != NULL)
2190    {
2191        /*
2192         * Copy the remote NDR format into the output arguments.
2193         */
2194        *remote_ndr_format = RPC_CN_ASSOC_NDR_FORMAT (call_rep->assoc);
2195
2196        /*
2197         * We now copy the descriptors into the iovector.
2198         * The stub will deallocate the fragment buffer.
2199         */
2200        call_fault_info->buff_dealloc =
2201            (rpc_buff_dealloc_fn_t)fault_fragp->fragbuf_dealloc;
2202        call_fault_info->buff_addr = (byte_p_t) fault_fragp;
2203        call_fault_info->buff_len = fault_fragp->max_data_size;
2204        call_fault_info->data_addr = (byte_p_t) fault_fragp->data_p;
2205        call_fault_info->data_len = fault_fragp->data_size;
2206
2207        *st = rpc_s_ok;
2208    }
2209    else
2210    {
2211        call_fault_info->buff_dealloc = NULL;
2212        call_fault_info->buff_addr = NULL;
2213        call_fault_info->buff_len = 0;
2214        call_fault_info->data_addr = NULL;
2215        call_fault_info->data_len = 0;
2216
2217        *st = rpc_s_no_fault;
2218    }
2219
2220    /*
2221     * Release the CN global mutex to allow other threads to
2222     * run.
2223     */
2224    RPC_CN_UNLOCK ();
2225}
2226
2227/*
2228**++
2229**
2230**  ROUTINE NAME:       rpc__cn_call_did_mgr_execute
2231**
2232**  SCOPE:              PRIVATE - declared in cncall.h
2233**
2234**  DESCRIPTION:
2235**
2236**  This routine will return whether or not a the manager routine
2237**  for the call identified by the call handle has begun executing or not.
2238**  It is intended for use by the client stub only.
2239**
2240**  INPUTS:
2241**
2242**      call_r          The call rep containing information
2243**                      pertaining to this RPC.
2244**
2245**  INPUTS/OUTPUTS:     none
2246**
2247**  OUTPUTS:
2248**
2249**      st              The return status of this routine.
2250**            rpc_s_ok          The call completed normally.
2251**            rpc_s_no_fault    No fault information available.
2252**
2253**
2254**  IMPLICIT INPUTS:    none
2255**
2256**  IMPLICIT OUTPUTS:   none
2257**
2258**  FUNCTION VALUE:
2259**
2260**      boolean32       true if the manager routine has begun, false otherwise.
2261**
2262**  SIDE EFFECTS:       none
2263**
2264**--
2265**/
2266
2267PRIVATE boolean32 rpc__cn_call_did_mgr_execute
2268(
2269  rpc_call_rep_p_t        call_r,
2270  unsigned32              *st ATTRIBUTE_UNUSED
2271)
2272{
2273    rpc_cn_call_rep_t       *call_rep;
2274    boolean                 call_executed;
2275
2276    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_did_mgr_execute);
2277    CODING_ERROR (st);
2278
2279    call_rep = (rpc_cn_call_rep_p_t) call_r;
2280
2281    /*
2282     * Acquire the CN global mutex to prevent other threads from
2283     * running.
2284     */
2285    RPC_CN_LOCK ();
2286
2287    call_executed = call_rep->call_executed;
2288
2289    /*
2290     * Release the CN global mutex to allow other threads to
2291     * run.
2292     */
2293    RPC_CN_UNLOCK ();
2294    return (call_executed);
2295}
2296
2297
2298/*
2299**++
2300**
2301**  ROUTINE NAME:       rpc__cn_call_cvt_from_nca_st
2302**
2303**  SCOPE:              INTERNAL
2304**
2305**  DESCRIPTION:
2306**
2307**  This routine will translate an on-wire status code (nca_s..)
2308**  into the corresponding runtime status code (rpc_s..).
2309**
2310**  INPUTS:
2311**
2312**      a_st            The NCA status code as rets it appears on the wire.
2313**                      This is the status as returned by, for example,
2314**                      a call_fault packet.
2315**
2316**  INPUTS/OUTPUTS:     none
2317**
2318**  OUTPUTS:            none
2319**
2320**  IMPLICIT INPUTS:    none
2321**
2322**  IMPLICIT OUTPUTS:   none
2323**
2324**  FUNCTION VALUE:
2325**
2326**      unsigned32      The runtime status code corresponding to
2327**                      the nca status code.
2328**
2329**  SIDE EFFECTS:       none
2330**
2331**--
2332**/
2333
2334INTERNAL unsigned32 rpc__cn_call_cvt_from_nca_st
2335(
2336  unsigned32 a_st
2337)
2338{
2339    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_cvt_from_nca_st);
2340    switch ((int)a_st)
2341    {
2342        case nca_s_op_rng_error:                return (rpc_s_op_rng_error);
2343        case nca_s_unk_if:                      return (rpc_s_unknown_if);
2344        case nca_s_proto_error:                 return (rpc_s_protocol_error);
2345        case nca_s_server_too_busy:             return (rpc_s_server_too_busy);
2346        case nca_s_invalid_pres_context_id:     return (rpc_s_context_id_not_found);
2347        case nca_s_unsupported_type:            return (rpc_s_unsupported_type);
2348        case nca_s_manager_not_entered:         return (rpc_s_manager_not_entered);
2349        case nca_s_out_args_too_big:            return (rpc_s_credentials_too_large);
2350        case nca_s_unsupported_authn_level:     return (rpc_s_unsupported_authn_level);
2351        case nca_s_invalid_checksum:            return (rpc_s_invalid_checksum);
2352        case nca_s_invalid_crc:                 return (rpc_s_invalid_crc);
2353        default:                                return (rpc_s_unknown_reject);
2354    }
2355}
2356
2357
2358/*
2359**++
2360**
2361**  ROUTINE NAME:       rpc__cn_call_cvt_to_nca_st
2362**
2363**  SCOPE:              INTERNAL
2364**
2365**  DESCRIPTION:
2366**
2367**  This routine will translate a local status to to an architected status code (nca_s..).
2368**
2369**  INPUTS:
2370**
2371**      l_st            The local (rpc_s...) status code.
2372**
2373**  INPUTS/OUTPUTS:     none
2374**
2375**  OUTPUTS:            none
2376**
2377**  IMPLICIT INPUTS:    none
2378**
2379**  IMPLICIT OUTPUTS:   none
2380**
2381**  FUNCTION VALUE:
2382**
2383**      unsigned32      The architected (nca_s...) status code.
2384**
2385**  SIDE EFFECTS:       none
2386**
2387**--
2388**/
2389
2390INTERNAL unsigned32 rpc__cn_call_cvt_to_nca_st
2391(
2392  unsigned32 l_st
2393)
2394{
2395    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_cvt_to_nca_st);
2396    switch ((int)l_st)
2397    {
2398        case rpc_s_op_rng_error:                return (nca_s_op_rng_error);
2399        case rpc_s_unknown_if:                  return (nca_s_unk_if);
2400        case rpc_s_protocol_error:              return (nca_s_proto_error);
2401        case rpc_s_cthread_not_found:           return (nca_s_server_too_busy);
2402        case rpc_s_server_too_busy:             return (nca_s_server_too_busy);
2403        case rpc_s_unsupported_type:            return (nca_s_unsupported_type);
2404        case rpc_s_unknown_mgr_type:            return (nca_s_unsupported_type);
2405        case rpc_s_manager_not_entered:         return (nca_s_manager_not_entered);
2406        case rpc_s_context_id_not_found:        return (nca_s_invalid_pres_context_id);
2407        case rpc_s_call_orphaned:               return (nca_s_unspec_reject);
2408        case rpc_s_unknown_reject:              return (nca_s_unspec_reject);
2409        case rpc_s_credentials_too_large:       return (nca_s_out_args_too_big);
2410        case rpc_s_unsupported_authn_level:     return (nca_s_unsupported_authn_level);
2411        case rpc_s_invalid_checksum:            return (nca_s_invalid_checksum);
2412        case rpc_s_invalid_crc:                 return (nca_s_invalid_crc);
2413        default:
2414            RPC_DBG_GPRINTF(("(rpc__cn_call_cvt_to_nca_st) unknown status; st=%08x\n", l_st));
2415            return (nca_s_unspec_reject);
2416    }
2417}
2418
2419/*
2420**++
2421**
2422**  ROUTINE NAME:       rpc__cn_call_no_conn_ind
2423**
2424**  SCOPE:              PRIVATE - declared in cncall.h
2425**
2426**  DESCRIPTION:
2427**
2428**  This routine will be called from a client receiver thread when
2429**  it detects the connection a call is in progress on has been lost.
2430**
2431**  INPUTS:
2432**
2433**      call_rep        The call rep data structure containing the
2434**                      state of the call in progress.
2435**
2436**  INPUTS/OUTPUTS:     none
2437**
2438**  OUTPUTS:            none
2439**
2440**  IMPLICIT INPUTS:    none
2441**
2442**  IMPLICIT OUTPUTS:   none
2443**
2444**  FUNCTION VALUE:     none
2445**
2446**  SIDE EFFECTS:       none
2447**
2448**--
2449**/
2450
2451PRIVATE void rpc__cn_call_no_conn_ind
2452(
2453  rpc_cn_call_rep_p_t call_rep ATTRIBUTE_UNUSED
2454)
2455{
2456    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_no_conn_ind);
2457
2458    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
2459                    ("CN: call_rep->%p call no connection indication\n",
2460                     call_rep));
2461
2462    /*
2463     * For now this routine does nothing.
2464     */
2465}
2466
2467/*
2468**++
2469**
2470**  ROUTINE NAME:       rpc__cn_call_ccb_create
2471**
2472**  SCOPE:              PRIVATE - declared in cncall.h
2473**
2474**  DESCRIPTION:
2475**
2476**  This routine will initialize an call control block
2477**  which is allocated from heap by rpc__list_element_alloc. It
2478**  will allocate a fragbuf for the protocol header and initialize
2479**  some fields of the header.
2480**
2481**  INPUTS:
2482**
2483**      ccb             The call control block to be initialized.
2484**
2485**  INPUTS/OUTPUTS:     none
2486**
2487**  OUTPUTS:            none
2488**
2489**  IMPLICIT INPUTS:    none
2490**
2491**  IMPLICIT OUTPUTS:   none
2492**
2493**  FUNCTION VALUE:     none
2494**
2495**  SIDE EFFECTS:       none
2496**
2497**--
2498**/
2499
2500PRIVATE void rpc__cn_call_ccb_create
2501(
2502  rpc_cn_call_rep_p_t     ccb
2503)
2504{
2505    rpc_cn_fragbuf_p_t      fragbuf_p;
2506    rpc_cn_packet_p_t       header_p;
2507    rpc_iovector_elt_p_t    iov_p;
2508
2509    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_ccb_create);
2510
2511    RPC_LIST_INIT (ccb->common.link);
2512    ccb->common.protocol_id = RPC_C_PROTOCOL_ID_NCACN;
2513    fragbuf_p = rpc__cn_fragbuf_alloc (false);
2514    fragbuf_p->fragbuf_dealloc = NULL;
2515    ccb->prot_header = fragbuf_p;
2516    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (ccb);
2517
2518    /*
2519     * Copy the common header fields.
2520     */
2521    memcpy (header_p, &rpc_g_cn_common_hdr, sizeof (rpc_g_cn_common_hdr));
2522
2523    iov_p = &(RPC_CN_CREP_IOV (ccb)[0]);
2524    iov_p->buff_dealloc = NULL;
2525    iov_p->buff_addr = (byte_p_t) fragbuf_p;
2526    iov_p->buff_len = fragbuf_p->max_data_size;
2527    iov_p->data_addr = (byte_p_t) fragbuf_p->data_p;
2528
2529    /*
2530     * Init the common call rep mutex.
2531     */
2532    RPC_CALL_LOCK_INIT ((rpc_call_rep_p_t) ccb);
2533}
2534
2535
2536/***********************************************************************/
2537/*
2538**++
2539**
2540**  ROUTINE NAME:       rpc__cn_call_ccb_free
2541**
2542**  SCOPE:              PRIVATE - declared in cncall.h
2543**
2544**  DESCRIPTION:
2545**
2546**  This routine will free the fragment buffer contained in an call
2547**  control block before the rpc__list_element_free routine returns
2548**  it to heap storage.
2549**
2550**  INPUTS:
2551**
2552**      ccb             The call control block to be initialized.
2553**
2554**  INPUTS/OUTPUTS:     none
2555**
2556**  OUTPUTS:            none
2557**
2558**  IMPLICIT INPUTS:    none
2559**
2560**  IMPLICIT OUTPUTS:   none
2561**
2562**  FUNCTION VALUE:     none
2563**
2564**  SIDE EFFECTS:       none
2565**
2566**--
2567**/
2568
2569PRIVATE void rpc__cn_call_ccb_free
2570(
2571  rpc_cn_call_rep_p_t     ccb
2572)
2573{
2574    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_ccb_free);
2575
2576    /*
2577     * Free the small fragbuf used for the protocol header.
2578     */
2579    if (ccb->prot_header != NULL)
2580    {
2581        rpc__cn_smfragbuf_free (ccb->prot_header);
2582    }
2583
2584    /*
2585     * Delete the common call rep mutex.
2586     */
2587    RPC_CALL_LOCK_DELETE ((rpc_call_rep_p_t) ccb);
2588}
2589
2590
2591/***********************************************************************/
2592/*
2593**++
2594**
2595**  ROUTINE NAME:       rpc__cn_call_local_cancel
2596**
2597**  SCOPE:              PRIVATE - declared in cncall.h
2598**
2599**  DESCRIPTION:
2600**
2601**  A local cancel has been detected (i.e., a cancellable operation
2602**  caused an unwound).  This routine can be invoked from either
2603**  the client or the server.
2604**  If it occurs on the client, a cancel is forwarded to the server.
2605**  If it occurs on the server, rpc_s_call_cancelled is returned.
2606**
2607**  Note that this routine assumes that the global CN lock is held.
2608**
2609**  INPUTS:
2610**
2611**      call_rep        The call rep.
2612**
2613**  INPUTS/OUTPUTS:     none
2614**
2615**  OUTPUTS:            none
2616**
2617**  IMPLICIT INPUTS:    none
2618**
2619**  IMPLICIT OUTPUTS:   none
2620**
2621**  FUNCTION VALUE:     none
2622**
2623**  SIDE EFFECTS:       none
2624**
2625**--
2626**/
2627
2628PRIVATE void rpc__cn_call_local_cancel
2629(
2630  rpc_cn_call_rep_p_t     call_rep,
2631  volatile boolean32      *retry_op,
2632  unsigned32              *status
2633)
2634{
2635    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_local_cancel);
2636    CODING_ERROR (status);
2637
2638    RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2639                   ("(rpc__cn_call_local_cancel) call_rep->%p local cancel caught\n",
2640                    call_rep));
2641    /*
2642     * If the call rep is NULL, this is the server side of a
2643     * call and it has been orphaned. We were in a cancellable pipe
2644     * routine. Return the rpc_s_call_cancelled status code.
2645     */
2646    if (call_rep == NULL)
2647    {
2648        *retry_op = false;
2649        *status = rpc_s_call_cancelled;
2650        return;
2651    }
2652
2653    if (RPC_CALL_IS_CLIENT (((rpc_call_rep_t *) call_rep)))
2654    {
2655        /*
2656         * Record the cancel that was just detected.
2657         */
2658        call_rep->u.client.cancel.local_count++;
2659        rpc__cn_call_start_cancel_timer (call_rep, status);
2660        if (*status == rpc_s_ok)
2661        {
2662            /*
2663             * Send a cancel event through the state machine for all
2664             * cancels detected so far but not forwarded yet.
2665             */
2666            rpc__cn_call_forward_cancel (call_rep, status);
2667            *retry_op = true;
2668        }
2669        else
2670        {
2671            *retry_op = false;
2672        }
2673    }
2674    else
2675    {
2676        *retry_op = false;
2677        *status = rpc_s_call_cancelled;
2678    }
2679}
2680
2681
2682/***********************************************************************/
2683/*
2684**++
2685**
2686**  ROUTINE NAME:       rpc__cn_call_check_for_cancel
2687**
2688**  SCOPE:              INTERNAL - declared locally
2689**
2690**  DESCRIPTION:
2691**
2692**  Check for a pending cancel. If one is caught increment the local
2693**  count field of the call rep to indicate it. Of course, if
2694**  general cancel delivery is disabled, then we aren't required
2695**  (and in fact don't want) to detect one.
2696**
2697**  INPUTS:
2698**
2699**      call_rep        The call rep.
2700**
2701**  INPUTS/OUTPUTS:     none
2702**
2703**  OUTPUTS:            none
2704**
2705**  IMPLICIT INPUTS:    none
2706**
2707**  IMPLICIT OUTPUTS:   none
2708**
2709**  FUNCTION VALUE:     none
2710**
2711**  SIDE EFFECTS:       none
2712**
2713**--
2714**/
2715
2716INTERNAL void rpc__cn_call_check_for_cancel
2717(
2718  rpc_cn_call_rep_p_t     call_rep
2719)
2720{
2721    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_check_for_cancel);
2722
2723    /*
2724     * If a cancel timeout has been established there's no need to
2725     * check. A cancel has been forwarded and no response has been
2726     * received yet.
2727     */
2728    if (call_rep->u.client.cancel.timeout_time == 0)
2729    {
2730        DCETHREAD_TRY
2731        {
2732            dcethread_checkinterrupt ();
2733        }
2734        DCETHREAD_CATCH (dcethread_interrupt_e)
2735        {
2736            RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2737                            ("(rpc__cn_call_check_for_cancel) call_rep->%p local cancel detected\n", call_rep));
2738            (call_rep)->u.client.cancel.local_count++;
2739        }
2740        DCETHREAD_ENDTRY
2741    }
2742}
2743
2744
2745/***********************************************************************/
2746/*
2747**++
2748**
2749**  ROUTINE NAME:       rpc__cn_call_forward_cancel
2750**
2751**  SCOPE:              INTERNAL - declared locally
2752**
2753**  DESCRIPTION:
2754**
2755**  Forward all cancels which have been detected to this point to
2756**  the server.
2757**
2758**  INPUTS:
2759**
2760**      call_rep        The call rep.
2761**
2762**  INPUTS/OUTPUTS:     none
2763**
2764**  OUTPUTS:            none
2765**
2766**  IMPLICIT INPUTS:    none
2767**
2768**  IMPLICIT OUTPUTS:   none
2769**
2770**  FUNCTION VALUE:     none
2771**
2772**  SIDE EFFECTS:       none
2773**
2774**--
2775**/
2776
2777INTERNAL void rpc__cn_call_forward_cancel
2778(
2779  rpc_cn_call_rep_p_t     call_rep,
2780  unsigned32              *status
2781)
2782{
2783    unsigned32          temp_status;
2784
2785    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_forward_cancel);
2786    CODING_ERROR (status);
2787
2788    /*
2789     * Foward all queued cancels if the first request fragment has been sent
2790     * to the server already.
2791     */
2792    if (call_rep->u.client.cancel.server_is_accepting)
2793    {
2794        for (; call_rep->u.client.cancel.local_count > 0;
2795             call_rep->u.client.cancel.local_count--)
2796        {
2797            RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2798                           ("(rpc__cn_call_forward_cancel) call_rep->%p forwarding cancel\n", call_rep));
2799            RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_LOCAL_ALERT,
2800                                    NULL,
2801                                    call_rep,
2802                                    temp_status);
2803        }
2804    }
2805    else
2806    {
2807        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2808                       ("(rpc__cn_call_forward_cancel) call_rep->%p haven't sent first frag yet\n", call_rep));
2809    }
2810    *status = call_rep->cn_call_status;
2811}
2812
2813
2814/*
2815**++
2816**
2817**  ROUTINE NAME:       rpc__cn_call_binding_serialize
2818**
2819**  SCOPE:              INTERNAL - declared locally
2820**
2821**  DESCRIPTION:
2822**
2823**  Serialize calls on this binding handle until the handle has a bound
2824**  server instance.  This is necessary to maintain the promise: "All
2825**  calls to using a specific binding handle will go to the same server
2826**  instance".
2827**
2828**  INPUTS:
2829**
2830**      binding_r       The binding rep access to which is being serialized
2831**      cancel_timeout  The thread's cancel timeout value
2832**
2833**  INPUTS/OUTPUTS:
2834**
2835**      cancel_cnt      The number of cancels detected while waiting
2836**                      for the binding rep to become free.
2837**
2838**  OUTPUTS:
2839**
2840**      st              The RPC runtime status code
2841**
2842**
2843**  IMPLICIT INPUTS:    none
2844**
2845**  IMPLICIT OUTPUTS:   none
2846**
2847**  FUNCTION VALUE:
2848**
2849**  SIDE EFFECTS:       none
2850**
2851**--
2852**/
2853
2854INTERNAL void rpc__cn_call_binding_serialize
2855(
2856  rpc_binding_rep_p_t     binding_r,
2857  rpc_clock_t             cancel_timeout,
2858  unsigned32              *cancel_cnt,
2859  unsigned32              *st
2860)
2861{
2862    volatile boolean    is_awaiting_timeout = false;
2863    volatile boolean    has_timed_out = false;
2864    volatile struct timespec     zero_delta, delta, abstime, curtime;
2865
2866    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_binding_serialize);
2867    RPC_LOCK_ASSERT(0);
2868    CODING_ERROR (st);
2869
2870    *st = rpc_s_ok;
2871
2872    zero_delta.tv_sec = 0;
2873    zero_delta.tv_nsec = 0;
2874    delta.tv_sec = 0;
2875    delta.tv_nsec = 0;
2876
2877    delta.tv_sec = cancel_timeout;
2878
2879    /*
2880     * Wait while the binding is being resolved by someone else
2881     * (this routine is called only by threads not doing the
2882     * resolving) and we haven't timed out.
2883     *
2884     * If the user attempts to cancel the call,
2885     * don't wait longer than the cancel timeout time.
2886     */
2887    while ((((rpc_cn_binding_rep_t *)binding_r)->being_resolved) &&
2888           (!has_timed_out))
2889    {
2890        DCETHREAD_TRY
2891        {
2892            if (!is_awaiting_timeout)
2893            {
2894                RPC_BINDING_COND_WAIT (0);
2895            }
2896            else
2897            {
2898                RPC_BINDING_COND_TIMED_WAIT ((struct timespec *) &abstime);
2899                dcethread_get_expiration ((struct timespec *) &zero_delta,
2900                                          (struct timespec *) &curtime);
2901                if (curtime.tv_sec >= abstime.tv_sec)
2902                {
2903                    has_timed_out = true;
2904                }
2905            }
2906        }
2907        DCETHREAD_CATCH (dcethread_interrupt_e)
2908        {
2909            /*
2910             * Track the cancels and setup a cancel timeout value
2911             * (if appropriate).
2912             */
2913            RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2914                           ("(rpc__cn_call_binding_serialize) binding_rep->%p cancel detected\n", binding_r));
2915            if (delta.tv_sec == 0)
2916            {
2917                has_timed_out = true;
2918            }
2919            else
2920            {
2921                if (delta.tv_sec == rpc_c_cancel_infinite_timeout)
2922                {
2923                    ;   /* we never timeout */
2924                }
2925                else
2926                {
2927                    /*
2928                     * Compute the max timeout time for the wait.
2929                     * Generate a cancel time stamp for use by the caller
2930                     * in subsequently setting up the call's cancel state.
2931                     */
2932                    if (is_awaiting_timeout == false)
2933                    {
2934                        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2935                                       ("(rpc__cn_call_binding_serialize) binding_rep->%p %lu sec cancel timeout setup\n",
2936                                        binding_r, (unsigned long)delta.tv_sec));
2937
2938                        dcethread_get_expiration ((struct timespec *) (&delta),
2939                                                  (struct timespec *) (&abstime));
2940                    }
2941                    is_awaiting_timeout = true;
2942                }
2943            }
2944            *cancel_cnt += 1;
2945
2946        /*
2947         * Any other type of exception is something serious; just let it
2948         * propagate and we die in our usual unclean fashion.
2949         */
2950        }
2951        DCETHREAD_ENDTRY
2952    }
2953
2954    if (has_timed_out)
2955    {
2956        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2957                       ("(rpc__cn_call_binding_serialize) binding_rep->%p cancel timeout\n", binding_r));
2958        *st = rpc_s_cancel_timeout;
2959    }
2960    else if (binding_r->addr_has_endpoint == false)
2961    {
2962        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2963                       ("(rpc__cn_call_binding_serialize) binding_rep->%p endpoint not found\n", binding_r));
2964        *st = rpc_s_endpoint_not_found;
2965    }
2966}
2967
2968
2969/*
2970**++
2971**
2972**  ROUTINE NAME:       rpc__cn_call_start_cancel_timer
2973**
2974**  SCOPE:              PRIVATE - delcared in cncall.h
2975**
2976**  DESCRIPTION:
2977**
2978**  Start a timer to time out cancels.
2979**
2980**  INPUTS:
2981**
2982**      call_r          The call rep representing the RPC being made.
2983**
2984**  INPUTS/OUTPUTS:     none
2985**
2986**  OUTPUTS:
2987**
2988**      st              The RPC runtime status code
2989**
2990**
2991**  IMPLICIT INPUTS:    none
2992**
2993**  IMPLICIT OUTPUTS:   none
2994**
2995**  FUNCTION VALUE:
2996**
2997**  SIDE EFFECTS:       none
2998**
2999**--
3000**/
3001
3002PRIVATE void rpc__cn_call_start_cancel_timer
3003(
3004  rpc_cn_call_rep_p_t     call_r,
3005  unsigned32              *st
3006)
3007{
3008    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_start_cancel_timer);
3009    CODING_ERROR (st);
3010
3011    RPC_CN_LOCK_ASSERT ();
3012
3013    /*
3014     * The timer may have already expired.
3015     */
3016    if ((*st = call_r->cn_call_status) == rpc_s_ok)
3017    {
3018        /*
3019         * Start a cancel timer if one is not already running and the
3020         * cancel timeout for this thread is not infinite.
3021         */
3022        if ((!call_r->u.client.cancel.timer_running) &&
3023            (call_r->u.client.cancel.timeout_time != (typeof(call_r->u.client.cancel.timeout_time))(rpc_c_cancel_infinite_timeout)))
3024        {
3025            RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
3026                           ("(rpc__cn_call_start_cancel_timer) call_rep->%p starting cancel timer - %ld seconds\n",
3027                            call_r, call_r->u.client.cancel.timeout_time));
3028            call_r->u.client.cancel.timer_running = true;
3029            call_r->u.client.cancel.thread_h = dcethread_self ();
3030            rpc__timer_set (&call_r->u.client.cancel.timer,
3031                            (rpc_timer_proc_p_t) rpc__cn_call_cancel_timer,
3032                            (dce_pointer_t) call_r,
3033                            (rpc_clock_t) RPC_CLOCK_SEC (call_r->u.client.cancel.timeout_time));
3034        }
3035    }
3036    else
3037    {
3038        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
3039                       ("(rpc__cn_call_start_cancel_timer) call_rep->%p timer expired ... returning rpc_s_cancel_timeout\n",
3040                        call_r));
3041    }
3042}
3043
3044
3045/*
3046**++
3047**
3048**  ROUTINE NAME:       rpc__cn_call_stop_cancel_timer
3049**
3050**  SCOPE:              PRIVATE - declared in cncall.h
3051**
3052**  DESCRIPTION:
3053**
3054**  Clear the timer to time out cancels.
3055**
3056**  INPUTS:
3057**
3058**      call_r          The call rep representing the RPC being made.
3059**
3060**  INPUTS/OUTPUTS:     none
3061**
3062**  OUTPUTS:
3063**
3064**      st              The RPC runtime status code
3065**
3066**
3067**  IMPLICIT INPUTS:    none
3068**
3069**  IMPLICIT OUTPUTS:   none
3070**
3071**  FUNCTION VALUE:
3072**
3073**  SIDE EFFECTS:       none
3074**
3075**--
3076**/
3077
3078PRIVATE void rpc__cn_call_stop_cancel_timer
3079(
3080  rpc_cn_call_rep_p_t     call_r
3081)
3082{
3083    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_stop_cancel_timer);
3084
3085    if (call_r->u.client.cancel.timer_running)
3086    {
3087        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
3088                       ("(rpc__cn_call_stop_cancel_timer) call_rep->%p cancel timer stopped\n", call_r));
3089        rpc__timer_clear (&call_r->u.client.cancel.timer);
3090    }
3091}
3092
3093
3094/*
3095**++
3096**
3097**  ROUTINE NAME:       rpc__cn_call_cancel_timer
3098**
3099**  SCOPE:              INTERNAL - declared locally
3100**
3101**  DESCRIPTION:
3102**
3103**  Timer routine to time out cancels
3104**
3105**  INPUTS:
3106**
3107**      call_r          The call rep representing the RPC being made.
3108**
3109**  INPUTS/OUTPUTS:     none
3110**
3111**  OUTPUTS:
3112**
3113**      st              The RPC runtime status code
3114**
3115**
3116**  IMPLICIT INPUTS:    none
3117**
3118**  IMPLICIT OUTPUTS:   none
3119**
3120**  FUNCTION VALUE:
3121**
3122**      true            the routine should be rescheduled
3123**      false           the routine should not be rescheduled
3124**
3125**  SIDE EFFECTS:       none
3126**
3127**--
3128**/
3129
3130INTERNAL boolean rpc__cn_call_cancel_timer
3131(
3132  rpc_cn_call_rep_p_t     call_r
3133)
3134{
3135    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_cancel_timer);
3136
3137    RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
3138                   ("(rpc__cn_call_cancel_timer) call_rep->%p cancel timer expired\n", call_r));
3139    RPC_CN_LOCK ();
3140    call_r->cn_call_status = rpc_s_cancel_timeout;
3141    dcethread_interrupt_throw (call_r->u.client.cancel.thread_h);
3142    call_r->u.client.cancel.timer_running = false;
3143
3144    /*
3145     * Set the server had pending flag so that the cancel which
3146     * started this timer will be reposted in call_end.
3147     */
3148    call_r->u.client.cancel.server_had_pending = true;
3149    rpc__timer_clear (&call_r->u.client.cancel.timer);
3150    RPC_CN_UNLOCK ();
3151    return (false);
3152}
3153