1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME 80** 81** cncall.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** The NCA Connection Protocol Service's Call Service. 90** 91** 92*/ 93 94#include <commonp.h> /* Common declarations for all RPC runtime */ 95#include <com.h> /* Common communications services */ 96#include <comprot.h> /* Common protocol services */ 97#include <ndrglob.h> /* NDR representation global declarations */ 98#include <ndrp.h> /* NDR system dependent definitions */ 99#include <cnp.h> /* NCA Connection private declarations */ 100#include <cnbind.h> /* NCA connection binding service */ 101#include <cnsm.h> /* NCA Connection generic state machine operations */ 102#include <cnclsm.h> /* NCA Connection client call state machine */ 103#include <cnpkt.h> /* NCA Connection protocol header */ 104#include <cnassoc.h> /* NCA Connection association services */ 105#include <cnfbuf.h> /* NCA Connection fragment buffer routines */ 106#include <cnxfer.h> /* NCA Connection data transfer routines */ 107#include <comtwr.h> /* Externals for Towers sub-component */ 108#include <comtwrref.h> /* tower defs for other RPC components */ 109#include <dce/ep.h> /* rpcd endpoint (ep) interface definitions */ 110#include <cncall.h> 111 112/* 113 * Macro to test for a cancel every so often for a cancel. The 114 * num_pkts field of the call rep is cleared when the first frag is 115 * sent. It is incremented on every subsequent transmitted or received 116 * fragment. 117 */ 118#define RPC_CN_CANCEL_CHECK_FREQ 8 119#define RPC_CN_CHECK_FOR_CANCEL(call_r) \ 120{ \ 121 if ((call_r)->num_pkts & RPC_CN_CANCEL_CHECK_FREQ) \ 122 { \ 123 rpc__cn_call_check_for_cancel (call_r);\ 124 } \ 125} 126 127/* 128 * Macro to forward, if the first frag has been sent, and queued 129 * cancels. 130 */ 131#define RPC_CN_FORWARD_QUEUED_CANCELS(call_r, st) \ 132{ \ 133 if ((call_r)->u.client.cancel.local_count) \ 134 { \ 135 rpc__cn_call_forward_cancel (call_r, st); \ 136 } \ 137} 138 139/* 140 * Macro to check for a pending cancel and forward, if the first frag 141 * has been sent, that cancel and any queued cancels. 142 */ 143#define RPC_CN_CHK_AND_FWD_CANCELS(call_r, st) \ 144{ \ 145 RPC_CN_CHECK_FOR_CANCEL (call_r); \ 146 RPC_CN_FORWARD_QUEUED_CANCELS (call_r, st); \ 147} 148 149INTERNAL unsigned32 rpc__cn_call_cvt_from_nca_st ( 150 unsigned32 /*a_st*/ 151 ); 152 153INTERNAL unsigned32 rpc__cn_call_cvt_to_nca_st ( 154 unsigned32 /*l_st*/ 155 ); 156 157INTERNAL void rpc__cn_call_check_for_cancel ( 158 rpc_cn_call_rep_p_t /*call_rep*/ 159 ); 160 161INTERNAL void rpc__cn_call_forward_cancel ( 162 rpc_cn_call_rep_p_t /*call_rep*/, 163 unsigned32 * /*status*/ 164 ); 165 166INTERNAL void rpc__cn_call_binding_serialize ( 167 rpc_binding_rep_p_t /*binding_r*/, 168 rpc_clock_t /*cancel_timeout*/, 169 unsigned32 * /*cancel_cnt*/, 170 unsigned32 * /*st*/ 171 ); 172 173INTERNAL boolean rpc__cn_call_cancel_timer ( 174 rpc_cn_call_rep_p_t /*call_r*/ 175 ); 176 177/***********************************************************************/ 178 179/* 180**++ 181** 182** ROUTINE NAME: rpc__cn_call_start 183** 184** SCOPE: PRIVATE - declared in cncall.h 185** 186** DESCRIPTION: 187** 188** This is the NCA connection oriented protocol specific routine 189** which begins a remote procedure call. It returns the information 190** needed to marshal input arguments. This routine is intended 191** for use by the client stub only. 192** 193** INPUTS: 194** 195** binding_r The binding rep containing the location of 196** the server. 197** call_options The options pertaining to this RPC. 198** ifspec_r The interface specification rep data structure 199** describing the interface to which the RPC belongs. 200** opnum The operation number of the RPC in the 201** interface. 202** 203** INPUTS/OUTPUTS: none 204** 205** OUTPUTS: 206** 207** transfer_syntax The negotiated transfer syntax for this RPC. 208** 209** st The return status of this routine. 210** rpc_s_ok The call was successful. 211** rpc_s_invalid_call_opt An invalid call option was specified. 212** 213** IMPLICIT INPUTS: none 214** 215** IMPLICIT OUTPUTS: none 216** 217** FUNCTION VALUE: 218** 219** call_rep The call rep. 220** 221** SIDE EFFECTS: none 222** 223**-- 224**/ 225 226PRIVATE rpc_call_rep_t *rpc__cn_call_start 227( 228 rpc_binding_rep_p_t binding_r, 229 unsigned32 call_options, 230 rpc_if_rep_p_t ifspec_r, 231 unsigned32 opnum, 232 rpc_transfer_syntax_t *transfer_syntax, 233 unsigned32 *st 234) 235{ 236 rpc_cn_call_rep_t *call_rep; 237 rpc_iovector_elt_p_t iov_p; 238 rpc_cn_packet_p_t header_p; 239 unsigned32 cancel_count = 0; 240 rpc_clock_t cancel_timeout = 0; 241 unsigned32 temp_st; 242 dcethread* current_thread_id; 243 boolean resolving_thread; 244 245 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_start); 246 RPC_LOG_CN_CALL_START_NTR; 247 CODING_ERROR (st); 248 249 /* 250 * If this call requires security, verify that the caller's 251 * credentials are valid right now. If they aren't, try to refresh 252 * them. If they can't be refreshed return an error. We do this 253 * now while there are no locks taken out. The CRED_REFRESH 254 * operation may make an RPC to the security server which will 255 * require the RPC locks to be taken out. This would result in a 256 * deadlock if we had any RPC locks taken out now. 257 * 258 * It is the responsibility of the authentication protocol to 259 * serialize access to the auth info structure. For example the 260 * Kerberos auth protocol uses a lock per auth_info structure to 261 * protect it (the krb_info_lock). 262 * 263 * XXX is there a deadlock here? See Transarc Defect 17575 264 * http://vcs.es.net/DCCC/DCEWG/DCE-1.1_Patch16.txt 265 */ 266 if (RPC_CN_AUTH_REQUIRED (binding_r->auth_info)) 267 { 268 /* 269 * The binding has an auth info structure hanging off it, 270 * which indicates this call is to be authenticated. 271 */ 272 RPC_CN_AUTH_CRED_REFRESH (binding_r->auth_info, 273 st); 274 if (*st != rpc_s_ok) 275 { 276 return (NULL); 277 } 278 } 279 280 /* 281 * Acquire the CN global mutex to prevent other threads from 282 * running. 283 */ 284 RPC_CN_LOCK (); 285 286 /* 287 * The broadcast call option and callbacks are not supported by the 288 * connection oriented protocol services. 289 * We detect callbacks by checking the binding to see if it is 290 * that of a server. 291 */ 292 if (call_options & rpc_c_call_brdcst) 293 { 294 *st = rpc_s_invalid_call_opt; 295 RPC_CN_UNLOCK (); 296 return (NULL); 297 } 298 299 if (binding_r->is_server) 300 { 301 *st = rpc_s_wrong_kind_of_binding; 302 RPC_CN_UNLOCK (); 303 return (NULL); 304 } 305 306 /* 307 * Get the thread's cancel timeout value (so we don't block forever). 308 */ 309 RPC_GET_CANCEL_TIMEOUT (cancel_timeout, st); 310 if (*st != rpc_s_ok) 311 { 312 RPC_CN_UNLOCK (); 313 return (NULL); 314 } 315 316 /* 317 * Check to see if we're currently resolving a binding. 318 */ 319 if (((rpc_cn_binding_rep_t *)binding_r)->being_resolved) 320 { 321 current_thread_id = dcethread_self (); 322 resolving_thread = dcethread_equal 323 (((rpc_cn_binding_rep_t *)binding_r)->resolving_thread_id, 324 current_thread_id); 325 if (!resolving_thread) 326 { 327 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 328 ("CN: call_rep->none waiting on binding resolution\n")); 329 /* 330 * Serialize calls on this binding handle until the handle 331 * has an endpoint. 332 */ 333 RPC_BINDING_CALL_START ((rpc_binding_rep_t *) binding_r); 334 335 rpc__cn_call_binding_serialize (binding_r, 336 cancel_timeout, 337 &cancel_count, 338 st); 339 RPC_BINDING_CALL_END (binding_r); 340 if (*st != rpc_s_ok) 341 { 342 /* 343 * The cancel timeout probably expired. 344 */ 345 RPC_CN_UNLOCK (); 346 return (NULL); 347 } 348 } 349 } 350 else 351 { 352 /* 353 * Check to see if we have a fully bound handle, i.e., 354 * the endpoint information is present. 355 * If not, call rpc_ep_resolve_binding. 356 */ 357 if (!binding_r->addr_has_endpoint) 358 { 359 /* 360 * The binding handle is partially bound. Prevent other 361 * threads from using it in a call until it is fully bound. 362 */ 363 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 364 ("CN: call_rep->none partially bound binding handle\n")); 365 366 RPC_BINDING_CALL_START ((rpc_binding_rep_t *) binding_r); 367 ((rpc_cn_binding_rep_t *)binding_r)->being_resolved = true; 368 ((rpc_cn_binding_rep_t *)binding_r)->resolving_thread_id = dcethread_self (); 369 370 RPC_CN_UNLOCK (); 371 rpc_ep_resolve_binding ((rpc_binding_handle_t) binding_r, 372 (rpc_if_handle_t) ifspec_r, st); 373 RPC_CN_LOCK (); 374 ((rpc_cn_binding_rep_t *)binding_r)->being_resolved = false; 375 376 /* 377 * Let other threads use the binding handle now. 378 */ 379 RPC_BINDING_CALL_END (binding_r); 380 if (binding_r->calls_in_progress) 381 { 382 RPC_BINDING_COND_BROADCAST (0); 383 } 384 385 /* 386 * If the attempt to resolve the binding handle was 387 * unsuccessful return. 388 */ 389 if (*st != rpc_s_ok) 390 { 391 RPC_CN_UNLOCK (); 392 return (NULL); 393 } 394 } 395 } 396 397 /* 398 * At this point, we have a fully-bound binding. 399 * We can now allocate a call_rep. 400 */ 401 call_rep = (rpc_cn_call_rep_p_t) 402 rpc__list_element_alloc (&rpc_g_cn_call_lookaside_list, true); 403 if (call_rep == NULL) 404 { 405 RPC_CN_UNLOCK (); 406 *st = rpc_s_no_memory; 407 return (NULL); 408 } 409 410 /* 411 * Mark it as a client call rep. 412 */ 413 call_rep->common.is_server = false; 414 call_rep->prot_tlr = NULL; 415 416 /* 417 * Clear out the io vectors 418 */ 419 { 420 int i; 421 for( i=1; i<RPC_C_MAX_IOVEC_LEN; i++ ) { 422 call_rep->buffered_output.iov.elt[i].buff_addr = NULL; 423 call_rep->buffered_output.iov.elt[i].buff_dealloc = NULL; 424 } 425 } 426 427 /* 428 * Start off in the initial state. 429 */ 430 rpc__cn_sm_init (rpc_g_cn_client_call_sm, 431 rpc_g_cn_client_call_action_tbl, 432 &(call_rep->call_state), 433 rpc_c_cn_cl_call); 434 call_rep->call_state.cur_state = RPC_C_CLIENT_CALL_INIT; 435 436 /* 437 * Init security info 438 */ 439 call_rep->sec = NULL; 440 441 /* 442 * Init the association in case allocating it later in this function 443 * fails. 444 */ 445 call_rep->assoc = NULL; 446 447 /* 448 * Init some booleans. 449 */ 450 call_rep->cn_call_status = rpc_s_ok; 451 call_rep->last_frag_received = false; 452 call_rep->call_executed = false; 453 454 /* 455 * Initialize some cancel state information. 456 */ 457 call_rep->u.client.cancel.server_is_accepting = false; 458 call_rep->u.client.cancel.server_had_pending = false; 459 call_rep->u.client.cancel.server_count = 0; 460 461 /* 462 * Initialize the fault fragbuf pointer to NULL. 463 */ 464 call_rep->u.client.fault_data = NULL; 465 466 /* 467 * Initialize alloc_hint to 0 468 */ 469 call_rep->alloc_hint = 0; 470 471 /* 472 * Include any cancels detected while serializing access to the 473 * binding handle. These will be forwarded when the first 474 * request fragment is sent. The absolute cancel timeout time 475 * left for this thread was gotten by RPC_GET_CANCEL_TIMEOUT. 476 */ 477 call_rep->u.client.cancel.local_count = cancel_count; 478 call_rep->u.client.cancel.timeout_time = cancel_timeout; 479 call_rep->u.client.cancel.timer_running = false; 480 if (cancel_count) 481 { 482 /* 483 * Start a cancel timer. We won't bother checking the status 484 * here because there is no timer running yet and no 485 * association set up yet. 486 */ 487 rpc__cn_call_start_cancel_timer (call_rep, st); 488 } 489 490 /* 491 * Save the binding rep in the call rep for use in an action routine. 492 */ 493 call_rep->binding_rep = binding_r; 494 495 /* 496 * Store the address of the fragment buffer in the 497 * call rep. 498 */ 499 header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); 500 501 RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_REQUEST; 502 RPC_CN_PKT_FLAGS (header_p) = RPC_C_CN_FLAGS_FIRST_FRAG; 503 if (call_options & rpc_c_call_maybe) 504 { 505 RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_MAYBE; 506 } 507 RPC_CN_PKT_ALERT_COUNT(header_p) = 0; 508 RPC_CN_PKT_FRAG_LEN (header_p) = 0; 509 RPC_CN_PKT_CALL_ID (header_p) = rpc_g_cn_call_id++; 510 RPC_CN_PKT_OPNUM (header_p) = opnum; 511 512 /* 513 * Initialize the iovector in the call_rep to contain only 514 * one initial element, pointing to the protocol header. 515 * Also, update pointers to show that we can copy data into 516 * the stub data area. 517 */ 518 RPC_CN_CREP_IOVLEN (call_rep) = 1; 519 RPC_CN_CREP_CUR_IOV_INDX (call_rep) = 0; 520 iov_p = &(RPC_CN_CREP_IOV (call_rep)[0]); 521 522 /* 523 * The start of stub data will depend upon whether the object 524 * UUID field is present. 525 */ 526 if (memcmp (&binding_r->obj, &uuid_g_nil_uuid, sizeof (idl_uuid_t)) != 0) 527 { 528 /* 529 * A non-nil object UUID is present. 530 */ 531 RPC_CN_PKT_OBJECT(header_p) = binding_r->obj; 532 RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_OBJECT_UUID; 533 RPC_CN_CREP_SIZEOF_HDR (call_rep) = RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ; 534 RPC_CN_CREP_FREE_BYTES (call_rep) = 535 RPC_C_CN_SMALL_FRAG_SIZE - RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ; 536 RPC_CN_CREP_ACC_BYTCNT (call_rep) = RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ; 537 RPC_CN_CREP_FREE_BYTE_PTR(call_rep) = 538 RPC_CN_PKT_RQST_STUB_DATA_W_OBJ (header_p); 539 iov_p->data_len = RPC_CN_PKT_SIZEOF_RQST_HDR_W_OBJ; 540 } 541 else 542 { 543 /* 544 * There is no object UUID (it is nil) in the binding rep. 545 */ 546 RPC_CN_CREP_SIZEOF_HDR (call_rep) = RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ; 547 RPC_CN_CREP_FREE_BYTES (call_rep) = 548 RPC_C_CN_SMALL_FRAG_SIZE - RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ; 549 RPC_CN_CREP_ACC_BYTCNT (call_rep) = RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ; 550 RPC_CN_CREP_FREE_BYTE_PTR(call_rep) = 551 RPC_CN_PKT_RQST_STUB_DATA_NO_OBJ (header_p); 552 iov_p->data_len = RPC_CN_PKT_SIZEOF_RQST_HDR_NO_OBJ; 553 } 554 555 /* 556 * Evaluate the RPC_REQUEST event. 557 * If we return successfully, an association should be allocated 558 * and we should be in the call_pending state. 559 */ 560 561 RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_START_CALL, 562 ifspec_r, 563 call_rep, 564 *st); 565 566 if (*st == rpc_s_ok) 567 { 568 /* 569 * Use the presentation context id in the call rep. This was 570 * placed there by the rpc__cn_assoc_alloc routine. 571 */ 572 RPC_CN_PKT_PRES_CONT_ID (header_p) = call_rep->context_id; 573 574 /* 575 * Use the negotiated minor version number from the association. 576 */ 577 RPC_CN_PKT_VERS_MINOR (header_p) = call_rep->assoc->assoc_vers_minor; 578 579 /* 580 * If security is requested for this call an auth trailer will 581 * be formatted here and included with every packet sent. 582 */ 583 if (call_rep->sec != NULL) 584 { 585 rpc_cn_auth_tlr_t *auth_tlr; 586 unsigned32 auth_value_len; 587 588 /* 589 * Allocate a small fragbuf to contain the authentication trailer. 590 */ 591 RPC_CN_FRAGBUF_ALLOC (call_rep->prot_tlr, RPC_C_CN_SMALL_FRAG_SIZE, st); 592 call_rep->prot_tlr->fragbuf_dealloc = NULL; 593 auth_value_len = RPC_C_CN_SMALL_FRAG_SIZE; 594 auth_tlr = (rpc_cn_auth_tlr_t *)call_rep->prot_tlr->data_p; 595 auth_tlr->auth_type = RPC_CN_AUTH_CVT_ID_API_TO_WIRE (call_rep->sec->sec_info->authn_protocol, st); 596 auth_tlr->auth_level = call_rep->sec->sec_info->authn_level; 597 auth_tlr->key_id = call_rep->sec->sec_key_id; 598 auth_tlr->stub_pad_length = 0; 599 auth_tlr->reserved = 0; 600 RPC_CN_AUTH_PRE_CALL (RPC_CN_ASSOC_SECURITY (call_rep->assoc), 601 call_rep->sec, 602 (dce_pointer_t) auth_tlr->auth_value, 603 &auth_value_len, 604 st); 605 RPC_CN_CREP_ADJ_IOV_FOR_TLR (call_rep, header_p, auth_value_len); 606 } 607 else 608 { 609 RPC_CN_PKT_AUTH_LEN (header_p) = 0; 610 } 611 612 /* 613 * Return the negotiated transfer syntax placed in the call 614 * rep by rpc__cn_assoc_alloc. 615 */ 616 *transfer_syntax = call_rep->transfer_syntax; 617 } 618 else 619 { 620 /* 621 * We had a problem. Clean-up using call-end. 622 */ 623 RPC_CN_UNLOCK (); 624 rpc__cn_call_end ((rpc_call_rep_p_t *) &call_rep, &temp_st); 625 RPC_CN_LOCK (); 626 } 627 628 /* 629 * Release the CN global mutex to allow other threads to 630 * run. 631 */ 632 RPC_CN_UNLOCK (); 633 RPC_LOG_CN_CALL_START_XIT; 634 return ((rpc_call_rep_p_t) call_rep); 635} 636 637 638/* 639**++ 640** 641** ROUTINE NAME: rpc__cn_call_transmit 642** 643** SCOPE: PRIVATE - declared in cncall.h 644** 645** DESCRIPTION: 646** 647** This is the NCA connection oriented protocol specific routine 648** to transmit a vector or marshalled arguments to the remote 649** thread. It uses the call rep as the identifier of the RPC 650** being performed. This routine is intended for use by the 651** client or server stub only. 652** 653** INPUTS: 654** 655** call_r The call rep containing information 656** pertaining to this RPC. 657** call_args A vector of buffers containing marshaled RPC 658** arguments. 659** 660** INPUTS/OUTPUTS: none 661** 662** OUTPUTS: 663** 664** st The return status of this routine. 665** rpc_s_ok The call was successful. 666** rpc_s_cancel_timeout 667** After forwarding a local alert, the 668** client timed out waiting for the 669** call to complete. 670** 671** IMPLICIT INPUTS: none 672** 673** IMPLICIT OUTPUTS: none 674** 675** FUNCTION VALUE: none 676** 677** SIDE EFFECTS: none 678** 679**-- 680**/ 681 682PRIVATE void rpc__cn_call_transmit 683( 684 rpc_call_rep_p_t call_r, 685 rpc_iovector_p_t call_args, 686 unsigned32 *st 687) 688{ 689 rpc_cn_call_rep_t *call_rep; 690 rpc_iovector_elt_p_t iov_elt_p; 691 unsigned32 i; 692 rpc_cn_fragbuf_p_t frag_buf; 693 rpc_cn_packet_p_t header_p; 694 unsigned32 fault_code; 695 boolean valid_fragbuf; 696 697 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_transmit); 698 RPC_LOG_CN_CALL_TRANSMIT_NTR; 699 CODING_ERROR (st); 700 701 call_rep = (rpc_cn_call_rep_p_t) call_r; 702 703 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 704 ("CN: call_rep->%p call transmit...\n", 705 call_rep)); 706 707 if (RPC_DBG2 (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT)) 708 { 709 RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT, 710 ("PACKET: call transmit args.num_elt->%d\n", call_args->num_elt)); 711 for (i = 0; i < call_args->num_elt; i++) 712 { 713 RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT, 714 (" elt[%d]: elt.flags->%x args.buff_len->%d args.data_len->%d\n", 715 i, 716 call_args->elt[i].flags, 717 call_args->elt[i].buff_len, 718 call_args->elt[i].data_len)); 719 } 720 } 721 722 /* 723 * Acquire the CN global mutex to prevent other threads from 724 * running. 725 */ 726 RPC_CN_LOCK (); 727 728 /* 729 * The event call_send corresponds to transmit_req on 730 * the client side and rpc_resp on the server side. 731 * 732 * If the call has been orphaned, return rpc_s_call_orphaned 733 * and deallocate any input data. 734 */ 735 if (call_rep->cn_call_status == rpc_s_call_orphaned) 736 { 737 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 738 ("CN: call_rep->%p call orphaned...\n", 739 call_rep)); 740 741 iov_elt_p = call_args->elt; 742 for (i = 1; i <= call_args->num_elt; i++, iov_elt_p++) 743 { 744 if (iov_elt_p->buff_dealloc != NULL) 745 { 746 (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr); 747 } 748 } 749 *st = rpc_s_call_orphaned; 750 } 751 else 752 { 753 RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_SEND, 754 call_args, 755 call_rep, 756 *st); 757 if (((call_rep->call_state.cur_state == RPC_C_CLIENT_CALL_CALL_FAILED) 758 || (call_rep->call_state.cur_state == RPC_C_CLIENT_CALL_CFDNE)) 759 && ((call_rep->call_state.cur_event == RPC_C_CALL_SEND) 760 || (call_rep->call_state.cur_event == RPC_C_CALL_TRANSMIT_REQ) 761 || (call_rep->call_state.cur_event == RPC_C_CALL_LAST_TRANSMIT_REQ))) 762 { 763 valid_fragbuf = false; 764 while (!valid_fragbuf) 765 { 766 rpc__cn_assoc_receive_frag(call_rep->assoc, 767 &frag_buf, 768 st); 769 770 if (*st != rpc_s_ok) 771 { 772 RPC_CN_UNLOCK (); 773 return; 774 } 775 if (frag_buf->data_p != NULL) 776 { 777 valid_fragbuf = true; 778 } 779 } 780 /* 781 * Now adjust data_p to point to just the stub data. 782 * Note that data_size has already been adjusted by 783 * raise_fault_action_rtn 784 */ 785 header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); 786 if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT) 787 { 788 789 frag_buf->data_p = (dce_pointer_t) 790 (RPC_CN_PKT_FAULT_STUB_DATA(header_p)); 791 792 /* 793 * We had conservatively assumed that the call has executed 794 * as soon as the call started. We can now update that 795 * information. 796 */ 797 798 if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_DID_NOT_EXECUTE) 799 { 800 call_rep->call_executed = false; 801 } 802 803 /* 804 * This can be either a call_reject or a call_fault. 805 */ 806 807 fault_code = RPC_CN_PKT_STATUS(header_p); 808 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 809 ("CN: call_rep->%p fault packet received st=%x\n", 810 call_rep, fault_code)); 811 if (fault_code) 812 { 813 /* 814 * Non-zero fault code implies a call_reject. 815 */ 816 817 /* 818 * Deallocate the fragment buffer since we won't be returning 819 * it to the client stub. 820 */ 821 822 (* frag_buf->fragbuf_dealloc) (frag_buf); 823 /* 824 * We translate the on-wire fault code into a local status 825 * and return it. 826 */ 827 *st = rpc__cn_call_cvt_from_nca_st(fault_code); 828 829 /* 830 * Release the CN global mutex to allow other threads to run 831 */ 832 833 RPC_CN_UNLOCK (); 834 return; 835 } 836 else 837 { 838 /* 839 * On a fault, we store the address of the fragment buffer 840 * in the call_rep for later retrieval via 841 * rpc__receive_fault. 842 */ 843 844 call_rep->u.client.fault_data = frag_buf; 845 *st = rpc_s_call_faulted; 846 847 /* 848 * Release the CN global mutex to allow other threads to 849 * run. 850 */ 851 852 RPC_CN_UNLOCK (); 853 return; 854 } 855 } 856 } 857 858 /* 859 * Check for any pending cancels just in case we're in a 860 * long marshalling loop and not calling any cancellable 861 * operations. Also, forward any cancels which may have been 862 * queued already before we were ready to forward them. 863 */ 864 if (RPC_CALL_IS_CLIENT (call_r)) 865 { 866 RPC_CN_CHK_AND_FWD_CANCELS (call_rep, st); 867 } 868 } 869 870 /* 871 * Release the CN global mutex to allow other threads to 872 * run. 873 */ 874 RPC_CN_UNLOCK (); 875 RPC_LOG_CN_CALL_TRANSMIT_XIT; 876} 877 878 879/* 880**++ 881** 882** ROUTINE NAME: rpc__cn_call_transceive 883** 884** SCOPE: PRIVATE - declared in cncall.h 885** 886** DESCRIPTION: 887** 888** This is the NCA connection oriented protocol specific routine 889** to transmit a vector of marshalled arguments to the remote 890** thread. It uses the call rep as the identifier of the RPC 891** being performed. Block until the first buffer of marshalled 892** output arguments has been received. This routine is intended 893** for use by the client stub only. 894** 895** INPUTS: 896** 897** call_r The call rep containing information 898** pertaining to this RPC. 899** in_call_args A vector of buffers containing marshaled RPC 900** input arguments. 901** 902** INPUTS/OUTPUTS: none 903** 904** OUTPUTS: 905** 906** out_call_args A buffer containing marshaled RPC output 907** arguments. 908** remote_ndr_format The Network Data Representation of the 909** server machine. 910** st The return status of this routine. 911** rpc_s_ok The call was successful. 912** rpc_s_call_faulted 913** A fault was received. 914** rpc_s_cancel_timeout 915** After forwarding a local alert, the 916** client timed out waiting for the 917** call to complete. 918** 919** 920** IMPLICIT INPUTS: none 921** 922** IMPLICIT OUTPUTS: none 923** 924** FUNCTION VALUE: none 925** 926** SIDE EFFECTS: none 927** 928**-- 929**/ 930 931PRIVATE void rpc__cn_call_transceive 932( 933 rpc_call_rep_p_t call_r, 934 rpc_iovector_p_t in_call_args, 935 rpc_iovector_elt_t *out_call_args, 936 ndr_format_t *remote_ndr_format, 937 unsigned32 *st 938) 939{ 940 rpc_cn_call_rep_p_t call_rep; 941 rpc_cn_fragbuf_p_t frag_buf; 942 rpc_cn_packet_p_t header_p; 943 rpc_iovector_elt_p_t iov_elt_p; 944 unsigned32 fault_code; 945 unsigned32 i; 946 boolean valid_fragbuf; 947 unsigned32 temp_status; 948 949 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_transceive); 950 RPC_LOG_CN_CALL_TRANSCEIVE_NTR; 951 CODING_ERROR (st); 952 953 call_rep = (rpc_cn_call_rep_p_t) call_r; 954 955 out_call_args->buff_dealloc = NULL; 956 out_call_args->data_addr = (byte_p_t) NULL; 957 out_call_args->data_len = 0; 958 959 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 960 ("CN: call_rep->%p call transceive...\n", 961 call_rep)); 962 963 if (RPC_DBG2 (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT)) 964 { 965 RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT, 966 ("PACKET: call transceive in_args.num_elt->%d\n", in_call_args->num_elt)); 967 for (i = 0; i < in_call_args->num_elt; i++) 968 { 969 RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT, 970 (" elt[%d]: elt.flags->%x in_args.buff_len->%d in_args.data_len->%d\n", 971 i, 972 in_call_args->elt[i].flags, 973 in_call_args->elt[i].buff_len, 974 in_call_args->elt[i].data_len)); 975 } 976 } 977 978 /* 979 * Acquire the CN global mutex to prevent other threads from 980 * running. 981 */ 982 RPC_CN_LOCK (); 983 984 rpc_g_cn_mgmt.calls_sent++; 985 986 /* 987 * If the call has been orphaned, return rpc_s_call_orphaned 988 * and deallocate any input data. 989 */ 990 if (call_rep->cn_call_status == rpc_s_call_orphaned) 991 { 992 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 993 ("CN: call_rep->%p call orphaned...\n", 994 call_rep)); 995 996 out_call_args->buff_dealloc = NULL; 997 out_call_args->data_addr = (byte_p_t) NULL; 998 out_call_args->data_len = 0; 999 1000 /* 1001 * Free the input args. 1002 */ 1003 iov_elt_p = in_call_args->elt; 1004 for (i = 1; i <= in_call_args->num_elt; i++, iov_elt_p++) 1005 { 1006 if (iov_elt_p->buff_dealloc != NULL) 1007 { 1008 (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr); 1009 } 1010 } 1011 *st = rpc_s_call_orphaned; 1012 1013 /* 1014 * Release the CN global mutex to allow other threads to 1015 * run. 1016 */ 1017 RPC_CN_UNLOCK (); 1018 return; 1019 } 1020 1021 /* 1022 * Transmit arguments to remote thread. 1023 * This is the last send fragment. 1024 * Note that we might get NULL data. 1025 */ 1026 RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_LAST_TRANSMIT_REQ, 1027 in_call_args, 1028 call_rep, 1029 temp_status); 1030 1031 if (call_rep->cn_call_status == rpc_s_ok) 1032 { 1033 /* 1034 * Check for any pending cancels just in case we're in a 1035 * long marshalling loop and not calling any cancellable 1036 * operations. Also, forward any cancels which may have been 1037 * queued already before we were ready to forward them. 1038 */ 1039 RPC_CN_CHK_AND_FWD_CANCELS (call_rep, &call_rep->cn_call_status); 1040 1041 /* 1042 * Do a receive if the call does not have maybe semantics. 1043 */ 1044 header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); 1045 if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE) == 0) 1046 { 1047 /* 1048 * If we have already received the last fragment, 1049 * return a null iovector element. 1050 */ 1051 if (call_rep->last_frag_received) 1052 { 1053 out_call_args->buff_dealloc = NULL; 1054 out_call_args->data_addr = (byte_p_t) NULL; 1055 out_call_args->data_len = 0; 1056 } 1057 else 1058 { 1059 /* 1060 * Receive a packet from the association. 1061 * (The receive routine allocates the fragment buffer.) 1062 * Make sure the fragbuf is not left over from an 1063 * orphaned presentation negotiation. 1064 */ 1065 valid_fragbuf = false; 1066 while (!valid_fragbuf) 1067 { 1068 rpc__cn_assoc_receive_frag (call_rep->assoc, 1069 &frag_buf, 1070 st); 1071 1072 if (*st != rpc_s_ok) 1073 { 1074 out_call_args->buff_dealloc = NULL; 1075 out_call_args->data_addr = (byte_p_t) NULL; 1076 out_call_args->data_len = 0; 1077 RPC_CN_UNLOCK (); 1078 return; 1079 } 1080 if (frag_buf->data_p != NULL) 1081 { 1082 valid_fragbuf = true; 1083 } 1084 } 1085 1086 /* 1087 * Set call_rep->last_frag_received if this is the last fragment. 1088 */ 1089 header_p = (rpc_cn_packet_p_t) frag_buf->data_p; 1090 if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) 1091 { 1092 call_rep->last_frag_received = true; 1093 } 1094 1095 /* check to see if las_frag should have been set in this packet or not */ 1096 if ((RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_REQUEST) || 1097 (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT) && 1098 (RPC_CN_PKT_ALLOC_HINT (header_p) != 0) ) 1099 { 1100 /* Request, responses and fault pkts have the alloc_hint that 1101 we can use to check the validity of last frag flag. 1102 Note: alloc_hint field can be 0 */ 1103 if ( (RPC_CN_PKT_ALLOC_HINT (header_p) <= frag_buf->data_size) && 1104 !(RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) ) 1105 { 1106 *st = rpc_s_call_faulted; 1107 1108 /* 1109 * Release the CN global mutex to allow other threads to 1110 * run. 1111 */ 1112 RPC_CN_UNLOCK (); 1113 1114 /* since this is only called by the client side, abort the client 1115 since the client did something invalid */ 1116 rpc_dce_svc_printf ( 1117 __FILE__, __LINE__, 1118 "%s flags 0x%x call id %d alloc_hint %d rcvd data size %d", 1119 rpc_svc_recv, 1120 svc_c_sev_fatal | svc_c_action_abort, 1121 rpc_s_protocol_error, 1122 "rpc__cn_call_transceive - last frag should be set", 1123 RPC_CN_PKT_FLAGS (header_p), 1124 RPC_CN_PKT_CALL_ID (header_p), 1125 RPC_CN_PKT_ALLOC_HINT (header_p), 1126 frag_buf->data_size ); 1127 1128 return; 1129 } 1130 } 1131 1132 /* 1133 * Copy the drep field from the association 1134 * (which is in the 4 byte wire format) 1135 * to the output remote_ndr_format arg. 1136 */ 1137 *remote_ndr_format = RPC_CN_ASSOC_NDR_FORMAT (call_rep->assoc); 1138 1139 /* 1140 * Now adjust data_p to point to just the stub data. 1141 * Note that data_size has already been adjusted. 1142 */ 1143 if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_RESPONSE) 1144 { 1145 frag_buf->data_p = (dce_pointer_t) 1146 (RPC_CN_PKT_RESP_STUB_DATA(header_p)); 1147 } 1148 else if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT) 1149 { 1150 frag_buf->data_p = (dce_pointer_t) 1151 RPC_CN_PKT_FAULT_STUB_DATA (header_p); 1152 /* 1153 * We had conservatively assumed that the call 1154 * has executed as soon as the call started. 1155 * We can now update that information. 1156 */ 1157 if (RPC_CN_PKT_FLAGS (header_p) & 1158 RPC_C_CN_FLAGS_DID_NOT_EXECUTE) 1159 { 1160 call_rep->call_executed = false; 1161 } 1162 1163 /* 1164 * This can be either a call_reject or a call_fault. 1165 */ 1166 fault_code = RPC_CN_PKT_STATUS(header_p); 1167 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 1168 ("CN: call_rep->%p fault packet received st = %x\n", 1169 call_rep, 1170 fault_code)); 1171 if (fault_code) 1172 { 1173 /* 1174 * Non-zero fault code implies a call_reject. 1175 */ 1176 1177 /* 1178 * Deallocate the fragment buffer since we 1179 * won't be returning it to the client stub. 1180 */ 1181 (* frag_buf->fragbuf_dealloc) (frag_buf); 1182 1183 /* 1184 * We translate the on-wire fault code into 1185 * a local status code & return it. 1186 */ 1187 *st = rpc__cn_call_cvt_from_nca_st (fault_code); 1188 1189 /* 1190 * Release the CN global mutex to allow other threads to 1191 * run. 1192 */ 1193 RPC_CN_UNLOCK (); 1194 return; 1195 } 1196 else 1197 { 1198 /* 1199 * On a fault, we store the address of the fragment 1200 * buffer in the call_rep for later retrieval via 1201 * rpc__receive_fault. 1202 */ 1203 call_rep->u.client.fault_data = frag_buf; 1204 *st = rpc_s_call_faulted; 1205 1206 /* 1207 * Release the CN global mutex to allow other threads to 1208 * run. 1209 */ 1210 RPC_CN_UNLOCK (); 1211 return; 1212 } 1213 } 1214 else 1215 { 1216 /* 1217 * This is a protocol error, just return the whole 1218 * packet. 1219 */ 1220 call_rep->cn_call_status = rpc_s_protocol_error; 1221 } 1222 1223 if (frag_buf->data_size > 0) 1224 { 1225 /* 1226 * Set up the iovector element to point to the received data. 1227 */ 1228 out_call_args->buff_dealloc = 1229 (rpc_buff_dealloc_fn_t)frag_buf->fragbuf_dealloc; 1230 out_call_args->buff_addr = (byte_p_t) frag_buf; 1231 out_call_args->buff_len = frag_buf->max_data_size; 1232 out_call_args->data_addr = (byte_p_t) frag_buf->data_p; 1233 out_call_args->data_len = frag_buf->data_size; 1234 1235 } 1236 else 1237 { 1238 /* 1239 * No stub data. 1240 */ 1241 out_call_args->data_addr = (byte_p_t) NULL; 1242 out_call_args->data_len = 0; 1243 1244 /* 1245 * We also deallocate the fragbuf now. 1246 */ 1247 (* frag_buf->fragbuf_dealloc) (frag_buf); 1248 } 1249 } 1250 } 1251 } 1252 *st = call_rep->cn_call_status; 1253 1254 /* 1255 * Release the CN global mutex to allow other threads to 1256 * run. 1257 */ 1258 RPC_CN_UNLOCK (); 1259 1260 RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT, 1261 ("PACKET: call transceive out_elt.flags->%x out_elt.buff_len->%d out_elt.data_len->%d\n", 1262 out_call_args->flags, 1263 out_call_args->buff_len, 1264 out_call_args->data_len)); 1265 RPC_LOG_CN_CALL_TRANSCEIVE_XIT; 1266} 1267 1268 1269/* 1270**++ 1271** 1272** ROUTINE NAME: rpc__cn_call_receive 1273** 1274** SCOPE: PRIVATE - declared in cncall.h 1275** 1276** DESCRIPTION: 1277** 1278** Return a buffer of marshalled arguments from the remote 1279** thread. This routine is intended for use by the client 1280** or server stub only. 1281** 1282** INPUTS: 1283** 1284** call_r The call rep containing information 1285** pertaining to this RPC. 1286** 1287** INPUTS/OUTPUTS: none 1288** 1289** OUTPUTS: 1290** 1291** call_args A vector of buffers containing marshaled RPC 1292** arguments. 1293** st The return status of this routine. 1294** rpc_s_ok The call was successful. 1295** rpc_s_call_orphaned 1296** rpc_s_call_faulted 1297** rpc_s_protocol_error 1298** 1299** 1300** IMPLICIT INPUTS: none 1301** 1302** IMPLICIT OUTPUTS: none 1303** 1304** FUNCTION VALUE: none 1305** 1306** SIDE EFFECTS: none 1307** 1308**-- 1309**/ 1310 1311PRIVATE void rpc__cn_call_receive 1312( 1313 rpc_call_rep_p_t call_r, 1314 rpc_iovector_elt_p_t call_args, 1315 unsigned32 *st 1316) 1317{ 1318 rpc_cn_call_rep_t *call_rep; 1319 rpc_cn_packet_p_t header_p; 1320 rpc_cn_fragbuf_p_t frag_buf; 1321 unsigned32 fault_code; 1322 boolean valid_fragbuf; 1323 1324 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_receive); 1325 RPC_LOG_CN_CALL_RECEIVE_NTR; 1326 CODING_ERROR (st); 1327 1328 call_rep = (rpc_cn_call_rep_p_t) call_r; 1329 1330 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 1331 ("CN: call_rep->%p call receive...\n", 1332 call_rep)); 1333 1334 /* 1335 * Acquire the CN global mutex to prevent other threads from 1336 * running. 1337 */ 1338 RPC_CN_LOCK (); 1339 1340 /* 1341 * If the call has been orphaned, return rpc_s_call_orphaned. 1342 */ 1343 if (call_rep->cn_call_status == rpc_s_call_orphaned) 1344 { 1345 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 1346 ("CN: call_rep->%p call orphaned...\n", 1347 call_rep)); 1348 1349 call_args->buff_dealloc = NULL; 1350 call_args->data_addr = (byte_p_t) NULL; 1351 call_args->data_len = 0; 1352 *st = rpc_s_call_orphaned; 1353 1354 /* 1355 * Release the CN global mutex to allow other threads to 1356 * run. 1357 */ 1358 RPC_CN_UNLOCK (); 1359 return; 1360 } 1361 1362 /* 1363 * If we have already received the last fragment, 1364 * return a null iovector element. 1365 */ 1366 if (call_rep->last_frag_received) 1367 { 1368 call_args->buff_dealloc = NULL; 1369 call_args->data_addr = (byte_p_t) NULL; 1370 call_args->data_len = 0; 1371 *st = rpc_s_ok; 1372 1373 /* 1374 * Release the CN global mutex to allow other threads to 1375 * run. 1376 */ 1377 RPC_CN_UNLOCK (); 1378 RPC_LOG_CN_CALL_RECEIVE_XIT; 1379 return; 1380 } 1381 1382 /* 1383 * Receive a packet from the association. 1384 * (The receive routine allocates the fragment buffer.) 1385 * Make sure the fragbuf is not left over from an 1386 * orphaned presentation negotiation. 1387 */ 1388 valid_fragbuf = false; 1389 while (!valid_fragbuf) 1390 { 1391 rpc__cn_assoc_receive_frag (call_rep->assoc, 1392 &frag_buf, 1393 st); 1394 if (*st != rpc_s_ok) 1395 { 1396 call_args->buff_dealloc = NULL; 1397 call_args->data_addr = (byte_p_t) NULL; 1398 call_args->data_len = 0; 1399 RPC_CN_UNLOCK (); 1400 return; 1401 } 1402 if (frag_buf->data_p != NULL) 1403 { 1404 valid_fragbuf = true; 1405 } 1406 } 1407 1408 /* 1409 * Set call_rep->last_frag_received if this is the last fragment. 1410 */ 1411 header_p = (rpc_cn_packet_p_t) frag_buf->data_p; 1412 if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) 1413 { 1414 call_rep->last_frag_received = true; 1415 } 1416 1417 /* check to see if las_frag should have been set in this packet or not */ 1418 if ((RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_REQUEST) || 1419 (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT) && 1420 (RPC_CN_PKT_ALLOC_HINT (header_p) != 0) ) 1421 { 1422 /* Request, responses and fault pkts have the alloc_hint that 1423 we can use to check the validity of last frag flag. 1424 Note: alloc_hint field can be 0 */ 1425 if ( (RPC_CN_PKT_ALLOC_HINT (header_p) <= frag_buf->data_size) && 1426 !(RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) ) 1427 { 1428 RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT, 1429 ("PACKET: call receive last frag should have been set. flags 0x%x call id %d alloc_hint %d rcvd data size %d\n", 1430 RPC_CN_PKT_FLAGS (header_p), 1431 RPC_CN_PKT_CALL_ID (header_p), 1432 RPC_CN_PKT_ALLOC_HINT (header_p), 1433 frag_buf->data_size)); 1434 *st = rpc_s_call_faulted; 1435 1436 /* 1437 * Release the CN global mutex to allow other threads to 1438 * run. 1439 */ 1440 RPC_CN_UNLOCK (); 1441 return; 1442 } 1443 } 1444 1445 /* 1446 * Now adjust data_p to point to just the stub data. 1447 * Note that data_size has already been adjusted. 1448 * To do this properly, we have to check the packet 1449 * type. 1450 */ 1451 if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_RESPONSE) 1452 { 1453 frag_buf->data_p = (dce_pointer_t) 1454 (RPC_CN_PKT_RESP_STUB_DATA(header_p)); 1455 } 1456 else if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_REQUEST) 1457 { 1458 if (RPC_CN_PKT_OBJ_UUID_PRESENT (header_p)) 1459 { 1460 frag_buf->data_p = (dce_pointer_t) 1461 RPC_CN_PKT_RQST_STUB_DATA_W_OBJ (header_p); 1462 } 1463 else 1464 { 1465 frag_buf->data_p = (dce_pointer_t) 1466 RPC_CN_PKT_RQST_STUB_DATA_NO_OBJ (header_p); 1467 } 1468 } 1469 else if (RPC_CN_PKT_PTYPE(header_p) == RPC_C_CN_PKT_FAULT) 1470 { 1471 frag_buf->data_p = (dce_pointer_t) RPC_CN_PKT_FAULT_STUB_DATA (header_p); 1472 /* 1473 * We had conservatively assumed that the call 1474 * has executed as soon as the call started. 1475 * We can now update that information. 1476 */ 1477 if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_DID_NOT_EXECUTE) 1478 { 1479 call_rep->call_executed = false; 1480 } 1481 1482 /* 1483 * This can be either a call_reject or a call_fault. 1484 */ 1485 fault_code = RPC_CN_PKT_STATUS(header_p); 1486 if (fault_code) 1487 { 1488 /* 1489 * Deallocate the fragment buffer since we 1490 * won't be returning it to the client stub. 1491 */ 1492 (* frag_buf->fragbuf_dealloc) (frag_buf); 1493 1494 /* 1495 * Non-zero fault code implies a call_reject. 1496 * 1497 * We translate the on-wire fault code into 1498 * a local status code & return it. 1499 */ 1500 *st = rpc__cn_call_cvt_from_nca_st (fault_code); 1501 1502 /* 1503 * Release the CN global mutex to allow other threads to 1504 * run. 1505 */ 1506 RPC_CN_UNLOCK (); 1507 return; 1508 } 1509 else 1510 { 1511 /* 1512 * On a fault, we store the address of the fragment 1513 * buffer in the call_rep for later retrieval via 1514 * rpc__receive_fault. 1515 */ 1516 call_rep->u.client.fault_data = frag_buf; 1517 *st = rpc_s_call_faulted; 1518 1519 /* 1520 * Release the CN global mutex to allow other threads to 1521 * run. 1522 */ 1523 RPC_CN_UNLOCK (); 1524 return; 1525 } 1526 } 1527 else 1528 { 1529 /* 1530 * This is a protocol error, just return the whole 1531 * packet. 1532 */ 1533 call_rep->cn_call_status = rpc_s_protocol_error; 1534 } 1535 1536 if (frag_buf->data_size > 0) 1537 { 1538 /* 1539 * Set up the iovector element to point to the received data. 1540 */ 1541 call_args->buff_addr = (byte_p_t) frag_buf; 1542 call_args->buff_len = frag_buf->max_data_size; 1543 call_args->data_addr = (byte_p_t) frag_buf->data_p; 1544 call_args->data_len = frag_buf->data_size; 1545 call_args->buff_dealloc = 1546 (rpc_buff_dealloc_fn_t)frag_buf->fragbuf_dealloc; 1547 } 1548 else 1549 { 1550 /* 1551 * No stub data. 1552 */ 1553 call_args->data_addr = (byte_p_t) NULL; 1554 call_args->data_len = 0; 1555 1556 /* 1557 * We also deallocate the fragbuf now. 1558 */ 1559 (* frag_buf->fragbuf_dealloc) (frag_buf); 1560 } 1561 1562 /* 1563 * Check for any pending cancels just in case we're in a 1564 * long unmarshalling loop and not calling any cancellable 1565 * operations. Also, forward any cancels which may have been 1566 * queued already before we were ready to forward them. 1567 */ 1568 if (RPC_CALL_IS_CLIENT (call_r)) 1569 { 1570 RPC_CN_CHK_AND_FWD_CANCELS (call_rep, st); 1571 } 1572 1573 /* 1574 * Release the CN global mutex to allow other threads to 1575 * run. 1576 */ 1577 *st = call_rep->cn_call_status; 1578 RPC_CN_UNLOCK (); 1579 1580 RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT, 1581 ("PACKET: call receive args.flags->%x args.buff_len->%d args.data_len->%d\n", 1582 call_args->flags, 1583 call_args->buff_len, 1584 call_args->data_len)); 1585 RPC_LOG_CN_CALL_RECEIVE_XIT; 1586} 1587 1588 1589/* 1590**++ 1591** 1592** ROUTINE NAME: rpc__cn_call_block_until_free 1593** 1594** SCOPE: PRIVATE - declared in cncall.h 1595** 1596** DESCRIPTION: 1597** 1598** This routine will block until all buffers given to the RPC 1599** runtime by the stub containing marshaled RPC output arguments 1600** are free. It is provided for use by the server stub when 1601** the marshaled arguments are contained in buffers which are 1602** on stack. The danger is that the server stub would return 1603** to the RPC runtime thereby invalidating its stack and buffer 1604** contents. This routine is intended for use by the server 1605** stub only. 1606** 1607** INPUTS: 1608** 1609** call_r The call rep containing information 1610** pertaining to this RPC. 1611** 1612** INPUTS/OUTPUTS: none 1613** 1614** OUTPUTS: 1615** 1616** st The return status of this routine. 1617** rpc_s_ok The call was successful. 1618** 1619** IMPLICIT INPUTS: none 1620** 1621** IMPLICIT OUTPUTS: none 1622** 1623** FUNCTION VALUE: none 1624** 1625** SIDE EFFECTS: none 1626** 1627**-- 1628**/ 1629 1630PRIVATE void rpc__cn_call_block_until_free 1631( 1632 rpc_call_rep_p_t call_r, 1633 unsigned32 *st 1634) 1635{ 1636 rpc_cn_call_rep_t *call_rep; 1637 1638 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_block_until_free); 1639 CODING_ERROR (st); 1640 1641 call_rep = (rpc_cn_call_rep_p_t) call_r; 1642 1643 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 1644 ("CN: call_rep->%p call block until free...\n", 1645 call_rep)); 1646 1647 /* 1648 * Acquire the CN global mutex to prevent other threads from 1649 * running. 1650 */ 1651 RPC_CN_LOCK (); 1652 1653 if (RPC_CN_CREP_ACC_BYTCNT (call_rep) >= RPC_CN_CREP_SIZEOF_HDR (call_rep)) 1654 { 1655 rpc__cn_transmit_buffers (call_rep, st); 1656 rpc__cn_dealloc_buffered_data (call_rep); 1657 RPC_CN_FREE_ALL_EXCEPT_PROT_HDR (call_rep); 1658 } 1659 1660 /* 1661 * Release the CN global mutex to allow other threads to 1662 * run. 1663 */ 1664 RPC_CN_UNLOCK (); 1665} 1666 1667 1668/* 1669**++ 1670** 1671** ROUTINE NAME: rpc__cn_call_alert 1672** 1673** SCOPE: PRIVATE - declared in cncall.h 1674** 1675** DESCRIPTION: 1676** 1677** This routine forwards a local alert to the remote RPC thread 1678** identified by the call rep provided. This routine is intended 1679** for use by the client stub only. 1680** 1681** INPUTS: 1682** 1683** call_r The call rep containing information 1684** pertaining to this RPC. 1685** 1686** INPUTS/OUTPUTS: none 1687** 1688** OUTPUTS: 1689** 1690** st The return status of this routine. 1691** rpc_s_ok The call was successful. 1692** rpc_s_alert_failed 1693** 1694** IMPLICIT INPUTS: none 1695** 1696** IMPLICIT OUTPUTS: none 1697** 1698** FUNCTION VALUE: none 1699** 1700** SIDE EFFECTS: none 1701** 1702**-- 1703**/ 1704 1705PRIVATE void rpc__cn_call_alert 1706( 1707 rpc_call_rep_p_t call_r, 1708 unsigned32 *st 1709) 1710{ 1711 rpc_cn_call_rep_t *call_rep; 1712 volatile boolean32 retry_op; 1713 1714 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_alert); 1715 CODING_ERROR (st); 1716 1717 call_rep = (rpc_cn_call_rep_p_t) call_r; 1718 1719 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 1720 ("CN: call_rep->%p call cancel...\n", 1721 call_rep)); 1722 1723 /* 1724 * Acquire the CN global mutex to prevent other threads from 1725 * running. 1726 */ 1727 RPC_CN_LOCK (); 1728 1729 /* 1730 * The stub has detected a local cancel. Do the right thing 1731 * based on whether we're a client or server. 1732 */ 1733 rpc__cn_call_local_cancel (call_rep, &retry_op, st); 1734 1735 /* 1736 * Release the CN global mutex to allow other threads to 1737 * run. 1738 */ 1739 RPC_CN_UNLOCK (); 1740} 1741 1742 1743/* 1744**++ 1745** 1746** ROUTINE NAME: rpc__cn_call_end 1747** 1748** SCOPE: PRIVATE - declared in cncall.h 1749** 1750** DESCRIPTION: 1751** 1752** Ends a remote procedure call. This is the last in the sequence 1753** of calls by the client or server stub. This call is intended 1754** for use by the client and server stubs only. 1755** 1756** INPUTS: none 1757** 1758** INPUTS/OUTPUTS: 1759** 1760** call_r The call rep containing information 1761** pertaining to this RPC. A NULL will be 1762** returned if this call is successful. 1763** 1764** OUTPUTS: 1765** 1766** st The return status of this routine. 1767** rpc_s_ok The call was successful. 1768** 1769** IMPLICIT INPUTS: none 1770** 1771** IMPLICIT OUTPUTS: none 1772** 1773** FUNCTION VALUE: none 1774** 1775** SIDE EFFECTS: none 1776** 1777**-- 1778**/ 1779 1780PRIVATE void rpc__cn_call_end 1781( 1782 rpc_call_rep_p_t *call_r, 1783 unsigned32 *st 1784) 1785{ 1786 rpc_cn_call_rep_t *call_rep; 1787 unsigned32 cur_iov_index; 1788 rpc_cn_fragbuf_p_t fault_fbp; 1789 rpc_cn_assoc_t *assoc; 1790 1791 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_end); 1792 RPC_LOG_CN_CALL_END_NTR; 1793 CODING_ERROR (st); 1794 1795 /* 1796 * Acquire the CN global mutex to prevent other threads from 1797 * running. 1798 */ 1799 RPC_CN_LOCK (); 1800 1801 call_rep = (rpc_cn_call_rep_p_t) *call_r; 1802 1803 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 1804 ("CN: call_rep->%p call end\n", 1805 call_rep)); 1806 1807 RPC_DBG_PRINTF (rpc_e_dbg_cn_pkt, RPC_C_CN_DBG_PKT, 1808 ("PACKET: call end\n")); 1809 1810 if (call_rep != NULL) 1811 { 1812 /* 1813 * Evaluate the state machine with the call_end event 1814 */ 1815 RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_END, 1816 NULL, 1817 call_rep, 1818 *st); 1819 1820 /* 1821 * Need to hold on to the assoc in a local variable since 1822 * rpc__cn_assoc_pop_call is going to NULL call_rep->assoc. 1823 * We'll pass the local variable to rpc__cn_assoc_dealloc. 1824 */ 1825 assoc = call_rep->assoc; 1826 1827 /* 1828 * Pop the call rep off the association. 1829 */ 1830 rpc__cn_assoc_pop_call (call_rep->assoc, call_rep); 1831 1832 /* 1833 * Deallocate the association. 1834 */ 1835 rpc__cn_assoc_dealloc (assoc, call_rep, st); 1836 1837 if (RPC_CALL_IS_CLIENT ((rpc_call_rep_p_t) call_rep)) 1838 { 1839 /* 1840 * Free remaining fault data fragbufs. 1841 */ 1842 if (call_rep->u.client.fault_data != NULL) 1843 { 1844 fault_fbp = (rpc_cn_fragbuf_p_t) (call_rep->u.client.fault_data); 1845 if (fault_fbp->fragbuf_dealloc != NULL) 1846 { 1847 (*fault_fbp->fragbuf_dealloc) (fault_fbp); 1848 } 1849 } 1850 1851 /* 1852 * Cancel this thread if: 1853 * 1854 * 1) the call completed on the server with a cancel pending 1855 * or the number of forwarded cancels is greater than the 1856 * number of cancels received by the server. (Note that 1857 * handle_recv_frag_action_rtn sets the server_had_pending 1858 * flag if one of these conditions exist.) 1859 * 1860 * 2) we have caught cancels in this thread but not 1861 * forwarded them yet. 1862 */ 1863 if ((call_rep->u.client.cancel.server_had_pending) || 1864 (call_rep->u.client.cancel.local_count > 0)) 1865 { 1866 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 1867 ("(rpc__cn_call_end) call_rep->%p reposting cancel\n", call_rep)); 1868 dcethread_interrupt_throw (dcethread_self()); 1869 } 1870 1871 /* 1872 * Stop the cancel timer if one was running. 1873 */ 1874 rpc__cn_call_stop_cancel_timer (call_rep); 1875 } 1876 1877 /* 1878 * If there are iovector elements in the call_rep, 1879 * free them all. There would not be any in the case 1880 * of a maybe call. 1881 */ 1882 if (RPC_CN_CREP_IOVLEN (call_rep) > 0) 1883 { 1884 for (cur_iov_index = 0; 1885 cur_iov_index < RPC_CN_CREP_IOVLEN (call_rep); 1886 cur_iov_index++) 1887 { 1888 if (RPC_CN_CREP_IOV (call_rep) [cur_iov_index].buff_dealloc != 1889 NULL) 1890 { 1891 (RPC_CN_CREP_IOV (call_rep) [cur_iov_index].buff_dealloc) 1892 (RPC_CN_CREP_IOV (call_rep) [cur_iov_index].buff_addr); 1893 } 1894 RPC_CN_CREP_IOV (call_rep) [cur_iov_index].buff_addr = NULL; 1895 } 1896 } 1897 1898 /* 1899 * If security was used on this call free the fragbuf used 1900 * for the authentication trailer. We check to make sure 1901 * that the fragbuf actually exists because we do not allocate 1902 * one on the server side for maybe calls. 1903 */ 1904 if ((call_rep->sec) && (call_rep->prot_tlr != NULL)) 1905 { 1906 rpc__cn_smfragbuf_free (call_rep->prot_tlr); 1907 } 1908 1909 /* 1910 * Free the call_rep itself. 1911 */ 1912 rpc__list_element_free (&rpc_g_cn_call_lookaside_list, 1913 (dce_pointer_t) call_rep); 1914 *call_r = NULL; 1915 } 1916 else 1917 { 1918 *st = rpc_s_ok; 1919 } 1920 1921 /* 1922 * Release the CN global mutex to allow other threads to 1923 * run. 1924 */ 1925 RPC_CN_UNLOCK (); 1926 1927 RPC_LOG_CN_CALL_END_XIT; 1928} 1929 1930 1931/* 1932**++ 1933** 1934** ROUTINE NAME: rpc__cn_call_transmit_fault 1935** 1936** SCOPE: PRIVATE - declared in cncall.h 1937** 1938** DESCRIPTION: 1939** 1940** This routine forwards an exception to the remote RPC thread 1941** identified by the call rep. This routine is intended for 1942** server stub use only. 1943** 1944** INPUTS: 1945** 1946** call_r The call rep containing information 1947** pertaining to this RPC. 1948** call_fault_info Marshaled fault information to be returned 1949** to the client. 1950** 1951** INPUTS/OUTPUTS: none 1952** 1953** OUTPUTS: 1954** 1955** st The return status of this routine. 1956** rpc_s_ok The call was successful. 1957** 1958** IMPLICIT INPUTS: none 1959** 1960** IMPLICIT OUTPUTS: none 1961** 1962** FUNCTION VALUE: none 1963** 1964** SIDE EFFECTS: none 1965** 1966**-- 1967**/ 1968 1969PRIVATE void rpc__cn_call_transmit_fault 1970( 1971 rpc_call_rep_p_t call_r, 1972 rpc_iovector_p_t call_fault_info, 1973 unsigned32 *st 1974) 1975{ 1976 rpc_cn_call_rep_p_t call_rep; 1977 rpc_iovector_elt_p_t iov_elt_p; 1978 unsigned32 i; 1979 1980 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_transmit_fault); 1981 CODING_ERROR (st); 1982 1983 call_rep = (rpc_cn_call_rep_p_t) call_r; 1984 1985 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 1986 ("CN: call_rep->%p call transmit fault\n", 1987 call_rep)); 1988 1989 /* 1990 * Acquire the CN global mutex to prevent other threads from 1991 * running. 1992 */ 1993 RPC_CN_LOCK (); 1994 1995 /* 1996 * If the call has been orphaned, return rpc_s_call_orphaned 1997 * and deallocate any input data. 1998 */ 1999 if (call_rep->cn_call_status == rpc_s_call_orphaned) 2000 { 2001 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 2002 ("CN: call_rep->%p call orphaned...\n", 2003 call_rep)); 2004 2005 iov_elt_p = call_fault_info->elt; 2006 for (i = 1; i <= call_fault_info->num_elt; i++, iov_elt_p++) 2007 { 2008 if (iov_elt_p->buff_dealloc != NULL) 2009 { 2010 (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr); 2011 } 2012 } 2013 *st = rpc_s_call_orphaned; 2014 } 2015 else 2016 { 2017 /* 2018 * Evaluate the state machine with the call_fault event. 2019 */ 2020 RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_FAULT, 2021 call_fault_info, 2022 call_rep, 2023 *st); 2024 } 2025 2026 /* 2027 * Release the CN global mutex to allow other threads to 2028 * run. 2029 */ 2030 RPC_CN_UNLOCK (); 2031} 2032 2033 2034/* 2035**++ 2036** 2037** ROUTINE NAME: rpc__cn_call_reject 2038** 2039** SCOPE: PRIVATE - declared in cncall.h 2040** 2041** DESCRIPTION: 2042** 2043** Map a local status code to an architected status code. 2044** Send a call reject packet. This is invoked after an 2045** error has been discovered in the call executor or receiver 2046** threads. 2047** 2048** INPUTS: 2049** 2050** call_r The call rep containing information 2051** pertaining to this RPC. 2052** l_st The local status code which will be mapped 2053** to an architected status code to be sent back 2054** to the client. 2055** 2056** INPUTS/OUTPUTS: none 2057** 2058** OUTPUTS: none 2059** 2060** IMPLICIT INPUTS: This routine assumes that the prototype 2061** send header in the call_rep has been 2062** set up. 2063** 2064** IMPLICIT OUTPUTS: none 2065** 2066** FUNCTION VALUE: none. 2067** 2068** SIDE EFFECTS: none 2069** 2070**-- 2071**/ 2072 2073PRIVATE void rpc__cn_call_reject 2074( 2075 rpc_call_rep_p_t call_r, 2076 unsigned32 l_st 2077) 2078{ 2079 rpc_cn_call_rep_p_t call_rep; 2080 unsigned32 st; 2081 2082 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_reject); 2083 2084 call_rep = (rpc_cn_call_rep_p_t) call_r; 2085 2086 RPC_CN_LOCK_ASSERT (); 2087 2088 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 2089 ("CN: call_rep->%p call rejected - reason = %x\n", 2090 call_rep, l_st)); 2091 2092 /* 2093 * Map the local status code to an appropriate architected 2094 * status code. 2095 */ 2096 call_rep->cn_call_status = rpc__cn_call_cvt_to_nca_st (l_st); 2097 2098 /* 2099 * For a fault with an architected status, we pass the 2100 * architected status code in the call rep and pass a null 2101 * fault_data. 2102 */ 2103 RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_FAULT_DNE, 2104 NULL, 2105 call_rep, 2106 st); 2107} 2108 2109 2110/* 2111**++ 2112** 2113** ROUTINE NAME: rpc__cn_call_receive_fault 2114** 2115** SCOPE: PRIVATE - declared in cncall.h 2116** 2117** DESCRIPTION: 2118** 2119** This routine will unmarshal a fault message from the remote 2120** (server) thread. It is intended for use by the client 2121** stub only. 2122** 2123** INPUTS: 2124** 2125** call_r The call rep containing information 2126** pertaining to this RPC. 2127** 2128** INPUTS/OUTPUTS: none 2129** 2130** OUTPUTS: 2131** 2132** remote_ndr_format The Network Data Representation format of the remote 2133** machine. This is used by the stub to unmarshal 2134** arguments encoded using NDR as the trasnfer syntax. 2135** 2136** call_fault_info A vector of buffers containing marshaled RPC 2137** fault information. 2138** 2139** st The return status of this routine. 2140** rpc_s_ok The call completed normally. 2141** rpc_s_no_fault No fault information available. 2142** 2143** 2144** IMPLICIT INPUTS: none 2145** 2146** IMPLICIT OUTPUTS: none 2147** 2148** FUNCTION VALUE: none 2149** 2150** SIDE EFFECTS: none 2151** 2152**-- 2153**/ 2154 2155PRIVATE void rpc__cn_call_receive_fault 2156( 2157 rpc_call_rep_p_t call_r, 2158 rpc_iovector_elt_p_t call_fault_info, 2159 ndr_format_t *remote_ndr_format, 2160 unsigned32 *st 2161 2162) 2163{ 2164 rpc_cn_call_rep_t *call_rep; 2165 rpc_cn_fragbuf_p_t fault_fragp; 2166 2167 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_receive_fault); 2168 CODING_ERROR (st); 2169 2170 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 2171 ("CN: call_rep->%p call receive fault\n", 2172 call_r)); 2173 2174 /* 2175 * Acquire the CN global mutex to prevent other threads from 2176 * running. 2177 */ 2178 RPC_CN_LOCK (); 2179 2180 /* 2181 * When a fault is received, the appropriate action routine 2182 * would unmarshal it (into a large fragment buffer) and store 2183 * its address in the callrep. 2184 */ 2185 call_rep = (rpc_cn_call_rep_p_t) call_r; 2186 fault_fragp = (rpc_cn_fragbuf_p_t) (call_rep->u.client.fault_data); 2187 call_rep->u.client.fault_data = NULL; 2188 2189 if (fault_fragp != NULL) 2190 { 2191 /* 2192 * Copy the remote NDR format into the output arguments. 2193 */ 2194 *remote_ndr_format = RPC_CN_ASSOC_NDR_FORMAT (call_rep->assoc); 2195 2196 /* 2197 * We now copy the descriptors into the iovector. 2198 * The stub will deallocate the fragment buffer. 2199 */ 2200 call_fault_info->buff_dealloc = 2201 (rpc_buff_dealloc_fn_t)fault_fragp->fragbuf_dealloc; 2202 call_fault_info->buff_addr = (byte_p_t) fault_fragp; 2203 call_fault_info->buff_len = fault_fragp->max_data_size; 2204 call_fault_info->data_addr = (byte_p_t) fault_fragp->data_p; 2205 call_fault_info->data_len = fault_fragp->data_size; 2206 2207 *st = rpc_s_ok; 2208 } 2209 else 2210 { 2211 call_fault_info->buff_dealloc = NULL; 2212 call_fault_info->buff_addr = NULL; 2213 call_fault_info->buff_len = 0; 2214 call_fault_info->data_addr = NULL; 2215 call_fault_info->data_len = 0; 2216 2217 *st = rpc_s_no_fault; 2218 } 2219 2220 /* 2221 * Release the CN global mutex to allow other threads to 2222 * run. 2223 */ 2224 RPC_CN_UNLOCK (); 2225} 2226 2227/* 2228**++ 2229** 2230** ROUTINE NAME: rpc__cn_call_did_mgr_execute 2231** 2232** SCOPE: PRIVATE - declared in cncall.h 2233** 2234** DESCRIPTION: 2235** 2236** This routine will return whether or not a the manager routine 2237** for the call identified by the call handle has begun executing or not. 2238** It is intended for use by the client stub only. 2239** 2240** INPUTS: 2241** 2242** call_r The call rep containing information 2243** pertaining to this RPC. 2244** 2245** INPUTS/OUTPUTS: none 2246** 2247** OUTPUTS: 2248** 2249** st The return status of this routine. 2250** rpc_s_ok The call completed normally. 2251** rpc_s_no_fault No fault information available. 2252** 2253** 2254** IMPLICIT INPUTS: none 2255** 2256** IMPLICIT OUTPUTS: none 2257** 2258** FUNCTION VALUE: 2259** 2260** boolean32 true if the manager routine has begun, false otherwise. 2261** 2262** SIDE EFFECTS: none 2263** 2264**-- 2265**/ 2266 2267PRIVATE boolean32 rpc__cn_call_did_mgr_execute 2268( 2269 rpc_call_rep_p_t call_r, 2270 unsigned32 *st ATTRIBUTE_UNUSED 2271) 2272{ 2273 rpc_cn_call_rep_t *call_rep; 2274 boolean call_executed; 2275 2276 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_did_mgr_execute); 2277 CODING_ERROR (st); 2278 2279 call_rep = (rpc_cn_call_rep_p_t) call_r; 2280 2281 /* 2282 * Acquire the CN global mutex to prevent other threads from 2283 * running. 2284 */ 2285 RPC_CN_LOCK (); 2286 2287 call_executed = call_rep->call_executed; 2288 2289 /* 2290 * Release the CN global mutex to allow other threads to 2291 * run. 2292 */ 2293 RPC_CN_UNLOCK (); 2294 return (call_executed); 2295} 2296 2297 2298/* 2299**++ 2300** 2301** ROUTINE NAME: rpc__cn_call_cvt_from_nca_st 2302** 2303** SCOPE: INTERNAL 2304** 2305** DESCRIPTION: 2306** 2307** This routine will translate an on-wire status code (nca_s..) 2308** into the corresponding runtime status code (rpc_s..). 2309** 2310** INPUTS: 2311** 2312** a_st The NCA status code as rets it appears on the wire. 2313** This is the status as returned by, for example, 2314** a call_fault packet. 2315** 2316** INPUTS/OUTPUTS: none 2317** 2318** OUTPUTS: none 2319** 2320** IMPLICIT INPUTS: none 2321** 2322** IMPLICIT OUTPUTS: none 2323** 2324** FUNCTION VALUE: 2325** 2326** unsigned32 The runtime status code corresponding to 2327** the nca status code. 2328** 2329** SIDE EFFECTS: none 2330** 2331**-- 2332**/ 2333 2334INTERNAL unsigned32 rpc__cn_call_cvt_from_nca_st 2335( 2336 unsigned32 a_st 2337) 2338{ 2339 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_cvt_from_nca_st); 2340 switch ((int)a_st) 2341 { 2342 case nca_s_op_rng_error: return (rpc_s_op_rng_error); 2343 case nca_s_unk_if: return (rpc_s_unknown_if); 2344 case nca_s_proto_error: return (rpc_s_protocol_error); 2345 case nca_s_server_too_busy: return (rpc_s_server_too_busy); 2346 case nca_s_invalid_pres_context_id: return (rpc_s_context_id_not_found); 2347 case nca_s_unsupported_type: return (rpc_s_unsupported_type); 2348 case nca_s_manager_not_entered: return (rpc_s_manager_not_entered); 2349 case nca_s_out_args_too_big: return (rpc_s_credentials_too_large); 2350 case nca_s_unsupported_authn_level: return (rpc_s_unsupported_authn_level); 2351 case nca_s_invalid_checksum: return (rpc_s_invalid_checksum); 2352 case nca_s_invalid_crc: return (rpc_s_invalid_crc); 2353 default: return (rpc_s_unknown_reject); 2354 } 2355} 2356 2357 2358/* 2359**++ 2360** 2361** ROUTINE NAME: rpc__cn_call_cvt_to_nca_st 2362** 2363** SCOPE: INTERNAL 2364** 2365** DESCRIPTION: 2366** 2367** This routine will translate a local status to to an architected status code (nca_s..). 2368** 2369** INPUTS: 2370** 2371** l_st The local (rpc_s...) status code. 2372** 2373** INPUTS/OUTPUTS: none 2374** 2375** OUTPUTS: none 2376** 2377** IMPLICIT INPUTS: none 2378** 2379** IMPLICIT OUTPUTS: none 2380** 2381** FUNCTION VALUE: 2382** 2383** unsigned32 The architected (nca_s...) status code. 2384** 2385** SIDE EFFECTS: none 2386** 2387**-- 2388**/ 2389 2390INTERNAL unsigned32 rpc__cn_call_cvt_to_nca_st 2391( 2392 unsigned32 l_st 2393) 2394{ 2395 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_cvt_to_nca_st); 2396 switch ((int)l_st) 2397 { 2398 case rpc_s_op_rng_error: return (nca_s_op_rng_error); 2399 case rpc_s_unknown_if: return (nca_s_unk_if); 2400 case rpc_s_protocol_error: return (nca_s_proto_error); 2401 case rpc_s_cthread_not_found: return (nca_s_server_too_busy); 2402 case rpc_s_server_too_busy: return (nca_s_server_too_busy); 2403 case rpc_s_unsupported_type: return (nca_s_unsupported_type); 2404 case rpc_s_unknown_mgr_type: return (nca_s_unsupported_type); 2405 case rpc_s_manager_not_entered: return (nca_s_manager_not_entered); 2406 case rpc_s_context_id_not_found: return (nca_s_invalid_pres_context_id); 2407 case rpc_s_call_orphaned: return (nca_s_unspec_reject); 2408 case rpc_s_unknown_reject: return (nca_s_unspec_reject); 2409 case rpc_s_credentials_too_large: return (nca_s_out_args_too_big); 2410 case rpc_s_unsupported_authn_level: return (nca_s_unsupported_authn_level); 2411 case rpc_s_invalid_checksum: return (nca_s_invalid_checksum); 2412 case rpc_s_invalid_crc: return (nca_s_invalid_crc); 2413 default: 2414 RPC_DBG_GPRINTF(("(rpc__cn_call_cvt_to_nca_st) unknown status; st=%08x\n", l_st)); 2415 return (nca_s_unspec_reject); 2416 } 2417} 2418 2419/* 2420**++ 2421** 2422** ROUTINE NAME: rpc__cn_call_no_conn_ind 2423** 2424** SCOPE: PRIVATE - declared in cncall.h 2425** 2426** DESCRIPTION: 2427** 2428** This routine will be called from a client receiver thread when 2429** it detects the connection a call is in progress on has been lost. 2430** 2431** INPUTS: 2432** 2433** call_rep The call rep data structure containing the 2434** state of the call in progress. 2435** 2436** INPUTS/OUTPUTS: none 2437** 2438** OUTPUTS: none 2439** 2440** IMPLICIT INPUTS: none 2441** 2442** IMPLICIT OUTPUTS: none 2443** 2444** FUNCTION VALUE: none 2445** 2446** SIDE EFFECTS: none 2447** 2448**-- 2449**/ 2450 2451PRIVATE void rpc__cn_call_no_conn_ind 2452( 2453 rpc_cn_call_rep_p_t call_rep ATTRIBUTE_UNUSED 2454) 2455{ 2456 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_no_conn_ind); 2457 2458 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 2459 ("CN: call_rep->%p call no connection indication\n", 2460 call_rep)); 2461 2462 /* 2463 * For now this routine does nothing. 2464 */ 2465} 2466 2467/* 2468**++ 2469** 2470** ROUTINE NAME: rpc__cn_call_ccb_create 2471** 2472** SCOPE: PRIVATE - declared in cncall.h 2473** 2474** DESCRIPTION: 2475** 2476** This routine will initialize an call control block 2477** which is allocated from heap by rpc__list_element_alloc. It 2478** will allocate a fragbuf for the protocol header and initialize 2479** some fields of the header. 2480** 2481** INPUTS: 2482** 2483** ccb The call control block to be initialized. 2484** 2485** INPUTS/OUTPUTS: none 2486** 2487** OUTPUTS: none 2488** 2489** IMPLICIT INPUTS: none 2490** 2491** IMPLICIT OUTPUTS: none 2492** 2493** FUNCTION VALUE: none 2494** 2495** SIDE EFFECTS: none 2496** 2497**-- 2498**/ 2499 2500PRIVATE void rpc__cn_call_ccb_create 2501( 2502 rpc_cn_call_rep_p_t ccb 2503) 2504{ 2505 rpc_cn_fragbuf_p_t fragbuf_p; 2506 rpc_cn_packet_p_t header_p; 2507 rpc_iovector_elt_p_t iov_p; 2508 2509 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_ccb_create); 2510 2511 RPC_LIST_INIT (ccb->common.link); 2512 ccb->common.protocol_id = RPC_C_PROTOCOL_ID_NCACN; 2513 fragbuf_p = rpc__cn_fragbuf_alloc (false); 2514 fragbuf_p->fragbuf_dealloc = NULL; 2515 ccb->prot_header = fragbuf_p; 2516 header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (ccb); 2517 2518 /* 2519 * Copy the common header fields. 2520 */ 2521 memcpy (header_p, &rpc_g_cn_common_hdr, sizeof (rpc_g_cn_common_hdr)); 2522 2523 iov_p = &(RPC_CN_CREP_IOV (ccb)[0]); 2524 iov_p->buff_dealloc = NULL; 2525 iov_p->buff_addr = (byte_p_t) fragbuf_p; 2526 iov_p->buff_len = fragbuf_p->max_data_size; 2527 iov_p->data_addr = (byte_p_t) fragbuf_p->data_p; 2528 2529 /* 2530 * Init the common call rep mutex. 2531 */ 2532 RPC_CALL_LOCK_INIT ((rpc_call_rep_p_t) ccb); 2533} 2534 2535 2536/***********************************************************************/ 2537/* 2538**++ 2539** 2540** ROUTINE NAME: rpc__cn_call_ccb_free 2541** 2542** SCOPE: PRIVATE - declared in cncall.h 2543** 2544** DESCRIPTION: 2545** 2546** This routine will free the fragment buffer contained in an call 2547** control block before the rpc__list_element_free routine returns 2548** it to heap storage. 2549** 2550** INPUTS: 2551** 2552** ccb The call control block to be initialized. 2553** 2554** INPUTS/OUTPUTS: none 2555** 2556** OUTPUTS: none 2557** 2558** IMPLICIT INPUTS: none 2559** 2560** IMPLICIT OUTPUTS: none 2561** 2562** FUNCTION VALUE: none 2563** 2564** SIDE EFFECTS: none 2565** 2566**-- 2567**/ 2568 2569PRIVATE void rpc__cn_call_ccb_free 2570( 2571 rpc_cn_call_rep_p_t ccb 2572) 2573{ 2574 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_ccb_free); 2575 2576 /* 2577 * Free the small fragbuf used for the protocol header. 2578 */ 2579 if (ccb->prot_header != NULL) 2580 { 2581 rpc__cn_smfragbuf_free (ccb->prot_header); 2582 } 2583 2584 /* 2585 * Delete the common call rep mutex. 2586 */ 2587 RPC_CALL_LOCK_DELETE ((rpc_call_rep_p_t) ccb); 2588} 2589 2590 2591/***********************************************************************/ 2592/* 2593**++ 2594** 2595** ROUTINE NAME: rpc__cn_call_local_cancel 2596** 2597** SCOPE: PRIVATE - declared in cncall.h 2598** 2599** DESCRIPTION: 2600** 2601** A local cancel has been detected (i.e., a cancellable operation 2602** caused an unwound). This routine can be invoked from either 2603** the client or the server. 2604** If it occurs on the client, a cancel is forwarded to the server. 2605** If it occurs on the server, rpc_s_call_cancelled is returned. 2606** 2607** Note that this routine assumes that the global CN lock is held. 2608** 2609** INPUTS: 2610** 2611** call_rep The call rep. 2612** 2613** INPUTS/OUTPUTS: none 2614** 2615** OUTPUTS: none 2616** 2617** IMPLICIT INPUTS: none 2618** 2619** IMPLICIT OUTPUTS: none 2620** 2621** FUNCTION VALUE: none 2622** 2623** SIDE EFFECTS: none 2624** 2625**-- 2626**/ 2627 2628PRIVATE void rpc__cn_call_local_cancel 2629( 2630 rpc_cn_call_rep_p_t call_rep, 2631 volatile boolean32 *retry_op, 2632 unsigned32 *status 2633) 2634{ 2635 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_local_cancel); 2636 CODING_ERROR (status); 2637 2638 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 2639 ("(rpc__cn_call_local_cancel) call_rep->%p local cancel caught\n", 2640 call_rep)); 2641 /* 2642 * If the call rep is NULL, this is the server side of a 2643 * call and it has been orphaned. We were in a cancellable pipe 2644 * routine. Return the rpc_s_call_cancelled status code. 2645 */ 2646 if (call_rep == NULL) 2647 { 2648 *retry_op = false; 2649 *status = rpc_s_call_cancelled; 2650 return; 2651 } 2652 2653 if (RPC_CALL_IS_CLIENT (((rpc_call_rep_t *) call_rep))) 2654 { 2655 /* 2656 * Record the cancel that was just detected. 2657 */ 2658 call_rep->u.client.cancel.local_count++; 2659 rpc__cn_call_start_cancel_timer (call_rep, status); 2660 if (*status == rpc_s_ok) 2661 { 2662 /* 2663 * Send a cancel event through the state machine for all 2664 * cancels detected so far but not forwarded yet. 2665 */ 2666 rpc__cn_call_forward_cancel (call_rep, status); 2667 *retry_op = true; 2668 } 2669 else 2670 { 2671 *retry_op = false; 2672 } 2673 } 2674 else 2675 { 2676 *retry_op = false; 2677 *status = rpc_s_call_cancelled; 2678 } 2679} 2680 2681 2682/***********************************************************************/ 2683/* 2684**++ 2685** 2686** ROUTINE NAME: rpc__cn_call_check_for_cancel 2687** 2688** SCOPE: INTERNAL - declared locally 2689** 2690** DESCRIPTION: 2691** 2692** Check for a pending cancel. If one is caught increment the local 2693** count field of the call rep to indicate it. Of course, if 2694** general cancel delivery is disabled, then we aren't required 2695** (and in fact don't want) to detect one. 2696** 2697** INPUTS: 2698** 2699** call_rep The call rep. 2700** 2701** INPUTS/OUTPUTS: none 2702** 2703** OUTPUTS: none 2704** 2705** IMPLICIT INPUTS: none 2706** 2707** IMPLICIT OUTPUTS: none 2708** 2709** FUNCTION VALUE: none 2710** 2711** SIDE EFFECTS: none 2712** 2713**-- 2714**/ 2715 2716INTERNAL void rpc__cn_call_check_for_cancel 2717( 2718 rpc_cn_call_rep_p_t call_rep 2719) 2720{ 2721 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_check_for_cancel); 2722 2723 /* 2724 * If a cancel timeout has been established there's no need to 2725 * check. A cancel has been forwarded and no response has been 2726 * received yet. 2727 */ 2728 if (call_rep->u.client.cancel.timeout_time == 0) 2729 { 2730 DCETHREAD_TRY 2731 { 2732 dcethread_checkinterrupt (); 2733 } 2734 DCETHREAD_CATCH (dcethread_interrupt_e) 2735 { 2736 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 2737 ("(rpc__cn_call_check_for_cancel) call_rep->%p local cancel detected\n", call_rep)); 2738 (call_rep)->u.client.cancel.local_count++; 2739 } 2740 DCETHREAD_ENDTRY 2741 } 2742} 2743 2744 2745/***********************************************************************/ 2746/* 2747**++ 2748** 2749** ROUTINE NAME: rpc__cn_call_forward_cancel 2750** 2751** SCOPE: INTERNAL - declared locally 2752** 2753** DESCRIPTION: 2754** 2755** Forward all cancels which have been detected to this point to 2756** the server. 2757** 2758** INPUTS: 2759** 2760** call_rep The call rep. 2761** 2762** INPUTS/OUTPUTS: none 2763** 2764** OUTPUTS: none 2765** 2766** IMPLICIT INPUTS: none 2767** 2768** IMPLICIT OUTPUTS: none 2769** 2770** FUNCTION VALUE: none 2771** 2772** SIDE EFFECTS: none 2773** 2774**-- 2775**/ 2776 2777INTERNAL void rpc__cn_call_forward_cancel 2778( 2779 rpc_cn_call_rep_p_t call_rep, 2780 unsigned32 *status 2781) 2782{ 2783 unsigned32 temp_status; 2784 2785 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_forward_cancel); 2786 CODING_ERROR (status); 2787 2788 /* 2789 * Foward all queued cancels if the first request fragment has been sent 2790 * to the server already. 2791 */ 2792 if (call_rep->u.client.cancel.server_is_accepting) 2793 { 2794 for (; call_rep->u.client.cancel.local_count > 0; 2795 call_rep->u.client.cancel.local_count--) 2796 { 2797 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 2798 ("(rpc__cn_call_forward_cancel) call_rep->%p forwarding cancel\n", call_rep)); 2799 RPC_CN_CALL_EVAL_EVENT (RPC_C_CALL_LOCAL_ALERT, 2800 NULL, 2801 call_rep, 2802 temp_status); 2803 } 2804 } 2805 else 2806 { 2807 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 2808 ("(rpc__cn_call_forward_cancel) call_rep->%p haven't sent first frag yet\n", call_rep)); 2809 } 2810 *status = call_rep->cn_call_status; 2811} 2812 2813 2814/* 2815**++ 2816** 2817** ROUTINE NAME: rpc__cn_call_binding_serialize 2818** 2819** SCOPE: INTERNAL - declared locally 2820** 2821** DESCRIPTION: 2822** 2823** Serialize calls on this binding handle until the handle has a bound 2824** server instance. This is necessary to maintain the promise: "All 2825** calls to using a specific binding handle will go to the same server 2826** instance". 2827** 2828** INPUTS: 2829** 2830** binding_r The binding rep access to which is being serialized 2831** cancel_timeout The thread's cancel timeout value 2832** 2833** INPUTS/OUTPUTS: 2834** 2835** cancel_cnt The number of cancels detected while waiting 2836** for the binding rep to become free. 2837** 2838** OUTPUTS: 2839** 2840** st The RPC runtime status code 2841** 2842** 2843** IMPLICIT INPUTS: none 2844** 2845** IMPLICIT OUTPUTS: none 2846** 2847** FUNCTION VALUE: 2848** 2849** SIDE EFFECTS: none 2850** 2851**-- 2852**/ 2853 2854INTERNAL void rpc__cn_call_binding_serialize 2855( 2856 rpc_binding_rep_p_t binding_r, 2857 rpc_clock_t cancel_timeout, 2858 unsigned32 *cancel_cnt, 2859 unsigned32 *st 2860) 2861{ 2862 volatile boolean is_awaiting_timeout = false; 2863 volatile boolean has_timed_out = false; 2864 volatile struct timespec zero_delta, delta, abstime, curtime; 2865 2866 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_binding_serialize); 2867 RPC_LOCK_ASSERT(0); 2868 CODING_ERROR (st); 2869 2870 *st = rpc_s_ok; 2871 2872 zero_delta.tv_sec = 0; 2873 zero_delta.tv_nsec = 0; 2874 delta.tv_sec = 0; 2875 delta.tv_nsec = 0; 2876 2877 delta.tv_sec = cancel_timeout; 2878 2879 /* 2880 * Wait while the binding is being resolved by someone else 2881 * (this routine is called only by threads not doing the 2882 * resolving) and we haven't timed out. 2883 * 2884 * If the user attempts to cancel the call, 2885 * don't wait longer than the cancel timeout time. 2886 */ 2887 while ((((rpc_cn_binding_rep_t *)binding_r)->being_resolved) && 2888 (!has_timed_out)) 2889 { 2890 DCETHREAD_TRY 2891 { 2892 if (!is_awaiting_timeout) 2893 { 2894 RPC_BINDING_COND_WAIT (0); 2895 } 2896 else 2897 { 2898 RPC_BINDING_COND_TIMED_WAIT ((struct timespec *) &abstime); 2899 dcethread_get_expiration ((struct timespec *) &zero_delta, 2900 (struct timespec *) &curtime); 2901 if (curtime.tv_sec >= abstime.tv_sec) 2902 { 2903 has_timed_out = true; 2904 } 2905 } 2906 } 2907 DCETHREAD_CATCH (dcethread_interrupt_e) 2908 { 2909 /* 2910 * Track the cancels and setup a cancel timeout value 2911 * (if appropriate). 2912 */ 2913 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 2914 ("(rpc__cn_call_binding_serialize) binding_rep->%p cancel detected\n", binding_r)); 2915 if (delta.tv_sec == 0) 2916 { 2917 has_timed_out = true; 2918 } 2919 else 2920 { 2921 if (delta.tv_sec == rpc_c_cancel_infinite_timeout) 2922 { 2923 ; /* we never timeout */ 2924 } 2925 else 2926 { 2927 /* 2928 * Compute the max timeout time for the wait. 2929 * Generate a cancel time stamp for use by the caller 2930 * in subsequently setting up the call's cancel state. 2931 */ 2932 if (is_awaiting_timeout == false) 2933 { 2934 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 2935 ("(rpc__cn_call_binding_serialize) binding_rep->%p %lu sec cancel timeout setup\n", 2936 binding_r, (unsigned long)delta.tv_sec)); 2937 2938 dcethread_get_expiration ((struct timespec *) (&delta), 2939 (struct timespec *) (&abstime)); 2940 } 2941 is_awaiting_timeout = true; 2942 } 2943 } 2944 *cancel_cnt += 1; 2945 2946 /* 2947 * Any other type of exception is something serious; just let it 2948 * propagate and we die in our usual unclean fashion. 2949 */ 2950 } 2951 DCETHREAD_ENDTRY 2952 } 2953 2954 if (has_timed_out) 2955 { 2956 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 2957 ("(rpc__cn_call_binding_serialize) binding_rep->%p cancel timeout\n", binding_r)); 2958 *st = rpc_s_cancel_timeout; 2959 } 2960 else if (binding_r->addr_has_endpoint == false) 2961 { 2962 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 2963 ("(rpc__cn_call_binding_serialize) binding_rep->%p endpoint not found\n", binding_r)); 2964 *st = rpc_s_endpoint_not_found; 2965 } 2966} 2967 2968 2969/* 2970**++ 2971** 2972** ROUTINE NAME: rpc__cn_call_start_cancel_timer 2973** 2974** SCOPE: PRIVATE - delcared in cncall.h 2975** 2976** DESCRIPTION: 2977** 2978** Start a timer to time out cancels. 2979** 2980** INPUTS: 2981** 2982** call_r The call rep representing the RPC being made. 2983** 2984** INPUTS/OUTPUTS: none 2985** 2986** OUTPUTS: 2987** 2988** st The RPC runtime status code 2989** 2990** 2991** IMPLICIT INPUTS: none 2992** 2993** IMPLICIT OUTPUTS: none 2994** 2995** FUNCTION VALUE: 2996** 2997** SIDE EFFECTS: none 2998** 2999**-- 3000**/ 3001 3002PRIVATE void rpc__cn_call_start_cancel_timer 3003( 3004 rpc_cn_call_rep_p_t call_r, 3005 unsigned32 *st 3006) 3007{ 3008 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_start_cancel_timer); 3009 CODING_ERROR (st); 3010 3011 RPC_CN_LOCK_ASSERT (); 3012 3013 /* 3014 * The timer may have already expired. 3015 */ 3016 if ((*st = call_r->cn_call_status) == rpc_s_ok) 3017 { 3018 /* 3019 * Start a cancel timer if one is not already running and the 3020 * cancel timeout for this thread is not infinite. 3021 */ 3022 if ((!call_r->u.client.cancel.timer_running) && 3023 (call_r->u.client.cancel.timeout_time != (typeof(call_r->u.client.cancel.timeout_time))(rpc_c_cancel_infinite_timeout))) 3024 { 3025 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 3026 ("(rpc__cn_call_start_cancel_timer) call_rep->%p starting cancel timer - %ld seconds\n", 3027 call_r, call_r->u.client.cancel.timeout_time)); 3028 call_r->u.client.cancel.timer_running = true; 3029 call_r->u.client.cancel.thread_h = dcethread_self (); 3030 rpc__timer_set (&call_r->u.client.cancel.timer, 3031 (rpc_timer_proc_p_t) rpc__cn_call_cancel_timer, 3032 (dce_pointer_t) call_r, 3033 (rpc_clock_t) RPC_CLOCK_SEC (call_r->u.client.cancel.timeout_time)); 3034 } 3035 } 3036 else 3037 { 3038 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 3039 ("(rpc__cn_call_start_cancel_timer) call_rep->%p timer expired ... returning rpc_s_cancel_timeout\n", 3040 call_r)); 3041 } 3042} 3043 3044 3045/* 3046**++ 3047** 3048** ROUTINE NAME: rpc__cn_call_stop_cancel_timer 3049** 3050** SCOPE: PRIVATE - declared in cncall.h 3051** 3052** DESCRIPTION: 3053** 3054** Clear the timer to time out cancels. 3055** 3056** INPUTS: 3057** 3058** call_r The call rep representing the RPC being made. 3059** 3060** INPUTS/OUTPUTS: none 3061** 3062** OUTPUTS: 3063** 3064** st The RPC runtime status code 3065** 3066** 3067** IMPLICIT INPUTS: none 3068** 3069** IMPLICIT OUTPUTS: none 3070** 3071** FUNCTION VALUE: 3072** 3073** SIDE EFFECTS: none 3074** 3075**-- 3076**/ 3077 3078PRIVATE void rpc__cn_call_stop_cancel_timer 3079( 3080 rpc_cn_call_rep_p_t call_r 3081) 3082{ 3083 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_stop_cancel_timer); 3084 3085 if (call_r->u.client.cancel.timer_running) 3086 { 3087 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 3088 ("(rpc__cn_call_stop_cancel_timer) call_rep->%p cancel timer stopped\n", call_r)); 3089 rpc__timer_clear (&call_r->u.client.cancel.timer); 3090 } 3091} 3092 3093 3094/* 3095**++ 3096** 3097** ROUTINE NAME: rpc__cn_call_cancel_timer 3098** 3099** SCOPE: INTERNAL - declared locally 3100** 3101** DESCRIPTION: 3102** 3103** Timer routine to time out cancels 3104** 3105** INPUTS: 3106** 3107** call_r The call rep representing the RPC being made. 3108** 3109** INPUTS/OUTPUTS: none 3110** 3111** OUTPUTS: 3112** 3113** st The RPC runtime status code 3114** 3115** 3116** IMPLICIT INPUTS: none 3117** 3118** IMPLICIT OUTPUTS: none 3119** 3120** FUNCTION VALUE: 3121** 3122** true the routine should be rescheduled 3123** false the routine should not be rescheduled 3124** 3125** SIDE EFFECTS: none 3126** 3127**-- 3128**/ 3129 3130INTERNAL boolean rpc__cn_call_cancel_timer 3131( 3132 rpc_cn_call_rep_p_t call_r 3133) 3134{ 3135 RPC_CN_DBG_RTN_PRINTF(rpc__cn_call_cancel_timer); 3136 3137 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 3138 ("(rpc__cn_call_cancel_timer) call_rep->%p cancel timer expired\n", call_r)); 3139 RPC_CN_LOCK (); 3140 call_r->cn_call_status = rpc_s_cancel_timeout; 3141 dcethread_interrupt_throw (call_r->u.client.cancel.thread_h); 3142 call_r->u.client.cancel.timer_running = false; 3143 3144 /* 3145 * Set the server had pending flag so that the cancel which 3146 * started this timer will be reposted in call_end. 3147 */ 3148 call_r->u.client.cancel.server_had_pending = true; 3149 rpc__timer_clear (&call_r->u.client.cancel.timer); 3150 RPC_CN_UNLOCK (); 3151 return (false); 3152} 3153