/* * * (c) Copyright 1990 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1990 HEWLETT-PACKARD COMPANY * (c) Copyright 1990 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. * */ /* */ /* ** ** NAME ** ** cnsclsm.c ** ** FACILITY: ** ** Remote Procedure Call (RPC) ** ** ABSTRACT: ** ** Server call State Machine for the Connection-based RPC runtime. ** ** */ #include /* Common declarations for all RPC runtime */ #include /* Common communications services */ #include /* Common protocol services */ #include /* NDR representation global declarations */ #include /* System dependent NDR decls */ #include /* NCA Connection private declarations */ #include /* NCA Connection fragment buffer declarations */ #include /* NCA Connection protocol header */ #include /* NCA Connection state machine declarations */ #include /* NCA Connection buffered data transfer */ #include /* NCA Connection association services */ #include /* Externals for Call Thread sub-component */ #include /* NCA connection call service */ #include /******************************************************************************/ /* * Global Definitions */ #ifdef DEBUG GLOBAL char *rpc_g_cn_call_server_events [] = { "RESPONSE ", "INDICATION ", "FAULT_DNE ", "FAULT ", "LOCAL_ALERT ", "END ", "REMOTE_ALERT_IND ", "ORPHANED " }; GLOBAL char *rpc_g_cn_call_server_states [] = { "INIT ", "REQUEST ", "RESPONSE ", "CALL_COMPLETED " }; #endif /***********************************************************************/ /* * S E R V E R 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 changed some predicate routines * and made them macros and we have absorbed the predicates into the * actions. Thus, there is no longer a need for the predicate table. * We invoke the predicate functions as MACROS or as function calls * from within the action routines. */ /* * The predicate routine prototypes. */ INTERNAL unsigned8 disconnected_maybe_pred_rtn _DCE_PROTOTYPE_ (( pointer_t spc_struct, pointer_t event_param )) ATTRIBUTE_UNUSED; INTERNAL unsigned8 request_fault_pred_rtn _DCE_PROTOTYPE_ (( pointer_t spc_struct, pointer_t event_param )) ATTRIBUTE_UNUSED; INTERNAL unsigned8 response_fault_pred_rtn _DCE_PROTOTYPE_ (( pointer_t spc_struct, pointer_t event_param )) ATTRIBUTE_UNUSED; INTERNAL unsigned8 last_recv_frag_pred_rtn _DCE_PROTOTYPE_ (( pointer_t spc_struct, pointer_t event_param )) ATTRIBUTE_UNUSED; INTERNAL unsigned8 first_frag_pred_rtn _DCE_PROTOTYPE_ (( pointer_t spc_struct, pointer_t event_param )) ATTRIBUTE_UNUSED; INTERNAL unsigned8 disc_last_send_pred_rtn _DCE_PROTOTYPE_ (( pointer_t spc_struct, pointer_t event_param )) ATTRIBUTE_UNUSED; /***********************************************************************/ /* * S E R V E R C A L L A C T I O N T A B L E */ /***********************************************************************/ /* * The actions. */ #define HANDLE_FIRST_FRAG 0 #define HANDLE_FRAG 1 #define SEND_CALL_RESP 2 #define SEND_CALL_FAULT 3 #define PROCESS_ALERT_MSG 4 #define ABORT_RESP 5 #define ABORT_RESP_SEND_FAULT 6 #define STOP_ORPHAN 7 #define DISCARD_FRAGMENT 8 #define CALL_END 9 #define PROTOCOL_ERROR 10 /* * We do not currently execute actions when we abort a receive. */ #define ABORT_RECEIVE RPC_C_SM_NO_ACTION #define ABORT_RECEIVE_SEND_FAULT SEND_CALL_FAULT /* * The action routine prototypes. */ INTERNAL unsigned32 handle_first_frag_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); INTERNAL unsigned32 handle_frag_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); INTERNAL unsigned32 send_call_resp_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); INTERNAL unsigned32 send_call_fault_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); INTERNAL unsigned32 process_alert_msg_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); INTERNAL unsigned32 abort_resp_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); INTERNAL unsigned32 abort_resp_send_fault_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); INTERNAL unsigned32 stop_orphan_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); INTERNAL unsigned32 discard_fragment_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); INTERNAL unsigned32 call_end_action_rtn _DCE_PROTOTYPE_ (( pointer_t /*spc_struct*/, pointer_t /*event_param*/, pointer_t /*sm*/ )); /* * The action table itself. */ GLOBAL rpc_cn_sm_action_fn_t rpc_g_cn_server_call_action_tbl [] = { handle_first_frag_action_rtn, handle_frag_action_rtn, send_call_resp_action_rtn, send_call_fault_action_rtn, process_alert_msg_action_rtn, abort_resp_action_rtn, abort_resp_send_fault_action_rtn, stop_orphan_action_rtn, discard_fragment_action_rtn, call_end_action_rtn, rpc__cn_call_sm_protocol_error }; /***********************************************************************/ /* * S E R V E R C A L L S T A T E T A B L E */ /* * A state table entry exists for every state in the state machine. * In the case of the server call state machine, for example, a * state table entry exists for init, call_request, call_response, * etc. * * Each state table entry describes the actions and state transitions * which can occur in response to each event while in that state. * So for example, the state table entry for the init state must * describe the outcomes for every event. * * The outcome for an event is a new state and an action routine to * invoke. * * Sometimes, how a given event is handled depends upon certain * conditions. For example, a fault_dne event occurring in the * call_response state is handled differently depending upon whether * the connection has been disconnected and the semantics of the * call. This is translated into a number of different outcomes * for each event. * * As an optimization, the structure rpc_cn_sm_state_tbl_entry_t * was modified to contain one unsigned8 value. That value can * be either a state to transition to, or the action index. * We distinguish between states and action indexes by value; * state values are >=100 and action indexes are in the range * of 1 - 14. If the state and event combination in the state table * requires an action, then the rpc_cn_sm_state_tbl_entry_t structure * contains an index into the action tbl for that set of * circumstances. The action routine itself will contain a * predicate function, usually inline, and the action routine will * update the control block's cur_state which in effect, is the * next state. The predicate function within the action routine * will guide the logic through the action so that the appropriate * action is taken depending on the outcome of the predicate * function. If the state and event combination requires no action but does * require a state update, then we look to rpc_cn_sm_state_tbl_entry_t * to contain that state update value. * */ INTERNAL rpc_cn_sm_state_tbl_entry_t init_state = { ILLEGAL_TRANSITION, /* event 0 - rpc_resp */ {HANDLE_FIRST_FRAG}, /* event 1 - rpc_ind */ ILLEGAL_TRANSITION, /* event 2 - fault_dne */ ILLEGAL_TRANSITION, /* event 3 - fault */ ILLEGAL_TRANSITION, /* event 4 - local_alert */ {RPC_C_SERVER_CALL_CALL_COMPLETED}, /* event 5 - call_end state */ ILLEGAL_TRANSITION, /* event 6 - remote_alert_ind */ ILLEGAL_TRANSITION /* event 7 - orphaned */ }; INTERNAL rpc_cn_sm_state_tbl_entry_t call_request_state = { ILLEGAL_TRANSITION, /* event 0 - rpc_resp */ {HANDLE_FRAG}, /* event 1 - rpc_ind */ {ABORT_RECEIVE_SEND_FAULT}, /* event 2 - fault_dne */ {ABORT_RECEIVE_SEND_FAULT}, /* event 3 - fault */ ILLEGAL_TRANSITION, /* event 4 - local_alert */ {CALL_END}, /* event 5 - call_end */ {PROCESS_ALERT_MSG}, /* event 6 - remote_alert_ind */ /* * This transition should not be going to the call * completed state when the call is still executing. * However, this implementation will return an error to any * attempts to send a reponse on a call which is in the * call_completed state before entering the state machine. */ {STOP_ORPHAN} /* event 7 - orphaned */ }; INTERNAL rpc_cn_sm_state_tbl_entry_t call_response_state = { {SEND_CALL_RESP}, /* event 0 - rpc_resp */ ILLEGAL_TRANSITION, /* event 1 - rpc_ind */ {ABORT_RESP_SEND_FAULT}, /* event 2 - fault_dne */ {ABORT_RESP_SEND_FAULT}, /* event 3 - fault */ ILLEGAL_TRANSITION, /* event 4 - local_alert */ {CALL_END}, /* event 5 - call_end */ {PROCESS_ALERT_MSG}, /* event 6 - remote_alert_ind */ {STOP_ORPHAN} /* event 7 - orphaned */ }; 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 */ ILLEGAL_TRANSITION, /* event 4 */ {RPC_C_SERVER_CALL_CALL_COMPLETED}, /* event 5 - call_end */ ILLEGAL_TRANSITION, /* event 6 */ {RPC_C_SERVER_CALL_CALL_COMPLETED} /* event 7 - orphaned */ }; GLOBAL rpc_cn_sm_state_entry_p_t rpc_g_cn_server_call_sm [] = { init_state, /* state 0 - init */ call_request_state, /* state 1 - call_request */ call_response_state, /* state 2 - call_response */ call_completed_state /* state 3 - call_completed */ }; /***********************************************************************/ /* * * S E R V E R C A L L P R E D I C A T E R O U T I N E S * */ /***********************************************************************/ /* **++ ** ** ROUTINE NAME: disconnected_maybe_pred_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Predicate routine to evaluate whether the communications link ** has been disconnected or if the call has maybe semantics. ** This routine is invoked from the Call Request and Call Response ** states when an RPCInd or RPCResp event occurred. ** ** 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 Fragment buffer containing the received data. ** Note that it is passed in as the special event ** related parameter which is passed to the state ** machine event evaluation routine. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: the association status has been set to non-OK if the ** connection has been disconnected. ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: 0 if Disconnected and MaybeSemantics are both false ** 1 if either Disconnected or MaybeSemantics is true ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned8 disconnected_maybe_pred_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param ) #else (spc_struct, event_param) pointer_t spc_struct; pointer_t event_param; #endif { RPC_CN_DBG_RTN_PRINTF(SERVER disconnected_maybe_pred_rtn); if ( (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status != rpc_s_ok) || (RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) & RPC_C_CN_FLAGS_MAYBE) ) { return (1); } else { return (0); } } /* **++ ** ** ROUTINE NAME: disc_last_send_pred_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Predicate routine which evaluates whether the communications link ** has been disconnected and whether this the the last fragment ** of the response. It is invoked from the Call Response state when ** an RPCResp event occurred. ** ** 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 Iovector element containing the stub data for ** the response. ** Note that it is passed in as the special event ** related parameter which is passed to the state ** machine event evaluation routine. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: the association status has been set to non-OK if the ** connection has been disconnected. ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: 0 if Disconnected is true ** 1 if Disconnected is false and this is the ** last fragment of the response. ** (NOTE that this value cannot in fact be ** returned since we can only detect ** the last fragment when the CALL_END ** is issued.) ** 2 if Disconnected is false and this is not ** the last fragment of the response. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned8 disc_last_send_pred_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param ATTRIBUTE_UNUSED ) #else (spc_struct, event_param) pointer_t spc_struct; pointer_t event_param; #endif { RPC_CN_DBG_RTN_PRINTF(SERVER disc_last_send_pred_rtn); if (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status != rpc_s_ok) { return (0); } else { return (2); } /* * Note, our current implementation can never detect the * last fragment of the response until the CALL_END is * issued. Consequently, 1 cannot be returned. */ } /* **++ ** ** MACRO NAME: DISC_LAST_SEND_PRED ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** This is a macro version of the disc_last_send_pred_rtn() predicate. ** We added the macro version to avoid overhead when calling the ** predicate function from within the action routines. ** Predicate macro which evaluates whether the communications link ** has been disconnected and whether this the the last fragment ** of the response. It is invoked from the Call Response state when ** an RPCResp event occurred. ** ** 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 Iovector element containing the stub data for ** the response. ** Note that it is passed in as the special event ** related parameter which is passed to the state ** machine event evaluation routine. ** ** 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 Disconnected is true ** 1 if Disconnected is false and this is the ** last fragment of the response. ** (NOTE that this value cannot in fact be ** returned since we can only detect ** the last fragment when the call_end ** is issued.) ** 2 if Disconnected is false and this is not ** the last fragment of the response. ** ** SIDE EFFECTS: none ** **-- **/ #define DISC_LAST_SEND_PRED(spc_struct, event_param, status) \ { \ RPC_CN_DBG_RTN_PRINTF(SERVER disc_last_send_pred_macro); \ if (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status != rpc_s_ok) \ { \ status = 0; \ } \ else \ { \ status = 2; \ } \ } /* **++ ** ** ROUTINE NAME: request_fault_pred_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Routine evaluating the combination of the predicates: MaybeSemantics, ** Disconnected, and LastSendFrag for the fault. It is invoked from ** the Call Request state when either a fault or fault_dne event occurs. ** ** 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 Iovector element containing the fault data. ** Note that it is passed in as the special event ** related parameter which is passed to the state ** machine event evaluation routine. ** This argument is ignored in the current ** implementation. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: the association status has been set to non-OK if the ** connection has been disconnected. ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: 0 if MaybeSemantics or Disconnected is true ** 1 if LastSendFrag for the fault is true and ** and both MaybeSemantics and Disconnected ** are false ** 2 if LastSendFrag for the fault is false, ** and both MaybeSemantics and Disconnected ** are false. ** Note that in our current implementation, ** this outcome cannot occur. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned8 request_fault_pred_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param ATTRIBUTE_UNUSED ) #else (spc_struct, event_param) pointer_t spc_struct; pointer_t event_param; #endif { rpc_cn_call_rep_p_t call_rep; RPC_CN_DBG_RTN_PRINTF(SERVER request_fault_pred_rtn); call_rep = (rpc_cn_call_rep_p_t) spc_struct; if ( ( call_rep->assoc->assoc_status != rpc_s_ok ) || ( (RPC_CN_PKT_FLAGS ( (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep))) & RPC_C_CN_FLAGS_MAYBE ) ) { return (0); } else { /* * Note: Although the architecture allows the fault data * to be sent in several chunks, the current implementation * assumes that it is passed to the runtime in a single * operation. */ return (1); } } /* **++ ** ** MACRO NAME: REQUEST_FAULT_PRED ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** This is a macro version of the request_fault_pred_rtn() predicate. ** We added the macro version to avoid overhead when calling the ** predicate function from within the action routines. ** Macro evaluating the combination of the predicates: MaybeSemantics, ** Disconnected, and LastSendFrag for the fault. It is invoked from ** the Call Request state when either a fault or fault_dne event occurs. ** ** 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 Iovector element containing the fault data. ** Note that it is passed in as the special event ** related parameter which is passed to the state ** machine event evaluation routine. ** This argument is ignored in the current ** implementation. ** ** 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 or Disconnected is true ** 1 if LastSendFrag for the fault is true and ** and both MaybeSemantics and Disconnected ** are false ** 2 if LastSendFrag for the fault is false, ** and both MaybeSemantics and Disconnected ** are false. ** Note that in our current implementation, ** this outcome cannot occur. ** ** SIDE EFFECTS: none ** **-- **/ #define REQUEST_FAULT_PRED(call_rep, event_param, status) \ { \ RPC_CN_DBG_RTN_PRINTF(SERVER request_fault_pred_macro); \ if ( ( call_rep->assoc->assoc_status != \ rpc_s_ok ) || \ ( (RPC_CN_PKT_FLAGS ( (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep))) \ & RPC_C_CN_FLAGS_MAYBE ) ) \ { \ status = 0; \ } \ else \ { \ status = 1; \ } \ } /* **++ ** ** ROUTINE NAME: response_fault_pred_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Evaluate the MaybeSemantics and Disconnected predicates from ** the Call Response state when either a fault or fault_dne ** event occurs. ** ** 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: the association status has been set to non-OK if the ** connection has been disconnected. ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: 0 if MaybeSemantics true, ** 1 if Disconnected is true, ** 2 otherwise. ** ** NOTE that the architecture allows 4 possible return values ** so that fault data can be transmitted in several ** operations. The current implementation assumes that ** any fault data is transmitted in a single operation. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned8 response_fault_pred_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param ATTRIBUTE_UNUSED ) #else (spc_struct, event_param) pointer_t spc_struct; pointer_t event_param; #endif { rpc_cn_packet_p_t header_p; RPC_CN_DBG_RTN_PRINTF(SERVER response_fault_pred_rtn); 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) { return (0); } else { if (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status != rpc_s_ok) { return (1); } else { return (2); } } } /* **++ ** ** MACRO NAME: RESPONSE_FAULT_PRED ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** This is a macro version of the response_fault_pred_rtn() predicate. ** We added the macro version to avoid overhead when calling the ** predicate function from within the action routines. ** Evaluate the MaybeSemantics and Disconnected predicates from ** the Call Response state when either a fault or fault_dne ** event occurs. ** ** 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. ** ** 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 true, ** 1 if Disconnected is true, ** 2 otherwise. ** ** NOTE that the architecture allows 4 possible return values ** so that fault data can be transmitted in several ** operations. The current implementation assumes that ** any fault data is transmitted in a single operation. ** ** SIDE EFFECTS: none ** **-- **/ #define RESPONSE_FAULT_PRED(spc_struct, event_param, status) \ { \ RPC_CN_DBG_RTN_PRINTF(SERVER response_fault_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) \ { \ status = 0; \ } \ else \ { \ if (((rpc_cn_call_rep_p_t) spc_struct)->assoc->assoc_status != rpc_s_ok) \ { \ status = 1; \ } \ else \ { \ status = 2; \ } \ } \ } /* **++ ** ** ROUTINE NAME: last_recv_frag_pred_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Evaluate whether this is the last received request fragment ** when an RPCInd event occurs. ** ** INPUTS: ** ** spc_struct This argument is 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 #ifdef _DCE_PROTO_ ( pointer_t spc_struct ATTRIBUTE_UNUSED, pointer_t event_param ) #else (spc_struct, event_param) pointer_t spc_struct; pointer_t event_param; #endif { RPC_CN_DBG_RTN_PRINTF(SERVER last_recv_frag_pred_rtn); if (RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) & RPC_C_CN_FLAGS_LAST_FRAG) { return (1); } else { return (0); } } /* **++ ** ** MACRO NAME: LAST_RECV_FRAG_PRED ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** This is a macro of the last_recv_frag_pred_rtn routine ** introduced to avoid the overhead of a call-to-subroutine. ** Evaluate whether this is the last received request fragment ** when an RPCInd event occurs. ** ** 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 LastRecvFrag is false ** 1 if LastRecvFrag is true ** ** SIDE EFFECTS: none ** **-- **/ #define LAST_RECV_FRAG_PRED(spc_struct, event_param, status) \ { \ RPC_CN_DBG_RTN_PRINTF(SERVER last_recv_frag_pred_macro ); \ if (RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) & \ RPC_C_CN_FLAGS_LAST_FRAG) \ { \ status = 1; \ } \ else \ { \ status = 0; \ } \ } /* **++ ** ** ROUTINE NAME: first_frag_pred_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Evaluates whether a received packet has the first_frag bit ** set. ** ** INPUTS: ** ** spc_struct This argument is 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 FirstFrag is false ** 1 if FirstFrag is true ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned8 first_frag_pred_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct ATTRIBUTE_UNUSED, pointer_t event_param ) #else (spc_struct, event_param) pointer_t spc_struct; pointer_t event_param; #endif { RPC_CN_DBG_RTN_PRINTF(SERVER first_frag_pred_rtn); if (RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) & RPC_C_CN_FLAGS_FIRST_FRAG) { return (1); } else { return (2); } } /* **++ ** ** MACRO NAME: ALERTED_PRED ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** This is a macro of the alerted_pred_rtn routine ** introduced to avoid the overhead of a call-to-subroutine. ** Evaluates whether the current call has been alerted. ** ** 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. ** ** 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 call was not alerted. ** 1 if call was alerted. ** ** SIDE EFFECTS: none ** **-- **/ #define ALERTED_PRED(spc_struct, status)\ {\ RPC_CN_DBG_RTN_PRINTF(SERVER alerted_pred_macro);\ if ( ((rpc_cn_call_rep_p_t) spc_struct)->cn_call_status ==\ rpc_s_call_cancelled )\ {\ status = 1;\ }\ else\ {\ status = 0;\ }\ } /***********************************************************************/ /* * S E R V E R C A L L A C T I O N R O U T I N E S */ /***********************************************************************/ /* **++ ** ** MACRO NAME: RPC_CN_ASSOC_QUEUE_FRAG ** ** SCOPE: INTERNAL ** ** DESCRIPTION: Used as an optimization. The macro function is ** called from several places and was included ** made into a macro for efficiency reasons. ** Called from handle_first_frag_action_rtn() ** and from handle_frag_action_rtn(). ** ** INPUTS: ** ** event_param The special event related parameter which is ** passed to the state machine event evaluation ** routine. ** This input argument is ignored. ** ** 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. ** ** fragbuf (rpc_cn_fragbuf_p_t)event_param. Used in ** the buffer manipulation routines called from ** within the macro. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: ** ** SIDE EFFECTS: none ** **-- **/ #define RPC_CN_ASSOC_QUEUE_FRAG(event_param, spc_struct, fragbuf) \ {\ if ((RPC_CN_PKT_FLAGS (RPC_CN_FRAGBUF_PKT_HDR (event_param)) & \ RPC_C_CN_FLAGS_FIRST_FRAG)) \ { \ rpc__cn_assoc_queue_frag (((rpc_cn_call_rep_p_t) spc_struct)->assoc, \ fragbuf, \ false); \ } \ else \ { \ rpc__cn_assoc_queue_frag (((rpc_cn_call_rep_p_t) spc_struct)->assoc, \ fragbuf, \ true); \ } \ } /* **++ ** ** MACRO NAME: RPC_CN_FRAGBUF_DATA_SIZE ** ** SCOPE: INTERNAL ** ** DESCRIPTION: Used as an optimization. The macro function is ** called from several places and was included ** made into a macro for efficiency reasons. ** Called from handle_first_frag_action_rtn() ** and from handle_frag_action_rtn(). ** ** INPUTS: ** ** header_p RPC_CN_FRAGBUF_PKT_HDR (event_param) ** ** fragbuf (rpc_cn_fragbuf_p_t)event_param. Used in ** the buffer manipulation routines called from ** within the macro. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: ** ** SIDE EFFECTS: none ** **-- **/ #define RPC_CN_FRAGBUF_DATA_SIZE(header_p, fragbuf)\ {\ if (RPC_CN_PKT_OBJ_UUID_PRESENT (header_p)) \ { \ fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) - \ RPC_CN_PKT_AUTH_TLR_LEN (header_p) - \ RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ; \ } \ else \ { \ fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) - \ RPC_CN_PKT_AUTH_TLR_LEN (header_p) - \ RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ; \ } \ } /* **++ ** ** ROUTINE NAME: handle_first_frag_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Make the received fragment data available to the stub for ** unmarshalling. The fragment is assumed to be the first ** fragment of the request. ** ** 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. ** ** INPUTS/OUTPUTS: ** ** event_param The fragment buffer containing the received ** data. On output, the data_p and data_size ** fields will describe the stub data. ** ** 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: none ** **-- **/ INTERNAL unsigned32 handle_first_frag_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param, pointer_t sm ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { unsigned32 status; rpc_cn_fragbuf_p_t request_fragbuf; rpc_cn_packet_p_t request_header_p; rpc_cn_packet_p_t response_header_p; rpc_cn_call_rep_p_t call_rep; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(SERVER handle_first_frag_action_rtn); sm_p = (rpc_cn_sm_ctlblk_t *)sm; call_rep = (rpc_cn_call_rep_p_t) spc_struct; request_fragbuf = (rpc_cn_fragbuf_p_t) event_param; request_header_p = RPC_CN_FRAGBUF_PKT_HDR (event_param); /* * As part of the performance changes, we run a macro version * of the predicate function, last_recv_frag_pred_rtn() here. * Update status inside the macro. */ LAST_RECV_FRAG_PRED (spc_struct, event_param, status); if (status == 1) /* LastRecvFrag is true */ { sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE; } else /* LastRecvFrag is false */ { sm_p->cur_state = RPC_C_SERVER_CALL_CALL_REQUEST; } status = rpc_s_ok; /* * Get the max_seg_size from the association. */ call_rep->max_seg_size = RPC_CN_ASSOC_MAX_XMIT_FRAG (call_rep->assoc); /* * Copy the opnum field into the local call rep. */ call_rep->opnum = RPC_CN_PKT_OPNUM (request_header_p); if (!(RPC_CN_PKT_FLAGS (request_header_p) & RPC_C_CN_FLAGS_MAYBE)) { /* * Fill in the fields of the response header if this is not * a maybe call. */ RPC_CN_CREP_SIZEOF_HDR (call_rep) = RPC_CN_PKT_SIZEOF_RESP_HDR; response_header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); RPC_CN_PKT_PTYPE (response_header_p) = RPC_C_CN_PKT_RESPONSE; RPC_CN_PKT_FLAGS (response_header_p) = RPC_C_CN_FLAGS_FIRST_FRAG; RPC_CN_PKT_FRAG_LEN (response_header_p) = 0; RPC_CN_PKT_VERS_MINOR (response_header_p) = call_rep->assoc->assoc_vers_minor; RPC_CN_PKT_CALL_ID (response_header_p) = RPC_CN_PKT_CALL_ID (request_header_p); RPC_CN_PKT_ALLOC_HINT (response_header_p) = 0; RPC_CN_PKT_PRES_CONT_ID (response_header_p) = RPC_CN_PKT_PRES_CONT_ID (request_header_p); RPC_CN_PKT_RESP_RSVD (response_header_p) = 0; /* * Initialize the iovector in the call_rep to contain only * one initial element, pointing to the protocol header. * Also, update pointers to show that we can copy data into * the stub data area. */ RPC_CN_CREP_IOVLEN (call_rep) = 1; RPC_CN_CREP_CUR_IOV_INDX (call_rep) = 0; RPC_CN_CREP_FREE_BYTES (call_rep) = RPC_C_CN_SMALL_FRAG_SIZE - RPC_CN_PKT_SIZEOF_RESP_HDR; RPC_CN_CREP_ACC_BYTCNT (call_rep) = RPC_CN_PKT_SIZEOF_RESP_HDR; RPC_CN_CREP_FREE_BYTE_PTR(call_rep) = RPC_CN_PKT_RESP_STUB_DATA (response_header_p); (RPC_CN_CREP_IOV (call_rep)[0]).data_len = RPC_CN_PKT_SIZEOF_RESP_HDR; /* * If security is requested for this call an auth trailer will * be formatted here and included with every packet sent. */ if (call_rep->sec != NULL) { rpc_cn_auth_tlr_t *auth_tlr; unsigned32 auth_value_len; /* * Allocate a small fragbuf to contain the authentication trailer. */ RPC_CN_FRAGBUF_ALLOC (call_rep->prot_tlr, RPC_C_CN_SMALL_FRAG_SIZE, &status); call_rep->prot_tlr->fragbuf_dealloc = NULL; auth_value_len = RPC_C_CN_SMALL_FRAG_SIZE; auth_tlr = (rpc_cn_auth_tlr_t *)call_rep->prot_tlr->data_p; auth_tlr->auth_type = RPC_CN_AUTH_CVT_ID_API_TO_WIRE (call_rep->sec->sec_info->authn_protocol, &status); auth_tlr->auth_level = call_rep->sec->sec_info->authn_level; auth_tlr->key_id = call_rep->sec->sec_key_id; auth_tlr->stub_pad_length = 0; auth_tlr->reserved = 0; RPC_CN_AUTH_PRE_CALL (RPC_CN_ASSOC_SECURITY (call_rep->assoc), call_rep->sec, (pointer_t) auth_tlr->auth_value, &auth_value_len, &status); if (status != rpc_s_ok) { dce_error_string_t error_text; int temp_status; dce_error_inq_text(status, (unsigned char*) error_text, &temp_status); /* * "%s on server failed: %s" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%s%x"), rpc_svc_auth, svc_c_sev_error, rpc_m_call_failed_s, "RPC_CN_AUTH_PRE_CALL", error_text )); /* * A fault packet containing an appropriate status code * will be sent to the client in the receiver * thread. */ return (status); } RPC_CN_CREP_ADJ_IOV_FOR_TLR (call_rep, response_header_p, auth_value_len); } else { RPC_CN_PKT_AUTH_LEN (response_header_p) = 0; } } else { /* * There is no response packet for a maybe call. */ (RPC_CN_CREP_IOV (call_rep)[0]).data_len = 0; /* * Even though there is no response for a maybe call, * we still set the flag bit because the server call state * machine predicates check it. */ RPC_CN_CREP_SIZEOF_HDR (call_rep) = RPC_CN_PKT_SIZEOF_RESP_HDR; response_header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); RPC_CN_PKT_FLAGS (response_header_p) = RPC_C_CN_FLAGS_MAYBE; } /* * Run the functional components of handle_frag_action_routine minus * its internal predicate component. */ /* * Adjust fragment buffer so that data_size describes the stub data. * Note that we do not adjust data_p; that will be done by * rpc__cn_call_receive. */ RPC_CN_FRAGBUF_DATA_SIZE(request_header_p, request_fragbuf); /* * Queue the stub data on the association so that the call * executor thread can get it. * * As an optimization for the first fragment the association * receive queue condition variable will not be signalled since * the call executor thread is not started until after we return * from this state transition back to the receiver thread main loop. */ RPC_CN_ASSOC_QUEUE_FRAG(event_param, spc_struct, (rpc_cn_fragbuf_p_t) event_param); /* * Check the header for a pending cancel. If we had a pending * cancel at the client side re-generate it here. */ if (RPC_CN_PKT_FLAGS (request_header_p) & RPC_C_CN_FLAGS_ALERT_PENDING) { RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(handle_first_frag_action_rtn) call_rep->%x alert pending bit set in header calling rpc__cthread_cancel()\n", call_rep)); RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep)); rpc__cthread_cancel ((rpc_call_rep_t *) call_rep); RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep)); } return (status); } /* **++ ** ** ROUTINE NAME: handle_frag_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** 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. ** ** INPUTS/OUTPUTS: ** ** event_param The fragment buffer containing the received ** data. On output, the data_p and data_size ** fields will describe the stub data. ** ** 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: none ** **-- **/ INTERNAL unsigned32 handle_frag_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param, pointer_t sm ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { unsigned32 status; 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(SERVER handle_frag_action_rtn); sm_p = (rpc_cn_sm_ctlblk_t *)sm; call_rep = (rpc_cn_call_rep_p_t) spc_struct; fragbuf = (rpc_cn_fragbuf_p_t) event_param; header_p = RPC_CN_FRAGBUF_PKT_HDR (event_param); /* * As part of the performance changes, we run a macro version * of the predicate function, last_recv_frag_pred_rtn() here. Update * status inside the macro. */ LAST_RECV_FRAG_PRED (spc_struct, event_param, status); if (status == 1) /* LastRecvFrag is true */ { sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE; } else /* LastRecvFrag is false */ { sm_p->cur_state = RPC_C_SERVER_CALL_CALL_REQUEST; } status = rpc_s_ok; /* * Adjust fragment buffer so that data_size describes the stub data. * Note that we do not adjust data_p; that will be done by * rpc__cn_call_receive. */ RPC_CN_FRAGBUF_DATA_SIZE(header_p, fragbuf); /* * Queue the stub data on the association so that the call * executor thread can get it. * * As an optimization for the first fragment the association * receive queue condition variable will not be signalled since * the call executor thread is not started until after we return * from this state transition back to the receiver thread main loop. */ RPC_CN_ASSOC_QUEUE_FRAG(event_param, spc_struct, fragbuf); return(status); } /* **++ ** ** ROUTINE NAME: send_call_resp_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Start sending the call response PDU(s) to the client. ** ** 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 send_call_resp_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param, pointer_t sm ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { 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(SERVER send_call_resp_action_rtn); sm_p = (rpc_cn_sm_ctlblk_t *)sm; call_rep = (rpc_cn_call_rep_p_t) spc_struct; stub_data_p = (rpc_iovector_p_t) event_param; /* * As part of the performance changes, we run a macro version * of the predicate function, disc_last_send_pred_rtn() here. Update * status inside the macro. Note that DISC_LAST_SEND_PRED * can only return 0 or 2, not 1. */ DISC_LAST_SEND_PRED(spc_struct, event_param, status ); sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE; if (status == 0) { abort_resp_action_rtn( spc_struct, event_param, sm); return(rpc_s_ok); } status = rpc_s_ok; /* * A call_response must have some stub data. * * This raises a question: * If the call had no output arguments, then I guess * the CALL_END on the client would send back just * the protocol header. The runtime would have no * way of knowing until the CALL_END. Right? * Does this mean that we need to track whether any * response was generated and if not, issue just a * response header during a call end. */ #ifdef DEBUG if ((stub_data_p == NULL) || (stub_data_p->num_elt <= 0)) { /* * rpc_m_no_stub_data * "(%s) No stub data to send" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%s"), rpc_svc_xmit, svc_c_sev_fatal | svc_c_action_abort, rpc_m_no_stub_data, "send_call_resp_action_rtn" )); } else { #endif status = rpc_s_ok; for (i = 0, iov_elt_p = stub_data_p->elt; i < stub_data_p->num_elt; i++, iov_elt_p++) { /* * If there is no data, 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); } } /* * If the number of bytes < our bcopy_lim, copy the data and deallocate the buffer. rpc__cn_copy_buffer will automatically transfer the data if the accumulated byte count reaches the segment size. */ else 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); } } /* * 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. */ else 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) { return (status); } } else { /* * Don't copy, add this buffer as a new iovector * element. rpc__cnadd_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) { return (status); } } } #ifdef DEBUG } #endif return (status); } /* **++ ** ** ROUTINE NAME: send_call_fault_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Start sending the call fault 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 fault 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. ** ** 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: call_rep->cn_call_status is assumed to ** indicate the cause of the fault. If it is ** 0, then it is assumed that there is ** fault data to be sent. ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: rpc_s_ok if the send was completed successfully. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned32 send_call_fault_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param, pointer_t sm ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { rpc_cn_call_rep_p_t call_rep; rpc_cn_packet_p_t header_p; rpc_iovector_p_t stub_data_p; rpc_iovector_elt_p_t iov_elt_p; unsigned32 i; unsigned32 status; unsigned32 pdu_size; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(SERVER send_call_fault_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; /* * As part of the performance changes, we run a macro version * of the predicate function, request_fault_pred_rtn() here. Update * status inside the macro. */ REQUEST_FAULT_PRED (call_rep, event_param, status); if (status == 0) { /* * abort_receive () is defined as RPC_C_SM_NO_ACTION */ sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED; return(status); } else if (status == 1) { sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED; } else if (status == 2) { sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE; } status = rpc_s_ok; /* * Use the packet header bufferred on the call rep to format the * fault packet header. */ header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); /* * The call is going to be terminated. 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); /* * Adjust the bufferred header to be the size of a fault packet * header. */ if (call_rep->sec == NULL) { pdu_size = RPC_CN_PKT_SIZEOF_FAULT_HDR; } else { pdu_size = RPC_CN_PKT_SIZEOF_FAULT_HDR + call_rep->prot_tlr->data_size; RPC_CN_CREP_IOVLEN (call_rep) = 2; } RPC_CN_CREP_SIZEOF_HDR (call_rep) = pdu_size; RPC_CN_CREP_IOV(call_rep)[0].data_len = pdu_size; RPC_CN_CREP_ACC_BYTCNT (call_rep) = pdu_size; /* * Now set up the fault packet header. */ RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_FAULT; if (call_rep->call_executed) { RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_FIRST_FRAG; } else { RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_DID_NOT_EXECUTE | RPC_C_CN_FLAGS_FIRST_FRAG; } RPC_CN_PKT_ALLOC_HINT (header_p) = 0; RPC_CN_PKT_PRES_CONT_ID (header_p) = call_rep->context_id; RPC_CN_PKT_RESP_RSVD (header_p) = 0; RPC_CN_PKT_RESP_RSVD2 (header_p) = 0; /* * The fault status can be either an architected non-zero * value indicating a runtime error, such as an interface * version mismatch, or zero, indicating a stub defined * exception specified with the stub data. */ if (call_rep->cn_call_status != rpc_s_ok) { RPC_CN_PKT_STATUS (header_p) = call_rep->cn_call_status; } else { RPC_CN_PKT_STATUS (header_p) = 0; #ifdef DEBUG /* * There should be stub data in this case. */ if ((stub_data_p == NULL) || (stub_data_p->num_elt <= 0)) { /* * rpc_m_no_stub_data * "(%s) No stub data to send" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%s"), rpc_svc_xmit, svc_c_sev_fatal | svc_c_action_abort, rpc_m_no_stub_data, "send_call_fault_action_rtn" )); } #endif /* * Chain the fault data onto the buffered output. */ for (i = 0, iov_elt_p = stub_data_p->elt; i < stub_data_p->num_elt; i++, iov_elt_p++) { rpc__cn_add_new_iovector_elmt (call_rep, iov_elt_p, &status); if (status != rpc_s_ok) { rpc__cn_dealloc_buffered_data (call_rep); return (status); } } } /* * We can only handle one fragment of fault data. */ RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG; /* * Update the alert_pending state and stop accepting * forwarded cancels. */ RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(send_call_fault_action_rtn) call_rep->%x setting alert count (%d) in packet header\n", call_rep, call_rep->u.server.cancel.local_count)); RPC_CN_PKT_ALERT_COUNT (header_p) = call_rep->u.server.cancel.local_count; RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep)); if (call_rep->common.u.server.cancel.had_pending) { RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(send_call_fault_action_rtn) call_rep->%x setting alert pending bit in packet header\n", call_rep)); RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_ALERT_PENDING; } RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep)); rpc__cn_transmit_buffers (call_rep, &status); rpc__cn_dealloc_buffered_data (call_rep); RPC_CN_CREP_IOVLEN (call_rep) = 1; return (status); } /* **++ ** ** ROUTINE NAME: process_alert_msg_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Process a received remote alert message. ** ** 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 remote ** alert message. This fragment buffer is ** deallocated. ** ** 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: none ** **-- **/ INTERNAL unsigned32 process_alert_msg_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param, pointer_t sm ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { rpc_cn_call_rep_p_t call_rep; rpc_cn_fragbuf_p_t fragbuf; unsigned32 status ATTRIBUTE_UNUSED; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(SERVER process_alert_msg_action_rtn); call_rep = (rpc_cn_call_rep_p_t) spc_struct; sm_p = (rpc_cn_sm_ctlblk_t *)sm; /* * Increment the number of remote cancels received. */ call_rep->u.server.cancel.local_count++; RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(process_alert_msg_action_rtn) call_rep->%x received remote alert packet total = %d\n", call_rep, call_rep->u.server.cancel.local_count)); /* * We are currently executing in the context of the * receiver thread so call cthread_cancel. This routine will * cancel the call executor thread if the server is accepting and * not queueing cancels. */ RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep)); rpc__cthread_cancel ((rpc_call_rep_t *) call_rep); RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep)); /* * We can just deallocate the fragment buffer. */ fragbuf = (rpc_cn_fragbuf_p_t) event_param; (* fragbuf->fragbuf_dealloc) (fragbuf); /* * In this case, the updated value of sm->cur_state is * determined by the current value of sm->cur_state. * Note that 2+rpc_c_cn_statebase is call_response_state; * 1+rpc_c_cn_statebase is call_request_state. rpc_c_ * cn_statbase is used to distinguish state values from * action routine indexes in the state tables. */ if (sm_p->cur_state == (2 + RPC_C_CN_STATEBASE )) sm_p->cur_state = RPC_C_SERVER_CALL_CALL_RESPONSE; else if (sm_p->cur_state == ( 1 + RPC_C_CN_STATEBASE )) sm_p->cur_state = RPC_C_SERVER_CALL_CALL_REQUEST; return( rpc_s_ok); } /* **++ ** ** ROUTINE NAME: abort_resp_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Discontinue any further transmission of data for the current ** call, to the best extent possible. Some error condition has ** terminated the current call. ** ** 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 If not null, this is the address of an ** iovector. ** ** INPUTS/OUTPUTS: ** ** sm The control block from the event evaluation ** routine. Input is the current state and ** event for the control block. SM is not changed ** here. ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: rpc_s_ok. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned32 abort_resp_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param ATTRIBUTE_UNUSED, pointer_t sm ATTRIBUTE_UNUSED ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { rpc_cn_call_rep_p_t call_rep; rpc_cn_packet_p_t header_p ATTRIBUTE_UNUSED; RPC_CN_DBG_RTN_PRINTF(SERVER abort_resp_action_rtn); call_rep = (rpc_cn_call_rep_p_t) spc_struct; /* * If there are buffered iovector elements, deallocate them. * * Note that the comparison below is not strictly correct. * Even if there is only a single iovector element, there * may be copied stub data after the header. It's ok to * ignore them because the only way in which the first * iovector element would be reused is if we use it to send * a fault. That operation would adjust the pointers * anyway to point to only the fault data. */ if (RPC_CN_CREP_IOVLEN (call_rep) > 1) { rpc__cn_dealloc_buffered_data (call_rep); /* * This will keep the call_end_action_rtn from attempting to * send the remaining iov which at this point is only an auth_tlr * if this was an authenticated call. We are calling this an * orphaned call which technically, it is, ie the connection is * gone and along with it the association. */ call_rep->cn_call_status = rpc_s_call_orphaned ; /* * Set the length of the iovector to be 1 (just the * protocol header); everything else has been * deallocated. * * Note that we don't use the FREE_ALL_EXCEPT_PROT_HEADER * macro from cnxfer.c since we know that we won't be * queueing more data. */ RPC_CN_CREP_IOVLEN (call_rep) = 1; } return (rpc_s_ok); } /* **++ ** ** ROUTINE NAME: abort_resp_send_fault_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Discontinue any further transmission of data for the current ** call, to the best extent possible; then send a fault. ** Some error condition has terminated the current call. ** ** 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 If not null, this is the address of an ** iovector element containing fault data. ** ** 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: none ** **-- **/ INTERNAL unsigned32 abort_resp_send_fault_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param, pointer_t sm ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { unsigned32 status; rpc_cn_sm_ctlblk_t *sm_p; unsigned8 n_state ATTRIBUTE_UNUSED; rpc_cn_packet_p_t header_p; rpc_cn_call_rep_p_t call_rep; rpc_iovector_elt_p_t iov_elt_p; rpc_iovector_p_t stub_data_p; unsigned32 i; unsigned32 pdu_size; RPC_CN_DBG_RTN_PRINTF(SERVER abort_resp_send_fault_action_rtn); sm_p = (rpc_cn_sm_ctlblk_t *)sm; /* * RESPONSE_FAULT_PRED sets status which is used here * to determine the updated state in the control block, * and to determine which action routines (if any) * to call next. */ RESPONSE_FAULT_PRED(spc_struct, event_param, status); if (status == 0) /* MaybeSemantics true */ { sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED; return (rpc_s_ok); } else if (status == 1) /* Disconnected is true */ { abort_resp_action_rtn (spc_struct, event_param, sm); sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED; return (rpc_s_ok); } else if (status == 2) /* Otherwise.. */ { sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED; } /* * REMOVED: this should be called acording to the spec, * but it doesn't do anything that isn't done already, * and it now sets the call status to orphaned. * * Abort the send; we don't care about its returned status. * status = abort_resp_action_rtn (spc_struct, event_param); */ /* * Send the fault. * * send_call_fault_action_rtn (spc_struct, event_param ); * We changed send_call_fault_action_rtn to include a predicate * for performance reasons so we cannot just call the routine * here because the predicate function would cause additional * and incorrect state transitions. */ RPC_CN_DBG_RTN_PRINTF(SERVER send_call_fault_action_rtn); call_rep = (rpc_cn_call_rep_p_t)spc_struct; stub_data_p = (rpc_iovector_p_t) event_param; /* * Use the packet header bufferred on the call rep to format the * fault packet header. */ header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); /* * The call is going to be terminated. 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); /* * Adjust the bufferred header to be the size of a fault packet * header. */ if (call_rep->sec == NULL) { pdu_size = RPC_CN_PKT_SIZEOF_FAULT_HDR; } else { pdu_size = RPC_CN_PKT_SIZEOF_FAULT_HDR + call_rep->prot_tlr->data_size; RPC_CN_CREP_IOVLEN (call_rep) = 2; } RPC_CN_CREP_SIZEOF_HDR (call_rep) = pdu_size; RPC_CN_CREP_IOV(call_rep)[0].data_len = pdu_size; RPC_CN_CREP_ACC_BYTCNT (call_rep) = pdu_size; /* * Now set up the fault packet header. */ RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_FAULT; if (call_rep->call_executed) { RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_FIRST_FRAG; } else { RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_DID_NOT_EXECUTE | RPC_C_CN_FLAGS_FIRST_FRAG; } RPC_CN_PKT_ALLOC_HINT (header_p) = 0; RPC_CN_PKT_PRES_CONT_ID (header_p) = call_rep->context_id; RPC_CN_PKT_RESP_RSVD (header_p) = 0; RPC_CN_PKT_RESP_RSVD2 (header_p) = 0; /* * The fault status can be either an architected non-zero * value indicating a runtime error, such as an interface * version mismatch, or zero, indicating a stub defined * exception specified with the stub data. */ if (call_rep->cn_call_status != rpc_s_ok) { RPC_CN_PKT_STATUS (header_p) = call_rep->cn_call_status; } else { RPC_CN_PKT_STATUS (header_p) = 0; #ifdef DEBUG /* * There should be stub data in this case. */ if ((stub_data_p == NULL) || (stub_data_p->num_elt <= 0)) { /* * rpc_m_no_stub_data * "(%s) No stub data to send" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%s"), rpc_svc_xmit, svc_c_sev_fatal | svc_c_action_abort, rpc_m_no_stub_data, "send_call_fault_action_rtn" )); } #endif /* * Chain the fault data onto the buffered output. */ for (i = 0, iov_elt_p = stub_data_p->elt; i < stub_data_p->num_elt; i++, iov_elt_p++) { rpc__cn_add_new_iovector_elmt (call_rep, iov_elt_p, &status); if (status != rpc_s_ok) { rpc__cn_dealloc_buffered_data (call_rep); return(status); } } } /* * We can only handle one fragment of fault data. */ RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG; /* * Update the alert_pending state and stop accepting * forwarded cancels. */ RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(send_call_fault_action_rtn) call_rep->%x setting alert count (%d) in packet header\n", call_rep, call_rep->u.server.cancel.local_count)); RPC_CN_PKT_ALERT_COUNT (header_p) = call_rep->u.server.cancel.local_count; RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep)); if (call_rep->common.u.server.cancel.had_pending) { RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(send_call_fault_action_rtn) call_rep->%x setting alert pending bit in packet header\n", call_rep)); RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_ALERT_PENDING; } RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep)); rpc__cn_transmit_buffers (call_rep, &status); rpc__cn_dealloc_buffered_data (call_rep); RPC_CN_CREP_IOVLEN (call_rep) = 1; return (status); } /* **++ ** ** ROUTINE NAME: stop_orphan_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Tell the stub to orphan the previous call. If it was executing, ** i.e., was still receiving for a pipe, alert it. Otherwise, ** discard the input data. If possible (not required), insure ** that no response or fault is returned for the orphaned call. ** ** 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 orphaned ** packet. This fragment buffer is deallocated. ** ** 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: none ** **-- **/ INTERNAL unsigned32 stop_orphan_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param, pointer_t sm ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { rpc_cn_call_rep_p_t call_rep; rpc_cn_fragbuf_p_t fragbuf; unsigned32 status; rpc_binding_rep_t *binding_r; rpc_cn_assoc_p_t assoc; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(SERVER stop_orphan_action_rtn); call_rep = (rpc_cn_call_rep_p_t) spc_struct; sm_p = (rpc_cn_sm_ctlblk_t *)sm; /* * We are currently executing in the context of the * receiver thread. The call has been orphaned by the client. * Free all stub data buffered for sending up to this point. */ rpc__cn_dealloc_buffered_data (call_rep); RPC_CN_FREE_ALL_EXCEPT_PROT_HDR (call_rep); /* * If the call is queued dequeue it otherwise cancel and wakeup the thread * it is executing in. */ status = rpc_s_ok; call_rep->cn_call_status = rpc_s_call_orphaned; if (rpc__cthread_dequeue((rpc_call_rep_t *) call_rep)) { RPC_DBG_PRINTF(rpc_e_dbg_orphan, RPC_C_CN_DBG_ORPHAN, ("(stop_orphan_action_rtn) call_rep->%x queued call ... dequeued call id = %x\n", call_rep, RPC_CN_PKT_CALL_ID ((rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(call_rep)))); binding_r = (rpc_binding_rep_t *) call_rep->binding_rep; RPC_CN_UNLOCK (); rpc__cn_call_end ((rpc_call_rep_p_t *) &call_rep, &status); RPC_CN_LOCK (); RPC_BINDING_RELEASE (&binding_r, &status); } else { /* * We need to cancel and wake up the call executor * thread. If the call executor thread is in the manager * routine the cancel may get through. If it is in the * runtime blocked on a call_receive cancels are disabled * and needs to be woken up. */ RPC_DBG_PRINTF(rpc_e_dbg_orphan, RPC_C_CN_DBG_ORPHAN, ("(stop_orphan_action_rtn) call_rep->%x running call ... cancelling and waking up call id = %x\n", call_rep, RPC_CN_PKT_CALL_ID ((rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(call_rep)))); /* * Need to hold on to the assoc in a local variable since * rpc__cn_assoc_pop_call is going to NULL call_rep->assoc. * We'll pass the local variable to rpc__cn_assoc_dealloc and * use it for RPC_COND_SIGNAL. */ assoc = call_rep->assoc; /* * Pop the call rep off the association. */ rpc__cn_assoc_pop_call (call_rep->assoc, call_rep); /* * Deallocate the association. */ rpc__cn_assoc_dealloc (assoc, call_rep, &status); /* * If the stub is waiting for more data, signal it (really * rpc__cn_assoc_receive_frag()) to wake up (and find out * it's been orphaned). */ if (assoc->assoc_msg_waiters > 0) { RPC_COND_SIGNAL (assoc->assoc_msg_cond, rpc_g_global_mutex); } RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep)); rpc__cthread_cancel ((rpc_call_rep_t *) call_rep); RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep)); } /* * Deallocate the fragment buffer containing the orphaned packet. */ fragbuf = (rpc_cn_fragbuf_p_t) event_param; (*fragbuf->fragbuf_dealloc) (fragbuf); /* * We do not need to call CALL_END since the call_executor * thread will do so when it processes the cancel. */ sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED; return(status); } /* **++ ** ** ROUTINE NAME: discard_fragment_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Discard the received packet. This routine is invoked when we ** get an unexpected (but benign) PDU. ** ** INPUTS: ** ** spc_struct This is the special structure which is passed ** to the state machine event evaluation routine. ** This parameer is ignored. ** ** event_param The fragment buffer containing the received ** packet. This is passed in as the event ** specific parameter 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. SM is not changed ** here. ** ** OUTPUTS: none ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: rpc_s_ok. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL unsigned32 discard_fragment_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct ATTRIBUTE_UNUSED, pointer_t event_param, pointer_t sm ATTRIBUTE_UNUSED ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { rpc_cn_fragbuf_p_t fragbuf_p; unsigned32 status; RPC_CN_DBG_RTN_PRINTF(SERVER discard_fragment_action_rtn); fragbuf_p = (rpc_cn_fragbuf_p_t) event_param; (* fragbuf_p->fragbuf_dealloc) (fragbuf_p); status = rpc_s_ok; return (status); } /* **++ ** ** ROUTINE NAME: call_end_action_rtn ** ** SCOPE: INTERNAL ** ** DESCRIPTION: ** ** Handle the call end event. ** ** 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. ** ** 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: none ** **-- **/ INTERNAL unsigned32 call_end_action_rtn #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param ATTRIBUTE_UNUSED, pointer_t sm ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { rpc_cn_call_rep_p_t call_rep; rpc_cn_packet_p_t header_p; unsigned32 status; rpc_cn_sm_ctlblk_t *sm_p; unsigned8 n_state ATTRIBUTE_UNUSED; RPC_CN_DBG_RTN_PRINTF(SERVER call_end_action_rtn); sm_p = (rpc_cn_sm_ctlblk_t *)sm; /* * If state is call_request_state (1+rpc_c_cn_statebase), we * need to use the alerted_pred_rtn function. * If the state is call_response * (2+rpc_c_cn_statebase), then we use no predicate routine. * The value of the state is augmented with rpc_c_cn_statebase in * order to quickly distinguish it from action routine indexes * in the rpc_cn_sm_event_eval() routine. */ if (sm_p->cur_state == ( 1 + RPC_C_CN_STATEBASE )) { ALERTED_PRED(spc_struct, status); if ( status == 1) { sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED; } else { /* No action required here. */ sm_p->cur_state = RPC_C_SM_NO_NSTATE; return (status); } } /* end of call_request_state */ else if(sm_p->cur_state == ( 2 + RPC_C_CN_STATEBASE )) sm_p->cur_state = RPC_C_SERVER_CALL_CALL_COMPLETED; status = rpc_s_ok; call_rep = (rpc_cn_call_rep_p_t) spc_struct; /* * If this is not a maybe call; i.e., there is a cached * protocol header, and we have not call call_end to * clean up after some error condition; * then send the last fragment. * Note that if there is no stub data, we will still * send a header with the last_frag_bit set. */ if (((RPC_CN_CREP_IOV (call_rep)[0]).data_len) != 0) { header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG; /* * Update the alert_pending state and stop accepting * forwarded cancels. */ RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(call_end_action_rtn) call_rep->%x setting alert count (%d) in packet header\n", call_rep, call_rep->u.server.cancel.local_count)); RPC_CN_PKT_ALERT_COUNT (header_p) = call_rep->u.server.cancel.local_count; RPC_CALL_LOCK (((rpc_call_rep_t *) call_rep)); if (call_rep->common.u.server.cancel.had_pending) { RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(call_end_action_rtn) call_rep->%x setting alert pending bit in packet header\n", call_rep)); RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_ALERT_PENDING; } RPC_CALL_UNLOCK (((rpc_call_rep_t *) call_rep)); /* * Don't transmit if orphaned. */ if (call_rep->cn_call_status != rpc_s_call_orphaned) { rpc__cn_transmit_buffers (call_rep, &status); } rpc__cn_dealloc_buffered_data (call_rep); /* * Set the length of the iovector to be 1 (just the * protocol header); everything else has been * deallocated. * * Note that we don't use the FREE_ALL_EXCEPT_PROT_HEADER * macro from cnxfer.c since we know that we won't be * queueing more data. */ RPC_CN_CREP_IOVLEN (call_rep) = 1; } return (status); } /* **++ ** ** ROUTINE NAME: rpc__cn_call_sm_protocol_error ** ** SCOPE: PRIVATE ** ** DESCRIPTION: ** ** Action routine invoked when an illegal transition is detected. ** This routine writes an error message to stdout and DIEs. ** ** INPUTS: ** ** spc_struct The special structure which is passed to the ** state machine event evaluation routine. ** This is assumed to be the call rep. ** ** event_param The event specific argument. ** ** INPUTS/OUTPUTS: none ** ** 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: unsigned32 ** ** SIDE EFFECTS: output is printed on stdout. ** **-- **/ PRIVATE unsigned32 rpc__cn_call_sm_protocol_error #ifdef _DCE_PROTO_ ( pointer_t spc_struct, pointer_t event_param ATTRIBUTE_UNUSED, pointer_t sm ) #else (spc_struct, event_param, sm) pointer_t spc_struct; pointer_t event_param; pointer_t sm; #endif { rpc_cn_call_rep_p_t call_rep; unsigned32 status ATTRIBUTE_UNUSED; rpc_cn_sm_ctlblk_t *sm_p; RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_sm_protocol_error); sm_p = (rpc_cn_sm_ctlblk_t *)sm; sm_p->cur_state = RPC_C_SM_NO_NSTATE; call_rep = (rpc_cn_call_rep_p_t) spc_struct; /* * "Illegal state transition detected in CN {client|server} call state * machine [cur_state: %d, cur_event: %d, call_rep: %x]" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%d%d%x"), rpc_svc_cn_state, svc_c_sev_fatal | svc_c_action_abort, RPC_CALL_IS_SERVER( (rpc_call_rep_t *)call_rep ) ? rpc_m_cn_ill_state_trans_sr : rpc_m_cn_ill_state_trans_cr, call_rep->call_state.cur_state, call_rep->call_state.cur_event, call_rep )); /* FIXME: is this correct? */ return rpc_s_ok; }