void rpc_ss_rundown_client ( /* [in] */ rpc_client_handle_t failed_client ) { error_status_t result; callee_client_entry_t *this_client; callee_context_entry_t *this_context; rpc_client_handle_t close_client = NULL; /* NULL or client to stop monitoring */ /* FIXME: is the volatility set correctly here? */ rpc_ss_rundown_list_elt * volatile rundown_list; rpc_ss_rundown_list_elt * volatile rundown_elt; rundown_list = NULL; #ifdef PERFMON RPC_SS_RUNDOWN_CLIENT_N; #endif RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); DPRINT(("Seized context tables\n")); for( this_client = &client_table[HASH_CLIENT_ID(failed_client)]; (this_client != NULL) && (close_client == NULL); this_client = this_client->next_h_client ) { if (this_client->client == failed_client) { while (this_client->ref_count != 0) { this_client->rundown_pending = idl_true; RPC_SS_THREADS_CONDITION_WAIT(&this_client->cond_var, &rpc_ss_context_table_mutex); /* Mutex has been released */ RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); } if (this_client->count == 0) { /* The manager closed the contexts while a rundown was pending */ rpc_ss_ctx_remove_client_entry(this_client); RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); #ifdef PERFMON RPC_SS_RUNDOWN_CLIENT_X; #endif return; } /* Need to clear the rundown pending flag so that the client entry can be deleted */ this_client->rundown_pending = idl_false; while (close_client == NULL) { /* Loop until all contexts for this client have been removed from the context table. Note that each iteration brings a different context to first_context position */ this_context = this_client->first_context; rundown_elt = (rpc_ss_rundown_list_elt *) malloc(sizeof(rpc_ss_rundown_list_elt)); if (rundown_elt == NULL) { RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); /* * rpc_m_ctxrundown_nomem * "Out of memory while trying to run down contexts of client %x" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%x"), rpc_svc_libidl, svc_c_sev_error, rpc_m_ctxrundown_nomem, this_client )); return; } rundown_elt->rundown = this_context->rundown; rundown_elt->user_context = this_context->user_context; rundown_elt->next = rundown_list; rundown_list = rundown_elt; rpc_ss_lkddest_callee_context (&this_context->uuid,&close_client,&result); } } } RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); while (rundown_list != NULL) { if (rundown_list->rundown != NULL) { DCETHREAD_TRY (*(rundown_list->rundown))(rundown_list->user_context); DCETHREAD_CATCH_ALL(caught) /* * rpc_m_ctxrundown_exc * "Exception in routine at %x, running down context %x of client %x" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%x%x%x"), rpc_svc_libidl, svc_c_sev_error, rpc_m_ctxrundown_exc, rundown_list->rundown, rundown_list->user_context, this_client )); DCETHREAD_ENDTRY } rundown_elt = rundown_list; rundown_list = rundown_list->next; free(rundown_elt); }
PRIVATE void rpc__cn_call_executor (pointer_t arg, boolean32 call_was_queued ATTRIBUTE_UNUSED) { rpc_binding_rep_t *binding_r; rpc_cn_call_rep_t *call_r; rpc_iovector_t iovector; dce_uuid_t type_uuid; rpc_mgr_epv_t manager_epv; rpc_v2_server_stub_epv_t server_stub_epv; rpc_if_rep_p_t if_spec_rep; unsigned32 flags; unsigned32 max_calls; unsigned32 max_rpc_size; rpc_if_callback_fn_t if_callback; unsigned32 status; RPC_LOG_CN_CTHD_NTR; RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, ("CN: call_rep->%x call executor running ... %s queued\n", arg, (call_was_queued ? "WAS" : "WAS NOT"))); /* * The arg passed in is really a call rep. */ call_r = (rpc_cn_call_rep_t *) arg; /* * Release the call rep lock which was acquired for us in the * common code. */ RPC_CALL_UNLOCK ((rpc_call_rep_t *) call_r); /* * If there is an object uuid, see if there's a type uuid * associated with it. */ rpc_object_inq_type (&call_r->binding_rep->obj, &type_uuid, &status); if ((status != rpc_s_object_not_found) && (status != rpc_s_ok)) { RPC_CALL_LOCK ((rpc_call_rep_t *) call_r); rpc__cthread_cancel_caf ((rpc_call_rep_t *) call_r); RPC_CALL_UNLOCK ((rpc_call_rep_t *) call_r); RPC_CN_LOCK (); rpc__cn_call_reject ((rpc_call_rep_p_t) call_r, status); RPC_CN_UNLOCK (); goto CLEANUP; } /* * Get the if rep and the server stub and manager EPV. */ rpc__if_lookup2 (call_r->u.server.if_id, call_r->u.server.if_vers, &type_uuid, &call_r->u.server.ihint, &if_spec_rep, &server_stub_epv, &manager_epv, &flags, &max_calls, &max_rpc_size, &if_callback, &status); if (status != rpc_s_ok) { RPC_CALL_LOCK ((rpc_call_rep_t *) call_r); rpc__cthread_cancel_caf ((rpc_call_rep_t *) call_r); RPC_CALL_UNLOCK ((rpc_call_rep_t *) call_r); RPC_CN_LOCK (); rpc__cn_call_reject ((rpc_call_rep_p_t) call_r, status); RPC_CN_UNLOCK (); goto CLEANUP; } /* * If the operation number is out of range, indicate a fault to * the protocol service, otherwise process the incoming packet(s). */ if (call_r->opnum >= if_spec_rep->opcnt) { RPC_CALL_LOCK ((rpc_call_rep_t *) call_r); rpc__cthread_cancel_caf ((rpc_call_rep_t *) call_r); RPC_CALL_UNLOCK ((rpc_call_rep_t *) call_r); RPC_CN_LOCK (); rpc__cn_call_reject ((rpc_call_rep_p_t) call_r, rpc_s_op_rng_error); RPC_CN_UNLOCK (); goto CLEANUP; } /* * Receive the first packet. */ rpc__cn_call_receive ((rpc_call_rep_t *) call_r, &iovector.elt[0], &status); if (status != rpc_s_ok) { RPC_CALL_LOCK ((rpc_call_rep_t *) call_r); rpc__cthread_cancel_caf ((rpc_call_rep_t *) call_r); RPC_CALL_UNLOCK ((rpc_call_rep_t *) call_r); RPC_CN_LOCK (); rpc__cn_call_reject ((rpc_call_rep_p_t) call_r, rpc_s_op_rng_error); RPC_CN_UNLOCK (); goto CLEANUP; } /* * Mark the call as having executed. */ call_r->call_executed = true; /* * Enable posting of cancels to this call executor thread. * This will also post any queued cancels. */ RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, ("(rpc__cn_call_executor) call_rep->%x enabling posting of cancels and posting any queued cancels\n", call_r)); RPC_CALL_LOCK ((rpc_call_rep_t *) call_r); rpc__cthread_cancel_enable_post ((rpc_call_rep_p_t) call_r); RPC_CALL_UNLOCK ((rpc_call_rep_t *) call_r); /* * Dispatch appropriately depending on the stub version. */ switch (if_spec_rep->stub_rtl_if_vers) { /* * If this is an old v0 or v1 stub runtime interface * then do the dirty work out of line. */ case 0: case 1: /* * rpc_m_pre_v2_ifspec * "(%s) Pre-v2 interface spec" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%s"), rpc_svc_server_call, svc_c_sev_fatal | svc_c_action_abort, rpc_m_pre_v2_ifspec, "rpc__cn_call_executor" )); break; /* * This is the v2 (new) stub runtime interface. */ case 2: RPC_LOG_SERVER_STUB_PRE; ((*server_stub_epv[call_r->opnum])) ((handle_t) call_r->binding_rep, (rpc_call_handle_t) call_r, &iovector.elt[0], &(RPC_CN_ASSOC_NDR_FORMAT (call_r->assoc)), &call_r->transfer_syntax, manager_epv, &status); RPC_LOG_SERVER_STUB_POST; break; /* * Unknown version */ default: /* * rpc_m_unk_ifspec * "(%s) Unknown interface spec version" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%s"), rpc_svc_server_call, svc_c_sev_fatal | svc_c_action_abort, rpc_m_pre_v2_ifspec, "rpc__cn_call_executor" )); break; } /* * Check for an error while in the server stub but before the * manager routine was entered. */ if (status != rpc_s_ok) { RPC_CALL_LOCK ((rpc_call_rep_t *) call_r); rpc__cthread_cancel_caf ((rpc_call_rep_t *) call_r); RPC_CALL_UNLOCK ((rpc_call_rep_t *) call_r); RPC_CN_LOCK (); rpc__cn_call_reject ((rpc_call_rep_p_t) call_r, status); RPC_CN_UNLOCK (); goto CLEANUP; } /* * If the stub returned successfully, end the call and free the binding handle. */ binding_r = (rpc_binding_rep_t *) call_r->binding_rep; RPC_CALL_LOCK ((rpc_call_rep_t *) call_r); rpc__cthread_cancel_caf ((rpc_call_rep_t *) call_r); RPC_CALL_UNLOCK ((rpc_call_rep_t *) call_r); CLEANUP: binding_r = (rpc_binding_rep_t *) call_r->binding_rep; rpc__cn_call_end ((rpc_call_rep_p_t *) &call_r, &status); RPC_LOCK (0); RPC_BINDING_RELEASE (&binding_r, &status); RPC_UNLOCK (0); RPC_LOG_CN_CTHD_XIT; }
PRIVATE void rpc__cn_unpack_hdr ( rpc_cn_packet_p_t pkt_p ) { rpc_cn_auth_tlr_p_t authp; /* ptr to pkt authentication data */ rpc_cn_pres_cont_list_p_t pconp; /* ptr to pkt presentation context lists */ rpc_cn_pres_result_list_p_t presp; /* ptr to pkt presentation result lists */ rpc_cn_port_any_p_t secadrp; /* ptr to pkt secondary address data */ rpc_cn_versions_supported_p_t versp; /* ptr to pkt versions supported data */ unsigned8 *drepp; /* ptr to pkt drep[] data */ boolean swap; /* boolean says we swap bytes/words */ boolean authenticate; /* boolean says authentication data is valid */ boolean has_uuid; /* boolean says an OBJECT uuid is present */ unsigned32 st; /* status variable */ /* * Get the DREP and see if we need to do byte/word swapping. */ drepp = RPC_CN_PKT_DREP (pkt_p); swap = (NDR_DREP_INT_REP (drepp) != NDR_LOCAL_INT_REP); /* * RPC_CN_COMMON_HDR_T * * Unpack the common part of the packet header. */ if (swap) { SWAB_INPLACE_16 (RPC_CN_PKT_FRAG_LEN (pkt_p)); SWAB_INPLACE_16 (RPC_CN_PKT_AUTH_LEN (pkt_p)); SWAB_INPLACE_32 (RPC_CN_PKT_CALL_ID (pkt_p)); } /* * See if the authentication data is valid. */ authenticate = RPC_CN_PKT_AUTH_LEN(pkt_p) != 0; authp = NULL; /* * Check for the presence of an OBJECT uuid. */ has_uuid = (RPC_CN_PKT_FLAGS (pkt_p) & RPC_C_CN_FLAGS_OBJECT_UUID) != 0; /* * Unpack the packet-type specific part of the packet. We also find the * start of the authentication data if there is any. */ switch (RPC_CN_PKT_PTYPE (pkt_p)) { /* * RPC_CN_BIND_HDR_T */ case RPC_C_CN_PKT_BIND: case RPC_C_CN_PKT_ALTER_CONTEXT: if (swap) { SWAB_INPLACE_16 (RPC_CN_PKT_MAX_XMIT_FRAG (pkt_p)); SWAB_INPLACE_16 (RPC_CN_PKT_MAX_RECV_FRAG (pkt_p)); SWAB_INPLACE_32 (RPC_CN_PKT_ASSOC_GROUP_ID (pkt_p)); } pconp = (rpc_cn_pres_cont_list_p_t)((unsigned8 *)(&RPC_CN_PKT_ASSOC_GROUP_ID (pkt_p)) + 4); authp = unpack_pres_context_list (pconp, swap); break; /* * RPC_CN_BIND_ACK_HDR_T */ case RPC_C_CN_PKT_BIND_ACK: case RPC_C_CN_PKT_ALTER_CONTEXT_RESP: if (swap) { SWAB_INPLACE_16 (RPC_CN_PKT_MAX_XMIT_FRAG (pkt_p)); SWAB_INPLACE_16 (RPC_CN_PKT_MAX_RECV_FRAG (pkt_p)); SWAB_INPLACE_32 (RPC_CN_PKT_ASSOC_GROUP_ID (pkt_p)); } secadrp = (rpc_cn_port_any_t *) ((unsigned8 *)(pkt_p) + RPC_CN_PKT_SIZEOF_BIND_ACK_HDR); presp = unpack_port_any (secadrp, drepp); force_alignment (4, (unsigned8 **)&presp); authp = unpack_pres_result_list (presp, swap); break; /* * RPC_CN_BIND_NACK_HDR_T */ case RPC_C_CN_PKT_BIND_NAK: if (swap) { SWAB_INPLACE_16 (RPC_CN_PKT_PROV_REJ_REASON (pkt_p)); } versp = &RPC_CN_PKT_VERSIONS (pkt_p); authp = unpack_versions_supported (versp); break; /* * RPC_CN_REQUEST_HDR_T */ case RPC_C_CN_PKT_REQUEST: if (swap) { SWAB_INPLACE_32 (RPC_CN_PKT_ALLOC_HINT (pkt_p)); SWAB_INPLACE_16 (RPC_CN_PKT_PRES_CONT_ID (pkt_p)); SWAB_INPLACE_16 (RPC_CN_PKT_OPNUM (pkt_p)); if (has_uuid) { SWAB_INPLACE_UUID (RPC_CN_PKT_OBJECT (pkt_p)); } } authp = end_of_stub_data (pkt_p); break; /* * RPC_CN_RESPONSE_HDR_T */ case RPC_C_CN_PKT_RESPONSE: if (swap) { SWAB_INPLACE_32 (RPC_CN_PKT_ALLOC_HINT (pkt_p)); SWAB_INPLACE_16 (RPC_CN_PKT_PRES_CONT_ID (pkt_p)); } authp = end_of_stub_data (pkt_p); break; /* * RPC_CN_FAULT_HDR_T */ case RPC_C_CN_PKT_FAULT: if (swap) { SWAB_INPLACE_32 (RPC_CN_PKT_ALLOC_HINT (pkt_p)); SWAB_INPLACE_16 (RPC_CN_PKT_PRES_CONT_ID (pkt_p)); SWAB_INPLACE_32 (RPC_CN_PKT_STATUS (pkt_p)); } authp = end_of_stub_data (pkt_p); break; /* * RPC_CN_AUTH3_HDR_T */ case RPC_C_CN_PKT_SHUTDOWN: case RPC_C_CN_PKT_AUTH3: case RPC_C_CN_PKT_REMOTE_ALERT: case RPC_C_CN_PKT_ORPHANED: break; default: /* "(%s) Illegal or unknown packet type: %x\n" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%s%x"), rpc_svc_cn_pkt, svc_c_sev_warning, rpc_m_bad_pkt_type, "rpc__cn_unpack_hdr", RPC_CN_PKT_PTYPE(pkt_p) )); return; } /* * Unpack the authentication part of the packet if it exists. */ if (authenticate && swap) { switch (RPC_CN_PKT_PTYPE (pkt_p)) { case RPC_C_CN_PKT_BIND: case RPC_C_CN_PKT_ALTER_CONTEXT: case RPC_C_CN_PKT_BIND_ACK: case RPC_C_CN_PKT_ALTER_CONTEXT_RESP: case RPC_C_CN_PKT_BIND_NAK: case RPC_C_CN_PKT_AUTH3: { #ifdef DEBUG char *p; #endif rpc_authn_protocol_id_t authn_protocol; authp = RPC_CN_PKT_AUTH_TLR (pkt_p, RPC_CN_PKT_FRAG_LEN (pkt_p)); #ifdef DEBUG p = (char *)authp; force_alignment(4, (unsigned8 **)&authp); if (p != (char *)authp) { /* * rpc_m_unalign_authtrl * "(%s) Unaligned RPC_CN_PKT_AUTH_TRL" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%s"), rpc_svc_cn_pkt, svc_c_sev_fatal | svc_c_action_abort, rpc_m_unalign_authtrl, "rpc__cn_unpack_hdr" )); } #endif SWAB_INPLACE_32(authp->key_id); authn_protocol = RPC_CN_AUTH_CVT_ID_WIRE_TO_API (authp->auth_type, &st); if (st == rpc_s_ok) { RPC_CN_AUTH_TLR_UNPACK (authn_protocol, pkt_p, RPC_CN_PKT_AUTH_LEN (pkt_p), drepp); } break; } default: /* * We do not need the auth trailer of the other packet * types since they are thrown away after recv_check. * So don't bother to unpack them in these cases. */ break; } } }