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**      cnsclsm.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  Server call State Machine for the Connection-based RPC runtime.
90**
91**
92*/
93
94
95#include <commonp.h>    /* Common declarations for all RPC runtime */
96#include <com.h>        /* Common communications services */
97#include <comprot.h>    /* Common protocol services */
98#include <ndrglob.h>    /* NDR representation global declarations */
99#include <ndrp.h>       /* System dependent NDR decls */
100#include <cnp.h>        /* NCA Connection private declarations */
101#include <cnfbuf.h>     /* NCA Connection fragment buffer declarations */
102#include <cnpkt.h>      /* NCA Connection protocol header */
103#include <cnsm.h>       /* NCA Connection state machine declarations */
104#include <cnxfer.h>     /* NCA Connection buffered data transfer */
105#include <cnassoc.h>    /* NCA Connection association services */
106#include <comcthd.h>    /* Externals for Call Thread sub-component  */
107#include <cncall.h>     /* NCA connection call service */
108#include <cnclsm.h>
109
110#include <dce/rpcexc.h>
111
112/******************************************************************************/
113/*
114 * Global Definitions
115 */
116#ifdef DEBUG
117GLOBAL const char     *rpc_g_cn_call_server_events [] =
118{
119    "RESPONSE         ",
120    "INDICATION       ",
121    "FAULT_DNE        ",
122    "FAULT            ",
123    "LOCAL_ALERT      ",
124    "END              ",
125    "REMOTE_ALERT_IND ",
126    "ORPHANED         "
127};
128
129GLOBAL const char     *rpc_g_cn_call_server_states [] =
130{
131    "INIT             ",
132    "REQUEST          ",
133    "RESPONSE         ",
134    "CALL_COMPLETED   "
135};
136#endif
137
138
139/***********************************************************************/
140/*
141 * S E R V E R   C A L L   P R E D I C A T E   T A B L E
142 */
143
144/*
145 * The predicates.
146 * As a performance enhancement, we have changed some predicate routines
147 * and made them macros and we have absorbed the predicates into the
148 * actions.  Thus, there is no longer a need for the predicate table.
149 * We invoke the predicate functions as MACROS or as function calls
150 * from within the action routines.
151 */
152/*
153 * The predicate routine prototypes.
154 */
155INTERNAL unsigned8 disconnected_maybe_pred_rtn
156    (
157	dce_pointer_t spc_struct,
158        dce_pointer_t event_param
159    ) ATTRIBUTE_UNUSED;
160INTERNAL unsigned8 request_fault_pred_rtn
161    (
162        dce_pointer_t spc_struct,
163        dce_pointer_t event_param
164    ) ATTRIBUTE_UNUSED;
165INTERNAL unsigned8 response_fault_pred_rtn
166    (
167        dce_pointer_t spc_struct,
168        dce_pointer_t event_param
169    ) ATTRIBUTE_UNUSED;
170INTERNAL unsigned8 last_recv_frag_pred_rtn
171    (
172        dce_pointer_t spc_struct,
173        dce_pointer_t event_param
174    ) ATTRIBUTE_UNUSED;
175INTERNAL unsigned8 first_frag_pred_rtn
176    (
177        dce_pointer_t spc_struct,
178        dce_pointer_t event_param
179    ) ATTRIBUTE_UNUSED;
180INTERNAL unsigned8 disc_last_send_pred_rtn
181    (
182        dce_pointer_t spc_struct,
183        dce_pointer_t event_param
184    ) ATTRIBUTE_UNUSED;
185
186
187/***********************************************************************/
188/*
189 * S E R V E R   C A L L   A C T I O N   T A B L E
190 */
191
192/***********************************************************************/
193
194/*
195 * The actions.
196 */
197#define HANDLE_FIRST_FRAG         0
198#define HANDLE_FRAG               1
199#define SEND_CALL_RESP            2
200#define SEND_CALL_FAULT           3
201#define PROCESS_ALERT_MSG         4
202#define ABORT_RESP                5
203#define ABORT_RESP_SEND_FAULT     6
204#define STOP_ORPHAN               7
205#define DISCARD_FRAGMENT          8
206#define CALL_END                  9
207#define PROTOCOL_ERROR           10
208
209/*
210 * We do not currently execute actions when we abort a receive.
211 */
212#define ABORT_RECEIVE             RPC_C_SM_NO_ACTION
213#define ABORT_RECEIVE_SEND_FAULT  SEND_CALL_FAULT
214
215/*
216 * The action routine prototypes.
217 */
218INTERNAL unsigned32     handle_first_frag_action_rtn (
219        dce_pointer_t  /*spc_struct*/,
220        dce_pointer_t /*event_param*/,
221	dce_pointer_t /*sm*/
222    );
223INTERNAL unsigned32     handle_frag_action_rtn (
224        dce_pointer_t  /*spc_struct*/,
225        dce_pointer_t /*event_param*/,
226	dce_pointer_t /*sm*/
227    );
228INTERNAL unsigned32     send_call_resp_action_rtn (
229        dce_pointer_t  /*spc_struct*/,
230        dce_pointer_t /*event_param*/,
231	dce_pointer_t /*sm*/
232    );
233INTERNAL unsigned32     send_call_fault_action_rtn (
234        dce_pointer_t  /*spc_struct*/,
235        dce_pointer_t /*event_param*/,
236	dce_pointer_t /*sm*/
237    );
238INTERNAL unsigned32     process_alert_msg_action_rtn (
239        dce_pointer_t  /*spc_struct*/,
240        dce_pointer_t /*event_param*/,
241	dce_pointer_t /*sm*/
242    );
243
244INTERNAL unsigned32     abort_resp_action_rtn (
245        dce_pointer_t  /*spc_struct*/,
246        dce_pointer_t /*event_param*/,
247	dce_pointer_t /*sm*/
248    );
249
250INTERNAL unsigned32     abort_resp_send_fault_action_rtn (
251        dce_pointer_t  /*spc_struct*/,
252        dce_pointer_t /*event_param*/,
253	dce_pointer_t /*sm*/
254    );
255INTERNAL unsigned32     stop_orphan_action_rtn (
256        dce_pointer_t  /*spc_struct*/,
257        dce_pointer_t /*event_param*/,
258	dce_pointer_t /*sm*/
259    );
260INTERNAL unsigned32     discard_fragment_action_rtn (
261        dce_pointer_t  /*spc_struct*/,
262        dce_pointer_t /*event_param*/,
263	dce_pointer_t /*sm*/
264    );
265INTERNAL unsigned32     call_end_action_rtn (
266        dce_pointer_t  /*spc_struct*/,
267        dce_pointer_t /*event_param*/,
268	dce_pointer_t /*sm*/
269    );
270
271/*
272 * The action table itself.
273 */
274GLOBAL rpc_cn_sm_action_fn_t  rpc_g_cn_server_call_action_tbl [] =
275{
276    handle_first_frag_action_rtn,
277    handle_frag_action_rtn,
278    send_call_resp_action_rtn,
279    send_call_fault_action_rtn,
280    process_alert_msg_action_rtn,
281    abort_resp_action_rtn,
282    abort_resp_send_fault_action_rtn,
283    stop_orphan_action_rtn,
284    discard_fragment_action_rtn,
285    call_end_action_rtn,
286    rpc__cn_call_sm_protocol_error
287};
288
289/***********************************************************************/
290/*
291 * S E R V E R   C A L L   S T A T E   T A B L E
292 */
293
294/*
295 * A state table entry exists for every state in the state machine.
296 * In the case of the server call state machine, for example, a
297 * state table entry exists for init, call_request, call_response,
298 * etc.
299 *
300 * Each state table entry describes the actions and state transitions
301 * which can occur in response to each event while in that state.
302 * So for example, the state table entry for the init state must
303 * describe the outcomes for every event.
304 *
305 * The outcome for an event is a new state and an action routine to
306 * invoke.
307 *
308 * Sometimes, how a given event is handled depends upon certain
309 * conditions.  For example, a fault_dne event occurring in the
310 * call_response state is handled differently depending upon whether
311 * the connection has been disconnected and the semantics of the
312 * call.  This is translated into a number of different outcomes
313 * for each event.
314 *
315 * As an optimization, the structure rpc_cn_sm_state_tbl_entry_t
316 * was modified to contain one unsigned8 value.  That value can
317 * be either a state to transition to, or the action index.
318 * We distinguish between states and action indexes by value;
319 * state values are >=100 and action indexes are in the range
320 * of 1 - 14. If the state and event combination in the state table
321 * requires an action, then the rpc_cn_sm_state_tbl_entry_t structure
322 * contains an index into the action tbl for that set of
323 * circumstances.  The action routine itself will contain a
324 * predicate function, usually inline, and the action routine will
325 * update the control block's cur_state which in effect, is the
326 * next state.   The predicate function within the action routine
327 * will guide the logic through the action so that the appropriate
328 * action is taken depending on the outcome of the predicate
329 * function.  If the state and event combination requires no action but does
330 * require a state update, then we look to rpc_cn_sm_state_tbl_entry_t
331 * to contain that state update value.
332 *
333 */
334
335INTERNAL rpc_cn_sm_state_tbl_entry_t init_state =
336
337    {
338        ILLEGAL_TRANSITION,                 /* event 0 - rpc_resp */
339		  {HANDLE_FIRST_FRAG},		    /* event 1 - rpc_ind */
340        ILLEGAL_TRANSITION,                 /* event 2 - fault_dne */
341        ILLEGAL_TRANSITION,                 /* event 3 - fault */
342        ILLEGAL_TRANSITION,                 /* event 4 - local_alert */
343		  {RPC_C_SERVER_CALL_CALL_COMPLETED},   /* event 5 - call_end state */
344        ILLEGAL_TRANSITION,                 /* event 6 - remote_alert_ind */
345        ILLEGAL_TRANSITION                  /* event 7 - orphaned */
346    };
347
348INTERNAL rpc_cn_sm_state_tbl_entry_t call_request_state =
349    {
350        ILLEGAL_TRANSITION,                 /* event 0 - rpc_resp */
351		  {HANDLE_FRAG},	 		    /* event 1 - rpc_ind */
352		  {ABORT_RECEIVE_SEND_FAULT}, 	    /* event 2 - fault_dne */
353		  {ABORT_RECEIVE_SEND_FAULT},           /* event 3 - fault */
354        ILLEGAL_TRANSITION,                 /* event 4 - local_alert */
355		  {CALL_END},                           /* event 5 - call_end */
356		  {PROCESS_ALERT_MSG},  		    /* event 6 - remote_alert_ind */
357        /*
358         * This transition should not be going to the call
359         * completed state when the call is still executing.
360         * However, this implementation will return an error to any
361         * attempts to send a reponse on a call which is in the
362         * call_completed state before entering the state machine.
363         */
364		  {STOP_ORPHAN}  	                    /* event 7 - orphaned */
365    };
366
367INTERNAL rpc_cn_sm_state_tbl_entry_t call_response_state =
368    {
369		 {SEND_CALL_RESP},                    /* event 0 - rpc_resp */
370        ILLEGAL_TRANSITION,                /* event 1 - rpc_ind */
371		  {ABORT_RESP_SEND_FAULT},             /* event 2 - fault_dne */
372		  {ABORT_RESP_SEND_FAULT},             /* event 3 - fault */
373        ILLEGAL_TRANSITION,                /* event 4 - local_alert */
374		  {CALL_END}, 		           /* event 5 - call_end */
375		  {PROCESS_ALERT_MSG},  	           /* event 6 - remote_alert_ind */
376		  {STOP_ORPHAN} 		           /* event 7 - orphaned */
377    };
378
379
380INTERNAL rpc_cn_sm_state_tbl_entry_t call_completed_state =
381    {
382        ILLEGAL_TRANSITION,                 /* event 0 */
383        ILLEGAL_TRANSITION,                 /* event 1 */
384        ILLEGAL_TRANSITION,                 /* event 2 */
385        ILLEGAL_TRANSITION,                 /* event 3 */
386        ILLEGAL_TRANSITION,                 /* event 4 */
387		  {RPC_C_SERVER_CALL_CALL_COMPLETED},   /* event 5 - call_end */
388        ILLEGAL_TRANSITION,                 /* event 6 */
389		  {RPC_C_SERVER_CALL_CALL_COMPLETED}    /* event 7 - orphaned */
390    };
391
392GLOBAL rpc_cn_sm_state_entry_p_t rpc_g_cn_server_call_sm [] =
393{
394    init_state,                     /* state 0 - init */
395    call_request_state,             /* state 1 - call_request */
396    call_response_state,            /* state 2 - call_response */
397    call_completed_state            /* state 3 - call_completed */
398};
399
400
401/***********************************************************************/
402/*
403 *
404 * S E R V E R   C A L L   P R E D I C A T E   R O U T I N E S
405 *
406 */
407
408/***********************************************************************/
409
410/*
411**++
412**
413**  ROUTINE NAME:       disconnected_maybe_pred_rtn
414**
415**  SCOPE:              INTERNAL
416**
417**  DESCRIPTION:
418**
419**  Predicate routine to evaluate whether the communications link
420**  has been disconnected or if the call has maybe semantics.
421**  This routine is invoked from the Call Request and Call Response
422**  states when an RPCInd or RPCResp event occurred.
423**
424**  INPUTS:
425**
426**      spc_struct      The call rep.  Note that this is passed in as
427**                      the special structure which is passed to the
428**                      state machine event evaluation routine.
429**
430**      event_param     Fragment buffer containing the received data.
431**                      Note that it is passed in as the special event
432**                      related parameter which is passed to the state
433**                      machine event evaluation routine.
434**
435**  INPUTS/OUTPUTS:     none
436**
437**  OUTPUTS:            none
438**
439**  IMPLICIT INPUTS:    the association status has been set to non-OK if the
440**                      connection has been disconnected.
441**
442**  IMPLICIT OUTPUTS:   none
443**
444**  FUNCTION VALUE:     0 if Disconnected and MaybeSemantics are both false
445**                      1 if either Disconnected or MaybeSemantics is true
446**
447**  SIDE EFFECTS:       none
448**
449**--
450**/
451
452INTERNAL unsigned8 disconnected_maybe_pred_rtn
453(
454  dce_pointer_t       spc_struct,
455  dce_pointer_t       event_param
456)
457{
458    RPC_CN_DBG_RTN_PRINTF(SERVER disconnected_maybe_pred_rtn);
459
460    if ( (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status !=
461          rpc_s_ok) ||
462         (RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) &
463          RPC_C_CN_FLAGS_MAYBE) )
464    {
465        return (1);
466    }
467    else
468    {
469        return (0);
470    }
471}
472
473
474/*
475**++
476**
477**  ROUTINE NAME:       disc_last_send_pred_rtn
478**
479**  SCOPE:              INTERNAL
480**
481**  DESCRIPTION:
482**
483**  Predicate routine which evaluates whether the communications link
484**  has been disconnected and whether this the the last fragment
485**  of the response.  It is invoked from the Call Response state when
486**  an RPCResp event occurred.
487**
488**  INPUTS:
489**
490**      spc_struct      The call rep.  Note that this is passed in as
491**                      the special structure which is passed to the
492**                      state machine event evaluation routine.
493**
494**      event_param     Iovector element containing the stub data for
495**                      the response.
496**                      Note that it is passed in as the special event
497**                      related parameter which is passed to the state
498**                      machine event evaluation routine.
499**
500**  INPUTS/OUTPUTS:     none
501**
502**  OUTPUTS:            none
503**
504**  IMPLICIT INPUTS:    the association status has been set to non-OK if the
505**                      connection has been disconnected.
506**
507**  IMPLICIT OUTPUTS:   none
508**
509**  FUNCTION VALUE:     0 if Disconnected is true
510**                      1 if Disconnected is false and this is the
511**                        last fragment of the response.
512**                        (NOTE that this value cannot in fact be
513**                         returned since we can only detect
514**                         the last fragment when the CALL_END
515**                         is issued.)
516**                      2 if Disconnected is false and this is not
517**                        the last fragment of the response.
518**
519**  SIDE EFFECTS:       none
520**
521**--
522**/
523
524INTERNAL unsigned8 disc_last_send_pred_rtn
525(
526  dce_pointer_t       spc_struct,
527  dce_pointer_t       event_param ATTRIBUTE_UNUSED
528)
529{
530    RPC_CN_DBG_RTN_PRINTF(SERVER disc_last_send_pred_rtn);
531
532    if  (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status !=
533          rpc_s_ok)
534    {
535        return (0);
536    }
537    else
538    {
539        return (2);
540    }
541
542    /*
543     * Note, our current implementation can never detect the
544     * last fragment of the response until the CALL_END is
545     * issued.  Consequently, 1 cannot be returned.
546     */
547}
548
549
550/*
551**++
552**
553**  MACRO NAME:		DISC_LAST_SEND_PRED
554**
555**  SCOPE:              INTERNAL
556**
557**  DESCRIPTION:
558**
559**  This is a macro version of the disc_last_send_pred_rtn() predicate.
560**  We added the macro version to avoid overhead when calling the
561**  predicate function from within the action routines.
562**  Predicate macro which evaluates whether the communications link
563**  has been disconnected and whether this the the last fragment
564**  of the response.  It is invoked from the Call Response state when
565**  an RPCResp event occurred.
566**
567**  INPUTS:
568**
569**      spc_struct      The call rep.  Note that this is passed in as
570**                      the special structure which is passed to the
571**                      state machine event evaluation routine.
572**
573**      event_param     Iovector element containing the stub data for
574**                      the response.
575**                      Note that it is passed in as the special event
576**                      related parameter which is passed to the state
577**                      machine event evaluation routine.
578**
579**	status		Instead of returning a value from the macro,
580**			write the value calculated in the macro to
581**			status.  Status' scope includes the routine
582**			calling the macro.  Check status in the calling
583**			routine to determine next state and in cases,
584**			flow through the action routine.
585**
586**  INPUTS/OUTPUTS:     none
587**
588**  OUTPUTS:
589**
590**	status		See explanation above.
591**
592**  IMPLICIT INPUTS:    none
593**
594**  IMPLICIT OUTPUTS:   none
595**
596**  FUNCTION VALUE:     0 if Disconnected is true
597**                      1 if Disconnected is false and this is the
598**                        last fragment of the response.
599**                        (NOTE that this value cannot in fact be
600**                         returned since we can only detect
601**                         the last fragment when the call_end
602**                         is issued.)
603**                      2 if Disconnected is false and this is not
604**                        the last fragment of the response.
605**
606**  SIDE EFFECTS:      none
607**
608**--
609**/
610#define  DISC_LAST_SEND_PRED(spc_struct, event_param, status) 	\
611{									\
612    RPC_CN_DBG_RTN_PRINTF(SERVER disc_last_send_pred_macro); 	\
613    if (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status !=  rpc_s_ok)	\
614    { 									\
615	status = 0; 							\
616    } 									\
617    else 								\
618    { 									\
619	status = 2; 							\
620    } 									\
621}
622
623
624/*
625**++
626**
627**  ROUTINE NAME:       request_fault_pred_rtn
628**
629**  SCOPE:              INTERNAL
630**
631**  DESCRIPTION:
632**
633**  Routine evaluating the combination of the predicates: MaybeSemantics,
634**  Disconnected, and LastSendFrag for the fault.  It is invoked from
635**  the Call Request state when either a fault or fault_dne event occurs.
636**
637**  INPUTS:
638**
639**      spc_struct      The call rep.  Note that this is passed in as
640**                      the special structure which is passed to the
641**                      state machine event evaluation routine.
642**
643**      event_param     Iovector element containing the fault data.
644**                      Note that it is passed in as the special event
645**                      related parameter which is passed to the state
646**                      machine event evaluation routine.
647**                      This argument is ignored in the current
648**                      implementation.
649**
650**  INPUTS/OUTPUTS:     none
651**
652**  OUTPUTS:            none
653**
654**  IMPLICIT INPUTS:    the association status has been set to non-OK if the
655**                      connection has been disconnected.
656**
657**  IMPLICIT OUTPUTS:   none
658**
659**  FUNCTION VALUE:     0 if MaybeSemantics or Disconnected is true
660**                      1 if LastSendFrag for the fault is true and
661**                        and both MaybeSemantics and Disconnected
662**                        are false
663**                      2 if LastSendFrag for the fault is false,
664**                        and both MaybeSemantics and Disconnected
665**                        are false.
666**                        Note that in our current implementation,
667**                        this outcome cannot occur.
668**
669**  SIDE EFFECTS:       none
670**
671**--
672**/
673
674INTERNAL unsigned8 request_fault_pred_rtn
675(
676  dce_pointer_t       spc_struct,
677  dce_pointer_t       event_param ATTRIBUTE_UNUSED
678)
679{
680    rpc_cn_call_rep_p_t call_rep;
681
682    RPC_CN_DBG_RTN_PRINTF(SERVER request_fault_pred_rtn);
683
684    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
685
686    if ( ( call_rep->assoc->assoc_status !=
687           rpc_s_ok ) ||
688         ( (RPC_CN_PKT_FLAGS ( (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep)))
689           & RPC_C_CN_FLAGS_MAYBE ) )
690    {
691        return (0);
692    }
693    else
694    {
695        /*
696         * Note: Although the architecture allows the fault data
697         * to be sent in several chunks, the current implementation
698         * assumes that it is passed to the runtime in a single
699         * operation.
700         */
701        return (1);
702    }
703}
704
705
706/*
707**++
708**
709**  MACRO NAME:		REQUEST_FAULT_PRED
710**
711**  SCOPE:              INTERNAL
712**
713**  DESCRIPTION:
714**
715**  This is a macro version of the request_fault_pred_rtn() predicate.
716**  We added the macro version to avoid overhead when calling the
717**  predicate function from within the action routines.
718**  Macro evaluating the combination of the predicates: MaybeSemantics,
719**  Disconnected, and LastSendFrag for the fault.  It is invoked from
720**  the Call Request state when either a fault or fault_dne event occurs.
721**
722**  INPUTS:
723**
724**      spc_struct      The call rep.  Note that this is passed in as
725**                      the special structure which is passed to the
726**                      state machine event evaluation routine.
727**
728**      event_param     Iovector element containing the fault data.
729**                      Note that it is passed in as the special event
730**                      related parameter which is passed to the state
731**                      machine event evaluation routine.
732**                      This argument is ignored in the current
733**                      implementation.
734**
735**	status		Instead of returning a value from the macro,
736**			write the value calculated in the macro to
737**			status.  Status' scope includes the routine
738**			calling the macro.  Check status in the calling
739**			routine to determine next state and in cases,
740**			flow through the action routine.
741**
742**  INPUTS/OUTPUTS:     none
743**
744**  OUTPUTS:
745**
746**	status		See explanation above.
747**
748**  IMPLICIT INPUTS:    none
749**
750**  IMPLICIT OUTPUTS:   none
751**
752**  FUNCTION VALUE:     0 if MaybeSemantics or Disconnected is true
753**                      1 if LastSendFrag for the fault is true and
754**                        and both MaybeSemantics and Disconnected
755**                        are false
756**                      2 if LastSendFrag for the fault is false,
757**                        and both MaybeSemantics and Disconnected
758**                        are false.
759**                        Note that in our current implementation,
760**                        this outcome cannot occur.
761**
762**  SIDE EFFECTS:       none
763**
764**--
765**/
766#define REQUEST_FAULT_PRED(call_rep, event_param, status)		\
767{									\
768    RPC_CN_DBG_RTN_PRINTF(SERVER request_fault_pred_macro);		\
769    if ( ( call_rep->assoc->assoc_status !=				\
770           rpc_s_ok ) ||						\
771         ( (RPC_CN_PKT_FLAGS ( (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep)))	\
772           & RPC_C_CN_FLAGS_MAYBE ) )					\
773    {									\
774        status = 0;							\
775    }									\
776    else								\
777    {									\
778        status = 1;							\
779    }									\
780}
781
782
783/*
784**++
785**
786**  ROUTINE NAME:       response_fault_pred_rtn
787**
788**  SCOPE:              INTERNAL
789**
790**  DESCRIPTION:
791**
792**  Evaluate the MaybeSemantics and Disconnected predicates from
793**  the Call Response state when either a fault or fault_dne
794**  event occurs.
795**
796**  INPUTS:
797**
798**      spc_struct      The call rep.  Note that this is passed in as
799**                      the special structure which is passed to the
800**                      state machine event evaluation routine.
801**
802**      event_param     The special event related parameter which is
803**                      passed to the state machine event evaluation
804**                      routine.
805**                      This input argument is ignored.
806**
807**  INPUTS/OUTPUTS:     none
808**
809**  OUTPUTS:            none
810**
811**  IMPLICIT INPUTS:    the association status has been set to non-OK if the
812**                      connection has been disconnected.
813**
814**  IMPLICIT OUTPUTS:   none
815**
816**  FUNCTION VALUE:     0 if MaybeSemantics true,
817**                      1 if Disconnected is true,
818**                      2 otherwise.
819**
820**       NOTE that the architecture allows 4 possible return values
821**            so that fault data can be transmitted in several
822**            operations.  The current implementation assumes that
823**            any fault data is transmitted in a single operation.
824**
825**  SIDE EFFECTS:       none
826**
827**--
828**/
829
830INTERNAL unsigned8 response_fault_pred_rtn
831(
832  dce_pointer_t       spc_struct,
833  dce_pointer_t       event_param ATTRIBUTE_UNUSED
834)
835{
836    rpc_cn_packet_p_t   header_p;
837
838    RPC_CN_DBG_RTN_PRINTF(SERVER response_fault_pred_rtn);
839
840    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (
841        (rpc_cn_call_rep_p_t) spc_struct);
842
843    if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE)
844    {
845        return (0);
846    }
847    else
848    {
849        if (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status
850            != rpc_s_ok)
851        {
852            return (1);
853        }
854        else
855        {
856            return (2);
857        }
858    }
859}
860
861
862/*
863**++
864**
865**  MACRO NAME:		RESPONSE_FAULT_PRED
866**
867**  SCOPE:              INTERNAL
868**
869**  DESCRIPTION:
870**
871**  This is a macro version of the response_fault_pred_rtn() predicate.
872**  We added the macro version to avoid overhead when calling the
873**  predicate function from within the action routines.
874**  Evaluate the MaybeSemantics and Disconnected predicates from
875**  the Call Response state when either a fault or fault_dne
876**  event occurs.
877**
878**  INPUTS:
879**
880**      spc_struct      The call rep.  Note that this is passed in as
881**                      the special structure which is passed to the
882**                      state machine event evaluation routine.
883**
884**      event_param     The special event related parameter which is
885**                      passed to the state machine event evaluation
886**                      routine.
887**                      This input argument is ignored.
888**
889**	status		Instead of returning a value from the macro,
890**			write the value calculated in the macro to
891**			status.  Status' scope includes the routine
892**			calling the macro.  Check status in the calling
893**			routine to determine next state and in cases,
894**			flow through the action routine.
895**
896**  INPUTS/OUTPUTS:     none
897**
898**  OUTPUTS:
899**
900**	status		See explanation above.
901**
902**  IMPLICIT INPUTS:    none
903**
904**  IMPLICIT OUTPUTS:   none
905**
906**  FUNCTION VALUE:     0 if MaybeSemantics true,
907**                      1 if Disconnected is true,
908**                      2 otherwise.
909**
910**       NOTE that the architecture allows 4 possible return values
911**            so that fault data can be transmitted in several
912**            operations.  The current implementation assumes that
913**            any fault data is transmitted in a single operation.
914**
915**  SIDE EFFECTS:       none
916**
917**--
918**/
919#define RESPONSE_FAULT_PRED(spc_struct, event_param, status)	\
920{								\
921    RPC_CN_DBG_RTN_PRINTF(SERVER response_fault_pred_macro);	\
922    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (	\
923        (rpc_cn_call_rep_p_t) spc_struct);			\
924    if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE)	\
925    {								\
926        status = 0;						\
927    }								\
928    else							\
929    {								\
930        if (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status != rpc_s_ok) \
931        {							\
932            status = 1; 					\
933        }							\
934        else							\
935        {							\
936            status = 2; 					\
937        }							\
938    }								\
939}
940
941
942/*
943**++
944**
945**  ROUTINE NAME:       last_recv_frag_pred_rtn
946**
947**  SCOPE:              INTERNAL
948**
949**  DESCRIPTION:
950**
951**  Evaluate whether this is the last received request fragment
952**  when an RPCInd event occurs.
953**
954**  INPUTS:
955**
956**      spc_struct      This argument is the special structure which
957**                      is passed to the state machine event evaluation
958**                      routine.
959**                      This argument is ignored.
960**
961**      event_param     The received packet contained in a fragment
962**                      buffer.  This is passed in as the special
963**                      event related parameter by the state machine
964**                      event evaluation routine.
965**
966**  INPUTS/OUTPUTS:     none
967**
968**  OUTPUTS:            none
969**
970**  IMPLICIT INPUTS:    none
971**
972**  IMPLICIT OUTPUTS:   none
973**
974**  FUNCTION VALUE:     0 if LastRecvFrag is false
975**                      1 if LastRecvFrag is true
976**
977**  SIDE EFFECTS:       none
978**
979**--
980**/
981
982INTERNAL unsigned8 last_recv_frag_pred_rtn
983(
984  dce_pointer_t       spc_struct ATTRIBUTE_UNUSED,
985  dce_pointer_t       event_param
986)
987{
988
989    RPC_CN_DBG_RTN_PRINTF(SERVER last_recv_frag_pred_rtn);
990
991    if (RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) &
992        RPC_C_CN_FLAGS_LAST_FRAG)
993    {
994        return (1);
995    }
996    else
997    {
998        return (0);
999    }
1000}
1001
1002
1003/*
1004**++
1005**
1006**  MACRO NAME:		LAST_RECV_FRAG_PRED
1007**
1008**  SCOPE:              INTERNAL
1009**
1010**  DESCRIPTION:
1011**
1012**  This is a macro of the last_recv_frag_pred_rtn routine
1013**  introduced to avoid the overhead of a call-to-subroutine.
1014**  Evaluate whether this is the last received request fragment
1015**  when an RPCInd event occurs.
1016**
1017**  INPUTS:
1018**
1019**      spc_struct      The association group. Note that this is passed in as
1020**                      the special structure which is passed to the
1021**                      state machine event evaluation routine.
1022**
1023**      event_param     The special event related parameter which is
1024**                      passed to the state machine event evaluation
1025**                      routine.
1026**                      This input argument is ignored.
1027**
1028**	status		Instead of returning a value from the macro,
1029**			write the value calculated in the macro to
1030**			status.  Status' scope includes the routine
1031**			calling the macro.  Check status in the calling
1032**			routine to determine next state and in cases,
1033**			flow through the action routine.
1034**
1035**  INPUTS/OUTPUTS:     none
1036**
1037**  OUTPUTS:
1038**
1039**	status		See explanation above.
1040**
1041**  IMPLICIT INPUTS:    none
1042**
1043**  IMPLICIT OUTPUTS:   none
1044**
1045**  FUNCTION VALUE:     0 if LastRecvFrag is false
1046**                      1 if LastRecvFrag is true
1047**
1048**  SIDE EFFECTS:       none
1049**
1050**--
1051**/
1052#define LAST_RECV_FRAG_PRED(spc_struct, event_param, status)	\
1053{									\
1054   RPC_CN_DBG_RTN_PRINTF(SERVER last_recv_frag_pred_macro );	\
1055   if (RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) &	\
1056        RPC_C_CN_FLAGS_LAST_FRAG)					\
1057    {									\
1058        status = 1;							\
1059    }									\
1060    else								\
1061    {									\
1062        status = 0;							\
1063    }									\
1064}
1065
1066
1067/*
1068**++
1069**
1070**  ROUTINE NAME:       first_frag_pred_rtn
1071**
1072**  SCOPE:              INTERNAL
1073**
1074**  DESCRIPTION:
1075**
1076**  Evaluates whether a received packet has the first_frag bit
1077**  set.
1078**
1079**  INPUTS:
1080**
1081**      spc_struct      This argument is the special structure which
1082**                      is passed to the state machine event evaluation
1083**                      routine.
1084**                      This argument is ignored.
1085**
1086**      event_param     The received packet contained in a fragment
1087**                      buffer.  This is passed in as the special
1088**                      event related parameter by the state machine
1089**                      event evaluation routine.
1090**
1091**  INPUTS/OUTPUTS:     none
1092**
1093**  OUTPUTS:            none
1094**
1095**  IMPLICIT INPUTS:    none
1096**
1097**  IMPLICIT OUTPUTS:   none
1098**
1099**  FUNCTION VALUE:     0 if FirstFrag is false
1100**                      1 if FirstFrag is true
1101**
1102**  SIDE EFFECTS:       none
1103**
1104**--
1105**/
1106
1107INTERNAL unsigned8 first_frag_pred_rtn
1108(
1109  dce_pointer_t       spc_struct ATTRIBUTE_UNUSED,
1110  dce_pointer_t       event_param
1111)
1112{
1113    RPC_CN_DBG_RTN_PRINTF(SERVER first_frag_pred_rtn);
1114
1115    if (RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) &
1116        RPC_C_CN_FLAGS_FIRST_FRAG)
1117    {
1118        return (1);
1119    }
1120    else
1121    {
1122        return (2);
1123    }
1124
1125}
1126
1127
1128/*
1129**++
1130**
1131**  MACRO NAME:		ALERTED_PRED
1132**
1133**  SCOPE:              INTERNAL
1134**
1135**  DESCRIPTION:
1136**
1137**  This is a macro of the alerted_pred_rtn routine
1138**  introduced to avoid the overhead of a call-to-subroutine.
1139**  Evaluates whether the current call has been alerted.
1140**
1141**  INPUTS:
1142**
1143**      spc_struct      The call rep. Note that this is passed in as
1144**                      the special structure which is passed to the
1145**                      state machine event evaluation routine.
1146**
1147**	status		Instead of returning a value from the macro,
1148**			write the value calculated in the macro to
1149**			status.  Status' scope includes the routine
1150**			calling the macro.  Check status in the calling
1151**			routine to determine next state and in cases,
1152**			flow through the action routine.
1153**
1154**  INPUTS/OUTPUTS:     none
1155**
1156**  OUTPUTS:
1157**
1158**	status		See explanation above.
1159**
1160**  IMPLICIT INPUTS:    none
1161**
1162**  IMPLICIT OUTPUTS:   none
1163**
1164**  FUNCTION VALUE:     0 if call was not alerted.
1165**                      1 if call was alerted.
1166**
1167**  SIDE EFFECTS:       none
1168**
1169**--
1170**/
1171#define ALERTED_PRED(spc_struct, status)\
1172{\
1173    RPC_CN_DBG_RTN_PRINTF(SERVER alerted_pred_macro);\
1174    if ( ((rpc_cn_call_rep_p_t) spc_struct)->cn_call_status ==\
1175        rpc_s_call_cancelled )\
1176    {\
1177        status = 1;\
1178    }\
1179    else\
1180    {\
1181        status = 0;\
1182    }\
1183}
1184
1185
1186/***********************************************************************/
1187/*
1188 * S E R V E R   C A L L   A C T I O N   R O U T I N E S
1189 */
1190/***********************************************************************/
1191/*
1192**++
1193**
1194**  MACRO NAME:         RPC_CN_ASSOC_QUEUE_FRAG
1195**
1196**  SCOPE:              INTERNAL
1197**
1198**  DESCRIPTION:	Used as an optimization.  The macro function is
1199**			called from several places and was included
1200**			made into a macro for efficiency reasons.
1201**			Called from handle_first_frag_action_rtn()
1202**			and from handle_frag_action_rtn().
1203**
1204**  INPUTS:
1205**
1206**      event_param     The special event related parameter which is
1207**                      passed to the state machine event evaluation
1208**                      routine.
1209**                      This input argument is ignored.
1210**
1211**      spc_struct      The association group. Note that this is passed in as
1212**                      the special structure which is passed to the
1213**			state machine event evaluation routine.
1214**
1215**	fragbuf 	(rpc_cn_fragbuf_p_t)event_param.  Used in
1216**			the buffer manipulation routines called from
1217**			within the macro.
1218**
1219**  INPUTS/OUTPUTS:     none
1220**
1221**  OUTPUTS:		none
1222**
1223**  IMPLICIT INPUTS:    none
1224**
1225**  IMPLICIT OUTPUTS:   none
1226**
1227**  FUNCTION VALUE:
1228**
1229**  SIDE EFFECTS:       none
1230**
1231**--
1232**/
1233#define RPC_CN_ASSOC_QUEUE_FRAG(event_param, spc_struct, fragbuf) \
1234{\
1235    if ((RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) & \
1236         RPC_C_CN_FLAGS_FIRST_FRAG)) \
1237    { \
1238        rpc__cn_assoc_queue_frag (((rpc_cn_call_rep_p_t) spc_struct)->assoc, \
1239                                  fragbuf, \
1240                                  false); \
1241    } \
1242    else \
1243    { \
1244        rpc__cn_assoc_queue_frag (((rpc_cn_call_rep_p_t) spc_struct)->assoc, \
1245                                  fragbuf, \
1246                                  true); \
1247    } \
1248}
1249
1250/*
1251**++
1252**
1253**  MACRO NAME:       	RPC_CN_FRAGBUF_DATA_SIZE
1254**
1255**  SCOPE:              INTERNAL
1256**
1257**  DESCRIPTION:	Used as an optimization.  The macro function is
1258**			called from several places and was included
1259**			made into a macro for efficiency reasons.
1260**			Called from handle_first_frag_action_rtn()
1261**			and from handle_frag_action_rtn().
1262**
1263**  INPUTS:
1264**
1265**	header_p	 RPC_CN_FRAGBUF_PKT_HDR (event_param)
1266**
1267**	fragbuf 	(rpc_cn_fragbuf_p_t)event_param.  Used in
1268**			the buffer manipulation routines called from
1269**			within the macro.
1270**
1271**  INPUTS/OUTPUTS:     none
1272**
1273**  OUTPUTS:		none
1274**
1275**  IMPLICIT INPUTS:    none
1276**
1277**  IMPLICIT OUTPUTS:   none
1278**
1279**  FUNCTION VALUE:
1280**
1281**  SIDE EFFECTS:       none
1282**
1283**--
1284**/
1285#define RPC_CN_FRAGBUF_DATA_SIZE(header_p, fragbuf)\
1286{\
1287    if (RPC_CN_PKT_OBJ_UUID_PRESENT (header_p)) \
1288    { \
1289        if (RPC_CN_PKT_FRAG_LEN (header_p) < \
1290            (RPC_CN_PKT_AUTH_TLR_LEN (header_p) + RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ)) \
1291        { \
1292            DCETHREAD_RAISE(rpc_x_ss_pipe_comm_error); \
1293        } \
1294        fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) - \
1295                             RPC_CN_PKT_AUTH_TLR_LEN (header_p) - \
1296                             RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ; \
1297    } \
1298    else \
1299    { \
1300        if (RPC_CN_PKT_FRAG_LEN (header_p) < \
1301            (RPC_CN_PKT_AUTH_TLR_LEN (header_p) + RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ)) \
1302        { \
1303            DCETHREAD_RAISE(rpc_x_ss_pipe_comm_error); \
1304        } \
1305        fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) - \
1306                             RPC_CN_PKT_AUTH_TLR_LEN (header_p) - \
1307                             RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ; \
1308    } \
1309}
1310
1311
1312/*
1313**++
1314**
1315**  ROUTINE NAME:       handle_first_frag_action_rtn
1316**
1317**  SCOPE:              INTERNAL
1318**
1319**  DESCRIPTION:
1320**
1321**  Make the received fragment data available to the stub for
1322**  unmarshalling.  The fragment is assumed to be the first
1323**  fragment of the request.
1324**
1325**  INPUTS:
1326**
1327**      spc_struct      The call rep.  Note that this is passed in as
1328**                      the special structure which is passed to the
1329**                      state machine event evaluation routine.
1330**
1331**  INPUTS/OUTPUTS:
1332**
1333**      event_param     The fragment buffer containing the received
1334**                      data.  On output, the data_p and data_size
1335**                      fields will describe the stub data.
1336**
1337**	sm		The control block from the event evaluation
1338**			routine.  Input is the current state and
1339**			event for the control block.  Output is the
1340**			next state or updated current state, for the
1341**			control block.
1342**
1343**  OUTPUTS:            none
1344**
1345**  IMPLICIT INPUTS:    none
1346**
1347**  IMPLICIT OUTPUTS:   none
1348**
1349**  FUNCTION VALUE:     completion status, one of:
1350**                      rpc_s_ok,
1351**
1352**  SIDE EFFECTS:       none
1353**
1354**--
1355**/
1356INTERNAL unsigned32     handle_first_frag_action_rtn
1357(
1358  dce_pointer_t       spc_struct,
1359  dce_pointer_t       event_param,
1360  dce_pointer_t       sm
1361)
1362{
1363    unsigned32              status;
1364    rpc_cn_fragbuf_p_t      request_fragbuf;
1365    rpc_cn_packet_p_t       request_header_p;
1366    rpc_cn_packet_p_t       response_header_p;
1367    rpc_cn_call_rep_p_t     call_rep;
1368    rpc_cn_sm_ctlblk_t 	    *sm_p;
1369
1370    RPC_CN_DBG_RTN_PRINTF(SERVER handle_first_frag_action_rtn);
1371    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
1372    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
1373    request_fragbuf = (rpc_cn_fragbuf_p_t) event_param;
1374    request_header_p = RPC_CN_FRAGBUF_PKT_HDR (event_param);
1375
1376    /*
1377     * As part of the performance changes, we run a macro version
1378     * of the predicate function, last_recv_frag_pred_rtn() here.
1379     * Update status inside the macro.
1380     */
1381    LAST_RECV_FRAG_PRED (spc_struct, event_param, status);
1382    if (status == 1)  /* LastRecvFrag is true */
1383    {
1384        sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE;
1385    }
1386    else  /* LastRecvFrag is false */
1387    {
1388        sm_p->cur_state = RPC_C_SERVER_CALL_CALL_REQUEST;
1389    }
1390    status = rpc_s_ok;
1391
1392    /*
1393     * Get the max_seg_size from the association.
1394     */
1395    call_rep->max_seg_size =
1396    RPC_CN_ASSOC_MAX_XMIT_FRAG (call_rep->assoc);
1397
1398    /*
1399     * Copy the opnum field into the local call rep.
1400     */
1401    call_rep->opnum = RPC_CN_PKT_OPNUM (request_header_p);
1402    if (!(RPC_CN_PKT_FLAGS (request_header_p) & RPC_C_CN_FLAGS_MAYBE))
1403    {
1404
1405	/*
1406         * Fill in the fields of the response header if this is not
1407         * a maybe call.
1408         */
1409        RPC_CN_CREP_SIZEOF_HDR (call_rep) = RPC_CN_PKT_SIZEOF_RESP_HDR;
1410        response_header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep);
1411
1412        RPC_CN_PKT_PTYPE (response_header_p) = RPC_C_CN_PKT_RESPONSE;
1413        RPC_CN_PKT_FLAGS (response_header_p) = RPC_C_CN_FLAGS_FIRST_FRAG;
1414        RPC_CN_PKT_FRAG_LEN (response_header_p) = 0;
1415        RPC_CN_PKT_VERS_MINOR (response_header_p) =
1416            call_rep->assoc->assoc_vers_minor;
1417        RPC_CN_PKT_CALL_ID (response_header_p) =
1418            RPC_CN_PKT_CALL_ID (request_header_p);
1419
1420        RPC_CN_PKT_ALLOC_HINT (response_header_p) = 0;
1421        RPC_CN_PKT_PRES_CONT_ID (response_header_p) =
1422            RPC_CN_PKT_PRES_CONT_ID (request_header_p);
1423
1424        RPC_CN_PKT_RESP_RSVD (response_header_p) = 0;
1425
1426        /*
1427         * Initialize the iovector in the call_rep to contain only
1428         * one initial element, pointing to the protocol header.
1429         * Also, update pointers to show that we can copy data into
1430         * the stub data area.
1431         */
1432        RPC_CN_CREP_IOVLEN (call_rep) = 1;
1433        RPC_CN_CREP_CUR_IOV_INDX (call_rep) = 0;
1434        RPC_CN_CREP_FREE_BYTES (call_rep) =
1435            RPC_C_CN_SMALL_FRAG_SIZE - RPC_CN_PKT_SIZEOF_RESP_HDR;
1436        RPC_CN_CREP_ACC_BYTCNT (call_rep) = RPC_CN_PKT_SIZEOF_RESP_HDR;
1437        RPC_CN_CREP_FREE_BYTE_PTR(call_rep) =
1438            RPC_CN_PKT_RESP_STUB_DATA (response_header_p);
1439        (RPC_CN_CREP_IOV (call_rep)[0]).data_len = RPC_CN_PKT_SIZEOF_RESP_HDR;
1440
1441        /*
1442         * If security is requested for this call an auth trailer will
1443         * be formatted here and included with every packet sent.
1444         */
1445        if (call_rep->sec != NULL)
1446        {
1447            rpc_cn_auth_tlr_t       *auth_tlr;
1448            unsigned32              auth_value_len;
1449
1450            /*
1451             * Allocate a small fragbuf to contain the authentication trailer.
1452             */
1453            RPC_CN_FRAGBUF_ALLOC (call_rep->prot_tlr, RPC_C_CN_SMALL_FRAG_SIZE, &status);
1454            call_rep->prot_tlr->fragbuf_dealloc = NULL;
1455            auth_value_len = RPC_C_CN_SMALL_FRAG_SIZE;
1456            auth_tlr = (rpc_cn_auth_tlr_t *)call_rep->prot_tlr->data_p;
1457            auth_tlr->auth_type = RPC_CN_AUTH_CVT_ID_API_TO_WIRE (call_rep->sec->sec_info->authn_protocol, &status);
1458            auth_tlr->auth_level = call_rep->sec->sec_info->authn_level;
1459            auth_tlr->key_id = call_rep->sec->sec_key_id;
1460            auth_tlr->stub_pad_length = 0;
1461            auth_tlr->reserved = 0;
1462            RPC_CN_AUTH_PRE_CALL (RPC_CN_ASSOC_SECURITY (call_rep->assoc),
1463                                  call_rep->sec,
1464                                  (dce_pointer_t) auth_tlr->auth_value,
1465                                  &auth_value_len,
1466                                  &status);
1467            if (status != rpc_s_ok)
1468            {
1469                dce_error_string_t error_text;
1470                int temp_status;
1471
1472                dce_error_inq_text(status, error_text, &temp_status);
1473
1474                /*
1475                 * "%s on server failed: %s"
1476                 */
1477                rpc_dce_svc_printf (
1478                    __FILE__, __LINE__,
1479                    "%s %x",
1480                    rpc_svc_auth,
1481                    svc_c_sev_error,
1482                    rpc_m_call_failed_s,
1483                    "RPC_CN_AUTH_PRE_CALL",
1484                    error_text );
1485
1486                /*
1487                 * A fault packet containing an appropriate status code
1488                 * will be sent to the client in the receiver
1489                 * thread.
1490                 */
1491                return (status);
1492            }
1493            RPC_CN_CREP_ADJ_IOV_FOR_TLR (call_rep, response_header_p, auth_value_len);
1494        }
1495        else
1496        {
1497            RPC_CN_PKT_AUTH_LEN (response_header_p) = 0;
1498        }
1499    }
1500    else
1501    {
1502        /*
1503         * There is no response packet for a maybe call.
1504         */
1505        (RPC_CN_CREP_IOV (call_rep)[0]).data_len = 0;
1506
1507        /*
1508         * Even though there is no response for a maybe call,
1509         * we still set the flag bit because the server call state
1510         * machine predicates check it.
1511         */
1512        RPC_CN_CREP_SIZEOF_HDR (call_rep) = RPC_CN_PKT_SIZEOF_RESP_HDR;
1513        response_header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep);
1514
1515        RPC_CN_PKT_FLAGS (response_header_p) = RPC_C_CN_FLAGS_MAYBE;
1516    }
1517
1518    /*
1519     * Run the functional components of handle_frag_action_routine minus
1520     * its internal predicate component.
1521     */
1522    /*
1523     * Adjust fragment buffer so that data_size describes the stub data.
1524     * Note that we do not adjust data_p; that will be done by
1525     * rpc__cn_call_receive.
1526     */
1527    RPC_CN_FRAGBUF_DATA_SIZE(request_header_p, request_fragbuf);
1528
1529    /*
1530     * Queue the stub data on the association so that the call
1531     * executor thread can get it.
1532     *
1533     * As an optimization for the first fragment the association
1534     * receive queue condition variable will not be signalled since
1535     * the call executor thread is not started until after we return
1536     * from this state transition back to the receiver thread main loop.
1537     */
1538    RPC_CN_ASSOC_QUEUE_FRAG(event_param, spc_struct,
1539			(rpc_cn_fragbuf_p_t) event_param);
1540
1541    /*
1542     * Check the header for a pending cancel. If we had a pending
1543     * cancel at the client side re-generate it here.
1544     */
1545    if (RPC_CN_PKT_FLAGS (request_header_p) & RPC_C_CN_FLAGS_ALERT_PENDING)
1546    {
1547        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
1548                       ("(handle_first_frag_action_rtn) call_rep->%p alert pending bit set in header calling rpc__cthread_cancel()\n", call_rep));
1549        RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep));
1550        rpc__cthread_cancel ((rpc_call_rep_t *) call_rep);
1551        RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep));
1552    }
1553    return (status);
1554}
1555
1556
1557/*
1558**++
1559**
1560**  ROUTINE NAME:       handle_frag_action_rtn
1561**
1562**  SCOPE:              INTERNAL
1563**
1564**  DESCRIPTION:
1565**
1566**  Make the received fragment data available to the stub for
1567**  unmarshalling.
1568**
1569**  INPUTS:
1570**
1571**      spc_struct      The call rep.  Note that this is passed in as
1572**                      the special structure which is passed to the
1573**                      state machine event evaluation routine.
1574**
1575**  INPUTS/OUTPUTS:
1576**
1577**      event_param     The fragment buffer containing the received
1578**                      data.  On output, the data_p and data_size
1579**                      fields will describe the stub data.
1580**
1581**	sm		The control block from the event evaluation
1582**			routine.  Input is the current state and
1583**			event for the control block.  Output is the
1584**			next state or updated current state, for the
1585**			control block.
1586**
1587**  OUTPUTS:            none
1588**
1589**  IMPLICIT INPUTS:    none
1590**
1591**  IMPLICIT OUTPUTS:   none
1592**
1593**  FUNCTION VALUE:     rpc_s_ok
1594**
1595**  SIDE EFFECTS:       none
1596**
1597**--
1598**/
1599INTERNAL unsigned32     handle_frag_action_rtn
1600(
1601  dce_pointer_t       spc_struct,
1602  dce_pointer_t       event_param,
1603  dce_pointer_t       sm
1604)
1605{
1606    unsigned32              status;
1607    rpc_cn_fragbuf_p_t      fragbuf;
1608    rpc_cn_packet_p_t       header_p;
1609    rpc_cn_sm_ctlblk_t 	    *sm_p;
1610
1611    RPC_CN_DBG_RTN_PRINTF(SERVER handle_frag_action_rtn);
1612    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
1613    fragbuf = (rpc_cn_fragbuf_p_t) event_param;
1614    header_p = RPC_CN_FRAGBUF_PKT_HDR (event_param);
1615
1616    /*
1617     * As part of the performance changes, we run a macro version
1618     * of the predicate function, last_recv_frag_pred_rtn() here.  Update
1619     * status inside the macro.
1620     */
1621    LAST_RECV_FRAG_PRED (spc_struct, event_param, status);
1622    if (status == 1)  /* LastRecvFrag is true */
1623    {
1624        sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE;
1625    }
1626    else  /* LastRecvFrag is false */
1627    {
1628        sm_p->cur_state = RPC_C_SERVER_CALL_CALL_REQUEST;
1629    }
1630
1631    status = rpc_s_ok;
1632
1633    /*
1634     * Adjust fragment buffer so that data_size describes the stub data.
1635     * Note that we do not adjust data_p; that will be done by
1636     *   rpc__cn_call_receive.
1637     */
1638    RPC_CN_FRAGBUF_DATA_SIZE(header_p, fragbuf);
1639
1640    /*
1641     * Queue the stub data on the association so that the call
1642     * executor thread can get it.
1643     *
1644     * As an optimization for the first fragment the association
1645     * receive queue condition variable will not be signalled since
1646     * the call executor thread is not started until after we return
1647     * from this state transition back to the receiver thread main loop.
1648     */
1649    RPC_CN_ASSOC_QUEUE_FRAG(event_param, spc_struct, fragbuf);
1650
1651    return(status);
1652}
1653
1654
1655/*
1656**++
1657**
1658**  ROUTINE NAME:       send_call_resp_action_rtn
1659**
1660**  SCOPE:              INTERNAL
1661**
1662**  DESCRIPTION:
1663**
1664**  Start sending the call response PDU(s) to the client.
1665**
1666**  INPUTS:
1667**
1668**      spc_struct      The call rep.  Note that this is passed in as
1669**                      the special structure which is passed to the
1670**                      state machine event evaluation routine.
1671**
1672**      event_param     The iovector describing the data to be sent.
1673**                      This is passed in as the special event related
1674**                      parameter passed to the state machine event
1675**                      evaluator.
1676**
1677**  INPUTS/OUTPUTS:
1678**
1679**	sm		The control block from the event evaluation
1680**			routine.  Input is the current state and
1681**			event for the control block.  Output is the
1682**			next state or updated current state, for the
1683**			control block.
1684**
1685**  OUTPUTS:            none
1686**
1687**  IMPLICIT INPUTS:    none
1688**
1689**  IMPLICIT OUTPUTS:   none
1690**
1691**  FUNCTION VALUE:     rpc_s_ok if the send was completed successfully.
1692**
1693**  SIDE EFFECTS:       none
1694**
1695**--
1696**/
1697
1698INTERNAL unsigned32     send_call_resp_action_rtn
1699(
1700  dce_pointer_t       spc_struct,
1701  dce_pointer_t       event_param,
1702  dce_pointer_t       sm
1703)
1704{
1705    rpc_cn_call_rep_p_t     call_rep;
1706    rpc_iovector_p_t        stub_data_p;
1707    rpc_iovector_elt_p_t    iov_elt_p;
1708    unsigned8               event ATTRIBUTE_UNUSED;
1709    unsigned32              i;
1710    unsigned32              status;
1711    rpc_cn_sm_ctlblk_t 	    *sm_p;
1712
1713    RPC_CN_DBG_RTN_PRINTF(SERVER send_call_resp_action_rtn);
1714    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
1715    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
1716    stub_data_p = (rpc_iovector_p_t) event_param;
1717
1718    /*
1719     * As part of the performance changes, we run a macro version
1720     * of the predicate function, disc_last_send_pred_rtn() here.  Update
1721     * status inside the macro.   Note that DISC_LAST_SEND_PRED
1722     * can only return 0 or 2, not 1.
1723     */
1724    DISC_LAST_SEND_PRED(spc_struct, event_param, status );
1725    sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE;
1726    if  (status == 0)
1727    {
1728        abort_resp_action_rtn( spc_struct, event_param, sm);
1729        return(rpc_s_ok);
1730    }
1731    status = rpc_s_ok;
1732
1733    /*
1734     * A call_response must have some stub data.
1735     *
1736     * This raises a question:
1737     *    If the call had no output arguments, then I guess
1738     *    the CALL_END on the client would send back just
1739     *    the protocol header.  The runtime would have no
1740     *    way of knowing until the CALL_END.  Right?
1741     *    Does this mean that we need to track whether any
1742     *    response was generated and if not, issue just a
1743     *    response header during a call end.
1744     */
1745#ifdef DEBUG
1746    if ((stub_data_p == NULL) || (stub_data_p->num_elt <= 0))
1747    {
1748        /*
1749         * rpc_m_no_stub_data
1750         * "(%s) No stub data to send"
1751         */
1752        rpc_dce_svc_printf (
1753            __FILE__, __LINE__,
1754            "%s",
1755            rpc_svc_xmit,
1756            svc_c_sev_fatal | svc_c_action_abort,
1757            rpc_m_no_stub_data,
1758            "send_call_resp_action_rtn" );
1759    }
1760    else
1761    {
1762#endif
1763        /* Fill in the alloc_hint */
1764        call_rep->alloc_hint = rpc__cn_get_alloc_hint(stub_data_p);
1765
1766        status = rpc_s_ok;
1767        for (i = 0, iov_elt_p = stub_data_p->elt;
1768             i < stub_data_p->num_elt;
1769             i++, iov_elt_p++)
1770        {
1771            /*
1772             * If there is no data, just deallocate the iovector
1773             * element.
1774             */
1775            if (iov_elt_p->data_len <= 0)
1776            {
1777                if (iov_elt_p->buff_dealloc != NULL)
1778                {
1779                    (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr);
1780                }
1781            }
1782            /*
1783             * If the number of bytes < our bcopy_lim, copy the data
1784               and deallocate the buffer.  rpc__cn_copy_buffer will
1785               automatically transfer the data if the accumulated byte
1786               count reaches the segment size.
1787             */
1788            else if (iov_elt_p->data_len <= RPC_C_CN_BCOPY_LIM)
1789            {
1790                rpc__cn_copy_buffer (call_rep, iov_elt_p, &status);
1791                if (iov_elt_p->buff_dealloc != NULL)
1792                {
1793                    (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr);
1794                }
1795            }
1796            /*
1797             * If the buffer must be made immediately reusable, copy
1798             * it also.
1799             * Note that this can be optimized later so that we won't
1800             * copy; just transmit the data; if certain criteria have
1801             * been met.
1802             */
1803            else if (iov_elt_p->flags & rpc_c_iovector_elt_reused)
1804            {
1805                rpc__cn_copy_buffer (call_rep, iov_elt_p, &status);
1806                if (status != rpc_s_ok)
1807                {
1808		      return (status);
1809                }
1810            }
1811            else
1812            {
1813                /*
1814                 * Don't copy, add this buffer as a new iovector
1815                 * element.  rpc__cnadd_new_vector_elmt will
1816                 * automatically transfer the data if the
1817                 * accumulated byte count reaches the segment size.
1818                 */
1819                rpc__cn_add_new_iovector_elmt (call_rep, iov_elt_p, &status);
1820
1821                if (status != rpc_s_ok)
1822                {
1823		      return (status);
1824                }
1825            }
1826        }
1827#ifdef DEBUG
1828    }
1829#endif
1830    return (status);
1831}
1832
1833
1834/*
1835**++
1836**
1837**  ROUTINE NAME:       send_call_fault_action_rtn
1838**
1839**  SCOPE:              INTERNAL
1840**
1841**  DESCRIPTION:
1842**
1843**  Start sending the call fault PDU(s) to the server.
1844**
1845**  INPUTS:
1846**
1847**      spc_struct      The call rep.  Note that this is passed in as
1848**                      the special structure which is passed to the
1849**                      state machine event evaluation routine.
1850**
1851**      event_param     The iovector describing the fault data
1852**                      to be sent.  This is passed in as the special
1853**                      event related parameter passed to the state
1854**                      machine event evaluator.
1855**                      This parameter can be null.
1856**
1857**  INPUTS/OUTPUTS:
1858**
1859**	sm		The control block from the event evaluation
1860**			routine.  Input is the current state and
1861**			event for the control block.  Output is the
1862**			next state or updated current state, for the
1863**			control block.
1864**
1865**  OUTPUTS:            none
1866**
1867**  IMPLICIT INPUTS:    call_rep->cn_call_status is assumed to
1868**                      indicate the cause of the fault.  If it is
1869**                      0, then it is assumed that there is
1870**                      fault data to be sent.
1871**
1872**  IMPLICIT OUTPUTS:   none
1873**
1874**  FUNCTION VALUE:     rpc_s_ok if the send was completed successfully.
1875**
1876**  SIDE EFFECTS:       none
1877**
1878**--
1879**/
1880INTERNAL unsigned32     send_call_fault_action_rtn
1881(
1882  dce_pointer_t       spc_struct,
1883  dce_pointer_t       event_param,
1884  dce_pointer_t       sm
1885)
1886{
1887    rpc_cn_call_rep_p_t     call_rep;
1888    rpc_cn_packet_p_t       header_p;
1889    rpc_iovector_p_t        stub_data_p;
1890    rpc_iovector_elt_p_t    iov_elt_p;
1891    unsigned32              i;
1892    unsigned32              status;
1893    unsigned32              pdu_size;
1894    rpc_cn_sm_ctlblk_t	    *sm_p;
1895
1896    RPC_CN_DBG_RTN_PRINTF(SERVER send_call_fault_action_rtn);
1897
1898    status = rpc_s_ok;
1899
1900    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
1901    stub_data_p = (rpc_iovector_p_t) event_param;
1902    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
1903
1904    /*
1905     * As part of the performance changes, we run a macro version
1906     * of the predicate function, request_fault_pred_rtn() here.  Update
1907     * status inside the macro.
1908     */
1909    REQUEST_FAULT_PRED (call_rep, event_param, status);
1910    if (status == 0)
1911    {
1912	/*
1913	 * abort_receive () is defined as RPC_C_SM_NO_ACTION
1914	 */
1915	sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED;
1916	return(status);
1917    }
1918    else if (status == 1)
1919    {
1920	sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED;
1921    }
1922    else if (status == 2)
1923    {
1924	sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE;
1925    }
1926    status = rpc_s_ok;
1927
1928    /*
1929     * Use the packet header bufferred on the call rep to format the
1930     * fault packet header.
1931     */
1932    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep);
1933
1934    /*
1935     * The call is going to be terminated. The stub data bufferred
1936     * on the call rep will not be sent and can be released.
1937     */
1938    rpc__cn_dealloc_buffered_data (call_rep);
1939    RPC_CN_FREE_ALL_EXCEPT_PROT_HDR (call_rep);
1940
1941    /*
1942     * Adjust the bufferred header to be the size of a fault packet
1943     * header.
1944     */
1945    if (call_rep->sec == NULL)
1946    {
1947        pdu_size = RPC_CN_PKT_SIZEOF_FAULT_HDR;
1948    }
1949    else
1950    {
1951        pdu_size =
1952            RPC_CN_PKT_SIZEOF_FAULT_HDR +
1953            call_rep->prot_tlr->data_size;
1954        RPC_CN_CREP_IOVLEN (call_rep) = 2;
1955    }
1956    RPC_CN_CREP_SIZEOF_HDR (call_rep) = pdu_size;
1957    RPC_CN_CREP_IOV(call_rep)[0].data_len = pdu_size;
1958    RPC_CN_CREP_ACC_BYTCNT (call_rep) = pdu_size;
1959
1960    /*
1961     * Now set up the fault packet header.
1962     */
1963    RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_FAULT;
1964    if (call_rep->call_executed)
1965    {
1966        RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_FIRST_FRAG;
1967    }
1968    else
1969    {
1970        RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_DID_NOT_EXECUTE |
1971                                   RPC_C_CN_FLAGS_FIRST_FRAG;
1972    }
1973    RPC_CN_PKT_ALLOC_HINT (header_p) = 0;
1974    RPC_CN_PKT_PRES_CONT_ID (header_p) = call_rep->context_id;
1975    RPC_CN_PKT_RESP_RSVD (header_p) = 0;
1976    RPC_CN_PKT_RESP_RSVD2 (header_p) = 0;
1977
1978    /*
1979     * The fault status can be either an architected non-zero
1980     * value indicating a runtime error, such as an interface
1981     * version mismatch, or zero, indicating a stub defined
1982     * exception specified with the stub data.
1983     */
1984    if (call_rep->cn_call_status != rpc_s_ok)
1985    {
1986        RPC_CN_PKT_STATUS (header_p) = call_rep->cn_call_status;
1987    }
1988    else
1989    {
1990        RPC_CN_PKT_STATUS (header_p) = 0;
1991
1992#ifdef DEBUG
1993        /*
1994         * There should be stub data in this case.
1995         */
1996        if ((stub_data_p == NULL) || (stub_data_p->num_elt <= 0))
1997        {
1998            /*
1999             * rpc_m_no_stub_data
2000             * "(%s) No stub data to send"
2001             */
2002            rpc_dce_svc_printf (
2003                __FILE__, __LINE__,
2004                "%s",
2005                rpc_svc_xmit,
2006                svc_c_sev_fatal | svc_c_action_abort,
2007                rpc_m_no_stub_data,
2008                "send_call_fault_action_rtn" );
2009        }
2010#endif
2011
2012        /*
2013         * Chain the fault data onto the buffered output.
2014         */
2015        assert(stub_data_p != NULL);
2016        for (i = 0, iov_elt_p = stub_data_p->elt;
2017             i < stub_data_p->num_elt;
2018             i++, iov_elt_p++)
2019        {
2020            rpc__cn_add_new_iovector_elmt (call_rep,
2021                                           iov_elt_p,
2022                                           &status);
2023            if (status != rpc_s_ok)
2024            {
2025                rpc__cn_dealloc_buffered_data (call_rep);
2026		return (status);
2027	    }
2028        }
2029    }
2030
2031    /*
2032     * We can only handle one fragment of fault data.
2033     */
2034    RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG;
2035
2036    /*
2037     * Update the alert_pending state and stop accepting
2038     * forwarded cancels.
2039     */
2040    RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2041                    ("(send_call_fault_action_rtn) call_rep->%p setting alert count (%d) in packet header\n",
2042                     call_rep,
2043                     call_rep->u.server.cancel.local_count));
2044    RPC_CN_PKT_ALERT_COUNT (header_p) = call_rep->u.server.cancel.local_count;
2045    RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep));
2046    if (call_rep->common.u.server.cancel.had_pending)
2047    {
2048        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2049                        ("(send_call_fault_action_rtn) call_rep->%p setting alert pending bit in packet header\n", call_rep));
2050        RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_ALERT_PENDING;
2051    }
2052    RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep));
2053    rpc__cn_transmit_buffers (call_rep, &status);
2054    rpc__cn_dealloc_buffered_data (call_rep);
2055    RPC_CN_CREP_IOVLEN (call_rep) = 1;
2056    return (status);
2057}
2058
2059
2060/*
2061**++
2062**
2063**  ROUTINE NAME:       process_alert_msg_action_rtn
2064**
2065**  SCOPE:              INTERNAL
2066**
2067**  DESCRIPTION:
2068**
2069**  Process a received remote alert message.
2070**
2071**  INPUTS:
2072**
2073**      spc_struct      The call rep.  Note that this is passed in as
2074**                      the special structure which is passed to the
2075**                      state machine event evaluation routine.
2076**
2077**      event_param     The fragment buffer containing the remote
2078**                      alert message.  This fragment buffer is
2079**                      deallocated.
2080**
2081**  INPUTS/OUTPUTS:
2082**
2083**	sm		The control block from the event evaluation
2084**			routine.  Input is the current state and
2085**			event for the control block.  Output is the
2086**			next state or updated current state, for the
2087**			control block.
2088**
2089**  OUTPUTS:            none
2090**
2091**  IMPLICIT INPUTS:    none
2092**
2093**  IMPLICIT OUTPUTS:   none
2094**
2095**  FUNCTION VALUE:     rpc_s_ok.
2096**
2097**  SIDE EFFECTS:       none
2098**
2099**--
2100**/
2101INTERNAL unsigned32     process_alert_msg_action_rtn
2102(
2103  dce_pointer_t       spc_struct,
2104  dce_pointer_t       event_param,
2105  dce_pointer_t       sm
2106)
2107{
2108    rpc_cn_call_rep_p_t     call_rep;
2109    rpc_cn_fragbuf_p_t      fragbuf;
2110    unsigned32              status ATTRIBUTE_UNUSED;
2111    rpc_cn_sm_ctlblk_t 	    *sm_p;
2112
2113    RPC_CN_DBG_RTN_PRINTF(SERVER process_alert_msg_action_rtn);
2114
2115    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
2116    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
2117    /*
2118     * Increment the number of remote cancels received.
2119     */
2120    call_rep->u.server.cancel.local_count++;
2121
2122    RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2123                   ("(process_alert_msg_action_rtn) call_rep->%p received remote alert packet total = %d\n",
2124                    call_rep,
2125                    call_rep->u.server.cancel.local_count));
2126
2127    /*
2128     * We are currently executing in the context of the
2129     * receiver thread so call cthread_cancel. This routine will
2130     * cancel the call executor thread if the server is accepting and
2131     * not queueing cancels.
2132     */
2133    RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep));
2134    rpc__cthread_cancel ((rpc_call_rep_t *) call_rep);
2135    RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep));
2136
2137    /*
2138     * We can just deallocate the fragment buffer.
2139     */
2140    fragbuf = (rpc_cn_fragbuf_p_t) event_param;
2141    (* fragbuf->fragbuf_dealloc) (fragbuf);
2142
2143    /*
2144     * In this case, the updated value of sm->cur_state is
2145     * determined by the current value of sm->cur_state.
2146     * Note that 2+rpc_c_cn_statebase is call_response_state;
2147     * 1+rpc_c_cn_statebase is call_request_state.  rpc_c_
2148     * cn_statbase is used to distinguish state values from
2149     * action routine indexes in the state tables.
2150     */
2151    if (sm_p->cur_state == (2 + RPC_C_CN_STATEBASE ))
2152	sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE;
2153    else if (sm_p->cur_state == ( 1 + RPC_C_CN_STATEBASE ))
2154	sm_p->cur_state = RPC_C_SERVER_CALL_CALL_REQUEST;
2155    return( rpc_s_ok);
2156}
2157
2158
2159/*
2160**++
2161**
2162**  ROUTINE NAME:       abort_resp_action_rtn
2163**
2164**  SCOPE:              INTERNAL
2165**
2166**  DESCRIPTION:
2167**
2168**  Discontinue any further transmission of data for the current
2169**  call, to the best extent possible.  Some error condition has
2170**  terminated the current call.
2171**
2172**  INPUTS:
2173**
2174**      spc_struct      The call rep.  Note that this is passed in as
2175**                      the special structure which is passed to the
2176**                      state machine event evaluation routine.
2177**
2178**      event_param     If not null, this is the address of an
2179**                      iovector.
2180**
2181**  INPUTS/OUTPUTS:
2182**
2183**	sm             The control block from the event evaluation
2184**                      routine.  Input is the current state and
2185**                      event for the control block.  SM is not changed
2186**			here.
2187**
2188**  OUTPUTS:            none
2189**
2190**  IMPLICIT INPUTS:    none
2191**
2192**  IMPLICIT OUTPUTS:   none
2193**
2194**  FUNCTION VALUE:     rpc_s_ok.
2195**
2196**  SIDE EFFECTS:       none
2197**
2198**--
2199**/
2200INTERNAL unsigned32     abort_resp_action_rtn
2201(
2202  dce_pointer_t       spc_struct,
2203  dce_pointer_t       event_param ATTRIBUTE_UNUSED,
2204  dce_pointer_t       sm ATTRIBUTE_UNUSED
2205)
2206{
2207    rpc_cn_call_rep_p_t     call_rep;
2208    rpc_cn_packet_p_t       header_p ATTRIBUTE_UNUSED;
2209
2210    RPC_CN_DBG_RTN_PRINTF(SERVER abort_resp_action_rtn);
2211
2212    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
2213
2214    /*
2215     * If there are buffered iovector elements, deallocate them.
2216     *
2217     * Note that the comparison below is not strictly correct.
2218     * Even if there is only a single iovector element, there
2219     * may be copied stub data after the header.  It's ok to
2220     * ignore them because the only way in which the first
2221     * iovector element would be reused is if we use it to send
2222     * a fault.  That operation would adjust the pointers
2223     * anyway to point to only the fault data.
2224     */
2225   if (RPC_CN_CREP_IOVLEN (call_rep) > 1)
2226    {
2227        rpc__cn_dealloc_buffered_data (call_rep);
2228
2229        /*
2230         * This will keep the call_end_action_rtn from attempting to
2231         * send the remaining iov which at this point is only an auth_tlr
2232         * if this was an authenticated call.  We are calling this an
2233         * orphaned call which technically, it is, ie the connection is
2234         * gone and along with it the association.
2235         */
2236        call_rep->cn_call_status = rpc_s_call_orphaned ;
2237
2238        /*
2239         * Set the length of the iovector to be 1 (just the
2240         * protocol header); everything else has been
2241         * deallocated.
2242         *
2243         * Note that we don't use the FREE_ALL_EXCEPT_PROT_HEADER
2244         * macro from cnxfer.c since we know that we won't be
2245         * queueing more data.
2246         */
2247        RPC_CN_CREP_IOVLEN (call_rep) = 1;
2248    }
2249
2250    return (rpc_s_ok);
2251}
2252
2253
2254/*
2255**++
2256**
2257**  ROUTINE NAME:       abort_resp_send_fault_action_rtn
2258**
2259**  SCOPE:              INTERNAL
2260**
2261**  DESCRIPTION:
2262**
2263**  Discontinue any further transmission of data for the current
2264**  call, to the best extent possible; then send a fault.
2265**  Some error condition has terminated the current call.
2266**
2267**  INPUTS:
2268**
2269**      spc_struct      The call rep.  Note that this is passed in as
2270**                      the special structure which is passed to the
2271**                      state machine event evaluation routine.
2272**
2273**      event_param     If not null, this is the address of an
2274**                      iovector element containing fault data.
2275**
2276**  INPUTS/OUTPUTS:
2277**
2278**	sm		The control block from the event evaluation
2279**			routine.  Input is the current state and
2280**			event for the control block.  Output is the
2281**			next state or updated current state, for the
2282**			control block.
2283**
2284**  OUTPUTS:            none
2285**
2286**  IMPLICIT INPUTS:    none
2287**
2288**  IMPLICIT OUTPUTS:   none
2289**
2290**  FUNCTION VALUE:     rpc_s_ok.
2291**
2292**  SIDE EFFECTS:       none
2293**
2294**--
2295**/
2296INTERNAL unsigned32     abort_resp_send_fault_action_rtn
2297(
2298  dce_pointer_t       spc_struct,
2299  dce_pointer_t       event_param,
2300  dce_pointer_t       sm
2301)
2302{
2303    unsigned32              status;
2304    rpc_cn_sm_ctlblk_t 	    *sm_p;
2305    unsigned8		    n_state ATTRIBUTE_UNUSED;
2306    rpc_cn_packet_p_t       header_p;
2307    rpc_cn_call_rep_p_t	    call_rep;
2308    rpc_iovector_elt_p_t    iov_elt_p;
2309    rpc_iovector_p_t        stub_data_p;
2310    unsigned32		    i;
2311    unsigned32	  	    pdu_size;
2312
2313    RPC_CN_DBG_RTN_PRINTF(SERVER abort_resp_send_fault_action_rtn);
2314    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
2315
2316    /*
2317     * RESPONSE_FAULT_PRED sets status which is used here
2318     * to determine the updated state in the control block,
2319     * and to determine which action routines (if any)
2320     * to call next.
2321     */
2322    RESPONSE_FAULT_PRED(spc_struct, event_param, status);
2323    if (status == 0)  		/* MaybeSemantics true */
2324    {
2325        sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED;
2326        return (rpc_s_ok);
2327    }
2328    else if (status == 1)  	/* Disconnected is true */
2329    {
2330	abort_resp_action_rtn (spc_struct, event_param, sm);
2331        sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED;
2332        return (rpc_s_ok);
2333    }
2334    else if (status == 2)   	/* Otherwise.. */
2335    {
2336            sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED;
2337    }
2338
2339    /*
2340     * REMOVED: this should be called acording to the spec,
2341     * but it doesn't do anything that isn't done already,
2342     * and it now sets the call status to orphaned.
2343     *
2344     * Abort the send; we don't care about its returned status.
2345     * status = abort_resp_action_rtn (spc_struct, event_param);
2346     */
2347
2348    /*
2349     * Send the fault.
2350     *
2351     * send_call_fault_action_rtn (spc_struct, event_param );
2352     * We changed send_call_fault_action_rtn to include a predicate
2353     * for performance reasons so we cannot just call the routine
2354     * here because the predicate function would cause additional
2355     * and incorrect state transitions.
2356     */
2357    RPC_CN_DBG_RTN_PRINTF(SERVER send_call_fault_action_rtn);
2358
2359    call_rep = (rpc_cn_call_rep_p_t)spc_struct;
2360    stub_data_p = (rpc_iovector_p_t) event_param;
2361
2362    /*
2363     * Use the packet header bufferred on the call rep to format the
2364     * fault packet header.
2365     */
2366    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep);
2367
2368    /*
2369     * The call is going to be terminated. The stub data bufferred
2370     * on the call rep will not be sent and can be released.
2371     */
2372    rpc__cn_dealloc_buffered_data (call_rep);
2373    RPC_CN_FREE_ALL_EXCEPT_PROT_HDR (call_rep);
2374
2375    /*
2376     * Adjust the bufferred header to be the size of a fault packet
2377     * header.
2378     */
2379    if (call_rep->sec == NULL)
2380    {
2381        pdu_size = RPC_CN_PKT_SIZEOF_FAULT_HDR;
2382    }
2383    else
2384    {
2385        pdu_size =
2386            RPC_CN_PKT_SIZEOF_FAULT_HDR +
2387            call_rep->prot_tlr->data_size;
2388        RPC_CN_CREP_IOVLEN (call_rep) = 2;
2389    }
2390    RPC_CN_CREP_SIZEOF_HDR (call_rep) = pdu_size;
2391    RPC_CN_CREP_IOV(call_rep)[0].data_len = pdu_size;
2392    RPC_CN_CREP_ACC_BYTCNT (call_rep) = pdu_size;
2393
2394    /*
2395     * Now set up the fault packet header.
2396     */
2397    RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_FAULT;
2398    if (call_rep->call_executed)
2399    {
2400        RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_FIRST_FRAG;
2401    }
2402    else
2403    {
2404        RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_DID_NOT_EXECUTE |
2405                                   RPC_C_CN_FLAGS_FIRST_FRAG;
2406    }
2407    RPC_CN_PKT_ALLOC_HINT (header_p) = 0;
2408    RPC_CN_PKT_PRES_CONT_ID (header_p) = call_rep->context_id;
2409    RPC_CN_PKT_RESP_RSVD (header_p) = 0;
2410    RPC_CN_PKT_RESP_RSVD2 (header_p) = 0;
2411
2412    /*
2413     * The fault status can be either an architected non-zero
2414     * value indicating a runtime error, such as an interface
2415     * version mismatch, or zero, indicating a stub defined
2416     * exception specified with the stub data.
2417     */
2418    if (call_rep->cn_call_status != rpc_s_ok)
2419    {
2420        RPC_CN_PKT_STATUS (header_p) = call_rep->cn_call_status;
2421    }
2422    else
2423    {
2424        RPC_CN_PKT_STATUS (header_p) = 0;
2425
2426#ifdef DEBUG
2427        /*
2428         * There should be stub data in this case.
2429         */
2430        if ((stub_data_p == NULL) || (stub_data_p->num_elt <= 0))
2431        {
2432            /*
2433             * rpc_m_no_stub_data
2434             * "(%s) No stub data to send"
2435             */
2436            rpc_dce_svc_printf (
2437                __FILE__, __LINE__,
2438                "%s",
2439                rpc_svc_xmit,
2440                svc_c_sev_fatal | svc_c_action_abort,
2441                rpc_m_no_stub_data,
2442                "send_call_fault_action_rtn" );
2443        }
2444#endif
2445
2446        /*
2447         * Chain the fault data onto the buffered output.
2448         */
2449        assert(stub_data_p != NULL);
2450        for (i = 0, iov_elt_p = stub_data_p->elt;
2451             i < stub_data_p->num_elt;
2452             i++, iov_elt_p++)
2453        {
2454            rpc__cn_add_new_iovector_elmt (call_rep,
2455                                           iov_elt_p,
2456                                           &status);
2457            if (status != rpc_s_ok)
2458            {
2459                rpc__cn_dealloc_buffered_data (call_rep);
2460		return(status);
2461	    }
2462        }
2463    }
2464
2465    /*
2466     * We can only handle one fragment of fault data.
2467     */
2468    RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG;
2469
2470    /*
2471     * Update the alert_pending state and stop accepting
2472     * forwarded cancels.
2473     */
2474    RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2475                    ("(send_call_fault_action_rtn) call_rep->%p setting alert count (%d) in packet header\n",
2476                     call_rep,
2477                     call_rep->u.server.cancel.local_count));
2478    RPC_CN_PKT_ALERT_COUNT (header_p) = call_rep->u.server.cancel.local_count;
2479    RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep));
2480    if (call_rep->common.u.server.cancel.had_pending)
2481    {
2482        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2483                        ("(send_call_fault_action_rtn) call_rep->%p setting alert pending bit in packet header\n", call_rep));
2484        RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_ALERT_PENDING;
2485    }
2486    RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep));
2487    rpc__cn_transmit_buffers (call_rep, &status);
2488    rpc__cn_dealloc_buffered_data (call_rep);
2489    RPC_CN_CREP_IOVLEN (call_rep) = 1;
2490    return (status);
2491}
2492
2493
2494/*
2495**++
2496**
2497**  ROUTINE NAME:       stop_orphan_action_rtn
2498**
2499**  SCOPE:              INTERNAL
2500**
2501**  DESCRIPTION:
2502**
2503**  Tell the stub to orphan the previous call.  If it was executing,
2504**  i.e., was still receiving for a pipe, alert it.  Otherwise,
2505**  discard the input data.  If possible (not required), insure
2506**  that no response or fault is returned for the orphaned call.
2507**
2508**  INPUTS:
2509**
2510**      spc_struct      The call rep.  Note that this is passed in as
2511**                      the special structure which is passed to the
2512**                      state machine event evaluation routine.
2513**
2514**      event_param     The fragment buffer containing the orphaned
2515**                      packet.  This fragment buffer is deallocated.
2516**
2517**  INPUTS/OUTPUTS:
2518**
2519**	sm		The control block from the event evaluation
2520**			routine.  Input is the current state and
2521**			event for the control block.  Output is the
2522**			next state or updated current state, for the
2523**			control block.
2524**
2525**  OUTPUTS:            none
2526**
2527**  IMPLICIT INPUTS:    none
2528**
2529**  IMPLICIT OUTPUTS:   none
2530**
2531**  FUNCTION VALUE:     rpc_s_ok.
2532**
2533**  SIDE EFFECTS:       none
2534**
2535**--
2536**/
2537
2538INTERNAL unsigned32     stop_orphan_action_rtn
2539(
2540  dce_pointer_t       spc_struct,
2541  dce_pointer_t       event_param,
2542  dce_pointer_t       sm
2543)
2544{
2545    rpc_cn_call_rep_p_t     call_rep;
2546    rpc_cn_fragbuf_p_t      fragbuf;
2547    unsigned32              status;
2548    rpc_binding_rep_t       *binding_r;
2549    rpc_cn_assoc_p_t        assoc;
2550    rpc_cn_sm_ctlblk_t 	    *sm_p;
2551
2552    RPC_CN_DBG_RTN_PRINTF(SERVER stop_orphan_action_rtn);
2553
2554    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
2555    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
2556
2557    /*
2558     * We are currently executing in the context of the
2559     * receiver thread. The call has been orphaned by the client.
2560     * Free all stub data buffered for sending up to this point.
2561     */
2562     rpc__cn_dealloc_buffered_data (call_rep);
2563     RPC_CN_FREE_ALL_EXCEPT_PROT_HDR (call_rep);
2564
2565    /*
2566     * If the call is queued dequeue it otherwise cancel and wakeup the thread
2567     * it is executing in.
2568     */
2569    status = rpc_s_ok;
2570    call_rep->cn_call_status = rpc_s_call_orphaned;
2571    if (rpc__cthread_dequeue((rpc_call_rep_t *) call_rep))
2572    {
2573        RPC_DBG_PRINTF(rpc_e_dbg_orphan, RPC_C_CN_DBG_ORPHAN,
2574                       ("(stop_orphan_action_rtn) call_rep->%p queued call ... dequeued call id = %x\n",
2575                        call_rep,
2576                        RPC_CN_PKT_CALL_ID ((rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(call_rep))));
2577        binding_r = (rpc_binding_rep_t *) call_rep->binding_rep;
2578        RPC_CN_UNLOCK ();
2579        rpc__cn_call_end ((rpc_call_rep_p_t *) &call_rep, &status);
2580        RPC_CN_LOCK ();
2581        RPC_BINDING_RELEASE (&binding_r, &status);
2582    }
2583    else
2584    {
2585        /*
2586         * We need to cancel and wake up the call executor
2587         * thread. If the call executor thread is in the manager
2588         * routine the cancel may get through. If it is in the
2589         * runtime blocked on a call_receive cancels are disabled
2590         * and needs to be woken up.
2591         */
2592        RPC_DBG_PRINTF(rpc_e_dbg_orphan, RPC_C_CN_DBG_ORPHAN,
2593                       ("(stop_orphan_action_rtn) call_rep->%p running call ... cancelling and waking up call id = %x\n",
2594                        call_rep,
2595                        RPC_CN_PKT_CALL_ID ((rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(call_rep))));
2596
2597        /*
2598         * Need to hold on to the assoc in a local variable since
2599         * rpc__cn_assoc_pop_call is going to NULL call_rep->assoc.
2600         * We'll pass the local variable to rpc__cn_assoc_dealloc and
2601         * use it for RPC_COND_SIGNAL.
2602         */
2603        assoc = call_rep->assoc;
2604
2605        /*
2606         * Pop the call rep off the association.
2607         */
2608        rpc__cn_assoc_pop_call (call_rep->assoc, call_rep);
2609
2610        /*
2611         * Deallocate the association.
2612         */
2613        rpc__cn_assoc_dealloc (assoc, call_rep, &status);
2614
2615        /*
2616         * If the stub is waiting for more data, signal it (really
2617         * rpc__cn_assoc_receive_frag()) to wake up (and find out
2618         * it's been orphaned).
2619         */
2620        if (assoc->assoc_msg_waiters > 0)
2621        {
2622            RPC_COND_SIGNAL (assoc->assoc_msg_cond, rpc_g_global_mutex);
2623        }
2624
2625        RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep));
2626        rpc__cthread_cancel ((rpc_call_rep_t *) call_rep);
2627        RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep));
2628    }
2629
2630    /*
2631     * Deallocate the fragment buffer containing the orphaned packet.
2632     */
2633    fragbuf = (rpc_cn_fragbuf_p_t) event_param;
2634    (*fragbuf->fragbuf_dealloc) (fragbuf);
2635
2636    /*
2637     * We do not need to call CALL_END since the call_executor
2638     * thread will do so when it processes the cancel.
2639     */
2640    sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED;
2641    return(status);
2642}
2643
2644
2645/*
2646**++
2647**
2648**  ROUTINE NAME:       discard_fragment_action_rtn
2649**
2650**  SCOPE:              INTERNAL
2651**
2652**  DESCRIPTION:
2653**
2654**  Discard the received packet.  This routine is invoked when we
2655**  get an unexpected (but benign) PDU.
2656**
2657**  INPUTS:
2658**
2659**      spc_struct      This is the special structure which is passed
2660**                      to the state machine event evaluation routine.
2661**                      This parameer is ignored.
2662**
2663**      event_param     The fragment buffer containing the received
2664**                      packet.  This is passed in as the event
2665**                      specific parameter to the state machine
2666**                      event evaluation routine.
2667**
2668**  INPUTS/OUTPUTS:
2669**
2670**	sm             The control block from the event evaluation
2671**                      routine.  Input is the current state and
2672**                      event for the control block.  SM is not changed
2673**			here.
2674**
2675**  OUTPUTS:            none
2676**
2677**  IMPLICIT INPUTS:    none
2678**
2679**  IMPLICIT OUTPUTS:   none
2680**
2681**  FUNCTION VALUE:     rpc_s_ok.
2682**
2683**  SIDE EFFECTS:       none
2684**
2685**--
2686**/
2687INTERNAL unsigned32     discard_fragment_action_rtn
2688(
2689  dce_pointer_t       spc_struct ATTRIBUTE_UNUSED,
2690  dce_pointer_t       event_param,
2691  dce_pointer_t       sm ATTRIBUTE_UNUSED
2692)
2693{
2694    rpc_cn_fragbuf_p_t  fragbuf_p;
2695    unsigned32          status;
2696
2697    RPC_CN_DBG_RTN_PRINTF(SERVER discard_fragment_action_rtn);
2698
2699    fragbuf_p = (rpc_cn_fragbuf_p_t) event_param;
2700    (* fragbuf_p->fragbuf_dealloc) (fragbuf_p);
2701
2702    status = rpc_s_ok;
2703    return (status);
2704}
2705
2706
2707/*
2708**++
2709**
2710**  ROUTINE NAME:       call_end_action_rtn
2711**
2712**  SCOPE:              INTERNAL
2713**
2714**  DESCRIPTION:
2715**
2716**  Handle the call end event.
2717**
2718**  INPUTS:
2719**
2720**      spc_struct      The call rep.  Note that this is passed in as
2721**                      the special structure which is passed to the
2722**                      state machine event evaluation routine.
2723**
2724**      event_param     This parameter is ignored.
2725**
2726**  INPUTS/OUTPUTS:
2727**
2728**	sm		The control block from the event evaluation
2729**			routine.  Input is the current state and
2730**			event for the control block.  Output is the
2731**			next state or updated current state, for the
2732**			control block.
2733**
2734**  OUTPUTS:            none
2735**
2736**  IMPLICIT INPUTS:    none
2737**
2738**  IMPLICIT OUTPUTS:   none
2739**
2740**  FUNCTION VALUE:     rpc_s_ok
2741**
2742**  SIDE EFFECTS:       none
2743**
2744**--
2745**/
2746INTERNAL unsigned32     call_end_action_rtn
2747(
2748  dce_pointer_t       spc_struct,
2749  dce_pointer_t       event_param ATTRIBUTE_UNUSED,
2750  dce_pointer_t       sm
2751)
2752{
2753    rpc_cn_call_rep_p_t     call_rep;
2754    rpc_cn_packet_p_t       header_p;
2755    unsigned32              status;
2756    rpc_cn_sm_ctlblk_t 	    *sm_p;
2757    unsigned8		    n_state ATTRIBUTE_UNUSED;
2758
2759    RPC_CN_DBG_RTN_PRINTF(SERVER call_end_action_rtn);
2760    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
2761
2762    /*
2763     * If state is call_request_state (1+rpc_c_cn_statebase), we
2764     * need to use the alerted_pred_rtn function.
2765     * If the state is call_response
2766     * (2+rpc_c_cn_statebase), then we use no predicate routine.
2767     * The value of the state is augmented with rpc_c_cn_statebase in
2768     * order to quickly distinguish it from action routine indexes
2769     * in the rpc_cn_sm_event_eval() routine.
2770     */
2771    if (sm_p->cur_state == ( 1 + RPC_C_CN_STATEBASE ))
2772    {
2773      ALERTED_PRED(spc_struct, status);
2774      if ( status == 1)
2775      {
2776		sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED;
2777      }
2778	else
2779      {
2780		/* No action required here. */
2781		sm_p->cur_state = RPC_C_SM_NO_NSTATE;
2782		return (status);
2783      }
2784    }  /* end of call_request_state */
2785
2786    else if(sm_p->cur_state == ( 2 + RPC_C_CN_STATEBASE ))
2787	sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED;
2788
2789    status = rpc_s_ok;
2790
2791    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
2792
2793    /*
2794     * If this is not a maybe call; i.e., there is a cached
2795     * protocol header, and we have not call call_end to
2796     * clean up after some error condition;
2797     * then send the last fragment.
2798     * Note that if there is no stub data, we will still
2799     * send a header with the last_frag_bit set.
2800     */
2801    if (((RPC_CN_CREP_IOV (call_rep)[0]).data_len) != 0)
2802    {
2803        header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep);
2804        RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG;
2805
2806        /*
2807         * Update the alert_pending state and stop accepting
2808         * forwarded cancels.
2809         */
2810        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2811                        ("(call_end_action_rtn) call_rep->%p setting alert count (%d) in packet header\n",
2812                         call_rep,
2813                         call_rep->u.server.cancel.local_count));
2814        RPC_CN_PKT_ALERT_COUNT (header_p) = call_rep->u.server.cancel.local_count;
2815        RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep));
2816        if (call_rep->common.u.server.cancel.had_pending)
2817        {
2818            RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2819                           ("(call_end_action_rtn) call_rep->%p setting alert pending bit in packet header\n", call_rep));
2820            RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_ALERT_PENDING;
2821        }
2822
2823        RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep));
2824
2825        /*
2826         * Don't transmit if orphaned.
2827         */
2828        if (call_rep->cn_call_status != rpc_s_call_orphaned)
2829        {
2830            rpc__cn_transmit_buffers (call_rep, &status);
2831        }
2832
2833        rpc__cn_dealloc_buffered_data (call_rep);
2834
2835        /*
2836         * Set the length of the iovector to be 1 (just the
2837         * protocol header); everything else has been
2838         * deallocated.
2839         *
2840         * Note that we don't use the FREE_ALL_EXCEPT_PROT_HEADER
2841         * macro from cnxfer.c since we know that we won't be
2842         * queueing more data.
2843         */
2844        RPC_CN_CREP_IOVLEN (call_rep) = 1;
2845    }
2846    return (status);
2847}
2848
2849
2850/*
2851**++
2852**
2853**  ROUTINE NAME:       rpc__cn_call_sm_protocol_error
2854**
2855**  SCOPE:              PRIVATE
2856**
2857**  DESCRIPTION:
2858**
2859**  Action routine invoked when an illegal transition is detected.
2860**  This routine writes an error message to stdout and DIEs.
2861**
2862**  INPUTS:
2863**
2864**      spc_struct      The special structure which is passed to the
2865**                      state machine event evaluation routine.
2866**                      This is assumed to be the call rep.
2867**
2868**      event_param     The event specific argument.
2869**
2870**  INPUTS/OUTPUTS:     none
2871**
2872**	sm		The control block from the event evaluation
2873**			routine.  Input is the current state and
2874**			event for the control block.  Output is the
2875**			next state or updated current state, for the
2876**			control block.
2877**
2878**  OUTPUTS:            none
2879**
2880**  IMPLICIT INPUTS:    none
2881**
2882**  IMPLICIT OUTPUTS:   none
2883**
2884**  FUNCTION VALUE:     unsigned32
2885**
2886**  SIDE EFFECTS:       output is printed on stdout.
2887**
2888**--
2889**/
2890PRIVATE unsigned32     rpc__cn_call_sm_protocol_error
2891(
2892  dce_pointer_t       spc_struct,
2893  dce_pointer_t       event_param ATTRIBUTE_UNUSED,
2894  dce_pointer_t       sm
2895)
2896{
2897    rpc_cn_call_rep_p_t call_rep;
2898    rpc_cn_sm_ctlblk_t 	    *sm_p;
2899
2900    RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_sm_protocol_error);
2901
2902    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
2903    sm_p->cur_state = RPC_C_SM_NO_NSTATE;
2904
2905    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
2906
2907    /*
2908     * "Illegal state transition detected in CN {client|server} call state
2909     * machine [cur_state: %d, cur_event: %d, call_rep: %x]"
2910     */
2911    rpc_dce_svc_printf (
2912        __FILE__, __LINE__,
2913        "%d %d %x",
2914        rpc_svc_cn_state,
2915        svc_c_sev_fatal | svc_c_action_abort,
2916        RPC_CALL_IS_SERVER( (rpc_call_rep_t *)call_rep ) ?
2917        rpc_m_cn_ill_state_trans_sr : rpc_m_cn_ill_state_trans_cr,
2918        call_rep->call_state.cur_state,
2919        call_rep->call_state.cur_event,
2920        call_rep );
2921	 /* FIXME: is this correct? */
2922	 return rpc_s_ok;
2923}
2924