/* * Copyright (c) 2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software have been released under the following terms: * * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION * * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this file for any * purpose is hereby granted without fee, provided that the above * copyright notices and this notice appears in all source code copies, * and that none of the names of Open Software Foundation, Inc., Hewlett- * Packard Company or Digital Equipment Corporation be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. Neither Open Software * Foundation, Inc., Hewlett-Packard Company nor Digital * Equipment Corporation makes any representations about the suitability * of this software for any purpose. * * Copyright (c) 2007, Novell, Inc. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Novell Inc. nor the names of its contributors * may be used to endorse or promote products derived from this * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @APPLE_LICENSE_HEADER_END@ */ /* ** ** NAME ** ** cncclsm.c ** ** FACILITY: ** ** Remote Procedure Call (RPC) ** ** ABSTRACT: ** ** Client call State Machine for the Connection-based RPC runtime. ** ** */ #include <commonp.h> /* Common declarations for all RPC runtime */ #include <com.h> /* Common communications services */ #include <comprot.h> /* Common protocol services */ #include <cnp.h> /* NCA Connection private declarations */ #include <cnfbuf.h> /* NCA Connection fragment buffer declarations */ #include <cnpkt.h> /* NCA Connection protocol header */ #include <cnassoc.h> /* NCA Connection association services */ #include <cnxfer.h> /* NCA Connection buffered data transfer routines */ #include <cnsm.h> /* NCA Connection state machine declarations */ #include <cncall.h> /* NCA connection call service */ #include <cnclsm.h> /******************************************************************************/ /* * Global Definitions */ #ifdef DEBUG GLOBAL const char *rpc_g_cn_call_client_events [] = { "TRANSMIT_REQ ", "CONFIRM ", "FAULT_DNE ", "FAULT ", "LOCAL_ALERT ", "END ", "ASSOC_ALLOC_ACK ", "ASSOC_ALLOC_NAK ", "START ", "LAST_TRANSMIT_REQ", "LOCAL_ERROR ", "ALERT_TIMEOUT " }; GLOBAL const char *rpc_g_cn_call_client_states [] = { "INIT ", "ASSOC_ALLOC_WAIT ", "STUB_WAIT ", "REQUEST ", "RESPONSE ", "CALL_COMPLETED ", "CALL_FAILED_DNE ", "CALL_FAILED " }; PRIVATE void rpc__cn_call_sm_trace ( rpc_cn_call_rep_t *crep, unsigned32 event_id, unsigned32 id, const char *file ATTRIBUTE_UNUSED, const char *funcname ATTRIBUTE_UNUSED, int lineno ATTRIBUTE_UNUSED ) { if (RPC_CALL_IS_CLIENT(&crep->common)) { RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE, ("(%s) STATE CLIENT CALL: %d state->%s event->%s\n", funcname, id, RPC_CN_CALL_CLIENT_STATE((crep)->call_state.cur_state), RPC_CN_CALL_CLIENT_EVENT(event_id))); } else { RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE, ("(%s) STATE SERVER CALL: %d state->%s event->%s\n", funcname, id, RPC_CN_CALL_SERVER_STATE((crep)->call_state.cur_state), RPC_CN_CALL_SERVER_EVENT(event_id))); } } PRIVATE void rpc__cn_call_sm_trace_state ( rpc_cn_call_rep_t *crep, unsigned32 id, const char *file ATTRIBUTE_UNUSED, const char *funcname ATTRIBUTE_UNUSED, int lineno ATTRIBUTE_UNUSED ) { if (RPC_CALL_IS_CLIENT(&crep->common)) { RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE, ("(%s) STATE CLIENT CALL: %d new state->%s\n", funcname, id, RPC_CN_CALL_CLIENT_STATE(crep->call_state.cur_state))); } else { RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE, ("(%s) STATE SERVER CALL: %d new state->%s\n", funcname, id, RPC_CN_CALL_SERVER_STATE(crep->call_state.cur_state))); } } #endif /* DEBUG */ /***********************************************************************/ /* ** C L I E N T C A L L P R E D I C A T E T A B L E **/ /* * The predicates. * As a performance enhancement, * we have revamped many predicate routines as macros and have absorbed * the predicates into the actions. Thus, there is no longer a need * for the predicate table; the predicate declarations too, are * modified. */ /* #define MAYBE_SEMANTICS_PRED 0 #define LAST_RECV_FRAG_PRED 1 */ /* * The predicate routine prototypes. */ INTERNAL unsigned8 maybe_semantics_pred_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/ ) ATTRIBUTE_UNUSED; INTERNAL unsigned8 last_recv_frag_pred_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/ ) ATTRIBUTE_UNUSED; /***********************************************************************/ /* ** C L I E N T C A L L A C T I O N T A B L E **/ /***********************************************************************/ /* * The actions. * * The QueueAlertTimeout action routine in the NCA CN arch spec * is not listed here since cancel timeouts are handled outside the * state machine. See the routine header of forward_alert_action_rtn * for more details. * * The VerifySecurity action routine in the NCA CN arch spec is not * listed here since this was embedded into existing action routines, * where appropriate in this implementation. */ #define TRANSMIT_REQ 0 #define HANDLE_RECV_FRAG 1 #define RAISE_FAULT 2 #define FORWARD_ALERT 3 #define ALLOCATE_ASSOC 4 /* abort send = send_orphaned + deallocate assoc + raise fault */ #define ABORT_SEND 5 #define ABORT_RECV 6 #define SEND_LAST_FRAG 7 #define PROTOCOL_ERROR 8 /* * The Action routine prototypes. */ INTERNAL unsigned32 transmit_req_action_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/, dce_pointer_t /*sm*/ ); INTERNAL unsigned32 handle_recv_frag_action_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/, dce_pointer_t /*sm*/ ); INTERNAL unsigned32 raise_fault_action_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/, dce_pointer_t /*sm*/ ); INTERNAL unsigned32 forward_alert_action_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/, dce_pointer_t /*sm*/ ); INTERNAL unsigned32 allocate_assoc_action_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/, dce_pointer_t /*sm*/ ); INTERNAL unsigned32 abort_send_action_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/, dce_pointer_t /*sm*/ ); INTERNAL unsigned32 abort_recv_action_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/, dce_pointer_t /*sm*/ ); INTERNAL unsigned32 send_last_frag_action_rtn ( dce_pointer_t /*spc_struct*/, dce_pointer_t /*event_param*/, dce_pointer_t /*sm*/ ); /* * The action table itself. */ GLOBAL rpc_cn_sm_action_fn_t rpc_g_cn_client_call_action_tbl [] = { transmit_req_action_rtn, handle_recv_frag_action_rtn, raise_fault_action_rtn, forward_alert_action_rtn, allocate_assoc_action_rtn, abort_send_action_rtn, abort_recv_action_rtn, send_last_frag_action_rtn, rpc__cn_call_sm_protocol_error }; /***********************************************************************/ /* ** C L I E N T C A L L S T A T E T A B L E **/ INTERNAL rpc_cn_sm_state_tbl_entry_t init_state = /* state 0 - init */ { ILLEGAL_TRANSITION, /* event 0 */ ILLEGAL_TRANSITION, /* event 1 */ ILLEGAL_TRANSITION, /* event 2 */ ILLEGAL_TRANSITION, /* event 3 */ ILLEGAL_TRANSITION, /* event 4 */ {RPC_C_CLIENT_CALL_CFDNE}, /* event 5 - call_end */ ILLEGAL_TRANSITION, /* event 6 */ ILLEGAL_TRANSITION, /* event 7 */ {ALLOCATE_ASSOC}, /* event 8 - start_call */ ILLEGAL_TRANSITION, /* event 9 */ ILLEGAL_TRANSITION, /* event 10 */ ILLEGAL_TRANSITION /* event 11 */ }; /* state 1 - assoc_alloc_wait */ INTERNAL rpc_cn_sm_state_tbl_entry_t assoc_alloc_wait_state = { ILLEGAL_TRANSITION, /* event 0 */ ILLEGAL_TRANSITION, /* event 1 */ ILLEGAL_TRANSITION, /* event 2 */ ILLEGAL_TRANSITION, /* event 3 */ ILLEGAL_TRANSITION, /* event 4 */ {RPC_C_CLIENT_CALL_CFDNE}, /* event 5 - call_end */ {RPC_C_CLIENT_CALL_STUB_WAIT}, /* event 6 - alloc_assoc_ack */ {RPC_C_CLIENT_CALL_CFDNE}, /* event 7 - alloc_assoc_nak */ ILLEGAL_TRANSITION, /* event 8 */ ILLEGAL_TRANSITION, /* event 9 */ ILLEGAL_TRANSITION, /* event 10 */ ILLEGAL_TRANSITION /* event 11 */ }; /* state 2 - stub_wait */ INTERNAL rpc_cn_sm_state_tbl_entry_t stub_wait_state = { {TRANSMIT_REQ}, /* event 0 - transmit_req */ ILLEGAL_TRANSITION, /* event 1 */ ILLEGAL_TRANSITION, /* event 2 */ ILLEGAL_TRANSITION, /* event 3 */ ILLEGAL_TRANSITION, /* event 4 */ {RPC_C_CLIENT_CALL_CFDNE}, /* event 5 - call_end */ ILLEGAL_TRANSITION, /* event 6 */ ILLEGAL_TRANSITION, /* event 7 */ ILLEGAL_TRANSITION, /* event 8 */ {SEND_LAST_FRAG}, /* event 9 - last_transmit_req */ {RPC_C_CLIENT_CALL_CFDNE}, /* event 10 - local_err */ ILLEGAL_TRANSITION, /* event 10 */ ILLEGAL_TRANSITION /* event 11 */ }; /* state 3 - call_request */ INTERNAL rpc_cn_sm_state_tbl_entry_t call_request_state = { {TRANSMIT_REQ}, /* event 0 - transmit_req */ ILLEGAL_TRANSITION, /* event 1 */ {RAISE_FAULT}, /* event 2 - fault_dne */ {RAISE_FAULT}, /* event 3 - fault */ {FORWARD_ALERT}, /* event 4 - local alert */ {ABORT_SEND}, /* event 5 - call_end */ ILLEGAL_TRANSITION, /* event 6 */ ILLEGAL_TRANSITION, /* event 7 */ ILLEGAL_TRANSITION, /* event 8 */ {SEND_LAST_FRAG}, /* event 9 - last_transmit_req */ {ABORT_SEND}, /* event 10 - local_err */ {ABORT_SEND} /* event 11 - alert timeout */ }; /* state 4 - call response */ INTERNAL rpc_cn_sm_state_tbl_entry_t call_response_state = { ILLEGAL_TRANSITION, /* event 0 */ {HANDLE_RECV_FRAG}, /* event 1 - rpc_conf */ {RAISE_FAULT}, /* event 2 - fault_dne */ {RAISE_FAULT}, /* event 3 - fault */ {FORWARD_ALERT}, /* event 4 - local alert */ {ABORT_SEND}, /* event 5 - call_end */ ILLEGAL_TRANSITION, /* event 6 */ ILLEGAL_TRANSITION, /* event 7 */ ILLEGAL_TRANSITION, /* event 8 */ ILLEGAL_TRANSITION, /* event 9 */ {ABORT_SEND}, /* event 10 - local_err */ {ABORT_SEND} /* event 11 - alert timeout */ }; /* state 5 - call_completed */ INTERNAL rpc_cn_sm_state_tbl_entry_t call_completed_state = { ILLEGAL_TRANSITION, /* event 0 */ ILLEGAL_TRANSITION, /* event 1 */ ILLEGAL_TRANSITION, /* event 2 */ ILLEGAL_TRANSITION, /* event 3 */ {RPC_C_CLIENT_CALL_CALL_COMPLETED}, /* event 4 - local alert */ {RPC_C_CLIENT_CALL_CALL_COMPLETED}, /* event 5 - call_end */ ILLEGAL_TRANSITION, /* event 6 */ ILLEGAL_TRANSITION, /* event 7 */ ILLEGAL_TRANSITION, /* event 8 */ ILLEGAL_TRANSITION, /* event 9 */ ILLEGAL_TRANSITION, /* event 10 */ ILLEGAL_TRANSITION /* event 11 */ }; /* state 6 - cfdne (call failed, did not execute) */ INTERNAL rpc_cn_sm_state_tbl_entry_t cfdne_state = { {RPC_C_CLIENT_CALL_CFDNE}, /* event 0 */ ILLEGAL_TRANSITION, /* event 1 */ ILLEGAL_TRANSITION, /* event 2 */ ILLEGAL_TRANSITION, /* event 3 */ {RPC_C_CLIENT_CALL_CFDNE}, /* event 4 - local alert */ {RPC_C_CLIENT_CALL_CFDNE}, /* event 5 - call_end */ ILLEGAL_TRANSITION, /* event 6 */ ILLEGAL_TRANSITION, /* event 7 */ ILLEGAL_TRANSITION, /* event 8 */ {RPC_C_CLIENT_CALL_CFDNE}, /* event 9 */ ILLEGAL_TRANSITION, /* event 10 */ ILLEGAL_TRANSITION /* event 11 */ }; /* state 7 - call_failed */ INTERNAL rpc_cn_sm_state_tbl_entry_t call_failed_state = { {RPC_C_CLIENT_CALL_CALL_FAILED}, /* event 0 */ ILLEGAL_TRANSITION, /* event 1 */ ILLEGAL_TRANSITION, /* event 2 */ ILLEGAL_TRANSITION, /* event 3 */ {RPC_C_CLIENT_CALL_CALL_FAILED}, /* event 4 - local alert */ {RPC_C_CLIENT_CALL_CALL_FAILED}, /* event 5 - call_end */ ILLEGAL_TRANSITION, /* event 6 */ ILLEGAL_TRANSITION, /* event 7 */ ILLEGAL_TRANSITION, /* event 8 */ {RPC_C_CLIENT_CALL_CALL_FAILED}, /* event 9 */ ILLEGAL_TRANSITION, /* event 10 */ ILLEGAL_TRANSITION /* event 11 */ }; GLOBAL rpc_cn_sm_state_entry_p_t rpc_g_cn_client_call_sm [] = { init_state, /* state 0 - init */ assoc_alloc_wait_state, /* state 1 - assoc_alloc_wait */ stub_wait_state, /* state 2 - stub_wait */ call_request_state, /* state 3 - call_request */ call_response_state, /* state 4 - call_response */ call_completed_state, /* state 5 - call_completed */ cfdne_state, /* state 6 - call failed, dne */ call_failed_state /* state 7 - call_failed */ }; /***********************************************************************/ /* ** ** 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 ** **/ /***********************************************************************/ /* **++ ** ** ROUTINE NAME: maybe_semantics_pred_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Predicate routine invoked from the Call Active State. ** ** INPUTS: ** ** spc_struct The call rep. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param The special event related parameter which is ** passed to the state machine event evaluation ** routine. ** This input argument is ignored. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: 0 if MaybeSemantics is false ** 1 if MaybeSemantics is true ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned8 maybe_semantics_pred_rtn ( dce_pointer_t spc_struct, dce_pointer_t event_param ATTRIBUTE_UNUSED ) { rpc_cn_packet_p_t header_p; RPC_CN_DBG_RTN_PRINTF(CLIENT maybe_semantics_pred_rtn); /* * check the protocol header (cached in the callrep) to see if * PFC_MAYBE is set. */ header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR ( (rpc_cn_call_rep_p_t) spc_struct); if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE) == 0) { return (0); } else { return (1); } } /* **++ ** ** MACRO NAME: MAYBE_SEMANTICS_PRED ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** This is a macro version of maybe_semantics_pred_rtn, introduced for ** performance reasons. The macro lets us avoid overhead associated with ** calling the predicate routine from within the action routine. ** Predicate macro is invoked from the Call Active State. ** ** INPUTS: ** ** spc_struct The association group. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param The special event related parameter which is ** passed to the state machine event evaluation ** routine. ** This input argument is ignored. ** ** status Instead of returning a value from the macro, ** write the value calculated in the macro to ** status. Status' scope includes the routine ** calling the macro. Check status in the calling ** routine to determine next state and in cases, ** flow through the action routine. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status See explanation above. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: 0 if MaybeSemantics is false ** 1 if MaybeSemantics is true ** ** SIDE EFFECTS: none ** **-- **/ #define MAYBE_SEMANTICS_PRED(spc_struct, event_param, status) \ {\ RPC_CN_DBG_RTN_PRINTF(CLIENT maybe_semantics_pred_macro);\ header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(\ (rpc_cn_call_rep_p_t) spc_struct);\ if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE) == 0)\ {\ status = 0;\ }\ else\ {\ status = 1;\ }\ } /* **++ ** ** ROUTINE NAME: last_recv_frag_pred_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Predicate routine invoked from the Call Response state when an ** RPCConf event occurs. ** ** INPUTS: ** ** spc_struct The callrep. This is passed as the ** special structure which is passed to the ** state machine event evaluation routine. ** This argument is ignored. ** ** event_param The received packet contained in a fragment ** buffer. This is passed in as the special ** event related parameter by the state machine ** event evaluation routine. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: 0 if LastRecvFrag is false ** 1 if LastRecvFrag is true ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned8 last_recv_frag_pred_rtn ( dce_pointer_t spc_struct ATTRIBUTE_UNUSED, dce_pointer_t event_param ) { rpc_cn_fragbuf_p_t fragbuf; rpc_cn_packet_p_t header_p; RPC_CN_DBG_RTN_PRINTF(CLIENT last_recv_frag_pred_rtn); fragbuf = (rpc_cn_fragbuf_p_t) event_param; /* * The [unpacked] packet header starts off in the header_overhead * area. */ header_p = (rpc_cn_packet_p_t) fragbuf->data_p; if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) == 0) { return (0); } else { return (1); } } /***********************************************************************/ /* * C L I E N T C A L L A C T I O N R O U T I N E S */ /***********************************************************************/ /* **++ ** ** ROUTINE NAME: allocate_assoc_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Action routine to allocate an association from the current ** association group. ** ** INPUTS: ** ** spc_struct The call rep. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param The if_spec_rep. This is passed in as the ** special event related parameter which was ** passed to the state machine evaluation routine. ** ** INPUTS/OUTPUTS: ** ** sm The control block from the event evaluation ** routine. Input is the current state and ** event for the control block. Output is the ** next state or updated current state, for the ** control block. ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: completion status, one of: ** rpc_s_ok, ** ** SIDE EFFECTS: Either alloc_assoc_ack or alloc_assoc_nak ** event would be appended to the state ** machine event evaluation list. ** **-- **/ INTERNAL unsigned32 allocate_assoc_action_rtn ( dce_pointer_t spc_struct, dce_pointer_t event_param, dce_pointer_t sm ) { rpc_cn_assoc_p_t assoc_p ATTRIBUTE_UNUSED; rpc_cn_call_rep_p_t call_rep_p; rpc_cn_sm_event_entry_t event_entry; unsigned32 status; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(CLIENT allocate_assoc_action_rtn); call_rep_p = (rpc_cn_call_rep_p_t) spc_struct; /* * Allocate the association. Pass in the binding rep, * and interface spec rep and get back an association, it * negotiated transfer syntax and its context id. */ if ((call_rep_p->assoc = rpc__cn_assoc_request (call_rep_p, (rpc_cn_binding_rep_t *) call_rep_p->binding_rep, (rpc_if_rep_t *) event_param, &call_rep_p->transfer_syntax, &call_rep_p->context_id, &call_rep_p->sec, &status)) != NULL) { call_rep_p->max_seg_size = RPC_CN_ASSOC_MAX_XMIT_FRAG (call_rep_p->assoc); rpc__cn_assoc_push_call (call_rep_p->assoc, call_rep_p, &status); event_entry.event_id = RPC_C_CALL_ALLOC_ASSOC_ACK; event_entry.event_param = (dce_pointer_t) NULL; } else { event_entry.event_id = RPC_C_CALL_ALLOC_ASSOC_NAK; event_entry.event_param = (dce_pointer_t) NULL; /* * We will return the status returned by assoc_request. * This status will be returned by the eval routine since * we will invoke no action routine when we transtion to * cfdne state. */ } /* * Insert the new event on the event queue for our state * machine. */ rpc__cn_sm_insert_event (&event_entry, &(call_rep_p->call_state)); sm_p = (rpc_cn_sm_ctlblk_t *)sm; sm_p->cur_state = RPC_C_CLIENT_CALL_ASSOC_ALLOC_WAIT; return (status); } /* **++ ** ** ROUTINE NAME: transmit_req_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Action routine to send the call request PDU(s) to the server. ** ** INPUTS: ** ** spc_struct The call rep. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param The iovector describing the data to be sent. ** This is passed in as the special event related ** parameter passed to the state machine event ** evaluator. ** ** INPUTS/OUTPUTS: ** ** sm The control block from the event evaluation ** routine. Input is the current state and ** event for the control block. Output is the ** next state or updated current state, for the ** control block. ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: rpc_s_ok if the send was completed successfully. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned32 transmit_req_action_rtn ( dce_pointer_t spc_struct, dce_pointer_t event_param, dce_pointer_t sm ) { rpc_cn_call_rep_p_t call_rep; rpc_iovector_p_t stub_data_p; rpc_iovector_elt_p_t iov_elt_p; unsigned8 event ATTRIBUTE_UNUSED; unsigned32 i; unsigned32 status; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(CLIENT transmit_req_action_rtn); status = rpc_s_ok; call_rep = (rpc_cn_call_rep_p_t) spc_struct; stub_data_p = (rpc_iovector_p_t) event_param; sm_p = (rpc_cn_sm_ctlblk_t *)sm; /* * We set call_executed to true at this point. * This is somewhat conservative; but it is correct. * We will reset call_executed if we get back a * fault_dne. */ call_rep->call_executed = true; /* * A call_transmit must have some stub data. If this RPC * had no input arguments, then the first call should have * been a call_transceive with no stub data. */ #ifdef DEBUG if (stub_data_p->num_elt <= 0) { status = rpc_s_coding_error; } else #endif { /* Fill in the alloc_hint */ call_rep->alloc_hint = rpc__cn_get_alloc_hint(stub_data_p); for (i = 0, iov_elt_p = stub_data_p->elt; /* first iovector element */ i < stub_data_p->num_elt; i++, iov_elt_p++) { /* * If the data_len is 0, just deallocate the iovector * element. */ if (iov_elt_p->data_len == 0) { if (iov_elt_p->buff_dealloc != NULL) { (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr); } } else { /* * If the number of bytes < our bcopy_lim, * copy the data and deallocate the buffer. * copy_buffer will automatically transfer the * data if the accumulated byte count reaches * the segment size. */ if (iov_elt_p->data_len <= RPC_C_CN_BCOPY_LIM) { rpc__cn_copy_buffer (call_rep, iov_elt_p, &status); if (iov_elt_p->buff_dealloc != NULL) { (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr); } } else { /* * If the buffer must be made immediately reusable, copy * it also. * Note that this can be optimized later so that we won't * copy; just transmit the data; if certain criteria have * been met. */ if (iov_elt_p->flags & rpc_c_iovector_elt_reused) { rpc__cn_copy_buffer (call_rep, iov_elt_p, &status); if (status != rpc_s_ok) { goto done; } } else { #if 0 if (iov_elt_p->flags & rpc_c_iovector_elt_reused) { found_reusable = true; } #endif /* * Don't copy, add this buffer as a new iovector * element. * add_new_vector_elmt will automatically transfer the * data if the accumulated byte count reaches * the segment size. */ rpc__cn_add_new_iovector_elmt (call_rep, iov_elt_p, &status); if (status != rpc_s_ok) { goto done; } } } } } } #if 0 /* * Finally, if there is any buffered data on the call rep flush * any data that we'd have to copy if possible. */ if (found_reusable) { rpc__cn_flush_buffers (call_rep, &status); } #endif done: ; sm_p->cur_state = RPC_C_CLIENT_CALL_REQUEST; return (status); } /* **++ ** ** ROUTINE NAME: send_last_frag_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Action routine to send the last call request fragment to the server. ** ** INPUTS: ** ** spc_struct The call rep. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param The iovector describing the data to be sent. ** This is passed in as the special event related ** parameter passed to the state machine event ** evaluator. ** This parameter can be null for a transceive ** with no input arguments. ** ** INPUTS/OUTPUTS: ** ** sm The control block from the event evaluation ** routine. Input is the current state and ** event for the control block. Output is the ** next state or updated current state, for the ** control block. ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: rpc_s_ok if the send was completed successfully. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned32 send_last_frag_action_rtn ( dce_pointer_t spc_struct, dce_pointer_t event_param, dce_pointer_t sm ) { rpc_cn_call_rep_p_t call_rep; rpc_iovector_p_t stub_data_p; rpc_cn_packet_p_t header_p; unsigned32 status; rpc_cn_sm_ctlblk_t *sm_p; unsigned8 n_state; RPC_CN_DBG_RTN_PRINTF(CLIENT send_last_frag_action_rtn); sm_p = (rpc_cn_sm_ctlblk_t *)sm; status = rpc_s_ok; call_rep = (rpc_cn_call_rep_p_t) spc_struct; /* * Status contains the result of the macro. */ MAYBE_SEMANTICS_PRED(spc_struct, event_param, status); if (status == 0) /* MaybeSemantics is false */ { n_state = RPC_C_CLIENT_CALL_RESPONSE; } else /* MaybeSemantics is true */ { n_state = RPC_C_CLIENT_CALL_CALL_COMPLETED; } stub_data_p = (rpc_iovector_p_t) event_param; /* * If there's stub data, we can process it just like a normal * call request. This might leave data buffered. * * Note that the absence of stub data is indicated by either * a null iovector pointer or an iovector with 0 elements. */ if ((stub_data_p != NULL) && (stub_data_p->num_elt > 0)) { /* * Note that since we are calling action routines from * within action routines, we need to update state as * a final step here. Otherwise, the action routines * would update sm->cur_state inappropriately for * the calling routine. */ status = transmit_req_action_rtn (spc_struct, event_param, sm); if (status != rpc_s_ok) { sm_p->cur_state = n_state; return (status); } } /* * Set the last frag flag bit in the cached protocol header * and send it along with any buffered data. */ RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG; if (RPC_CN_CREP_ACC_BYTCNT (call_rep) >= RPC_CN_CREP_SIZEOF_HDR (call_rep)) { rpc__cn_transmit_buffers (call_rep, &status); rpc__cn_dealloc_buffered_data (call_rep); /* * Set the length of the iov to 1. We don't use the general * FREE_ALL_EXCEPT_PROT_HEADER macro since we won't be * using the iov again. */ RPC_CN_CREP_IOVLEN (call_rep) = 1; if (status != rpc_s_ok) { sm_p->cur_state = n_state; call_rep->assoc->assoc_status = status; return (status); } } else { /* * If the accumulated bytecount field is less than at * least that of the request header, something is really * off. */ /* * rpc_m_invalid_accbytcnt * "(%s) Inconsistency in ACC_BYTCNT field" */ rpc_dce_svc_printf ( __FILE__, __LINE__, "%s", rpc_svc_cn_errors, svc_c_sev_fatal | svc_c_action_abort, rpc_m_invalid_accbytcnt, "send_last_frag_action_rtn" ); } sm_p->cur_state = n_state; return (rpc_s_ok); } /* **++ ** ** ROUTINE NAME: handle_recv_frag_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Action routine to make the (received) fragment data available ** to the stub for unmarshalling. ** ** INPUTS: ** ** spc_struct The call rep. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param The fragment buffer containing the response ** message. This is passed in as the special ** event related parameter which was passed to ** the state machine event evaluation routine. ** ** INPUTS/OUTPUTS: ** ** sm The control block from the event evaluation ** routine. Input is the current state and ** event for the control block. Output is the ** next state or updated current state, for the ** control block. ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: rpc_s_ok ** ** SIDE EFFECTS: Either a fault or fault_dne event may be ** appended to the state machine event list. ** **-- **/ INTERNAL unsigned32 handle_recv_frag_action_rtn ( dce_pointer_t spc_struct, dce_pointer_t event_param, dce_pointer_t sm ) { unsigned32 status ATTRIBUTE_UNUSED; rpc_cn_fragbuf_p_t fragbuf; rpc_cn_packet_p_t header_p; rpc_cn_call_rep_p_t call_rep; rpc_cn_sm_ctlblk_t *sm_p; unsigned8 n_state = 0; RPC_CN_DBG_RTN_PRINTF(CLIENT handle_recv_frag_action_rtn); call_rep = (rpc_cn_call_rep_p_t) spc_struct; fragbuf = (rpc_cn_fragbuf_p_t) event_param; sm_p = (rpc_cn_sm_ctlblk_t *)sm; header_p = (rpc_cn_packet_p_t) fragbuf->data_p; /* * We've got a proper response. Adjust data_size to describe * the stub data. * Note that we do not need to adjust data_p since that will * be done by rpc__cn_call_receive. */ fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) - RPC_CN_PKT_AUTH_TLR_LEN (header_p) - RPC_CN_PKT_SIZEOF_RESP_HDR; /* * Determine whether this is the last response fragment. */ if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) { /* * The predicate associated with this routine, * last_recv_frag_pred_rtn, checks the same * flags checked above in the if statement. * If RPC_CN_PKT_FLAGS & rpc_c_cn_flags_lastfrag * are 0, then set state to rpc_c_client_call * response, else set state to rpc_c_client_call_ * call_complete. */ n_state = RPC_C_CLIENT_CALL_CALL_COMPLETED; /* * If there is a timer running stop it since we've heard from * the server. */ rpc__cn_call_stop_cancel_timer (call_rep); /* * Record whether the server finished with a pending alert. Note * that the alert count in the packet does not include the * alert forwarded by setting the PFC_PENDING_ALERT bit in the * first fragment of the request. */ if ((call_rep->u.client.cancel.server_count > RPC_CN_PKT_ALERT_COUNT (header_p)) || (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING)) { /* * Either the number of alerts forwarded by us is * greater than the number of alerts posted to the call * executor thread on the server OR the there was still an alert * pending in the call executor thread when the server * stub returned. In either case set the * server_had_pending flag in the call_rep to indicate an * alert should be posted to the client caller thread * before returning to the client stub. */ call_rep->u.client.cancel.server_had_pending = true; #ifdef DEBUG if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING) { RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(handle_recv_frag_action_rtn) call_rep->%p alert pending flag is set in header\n", call_rep)); } else { RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(handle_recv_frag_action_rtn) call_rep->%p number alerts forwarded (%d) > alert count in header (%d)\n", call_rep, call_rep->u.client.cancel.server_count, RPC_CN_PKT_ALERT_COUNT (header_p))); } #endif } } else { n_state = RPC_C_CLIENT_CALL_RESPONSE; } /* * We are currently executing in the receiver thread. * * If there is stub data, queue it on the association so that * the client call thread can get it. * If there is no stub data (e.g., no out arguments), just * deallocate the fragment buffer. * We make an exception for the first fragment; it is always * queued since the client call thread may already be blocked * on the condition variable. */ if (fragbuf->data_size || (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_FIRST_FRAG)) { rpc__cn_assoc_queue_frag (call_rep->assoc, fragbuf, true); } else { (* fragbuf->fragbuf_dealloc) (fragbuf); } /* * Increment num_pkts in the call rep. This will be used in * determining when to check for pending cancels. */ call_rep->num_pkts++; sm_p->cur_state = n_state; return (rpc_s_ok); } /* **++ ** ** ROUTINE NAME: raise_fault_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Action routine to deallocate the current association and raise ** fault. Operationally, this will store the address of the ** fragment buffer in the callrep (for later retrieval via the ** rpc__receive_fault). ** ** INPUTS: ** ** spc_struct The call rep. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param The fault packet. This is passed in as the ** event specific structure. ** ** INPUTS/OUTPUTS: ** ** sm The control block from the event evaluation ** routine. Input is the current state and ** event for the control block. Output is the ** next state or updated current state, for the ** control block. ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: rpc_s_call_faulted ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned32 raise_fault_action_rtn ( dce_pointer_t spc_struct, dce_pointer_t event_param, dce_pointer_t sm ) { unsigned32 status ATTRIBUTE_UNUSED; rpc_cn_fragbuf_p_t fragbuf; rpc_cn_packet_p_t header_p; rpc_cn_call_rep_p_t call_rep; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(CLIENT raise_fault_action_rtn); call_rep = (rpc_cn_call_rep_p_t) spc_struct; fragbuf = (rpc_cn_fragbuf_p_t) event_param; header_p = (rpc_cn_packet_p_t) fragbuf->data_p; sm_p = (rpc_cn_sm_ctlblk_t *)sm; /* * We've got a proper response. Adjust data_size to describe * the stub data. * Note that we do not need to adjust data_p since that will * be done by rpc__cn_call_receive. */ fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) - RPC_CN_PKT_AUTH_TLR_LEN (header_p) - RPC_CN_PKT_SIZEOF_FAULT_HDR; /* * If there is a timer running stop it since we've heard from * the server. */ rpc__cn_call_stop_cancel_timer (call_rep); /* * Determine whether this is the last fault fragment. */ if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) { /* * Record whether the server finished with a pending alert. Note * that the alert count in the packet does not include the * alert forwarded by setting the PFC_PENDING_ALERT bit in the * first fragment of the request. */ if ((call_rep->u.client.cancel.server_count > RPC_CN_PKT_ALERT_COUNT (header_p)) || (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING)) { /* * Either the number of alerts forwarded by us is * greater than the number of alerts posted to the call * executor thread on the server OR the there was still an alert * pending in the call executor thread when the server * stub returned. In either case set the * server_had_pending flag in the call_rep to indicate an * alert should be posted to the client caller thread * before returning to the client stub. */ call_rep->u.client.cancel.server_had_pending = true; #ifdef DEBUG if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING) { RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(raise_fault_action_rtn) call_rep->%p alert pending flag is set in header\n", call_rep)); } else { RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(raise_fault_action_rtn) call_rep->%p number alerts forwarded (%d) > alert count in header (%d)\n", call_rep, call_rep->u.client.cancel.server_count, RPC_CN_PKT_ALERT_COUNT (header_p))); } #endif } } /* * We are currently executing in the receiver thread. * * If there is stub data, queue it on the association so that * the client call thread can get it. * If there is no stub data (e.g., no out arguments), just * deallocate the fragment buffer. * We make an exception for the first fragment; it is always * queued since the client call thread may already be blocked * on the condition variable. */ if (fragbuf->data_size || (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_FIRST_FRAG)) { rpc__cn_assoc_queue_frag (call_rep->assoc, fragbuf, true); } else { (* fragbuf->fragbuf_dealloc) (fragbuf); } /* * There is no predicate associated with this routine but the * new value of sm->cur_state is determined by the value of * sm->cur_event coming into the routine. Note that * 2+statebase is event fault_dns; 3+statebase is event * fault. */ if (sm_p->cur_event == (2 + RPC_C_CN_STATEBASE )) sm_p->cur_state = RPC_C_CLIENT_CALL_CFDNE; else if (sm_p->cur_event == (3 + RPC_C_CN_STATEBASE )) sm_p->cur_state = RPC_C_CLIENT_CALL_CALL_FAILED; return (rpc_s_ok); } /* **++ ** ** ROUTINE NAME: forward_alert_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Action routine to forward an alert. The first alert that is ** forwarded will start the alert timer. This timer will run until ** either the call is completed or a reponse is received from the ** server. If the timer expires the call is orphaned. The alert ** timer setting, clearing and expiration handling is all done outside ** the state machine action routines, primarily in the ** rpc__cn_call_forward_cancel, rpc__cn_call_[start,stop]_cancel_timer ** and rpc__cn_call_cancel_timer. All cancellable operations made in ** the CN runtime are encompassed in cancel exception handlers. ** ** INPUTS: ** ** spc_struct The call rep. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param The error_status to return. This is passed in ** as the special event related parameter which ** was passed to the state machine event ** evaluation routine. ** ** INPUTS/OUTPUTS: ** ** sm The control block from the event evaluation ** routine. Input is the current state and ** event for the control block. Output is the ** next state or updated current state, for the ** control block. ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: rpc_s_call_faulted ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned32 forward_alert_action_rtn ( dce_pointer_t spc_struct, dce_pointer_t event_param ATTRIBUTE_UNUSED, dce_pointer_t sm ) { rpc_cn_call_rep_p_t call_rep; rpc_cn_packet_p_t header_p; struct { rpc_iovector_t iov; rpc_iovector_elt_t elt_1; } pdu; unsigned32 status; unsigned8 prev_ptype; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(CLIENT forward_alert_action_rtn); call_rep = (rpc_cn_call_rep_p_t) spc_struct; sm_p = (rpc_cn_sm_ctlblk_t *)sm; header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); /* * The remote alert indication packet uses only the * common fields of the header. We can therefore just * use the current header. */ prev_ptype = RPC_CN_PKT_PTYPE (header_p); RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_REMOTE_ALERT; RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_ALERT_PENDING; /* * If security was requested on this call an authentication * trailer will have to be added to the alert PDU. */ if (call_rep->sec == NULL) { RPC_CN_PKT_FRAG_LEN (header_p) = RPC_CN_PKT_SIZEOF_ALERT_HDR; pdu.iov.num_elt = 1; } else { RPC_CN_PKT_FRAG_LEN (header_p) = RPC_CN_PKT_SIZEOF_ALERT_HDR + call_rep->prot_tlr->data_size - RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep); pdu.iov.num_elt = 2; pdu.elt_1.buff_dealloc = NULL; pdu.elt_1.data_addr = (byte_p_t) call_rep->prot_tlr->data_p; pdu.elt_1.data_len = call_rep->prot_tlr->data_size - RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep); } /* * Send the packet over. */ pdu.iov.elt[0].buff_dealloc = NULL; pdu.iov.elt[0].data_addr = (byte_p_t) header_p; pdu.iov.elt[0].data_len = RPC_CN_PKT_SIZEOF_ALERT_HDR; rpc__cn_assoc_send_frag (call_rep->assoc, &pdu.iov, call_rep->sec, &status); /* * Restore the previous packet type. */ RPC_CN_PKT_PTYPE (header_p) = prev_ptype; /* * Increment the count of forwarded cancels. */ call_rep->u.client.cancel.server_count++; RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(forward_alert_action_rtn) call_rep->%p forwarding cancel total so far = %d\n", call_rep, call_rep->u.client.cancel.server_count)); /* * There is no predicate associated with this routine but the * new value of sm->cur_state is determined by the value of * sm->cur_state coming into the routine. In otherwords, * this action routine is called from 2 different states * and the value of that state determines the new value * for sm->cur_state. Note that 3+statebase is call_request; * 4+statebase is call_response. rpc_c_cn_statebase is * set to 100 to distinguish it from action routine * indexes used in the rpc__cn_sm_event_eval() routine. */ if (sm_p->cur_state == (3 + RPC_C_CN_STATEBASE)) sm_p->cur_state = RPC_C_CLIENT_CALL_REQUEST; else if (sm_p->cur_state == (4 + RPC_C_CN_STATEBASE)) sm_p->cur_state = RPC_C_CLIENT_CALL_RESPONSE; return (status); } /* **++ ** ** ROUTINE NAME: abort_send_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Action routine to abort a send. ** It sends an orphaned message, and then raises a fault by ** returning the error status back to the caller. ** ** INPUTS: ** ** spc_struct The call rep. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param This parameter is ignored. It is passed in ** as the special event related parameter which ** was passed to the state machine event ** evaluation routine. ** ** INPUTS/OUTPUTS: ** ** sm The control block from the event evaluation ** routine. Input is the current state and ** event for the control block. Output is the ** next state or updated current state, for the ** control block. ** ** OUTPUTS: rpc_s_call_faulted ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: error_status reflecting the fault ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned32 abort_send_action_rtn ( dce_pointer_t spc_struct, dce_pointer_t event_param ATTRIBUTE_UNUSED, dce_pointer_t sm ) { rpc_cn_call_rep_p_t call_rep; rpc_cn_packet_p_t header_p; unsigned32 status; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(CLIENT abort_send_action_rtn); call_rep = (rpc_cn_call_rep_p_t) spc_struct; sm_p = (rpc_cn_sm_ctlblk_t *)sm; /* * The call is going to be orphaned. The stub data bufferred * on the call rep will not be sent and can be released. */ rpc__cn_dealloc_buffered_data (call_rep); RPC_CN_FREE_ALL_EXCEPT_PROT_HDR (call_rep); /* * Now prepare to send an orphaned packet to the server. */ header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(call_rep); RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_ORPHANED; RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG; RPC_DBG_PRINTF (rpc_e_dbg_orphan, RPC_C_CN_DBG_ORPHAN, ("(abort_send_action_rtn) call_rep->%p sending orphan packet ... call id = %x\n", call_rep, RPC_CN_PKT_CALL_ID (header_p))); /* * If security was requested on this call an authentication * trailer will have to be added to the orphan PDU. */ if (call_rep->sec == NULL) { RPC_CN_PKT_FRAG_LEN (header_p) = RPC_CN_PKT_SIZEOF_ORPHANED_HDR; RPC_CN_CREP_IOVLEN (call_rep) = 1; } else { RPC_CN_PKT_FRAG_LEN (header_p) = RPC_CN_PKT_SIZEOF_ORPHANED_HDR + call_rep->prot_tlr->data_size - RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep); RPC_CN_CREP_IOVLEN (call_rep) = 2; RPC_CN_CREP_IOV (call_rep)[1].data_addr = (byte_p_t) call_rep->prot_tlr->data_p; RPC_CN_CREP_IOV (call_rep)[1].data_len = call_rep->prot_tlr->data_size - RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep); RPC_CN_CREP_IOV (call_rep)[1].buff_dealloc = NULL; } /* * Send the packet over. Note that the returned status is * ignored. */ RPC_CN_CREP_IOV (call_rep)[0].data_addr = (byte_p_t) header_p; RPC_CN_CREP_IOV (call_rep)[0].data_len = RPC_CN_PKT_SIZEOF_ORPHANED_HDR; rpc__cn_assoc_send_frag (call_rep->assoc, &(call_rep->buffered_output.iov), call_rep->sec, &status); /* * Now return to the caller (presumably rpc__cn_call_end) which * will deallocate the association on our end and clean up. */ sm_p->cur_state = RPC_C_CLIENT_CALL_CALL_FAILED; return (rpc_s_ok); } /* **++ ** ** ROUTINE NAME: abort_recv_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Action routine to abort a receive. ** ** INPUTS: ** ** spc_struct The call rep. Note that this is passed in as ** the special structure which is passed to the ** state machine event evaluation routine. ** ** event_param The fault data. ** This is passed in as the special event related ** parameter which was passed to the state machine ** event evaluation routine. ** ** INPUTS/OUTPUTS: ** ** sm The control block from the event evaluation ** routine. Input is the current state and ** event for the control block. Output is the ** next state or updated current state, for the ** control block. ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: completion status ** rpc_s_call_faulted ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned32 abort_recv_action_rtn ( dce_pointer_t spc_struct, dce_pointer_t event_param, dce_pointer_t sm ) { unsigned32 status; RPC_CN_DBG_RTN_PRINTF(CLIENT abort_recv_action_rtn); /* * Note that we are getting state from raise_fault_action_rtn(). Also * note that it does not seem that we are actually using abort_recv_ * action_rtn in the state tables. * * Note, we don't need to chase down our receiver thread. * We will shortly deallocate the association. The receiver * thread will automatically discard fragments for non-existent * associations. * * We make this a separate action routine (instead of using * raise_fault_action_rtn) to leave room for future optimizations. */ /* * Abort the association. */ rpc__cn_assoc_abort (((rpc_cn_call_rep_p_t) spc_struct)->assoc, &status); /* * Raise the fault. */ return (raise_fault_action_rtn (spc_struct, event_param, sm )); }