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**      cncclsm.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  Client 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 <cnp.h>        /* NCA Connection private declarations */
99#include <cnfbuf.h>     /* NCA Connection fragment buffer declarations */
100#include <cnpkt.h>      /* NCA Connection protocol header */
101#include <cnassoc.h>    /* NCA Connection association services */
102#include <cnxfer.h>     /* NCA Connection buffered data transfer routines */
103#include <cnsm.h>       /* NCA Connection state machine declarations */
104#include <cncall.h>     /* NCA connection call service */
105#include <cnclsm.h>
106
107
108/******************************************************************************/
109/*
110 * Global Definitions
111 */
112#ifdef DEBUG
113GLOBAL const char     *rpc_g_cn_call_client_events [] =
114{
115    "TRANSMIT_REQ     ",
116    "CONFIRM          ",
117    "FAULT_DNE        ",
118    "FAULT            ",
119    "LOCAL_ALERT      ",
120    "END              ",
121    "ASSOC_ALLOC_ACK  ",
122    "ASSOC_ALLOC_NAK  ",
123    "START            ",
124    "LAST_TRANSMIT_REQ",
125    "LOCAL_ERROR      ",
126    "ALERT_TIMEOUT    "
127};
128
129GLOBAL const char     *rpc_g_cn_call_client_states [] =
130{
131    "INIT             ",
132    "ASSOC_ALLOC_WAIT ",
133    "STUB_WAIT        ",
134    "REQUEST          ",
135    "RESPONSE         ",
136    "CALL_COMPLETED   ",
137    "CALL_FAILED_DNE  ",
138    "CALL_FAILED      "
139};
140
141PRIVATE void rpc__cn_call_sm_trace
142(
143    rpc_cn_call_rep_t   *crep,
144    unsigned32          event_id,
145    unsigned32          id,
146    const char          *file ATTRIBUTE_UNUSED,
147    const char          *funcname ATTRIBUTE_UNUSED,
148    int                 lineno ATTRIBUTE_UNUSED
149)
150{
151    if (RPC_CALL_IS_CLIENT(&crep->common))
152    {
153        RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE,
154            ("(%s) STATE CLIENT CALL:   %d state->%s event->%s\n",
155             funcname, id,
156             RPC_CN_CALL_CLIENT_STATE((crep)->call_state.cur_state),
157             RPC_CN_CALL_CLIENT_EVENT(event_id)));
158    }
159    else
160    {
161        RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE,
162            ("(%s) STATE SERVER CALL:   %d state->%s event->%s\n",
163             funcname, id,
164             RPC_CN_CALL_SERVER_STATE((crep)->call_state.cur_state),
165             RPC_CN_CALL_SERVER_EVENT(event_id)));
166    }
167}
168
169PRIVATE void rpc__cn_call_sm_trace_state
170(
171    rpc_cn_call_rep_t   *crep,
172    unsigned32          id,
173    const char          *file ATTRIBUTE_UNUSED,
174    const char          *funcname ATTRIBUTE_UNUSED,
175    int                 lineno ATTRIBUTE_UNUSED
176)
177{
178    if (RPC_CALL_IS_CLIENT(&crep->common))
179    {
180        RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE,
181            ("(%s) STATE CLIENT CALL:   %d new state->%s\n",
182             funcname, id,
183             RPC_CN_CALL_CLIENT_STATE(crep->call_state.cur_state)));
184    }
185    else
186    {
187        RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE,
188            ("(%s) STATE SERVER CALL:   %d new state->%s\n",
189             funcname, id,
190             RPC_CN_CALL_SERVER_STATE(crep->call_state.cur_state)));
191    }
192}
193
194#endif /* DEBUG */
195
196
197/***********************************************************************/
198/*
199** C L I E N T   C A L L   P R E D I C A T E   T A B L E
200**/
201/*
202 * The predicates.
203 * As a performance enhancement,
204 * we have revamped many predicate routines as macros and have absorbed
205 * the predicates into the actions.  Thus, there is no longer a need
206 * for the predicate table;  the predicate declarations too, are
207 * modified.
208 */
209/*
210#define MAYBE_SEMANTICS_PRED    0
211#define LAST_RECV_FRAG_PRED     1
212*/
213/*
214 * The predicate routine prototypes.
215 */
216INTERNAL unsigned8 maybe_semantics_pred_rtn (
217        dce_pointer_t /*spc_struct*/,
218        dce_pointer_t /*event_param*/
219    ) ATTRIBUTE_UNUSED;
220INTERNAL unsigned8 last_recv_frag_pred_rtn (
221        dce_pointer_t /*spc_struct*/,
222        dce_pointer_t /*event_param*/
223    ) ATTRIBUTE_UNUSED;
224
225
226/***********************************************************************/
227/*
228** C L I E N T   C A L L   A C T I O N   T A B L E
229**/
230
231/***********************************************************************/
232
233/*
234 * The actions.
235 *
236 * The QueueAlertTimeout action routine in the NCA CN arch spec
237 * is not listed here since cancel timeouts are handled outside the
238 * state machine. See the routine header of forward_alert_action_rtn
239 * for more details.
240 *
241 * The VerifySecurity action routine in the NCA CN arch spec is not
242 * listed here since this was embedded into existing action routines,
243 * where appropriate in this implementation.
244 */
245#define TRANSMIT_REQ            0
246#define HANDLE_RECV_FRAG        1
247#define RAISE_FAULT             2
248#define FORWARD_ALERT           3
249#define ALLOCATE_ASSOC          4
250
251/* abort send = send_orphaned + deallocate assoc + raise fault */
252#define ABORT_SEND              5
253
254#define ABORT_RECV              6
255#define SEND_LAST_FRAG          7
256#define PROTOCOL_ERROR          8
257
258/*
259 * The Action routine prototypes.
260 */
261INTERNAL unsigned32     transmit_req_action_rtn (
262        dce_pointer_t /*spc_struct*/,
263        dce_pointer_t /*event_param*/,
264        dce_pointer_t /*sm*/
265    );
266INTERNAL unsigned32     handle_recv_frag_action_rtn (
267        dce_pointer_t /*spc_struct*/,
268        dce_pointer_t /*event_param*/,
269        dce_pointer_t /*sm*/
270    );
271INTERNAL unsigned32     raise_fault_action_rtn (
272        dce_pointer_t /*spc_struct*/,
273        dce_pointer_t /*event_param*/,
274        dce_pointer_t /*sm*/
275    );
276INTERNAL unsigned32     forward_alert_action_rtn (
277        dce_pointer_t /*spc_struct*/,
278        dce_pointer_t /*event_param*/,
279        dce_pointer_t /*sm*/
280    );
281INTERNAL unsigned32     allocate_assoc_action_rtn (
282        dce_pointer_t /*spc_struct*/,
283        dce_pointer_t /*event_param*/,
284        dce_pointer_t /*sm*/
285    );
286INTERNAL unsigned32     abort_send_action_rtn (
287        dce_pointer_t /*spc_struct*/,
288        dce_pointer_t /*event_param*/,
289        dce_pointer_t /*sm*/
290    );
291INTERNAL unsigned32     abort_recv_action_rtn (
292        dce_pointer_t /*spc_struct*/,
293        dce_pointer_t /*event_param*/,
294        dce_pointer_t /*sm*/
295    );
296INTERNAL unsigned32     send_last_frag_action_rtn (
297        dce_pointer_t /*spc_struct*/,
298        dce_pointer_t /*event_param*/,
299        dce_pointer_t /*sm*/
300    );
301
302/*
303 * The action table itself.
304 */
305GLOBAL rpc_cn_sm_action_fn_t  rpc_g_cn_client_call_action_tbl [] =
306{
307    transmit_req_action_rtn,
308    handle_recv_frag_action_rtn,
309    raise_fault_action_rtn,
310    forward_alert_action_rtn,
311    allocate_assoc_action_rtn,
312    abort_send_action_rtn,
313    abort_recv_action_rtn,
314    send_last_frag_action_rtn,
315    rpc__cn_call_sm_protocol_error
316};
317
318/***********************************************************************/
319/*
320** C L I E N T   C A L L   S T A T E   T A B L E
321**/
322
323INTERNAL rpc_cn_sm_state_tbl_entry_t init_state =
324
325    /* state 0 - init */
326    {
327        ILLEGAL_TRANSITION,                 /* event 0 */
328        ILLEGAL_TRANSITION,                 /* event 1 */
329        ILLEGAL_TRANSITION,                 /* event 2 */
330        ILLEGAL_TRANSITION,                 /* event 3 */
331        ILLEGAL_TRANSITION,                 /* event 4 */
332		  {RPC_C_CLIENT_CALL_CFDNE},	    /* event 5 - call_end */
333        ILLEGAL_TRANSITION,                 /* event 6 */
334        ILLEGAL_TRANSITION,                 /* event 7 */
335		  {ALLOCATE_ASSOC},  		    /* event 8 - start_call */
336        ILLEGAL_TRANSITION,                 /* event 9 */
337        ILLEGAL_TRANSITION,                 /* event 10 */
338        ILLEGAL_TRANSITION                  /* event 11 */
339    };
340
341    /* state 1 - assoc_alloc_wait */
342INTERNAL rpc_cn_sm_state_tbl_entry_t assoc_alloc_wait_state =
343    {
344        ILLEGAL_TRANSITION,                 /* event 0 */
345        ILLEGAL_TRANSITION,                 /* event 1 */
346        ILLEGAL_TRANSITION,                 /* event 2 */
347        ILLEGAL_TRANSITION,                 /* event 3 */
348        ILLEGAL_TRANSITION,                 /* event 4 */
349		  {RPC_C_CLIENT_CALL_CFDNE}, 	    /* event 5 - call_end */
350		  {RPC_C_CLIENT_CALL_STUB_WAIT},        /* event 6 - alloc_assoc_ack */
351		  {RPC_C_CLIENT_CALL_CFDNE},            /* event 7 - alloc_assoc_nak */
352        ILLEGAL_TRANSITION,                 /* event 8 */
353        ILLEGAL_TRANSITION,                 /* event 9 */
354        ILLEGAL_TRANSITION,                 /* event 10 */
355        ILLEGAL_TRANSITION                  /* event 11 */
356    };
357
358    /* state 2 - stub_wait */
359INTERNAL rpc_cn_sm_state_tbl_entry_t stub_wait_state =
360    {
361		 {TRANSMIT_REQ},    	            /* event 0 - transmit_req */
362        ILLEGAL_TRANSITION,                 /* event 1 */
363        ILLEGAL_TRANSITION,                 /* event 2 */
364        ILLEGAL_TRANSITION,                 /* event 3 */
365        ILLEGAL_TRANSITION,                 /* event 4 */
366		  {RPC_C_CLIENT_CALL_CFDNE},            /* event 5 - call_end */
367        ILLEGAL_TRANSITION,                 /* event 6 */
368        ILLEGAL_TRANSITION,                 /* event 7 */
369        ILLEGAL_TRANSITION,                 /* event 8 */
370		  {SEND_LAST_FRAG},  	            /* event 9 - last_transmit_req */
371		  {RPC_C_CLIENT_CALL_CFDNE},            /* event 10 - local_err */
372        ILLEGAL_TRANSITION,                 /* event 10 */
373        ILLEGAL_TRANSITION                  /* event 11 */
374    };
375
376    /* state 3 - call_request */
377INTERNAL rpc_cn_sm_state_tbl_entry_t call_request_state =
378    {
379		 {TRANSMIT_REQ},  		            /* event 0 - transmit_req */
380        ILLEGAL_TRANSITION,                 /* event 1 */
381		  {RAISE_FAULT}, 		            /* event 2 - fault_dne */
382		  {RAISE_FAULT}, 		            /* event 3 - fault */
383		  {FORWARD_ALERT}, 		            /* event 4 - local alert */
384		  {ABORT_SEND},  			    /* event 5 - call_end */
385        ILLEGAL_TRANSITION,                 /* event 6 */
386        ILLEGAL_TRANSITION,                 /* event 7 */
387        ILLEGAL_TRANSITION,                 /* event 8 */
388		  {SEND_LAST_FRAG},  	            /* event 9 - last_transmit_req */
389		  {ABORT_SEND}, 			    /* event 10 - local_err */
390		  {ABORT_SEND}  			    /* event 11 - alert timeout */
391    };
392
393    /* state 4 - call response */
394INTERNAL rpc_cn_sm_state_tbl_entry_t call_response_state =
395    {
396        ILLEGAL_TRANSITION,                 /* event 0 */
397		  {HANDLE_RECV_FRAG}, 	            /* event 1 - rpc_conf */
398		  {RAISE_FAULT},  		            /* event 2 - fault_dne */
399		  {RAISE_FAULT}, 		            /* event 3 - fault */
400		  {FORWARD_ALERT},  	            /* event 4 - local alert */
401		  {ABORT_SEND},  		            /* event 5 - call_end */
402        ILLEGAL_TRANSITION,                 /* event 6 */
403        ILLEGAL_TRANSITION,                 /* event 7 */
404        ILLEGAL_TRANSITION,                 /* event 8 */
405        ILLEGAL_TRANSITION,                 /* event 9 */
406		  {ABORT_SEND},          		    /* event 10 - local_err */
407		  {ABORT_SEND}                          /* event 11 - alert timeout */
408    };
409
410    /* state 5 - call_completed */
411INTERNAL rpc_cn_sm_state_tbl_entry_t call_completed_state =
412    {
413        ILLEGAL_TRANSITION,                 /* event 0 */
414        ILLEGAL_TRANSITION,                 /* event 1 */
415        ILLEGAL_TRANSITION,                 /* event 2 */
416        ILLEGAL_TRANSITION,                 /* event 3 */
417		  {RPC_C_CLIENT_CALL_CALL_COMPLETED},   /* event 4 - local alert */
418		  {RPC_C_CLIENT_CALL_CALL_COMPLETED},   /* event 5 - call_end */
419        ILLEGAL_TRANSITION,                 /* event 6 */
420        ILLEGAL_TRANSITION,                 /* event 7 */
421        ILLEGAL_TRANSITION,                 /* event 8 */
422        ILLEGAL_TRANSITION,                 /* event 9 */
423        ILLEGAL_TRANSITION,                 /* event 10 */
424        ILLEGAL_TRANSITION                  /* event 11 */
425    };
426
427    /* state 6 - cfdne (call failed, did not execute) */
428INTERNAL rpc_cn_sm_state_tbl_entry_t cfdne_state =
429    {
430		 {RPC_C_CLIENT_CALL_CFDNE},            /* event 0 */
431        ILLEGAL_TRANSITION,                 /* event 1 */
432        ILLEGAL_TRANSITION,                 /* event 2 */
433        ILLEGAL_TRANSITION,                 /* event 3 */
434		  {RPC_C_CLIENT_CALL_CFDNE},            /* event 4 - local alert */
435		  {RPC_C_CLIENT_CALL_CFDNE},            /* event 5 - call_end */
436        ILLEGAL_TRANSITION,                 /* event 6 */
437        ILLEGAL_TRANSITION,                 /* event 7 */
438        ILLEGAL_TRANSITION,                 /* event 8 */
439		  {RPC_C_CLIENT_CALL_CFDNE},            /* event 9 */
440        ILLEGAL_TRANSITION,                 /* event 10 */
441        ILLEGAL_TRANSITION                  /* event 11 */
442    };
443
444    /* state 7 - call_failed */
445INTERNAL rpc_cn_sm_state_tbl_entry_t call_failed_state =
446    {
447		 {RPC_C_CLIENT_CALL_CALL_FAILED},      /* event 0 */
448        ILLEGAL_TRANSITION,                 /* event 1 */
449        ILLEGAL_TRANSITION,                 /* event 2 */
450        ILLEGAL_TRANSITION,                 /* event 3 */
451		  {RPC_C_CLIENT_CALL_CALL_FAILED}, 	    /* event 4 - local alert */
452		  {RPC_C_CLIENT_CALL_CALL_FAILED},      /* event 5 - call_end */
453        ILLEGAL_TRANSITION,                 /* event 6 */
454        ILLEGAL_TRANSITION,                 /* event 7 */
455        ILLEGAL_TRANSITION,                 /* event 8 */
456		{RPC_C_CLIENT_CALL_CALL_FAILED},      /* event 9 */
457        ILLEGAL_TRANSITION,                 /* event 10 */
458        ILLEGAL_TRANSITION                  /* event 11 */
459    };
460
461GLOBAL rpc_cn_sm_state_entry_p_t rpc_g_cn_client_call_sm [] =
462{
463    init_state,                     /* state 0 - init */
464    assoc_alloc_wait_state,         /* state 1 - assoc_alloc_wait */
465    stub_wait_state,                /* state 2 - stub_wait */
466    call_request_state,             /* state 3 - call_request */
467    call_response_state,            /* state 4 - call_response */
468    call_completed_state,           /* state 5 - call_completed */
469    cfdne_state,                    /* state 6 - call failed, dne */
470    call_failed_state               /* state 7 - call_failed */
471
472};
473
474
475/***********************************************************************/
476/*
477**
478** C L I E N T   C A L L   P R E D I C A T E   R O U T I N E S
479**
480**/
481
482/***********************************************************************/
483
484/*
485**++
486**
487**  ROUTINE NAME:       maybe_semantics_pred_rtn
488**
489**  SCOPE:              INTERNAL
490**
491**  DESCRIPTION:
492**
493**  Predicate routine invoked from the Call Active State.
494**
495**  INPUTS:
496**
497**      spc_struct      The call rep.  Note that this is passed in as
498**                      the special structure which is passed to the
499**                      state machine event evaluation routine.
500**
501**      event_param     The special event related parameter which is
502**                      passed to the state machine event evaluation
503**                      routine.
504**                      This input argument is ignored.
505**
506**  INPUTS/OUTPUTS:     none
507**
508**  OUTPUTS:            none
509**
510**  IMPLICIT INPUTS:    none
511**
512**  IMPLICIT OUTPUTS:   none
513**
514**  FUNCTION VALUE:     0 if MaybeSemantics is false
515**                      1 if MaybeSemantics is true
516**
517**  SIDE EFFECTS:       none
518**
519**--
520**/
521
522INTERNAL unsigned8 maybe_semantics_pred_rtn
523(
524  dce_pointer_t       spc_struct,
525  dce_pointer_t       event_param ATTRIBUTE_UNUSED
526)
527{
528    rpc_cn_packet_p_t   header_p;
529
530    RPC_CN_DBG_RTN_PRINTF(CLIENT maybe_semantics_pred_rtn);
531
532    /*
533     *  check the protocol header (cached in the callrep) to see if
534     *  PFC_MAYBE is set.
535     */
536
537    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (
538        (rpc_cn_call_rep_p_t) spc_struct);
539    if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE) == 0)
540    {
541        return (0);
542    }
543    else
544    {
545        return (1);
546    }
547}
548
549
550/*
551**++
552**
553**  MACRO NAME:		MAYBE_SEMANTICS_PRED
554**
555**  SCOPE:              INTERNAL
556**
557**  DESCRIPTION:
558**
559**  This is a macro version of maybe_semantics_pred_rtn, introduced  for
560**  performance reasons.  The macro lets us avoid overhead associated with
561**  calling the predicate routine from within the action routine.
562**  Predicate macro is invoked from the Call Active State.
563**
564**  INPUTS:
565**
566**      spc_struct      The association group. Note that this is passed in as
567**                      the special structure which is passed to the
568**                      state machine event evaluation routine.
569**
570**      event_param     The special event related parameter which is
571**                      passed to the state machine event evaluation
572**                      routine.
573**                      This input argument is ignored.
574**
575**	status		Instead of returning a value from the macro,
576**			write the value calculated in the macro to
577**			status.  Status' scope includes the routine
578**			calling the macro.  Check status in the calling
579**			routine to determine next state and in cases,
580**			flow through the action routine.
581**
582**  INPUTS/OUTPUTS:     none
583**
584**  OUTPUTS:
585**
586**	status		See explanation above.
587**
588**  IMPLICIT INPUTS:    none
589**
590**  IMPLICIT OUTPUTS:   none
591**
592**  FUNCTION VALUE:     0 if MaybeSemantics is false
593**                      1 if MaybeSemantics is true
594**
595**  SIDE EFFECTS:       none
596**
597**--
598**/
599#define MAYBE_SEMANTICS_PRED(spc_struct, event_param, status)	\
600{\
601    RPC_CN_DBG_RTN_PRINTF(CLIENT maybe_semantics_pred_macro);\
602    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(\
603        (rpc_cn_call_rep_p_t) spc_struct);\
604    if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE) == 0)\
605    {\
606        status = 0;\
607    }\
608    else\
609    {\
610	status = 1;\
611    }\
612}
613
614
615/*
616**++
617**
618**  ROUTINE NAME:       last_recv_frag_pred_rtn
619**
620**  SCOPE:              INTERNAL
621**
622**  DESCRIPTION:
623**
624**  Predicate routine invoked from the Call Response state when an
625**  RPCConf event occurs.
626**
627**  INPUTS:
628**
629**      spc_struct      The callrep.  This is passed as the
630**                      special structure which is passed to the
631**                      state machine event evaluation routine.
632**                      This argument is ignored.
633**
634**      event_param     The received packet contained in a fragment
635**                      buffer.  This is passed in as the special
636**                      event related parameter by the state machine
637**                      event evaluation routine.
638**
639**  INPUTS/OUTPUTS:     none
640**
641**  OUTPUTS:            none
642**
643**  IMPLICIT INPUTS:    none
644**
645**  IMPLICIT OUTPUTS:   none
646**
647**  FUNCTION VALUE:     0 if LastRecvFrag is false
648**                      1 if LastRecvFrag is true
649**
650**  SIDE EFFECTS:       none
651**
652**--
653**/
654
655INTERNAL unsigned8 last_recv_frag_pred_rtn
656(
657  dce_pointer_t       spc_struct ATTRIBUTE_UNUSED,
658  dce_pointer_t       event_param
659)
660{
661    rpc_cn_fragbuf_p_t      fragbuf;
662    rpc_cn_packet_p_t       header_p;
663
664    RPC_CN_DBG_RTN_PRINTF(CLIENT last_recv_frag_pred_rtn);
665    fragbuf = (rpc_cn_fragbuf_p_t) event_param;
666
667    /*
668     * The [unpacked] packet header starts off in the header_overhead
669     * area.
670     */
671    header_p = (rpc_cn_packet_p_t) fragbuf->data_p;
672
673    if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) == 0)
674    {
675        return (0);
676    }
677    else
678    {
679        return (1);
680    }
681
682}
683
684/***********************************************************************/
685/*
686 * C L I E N T   C A L L   A C T I O N   R O U T I N E S
687 */
688/***********************************************************************/
689
690/*
691**++
692**
693**  ROUTINE NAME:       allocate_assoc_action_rtn
694**
695**  SCOPE:              INTERNAL
696**
697**  DESCRIPTION:
698**
699**  Action routine to allocate an association from the current
700**  association group.
701**
702**  INPUTS:
703**
704**      spc_struct      The call rep.  Note that this is passed in as
705**                      the special structure which is passed to the
706**                      state machine event evaluation routine.
707**
708**      event_param     The if_spec_rep.  This is passed in as the
709**                      special event related parameter which was
710**                      passed to the state machine evaluation routine.
711**
712**  INPUTS/OUTPUTS:
713**
714**	sm              The control block from the event evaluation
715**                      routine.  Input is the current state and
716**                      event for the control block.  Output is the
717**                      next state or updated current state, for the
718**                      control block.
719**
720**  OUTPUTS:            none
721**
722**  IMPLICIT INPUTS:    none
723**
724**  IMPLICIT OUTPUTS:   none
725**
726**  FUNCTION VALUE:     completion status, one of:
727**                      rpc_s_ok,
728**
729**  SIDE EFFECTS:       Either alloc_assoc_ack or alloc_assoc_nak
730**                      event would be appended to the state
731**                      machine event evaluation list.
732**
733**--
734**/
735INTERNAL unsigned32     allocate_assoc_action_rtn
736(
737  dce_pointer_t       spc_struct,
738  dce_pointer_t       event_param,
739  dce_pointer_t       sm
740)
741{
742    rpc_cn_assoc_p_t        assoc_p ATTRIBUTE_UNUSED;
743    rpc_cn_call_rep_p_t     call_rep_p;
744    rpc_cn_sm_event_entry_t event_entry;
745    unsigned32              status;
746    rpc_cn_sm_ctlblk_t 	    *sm_p;
747
748    RPC_CN_DBG_RTN_PRINTF(CLIENT allocate_assoc_action_rtn);
749
750    call_rep_p = (rpc_cn_call_rep_p_t) spc_struct;
751
752    /*
753     * Allocate the association.  Pass in the binding rep,
754     * and interface spec rep and get back an association, it
755     * negotiated transfer syntax and its context id.
756     */
757    if ((call_rep_p->assoc = rpc__cn_assoc_request
758         (call_rep_p,
759          (rpc_cn_binding_rep_t *) call_rep_p->binding_rep,
760          (rpc_if_rep_t *) event_param,
761          &call_rep_p->transfer_syntax,
762          &call_rep_p->context_id,
763          &call_rep_p->sec,
764          &status)) != NULL)
765    {
766        call_rep_p->max_seg_size = RPC_CN_ASSOC_MAX_XMIT_FRAG (call_rep_p->assoc);
767        rpc__cn_assoc_push_call (call_rep_p->assoc, call_rep_p, &status);
768        event_entry.event_id = RPC_C_CALL_ALLOC_ASSOC_ACK;
769        event_entry.event_param = (dce_pointer_t) NULL;
770    }
771    else
772    {
773        event_entry.event_id = RPC_C_CALL_ALLOC_ASSOC_NAK;
774        event_entry.event_param = (dce_pointer_t) NULL;
775
776        /*
777         * We will return the status returned by assoc_request.
778         * This status will be returned by the eval routine since
779         * we will invoke no action routine when we transtion to
780         * cfdne state.
781         */
782    }
783
784    /*
785     * Insert the new event on the event queue for our state
786     * machine.
787     */
788    rpc__cn_sm_insert_event (&event_entry, &(call_rep_p->call_state));
789    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
790    sm_p->cur_state = RPC_C_CLIENT_CALL_ASSOC_ALLOC_WAIT;
791    return (status);
792}
793
794
795/*
796**++
797**
798**  ROUTINE NAME:       transmit_req_action_rtn
799**
800**  SCOPE:              INTERNAL
801**
802**  DESCRIPTION:
803**
804**  Action routine to send the call request PDU(s) to the server.
805**
806**  INPUTS:
807**
808**      spc_struct      The call rep.  Note that this is passed in as
809**                      the special structure which is passed to the
810**                      state machine event evaluation routine.
811**
812**      event_param     The iovector describing the data to be sent.
813**                      This is passed in as the special event related
814**                      parameter passed to the state machine event
815**                      evaluator.
816**
817**  INPUTS/OUTPUTS:
818**
819**	sm              The control block from the event evaluation
820**                      routine.  Input is the current state and
821**                      event for the control block.  Output is the
822**                      next state or updated current state, for the
823**                      control block.
824**
825**  OUTPUTS:            none
826**
827**  IMPLICIT INPUTS:    none
828**
829**  IMPLICIT OUTPUTS:   none
830**
831**  FUNCTION VALUE:     rpc_s_ok if the send was completed successfully.
832**
833**  SIDE EFFECTS:       none
834**
835**--
836**/
837
838INTERNAL unsigned32     transmit_req_action_rtn
839(
840  dce_pointer_t       spc_struct,
841  dce_pointer_t       event_param,
842  dce_pointer_t       sm
843)
844{
845
846    rpc_cn_call_rep_p_t     call_rep;
847    rpc_iovector_p_t        stub_data_p;
848    rpc_iovector_elt_p_t    iov_elt_p;
849    unsigned8               event ATTRIBUTE_UNUSED;
850    unsigned32              i;
851    unsigned32              status;
852    rpc_cn_sm_ctlblk_t	    *sm_p;
853
854    RPC_CN_DBG_RTN_PRINTF(CLIENT transmit_req_action_rtn);
855
856    status = rpc_s_ok;
857
858    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
859    stub_data_p = (rpc_iovector_p_t) event_param;
860    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
861
862    /*
863     * We set call_executed to true at this point.
864     * This is somewhat conservative; but it is correct.
865     * We will reset call_executed if we get back a
866     * fault_dne.
867     */
868    call_rep->call_executed = true;
869
870    /*
871     * A call_transmit must have some stub data.  If this RPC
872     * had no input arguments, then the first call should have
873     * been a call_transceive with no stub data.
874     */
875#ifdef DEBUG
876    if (stub_data_p->num_elt <= 0)
877    {
878        status = rpc_s_coding_error;
879    }
880    else
881#endif
882    {
883        /* Fill in the alloc_hint */
884        call_rep->alloc_hint = rpc__cn_get_alloc_hint(stub_data_p);
885
886        for (i = 0,
887             iov_elt_p = stub_data_p->elt;   /* first iovector element */
888             i < stub_data_p->num_elt;
889             i++, iov_elt_p++)
890        {
891            /*
892             * If the data_len is 0, just deallocate the iovector
893             * element.
894             */
895            if (iov_elt_p->data_len == 0)
896            {
897                if (iov_elt_p->buff_dealloc != NULL)
898                {
899                    (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr);
900                }
901            }
902            else
903            {
904                /*
905                 * If the number of bytes < our bcopy_lim,
906                 * copy the data and deallocate the buffer.
907                 * copy_buffer will automatically transfer the
908                 * data if the accumulated byte count reaches
909                 * the segment size.
910                 */
911                if (iov_elt_p->data_len <= RPC_C_CN_BCOPY_LIM)
912                {
913                    rpc__cn_copy_buffer (call_rep, iov_elt_p, &status);
914                    if (iov_elt_p->buff_dealloc != NULL)
915                    {
916                        (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr);
917                    }
918                }
919                else
920                {
921                    /*
922                     * If the buffer must be made immediately reusable, copy
923                     * it also.
924                     * Note that this can be optimized later so that we won't
925                     * copy; just transmit the data; if certain criteria have
926                     * been met.
927                     */
928                    if (iov_elt_p->flags & rpc_c_iovector_elt_reused)
929                    {
930                        rpc__cn_copy_buffer (call_rep, iov_elt_p, &status);
931                        if (status != rpc_s_ok)
932                        {
933                            goto done;
934                        }
935                    }
936                    else
937                    {
938#if 0
939                        if (iov_elt_p->flags & rpc_c_iovector_elt_reused)
940                        {
941                            found_reusable = true;
942                        }
943#endif
944                        /*
945                         * Don't copy, add this buffer as a new iovector
946                         * element.
947                         * add_new_vector_elmt will automatically transfer the
948                         * data if the accumulated byte count reaches
949                         * the segment size.
950                         */
951                        rpc__cn_add_new_iovector_elmt (call_rep, iov_elt_p, &status);
952                        if (status != rpc_s_ok)
953                        {
954                            goto done;
955                        }
956                    }
957                }
958            }
959        }
960    }
961
962#if 0
963    /*
964     * Finally, if there is any buffered data on the call rep flush
965     * any data that we'd have to copy if possible.
966     */
967    if (found_reusable)
968    {
969        rpc__cn_flush_buffers (call_rep, &status);
970    }
971#endif
972
973done:
974;
975    sm_p->cur_state = RPC_C_CLIENT_CALL_REQUEST;
976    return (status);
977}
978
979
980/*
981**++
982**
983**  ROUTINE NAME:       send_last_frag_action_rtn
984**
985**  SCOPE:              INTERNAL
986**
987**  DESCRIPTION:
988**
989**  Action routine to send the last call request fragment to the server.
990**
991**  INPUTS:
992**
993**      spc_struct      The call rep.  Note that this is passed in as
994**                      the special structure which is passed to the
995**                      state machine event evaluation routine.
996**
997**      event_param     The iovector describing the data to be sent.
998**                      This is passed in as the special event related
999**                      parameter passed to the state machine event
1000**                      evaluator.
1001**                      This parameter can be null for a transceive
1002**                      with no input arguments.
1003**
1004**  INPUTS/OUTPUTS:
1005**
1006**	sm              The control block from the event evaluation
1007**                      routine.  Input is the current state and
1008**                      event for the control block.  Output is the
1009**                      next state or updated current state, for the
1010**                      control block.
1011**
1012**  OUTPUTS:            none
1013**
1014**  IMPLICIT INPUTS:    none
1015**
1016**  IMPLICIT OUTPUTS:   none
1017**
1018**  FUNCTION VALUE:     rpc_s_ok if the send was completed successfully.
1019**
1020**  SIDE EFFECTS:       none
1021**
1022**--
1023**/
1024
1025INTERNAL unsigned32     send_last_frag_action_rtn
1026(
1027  dce_pointer_t       spc_struct,
1028  dce_pointer_t       event_param,
1029  dce_pointer_t       sm
1030)
1031{
1032
1033    rpc_cn_call_rep_p_t     call_rep;
1034    rpc_iovector_p_t        stub_data_p;
1035    rpc_cn_packet_p_t       header_p;
1036    unsigned32              status;
1037    rpc_cn_sm_ctlblk_t	    *sm_p;
1038    unsigned8		    n_state;
1039
1040    RPC_CN_DBG_RTN_PRINTF(CLIENT send_last_frag_action_rtn);
1041
1042    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
1043    status = rpc_s_ok;
1044    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
1045
1046    /*
1047     * Status contains the result of the macro.
1048     */
1049    MAYBE_SEMANTICS_PRED(spc_struct, event_param, status);
1050    if (status == 0)  /* MaybeSemantics is false */
1051    {
1052        n_state = RPC_C_CLIENT_CALL_RESPONSE;
1053    }
1054    else  /* MaybeSemantics is true */
1055    {
1056        n_state = RPC_C_CLIENT_CALL_CALL_COMPLETED;
1057    }
1058
1059    stub_data_p = (rpc_iovector_p_t) event_param;
1060
1061    /*
1062     * If there's stub data, we can process it just like a normal
1063     * call request.  This might leave data buffered.
1064     *
1065     * Note that the absence of stub data is indicated by either
1066     * a null iovector pointer or an iovector with 0 elements.
1067     */
1068    if ((stub_data_p != NULL) && (stub_data_p->num_elt > 0))
1069    {
1070        /*
1071	 * Note that since we are calling action routines from
1072	 * within action routines, we need to update state as
1073	 * a final step here.  Otherwise, the action routines
1074	 * would update sm->cur_state inappropriately for
1075	 * the calling routine.
1076	 */
1077        status =
1078		transmit_req_action_rtn (spc_struct, event_param, sm);
1079        if (status != rpc_s_ok)
1080        {
1081		sm_p->cur_state = n_state;
1082		return (status);
1083        }
1084    }
1085
1086    /*
1087     * Set the last frag flag bit in the cached protocol header
1088     * and send it along with any buffered data.
1089     */
1090    RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG;
1091    if (RPC_CN_CREP_ACC_BYTCNT (call_rep) >= RPC_CN_CREP_SIZEOF_HDR (call_rep))
1092    {
1093        rpc__cn_transmit_buffers (call_rep, &status);
1094        rpc__cn_dealloc_buffered_data (call_rep);
1095
1096        /*
1097         * Set the length of the iov to 1.  We don't use the general
1098         * FREE_ALL_EXCEPT_PROT_HEADER macro since we won't be
1099         * using the iov again.
1100         */
1101        RPC_CN_CREP_IOVLEN (call_rep) = 1;
1102        if (status != rpc_s_ok)
1103        {
1104		sm_p->cur_state = n_state;
1105		call_rep->assoc->assoc_status = status;
1106		return (status);
1107        }
1108    }
1109    else
1110    {
1111        /*
1112         * If the accumulated bytecount field is less than at
1113         * least that of the request header, something is really
1114         * off.
1115         */
1116        /*
1117         * rpc_m_invalid_accbytcnt
1118         * "(%s) Inconsistency in ACC_BYTCNT field"
1119         */
1120        rpc_dce_svc_printf (
1121            __FILE__, __LINE__,
1122            "%s",
1123            rpc_svc_cn_errors,
1124            svc_c_sev_fatal | svc_c_action_abort,
1125            rpc_m_invalid_accbytcnt,
1126            "send_last_frag_action_rtn" );
1127    }
1128
1129    sm_p->cur_state = n_state;
1130    return (rpc_s_ok);
1131
1132}
1133
1134
1135/*
1136**++
1137**
1138**  ROUTINE NAME:       handle_recv_frag_action_rtn
1139**
1140**  SCOPE:              INTERNAL
1141**
1142**  DESCRIPTION:
1143**
1144**  Action routine to make the (received) fragment data available
1145**  to the stub for unmarshalling.
1146**
1147**  INPUTS:
1148**
1149**      spc_struct      The call rep.  Note that this is passed in as
1150**                      the special structure which is passed to the
1151**                      state machine event evaluation routine.
1152**
1153**      event_param     The fragment buffer containing the response
1154**                      message.  This is passed in as the special
1155**                      event related parameter which was passed to
1156**                      the state machine event evaluation routine.
1157**
1158**  INPUTS/OUTPUTS:
1159**
1160**	sm              The control block from the event evaluation
1161**                      routine.  Input is the current state and
1162**                      event for the control block.  Output is the
1163**                      next state or updated current state, for the
1164**                      control block.
1165**
1166**  OUTPUTS:            none
1167**
1168**  IMPLICIT INPUTS:    none
1169**
1170**  IMPLICIT OUTPUTS:   none
1171**
1172**  FUNCTION VALUE:     rpc_s_ok
1173**
1174**  SIDE EFFECTS:       Either a fault or fault_dne event may be
1175**                      appended to the state machine event list.
1176**
1177**--
1178**/
1179INTERNAL unsigned32     handle_recv_frag_action_rtn
1180(
1181  dce_pointer_t       spc_struct,
1182  dce_pointer_t       event_param,
1183  dce_pointer_t       sm
1184)
1185{
1186    unsigned32              status ATTRIBUTE_UNUSED;
1187    rpc_cn_fragbuf_p_t      fragbuf;
1188    rpc_cn_packet_p_t       header_p;
1189    rpc_cn_call_rep_p_t     call_rep;
1190    rpc_cn_sm_ctlblk_t	    *sm_p;
1191    unsigned8		    n_state = 0;
1192
1193    RPC_CN_DBG_RTN_PRINTF(CLIENT handle_recv_frag_action_rtn);
1194
1195    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
1196    fragbuf = (rpc_cn_fragbuf_p_t) event_param;
1197    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
1198    header_p = (rpc_cn_packet_p_t) fragbuf->data_p;
1199
1200    /*
1201     * We've got a proper response.  Adjust data_size to describe
1202     * the stub data.
1203     * Note that we do not need to adjust data_p since that will
1204     * be done by rpc__cn_call_receive.
1205     */
1206    fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) -
1207                         RPC_CN_PKT_AUTH_TLR_LEN (header_p) -
1208                         RPC_CN_PKT_SIZEOF_RESP_HDR;
1209
1210    /*
1211     * Determine whether this is the last response fragment.
1212     */
1213    if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG)
1214    {
1215
1216        /*
1217         * The predicate associated with this routine,
1218	 * last_recv_frag_pred_rtn, checks the same
1219	 * flags checked above in the if statement.
1220	 * If RPC_CN_PKT_FLAGS & rpc_c_cn_flags_lastfrag
1221         * are 0, then set state to rpc_c_client_call
1222	 * response, else set state to rpc_c_client_call_
1223         * call_complete.
1224         */
1225        n_state = RPC_C_CLIENT_CALL_CALL_COMPLETED;
1226        /*
1227         * If there is a timer running stop it since we've heard from
1228         * the server.
1229         */
1230        rpc__cn_call_stop_cancel_timer (call_rep);
1231
1232        /*
1233         * Record whether the server finished with a pending alert. Note
1234         * that the alert count in the packet does not include the
1235         * alert forwarded by setting the PFC_PENDING_ALERT bit in the
1236         * first fragment of the request.
1237         */
1238        if ((call_rep->u.client.cancel.server_count > RPC_CN_PKT_ALERT_COUNT (header_p)) ||
1239            (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING))
1240        {
1241            /*
1242             * Either the number of alerts forwarded by us is
1243             * greater than the number of alerts posted to the call
1244             * executor thread on the server OR the there was still an alert
1245             * pending in the call executor thread when the server
1246             * stub returned. In either case set the
1247             * server_had_pending flag in the call_rep to indicate an
1248             * alert should be posted to the client caller thread
1249             * before returning to the client stub.
1250             */
1251            call_rep->u.client.cancel.server_had_pending = true;
1252#ifdef DEBUG
1253            if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING)
1254            {
1255                RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
1256                                ("(handle_recv_frag_action_rtn) call_rep->%p alert pending flag is set in header\n", call_rep));
1257            }
1258            else
1259            {
1260                RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
1261                ("(handle_recv_frag_action_rtn) call_rep->%p number alerts forwarded (%d) > alert count in header (%d)\n",
1262                 call_rep,
1263                 call_rep->u.client.cancel.server_count,
1264                 RPC_CN_PKT_ALERT_COUNT (header_p)));
1265            }
1266#endif
1267        }
1268    }
1269    else
1270    {
1271	n_state = RPC_C_CLIENT_CALL_RESPONSE;
1272    }
1273    /*
1274     * We are currently executing in the receiver thread.
1275     *
1276     * If there is stub data, queue it on the association so that
1277     * the client call thread can get it.
1278     * If there is no stub data (e.g., no out arguments), just
1279     * deallocate the fragment buffer.
1280     * We make an exception for the first fragment; it is always
1281     * queued since the client call thread may already be blocked
1282     * on the condition variable.
1283     */
1284    if (fragbuf->data_size ||
1285        (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_FIRST_FRAG))
1286    {
1287        rpc__cn_assoc_queue_frag (call_rep->assoc, fragbuf, true);
1288    }
1289    else
1290    {
1291        (* fragbuf->fragbuf_dealloc) (fragbuf);
1292    }
1293
1294    /*
1295     * Increment num_pkts in the call rep. This will be used in
1296     * determining when to check for pending cancels.
1297     */
1298    call_rep->num_pkts++;
1299
1300    sm_p->cur_state = n_state;
1301    return (rpc_s_ok);
1302}
1303
1304
1305/*
1306**++
1307**
1308**  ROUTINE NAME:       raise_fault_action_rtn
1309**
1310**  SCOPE:              INTERNAL
1311**
1312**  DESCRIPTION:
1313**
1314**  Action routine to deallocate the current association and raise
1315**  fault.  Operationally, this will store the address of the
1316**  fragment buffer in the callrep (for later retrieval via the
1317**  rpc__receive_fault).
1318**
1319**  INPUTS:
1320**
1321**      spc_struct      The call rep.  Note that this is passed in as
1322**                      the special structure which is passed to the
1323**                      state machine event evaluation routine.
1324**
1325**      event_param     The fault packet.  This is passed in as the
1326**                      event specific structure.
1327**
1328**  INPUTS/OUTPUTS:
1329**
1330**	sm              The control block from the event evaluation
1331**                      routine.  Input is the current state and
1332**                      event for the control block.  Output is the
1333**                      next state or updated current state, for the
1334**                      control block.
1335**
1336**  OUTPUTS:            none
1337**
1338**  IMPLICIT INPUTS:    none
1339**
1340**  IMPLICIT OUTPUTS:   none
1341**
1342**  FUNCTION VALUE:     rpc_s_call_faulted
1343**
1344**  SIDE EFFECTS:       none
1345**
1346**--
1347**/
1348INTERNAL unsigned32     raise_fault_action_rtn
1349(
1350  dce_pointer_t       spc_struct,
1351  dce_pointer_t       event_param,
1352  dce_pointer_t       sm
1353)
1354{
1355    unsigned32              status ATTRIBUTE_UNUSED;
1356    rpc_cn_fragbuf_p_t      fragbuf;
1357    rpc_cn_packet_p_t       header_p;
1358    rpc_cn_call_rep_p_t     call_rep;
1359    rpc_cn_sm_ctlblk_t	    *sm_p;
1360
1361    RPC_CN_DBG_RTN_PRINTF(CLIENT raise_fault_action_rtn);
1362
1363    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
1364    fragbuf = (rpc_cn_fragbuf_p_t) event_param;
1365    header_p = (rpc_cn_packet_p_t) fragbuf->data_p;
1366    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
1367
1368    /*
1369     * We've got a proper response.  Adjust data_size to describe
1370     * the stub data.
1371     * Note that we do not need to adjust data_p since that will
1372     * be done by rpc__cn_call_receive.
1373     */
1374    fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) -
1375                         RPC_CN_PKT_AUTH_TLR_LEN (header_p) -
1376                         RPC_CN_PKT_SIZEOF_FAULT_HDR;
1377
1378    /*
1379     * If there is a timer running stop it since we've heard from
1380     * the server.
1381     */
1382    rpc__cn_call_stop_cancel_timer (call_rep);
1383
1384    /*
1385     * Determine whether this is the last fault fragment.
1386     */
1387    if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG)
1388    {
1389        /*
1390         * Record whether the server finished with a pending alert. Note
1391         * that the alert count in the packet does not include the
1392         * alert forwarded by setting the PFC_PENDING_ALERT bit in the
1393         * first fragment of the request.
1394         */
1395        if ((call_rep->u.client.cancel.server_count > RPC_CN_PKT_ALERT_COUNT (header_p)) ||
1396            (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING))
1397        {
1398            /*
1399             * Either the number of alerts forwarded by us is
1400             * greater than the number of alerts posted to the call
1401             * executor thread on the server OR the there was still an alert
1402             * pending in the call executor thread when the server
1403             * stub returned. In either case set the
1404             * server_had_pending flag in the call_rep to indicate an
1405             * alert should be posted to the client caller thread
1406             * before returning to the client stub.
1407             */
1408            call_rep->u.client.cancel.server_had_pending = true;
1409#ifdef DEBUG
1410            if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING)
1411            {
1412                RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
1413                               ("(raise_fault_action_rtn) call_rep->%p alert pending flag is set in header\n", call_rep));
1414            }
1415            else
1416            {
1417                RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
1418                               ("(raise_fault_action_rtn) call_rep->%p number alerts forwarded (%d) > alert count in header (%d)\n",
1419                                call_rep,
1420                                call_rep->u.client.cancel.server_count,
1421                                RPC_CN_PKT_ALERT_COUNT (header_p)));
1422            }
1423#endif
1424        }
1425    }
1426
1427    /*
1428     * We are currently executing in the receiver thread.
1429     *
1430     * If there is stub data, queue it on the association so that
1431     * the client call thread can get it.
1432     * If there is no stub data (e.g., no out arguments), just
1433     * deallocate the fragment buffer.
1434     * We make an exception for the first fragment; it is always
1435     * queued since the client call thread may already be blocked
1436     * on the condition variable.
1437     */
1438    if (fragbuf->data_size ||
1439        (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_FIRST_FRAG))
1440    {
1441        rpc__cn_assoc_queue_frag (call_rep->assoc, fragbuf, true);
1442    }
1443    else
1444    {
1445        (* fragbuf->fragbuf_dealloc) (fragbuf);
1446    }
1447
1448    /*
1449     * There is no predicate associated with this routine but the
1450     * new value of sm->cur_state is determined by the value of
1451     * sm->cur_event coming into the routine.  Note that
1452     * 2+statebase is event fault_dns;  3+statebase is event
1453     * fault.
1454     */
1455    if (sm_p->cur_event == (2 + RPC_C_CN_STATEBASE ))
1456	sm_p->cur_state =  RPC_C_CLIENT_CALL_CFDNE;
1457    else if (sm_p->cur_event == (3 + RPC_C_CN_STATEBASE ))
1458	sm_p->cur_state = RPC_C_CLIENT_CALL_CALL_FAILED;
1459    return (rpc_s_ok);
1460}
1461
1462
1463/*
1464**++
1465**
1466**  ROUTINE NAME:       forward_alert_action_rtn
1467**
1468**  SCOPE:              INTERNAL
1469**
1470**  DESCRIPTION:
1471**
1472**  Action routine to forward an alert. The first alert that is
1473**  forwarded will start the alert timer. This timer will run until
1474**  either the call is completed or a reponse is received from the
1475**  server. If the timer expires the call is orphaned. The alert
1476**  timer setting, clearing and expiration handling is all done outside
1477**  the state machine action routines, primarily in the
1478**  rpc__cn_call_forward_cancel, rpc__cn_call_[start,stop]_cancel_timer
1479**  and rpc__cn_call_cancel_timer. All cancellable operations made in
1480**  the CN runtime are encompassed in cancel exception handlers.
1481**
1482**  INPUTS:
1483**
1484**      spc_struct      The call rep.  Note that this is passed in as
1485**                      the special structure which is passed to the
1486**                      state machine event evaluation routine.
1487**
1488**      event_param     The error_status to return. This is passed in
1489**                      as the special event related parameter which
1490**                      was passed to the state machine event
1491**                      evaluation routine.
1492**
1493**  INPUTS/OUTPUTS:
1494**
1495**	sm              The control block from the event evaluation
1496**                      routine.  Input is the current state and
1497**                      event for the control block.  Output is the
1498**                      next state or updated current state, for the
1499**                      control block.
1500**
1501**  OUTPUTS:            none
1502**
1503**  IMPLICIT INPUTS:    none
1504**
1505**  IMPLICIT OUTPUTS:   none
1506**
1507**  FUNCTION VALUE:     rpc_s_call_faulted
1508**
1509**  SIDE EFFECTS:       none
1510**
1511**--
1512**/
1513INTERNAL unsigned32     forward_alert_action_rtn
1514(
1515  dce_pointer_t       spc_struct,
1516  dce_pointer_t       event_param ATTRIBUTE_UNUSED,
1517  dce_pointer_t       sm
1518)
1519{
1520    rpc_cn_call_rep_p_t         call_rep;
1521    rpc_cn_packet_p_t           header_p;
1522    struct
1523    {
1524        rpc_iovector_t          iov;
1525        rpc_iovector_elt_t      elt_1;
1526    } pdu;
1527    unsigned32                  status;
1528    unsigned8                   prev_ptype;
1529    rpc_cn_sm_ctlblk_t		*sm_p;
1530
1531    RPC_CN_DBG_RTN_PRINTF(CLIENT forward_alert_action_rtn);
1532
1533    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
1534    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
1535    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep);
1536
1537    /*
1538     * The remote alert indication packet uses only the
1539     * common fields of the header.  We can therefore just
1540     * use the current header.
1541     */
1542    prev_ptype = RPC_CN_PKT_PTYPE (header_p);
1543    RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_REMOTE_ALERT;
1544    RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_ALERT_PENDING;
1545
1546    /*
1547     * If security was requested on this call an authentication
1548     * trailer will have to be added to the alert PDU.
1549     */
1550    if (call_rep->sec == NULL)
1551    {
1552        RPC_CN_PKT_FRAG_LEN (header_p) = RPC_CN_PKT_SIZEOF_ALERT_HDR;
1553        pdu.iov.num_elt = 1;
1554    }
1555    else
1556    {
1557        RPC_CN_PKT_FRAG_LEN (header_p) =
1558            RPC_CN_PKT_SIZEOF_ALERT_HDR +
1559            call_rep->prot_tlr->data_size -
1560            RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep);
1561        pdu.iov.num_elt = 2;
1562        pdu.elt_1.buff_dealloc = NULL;
1563        pdu.elt_1.data_addr = (byte_p_t) call_rep->prot_tlr->data_p;
1564        pdu.elt_1.data_len =
1565            call_rep->prot_tlr->data_size -
1566            RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep);
1567    }
1568
1569    /*
1570     * Send the packet over.
1571     */
1572    pdu.iov.elt[0].buff_dealloc = NULL;
1573    pdu.iov.elt[0].data_addr = (byte_p_t) header_p;
1574    pdu.iov.elt[0].data_len = RPC_CN_PKT_SIZEOF_ALERT_HDR;
1575    rpc__cn_assoc_send_frag (call_rep->assoc, &pdu.iov, call_rep->sec, &status);
1576
1577    /*
1578     * Restore the previous packet type.
1579     */
1580    RPC_CN_PKT_PTYPE (header_p) = prev_ptype;
1581
1582    /*
1583     * Increment the count of forwarded cancels.
1584     */
1585    call_rep->u.client.cancel.server_count++;
1586    RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
1587                ("(forward_alert_action_rtn) call_rep->%p forwarding cancel total so far = %d\n",
1588                 call_rep,
1589                 call_rep->u.client.cancel.server_count));
1590
1591    /*
1592     * There is no predicate associated with this routine but the
1593     * new value of sm->cur_state is determined by the value of
1594     * sm->cur_state  coming into the routine.  In otherwords,
1595     * this action routine is called from 2 different states
1596     * and the value of that state determines the new value
1597     * for sm->cur_state.  Note that 3+statebase is call_request;
1598     * 4+statebase is call_response.  rpc_c_cn_statebase is
1599     * set to 100 to distinguish it from action routine
1600     * indexes used in the rpc__cn_sm_event_eval() routine.
1601     */
1602    if (sm_p->cur_state == (3 + RPC_C_CN_STATEBASE))
1603	sm_p->cur_state = RPC_C_CLIENT_CALL_REQUEST;
1604    else if (sm_p->cur_state == (4 + RPC_C_CN_STATEBASE))
1605	sm_p->cur_state = RPC_C_CLIENT_CALL_RESPONSE;
1606    return (status);
1607}
1608
1609
1610/*
1611**++
1612**
1613**  ROUTINE NAME:       abort_send_action_rtn
1614**
1615**  SCOPE:              INTERNAL
1616**
1617**  DESCRIPTION:
1618**
1619**  Action routine to abort a send.
1620**  It sends an orphaned message, and then raises a fault by
1621**  returning the error status back to the caller.
1622**
1623**  INPUTS:
1624**
1625**      spc_struct      The call rep.  Note that this is passed in as
1626**                      the special structure which is passed to the
1627**                      state machine event evaluation routine.
1628**
1629**      event_param     This parameter is ignored.  It is passed in
1630**                      as the special event related parameter which
1631**                      was passed to the state machine event
1632**                      evaluation routine.
1633**
1634**  INPUTS/OUTPUTS:
1635**
1636**	sm              The control block from the event evaluation
1637**                      routine.  Input is the current state and
1638**                      event for the control block.  Output is the
1639**                      next state or updated current state, for the
1640**                      control block.
1641**
1642**  OUTPUTS:            rpc_s_call_faulted
1643**
1644**  IMPLICIT INPUTS:    none
1645**
1646**  IMPLICIT OUTPUTS:   none
1647**
1648**  FUNCTION VALUE:     error_status reflecting the fault
1649**
1650**  SIDE EFFECTS:       none
1651**
1652**--
1653**/
1654INTERNAL unsigned32     abort_send_action_rtn
1655(
1656  dce_pointer_t       spc_struct,
1657  dce_pointer_t       event_param ATTRIBUTE_UNUSED,
1658  dce_pointer_t       sm
1659)
1660{
1661    rpc_cn_call_rep_p_t         call_rep;
1662    rpc_cn_packet_p_t           header_p;
1663    unsigned32                  status;
1664    rpc_cn_sm_ctlblk_t		*sm_p;
1665
1666    RPC_CN_DBG_RTN_PRINTF(CLIENT abort_send_action_rtn);
1667
1668    call_rep = (rpc_cn_call_rep_p_t) spc_struct;
1669    sm_p = (rpc_cn_sm_ctlblk_t *)sm;
1670
1671    /*
1672     * The call is going to be orphaned. The stub data bufferred
1673     * on the call rep will not be sent and can be released.
1674     */
1675    rpc__cn_dealloc_buffered_data (call_rep);
1676    RPC_CN_FREE_ALL_EXCEPT_PROT_HDR (call_rep);
1677
1678    /*
1679     * Now prepare to send an orphaned packet to the server.
1680     */
1681    header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(call_rep);
1682    RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_ORPHANED;
1683    RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG;
1684    RPC_DBG_PRINTF (rpc_e_dbg_orphan, RPC_C_CN_DBG_ORPHAN,
1685                    ("(abort_send_action_rtn) call_rep->%p sending orphan packet ... call id = %x\n",
1686                     call_rep,
1687                     RPC_CN_PKT_CALL_ID (header_p)));
1688
1689    /*
1690     * If security was requested on this call an authentication
1691     * trailer will have to be added to the orphan PDU.
1692     */
1693    if (call_rep->sec == NULL)
1694    {
1695        RPC_CN_PKT_FRAG_LEN (header_p) = RPC_CN_PKT_SIZEOF_ORPHANED_HDR;
1696        RPC_CN_CREP_IOVLEN (call_rep) = 1;
1697    }
1698    else
1699    {
1700        RPC_CN_PKT_FRAG_LEN (header_p) =
1701            RPC_CN_PKT_SIZEOF_ORPHANED_HDR +
1702            call_rep->prot_tlr->data_size -
1703            RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep);
1704        RPC_CN_CREP_IOVLEN (call_rep) = 2;
1705        RPC_CN_CREP_IOV (call_rep)[1].data_addr = (byte_p_t) call_rep->prot_tlr->data_p;
1706        RPC_CN_CREP_IOV (call_rep)[1].data_len =
1707            call_rep->prot_tlr->data_size -
1708            RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep);
1709        RPC_CN_CREP_IOV (call_rep)[1].buff_dealloc = NULL;
1710    }
1711
1712    /*
1713     * Send the packet over.  Note that the returned status is
1714     * ignored.
1715     */
1716    RPC_CN_CREP_IOV (call_rep)[0].data_addr = (byte_p_t) header_p;
1717    RPC_CN_CREP_IOV (call_rep)[0].data_len = RPC_CN_PKT_SIZEOF_ORPHANED_HDR;
1718    rpc__cn_assoc_send_frag (call_rep->assoc,
1719                             &(call_rep->buffered_output.iov),
1720                             call_rep->sec,
1721                             &status);
1722    /*
1723     * Now return to the caller (presumably rpc__cn_call_end) which
1724     * will deallocate the association on our end and clean up.
1725     */
1726    sm_p->cur_state = RPC_C_CLIENT_CALL_CALL_FAILED;
1727    return (rpc_s_ok);
1728}
1729
1730/*
1731**++
1732**
1733**  ROUTINE NAME:       abort_recv_action_rtn
1734**
1735**  SCOPE:              INTERNAL
1736**
1737**  DESCRIPTION:
1738**
1739**  Action routine to abort a receive.
1740**
1741**  INPUTS:
1742**
1743**      spc_struct      The call rep.  Note that this is passed in as
1744**                      the special structure which is passed to the
1745**                      state machine event evaluation routine.
1746**
1747**      event_param     The fault data.
1748**                      This is passed in as the special event related
1749**                      parameter which was passed to the state machine
1750**                      event evaluation routine.
1751**
1752**  INPUTS/OUTPUTS:
1753**
1754**	sm              The control block from the event evaluation
1755**                      routine.  Input is the current state and
1756**                      event for the control block.  Output is the
1757**                      next state or updated current state, for the
1758**                      control block.
1759**
1760**  OUTPUTS:            none
1761**
1762**  IMPLICIT INPUTS:    none
1763**
1764**  IMPLICIT OUTPUTS:   none
1765**
1766**  FUNCTION VALUE:     completion status
1767**                          rpc_s_call_faulted
1768**
1769**  SIDE EFFECTS:       none
1770**
1771**--
1772**/
1773INTERNAL unsigned32     abort_recv_action_rtn
1774(
1775  dce_pointer_t       spc_struct,
1776  dce_pointer_t       event_param,
1777  dce_pointer_t       sm
1778)
1779{
1780    unsigned32      status;
1781
1782    RPC_CN_DBG_RTN_PRINTF(CLIENT abort_recv_action_rtn);
1783    /*
1784     * Note that we are getting state from raise_fault_action_rtn().  Also
1785     * note that it does not seem that we are actually using abort_recv_
1786     * action_rtn in the state tables.
1787     *
1788     * Note, we don't need to chase down our receiver thread.
1789     * We will shortly deallocate the association.  The receiver
1790     * thread will automatically discard fragments for non-existent
1791     * associations.
1792     *
1793     * We make this a separate action routine (instead of using
1794     * raise_fault_action_rtn) to leave room for future optimizations.
1795     */
1796
1797    /*
1798     * Abort the association.
1799     */
1800    rpc__cn_assoc_abort (((rpc_cn_call_rep_p_t) spc_struct)->assoc, &status);
1801
1802    /*
1803     * Raise the fault.
1804     */
1805    return (raise_fault_action_rtn (spc_struct, event_param, sm ));
1806}
1807