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** dgsct.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** DG protocol service routines. Handle server connection table (SCT). 90** 91** 92*/ 93 94#include <dg.h> 95#include <dgsct.h> 96#include <dgslive.h> 97#include <dgscall.h> 98#include <comauth.h> 99 100#include <dce/conv.h> 101 102/* ========================================================================= */ 103 104/* 105 * The following structure is used to register the network monitor function 106 * in the timer queue. 107 */ 108 109INTERNAL rpc_timer_t sct_timer; 110 111typedef struct { 112 rpc_clock_t timer_timestamp; 113 unsigned32 timer_last_scanned_count; 114 unsigned32 timer_last_freed_count; 115} sct_stats_t; 116 117INTERNAL sct_stats_t sct_stats; 118 119/* 120 * Keep a count of the number of SCT entries, active or not, so we know when we 121 * need to be running the monitor routine. (We especially don't want to be 122 * running the monitor for clients that would never need it.) 123 * 124 * This variable is only used under the protection of the global lock. 125 */ 126 127INTERNAL unsigned32 num_sct_entries = 0; 128 129/* 130 * Run the SCT monitor routine every 5 minutes, clean out entries that are over 131 * 10 minutes old. 132 */ 133 134#define SCT_MONITOR_INTERVAL 300 135#define SCTE_TIMEOUT_INTERVAL 600 136 137INTERNAL int rpc_g_dg_sct_mon_int = SCT_MONITOR_INTERVAL; 138INTERNAL int rpc_g_dg_sct_timeout = SCTE_TIMEOUT_INTERVAL; 139 140/* ========================================================================= */ 141 142INTERNAL void rpc__dg_sct_timer ( dce_pointer_t ); 143 144/* ========================================================================= */ 145 146/* 147 * R P C _ _ D G _ S C T _ I N Q _ S C A L L 148 * 149 * Return the connection's locked scall. If the connection doesn't have 150 * an (accurate) previous / in-progress scall then for all practical 151 * purposes it has no scall; return NULL. 152 * 153 * Also, check the scte's maybe chain if the current request is using 154 * maybe semantics. 155 */ 156 157PRIVATE void rpc__dg_sct_inq_scall 158( 159 rpc_dg_sct_elt_p_t scte, 160 rpc_dg_scall_p_t *scallp, 161 rpc_dg_recvq_elt_p_t rqe 162) 163{ 164 unsigned32 cur_rqe_seq = rqe->hdrp->seq; 165 rpc_dg_scall_p_t temp; 166 167 RPC_LOCK_ASSERT(0); 168 169 /* 170 * First see if the SCTE's ".scall" field holds a useable scall. 171 */ 172 *scallp = scte->scall; 173 if (*scallp != NULL) 174 { 175 RPC_DG_CALL_LOCK(&(*scallp)->c); 176 177 /* 178 * If the current RQE's sequence number is equal to the scall's 179 * sequence number, then this RQE is for the currently running 180 * call associated with the scall. If the RQE's sequence number 181 * is greater than the scall sequence number, then this RQE is 182 * for a new call. In either case, we want to use the current 183 * scall for deciding how to dispense with this new RQE. 184 */ 185 if (RPC_DG_SEQ_IS_LTE((*scallp)->c.call_seq, cur_rqe_seq)) 186 { 187 /* 188 * One last check we need to do is to make sure that the current 189 * .scall does not represent a call that was "backed out" (see 190 * rpc__dg_sct_backout_new_call). We can tell this by the 191 * sequence number in the SCTE. If this is the case, don't 192 * return the current scall, since it doesn't represent any 193 * useful state. 194 */ 195 if ((*scallp)->c.call_seq != (scte)->high_seq) 196 { 197 RPC_DG_CALL_UNLOCK(&(*scallp)->c); 198 *scallp = NULL; 199 RPC_DBG_PRINTF(rpc_e_dbg_general, 3, ( 200 "(rpc__dg_sct_inq_scall) not using backed out scall\n")); 201 202 return; 203 204 } 205 RPC_DBG_PRINTF(rpc_e_dbg_general, 3, ( 206 "(rpc__dg_sct_inq_scall) using cached scall\n")); 207 return; 208 } 209 210 /* 211 * The RQE's sequence number indicates that it is for a call 212 * prior to the one associated with the current .scall. Unlock 213 * the .scall, and go look for a matching scall on the maybe_chain. 214 */ 215 RPC_DG_CALL_UNLOCK(&(*scallp)->c); 216 *scallp = NULL; 217 } 218 219 for (temp = scte->maybe_chain; temp != NULL; 220 temp = (rpc_dg_scall_p_t) temp->c.next) 221 { 222 RPC_DG_CALL_LOCK(&temp->c); 223 if (temp->c.call_seq == cur_rqe_seq) 224 { 225 *scallp = temp; 226 RPC_DBG_PRINTF(rpc_e_dbg_general, 3, ( 227 "(rpc__dg_sct_inq_scall) using scall from maybe_chain\n")); 228 return; 229 } 230 RPC_DG_CALL_UNLOCK(&temp->c); 231 } 232 233 /* 234 * return with *scallp set to NULL 235 */ 236 RPC_DBG_PRINTF(rpc_e_dbg_general, 3, ( 237 "(rpc__dg_sct_inq_scall) didn't find scall\n")); 238} 239 240/* 241 * R P C _ _ D G _ S C T _ N E W _ C A L L 242 * 243 * Setup the connection for the new call to be run. Return a locked 244 * scall for the new call (create one if necessary). Make certain that 245 * no one does anything crazy with the connection sequence number. The 246 * scallp arg is [in,out]. If it is NULL a scall will be "materialized", 247 * otherwise, the scall it identifies must already be the one associated 248 * with the connection and it must already be locked (this operation 249 * is paired with INQ_SCALL() above). 250 */ 251 252PRIVATE void rpc__dg_sct_new_call 253( 254 rpc_dg_sct_elt_p_t scte, 255 rpc_dg_sock_pool_elt_p_t si, 256 rpc_dg_recvq_elt_p_t rqe, 257 rpc_dg_scall_p_t *scallp 258) 259{ 260 boolean maybe = RPC_DG_HDR_FLAG_IS_SET(rqe->hdrp, RPC_C_DG_PF_MAYBE); 261 unsigned32 cur_rqe_seq = rqe->hdrp->seq; 262 263 RPC_LOCK_ASSERT(0); 264 265 if (*(scallp) == NULL) 266 { 267 /* 268 * Use the SCTE's ".scall" pointer if available. Maybe calls require 269 * a little different treatment; if the maybe call was originally sent 270 * prior to the call associated with the ".scall" (i.e. has a lower 271 * sequence number), we want to make sure it doesn't count as an 272 * implicit ACK. In this case, just alloc up a new scall. 273 */ 274 275 *scallp = scte->scall; 276 277 if (*scallp != NULL) 278 { 279 RPC_DG_CALL_LOCK(&(*scallp)->c); 280 281 if (maybe && 282 RPC_DG_SEQ_IS_LT( cur_rqe_seq, (*scallp)->c.call_seq)) 283 { 284 RPC_DG_CALL_UNLOCK(&(*scallp)->c); 285 *scallp = NULL; 286 287 RPC_DBG_PRINTF(rpc_e_dbg_general, 3, ( 288 "(rpc__dg_sct_new_call) handling out-of-order maybe\n")); 289 } 290 else 291 { 292 RPC_DBG_PRINTF(rpc_e_dbg_general, 3, ( 293 "(rpc__dg_sct_new_call) using cached scall\n")); 294 } 295 } 296 } 297 else 298 { 299 /* assert(*scallp == scte->scall || *scallp is on maybe_chain); */ 300 } 301 if (*scallp != NULL) 302 { 303 rpc__dg_scall_reinit(*scallp, si, rqe); 304 } 305 else 306 { 307 *scallp = rpc__dg_scall_alloc(scte, si, rqe); 308 } 309 if (*scallp != NULL) 310 { 311 if (RPC_DG_SEQ_IS_LT((*scallp)->c.call_seq, scte->high_seq) && !maybe) 312 { 313 /* 314 * rpc_m_invalid_seqnum 315 * "(%s) Invalid call sequence number" 316 */ 317 rpc_dce_svc_printf ( 318 __FILE__, __LINE__, 319 "%s", 320 rpc_svc_general, 321 svc_c_sev_fatal | svc_c_action_abort, 322 rpc_m_invalid_seqnum, 323 "rpc__dg_sct_new_call" ); 324 } 325 if (!maybe || RPC_DG_SEQ_IS_LT(scte->high_seq, (*scallp)->c.call_seq)) 326 scte->high_seq = (*scallp)->c.call_seq; 327 } 328} 329 330/* 331 * R P C _ _ D G _ S C T _ B A C K O U T _ N E W _ C A L L 332 * 333 * A previously "tentatively accepted" RPC has now been unaccepted due 334 * to some server resource constraints. Backup the connection's notion 335 * of the highest sequence to ensure that a (possible) subsequent 336 * retransmission will be allowed to retry. 337 * 338 * Don't EVER use this if the call has actually been run! 339 */ 340 341PRIVATE void rpc__dg_sct_backout_new_call 342( 343 rpc_dg_sct_elt_p_t scte, 344 unsigned32 seq 345) 346{ 347 RPC_LOCK_ASSERT(0); 348 349 if (scte != NULL && seq == (scte)->high_seq) 350 { 351 scte->high_seq--; 352 } 353} 354 355/* 356 * R P C _ _ D G _ S C T _ L O O K U P 357 * 358 * Lookup the connection (SCTE) in the server connection table using 359 * the provided actid and probe hint (ahint). Return the scte or NULL 360 * if no matching entry is found. 361 * 362 * This increments the SCTE reference count (if one is found), making 363 * it unavailable for GCing - it should be released when the reference 364 * is no longer needed. 365 */ 366 367PRIVATE rpc_dg_sct_elt_p_t rpc__dg_sct_lookup 368( 369 uuid_p_t actid, 370 unsigned32 probe_hint 371) 372{ 373 rpc_dg_sct_elt_p_t scte; 374 unsigned16 probe; 375 boolean once = false; 376 unsigned32 st; 377 378 RPC_LOCK_ASSERT(0); 379 380 /* 381 * Determine the hash chain to use 382 */ 383 384 if (probe_hint == RPC_C_DG_NO_HINT || probe_hint >= RPC_DG_SCT_SIZE) 385 probe = rpc__dg_uuid_hash(actid) % RPC_DG_SCT_SIZE; 386 else 387 probe = probe_hint; 388 389 /* 390 * Scan down the probe chain, reserve and return a matching SCTE. 391 */ 392 393RETRY: 394 scte = rpc_g_dg_sct[probe]; 395 396 while (scte != NULL) 397 { 398 if (UUID_EQ(*actid, scte->actid, &st)) 399 { 400 RPC_DG_SCT_REFERENCE(scte); 401 return(scte); 402 } 403 else 404 scte = scte->next; 405 } 406 407 /* 408 * No matching entry found. If we used the provided hint, try 409 * recomputing the probe and if this yields a new probe, give it 410 * one more try. 411 */ 412 413 if (probe == probe_hint && !once) 414 { 415 once = true; 416 probe = rpc__dg_uuid_hash(actid) % RPC_DG_SCT_SIZE; 417 if (probe != probe_hint) 418 goto RETRY; 419 } 420 421 return(NULL); 422} 423 424/* 425 * R P C _ _ D G _ S C T _ G E T 426 * 427 * Lookup the connection (SCTE) in the server connection table using 428 * the provided actid and probe hint (ahint); create one if necessary 429 * (based on the call seq that is inducing its creation). 430 * Return the SCTE. 431 * 432 * This increments the SCTE reference count, making it unavailable for 433 * GCing - it should be released when the reference is no longer needed. 434 */ 435 436PRIVATE rpc_dg_sct_elt_p_t rpc__dg_sct_get 437( 438 uuid_p_t actid, 439 unsigned32 probe_hint, 440 unsigned32 seq 441) 442{ 443 rpc_dg_sct_elt_p_t scte; 444 unsigned16 probe; 445 446 /* 447 * Determine the hash chain to use. 448 */ 449 450 if (probe_hint == RPC_C_DG_NO_HINT || probe_hint >= RPC_DG_SCT_SIZE) 451 probe = rpc__dg_uuid_hash(actid) % RPC_DG_SCT_SIZE; 452 else 453 probe = probe_hint; 454 455 /* 456 * Use an existing entry if we've got one. 457 */ 458 459 scte = rpc__dg_sct_lookup(actid, probe); 460 if (scte != NULL) 461 return(scte); 462 463 /* 464 * Create the new SCTE, reserve it and add it to the head of the list. 465 */ 466 467 RPC_MEM_ALLOC(scte, rpc_dg_sct_elt_p_t, sizeof *scte, 468 RPC_C_MEM_DG_SCTE, RPC_C_MEM_NOWAIT); 469 scte->refcnt = 0; 470 scte->high_seq = seq - 1; 471 scte->high_seq_is_way_validated = false; 472 scte->auth_epv = NULL; 473 scte->key_info = NULL; 474 scte->scall = NULL; 475 scte->maybe_chain = NULL; 476 scte->actid = *actid; 477 scte->ahint = probe; 478 scte->timestamp = RPC_CLOCK_SEC(0); 479 scte->client = NULL; 480 481 RPC_LOCK_ASSERT(0); 482 483 /* 484 * Add the new SCTE to the head of the list. 485 */ 486 487 scte->next = rpc_g_dg_sct[probe]; 488 rpc_g_dg_sct[probe] = scte; 489 RPC_DG_SCT_REFERENCE(scte); /* This is for the reference from the SCT */ 490 491 /* 492 * Increment the count of SCTE's. If this is the first/only one, 493 * add the SCT monitor to the timer queue to handle aging SCTE's. 494 */ 495 496 rpc__server_incr_clients(); 497 num_sct_entries++; 498 if (num_sct_entries == 1) 499 { 500 rpc__timer_set(&sct_timer, rpc__dg_sct_timer, 501 (dce_pointer_t) NULL, RPC_CLOCK_SEC(rpc_g_dg_sct_mon_int)); 502 } 503 504 /* 505 * Reserve a reference to and return the SCTE. 506 */ 507 508 RPC_DG_SCT_REFERENCE(scte); 509 510 return(scte); 511} 512 513/* 514 * R P C _ _ D G _ S C T _ T I M E R 515 * 516 * This routine searches through the SCT for entries that have not been in use 517 * for a certain period of time. It is run peridically from the timer queue. 518 */ 519 520INTERNAL void rpc__dg_sct_timer 521( 522 dce_pointer_t junk ATTRIBUTE_UNUSED 523) 524{ 525 rpc_dg_sct_elt_p_t scte, prev_scte; 526 unsigned32 i; 527 int sct_timeout = rpc_g_dg_sct_timeout; 528 529 /* 530 * The SCT is protected by the global lock. 531 */ 532 533 RPC_LOCK(0); 534 535 sct_stats.timer_timestamp = rpc__clock_stamp(); 536 sct_stats.timer_last_freed_count = 0; 537 sct_stats.timer_last_scanned_count = 0; 538 539 /* 540 * Look in each bucket of hash table... 541 */ 542 543 for (i = 0; i < RPC_DG_SCT_SIZE; i++) 544 { 545 scte = rpc_g_dg_sct[i]; 546 prev_scte = NULL; 547 548 /* 549 * Scan each chain for scte's that have aged. 550 */ 551 552 while (scte != NULL) 553 { 554 sct_stats.timer_last_scanned_count++; 555 /* 556 * If the SCTE reference count is one, then the only reference 557 * is from the SCT itself. (Any other references would be 558 * from SCALLs.) So if the count is 1, and we're not 559 * monitoring liveness for client associated with this SCTE, 560 * and the SCTE hasn't been used in a while, release the 561 * SCTE. 562 */ 563 564 if (scte->refcnt == 1 && 565 (scte->client == NULL || scte->client->rundown == NULL) && 566 rpc__clock_aged(scte->timestamp, 567 RPC_CLOCK_SEC(sct_timeout))) 568 { 569 sct_stats.timer_last_freed_count++; 570 if (prev_scte == NULL) 571 rpc_g_dg_sct[i] = scte->next; 572 else 573 prev_scte->next = scte->next; 574 575 /* 576 * If the SCTE has reference to some auth_info, free it. 577 */ 578 579 if (scte->key_info) 580 { 581 RPC_DG_KEY_RELEASE(scte->key_info); 582 CLOBBER_PTR(scte->key_info); 583 } 584 585 /* 586 * If the SCTE has a reference to a client handle (ie. was 587 * monitoring liveness) release that reference. 588 */ 589 590 RPC_DG_CLIENT_RELEASE(scte); 591 592 /* 593 * Release the actual SCTE. 594 */ 595 596 RPC_MEM_FREE(scte, RPC_C_MEM_DG_SCTE); 597 598 rpc__server_decr_clients(); 599 num_sct_entries--; 600 601 scte = (prev_scte == NULL) ? rpc_g_dg_sct[i] : prev_scte->next; 602 } 603 else 604 { 605 prev_scte = scte; 606 scte = scte->next; 607 } 608 } 609 } 610 611 RPC_DBG_PRINTF(rpc_e_dbg_general, 5, 612 ("(sct_timer) Scanned %d Freed %d\n", 613 sct_stats.timer_last_scanned_count, 614 sct_stats.timer_last_freed_count)); 615 616 /* 617 * If there are no more SCTE's in the SCT, then remove the monitor 618 * routine from the timer queue. 619 */ 620 621 if (num_sct_entries == 0) 622 { 623 RPC_DBG_PRINTF(rpc_e_dbg_general, 2, 624 ("(sct_timer) removing SCT monitor from timer queue\n")); 625 626 rpc__timer_clear(&sct_timer); 627 } 628 629 RPC_UNLOCK(0); 630} 631 632/* 633 * R P C _ _ D G _ S C T _ M A K E _ W A Y _ B I N D I N G 634 * 635 * Make a binding to do a WAY call with. 636 * 637 * All WAY calls *must* be made using a activity id other than our own 638 * (i.e., we must not do a "real callback"; see conv.idl). To achieve 639 * this, we create a new call handle bound to the client. 640 * 641 * Alloc up a copy of the address before creating the binding handle, 642 * binding_free will expect to be able to free this pointer to the address. 643 */ 644 645PRIVATE rpc_binding_handle_t rpc__dg_sct_make_way_binding 646( 647 rpc_dg_sct_elt_p_t scte, 648 unsigned32 *st 649) 650{ 651 rpc_addr_p_t way_addr; 652 rpc_dg_binding_client_p_t client_binding; 653 unsigned32 xst; 654 655 RPC_LOCK_ASSERT(0); 656 657 /* 658 * Since the scte doesn't directly contain the info necessary 659 * to create a binding to the client, use the scall. 660 */ 661 if (scte->scall == NULL) 662 { 663 RPC_DBG_GPRINTF(("(rpc__dg_sct_make_way_binding) no scall\n")); 664 *st = rpc_s_who_are_you_failed; 665 return (NULL); 666 } 667 668 rpc__naf_addr_copy(scte->scall->c.addr, &way_addr, st); 669 670 client_binding = (rpc_dg_binding_client_p_t) rpc__binding_alloc 671 (false, &uuid_g_nil_uuid, RPC_C_PROTOCOL_ID_NCADG, way_addr, st); 672 673 if (*st != rpc_s_ok) 674 { 675 RPC_DBG_GPRINTF 676 (("(rpc__dg_make_way_binding) Couldn't create handle, st=0x%x\n", *st)); 677 rpc__naf_addr_free(&way_addr, &xst); 678 return (NULL); 679 } 680 681 /* 682 * Indicate that this handle was created for making calls on the 683 * conv interface. The packet rationing code needs to know this 684 * in order to allow the WAY/WAY2 call to inherit the packet 685 * reservation made by the originating scall. 686 */ 687 688 client_binding->is_WAY_binding = scte->scall->c.n_resvs; 689 690 /* 691 * Set the com_timeout value for this handle to match the one in use 692 * by the server. 693 */ 694 rpc_mgmt_set_com_timeout((rpc_binding_handle_t) client_binding, 695 rpc_mgmt_inq_server_com_timeout(), st); 696 697 return ((rpc_binding_handle_t) client_binding); 698} 699 700/* 701 * R P C _ _ D G _ S C T _ W A Y _ V A L I D A T E 702 * 703 * Ensure that the connection sequence information is Who-Are-You 704 * Validated. WAY validated sequence information is necessary to 705 * to ensure that non-idempotent calls have at-most-once semantics. 706 * 707 * Server's interlude to "conv_who_are_you" remote procedure (or the 708 * equivalent local procedure that handles authentication). 709 * 710 * The analogous "who_are_you" processing necessary for non-idempotent 711 * callbacks (from a server manager to the client originating the call, 712 * who needs to validate the callback's seq) is performed elsewhere. 713 */ 714 715PRIVATE void rpc__dg_sct_way_validate 716( 717 rpc_dg_sct_elt_p_t scte, 718 unsigned32 force_way_auth, 719 unsigned32 *st 720) 721{ 722 rpc_dg_sct_elt_p_t scte_ref; 723 unsigned32 seq; 724 unsigned32 xst; 725 rpc_key_info_p_t key_info; 726 idl_uuid_t cas_uuid; /* retrieved but ignored here. */ 727 rpc_binding_handle_t h; 728 729 /* 730 * The connection must be locked. 731 */ 732 RPC_LOCK_ASSERT(0); 733 734 *st = rpc_s_ok; 735 736 /* 737 * for lazy coders... 738 */ 739 if (RPC_DG_SCT_IS_WAY_VALIDATED(scte) && ! force_way_auth) 740 return; 741 742 h = rpc__dg_sct_make_way_binding(scte, st); 743 744 if (*st != rpc_s_ok) 745 return; 746 747 key_info = scte->key_info; 748 749 /* 750 * Since we're going to unlock the scte while performing the WAY, 751 * acquire a reference to it to ensure that it doesn't dissappear... 752 */ 753 scte_ref = scte; 754 RPC_DG_SCT_REFERENCE(scte_ref); 755 756 RPC_UNLOCK(0); 757 758 /* 759 * It's not entirely clear if the caller of this code will always 760 * (or must) have general cancel delivery disabled. To be flexible, 761 * try to do the right thing regardless of how we were called. A 762 * failure in either scenario results is a bad status (in the case 763 * of a cancel, we give the caller the opportunity to do something based 764 * on this knowledge. 765 * 766 * Note our use of "scte->actid" is "safe" even though we don't 767 * hold the scte lock at this time: (a) we do have a 'reference' to the 768 * scte, so it isn't going away and (b) nobody will be changing the 769 * actid. We could copy this info while holding the lock, but why waste 770 * the time / stack space? 771 */ 772 DCETHREAD_TRY 773 { 774 /* 775 * Do either an AUTH-WAY or a plain WAY. At least one AUTH-WAY 776 * (per call) is required if this is an authenticated call that 777 * we're validating (key_info != NULL). However, if the SCTE 778 * says that the high seq has been WAY validated, then we know 779 * we must have done the AUTH-WAY (and we're here because the 780 * client simply failed to present a non-zero boot time in the 781 * original request); in that case, just do the plain WAY (unless 782 * we're "forcing" a WAY, which the auth logic might be doing 783 * in some key expiration case). And clearly if the call is 784 * not authenticated, we just do the plain WAY. 785 */ 786 787 if (key_info != NULL && (force_way_auth || ! scte->high_seq_is_way_validated)) 788 { 789 rpc_dg_auth_epv_p_t auth_epv = scte->auth_epv; 790 791 RPC_DBG_PRINTF(rpc_e_dbg_general, 3, 792 ("(rpc__dg_sct_way_validate) Doing AUTH who-are-you callback\n")); 793 794 (*auth_epv->way) 795 (key_info, h, &scte->actid, rpc_g_dg_server_boot_time, &seq, 796 &cas_uuid, st); 797 } 798 else 799 { 800 RPC_DBG_PRINTF(rpc_e_dbg_general, 3, 801 ("(rpc__dg_sct_way_validate) Doing who-are-you callback\n")); 802 803 (*conv_v3_0_c_epv.conv_who_are_you) 804 (h, &scte->actid, rpc_g_dg_server_boot_time, &seq, st); 805 } 806 } 807 DCETHREAD_CATCH (dcethread_interrupt_e) 808 { 809 RPC_DBG_GPRINTF(("(rpc__dg_sct_way_validate) cancel exception while performing callback\n")); 810 *st = rpc_s_call_cancelled; 811 } 812 DCETHREAD_CATCH_ALL(THIS_CATCH) 813 { 814 RPC_DBG_GPRINTF(("(rpc__dg_sct_way_validate) exception while performing callback\n")); 815 *st = rpc_s_who_are_you_failed; 816 } 817 DCETHREAD_ENDTRY 818 819 rpc_binding_free((rpc_binding_handle_t *) &h, &xst); 820 821 /* 822 * Reaquire the connection's lock and release our temporary reference. 823 */ 824 RPC_LOCK(0); 825 RPC_DG_SCT_RELEASE(&scte_ref); 826 827 if (*st != rpc_s_ok) 828 { 829 RPC_DBG_GPRINTF 830 (("(rpc__dg_sct_way_validate) who_are_you failed, st=0x%x\n", *st)); 831 return; 832 } 833 834 /* 835 * The WAY succeded; update the connection's WAY validated sequence info. 836 * 837 * BE CAREFUL... 838 * Since we've had things unlocked, it is possible the the client 839 * has made a *new* call to us since we actually performed the WAY. 840 * If this has happened our newly determined seq will be less that 841 * what's in the scte; DON'T SET IT BACKWARDS - it is still correct 842 * to set it as way_validated. 843 */ 844 845 if (! RPC_DG_SEQ_IS_LT(seq, scte->high_seq)) 846 { 847 scte->high_seq = seq; 848 } 849 850 scte->high_seq_is_way_validated = true; 851 852 if (scte->scall == NULL) 853 { 854 RPC_DBG_GPRINTF(("(rpc__dg_sct_way_validate) SCTE's SCALL was NULL\n")); 855 } 856 else 857 { 858 RPC_DG_CALL_LOCK(&scte->scall->c); 859 scte->scall->client_needs_sboot = false; 860 RPC_DG_CALL_UNLOCK(&scte->scall->c); 861 } 862} 863 864/* 865 * R P C _ _ D G _ S C T _ F O R K _ H A N D L E R 866 * 867 * Handle fork related processing for this module. 868 */ 869 870PRIVATE void rpc__dg_sct_fork_handler 871( 872 rpc_fork_stage_id_t stage 873) 874{ 875 unsigned32 i; 876 877 switch ((int)stage) 878 { 879 case RPC_C_PREFORK: 880 break; 881 case RPC_C_POSTFORK_PARENT: 882 break; 883 case RPC_C_POSTFORK_CHILD: 884 /* 885 * Clear out the Server Connection Table 886 */ 887 num_sct_entries = 0; 888 for (i = 0; i < RPC_DG_SCT_SIZE; i++) 889 rpc_g_dg_sct[i] = NULL; 890 break; 891 } 892} 893