1/* 2 * Copyright (c) 2010-2011 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** cnassoc.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** The NCA Connection Protocol Service's Association 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 <cnp.h> /* NCA Connection private declarations */ 98#include <cnid.h> /* NCA Connection local ID service */ 99#include <cnrcvr.h> /* NCA Connection receiver thread */ 100#include <cnnet.h> /* NCA Connection network service */ 101#include <cnpkt.h> /* NCA Connection packet encoding */ 102#include <cnsm.h> /* NCA Connection state machine service */ 103#include <cnassm.h> /* NCA Connection association state machine */ 104#include <cnasgsm.h> /* NCA Connection association group state machine */ 105#include <comauth.h> /* Externals for Auth. Services sub-component */ 106#include <cncall.h> /* NCA connection call service */ 107#include <cnassoc.h> 108 109#include <dce/rpcexc.h> 110 111#if HAVE_LWIO_LWIO_H 112#include <lwio/lwio.h> 113#endif 114 115 116 117/******************************************************************************/ 118/* 119 * Internal variables 120 */ 121/******************************************************************************/ 122/* 123 * We want to serialize the group create operation. We do this so 124 * that we do not wind up with multiple groups if multiple threads 125 * from a client make RPCs to the same server. This would be especially 126 * painful if there are context handles since each of these groups will 127 * have to maintain an association. (If all the associations were in 128 * a single group, only one association needs to be maintained.) 129 * 130 * The following variables simulate a mutex around the group 131 * create operation. We call this the grp_new mutex. We do not 132 * use a real mutex because mutex waits are non-cancellable. We 133 * want this operation to be cancellable to support cancel timeouts 134 * even when there is no association. 135 * 136 * To acquire the grp_new mutex, a thread must set grp_new_in_progress to 137 * true. A thread must acquire this mutex prior to creating a group. 138 * If you have nested calls to assoc_request, only the outermost 139 * [initial] call to assoc_request should acquire the grp_new mutex. 140 * 141 * To release the grp_new mutex, a thread should clear grp_new_in_progress 142 * and do a condition broadcast on grp_new_wt. Only the call frame 143 * that acquired the grp_new mutex should release it. 144 * 145 * grp_new_waiters is an optimization. It is the number of threads 146 * waiting for the grp_new mutex. A thread must 147 * increment this prior to waiting for the grp_new mutex. 148 * We don't signal the grp_new_wt condition variable if 149 * there are no waiters when the grp_new mutex is released. 150 */ 151INTERNAL rpc_cond_t grp_new_wt; 152INTERNAL unsigned16 grp_new_waiters; 153INTERNAL boolean32 grp_new_in_progress; 154 155 156/******************************************************************************/ 157/* 158 * Internal routine declarations 159 */ 160/******************************************************************************/ 161/* 162 * R P C _ _ C N _ A S S O C _ O P E N 163 */ 164 165INTERNAL void rpc__cn_assoc_open ( 166 rpc_cn_assoc_p_t /*assoc*/, 167 rpc_addr_p_t /*rpc_addr*/, 168 rpc_if_rep_p_t /*if_r*/, 169 rpc_cn_local_id_t /*grp_id*/, 170 rpc_auth_info_p_t /*auth_info*/, 171 rpc_transport_info_p_t /*transport_info*/, 172 rpc_transfer_syntax_t * /*syntax*/, 173 unsigned16 * /*context_id*/, 174 rpc_cn_sec_context_p_t * /*sec*/, 175 unsigned32 * /*st*/); 176 177/* 178 * R P C _ _ C N _ A S S O C _ A L T E R _ C O N T E X T 179 */ 180 181INTERNAL void rpc__cn_assoc_alter_context ( 182 rpc_cn_assoc_p_t /*assoc*/, 183 rpc_if_rep_p_t /*if_r*/, 184 rpc_auth_info_p_t /*info*/, 185 rpc_transfer_syntax_t * /*syntax*/, 186 unsigned16 * /*context_id*/, 187 rpc_cn_sec_context_p_t * /*sec*/, 188 unsigned32 * /*st*/); 189 190/* 191 * R P C _ _ C N _ A S S O C _ R E C L A I M 192 */ 193 194INTERNAL void rpc__cn_assoc_reclaim ( 195 rpc_cn_local_id_t /*grp_id*/, 196 unsigned32 /*type*/, 197 boolean32 /*loop*/); 198 199/* 200 * R P C _ _ C N _ A S S O C _ T I M E R _ R E C L A I M 201 */ 202 203INTERNAL void rpc__cn_assoc_timer_reclaim ( 204 unsigned32 /*type*/); 205 206/* 207 * R P C _ _ C N _ A S S O C _ A C B _ A L L O C 208 */ 209 210INTERNAL rpc_cn_assoc_t *rpc__cn_assoc_acb_alloc ( 211 boolean32 /*wait*/, 212 unsigned32 /*type*/, 213 unsigned32 * /*st*/); 214 215/* 216 * R P C _ _ C N _ A S S O C _ G R P _ I N I T 217 */ 218 219INTERNAL void rpc__cn_assoc_grp_init ( 220 rpc_cn_assoc_grp_p_t /*assoc_grp*/, 221 unsigned32 /*index*/); 222 223/* 224 * R P C _ _ C N _ A S S O C _ G R P _ C R E A T E 225 */ 226 227INTERNAL rpc_cn_local_id_t rpc__cn_assoc_grp_create ( 228 unsigned32 * /*st*/); 229 230/* 231 * R P C _ _ C N _ A S S O C _ S Y N T A X _ A L L O C 232 */ 233 234INTERNAL rpc_cn_syntax_t *rpc__cn_assoc_syntax_alloc ( 235 rpc_if_rep_p_t /*if_r*/, 236 unsigned32 * /*st*/); 237 238 239/******************************************************************************/ 240/* 241 * Macros 242 */ 243/******************************************************************************/ 244 245 246/******************************************************************************/ 247/* 248 * Local defines 249 */ 250/******************************************************************************/ 251 252/* 253 * The number of association groups to allocate when the table needs 254 * to grow. 255 */ 256#define RPC_C_ASSOC_GRP_ALLOC_SIZE 10 257 258/* 259 * The default number of associations allowed on an association 260 * group. 261 */ 262#define RPC_C_ASSOC_GRP_MAX_ASSOCS_DEFAULT 0xffffffff 263 264/* 265 * The maximum resource wait in seconds. This is the maximum amount 266 * of time trying to request an association. This value is specified 267 * as 300 in Appendix A of the NCA connection architecture spec. 268 */ 269#define RPC_C_ASSOC_MAX_RESOURCE_WAIT 60 270 271/* 272 * The client idle connection disconnect time in seconds. 273 * This value is specified as 300 in Appendix A of the NCA connection 274 * architecture spec. 275 */ 276#define RPC_C_ASSOC_CLIENT_DISC_TIMER 60 277 278/* 279 * The server idle connection disconnect time in seconds. 280 * This value is specified as 300 in Appendix A of the NCA connection 281 * architecture spec. 282 */ 283#define RPC_C_ASSOC_SERVER_DISC_TIMER 60 284 285/* 286 * The initial amount of time in seconds to wait before retrying an 287 * association request. This corresponds to the slot time in the 288 * exponential backoff algorithm used. 289 */ 290#define RPC_C_ASSOC_INITIAL_WAIT_INTERVAL 1 291 292/* 293 * The maximum amount of time in seconds after each connection 294 * request attempt. 295 */ 296#define RPC_C_ASSOC_MAX_WAIT_INTERVAL 5 297 298 299/******************************************************************************/ 300/* 301 * Routine definitions 302 */ 303/******************************************************************************/ 304/* 305**++ 306** 307** ROUTINE NAME: rpc__cn_assoc_request 308** 309** SCOPE: PRIVATE - declared in cnassoc.h 310** 311** DESCRIPTION: 312** 313** This routine is called by the client call state machine 314** when an association is needed to perform an RPC over. The 315** returned association will contain a connection to the 316** desired address space as will have had the full presentation 317** negotiation performed over it. 318** 319** INPUTS: 320** 321** call_r The call rep for the RPC. 322** binding_r The binding rep containing the server 323** address space address. 324** if_r The interface rep through which this RPC is 325** being made containing the presentation 326** negotiation information. 327** 328** INPUTS/OUTPUTS: none 329** 330** OUTPUTS: 331** 332** syntax The negotiated transfer syntax. 333** context_id The context id of the transfer syntax 334** assigned by the client runtime. 335** sec The pointer to the negotiated security 336** context element, NULL if none. 337** st The return status of this routine. 338** rpc_s_ok 339** rpc_s_tsyntaxes_unsupported 340** rpc_s_unknown_if 341** 342** IMPLICIT INPUTS: none 343** 344** IMPLICIT OUTPUTS: none 345** 346** FUNCTION VALUE: 347** 348** return The association. NULL if not created. 349** 350** SIDE EFFECTS: none 351** 352**-- 353**/ 354 355PRIVATE rpc_cn_assoc_t *rpc__cn_assoc_request 356( 357 rpc_cn_call_rep_p_t call_r, 358 rpc_cn_binding_rep_p_t binding_r, 359 rpc_if_rep_p_t if_r, 360 rpc_transfer_syntax_t *syntax, 361 unsigned16 *context_id, 362 rpc_cn_sec_context_p_t *sec, 363 unsigned32 *st 364) 365{ 366 rpc_cn_assoc_t * volatile assoc = NULL; 367 rpc_cn_assoc_grp_t * volatile assoc_grp = NULL; 368 rpc_addr_p_t rpc_addr; 369 unsigned32 volatile wait_interval, total_wait; 370 rpc_cn_local_id_t grp_id; 371 rpc_cn_local_id_t volatile rem_grp_id; 372 struct timespec timespec; 373 struct timespec abstime; 374 375 /* 376 * i_hold_grp_new_mutex means that this call frame holds the 377 * grp_new mutex. The grp_new_mutex is described above. 378 */ 379 volatile boolean i_hold_grp_new_mutex; 380 381 volatile boolean32 retry_op; 382 volatile boolean old_server = true; /* MS servers are 5.0 servers */ 383 unsigned32 temp_st; 384 385 //DO_NOT_CLOBBER(assoc); 386 //DO_NOT_CLOBBER(assoc_grp); 387 //DO_NOT_CLOBBER(wait_interval); 388 //DO_NOT_CLOBBER(total_wait); 389 //DO_NOT_CLOBBER(rem_grp_id); 390 //DO_NOT_CLOBBER(i_hold_grp_new_mutex); 391 //DO_NOT_CLOBBER(old_server); 392 393 RPC_LOG_CN_ASSOC_REQ_NTR; 394 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_request); 395 CODING_ERROR (st); 396 397 /* 398 * The CN RPC protocol looks at the binding timeout as a binary 399 * value. If the timeout is infinite it will try forever to 400 * establish a connection. If not it will try once and rely on the 401 * transport protocol below to perform the appropriate retries. 402 * It would be nice if we could turn some generic transport knob 403 * to tell it how hard to try but as of today there is no such facility. 404 */ 405 wait_interval = RPC_C_ASSOC_INITIAL_WAIT_INTERVAL; 406 i_hold_grp_new_mutex = false; 407 total_wait = 0; 408 409 while (true) 410 { 411 /* 412 * Ideally we'd like to use an association which already exists, 413 * is open, and has already had the transfer syntax negotiated for 414 * the abstract syntax (interface UUID and version) given. To 415 * find a cached association we must first find an association 416 * group representing the server address space given in the 417 * binding rep. There are two ways of finding an association 418 * group. First we can use the group ID contained in the 419 * connection part of the binding rep. This will get us directly 420 * to an association group. If that doesn't work we can use the 421 * RPC address contained in the common part of the binding rep. 422 * This means we have to scan and compare possibly all the 423 * association groups. 424 */ 425 grp_id = rpc__cn_assoc_grp_lkup_by_id (binding_r->grp_id, 426 RPC_C_CN_ASSOC_GRP_CLIENT, 427 binding_r->common.transport_info, 428 st); 429 if (*st != rpc_s_ok) 430 { 431 /* 432 * The assoc group was not found using the group ID in the 433 * binding rep. Now try the RPC address in the binding rep. 434 */ 435 grp_id = rpc__cn_assoc_grp_lkup_by_addr (binding_r->common.rpc_addr, 436 binding_r->common.transport_info, 437 RPC_C_CN_ASSOC_GRP_CLIENT, 438 st); 439 } 440 441 /* 442 * Check whether an association group was found. 443 */ 444 assoc_grp = RPC_CN_ASSOC_GRP (grp_id); 445 if (assoc_grp != NULL) 446 { 447 /* 448 * We now have an association group. Save the group id in the 449 * binding rep for use on subsequent lookups and look for an open 450 * association on the group. 451 */ 452 binding_r->grp_id.all = assoc_grp->grp_id.all; 453 RPC_LIST_FIRST (assoc_grp->grp_assoc_list, 454 assoc, 455 rpc_cn_assoc_p_t); 456 457 /* 458 * Cycle through all the associations on this group 459 * looking for an unallocated one. 460 */ 461 while (assoc != NULL) 462 { 463 /* 464 * Look at the reference count of the association to determine 465 * whether it is allocated. 466 */ 467 if (assoc->assoc_ref_count == 0) 468 { 469 /* 470 * Store the call rep in the association for use 471 * in cancel timeout processing. 472 */ 473 assoc->call_rep = call_r; 474 475 /* 476 * Allocate the association. 477 * Send an association allocate request through 478 * the association state machine. This will put 479 * the association into the active state and 480 * will prevent other threads from allocating it. 481 */ 482 rpc__cn_assoc_alloc (assoc, st); 483 if (*st == rpc_s_ok) 484 { 485 /* 486 * This association is active. Send an alter 487 * presentation context event through the 488 * association state machine if necessary. 489 */ 490 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 491 ("CN: call_rep->%p assoc->%p desc->%p negotiating presentation syntax over existing association\n", 492 assoc->call_rep, 493 assoc, 494 assoc->cn_ctlblk.cn_sock)); 495 rpc__cn_assoc_alter_context (assoc, 496 if_r, 497 binding_r->common.auth_info, 498 syntax, 499 context_id, 500 sec, 501 st); 502 503 RPC_LOG_CN_ASSOC_REQ_XIT; 504 if (*st != rpc_s_ok) 505 { 506 /* 507 * The alter context request failed. 508 * Just deallocate the association and 509 * return NULL. 510 */ 511 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 512 ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation failed st = %x\n", 513 assoc->call_rep, 514 assoc, 515 assoc->cn_ctlblk.cn_sock, 516 *st)); 517 518 /* 519 * The call is about to be orphaned, so remove it from the assoc 520 */ 521 if (assoc->call_rep == call_r) 522 { 523 assoc->call_rep = NULL; 524 } 525 526 rpc__cn_assoc_dealloc (assoc, 527 call_r, 528 &temp_st); 529 return (NULL); 530 } 531 else 532 { 533 /* 534 * The alter context request succeeded. 535 * Return the association. 536 */ 537 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 538 ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation succeeded\n", 539 assoc->call_rep, 540 assoc, 541 assoc->cn_ctlblk.cn_sock)); 542 543 /* 544 * Update transport information on binding handle 545 */ 546 547 rpc__transport_info_release(binding_r->common.transport_info); 548 binding_r->common.transport_info = assoc->transport_info; 549 rpc__transport_info_retain(binding_r->common.transport_info); 550 551 return (assoc); 552 } 553 } 554 } 555 RPC_LIST_NEXT (assoc, assoc, rpc_cn_assoc_p_t); 556 } /* while (assoc != NULL) */ 557 558 /* 559 * Remember the secondary address for this group we're 560 * going to need it below to establish a new 561 * session/transport connection. 562 */ 563 rpc_addr = assoc_grp->grp_secaddr; 564 565 /* 566 * Remember the remote group id for this group. It will 567 * be sent to the server when the association is requested. 568 */ 569 rem_grp_id = assoc_grp->grp_remid; 570 } /* end if (assoc_grp != NULL) */ 571 572 else /* assoc_grp == NULL */ 573 { 574 575 /* 576 * Use the address in the binding rep to establish the 577 * new session/transport connection. 578 */ 579 rpc_addr = binding_r->common.rpc_addr; 580 RPC_CN_LOCAL_ID_CLEAR (rem_grp_id); 581 582 /* 583 * We don't have an association group at this point. 584 * We want to serialize the creation of association 585 * groups to prevent multiple association 586 * groups to the same server address space. 587 * We therefore acquire the grp_new mutex. 588 * 589 * Note: we can still get multiple association 590 * groups to the same address space if we have 591 * recursive calls to assoc_request. We can also 592 * get them if multiple threads from the same client 593 * use different protocol sequences to call the same 594 * server. But we don't expect either of these to be 595 * frequent occurences. 596 */ 597 598 /* 599 * Attempt to acquire the grp_new mutex. 600 */ 601 if (grp_new_in_progress) 602 { 603 /* 604 * Some other thread holds the grp_new mutex. We'll 605 * have to record ourself as a waiter for it and be 606 * patient. 607 */ 608 grp_new_waiters++; 609 610 while (grp_new_in_progress) 611 { 612 /* 613 * Since this is a cancellable operation we'll set 614 * up an exception handler. 615 */ 616 retry_op = true; 617 DCETHREAD_TRY 618 { 619 RPC_COND_WAIT (grp_new_wt, 620 rpc_g_global_mutex); 621 } 622 DCETHREAD_CATCH (dcethread_interrupt_e) 623 { 624 /* 625 * Record the fact that a cancel has been 626 * detected. Also, start a timer if this is 627 * the first cancel detected. 628 */ 629 rpc__cn_call_local_cancel (call_r, 630 &retry_op, 631 st); 632 assert(assoc != NULL); 633 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 634 ("(rpc__cn_assoc_request) call_rep->%p assoc->%p desc->%p cancel caught before association setup\n", 635 call_r, 636 assoc, 637 assoc->cn_ctlblk.cn_sock)); 638 } 639 DCETHREAD_ENDTRY 640 641 /* 642 * If the cancel timer expired decrement the 643 * count of threads waiting to establish a new 644 * association and return. 645 */ 646 if (!retry_op) 647 { 648 grp_new_waiters--; 649 return (NULL); 650 } 651 } 652 653 /* 654 * We're done waiting. Try for an existing 655 * association or at least existing group by going 656 * through the loop again. 657 */ 658 grp_new_waiters--; 659 continue; 660 } 661 else /* grp_new_in_progress is false; i.e., grp_new mutex 662 * is available. 663 */ 664 { 665 /* 666 * There is no other thread opening a new 667 * association. Acquire the grp_new mutex. 668 * We also set i_hold_grp_new_mutex. 669 * 670 * Note: If we get here, we are by definition, in 671 * the outermost call to assoc_request. 672 */ 673 grp_new_in_progress = true; 674 i_hold_grp_new_mutex = true; 675 676 } 677 } /* end else (assoc_grp == NULL) */ 678 679 /* 680 * Determine whether the association group we have at 681 * this point, if any, can support another association. 682 */ 683 if ((assoc_grp == NULL) 684 || 685 (assoc_grp->grp_cur_assoc < assoc_grp->grp_max_assoc)) 686 { 687 /* 688 * We can add another association to the group (if we 689 * have one) if it can be established. First create an 690 * association control block structure and its receiver thread. 691 * We don't check the return value because it always 692 * returns rpc_s_ok. 693 */ 694 assoc = rpc__cn_assoc_acb_alloc (true, 695 RPC_C_CN_ASSOC_CLIENT, 696 st); 697 if (*st != rpc_s_ok) { 698 if (i_hold_grp_new_mutex) { 699 grp_new_in_progress = false; 700 RPC_COND_BROADCAST (grp_new_wt, rpc_g_global_mutex); 701 } 702 return NULL; 703 } 704 705 /* 706 * We have an association control block. Send an 707 * association request event through its state machine. 708 * Set the association reference count to 1 so that this 709 * association will not be allocated by another thread 710 * while still being set up. 711 */ 712 RPC_CN_ASSOC_ACB_INC_REF (assoc); 713 assoc->assoc_ref_count++; 714 if (old_server) 715 { 716 assoc->assoc_vers_minor = RPC_C_CN_PROTO_VERS_COMPAT; 717 } 718 719 /* 720 * Store the call rep in the association for use 721 * in cancel timeout processing. 722 */ 723 assoc->call_rep = call_r; 724 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 725 ("CN: call_rep->%p assoc->%p desc->%p establishing connection & negotiating presentation syntax\n", 726 assoc->call_rep, 727 assoc, 728 assoc->cn_ctlblk.cn_sock)); 729 730 rpc__cn_assoc_open (assoc, 731 rpc_addr, 732 if_r, 733 rem_grp_id, 734 binding_r->common.auth_info, 735 binding_r->common.transport_info, 736 syntax, 737 context_id, 738 sec, 739 st); 740 741 /* 742 * Release the grp_new mutex if we locked it. 743 */ 744 if (i_hold_grp_new_mutex) 745 { 746 /* 747 * A new association has just been opened so reset 748 * the flag to allow other thread's which want to open 749 * new associations to do so. 750 */ 751 grp_new_in_progress = false; 752 RPC_COND_BROADCAST (grp_new_wt, 753 rpc_g_global_mutex); 754 } 755 RPC_CN_ASSOC_ACB_DEC_REF (assoc); 756 assoc->assoc_ref_count--; 757 if (*st == rpc_s_ok) 758 { 759 /* 760 * Allocate the association. 761 * Send an association allocate request through the association state 762 * machine. This will put the association into the active state. 763 */ 764 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 765 ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation succeeded\n", 766 assoc->call_rep, 767 assoc, 768 assoc->cn_ctlblk.cn_sock)); 769 770 rpc__cn_assoc_alloc (assoc, st); 771 if (*st == rpc_s_ok) 772 { 773 /* 774 * We now have an association group. Save the group id in the 775 * binding rep for use on subsequent lookups and look for an open 776 * association on the group. 777 */ 778 binding_r->grp_id.all = assoc->assoc_grp_id.all; 779 780 /* 781 * Update transport information on binding handle 782 */ 783 784 rpc__transport_info_release(binding_r->common.transport_info); 785 binding_r->common.transport_info = assoc->transport_info; 786 rpc__transport_info_retain(binding_r->common.transport_info); 787 788 /* 789 * The association has been allocated and is now 790 * ready for an RPC. 791 */ 792 RPC_LOG_CN_ASSOC_REQ_XIT; 793 return (assoc); 794 } 795 } 796 else 797 { 798 /* 799 * The association open failed. We may have failed 800 * while trying to establish a session/transport 801 * connection or during or after presentation 802 * negotiation. If the connect request failed the 803 * association will be in the closed state and the acb 804 * just has to be dealloced to go back on the 805 * lookaside list. If the presentation 806 * negotiation failed the association will already 807 * on a group. We can also just deallocate the 808 * acb in this case since it is attached to an 809 * association group. If a cancel timeout occured 810 * the negotiation will eventually complete and the 811 * association will be placed on a group. 812 */ 813 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 814 ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation failed st = %x\n", 815 assoc->call_rep, 816 assoc, 817 assoc->cn_ctlblk.cn_sock, 818 *st)); 819 820 /* 821 * The call is about to be orphaned, so remove it from the assoc 822 */ 823 if (assoc->call_rep == call_r) 824 { 825 assoc->call_rep = NULL; 826 } 827 828 if ((old_server == false) && 829 (*st == rpc_s_connection_closed) && 830 ((assoc->assoc_vers_minor == RPC_C_CN_PROTO_VERS_COMPAT) || 831 (assoc->bind_packets_sent > 1))) 832 { 833 /* Probably a 5.0 server with fragmented BINDs - retry */ 834 old_server = true; 835 RPC_CN_ASSOC_ACB_INC_REF (assoc); 836 rpc__cn_assoc_acb_dealloc (assoc); 837 assoc = NULL; 838 continue; 839 } 840 841 RPC_CN_ASSOC_ACB_INC_REF (assoc); 842 rpc__cn_assoc_acb_dealloc (assoc); 843 assoc = NULL; 844 845 /* 846 * Return a failure immediately if: 847 * 848 * 1) the association open failed because it was 849 * rejected or a local error occurred OR 850 * 851 * 2) the connection request failed and the binding 852 * timeout was less than 6 853 */ 854 if (!rpc__cn_network_connect_fail (*st)) 855 { 856 return (NULL); 857 } 858 else 859 { 860 if (binding_r->common.timeout < 6) 861 { 862 return (NULL); 863 } 864 } 865 } /* end else (*st != rpc_s_ok) */ 866 } /* end if (assoc_grp == NULL) || (assoc_grp->grp_cur_assoc */ 867 /* < assoc_grp->grp_max_assoc) */ 868 else 869 { 870 *st = rpc_s_assoc_grp_max_exceeded; 871 } 872 873 /* 874 * We've dropped to this point in the for loop if 875 * 876 * 1) the connection request failed because it either timed 877 * out or the server rejected it and the binding timeout 878 * was 6 or higher or 879 * 880 * 2) the maximum number of associations were reached on a 881 * particular group. 882 * 883 * In any case we will try to reclaim some open 884 * associations, and perform an exponential backoff. 885 */ 886 timespec.tv_sec = MIN (RPC_RANDOM_GET (0, wait_interval), 887 RPC_C_ASSOC_MAX_WAIT_INTERVAL); 888 timespec.tv_nsec = 0; 889 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 890 ("CN: call_rep->%p assoc->%p desc->%p backing off %lu seconds before retrying ...\n", 891 call_r, 892 NULL, 893 NULL, 894 (unsigned long)timespec.tv_sec)); 895 if (!RPC_CN_LOCAL_ID_VALID (grp_id)) 896 { 897 rpc__cn_assoc_reclaim (grp_id, RPC_C_CN_ASSOC_GRP_CLIENT, true); 898 RPC_CN_UNLOCK (); 899 retry_op = true; 900 DCETHREAD_TRY 901 { 902 dcethread_delay (×pec); 903 } 904 DCETHREAD_CATCH (dcethread_interrupt_e) 905 { 906 RPC_CN_LOCK (); 907 908 /* 909 * Record the fact that a cancel has been 910 * detected. Also, start a timer if this is 911 * the first cancel detected. 912 */ 913 rpc__cn_call_local_cancel (call_r, 914 &retry_op, 915 st); 916 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 917 ("(rpc__cn_assoc_request) call_rep->%p assoc->%p desc->%p cancel caught before association setup\n", 918 call_r, 919 NULL, 920 NULL)); 921 RPC_CN_UNLOCK (); 922 } 923 DCETHREAD_ENDTRY 924 RPC_CN_LOCK (); 925 if (!retry_op) 926 { 927 return (NULL); 928 } 929 } 930 else 931 { 932 assoc_grp = RPC_CN_ASSOC_GRP (grp_id); 933 assert(assoc_grp != NULL); 934 rpc__cn_assoc_reclaim (assoc_grp->grp_id, 935 RPC_C_CN_ASSOC_GRP_CLIENT, 936 true); 937 assoc_grp->grp_assoc_waiters++; 938 dcethread_get_expiration (×pec, &abstime); 939 retry_op = true; 940 DCETHREAD_TRY 941 { 942 RPC_COND_TIMED_WAIT (assoc_grp->grp_assoc_wt, 943 rpc_g_global_mutex, 944 &abstime); 945 } 946 DCETHREAD_CATCH (dcethread_interrupt_e) 947 { 948 /* 949 * Record the fact that a cancel has been 950 * detected. Also, start a timer if this is 951 * the first cancel detected. 952 */ 953 rpc__cn_call_local_cancel (call_r, 954 &retry_op, 955 st); 956 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 957 ("(rpc__cn_assoc_request) call_rep->%p cancel caught before association setup\n", 958 call_r)); 959 } 960 DCETHREAD_ENDTRY 961 if (!retry_op) 962 { 963 return (NULL); 964 } 965 assoc_grp->grp_assoc_waiters--; 966 } 967 968 total_wait = total_wait + wait_interval; 969 if (binding_r->common.timeout != rpc_c_binding_infinite_timeout) 970 { 971 if (total_wait > 972 MIN ((binding_r->common.timeout * 6), RPC_C_ASSOC_MAX_RESOURCE_WAIT)) 973 { 974 break; 975 } 976 } 977 wait_interval = MIN ((wait_interval * 2), RPC_C_ASSOC_MAX_WAIT_INTERVAL); 978 } /* while (true) */ 979 980 /* 981 * The status code returned from here will be the last one 982 * returned from the rpc__socket_connect call. 983 */ 984 return (NULL); 985} 986 987 988/***********************************************************************/ 989/* 990**++ 991** 992** ROUTINE NAME: rpc__cn_assoc_listen 993** 994** SCOPE: PRIVATE - declared in cnassoc.h 995** 996** DESCRIPTION: 997** 998** This routine is called when a new connection has been accepted. 999** A new association will be set up, including its receiver 1000** thread, and returned. 1001** 1002** INPUTS: 1003** 1004** desc The network descriptor of the new connection. 1005** endpoint The local endpoint the connection came into. 1006** 1007** INPUTS/OUTPUTS: none 1008** 1009** OUTPUTS: 1010** 1011** st The return status of this routine. 1012** rpc_s_ok 1013** 1014** IMPLICIT INPUTS: none 1015** 1016** IMPLICIT OUTPUTS: none 1017** 1018** FUNCTION VALUE: 1019** 1020** return The association. NULL if not created. 1021** 1022** SIDE EFFECTS: none 1023** 1024**-- 1025**/ 1026 1027PRIVATE rpc_cn_assoc_t *rpc__cn_assoc_listen 1028( 1029 rpc_socket_t newsock, 1030 unsigned_char_p_t endpoint, 1031 unsigned32 *st 1032) 1033{ 1034 rpc_cn_assoc_t *assoc; 1035 rpc_socket_error_t serr = RPC_C_SOCKET_OK; 1036 rpc_transport_info_p_t transport_info = NULL; 1037 1038 RPC_LOG_CN_ASSOC_LIS_NTR; 1039 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_listen); 1040 CODING_ERROR (st); 1041 1042 /* 1043 * Create a server association. 1044 */ 1045 assoc = rpc__cn_assoc_acb_alloc (false, RPC_C_CN_ASSOC_SERVER, st); 1046 if (*st != rpc_s_ok) 1047 { 1048 /* 1049 * The creation failed. The caller will close the socket. 1050 */ 1051 return (NULL); 1052 } 1053 1054 /* 1055 * Indicate that there is a valid connection. 1056 */ 1057 assoc->cn_ctlblk.cn_state = RPC_C_CN_OPEN; 1058 assoc->cn_ctlblk.cn_sock = newsock; 1059 assoc->cn_ctlblk.cn_listening_endpoint = endpoint; 1060 1061 /* Attempt to query socket for transport information */ 1062 serr = rpc__socket_inq_transport_info(newsock, &transport_info); 1063 if (RPC_SOCKET_IS_ERR(serr)) 1064 { 1065 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS, 1066 ("(rpc__cn_assoc_listen) desc->%p rpc__socket_inq_transport_info failed, error = %d\n", 1067 assoc->cn_ctlblk.cn_sock, 1068 serr)); 1069 } 1070 else 1071 { 1072 rpc__transport_info_release(assoc->transport_info); 1073 assoc->transport_info = transport_info; 1074 } 1075 1076 /* 1077 * A connection is now set up. Tell the receiver thread to begin 1078 * receiving on the connection. 1079 */ 1080 if (assoc->cn_ctlblk.cn_rcvr_waiters) 1081 { 1082 RPC_COND_SIGNAL (assoc->cn_ctlblk.cn_rcvr_cond, 1083 rpc_g_global_mutex); 1084 } 1085 else 1086 { 1087 RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS, 1088 ( "####### assoc->%p We're not signalling here\n", assoc )); 1089 } 1090 *st = rpc_s_ok; 1091 RPC_LOG_CN_ASSOC_LIS_XIT; 1092 return (assoc); 1093} 1094 1095 1096/******************************************************************************/ 1097/* 1098**++ 1099** 1100** ROUTINE NAME: rpc__cn_assoc_alloc 1101** 1102** SCOPE: PRIVATE - declared in cnassoc.h 1103** 1104** DESCRIPTION: 1105** 1106** This routine will send an association allocate request 1107** through the association state and allocate the association 1108** control block. 1109** 1110** INPUTS: 1111** 1112** assoc The association being allocated 1113** 1114** INPUTS/OUTPUTS: none 1115** 1116** OUTPUTS: 1117** 1118** st The return status of this routine. 1119** rpc_s_ok 1120** 1121** IMPLICIT INPUTS: none 1122** 1123** IMPLICIT OUTPUTS: none 1124** 1125** FUNCTION VALUE: none 1126** 1127** SIDE EFFECTS: none 1128** 1129**-- 1130**/ 1131 1132PRIVATE void rpc__cn_assoc_alloc 1133( 1134 rpc_cn_assoc_p_t assoc, 1135 unsigned32 *st 1136) 1137{ 1138 RPC_LOG_CN_ASSOC_ALLOC_NTR; 1139 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_alloc); 1140 CODING_ERROR(st); 1141 1142 RPC_CN_STATS_INCR (alloced_assocs); 1143 RPC_CN_ASSOC_ACB_INC_REF (assoc); 1144 RPC_CN_ASSOC_EVAL_USER_EVENT (assoc, 1145 RPC_C_ASSOC_ALLOCATE_REQ, 1146 NULL, 1147 *st); 1148 RPC_LOG_CN_ASSOC_ALLOC_XIT; 1149} 1150 1151 1152/******************************************************************************/ 1153/* 1154**++ 1155** 1156** ROUTINE NAME: rpc__cn_assoc_dealloc 1157** 1158** SCOPE: PRIVATE - declared in cnassoc.h 1159** 1160** DESCRIPTION: 1161** 1162** This routine will send a deallocate event through the 1163** association state machine and deallocate the association 1164** control block. 1165** 1166** INPUTS: 1167** 1168** assoc The association being deallocated 1169** call_rep The call rep of the association. 1170** 1171** INPUTS/OUTPUTS: none 1172** 1173** OUTPUTS: 1174** 1175** st The return status of this routine. 1176** rpc_s_ok 1177** 1178** IMPLICIT INPUTS: none 1179** 1180** IMPLICIT OUTPUTS: none 1181** 1182** FUNCTION VALUE: none 1183** 1184** SIDE EFFECTS: none 1185** 1186**-- 1187**/ 1188 1189PRIVATE void rpc__cn_assoc_dealloc 1190( 1191 rpc_cn_assoc_p_t assoc, 1192 rpc_cn_call_rep_p_t call_rep, 1193 unsigned32 *st 1194) 1195{ 1196 rpc_cn_assoc_grp_t *assoc_grp; 1197 rpc_cn_fragbuf_t *fragbuf; 1198 1199 RPC_LOG_CN_ASSOC_DEALLOC_NTR; 1200 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_dealloc); 1201 CODING_ERROR(st); 1202 1203 *st = rpc_s_ok; 1204 if (assoc != NULL) 1205 { 1206 /* 1207 * Send a deallocate request through the association state 1208 * machine. Make sure to clear the association status code 1209 * first so that the deallocate request will be processed (the 1210 * macro EVAL_USER_EVENT checks that the association status is 1211 * OK before processing the event). 1212 */ 1213 RPC_CN_STATS_INCR (dealloced_assocs); 1214 assoc->assoc_status = rpc_s_ok; 1215 RPC_CN_ASSOC_EVAL_USER_EVENT (assoc, 1216 RPC_C_ASSOC_DEALLOCATE_REQ, 1217 NULL, 1218 *st); 1219 1220 /* 1221 * Signal any threads waiting for an association that they can 1222 * retry. Only client threads wait for an existing association. 1223 */ 1224 assoc_grp = RPC_CN_ASSOC_GRP (assoc->assoc_grp_id); 1225 if ((assoc_grp != NULL) && 1226 (assoc_grp->grp_assoc_waiters) && 1227 (assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT)) 1228 { 1229 RPC_COND_SIGNAL (assoc_grp->grp_assoc_wt, 1230 rpc_g_global_mutex); 1231 } 1232 1233 /* 1234 * If the passed call_rep is the same as the call rep in the passed 1235 * assoc, then it's ok to flush the receive queue of the association 1236 * just in case this call was orphaned. (The alter context request 1237 * failed in rpc__cn_assoc_request().) 1238 * If both the call rep in the passed assoc and the assoc in the 1239 * passed call rep are NULL, then it's ok to flush the receive queue 1240 * of the association just in case this call was orphaned. (The link 1241 * was broken by rpc__cn_assoc_pop_call().) 1242 * Otherwise, don't flush the receive queue - it means that this 1243 * call rep belongs to an orphaned or being about to finish call. 1244 * The call rep in the assoc refers to a queued call to be executed. 1245 */ 1246 if (call_rep == assoc->call_rep 1247 || (assoc->call_rep == NULL && call_rep->assoc == NULL)) 1248 { 1249 1250 /* 1251 * Flush the receive queue of the association just in case this 1252 * call was orphaned. 1253 */ 1254 RPC_LIST_FIRST (assoc->msg_list, 1255 fragbuf, 1256 rpc_cn_fragbuf_p_t); 1257 while (fragbuf != NULL) 1258 { 1259 rpc_cn_fragbuf_t *next_fragbuf; 1260 1261 RPC_LIST_NEXT (fragbuf, 1262 next_fragbuf, 1263 rpc_cn_fragbuf_p_t); 1264 if (fragbuf->fragbuf_dealloc != NULL) 1265 { 1266 (*fragbuf->fragbuf_dealloc)(fragbuf); 1267 } 1268 fragbuf = next_fragbuf; 1269 } 1270 RPC_LIST_INIT (assoc->msg_list); 1271 } 1272 1273 /* 1274 * Deallocate the association control block. 1275 */ 1276 rpc__cn_assoc_acb_dealloc (assoc); 1277 } 1278 RPC_LOG_CN_ASSOC_DEALLOC_XIT; 1279} 1280 1281 1282/***********************************************************************/ 1283/* 1284**++ 1285** 1286** ROUTINE NAME: rpc__cn_assoc_abort 1287** 1288** SCOPE: PRIVATE - declared in cnassoc.h 1289** 1290** DESCRIPTION: 1291** 1292** This routine will send an abort association request through the 1293** association state machine. The caller of this routine is assumed 1294** to not have a reference to the acb (i.e. it may be the association 1295** timer reclaimation thread). 1296** 1297** INPUTS: 1298** 1299** assoc The association. 1300** 1301** INPUTS/OUTPUTS: none 1302** 1303** OUTPUTS: 1304** 1305** st The return status of this routine. 1306** rpc_s_ok 1307** 1308** IMPLICIT INPUTS: none 1309** 1310** IMPLICIT OUTPUTS: none 1311** 1312** FUNCTION VALUE: none 1313** 1314** SIDE EFFECTS: none 1315** 1316**-- 1317**/ 1318 1319PRIVATE void rpc__cn_assoc_abort 1320( 1321 rpc_cn_assoc_p_t assoc, 1322 unsigned32 *st 1323) 1324{ 1325 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_abort); 1326 1327 RPC_CN_STATS_INCR (aborted_assocs); 1328 1329 /* 1330 * Send an association abort request through the association 1331 * state machine. Make sure to clear the association status code 1332 * first so the event will be processed. 1333 */ 1334 assoc->assoc_status = rpc_s_ok; 1335 RPC_CN_ASSOC_EVAL_USER_EVENT (assoc, 1336 RPC_C_ASSOC_ABORT_REQ, 1337 NULL, 1338 *st); 1339} 1340 1341 1342/******************************************************************************/ 1343/* 1344**++ 1345** 1346** ROUTINE NAME: rpc__cn_assoc_pop_call 1347** 1348** SCOPE: PRIVATE - declared in cnassoc.h 1349** 1350** DESCRIPTION: 1351** 1352** This routine will return the call rep contained on the association. 1353** 1354** INPUTS: 1355** 1356** assoc The association containing the call rep. 1357** 1358** INPUTS/OUTPUTS: none 1359** 1360** OUTPUTS: none 1361** 1362** IMPLICIT INPUTS: none 1363** 1364** IMPLICIT OUTPUTS: none 1365** 1366** FUNCTION VALUE: 1367** 1368** call_r The call rep. 1369** 1370** SIDE EFFECTS: none 1371** 1372**-- 1373**/ 1374 1375PRIVATE rpc_cn_call_rep_t *rpc__cn_assoc_pop_call 1376( 1377 rpc_cn_assoc_p_t assoc, 1378 rpc_cn_call_rep_p_t call_rep 1379) 1380{ 1381 rpc_cn_call_rep_t *call_r; 1382 rpc_cn_assoc_grp_t *assoc_grp; 1383 unsigned32 st; 1384 1385 RPC_LOG_CN_ASSOC_POP_CALL_NTR; 1386 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_pop_call); 1387 1388 if (assoc != NULL) 1389 { 1390 /* 1391 * Decrement the association group's total call count. If it 1392 * becomes zero, it's a server association group and the current 1393 * state is call wait send a no calls indication event through 1394 * the group's state machine. 1395 */ 1396 assoc_grp = RPC_CN_ASSOC_GRP (assoc->assoc_grp_id); 1397 if (assoc_grp != NULL) 1398 { 1399 assoc_grp->grp_callcnt--; 1400 if ((assoc_grp->grp_flags & RPC_C_CN_ASSOC_GRP_SERVER) 1401 && 1402 (assoc_grp->grp_callcnt == 0) 1403 && 1404 (assoc_grp->grp_state.cur_state == 1405 RPC_C_SERVER_ASSOC_GRP_CALL_WAIT)) 1406 { 1407 RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp, 1408 RPC_C_ASSOC_GRP_NO_CALLS_IND, 1409 assoc, 1410 assoc_grp->grp_status); 1411 } 1412 } 1413 1414 /* 1415 * If this was the last call on a client association send a 1416 * calls done event through its state machine. 1417 */ 1418 if (assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT) 1419 { 1420 /* 1421 * Make sure to clear the association status code first 1422 * so this event will be processed. 1423 */ 1424 assoc->assoc_status = rpc_s_ok; 1425 RPC_CN_ASSOC_EVAL_USER_EVENT (assoc, 1426 RPC_C_ASSOC_CALLS_DONE, 1427 NULL, 1428 st); 1429 } 1430 1431 /* 1432 * Save a pointer to the call rep on the association. 1433 */ 1434 call_r = assoc->call_rep; 1435 1436 /* 1437 * If the passed call_rep is the same as the call rep in the 1438 * passed assoc, then it's ok to break the link. Otherwise, 1439 * don't change the assoc - it means that this call rep belongs 1440 * to an orphaned call. The assoc refers to a queued call to be 1441 * executed. 1442 */ 1443 if (call_rep == call_r) 1444 { 1445 assoc->call_rep = NULL; 1446 } 1447 1448 /* 1449 * Break the connection from the call rep back to the association. 1450 */ 1451 call_rep->assoc = NULL; 1452 1453 RPC_LOG_CN_ASSOC_POP_CALL_XIT; 1454 } 1455 else 1456 { 1457 call_r = NULL; 1458 } 1459 1460 return (call_r); 1461} 1462 1463 1464/******************************************************************************/ 1465/* 1466**++ 1467** 1468** ROUTINE NAME: rpc__cn_assoc_push_call 1469** 1470** SCOPE: PRIVATE - declared in cnassoc.h 1471** 1472** DESCRIPTION: 1473** 1474** This routine will put a call rep on an association. 1475** 1476** INPUTS: 1477** 1478** assoc The association containing the call rep. 1479** call_r The call rep to be placed. 1480** 1481** INPUTS/OUTPUTS: none 1482** 1483** OUTPUTS: none 1484** 1485** IMPLICIT INPUTS: none 1486** 1487** IMPLICIT OUTPUTS: none 1488** 1489** FUNCTION VALUE: none 1490** 1491** SIDE EFFECTS: none 1492** 1493**-- 1494**/ 1495 1496PRIVATE void rpc__cn_assoc_push_call 1497( 1498 rpc_cn_assoc_p_t assoc, 1499 rpc_cn_call_rep_p_t call_r, 1500 unsigned32 *st 1501) 1502{ 1503 rpc_cn_assoc_grp_t *assoc_grp; 1504 1505 RPC_LOG_CN_ASSOC_PUSH_CALL_NTR; 1506 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_push_call); 1507 1508 /* 1509 * Push the new call rep onto the association. 1510 */ 1511 assoc->call_rep = call_r; 1512 1513 /* 1514 * Increment the association group's total call count. 1515 */ 1516 assoc_grp = RPC_CN_ASSOC_GRP (assoc->assoc_grp_id); 1517 if (assoc_grp != NULL) 1518 { 1519 *st = rpc_s_ok; 1520 assoc_grp->grp_callcnt++; 1521 } 1522 else 1523 { 1524 *st = rpc_s_assoc_grp_not_found; 1525 } 1526 1527 RPC_LOG_CN_ASSOC_PUSH_CALL_XIT; 1528} 1529 1530 1531/******************************************************************************/ 1532/* 1533**++ 1534** 1535** ROUTINE NAME: rpc__cn_assoc_queue_frag 1536** 1537** SCOPE: PRIVATE - declared in cnassoc.h 1538** 1539** DESCRIPTION: 1540** 1541** This routine will queue a fragment buffer on the end of the 1542** message list of an association. In addition it will notify any 1543** thread waiting for a fragment buffer on this association that 1544** one is available. 1545** 1546** INPUTS: 1547** 1548** assoc The association containing the queue of 1549** fragment buffers. 1550** fragbuf The fragment buffer to queue. 1551** signal true if the condition variable should be signalled. 1552** 1553** INPUTS/OUTPUTS: none 1554** 1555** OUTPUTS: none 1556** 1557** IMPLICIT INPUTS: none 1558** 1559** IMPLICIT OUTPUTS: none 1560** 1561** FUNCTION VALUE: none 1562** 1563** SIDE EFFECTS: none 1564** 1565**-- 1566**/ 1567 1568PRIVATE void rpc__cn_assoc_queue_frag 1569( 1570 rpc_cn_assoc_p_t assoc, 1571 rpc_cn_fragbuf_p_t fragbuf, 1572 boolean32 signal 1573) 1574{ 1575 RPC_LOG_CN_ASSOC_Q_FRAG_NTR; 1576 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_queue_frag); 1577 1578 /* 1579 * Queue the fragment buffer to the tail of the list. 1580 */ 1581 RPC_LIST_ADD_TAIL (assoc->msg_list, fragbuf, rpc_cn_fragbuf_p_t); 1582 1583 /* 1584 * Notify any waiting threads that there's a buffer on this 1585 * association if the caller indicated it and there are waiters. 1586 */ 1587 if (signal && assoc->assoc_msg_waiters) 1588 { 1589 RPC_COND_SIGNAL (assoc->assoc_msg_cond, 1590 rpc_g_global_mutex); 1591 } 1592 RPC_LOG_CN_ASSOC_Q_FRAG_XIT; 1593} 1594 1595 1596/******************************************************************************/ 1597/* 1598**++ 1599** 1600** ROUTINE NAME: rpc__cn_assoc_queue_dummy_frag 1601** 1602** SCOPE: PRIVATE - declared in cnassoc.h 1603** 1604** DESCRIPTION: 1605** 1606** This routine will queue the built-in dummy fragment buffer on 1607** the end of the message list of an association. In addition it will notify 1608** any thread waiting for a fragment buffer on this association that 1609** one is available. 1610** 1611** INPUTS: 1612** 1613** assoc The association containing the queue of 1614** fragment buffers. 1615** 1616** INPUTS/OUTPUTS: none 1617** 1618** OUTPUTS: none 1619** 1620** IMPLICIT INPUTS: none 1621** 1622** IMPLICIT OUTPUTS: none 1623** 1624** FUNCTION VALUE: none 1625** 1626** SIDE EFFECTS: none 1627** 1628**-- 1629**/ 1630 1631PRIVATE void rpc__cn_assoc_queue_dummy_frag 1632( 1633 rpc_cn_assoc_p_t assoc 1634) 1635{ 1636 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_queue_dummy_frag); 1637 1638 /* 1639 * Queue the fragment buffer to the tail of the list. 1640 */ 1641 RPC_LIST_ADD_TAIL (assoc->msg_list, 1642 &assoc->assoc_dummy_fragbuf, 1643 rpc_cn_fragbuf_p_t); 1644 1645 /* 1646 * Notify any waiting threads that there's a buffer on this 1647 * association if the caller indicated it and there are waiters. 1648 */ 1649 if (assoc->assoc_msg_waiters) 1650 { 1651 RPC_COND_SIGNAL (assoc->assoc_msg_cond, 1652 rpc_g_global_mutex); 1653 } 1654} 1655 1656 1657/******************************************************************************/ 1658/* 1659**++ 1660** 1661** ROUTINE NAME: rpc__cn_assoc_receive_frag 1662** 1663** SCOPE: PRIVATE - declared in cnassoc.h 1664** 1665** DESCRIPTION: 1666** 1667** This routine will receive a fragment over the connection 1668** attached to an association. 1669** 1670** INPUTS: 1671** 1672** assoc The association to receive from. 1673** fragbuf The place to put the received fragment. 1674** 1675** INPUTS/OUTPUTS: none 1676** 1677** OUTPUTS: 1678** 1679** st The return status of this routine. 1680** rpc_s_ok 1681** 1682** IMPLICIT INPUTS: none 1683** 1684** IMPLICIT OUTPUTS: none 1685** 1686** FUNCTION VALUE: 1687** 1688** rpc_s_ok 1689** 1690** SIDE EFFECTS: none 1691** 1692**-- 1693**/ 1694 1695PRIVATE void rpc__cn_assoc_receive_frag 1696( 1697 rpc_cn_assoc_p_t assoc, 1698 rpc_cn_fragbuf_p_t *fragbuf, 1699 unsigned32 *st 1700) 1701{ 1702 volatile boolean32 retry_op; 1703 rpc_cn_call_rep_p_t call_rep; 1704 rpc_binding_rep_p_t binding_r; 1705 1706 RPC_LOG_CN_ASSOC_RECV_FRAG_NTR; 1707 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_receive_frag); 1708 CODING_ERROR(st); 1709 1710 /* 1711 * Wait for the receiver thread to put something on the queue. 1712 */ 1713 retry_op = true; 1714 while ((assoc->assoc_status == rpc_s_ok) && (RPC_LIST_EMPTY (assoc->msg_list))) 1715 { 1716 /* 1717 * Save the assoc's call_rep before we begin the wait. 1718 */ 1719 call_rep = assoc->call_rep; 1720 binding_r = call_rep->binding_rep; 1721 assert(binding_r != NULL); 1722 1723 assoc->assoc_msg_waiters++; 1724 1725 /* 1726 * Since this is a cancellable operation we'll set 1727 * up an exception handler. 1728 */ 1729 RPC_LOG_TRY_PRE; 1730 DCETHREAD_TRY 1731 RPC_LOG_TRY_POST; 1732 { 1733 RPC_COND_WAIT (assoc->assoc_msg_cond, 1734 rpc_g_global_mutex); 1735 } 1736 RPC_LOG_CATCH_PRE; 1737 DCETHREAD_CATCH (dcethread_interrupt_e) 1738 RPC_LOG_CATCH_POST; 1739 { 1740 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 1741 ("(rpc__cn_assoc_receive_frag) call_rep->%p assoc->%p desc->%p cancel caught\n", 1742 assoc->call_rep, 1743 assoc, 1744 assoc->cn_ctlblk.cn_sock)); 1745 rpc__cn_call_local_cancel (call_rep, 1746 &retry_op, 1747 st); 1748 } 1749 RPC_LOG_ENDTRY_PRE; 1750 DCETHREAD_ENDTRY 1751 RPC_LOG_ENDTRY_POST; 1752 1753 assoc->assoc_msg_waiters--; 1754 1755 /* 1756 * If the call_rep is different from the original call, it means 1757 * the original call was orphaned and another call began in 1758 * another call executor thread (on this assoc). In this 1759 * case we don't want to read a fragbuf (it doesn't belong to us). 1760 * We'll get here when the stop_orphan_action_rtn either signals 1761 * the assoc_msg_cond condition variable cancels the call executor 1762 * thread. 1763 */ 1764 if (call_rep != assoc->call_rep) 1765 { 1766 *st = rpc_s_call_orphaned; 1767 return; 1768 } 1769 1770 /* 1771 * If a cancel was caught and the operation should not be 1772 * retried just return now. The error status is already set up. 1773 */ 1774 if (!retry_op) 1775 { 1776 return; 1777 } 1778 } 1779 1780 /* 1781 * Remove a fragment from the queue. 1782 */ 1783 RPC_LIST_REMOVE_HEAD (assoc->msg_list, 1784 *fragbuf, 1785 rpc_cn_fragbuf_p_t); 1786 1787 *st = assoc->assoc_status; 1788 RPC_LOG_CN_ASSOC_RECV_FRAG_XIT; 1789} 1790 1791 1792/******************************************************************************/ 1793/* 1794**++ 1795** 1796** ROUTINE NAME: rpc__cn_assoc_send_frag 1797** 1798** SCOPE: PRIVATE - declared in cnassoc.h 1799** 1800** DESCRIPTION: 1801** 1802** This routine will send a vector of fragments over the connection 1803** attached to an association. 1804** 1805** INPUTS: 1806** 1807** assoc The association to send over. 1808** iovector The iovector containing the buffers to be sent. 1809** sec The security context element containing 1810** information required to apply the authn 1811** level requested, NULL if none. 1812** 1813** INPUTS/OUTPUTS: none 1814** 1815** OUTPUTS: 1816** 1817** st The return status of this routine. 1818** rpc_s_ok 1819** rpc_s_connection_aborted 1820** rpc_s_connection_closed 1821** 1822** IMPLICIT INPUTS: none 1823** 1824** IMPLICIT OUTPUTS: none 1825** 1826** FUNCTION VALUE: none 1827** 1828** SIDE EFFECTS: none 1829** 1830**-- 1831**/ 1832 1833PRIVATE void rpc__cn_assoc_send_frag 1834( 1835 rpc_cn_assoc_p_t assoc, 1836 rpc_iovector_p_t iovector, 1837 rpc_cn_sec_context_p_t sec, 1838 unsigned32 *st 1839) 1840{ 1841 rpc_socket_iovec_t iov[RPC_C_MAX_IOVEC_LEN]; 1842 volatile int iovcnt; 1843 rpc_socket_iovec_t * volatile iovp; 1844 rpc_socket_iovec_t out_iov; 1845 static rpc_addr_p_t addr = NULL; 1846 volatile size_t bytes_to_send; 1847 volatile boolean32 free_iov_buffer; 1848 volatile boolean32 retry_op; 1849 volatile rpc_socket_error_t serr; 1850 size_t cc; 1851 byte_p_t volatile save_base = NULL; 1852 1853 //DO_NOT_CLOBBER(iovcnt); 1854 //DO_NOT_CLOBBER(iovp); 1855 //DO_NOT_CLOBBER(bytes_to_send); 1856 //DO_NOT_CLOBBER(free_iov_buffer); 1857 //DO_NOT_CLOBBER(save_base); 1858 1859 RPC_LOG_CN_ASSOC_SEND_FRAG_NTR; 1860 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_send_frag); 1861 CODING_ERROR(st); 1862 1863 if (!assoc->cn_ctlblk.cn_sock) 1864 { 1865 *st = rpc_s_connection_closed; 1866 return; 1867 } 1868 1869 memset(&iov[0], 0, sizeof(iov)); 1870 1871 /* 1872 * Convert the RPC iovector array of buffers passed in the 1873 * system defined iov array of buffers to be handed to the 1874 * socket interface. 1875 */ 1876 RPC_CN_NETWORK_IOVECTOR_TO_IOV (iovector, 1877 iov, 1878 iovcnt, 1879 bytes_to_send); 1880 iovp = &iov[0]; 1881 1882 /* 1883 * Apply the authentication level requested, if any. 1884 */ 1885 free_iov_buffer = false; 1886 if (sec != NULL) 1887 { 1888 RPC_CN_AUTH_PRE_SEND (&assoc->security, 1889 sec, 1890 iovp, 1891 iovcnt, 1892 &out_iov, 1893 st); 1894 if (*st != rpc_s_ok) 1895 { 1896 if (assoc->assoc_flags & RPC_C_CN_ASSOC_SERVER) 1897 { 1898 dce_error_string_t error_text; 1899 int temp_status; 1900 1901 dce_error_inq_text(*st, error_text, &temp_status); 1902 1903 /* 1904 * rpc_m_call_failed_s 1905 * "%s on server failed: %s" 1906 */ 1907 rpc_dce_svc_printf ( 1908 __FILE__, __LINE__, 1909 "%s %x", 1910 rpc_svc_auth, 1911 svc_c_sev_error, 1912 rpc_m_call_failed_s, 1913 "RPC_CN_AUTH_PRE_SEND", 1914 error_text ); 1915 } 1916 return; 1917 }; 1918 1919 /* 1920 * The pre_send routine may have had to coalesce the iov 1921 * elements given to it into a single buffer for encryption. 1922 * If so then we should send that instead of what was given 1923 * to pre_send. 1924 */ 1925 if (out_iov.iov_base != NULL) 1926 { 1927 iovp = &out_iov; 1928 iovcnt = 1; 1929 bytes_to_send = iovp->iov_len; 1930 free_iov_buffer = true; 1931 save_base = iovp->iov_base; 1932 } 1933 } 1934 1935 /* 1936 * Now send the constructed system iov array on the connection 1937 * identified in the association control block. 1938 */ 1939 serr = 0; 1940 /* be careful, retry_op really is read contrary to what clang 1941 analyzer states */ 1942 retry_op = true; 1943 while ((bytes_to_send) && (!RPC_SOCKET_IS_ERR (serr))) 1944 { 1945 RPC_LOG_TRY_PRE; 1946 DCETHREAD_TRY 1947 RPC_LOG_TRY_POST; 1948 { 1949 /* 1950 * Unlock the global mutex in case we get flow blocked. This 1951 * will allow other threads to continue. Set the "in_sendmsg" 1952 * flag to indicate to the receiver thread that we are in sendmsg 1953 * so it should not send any events through the state machine 1954 * until we are done. 1955 */ 1956 assoc->cn_ctlblk.in_sendmsg = true; 1957 RPC_CN_UNLOCK (); 1958 1959#ifdef NON_CANCELLABLE_IO 1960 /* 1961 * By posix definition dcethread_enableasync is not a "cancel 1962 * point" because it must return an error status and an errno. 1963 * dcethread_enableasync(1) will not deliver 1964 * a pending cancel nor will the cancel be delivered asynchronously, 1965 * thus the need for dcethread_testcancel. 1966 */ 1967 dcethread_enableasync_throw(1); 1968 dcethread_checkinterrupt_throw(); 1969#endif /* NON_CANCELLABLE_IO */ 1970 serr = rpc__socket_sendmsg ( 1971 assoc->cn_ctlblk.cn_sock, 1972 iovp, 1973 iovcnt, 1974 addr, 1975 &cc); 1976 1977#ifdef NON_CANCELLABLE_IO 1978 dcethread_enableasync_throw(0); 1979#endif /* NON_CANCELLABLE_IO */ 1980 /* 1981 * A sendmsg has just completed. Re-aquire the global mutex 1982 * and notify our receiver thread that we are done if it is 1983 * waiting. 1984 * 1985 * NOTE that we also need to reacquire the mutex in 1986 * every DCETHREAD_CATCH clause associated with this TRY/ENDTRY. 1987 */ 1988 RPC_CN_LOCK (); 1989 assoc->cn_ctlblk.in_sendmsg = false; 1990 1991 } 1992 RPC_LOG_CATCH_PRE; 1993 DCETHREAD_CATCH (dcethread_interrupt_e) 1994 RPC_LOG_CATCH_POST; 1995 { 1996#ifdef NON_CANCELLABLE_IO 1997 dcethread_enableasync_throw(0); 1998#endif /* NON_CANCELLABLE_IO */ 1999 /* 2000 * A sendmsg has just completed. Re-aquire the global mutex 2001 * and notify our receiver thread that we are done if it is 2002 * waiting. 2003 */ 2004 RPC_CN_LOCK (); 2005 assoc->cn_ctlblk.in_sendmsg = false; 2006 2007 /* 2008 * The test for cancel is before any data has been sent. 2009 * Set count of bytes of data sent to zero. 2010 */ 2011 cc = 0; 2012 /* 2013 * Do NOT forward the cancel to the server just record 2014 * that it was detected. 2015 * Note: this is a copy of rpc__cn_call_local_cancel() 2016 * with the call to rpc__cn_call_forward_cancel() removed. 2017 */ 2018 if (RPC_CALL_IS_CLIENT (((rpc_call_rep_t *) assoc->call_rep))) 2019 { 2020 /* 2021 * Record the cancel that was just detected. 2022 */ 2023 assoc->call_rep->u.client.cancel.local_count++; 2024 rpc__cn_call_start_cancel_timer (assoc->call_rep, st); 2025 if (*st == rpc_s_ok) 2026 { 2027 retry_op = true; 2028 } 2029 else 2030 { 2031 retry_op = false; 2032 } 2033 } 2034 else 2035 { 2036 retry_op = false; 2037 *st = rpc_s_call_cancelled; 2038 } 2039 2040 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 2041 ("(rpc__cn_assoc_send_frag) call_rep->%p assoc->%p desc->%p cancel caught\n", 2042 assoc->call_rep, 2043 assoc, 2044 assoc->cn_ctlblk.cn_sock)); 2045 2046 } 2047 DCETHREAD_CATCH (dcethread_SIGPIPE_e) 2048 { 2049#ifdef NON_CANCELLABLE_IO 2050 dcethread_enableasync_throw(0); 2051#endif 2052 /* 2053 * A sendmsg has just completed. Re-aquire the global mutex 2054 * and notify our receiver thread that we are done if it is 2055 * waiting. 2056 */ 2057 RPC_CN_LOCK (); 2058 assoc->cn_ctlblk.in_sendmsg = false; 2059 2060 cc = -1; 2061 serr = RPC_C_SOCKET_EPIPE; 2062 } 2063 RPC_LOG_ENDTRY_PRE; 2064 DCETHREAD_ENDTRY 2065 RPC_LOG_ENDTRY_POST; 2066 2067 if (assoc->cn_ctlblk.waiting_for_sendmsg_complete) 2068 { 2069 RPC_COND_SIGNAL (assoc->cn_ctlblk.cn_rcvr_cond, 2070 rpc_g_global_mutex); 2071 } 2072 2073 /* 2074 * If a cancel was caught and the operation should not be 2075 * retried just return now. The error status is already set 2076 * up. 2077 */ 2078 if (!retry_op) 2079 { 2080 return; 2081 } 2082 2083 /* 2084 * Check the operation for an error. 2085 */ 2086 if (RPC_SOCKET_IS_ERR (serr)) 2087 { 2088 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS, 2089 ("(rpc__cn_assoc_send_frag) call_rep->%p assoc->%p desc->%p SENDMSG failed, error=%d\n", 2090 assoc->call_rep, 2091 assoc, 2092 assoc->cn_ctlblk.cn_sock, 2093 RPC_SOCKET_ETOI(serr))); 2094 /* 2095 * The transmit failed. Find out why. 2096 */ 2097 switch (serr) 2098 { 2099 case (RPC_C_SOCKET_ECONNRESET): 2100 assoc->assoc_status = rpc_s_connection_aborted; 2101 *st = rpc_s_connection_aborted; 2102 break; 2103 2104 default: 2105 assoc->assoc_status = rpc_s_connection_closed; 2106 *st = rpc_s_connection_closed; 2107 } 2108 break; 2109 } 2110 2111 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 2112 ("CN: call_rep->%p assoc->%p desc->%p sent %ld bytes\n", 2113 assoc->call_rep, 2114 assoc, 2115 assoc->cn_ctlblk.cn_sock, 2116 cc)); 2117 bytes_to_send -= cc; 2118 if (bytes_to_send) 2119 { 2120 RPC_CN_NETWORK_IOV_ADJUST (iovp, iovcnt, cc); 2121 } 2122 } 2123 2124 /* 2125 * Free the security allocated contiguous buffer is we have to. 2126 */ 2127 if (free_iov_buffer) 2128 { 2129 RPC_MEM_FREE (save_base, 2130 RPC_C_MEM_CN_ENCRYPT_BUF); 2131 } 2132 2133 if (!RPC_SOCKET_IS_ERR (serr)) 2134 { 2135 /* 2136 * Keep some stats on the packets sent. 2137 */ 2138 RPC_CN_STATS_INCR (pstats[RPC_CN_PKT_PTYPE (((rpc_cn_packet_p_t) iovector->elt[0].data_addr))].sent); 2139 RPC_CN_STATS_INCR (pkts_sent); 2140 *st = rpc_s_ok; 2141 RPC_CN_PKT_TRC (((rpc_cn_packet_p_t) iovector->elt[0].data_addr)); 2142 RPC_CN_IOV_DUMP (iovector); 2143 2144 /* 2145 * Increment the per-association security context next send 2146 * sequence number. 2147 */ 2148 assoc->security.assoc_next_snd_seq++; 2149 } 2150 RPC_LOG_CN_ASSOC_SEND_FRAG_XIT; 2151} 2152 2153 2154/******************************************************************************/ 2155/* 2156**++ 2157** 2158** ROUTINE NAME: rpc__cn_assoc_send_fragbuf 2159** 2160** SCOPE: PRIVATE - declared in cnassoc.h 2161** 2162** DESCRIPTION: 2163** 2164** This routine will convert a fragbuf to a vector of fragments 2165** and send them over a connection. If indicated the fragbuf will 2166** then be freed. 2167** 2168** INPUTS: 2169** 2170** assoc The association to send over. 2171** fragbuf The fragbuf to be sent. 2172** sec The security context element containing 2173** information required to apply the authn 2174** level requested, NULL if none. 2175** freebuf Flags to indicate we should free the fragbuf. 2176** 2177** INPUTS/OUTPUTS: none 2178** 2179** OUTPUTS: 2180** 2181** st The return status of this routine. 2182** 2183** IMPLICIT INPUTS: none 2184** 2185** IMPLICIT OUTPUTS: none 2186** 2187** FUNCTION VALUE: none 2188** 2189** SIDE EFFECTS: none 2190** 2191**-- 2192**/ 2193 2194PRIVATE void rpc__cn_assoc_send_fragbuf 2195( 2196 rpc_cn_assoc_p_t assoc, 2197 rpc_cn_fragbuf_p_t fragbuf, 2198 rpc_cn_sec_context_p_t sec, 2199 boolean32 freebuf, 2200 unsigned32 *st 2201) 2202{ 2203 rpc_iovector_t iovector; 2204 2205 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_send_fragbuf); 2206 2207 /* 2208 * The PDU is ready to be sent. Put it into an RPC 2209 * iovector structure. 2210 */ 2211 iovector.num_elt = 1; 2212 iovector.elt[0].flags = 0; 2213 iovector.elt[0].data_addr = (byte_p_t) fragbuf->data_p; 2214 iovector.elt[0].data_len = fragbuf->data_size; 2215 2216 /* 2217 * Now actually send the PDU. 2218 */ 2219 rpc__cn_assoc_send_frag (assoc, &iovector, sec, st); 2220 2221 /* 2222 * Free up the fragment buffer we used whether the send 2223 * succeeded or failed. 2224 */ 2225 if (freebuf) 2226 (*fragbuf->fragbuf_dealloc)(fragbuf); 2227} 2228 2229 2230/******************************************************************************/ 2231/* 2232**++ 2233** 2234** ROUTINE NAME: rpc__cn_assoc_syntax_negotiate 2235** 2236** SCOPE: PRIVATE - declared in cnassoc.h 2237** 2238** DESCRIPTION: 2239** 2240** This routine takes as input a list of abstract syntaxes. Each 2241** abstract syntax has a list of transfer syntaxes associated with 2242** it. This routine will determine whether any of the transfer syntaxes 2243** associated with an abstract syntax are supported. Since an abstract 2244** syntax is really an interface UUID and version this is done by 2245** performing an interface lookup which returns the interface 2246** specification data structure. This structure contains the list of 2247** transfer syntaxes the stub supports. Note that this is another 2248** place we'd have to expand the list of transfer syntaxes if procdural 2249** marshaling were being supported. 2250** 2251** INPUTS: 2252** 2253** assoc The association over which the negotiation 2254** is taking place. 2255** pres_cont_list A list of abstract syntaxes. Each abstract 2256** syntax contains a list of transfer syntaxes. 2257** 2258** INPUTS/OUTPUTS: 2259** 2260** size On input, the size left for formatting the 2261** presentation result list. On output the 2262** actual size taken for it. 2263** 2264** OUTPUTS: 2265** 2266** pres_result_list A list of negotiated transfer syntaxes. One 2267** for each abstract syntax in the 2268** presentation context list. 2269** st The return status of this routine. 2270** 2271** IMPLICIT INPUTS: none 2272** 2273** IMPLICIT OUTPUTS: none 2274** 2275** FUNCTION VALUE: none 2276** 2277** SIDE EFFECTS: none 2278** 2279**-- 2280**/ 2281 2282PRIVATE void rpc__cn_assoc_syntax_negotiate 2283( 2284 rpc_cn_assoc_p_t assoc, 2285 rpc_cn_pres_cont_list_p_t pres_cont_list, 2286 unsigned32 *size, 2287 rpc_cn_pres_result_list_t *pres_result_list, 2288 unsigned32 *st 2289) 2290{ 2291 unsigned16 ihint; 2292 rpc_if_rep_t *if_r; 2293 boolean syntax_match; 2294 rpc_cn_syntax_t *pres_context; 2295 unsigned32 i, j, k; 2296 2297 CODING_ERROR (st); 2298 RPC_LOG_CN_ASSOC_SYN_NEG_NTR; 2299 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_syntax_negotiate); 2300 2301 if ((i = sizeof (rpc_cn_pres_result_list_t) + 2302 (sizeof (rpc_cn_pres_result_t) * 2303 (pres_cont_list->n_context_elem - 1))) > *size) 2304 { 2305 *st = RPC_S_HEADER_FULL; 2306 *size = 0; 2307 return; 2308 } 2309 2310 *size = i; 2311 *st = rpc_s_ok; 2312 2313 /* 2314 * The number of results has to be the same as the number of 2315 * context elements in the list. 2316 */ 2317 pres_result_list->n_results = pres_cont_list->n_context_elem; 2318 2319 /* 2320 * For each element in the presentation context list determine 2321 * if the server stub supports a common transfer syntaxes. 2322 */ 2323 for (i = 0; i < pres_cont_list->n_context_elem; i++) 2324 { 2325 /* 2326 * Find the interface specification for the abstract syntax 2327 * (really interface UUID and version). The interface spec 2328 * contains the list of transfer syntaxes supported by the stub. 2329 */ 2330 ihint = RPC_C_INVALID_IHINT; 2331 rpc__if_lookup (&pres_cont_list->pres_cont_elem[i].abstract_syntax.id, 2332 pres_cont_list->pres_cont_elem[i].abstract_syntax.version, 2333 NULL, 2334 &ihint, 2335 &if_r, 2336 NULL, 2337 NULL, 2338 st); 2339 2340#ifdef DEBUG 2341 if (RPC_DBG_EXACT (rpc_es_dbg_cn_errors, 2342 RPC_C_CN_DBG_IF_LOOKUP)) 2343 { 2344 *st = RPC_S_CN_DBG_FAILURE; 2345 } 2346#endif 2347 2348 if (*st != rpc_s_ok) 2349 { 2350 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 2351 ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation failed - abstract syntax not registered - st = %x\n", 2352 assoc->call_rep, 2353 assoc, 2354 assoc->cn_ctlblk.cn_sock, 2355 *st)); 2356 2357 /* 2358 * There is no interface registered for the abstract 2359 * syntax given. Fill in the result for this abstract 2360 * syntax in the result list. 2361 */ 2362 pres_result_list->pres_results[i].result = 2363 RPC_C_CN_PCONT_PROVIDER_REJECTION; 2364 2365 pres_result_list->pres_results[i].reason = 2366 RPC_C_CN_PPROV_ABSTRACT_SYNTAX_NOT_SUPPORTED; 2367 2368 memset ((char *)&(pres_result_list->pres_results[i].transfer_syntax), 2369 0, 2370 sizeof (rpc_cn_pres_syntax_id_t)); 2371 } 2372 else 2373 { 2374 /* 2375 * An interface was found. Now try and find a transfer 2376 * syntax common to both the list given in the 2377 * presentation context list and the list in the 2378 * interface spec. 2379 */ 2380 for (j = 0, syntax_match = false; 2381 (!syntax_match) && 2382 (j < pres_cont_list->pres_cont_elem[i].n_transfer_syn); 2383 j++) 2384 { 2385 for (k = 0; k < if_r->syntax_vector.count; k++) 2386 { 2387 if (RPC_CN_ASSOC_SYNTAX_EQUAL ( 2388 &(pres_cont_list->pres_cont_elem[i].transfer_syntaxes[j]), 2389 &(if_r->syntax_vector.syntax_id[k]), 2390 &st)) 2391 { 2392 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 2393 ("CN: call_rep->%p assoc->%p desc->%p presentation syntax negotiated\n", 2394 assoc->call_rep, 2395 assoc, 2396 assoc->cn_ctlblk.cn_sock)); 2397 2398 /* 2399 * We have a transfer syntax which matches. 2400 * Allocate a syntax element, fill it in, 2401 * and put it on the association syntax list. 2402 * Mark the the syntax appropriately in the presentation 2403 * results list and skip to the next 2404 * abstract syntax. Note that the transfer 2405 * syntax UUID is not filled in. The server 2406 * stub requires only the syntax vector index. 2407 */ 2408 pres_context = rpc__cn_assoc_syntax_alloc (if_r, st); 2409 2410 pres_context->syntax_ihint = ihint; 2411 pres_context->syntax_pres_id = pres_cont_list->pres_cont_elem[i].pres_context_id; 2412 pres_context->syntax_valid = true; 2413 pres_context->syntax_vector_index = k; 2414 RPC_LIST_ADD_TAIL (assoc->syntax_list, pres_context, rpc_cn_syntax_p_t); 2415 2416 pres_result_list->pres_results[i].result = 2417 RPC_C_CN_PCONT_ACCEPTANCE; 2418 2419 pres_result_list->pres_results[i].transfer_syntax = 2420 pres_cont_list->pres_cont_elem[i].transfer_syntaxes[j]; 2421 2422 syntax_match = true; 2423 break; 2424 } 2425 } /* end for (k...) */ 2426 } /* end for (j...) */ 2427 2428#ifdef DEBUG 2429 if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, 2430 RPC_C_CN_DBG_NO_XFER_SYNTAX)) 2431 { 2432 syntax_match = false; 2433 } 2434#endif 2435 2436 /* 2437 * See if a syntax was matched for this abstract syntax. 2438 */ 2439 if (!syntax_match) 2440 { 2441 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 2442 ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation failed - no matching transfer syntax\n", 2443 assoc->call_rep, 2444 assoc, 2445 assoc->cn_ctlblk.cn_sock)); 2446 2447 /* 2448 * No matching syntax was found. Mark the 2449 * presentation result list appropriately. 2450 */ 2451 pres_result_list->pres_results[i].result = 2452 RPC_C_CN_PCONT_PROVIDER_REJECTION; 2453 2454 pres_result_list->pres_results[i].reason = 2455 RPC_C_CN_PPROV_PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED; 2456 2457 memset ((char *)&(pres_result_list->pres_results[i].transfer_syntax), 2458 0, 2459 sizeof (rpc_cn_pres_syntax_id_t)); 2460 } /* end if (!syntax_match) */ 2461 } /* end else (st != rpc_s_unkwown_if) */ 2462 } /* end for (i = 0; i < pres_cont_list->n_context_elem; i++) */ 2463 2464 *st = rpc_s_ok; 2465 RPC_LOG_CN_ASSOC_SYN_NEG_XIT; 2466} 2467 2468 2469/******************************************************************************/ 2470/* 2471**++ 2472** 2473** ROUTINE NAME: rpc__cn_assoc_syntax_lkup_by_id 2474** 2475** SCOPE: PRIVATE - declared in cnassoc.h 2476** 2477** DESCRIPTION: 2478** 2479** This routine will lookup the presentation context element by 2480** matching the presentation context id. 2481** 2482** INPUTS: 2483** 2484** assoc The association being looked up. 2485** context_id The context id of the presentation context being looked up. 2486** 2487** INPUTS/OUTPUTS: none 2488** 2489** OUTPUTS: 2490** 2491** pres_context The pointer to the matching presentation 2492** context element. 2493** st The return status of this routine. 2494** rpc_s_ok 2495** rpc_s_context_id_not_found 2496** 2497** IMPLICIT INPUTS: none 2498** 2499** IMPLICIT OUTPUTS: none 2500** 2501** FUNCTION VALUE: none 2502** 2503** SIDE EFFECTS: none 2504** 2505**-- 2506**/ 2507 2508PRIVATE void rpc__cn_assoc_syntax_lkup_by_id 2509( 2510 rpc_cn_assoc_p_t assoc, 2511 unsigned32 context_id, 2512 rpc_cn_syntax_p_t *pres_context, 2513 unsigned32 *st 2514) 2515{ 2516 RPC_LOG_CN_ASSOC_SYN_LKUP_NTR; 2517 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_syntax_lkup_by_id); 2518 CODING_ERROR(st); 2519 2520 /* 2521 * Scan the syntax list on the association for a match on the 2522 * context id. 2523 */ 2524 RPC_LIST_FIRST (assoc->syntax_list, 2525 *pres_context, 2526 rpc_cn_syntax_p_t); 2527 while (*pres_context != NULL) 2528 { 2529 /* 2530 * Compare the presentation context id in the syntax element 2531 * with the one passed in. 2532 */ 2533 if ((*pres_context)->syntax_pres_id == context_id) 2534 { 2535 /* 2536 * We have a match. Return it. 2537 */ 2538 *st = rpc_s_ok; 2539 return; 2540 } 2541 RPC_LIST_NEXT (*pres_context, *pres_context, rpc_cn_syntax_p_t); 2542 } 2543 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS, 2544 ("CN: call_rep->%p assoc->%p desc->%p presentation context for context id given not found context_id->%x\n", 2545 assoc->call_rep, 2546 assoc, 2547 assoc->cn_ctlblk.cn_sock, 2548 context_id)); 2549 *st = rpc_s_context_id_not_found; 2550 RPC_LOG_CN_ASSOC_SYN_LKUP_XIT; 2551} 2552 2553 2554/******************************************************************************/ 2555/* 2556**++ 2557** 2558** ROUTINE NAME: rpc__cn_assoc_syntax_lkup_by_cl 2559** 2560** SCOPE: PRIVATE - declared in cnassoc.h 2561** 2562** DESCRIPTION: 2563** 2564** This routine will lookup the presentation context element by 2565** matching the call id. 2566** 2567** INPUTS: 2568** 2569** assoc The association being looked up. 2570** call_id The call id of the presentation context being looked up. 2571** 2572** INPUTS/OUTPUTS: none 2573** 2574** OUTPUTS: 2575** 2576** pres_context The pointer to the matching presentation 2577** context element. 2578** st The return status of this routine. 2579** rpc_s_ok 2580** rpc_s_call_id_not_found 2581** 2582** IMPLICIT INPUTS: none 2583** 2584** IMPLICIT OUTPUTS: none 2585** 2586** FUNCTION VALUE: none 2587** 2588** SIDE EFFECTS: none 2589** 2590**-- 2591**/ 2592 2593PRIVATE void rpc__cn_assoc_syntax_lkup_by_cl 2594( 2595rpc_cn_assoc_p_t assoc, 2596unsigned32 call_id, 2597rpc_cn_syntax_p_t *pres_context, 2598unsigned32 *st 2599) 2600{ 2601 RPC_LOG_CN_ASSOC_SYN_LKUP_NTR; 2602 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_syntax_lkup_by_cl); 2603 CODING_ERROR(st); 2604 2605 /* 2606 * Scan the syntax list on the association for a match on the 2607 * context id. 2608 */ 2609 RPC_LIST_FIRST (assoc->syntax_list, 2610 *pres_context, 2611 rpc_cn_syntax_p_t); 2612 while (*pres_context != NULL) 2613 { 2614 /* 2615 * Compare the presentation context id in the syntax element 2616 * with the one passed in. 2617 */ 2618 if ((*pres_context)->syntax_call_id == call_id) 2619 { 2620 /* 2621 * We have a match. Return it. 2622 */ 2623 *st = rpc_s_ok; 2624 return; 2625 } 2626 RPC_LIST_NEXT (*pres_context, *pres_context, rpc_cn_syntax_p_t); 2627 } 2628 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS, 2629 ("CN: call_rep->%p assoc->%p desc->%p presentation context for call id given not found call_id->%x\n", 2630 assoc->call_rep, 2631 assoc, 2632 assoc->cn_ctlblk.cn_sock, 2633 call_id)); 2634 *st = rpc_s_call_id_not_found; 2635 RPC_LOG_CN_ASSOC_SYN_LKUP_XIT; 2636} 2637 2638 2639/******************************************************************************/ 2640/* 2641**++ 2642** 2643** ROUTINE NAME: rpc__cn_assoc_sec_lkup_by_id 2644** 2645** SCOPE: PRIVATE - declared in cnassoc.h 2646** 2647** DESCRIPTION: 2648** 2649** This routine will lookup the security context element on an 2650** association corresponding to the key ID given. 2651** 2652** INPUTS: 2653** 2654** assoc The association being looked up. 2655** key_id The key ID of the security context being looked up. 2656** 2657** INPUTS/OUTPUTS: none 2658** 2659** OUTPUTS: 2660** 2661** sec The security context element. 2662** st The return status of this routine. 2663** rpc_s_ok 2664** rpc_s_key_id_not_found 2665** 2666** IMPLICIT INPUTS: none 2667** 2668** IMPLICIT OUTPUTS: none 2669** 2670** FUNCTION VALUE: none 2671** 2672** SIDE EFFECTS: none 2673** 2674**-- 2675**/ 2676 2677PRIVATE void rpc__cn_assoc_sec_lkup_by_id 2678( 2679 rpc_cn_assoc_p_t assoc, 2680 unsigned32 key_id, 2681 rpc_cn_sec_context_p_t *sec, 2682 unsigned32 *st 2683) 2684{ 2685 rpc_cn_sec_context_t *sec_context; 2686 2687 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_sec_lkup_by_id); 2688 CODING_ERROR(st); 2689 2690 /* 2691 * Scan the security context list on the association for a match on the 2692 * context id. 2693 */ 2694 RPC_LIST_FIRST (assoc->security.context_list, 2695 sec_context, 2696 rpc_cn_sec_context_p_t); 2697 while (sec_context != NULL) 2698 { 2699 /* 2700 * Compare the key ID in the security context element 2701 * with the one passed in. 2702 */ 2703 if (sec_context->sec_key_id == key_id) 2704 { 2705 /* 2706 * We have a match. Return the pointer to the security 2707 * context element. 2708 */ 2709 *sec = sec_context; 2710 *st = rpc_s_ok; 2711 return; 2712 } 2713 RPC_LIST_NEXT (sec_context, sec_context, rpc_cn_sec_context_p_t); 2714 } 2715 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_SECURITY_ERRORS, 2716 ("CN: call_rep->%p assoc->%p desc->%p no matching security context element for key id key_id->%x\n", 2717 assoc->call_rep, 2718 assoc, 2719 assoc->cn_ctlblk.cn_sock, 2720 key_id)); 2721 *sec = NULL; 2722 *st = rpc_s_key_id_not_found; 2723} 2724 2725 2726/******************************************************************************/ 2727/* 2728**++ 2729** 2730** ROUTINE NAME: rpc__cn_assoc_sec_lkup_by_cl 2731** 2732** SCOPE: PRIVATE - declared in cnassoc.h 2733** 2734** DESCRIPTION: 2735** 2736** This routine will lookup the security context element on an 2737** association corresponding to the call id given. 2738** 2739** INPUTS: 2740** 2741** assoc The association being looked up. 2742** call_id The call ID of the security context being looked up. 2743** 2744** INPUTS/OUTPUTS: none 2745** 2746** OUTPUTS: 2747** 2748** sec The security context element. 2749** st The return status of this routine. 2750** rpc_s_ok 2751** rpc_s_call_id_not_found 2752** 2753** IMPLICIT INPUTS: none 2754** 2755** IMPLICIT OUTPUTS: none 2756** 2757** FUNCTION VALUE: none 2758** 2759** SIDE EFFECTS: none 2760** 2761**-- 2762**/ 2763 2764PRIVATE void rpc__cn_assoc_sec_lkup_by_cl 2765( 2766 rpc_cn_assoc_p_t assoc, 2767 unsigned32 call_id, 2768 rpc_cn_sec_context_p_t *sec, 2769 unsigned32 *st 2770) 2771{ 2772 rpc_cn_sec_context_t *sec_context; 2773 2774 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_sec_lkup_by_cl); 2775 CODING_ERROR(st); 2776 2777 /* 2778 * Scan the security context list on the association for a match on the 2779 * context id. 2780 */ 2781 RPC_LIST_FIRST (assoc->security.context_list, 2782 sec_context, 2783 rpc_cn_sec_context_p_t); 2784 while (sec_context != NULL) 2785 { 2786 /* 2787 * Compare the key ID in the security context element 2788 * with the one passed in. 2789 */ 2790 if (sec_context->sec_last_call_id == call_id) 2791 { 2792 /* 2793 * We have a match. Return the pointer to the security 2794 * context element. 2795 */ 2796 *sec = sec_context; 2797 *st = rpc_s_ok; 2798 return; 2799 } 2800 RPC_LIST_NEXT (sec_context, sec_context, rpc_cn_sec_context_p_t); 2801 } 2802 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_SECURITY_ERRORS, 2803 ("CN: call_rep->%p assoc->%p desc->%p no matching security context element for call id call_id->%x\n", 2804 assoc->call_rep, 2805 assoc, 2806 assoc->cn_ctlblk.cn_sock, 2807 call_id)); 2808 *sec = NULL; 2809 *st = rpc_s_call_id_not_found; 2810} 2811 2812 2813/******************************************************************************/ 2814/* 2815**++ 2816** 2817** ROUTINE NAME: rpc__cn_assoc_post_error 2818** 2819** SCOPE: PRIVATE - declared in cnassoc.h 2820** 2821** DESCRIPTION: 2822** 2823** This routine is called when the network receiver thread 2824** encounters a fatal local error. Errors with the connection 2825** are sent through the association state machine. This 2826** routine will close the connection, post a no connection indication 2827** event to the association state machine and mark the association with 2828** the appropriate status code 2829** 2830** INPUTS: 2831** 2832** assoc The association. 2833** st The error encountered. 2834** 2835** INPUTS/OUTPUTS: none 2836** 2837** OUTPUTS: none 2838** 2839** IMPLICIT INPUTS: none 2840** 2841** IMPLICIT OUTPUTS: none 2842** 2843** FUNCTION VALUE: none 2844** 2845** SIDE EFFECTS: none 2846** 2847**-- 2848**/ 2849 2850PRIVATE void rpc__cn_assoc_post_error 2851( 2852 rpc_cn_assoc_p_t assoc, 2853 unsigned32 st 2854) 2855{ 2856 unsigned32 local_st; 2857 2858 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_post_error); 2859 2860 RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL, 2861 ("(rpc__cn_assoc_post_error) st->%08x cn_state->%d cur_state->%d\n", 2862 st, assoc->cn_ctlblk.cn_state, assoc->assoc_state.cur_state)); 2863 2864 if ((assoc->cn_ctlblk.cn_state != RPC_C_CN_CLOSED) 2865 && 2866 (assoc->assoc_state.cur_state != RPC_C_SM_CLOSED_STATE)) 2867 { 2868 /* 2869 * First close the connection on the association. We will ignore 2870 * any error status from this routine. 2871 */ 2872 if (st != rpc_s_connection_closed) { 2873 rpc__cn_network_close_connect (assoc, &local_st); 2874 } 2875 2876 /* 2877 * Post a no connection indication event to the association 2878 * state machine. This will transition the association into the 2879 * correct state and set the association message list condition 2880 * variable. Setting this will wake up any threads blocked 2881 * waiting for receive data. 2882 * 2883 * Make sure to clear the association status code first 2884 * so this event will be processed. 2885 */ 2886 assoc->assoc_status = rpc_s_ok; 2887 RPC_CN_ASSOC_EVAL_USER_EVENT (assoc, 2888 RPC_C_ASSOC_NO_CONN_IND, 2889 NULL, 2890 st); 2891 } 2892 else 2893 { 2894 return; 2895 } 2896 2897 /* 2898 * Mark the association with the status code passed in as an 2899 * argument. 2900 */ 2901 assoc->assoc_status = st; 2902} 2903 2904 2905/***********************************************************************/ 2906/* 2907**++ 2908** 2909** ROUTINE NAME: rpc__cn_assoc_sm_protocol_error 2910** 2911** SCOPE: PRIVATE 2912** 2913** DESCRIPTION: 2914** 2915** Action routine invoked when an illegal transition is detected. 2916** This routine writes an error message to stdout and DIEs. 2917** 2918** INPUTS: 2919** 2920** spc_struct The special structure which is passed to the 2921** state machine event evaluation routine. 2922** This is assumed to be the assoc. 2923** 2924** event_param The event specific argument. 2925** 2926** INPUTS/OUTPUTS: 2927** sm The control block from the event 2928** evaluation routine. Input is the current 2929** status and event for the control block. 2930** Output is the next state or updated 2931** current state, for the control block. 2932** 2933** OUTPUTS: none 2934** 2935** IMPLICIT INPUTS: none 2936** 2937** IMPLICIT OUTPUTS: none 2938** 2939** FUNCTION VALUE: unsigned32 2940** 2941** SIDE EFFECTS: output is printed on stdout. 2942** 2943**-- 2944**/ 2945PRIVATE unsigned32 rpc__cn_assoc_sm_protocol_error 2946( 2947 dce_pointer_t spc_struct, 2948 dce_pointer_t event_param ATTRIBUTE_UNUSED, 2949 dce_pointer_t sm ATTRIBUTE_UNUSED 2950) 2951{ 2952 rpc_cn_assoc_t *assoc; 2953 2954 assoc = (rpc_cn_assoc_t *) spc_struct; 2955 2956 /* 2957 * "Illegal state transition detected in CN {server|client} association 2958 * state machine [cur_state: %s, cur_event: %s, assoc: %x]" 2959 */ 2960 if (assoc->assoc_flags & RPC_C_CN_ASSOC_SERVER) 2961 { 2962 rpc_dce_svc_printf ( 2963 __FILE__, __LINE__, 2964 "%s %s %x", 2965 rpc_svc_cn_state, 2966 svc_c_sev_fatal | svc_c_action_abort, 2967 rpc_m_cn_ill_state_trans_sa, 2968 rpc_g_cn_assoc_server_states[assoc->assoc_state.cur_state-RPC_C_CN_STATEBASE], 2969 rpc_g_cn_assoc_server_events[assoc->assoc_state.cur_event-RPC_C_CN_STATEBASE], 2970 assoc ); 2971 } 2972 else 2973 { 2974 rpc_dce_svc_printf ( 2975 __FILE__, __LINE__, 2976 "%s %s %x", 2977 rpc_svc_cn_state, 2978 svc_c_sev_fatal | svc_c_action_abort, 2979 rpc_m_cn_ill_state_trans_ca, 2980 rpc_g_cn_assoc_client_states[assoc->assoc_state.cur_state-RPC_C_CN_STATEBASE], 2981 rpc_g_cn_assoc_client_events[assoc->assoc_state.cur_event-RPC_C_CN_STATEBASE], 2982 assoc ); 2983 } 2984 /* FIXME: what should be returned ? */ 2985 return 0; 2986} 2987 2988 2989/* 2990**++ 2991** 2992** ROUTINE NAME: rpc__cn_call_status_to_prej 2993** 2994** SCOPE: INTERNAL 2995** 2996** DESCRIPTION: 2997** 2998** This routine will translate a local status code into a 2999** presentation provider bind NACK reason code. 3000** 3001** INPUTS: 3002** 3003** st The local status code. 3004** 3005** INPUTS/OUTPUTS: none 3006** 3007** OUTPUTS: none 3008** 3009** IMPLICIT INPUTS: none 3010** 3011** IMPLICIT OUTPUTS: none 3012** 3013** FUNCTION VALUE: 3014** 3015** unsigned32 The presentation provider reason code. 3016** 3017** SIDE EFFECTS: none 3018** 3019**-- 3020**/ 3021 3022PRIVATE unsigned32 rpc__cn_assoc_status_to_prej 3023( 3024unsigned32 st 3025) 3026{ 3027 switch ((int)st) 3028 { 3029 case rpc_s_assoc_grp_max_exceeded: 3030 case RPC_S_HEADER_FULL: 3031 return (RPC_C_CN_PREJ_LOCAL_LIMIT_EXCEEDED); 3032 3033 case rpc_s_rpc_prot_version_mismatch: 3034 return (RPC_C_CN_PREJ_PROTOCOL_VERSION_NOT_SUPPORTED); 3035 3036 default: 3037 return (RPC_C_CN_PREJ_REASON_NOT_SPECIFIED); 3038 } 3039} 3040 3041 3042/* 3043**++ 3044** 3045** ROUTINE NAME: rpc__cn_call_prej_to_status 3046** 3047** SCOPE: INTERNAL 3048** 3049** DESCRIPTION: 3050** 3051** This routine will translate a presentation provider bind NACK 3052** reason code into a local status code. 3053** 3054** 3055** INPUTS: 3056** 3057** prej The presentation provider reason code. 3058** 3059** INPUTS/OUTPUTS: none 3060** 3061** OUTPUTS: none 3062** 3063** IMPLICIT INPUTS: none 3064** 3065** IMPLICIT OUTPUTS: none 3066** 3067** FUNCTION VALUE: 3068** 3069** unsigned32 The local status code. 3070** 3071** SIDE EFFECTS: none 3072** 3073**-- 3074**/ 3075 3076PRIVATE unsigned32 rpc__cn_assoc_prej_to_status 3077( 3078unsigned32 prej 3079) 3080{ 3081 switch ((int)prej) 3082 { 3083 case RPC_C_CN_PREJ_LOCAL_LIMIT_EXCEEDED: 3084 case RPC_C_CN_PREJ_TEMPORARY_CONGESTION: 3085 return (rpc_s_server_too_busy); 3086 3087 case RPC_C_CN_PREJ_PROTOCOL_VERSION_NOT_SUPPORTED: 3088 return (rpc_s_rpc_prot_version_mismatch); 3089 3090 /* Win 2003 server (and possibly other Microsoft products) return 3091 * a bind_nak with reject reason 0 (reason not specified) if a second 3092 * bind session is created to the same named pipe from a different 3093 * tcp connection. 3094 * 3095 * To work around this issue, we treat it like the server rejected the 3096 * bind because there are too many remote connections. This causes 3097 * the bind to be retried, or an existing binding is reused when it 3098 * becomes free (which works for win 2003 server). 3099 */ 3100 case RPC_C_CN_PREJ_REASON_NOT_SPECIFIED: 3101 return (rpc_s_too_many_rem_connects); 3102 3103 case RPC_C_CN_PREJ_AUTH_TYPE_NOT_RECOGNIZED: 3104 return (rpc_s_unknown_authn_service); 3105 3106 case RPC_C_CN_PREJ_INVALID_CHECKSUM: 3107 return (rpc_s_invalid_checksum); 3108 3109 default: 3110 return (rpc_s_unknown_reject); 3111 } 3112} 3113 3114 3115/* 3116**++ 3117** 3118** ROUTINE NAME: rpc__cn_call_pprov_to_status 3119** 3120** SCOPE: INTERNAL 3121** 3122** DESCRIPTION: 3123** 3124** This routine will translate a presentation provider bind NACK 3125** reason code into a local status code. 3126** 3127** 3128** INPUTS: 3129** 3130** pprov The presentation provider reason code. 3131** 3132** INPUTS/OUTPUTS: none 3133** 3134** OUTPUTS: none 3135** 3136** IMPLICIT INPUTS: none 3137** 3138** IMPLICIT OUTPUTS: none 3139** 3140** FUNCTION VALUE: 3141** 3142** unsigned32 The local status code. 3143** 3144** SIDE EFFECTS: none 3145** 3146**-- 3147**/ 3148 3149PRIVATE unsigned32 rpc__cn_assoc_pprov_to_status 3150( 3151unsigned32 pprov 3152) 3153{ 3154 switch ((int)pprov) 3155 { 3156 case RPC_C_CN_PPROV_LOCAL_LIMIT_EXCEEDED: 3157 return (rpc_s_server_too_busy); 3158 3159 case RPC_C_CN_PPROV_PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED: 3160 return (rpc_s_tsyntaxes_unsupported); 3161 3162 case RPC_C_CN_PPROV_ABSTRACT_SYNTAX_NOT_SUPPORTED: 3163 return (rpc_s_unknown_if); 3164 3165 case RPC_C_CN_PPROV_REASON_NOT_SPECIFIED: 3166 default: 3167 return (rpc_s_unknown_reject); 3168 } 3169} 3170 3171 3172/***********************************************************************/ 3173/* 3174**++ 3175** 3176** ROUTINE NAME: rpc__cn_assoc_open 3177** 3178** SCOPE: INTERNAL - declared locally 3179** 3180** DESCRIPTION: 3181** 3182** This routine will send an association request event through 3183** the association state machine. This routine will then wait 3184** until the association request has been accepted. It will 3185** then allocate the association and record the negotiated 3186** transfer syntax. 3187** 3188** INPUTS: 3189** 3190** assoc The association. 3191** call_r The call rep which will hold the binding and 3192** interface reps for the state machine action routines. 3193** binding_r The binding rep containing the server address. 3194** if_r The interface specification rep containing 3195** the abstract syntax and supported 3196** transfer syntaxes. 3197** info The authentication information structure 3198** containing the per-principal-pair security 3199** information, NULL if none. 3200** 3201** INPUTS/OUTPUTS: none 3202** 3203** OUTPUTS: 3204** 3205** syntax The negotiated transfer syntax. 3206** context_id The transfer syntax's context id. 3207** sec The negotiated security context element, 3208** NULL if none. 3209** st The return status of this routine. 3210** rpc_s_ok 3211** rpc_s_tsyntaxes_unsupported 3212** rpc_s_unknown_if 3213** 3214** IMPLICIT INPUTS: none 3215** 3216** IMPLICIT OUTPUTS: none 3217** 3218** FUNCTION VALUE: none 3219** 3220** SIDE EFFECTS: none 3221** 3222**-- 3223**/ 3224 3225INTERNAL void rpc__cn_assoc_open 3226( 3227 rpc_cn_assoc_p_t assoc, 3228 rpc_addr_p_t rpc_addr, 3229 rpc_if_rep_p_t if_r, 3230 rpc_cn_local_id_t grp_id, 3231 rpc_auth_info_p_t auth_info, 3232 rpc_transport_info_p_t transport_info, 3233 rpc_transfer_syntax_t *syntax, 3234 unsigned16 *context_id, 3235 rpc_cn_sec_context_p_t *sec, 3236 unsigned32 *st 3237) 3238{ 3239 rpc_cn_syntax_t *pres_context; 3240 rpc_cn_sec_context_t *sec_context; 3241 rpc_cn_fragbuf_t *fragbuf; 3242 rpc_cn_assoc_sm_work_t assoc_sm_work; 3243 3244 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_open); 3245 CODING_ERROR (st); 3246 3247 /* 3248 * Init the work structure needed by the action routine. 3249 */ 3250 memset (&assoc_sm_work, 0, sizeof (rpc_cn_assoc_sm_work_t)); 3251 3252 /* 3253 * Allocate and init a presentation context element and add it 3254 * to the tail of the association presentation context element 3255 * list. Also, put a pointer to it in the state machine work structure. 3256 */ 3257 pres_context = rpc__cn_assoc_syntax_alloc (if_r, st); 3258 if (*st != rpc_s_ok) 3259 { 3260 return; 3261 } 3262 RPC_LIST_ADD_TAIL (assoc->syntax_list, pres_context, rpc_cn_syntax_p_t); 3263 assoc_sm_work.pres_context = pres_context; 3264 3265 /* 3266 * Determine whether security is required for the RPC being 3267 * executed. 3268 */ 3269 if (RPC_CN_AUTH_REQUIRED (auth_info)) 3270 { 3271 /* 3272 * Allocate and init a security context element and add it 3273 * to the tail of the association security context element 3274 * list. Also, put a pointer to it in the state machine work structure. 3275 */ 3276 sec_context = rpc__cn_assoc_sec_alloc (auth_info, st); 3277 assert(sec_context != NULL); 3278 if (*st != rpc_s_ok) 3279 { 3280 RPC_LIST_REMOVE (assoc->syntax_list, pres_context); 3281 rpc__cn_assoc_syntax_free (&pres_context); 3282 return; 3283 } 3284 RPC_LIST_ADD_TAIL (assoc->security.context_list, sec_context, rpc_cn_sec_context_p_t); 3285 assoc_sm_work.sec_context = sec_context; 3286 } 3287 else 3288 { 3289 sec_context = NULL; 3290 } 3291 3292 /* 3293 * Set the association group ID in the state machine work 3294 * structure. 3295 */ 3296 assoc_sm_work.grp_id = grp_id.all; 3297 3298 /* 3299 * Record the address to which the connection is being made in 3300 * the association. 3301 */ 3302 3303 /* 3304 * Here is another one of those marvelous chances for the rpc_addr to 3305 * become a dangling reference. We make sure that this association 3306 * has it's own rpc_addr memory. 3307 */ 3308 { 3309 rpc_addr_p_t rpc_addr1; 3310 3311 rpc__naf_addr_copy(rpc_addr, &rpc_addr1, st); 3312 3313 if ( *st != rpc_s_ok ) 3314 return; 3315 3316 assoc->cn_ctlblk.rpc_addr = rpc_addr1; 3317 } 3318 3319 assoc->transport_info = transport_info; 3320 3321 if (transport_info) 3322 { 3323 rpc__transport_info_retain(transport_info); 3324 } 3325 3326 /* 3327 * This seems redundant, but we need this structure in the association 3328 * in case we have to retry the bind due to protocol version mismatch. 3329 */ 3330 assoc->assoc_sm_work = &assoc_sm_work; 3331 3332 /* 3333 * Send an association request through the association state 3334 * machine. This will create a transport connection and return 3335 * an association in the open state with the transport syntax 3336 * and optional security context negotiated. 3337 */ 3338 RPC_CN_ASSOC_EVAL_USER_EVENT (assoc, 3339 RPC_C_ASSOC_REQ, 3340 &assoc_sm_work, 3341 *st); 3342 3343#ifdef DEBUG 3344 if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_ASSOC_REQ_FAIL)) 3345 { 3346 assoc->assoc_status = RPC_S_CN_DBG_FAILURE; 3347 } 3348#endif 3349 3350 RPC_DBG_PRINTF (rpc_es_dbg_general, RPC_C_CN_DBG_GENERAL, 3351 ("(%s) RPC_CN_ASSOC_EVAL_USER_EVENT(.., RPC_C_ASSOC_REQ,...) returned %#08x, %#08x\n", 3352 __func__, assoc->assoc_status, *st)); 3353 3354 *st = assoc->assoc_status; 3355 if (*st != rpc_s_ok) 3356 { 3357 RPC_LIST_REMOVE (assoc->syntax_list, pres_context); 3358 rpc__cn_assoc_syntax_free (&pres_context); 3359 if (RPC_CN_AUTH_REQUIRED (auth_info)) 3360 { 3361 RPC_LIST_REMOVE (assoc->security.context_list, sec_context); 3362 rpc__cn_assoc_sec_free (&sec_context); 3363 } 3364 return; 3365 } 3366 3367 /* 3368 * Wait for both presentation and optional security context 3369 * negotiations to complete either successfully or with an error. 3370 */ 3371 while (!(pres_context->syntax_valid) 3372 || 3373 (RPC_CN_AUTH_REQUIRED (auth_info) && (sec_context->sec_state != RPC_C_SEC_STATE_COMPLETE))) 3374 { 3375 rpc__cn_assoc_receive_frag (assoc, &fragbuf, st); 3376 if (*st != rpc_s_ok) 3377 { 3378 return; 3379 } 3380 3381 /* 3382 * If either the presentation or security negotiations 3383 * complete with an error return. 3384 */ 3385 if (pres_context->syntax_status != rpc_s_ok) 3386 { 3387 *st = pres_context->syntax_status; 3388 return; 3389 } 3390 if (RPC_CN_AUTH_REQUIRED (auth_info) && (sec_context->sec_status != rpc_s_ok)) 3391 { 3392 *st = sec_context->sec_status; 3393 return; 3394 } 3395 if (RPC_CN_AUTH_REQUIRED (auth_info) && (sec_context->sec_state == RPC_C_SEC_STATE_INCOMPLETE)) 3396 { 3397 RPC_CN_ASSOC_EVAL_USER_EVENT (assoc, 3398 RPC_C_ASSOC_ALTER_CONTEXT_REQ, 3399 &assoc_sm_work, 3400 *st); 3401 } 3402 } 3403 3404 /* 3405 * The negotiations have completed. Copy out the results. Note 3406 * that the presentation syntax UUID is not copied. The client 3407 * stub does not require it. 3408 */ 3409 *sec = sec_context; 3410 syntax->index = pres_context->syntax_vector_index; 3411 syntax->convert_epv = pres_context->syntax_epv; 3412 *context_id = pres_context->syntax_pres_id; 3413 3414 /* 3415 * Mark the call_rep PDU header with the negotiated minor 3416 * version number. 3417 */ 3418 RPC_CN_PKT_VERS_MINOR ((rpc_cn_packet_p_t) 3419 RPC_CN_CREP_SEND_HDR (assoc->call_rep)) = assoc->assoc_vers_minor; 3420 3421 *st = rpc_s_ok; 3422} 3423 3424 3425/***********************************************************************/ 3426/* 3427**++ 3428** 3429** ROUTINE NAME: rpc__cn_assoc_alter_context 3430** 3431** SCOPE: INTERNAL - declared locally 3432** 3433** DESCRIPTION: 3434** 3435** This routine will either locate a previously established or 3436** estblish a new presentation and optional security context for the 3437** current RPC. 3438** 3439** INPUTS: 3440** 3441** assoc The association. 3442** if_r The interface specification rep containing 3443** the abstract syntax and supported 3444** transfer syntaxes. 3445** info The authentication information structure 3446** containing the per-principal-pair security 3447** information, NULL if none. 3448** 3449** INPUTS/OUTPUTS: none 3450** 3451** OUTPUTS: 3452** 3453** syntax The negotiated transfer syntax. 3454** context_id The transfer syntax's context id. 3455** sec The negotiated security context element, 3456** NULL if none. 3457** st The return status of this routine. 3458** rpc_s_ok 3459** 3460** IMPLICIT INPUTS: none 3461** 3462** IMPLICIT OUTPUTS: none 3463** 3464** FUNCTION VALUE: none 3465** 3466** SIDE EFFECTS: none 3467** 3468**-- 3469**/ 3470 3471INTERNAL void rpc__cn_assoc_alter_context 3472( 3473rpc_cn_assoc_p_t assoc, 3474rpc_if_rep_p_t if_r, 3475rpc_auth_info_p_t info, 3476rpc_transfer_syntax_t *syntax, 3477unsigned16 *context_id, 3478rpc_cn_sec_context_p_t *sec, 3479unsigned32 *st 3480) 3481{ 3482 rpc_cn_syntax_t *pres_context; 3483 rpc_cn_sec_context_t *sec_context; 3484 rpc_cn_fragbuf_t *fragbuf; 3485 rpc_cn_assoc_sm_work_t assoc_sm_work; 3486 boolean pres_context_setup; 3487 boolean sec_context_setup = false; 3488 boolean32 sec_cred_changed = false; 3489 rpc_cn_assoc_grp_t * volatile assoc_grp = NULL; 3490 3491 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_alter_context); 3492 CODING_ERROR (st); 3493 3494 /* 3495 * Clear local booleans to indicate whether a presentation context and 3496 * optional security context are set up. 3497 */ 3498 pres_context_setup = false; 3499 3500 /* 3501 * Scan all previously negotiated presentation contexts. 3502 */ 3503 RPC_LIST_FIRST (assoc->syntax_list, pres_context, rpc_cn_syntax_p_t); 3504 while (pres_context != NULL) 3505 { 3506 /* 3507 * If the interface UUID and version in the input argument 3508 * ifspec match the presentation context abstract UUID and 3509 * version this presentation context can be use for the 3510 * current RPC. 3511 */ 3512#if (uuid_c_version == 1) 3513 if ((memcmp (&pres_context->syntax_abstract_id.id, 3514 &if_r->id, 3515 sizeof (idl_uuid_t)) == 0) 3516#else 3517***Make sure memcmp works on this version of UUIDs*** 3518#endif 3519 && 3520 (pres_context->syntax_abstract_id.version == if_r->vers)) 3521 { 3522 /* 3523 * Handle the case where a previous negotiation was 3524 * orphaned and failed with a presentation provider reject 3525 * (an rpc_bind_ack or rpc_alter_context_response was returned). 3526 */ 3527 if (pres_context->syntax_status != rpc_s_ok) 3528 { 3529 *st = pres_context->syntax_status; 3530 return; 3531 } 3532 pres_context_setup = true; 3533 break; 3534 } 3535 RPC_LIST_NEXT (pres_context, pres_context, rpc_cn_syntax_p_t); 3536 } 3537 3538 /* 3539 * Determine whether the current RPC requires security. 3540 */ 3541 if (RPC_CN_AUTH_REQUIRED (info)) 3542 { 3543 RPC_DBG_PRINTF (rpc_e_dbg_auth, RPC_C_CN_DBG_GENERAL, 3544 ("(%s) auth required principal=%s level=%u protocol=%u\n", 3545 __func__, info->server_princ_name, 3546 info->authn_level, info->authn_protocol)); 3547 /* 3548 * Scan all previously negotiated security contexts. 3549 */ 3550 RPC_LIST_FIRST (assoc->security.context_list, sec_context, rpc_cn_sec_context_p_t); 3551 while (sec_context != NULL) 3552 { 3553 /* 3554 * If the auth info passed in equals the auth info in 3555 * the security context element this security context can 3556 * be use for the current RPC. 3557 */ 3558 if (info == sec_context->sec_info) 3559 { 3560 /* 3561 * This security context element matches the auth 3562 * info we're looking for, which means the client and 3563 * server principal IDs as well as the authn protocol 3564 * match. We'll at least reuse the memory for this 3565 * structure even if we have to send an 3566 * rpc_alter_context PDU to update it. 3567 */ 3568 3569 /* 3570 * Determine whether the credentials have been 3571 * refreshed since this security context was set up. 3572 * If so, we'll have to send an rpc_alter_context PDU 3573 * to update the security context with the new 3574 * credentials. 3575 */ 3576 sec_cred_changed = RPC_CN_AUTH_CRED_CHANGED (sec_context, st); 3577 break; 3578 } 3579 RPC_LIST_NEXT (sec_context, sec_context, rpc_cn_sec_context_p_t); 3580 } 3581 } 3582 else 3583 { 3584 sec_context = NULL; 3585 } 3586 3587 /* 3588 * Determine whether either a presentation or security 3589 * context negotiation has to occur. 3590 */ 3591 if ((!pres_context_setup) 3592 || 3593 (RPC_CN_AUTH_REQUIRED (info) && (sec_context == NULL)) 3594 || 3595 (RPC_CN_AUTH_REQUIRED (info) && (sec_cred_changed))) 3596 { 3597 /* 3598 * Init the work structure needed by the action routine. 3599 */ 3600 memset (&assoc_sm_work, 0, sizeof (rpc_cn_assoc_sm_work_t)); 3601 3602 if (!pres_context_setup) 3603 { 3604 /* 3605 * We didn't find a presentation context element on 3606 * the association for the current RPC. Allocate and 3607 * init a presentation context element and add it 3608 * to the tail of the association presentation context element 3609 * list. Also, put a pointer to it in the state machine work structure. 3610 */ 3611 pres_context = rpc__cn_assoc_syntax_alloc (if_r, st); 3612 if (*st != rpc_s_ok) 3613 { 3614 return; 3615 } 3616 RPC_LIST_ADD_TAIL (assoc->syntax_list, pres_context, rpc_cn_syntax_p_t); 3617 assoc_sm_work.pres_context = pres_context; 3618 } 3619 else 3620 { 3621 /* MSRPC seems to expect a context negotiation even if we aren't 3622 changing the presentation context, so just send what we already 3623 have */ 3624 assoc_sm_work.pres_context = pres_context; 3625 assoc_sm_work.reuse_context = TRUE; 3626 } 3627 3628 3629 /* 3630 * If authentication is required on this call, we may have 3631 * to send an rpc_alter_context PDU. The only time one doesn't 3632 * have to be sent is when a security context has been 3633 * established which has valid credentials and has been 3634 * successfully established previously. 3635 */ 3636 if (RPC_CN_AUTH_REQUIRED (info)) 3637 { 3638 /* 3639 * If the security context pointer is NULL we didn't 3640 * find a match above. This means we need to allocate 3641 * memory for a new security context element and send an 3642 * rpc_alter_context PDU to set it up. 3643 */ 3644 if (sec_context == NULL) 3645 { 3646 /* 3647 * Allocate and init a security context element and add it 3648 * to the tail of the association security context element 3649 * list. Also, put a pointer to it in the state machine work structure. 3650 */ 3651 sec_context = rpc__cn_assoc_sec_alloc (info, st); 3652 if (*st != rpc_s_ok) 3653 { 3654 if (!pres_context_setup) 3655 { 3656 RPC_LIST_REMOVE (assoc->syntax_list, pres_context); 3657 rpc__cn_assoc_syntax_free (&pres_context); 3658 } 3659 return; 3660 } 3661 sec_context_setup = false; 3662 RPC_LIST_ADD_TAIL (assoc->security.context_list, sec_context, rpc_cn_sec_context_p_t); 3663 assoc_sm_work.sec_context = sec_context; 3664 } 3665 else 3666 { 3667 sec_context_setup = true; 3668 } 3669 3670 /* 3671 * The indication that a previous security context setup 3672 * has failed is when the status code is not rpc_s_ok in 3673 * it. This condition, or a credential change, means that 3674 * an rpc_alter_context PDU should be sent to update the 3675 * existing security context. 3676 */ 3677 if ((sec_context->sec_status != rpc_s_ok) 3678 || 3679 sec_cred_changed) 3680 { 3681 assoc_sm_work.sec_context = sec_context; 3682 } 3683 } 3684 3685 assoc_grp = RPC_CN_ASSOC_GRP(assoc->assoc_grp_id); 3686 assoc_sm_work.grp_id = assoc_grp->grp_remid.all; 3687 3688 /* 3689 * Evaluate an alter_context event through the client 3690 * association state machine. This will result in an 3691 * alter_context PDU being transmitted to the server. 3692 */ 3693 RPC_CN_ASSOC_EVAL_USER_EVENT (assoc, 3694 RPC_C_ASSOC_ALTER_CONTEXT_REQ, 3695 &assoc_sm_work, 3696 *st); 3697 *st = assoc->assoc_status; 3698 if (*st != rpc_s_ok) 3699 { 3700 if (!pres_context_setup) 3701 { 3702 RPC_LIST_REMOVE (assoc->syntax_list, pres_context); 3703 rpc__cn_assoc_syntax_free (&pres_context); 3704 } 3705 3706 if (RPC_CN_AUTH_REQUIRED (info) && (!sec_context_setup)) 3707 { 3708 assert (sec_context != NULL); 3709 RPC_LIST_REMOVE (assoc->security.context_list, sec_context); 3710 rpc__cn_assoc_sec_free (&sec_context); 3711 } 3712 return; 3713 } 3714 3715 } 3716 3717 /* 3718 * If we need authentication, then we must have a security context by now. 3719 */ 3720 if (RPC_CN_AUTH_REQUIRED (info)) { 3721 assert (RPC_CN_AUTH_REQUIRED (info) && sec_context != NULL); 3722 } 3723 3724 /* 3725 * Wait for both presentation and optional security context 3726 * negotiations to complete either successfully or with an error. 3727 */ 3728 while (!(pres_context->syntax_valid) 3729 || 3730 (RPC_CN_AUTH_REQUIRED (info) && (sec_context->sec_state != RPC_C_SEC_STATE_COMPLETE))) 3731 { 3732 rpc__cn_assoc_receive_frag (assoc, &fragbuf, st); 3733 if (*st != rpc_s_ok) 3734 { 3735 return; 3736 } 3737 /* 3738 * If either the presentation or security negotiations 3739 * complete with an error return. 3740 */ 3741 if (pres_context->syntax_status != rpc_s_ok) 3742 { 3743 *st = pres_context->syntax_status; 3744 return; 3745 } 3746 if (RPC_CN_AUTH_REQUIRED (info) && (sec_context->sec_status != rpc_s_ok)) 3747 { 3748 *st = sec_context->sec_status; 3749 return; 3750 } 3751 } 3752 3753 /* 3754 * The negotiations have completed. Copy out the results. Note 3755 * that the presentation syntax UUID is not copied. The client 3756 * stub does not require it. 3757 */ 3758 *sec = sec_context; 3759 syntax->index = pres_context->syntax_vector_index; 3760 syntax->convert_epv = pres_context->syntax_epv; 3761 *context_id = pres_context->syntax_pres_id; 3762 *st = rpc_s_ok; 3763} 3764 3765 3766/***********************************************************************/ 3767/* 3768**++ 3769** 3770** ROUTINE NAME: rpc__cn_assoc_sec_alloc 3771** 3772** SCOPE: PRIVATE - declared in cnassoc.h 3773** 3774** DESCRIPTION: 3775** 3776** This routine will allocate and intialize a security context element. 3777** 3778** INPUTS: 3779** 3780** info The per-principal-pair security information. 3781** 3782** INPUTS/OUTPUTS: none 3783** 3784** OUTPUTS: 3785** 3786** st The return status of this routine. 3787** rpc_s_ok 3788** 3789** IMPLICIT INPUTS: none 3790** 3791** IMPLICIT OUTPUTS: none 3792** 3793** FUNCTION VALUE: none 3794** 3795** SIDE EFFECTS: none 3796** 3797**-- 3798**/ 3799 3800PRIVATE rpc_cn_sec_context_t *rpc__cn_assoc_sec_alloc 3801( 3802 rpc_auth_info_p_t info, 3803 unsigned32 *st 3804) 3805{ 3806 rpc_cn_sec_context_t *sec_context; 3807 rpc_cn_auth_info_t *cn_info; 3808 3809#ifdef DEBUG 3810 if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_SEC_ALLOC_FAIL)) 3811 { 3812 *st = RPC_S_CN_DBG_FAILURE; 3813 return (NULL); 3814 } 3815#endif 3816 3817 /* 3818 * Allocate a CN specific per-principal-pair security 3819 * information structure. 3820 */ 3821 RPC_CN_AUTH_GET_PROT_INFO (info, &cn_info, st); 3822 if (*st != rpc_s_ok) 3823 { 3824 if (info->is_server) 3825 { 3826 dce_error_string_t error_text; 3827 int temp_status; 3828 3829 dce_error_inq_text(*st, error_text, &temp_status); 3830 3831 /* 3832 * rpc_m_call_failed_s 3833 * "%s on server failed: %s" 3834 */ 3835 rpc_dce_svc_printf ( 3836 __FILE__, __LINE__, 3837 "%s %x", 3838 rpc_svc_auth, 3839 svc_c_sev_error, 3840 rpc_m_call_failed_s, 3841 "RPC_CN_AUTH_GET_PROT_INFO", 3842 error_text ); 3843 } 3844 return (NULL); 3845 } 3846 cn_info->cn_epv = RPC_CN_AUTH_PROT_EPV (info->authn_protocol); 3847 3848 /* 3849 * Allocate a security context element and init it. 3850 */ 3851 sec_context = (rpc_cn_sec_context_t *) 3852 rpc__list_element_alloc (&rpc_g_cn_sec_lookaside_list, true); 3853 if (sec_context == NULL) { 3854 *st = rpc_s_no_memory; 3855 return NULL; 3856 } 3857 sec_context->sec_state = RPC_C_SEC_STATE_INVALID; 3858 sec_context->sec_status = rpc_s_ok; 3859 sec_context->sec_info = info; 3860 sec_context->sec_cn_info = cn_info; 3861 3862 /* 3863 * Note that the credentials themselves in the auth_info 3864 * structure were already checked for expiration in 3865 * rpc__cn_call_start() on the client side. It therefore isn't 3866 * necessary to do any more checking here since they were either 3867 * refreshed or an error was returned back in call_start. 3868 * 3869 * On the server, the client has not been authenticated yet. 3870 * This security context may therefore be invalid. 3871 * 3872 * Add a reference to the auth information structure since a 3873 * pointer to it is being kept in the security context element. 3874 */ 3875 RPC_CN_AUTH_ADD_REFERENCE (info); 3876 return (sec_context); 3877} 3878 3879 3880/***********************************************************************/ 3881/* 3882**++ 3883** 3884** ROUTINE NAME: rpc__cn_assoc_sec_free 3885** 3886** SCOPE: PRIVATE - declared in cnassoc.h 3887** 3888** DESCRIPTION: 3889** 3890** This routine will free a security context element, 3891** dereference the per-principal-pair security information, and free 3892** the CN specific per-principal-pair security information. 3893** 3894** INPUTS: none 3895** 3896** INPUTS/OUTPUTS: 3897** 3898** sec The security context element, NULL on output. 3899** 3900** OUTPUTS: none 3901** 3902** IMPLICIT INPUTS: none 3903** 3904** IMPLICIT OUTPUTS: none 3905** 3906** FUNCTION VALUE: none 3907** 3908** SIDE EFFECTS: none 3909** 3910**-- 3911**/ 3912 3913PRIVATE void rpc__cn_assoc_sec_free 3914( 3915 rpc_cn_sec_context_p_t *sec 3916) 3917{ 3918 /* 3919 * Free the CN specific per-principal-pair security 3920 * information structure. 3921 */ 3922 RPC_CN_AUTH_FREE_PROT_INFO ((*sec)->sec_info, &(*sec)->sec_cn_info); 3923 3924 /* 3925 * Remove the reference to the auth information structure. 3926 */ 3927 RPC_CN_AUTH_RELEASE_REFERENCE ((rpc_auth_info_p_t *) &(*sec)->sec_info); 3928 3929 /* 3930 * Free the security context element. 3931 */ 3932 rpc__list_element_free (&rpc_g_cn_sec_lookaside_list, 3933 (dce_pointer_t) (*sec)); 3934 3935 *sec = NULL; 3936} 3937 3938 3939/***********************************************************************/ 3940/* 3941**++ 3942** 3943** ROUTINE NAME: rpc__cn_assoc_syntax_alloc 3944** 3945** SCOPE: INTERNAL - declared locally 3946** 3947** DESCRIPTION: 3948** 3949** This routine will allocate and intialize a presentation context element. 3950** 3951** INPUTS: 3952** 3953** if_r The interface spec. 3954** 3955** INPUTS/OUTPUTS: none 3956** 3957** OUTPUTS: 3958** 3959** st The return status of this routine. 3960** rpc_s_ok 3961** 3962** IMPLICIT INPUTS: none 3963** 3964** IMPLICIT OUTPUTS: none 3965** 3966** FUNCTION VALUE: none 3967** 3968** SIDE EFFECTS: none 3969** 3970**-- 3971**/ 3972 3973INTERNAL rpc_cn_syntax_t *rpc__cn_assoc_syntax_alloc 3974( 3975 rpc_if_rep_p_t if_r, 3976 unsigned32 *st 3977) 3978{ 3979 rpc_cn_syntax_t *pres_context; 3980 3981 pres_context = 3982 (rpc_cn_syntax_t *)rpc__list_element_alloc (&rpc_g_cn_syntax_lookaside_list, 3983 true); 3984 if (pres_context == NULL) { 3985 *st = rpc_s_no_memory; 3986 return NULL; 3987 } 3988 pres_context->syntax_valid = false; 3989 pres_context->syntax_status = rpc_s_ok; 3990 pres_context->syntax_abstract_id.id = if_r->id; 3991 pres_context->syntax_abstract_id.version = if_r->vers; 3992 pres_context->syntax_vector = &if_r->syntax_vector; 3993 pres_context->syntax_epv = NULL; 3994 *st = rpc_s_ok; 3995 return (pres_context); 3996} 3997 3998 3999/***********************************************************************/ 4000/* 4001**++ 4002** 4003** ROUTINE NAME: rpc__cn_assoc_syntax_free 4004** 4005** SCOPE: PRIVATE - declated in cnassoc.h 4006** 4007** DESCRIPTION: 4008** 4009** This routine will free a presentation context element. 4010** 4011** INPUTS: none 4012** 4013** INPUTS/OUTPUTS: 4014** 4015** syntax The presentation context element, NULL on output. 4016** 4017** OUTPUTS: none 4018** 4019** IMPLICIT INPUTS: none 4020** 4021** IMPLICIT OUTPUTS: none 4022** 4023** FUNCTION VALUE: none 4024** 4025** SIDE EFFECTS: none 4026** 4027**-- 4028**/ 4029 4030PRIVATE void rpc__cn_assoc_syntax_free 4031( 4032 rpc_cn_syntax_p_t *syntax 4033) 4034{ 4035 /* 4036 * Free the presentation context element. 4037 */ 4038 rpc__list_element_free (&rpc_g_cn_syntax_lookaside_list, 4039 (dce_pointer_t) *syntax); 4040 *syntax = NULL; 4041} 4042 4043 4044/******************************************************************************/ 4045/* 4046**++ 4047** 4048** ROUTINE NAME: rpc__cn_assoc_timer_reclaim 4049** 4050** SCOPE: INTERNAL - declared locally 4051** 4052** DESCRIPTION: 4053** 4054** This routine is called at timed intervals to close 4055** associations which have been inactive. 4056** 4057** INPUTS: 4058** 4059** type The type of associations to reclaim. 4060** 4061** INPUTS/OUTPUTS: none 4062** 4063** OUTPUTS: none 4064** 4065** IMPLICIT INPUTS: none 4066** 4067** IMPLICIT OUTPUTS: none 4068** 4069** FUNCTION VALUE: none 4070** 4071** SIDE EFFECTS: none 4072** 4073**-- 4074**/ 4075 4076INTERNAL void rpc__cn_assoc_timer_reclaim 4077( 4078 unsigned32 type 4079) 4080{ 4081 rpc_cn_local_id_t grp_id; 4082 4083 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_timer_reclaim); 4084 4085 /* 4086 * Reclaim associations of the given type. Provide an invalid 4087 * group id so that no group is off limits to the policy. 4088 */ 4089 RPC_CN_LOCAL_ID_CLEAR (grp_id); 4090 RPC_CN_LOCK (); 4091 rpc__cn_assoc_reclaim (grp_id, type, false); 4092 RPC_CN_UNLOCK (); 4093} 4094 4095 4096/******************************************************************************/ 4097/* 4098**++ 4099** 4100** ROUTINE NAME: rpc__cn_assoc_reclaim 4101** 4102** SCOPE: INTERNAL - declared locally 4103** 4104** DESCRIPTION: 4105** 4106** This routine is called to invoke the local policy algorithm 4107** to determine which associations/connections should be closed. 4108** 4109** INPUTS: 4110** 4111** grp_id The association group id over which an open 4112** association is needed. 4113** type The type of associations to be reclaimed. 4114** 4115** loop If loop is false, we will stop after finding 4116** the first association to shut down. 4117** 4118** INPUTS/OUTPUTS: none 4119** 4120** OUTPUTS: none 4121** 4122** IMPLICIT INPUTS: none 4123** 4124** IMPLICIT OUTPUTS: none 4125** 4126** FUNCTION VALUE: none 4127** 4128** SIDE EFFECTS: none 4129** 4130**-- 4131**/ 4132 4133INTERNAL void rpc__cn_assoc_reclaim 4134( 4135 rpc_cn_local_id_t grp_id, 4136 unsigned32 type, 4137 boolean32 loop 4138) 4139{ 4140 unsigned32 i; 4141 boolean shutdown_or_abort = false; 4142 rpc_cn_assoc_t *assoc; 4143 unsigned32 st; 4144 4145 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_reclaim); 4146 4147 /* 4148 * Check whether there are any active groups. 4149 */ 4150 if (rpc_g_cn_assoc_grp_tbl.grp_active_count != 0) 4151 { 4152 /* 4153 * Scan all the association groups in the group table. 4154 */ 4155 for (i = 0; 4156 i < rpc_g_cn_assoc_grp_tbl.grp_count; 4157 i++) 4158 { 4159 /* 4160 * Check whether the group id given matches, the group is active 4161 * and of the right type. Also, check if there is any active 4162 * context handle between a client and server (i.e. the association 4163 * will be allowed to shutdown if the group reference count 4164 * is zero or there is more than one association on the group). 4165 * Note that for future enhancement, we should implement the 4166 * checking on the activeness of the context handle as a predicate 4167 * through server association FSM. 4168 */ 4169 if ((!RPC_CN_LOCAL_ID_EQUAL 4170 (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_id, grp_id)) 4171 && 4172 (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_flags & type) 4173 && 4174 (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_state.cur_state 4175 == RPC_C_ASSOC_GRP_ACTIVE) 4176 && 4177 (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_refcnt == 0 4178 || 4179 rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_cur_assoc > 1) 4180 ) 4181 { 4182 /* 4183 * The group id doesn't match and the group is of the 4184 * correct type and is active. Scan the associations on its 4185 * list. 4186 */ 4187 RPC_LIST_FIRST 4188 (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_assoc_list, 4189 assoc, 4190 rpc_cn_assoc_p_t); 4191 while (assoc != NULL) 4192 { 4193 /* 4194 * Check whether the association is free for 4195 * reclaimation. 4196 */ 4197 if (assoc->assoc_ref_count == 0) 4198 { 4199 /* 4200 * Increment the association reference count so 4201 * that this association won't be deallocated by 4202 * the receiver thread when we try to send the 4203 * shutdown request. 4204 */ 4205 RPC_CN_ASSOC_ACB_INC_REF(assoc); 4206 4207 /* 4208 * This association has no active references. 4209 */ 4210 if (assoc->assoc_flags & RPC_C_CN_ASSOC_SCANNED) 4211 { 4212 /* 4213 * The association has been scanned previsouly. 4214 * Check the shutdown request count to see if 4215 * it reached the maximum allowed 4216 */ 4217 if (0 /* Windows RPC runtime never sends shutdowns */ && 4218 assoc->assoc_shutdown_req_count <= 4219 RPC_C_CN_ASSOC_SERVER_MAX_SHUTDOWN_REQ_COUNT) 4220 { 4221 /* 4222 * Haven't reached the maximum shutdown 4223 * request count, send an additional shutdown 4224 * message to the client. We do this by sending 4225 * a shutdown request through its state machine 4226 * and increase the shutdown request count. 4227 */ 4228 RPC_CN_ASSOC_EVAL_USER_EVENT (assoc, 4229 RPC_C_ASSOC_SHUTDOWN_REQ, 4230 NULL, 4231 st); 4232 assoc->assoc_shutdown_req_count++ ; 4233 shutdown_or_abort = true; 4234 } 4235 else 4236 { 4237 /* 4238 * Architecture spec requires that a client 4239 * responds to a shutdown message. If we get 4240 * no response from repeated shutdowns, we 4241 * assume that the client is not working 4242 * properly and abort the association. 4243 * 4244 * We have sent the client the maximum number 4245 * of shutdown requests. The client has not 4246 * initiated an orderly shutdown process. The 4247 * client might be hung. It's time to abort 4248 * the association! 4249 */ 4250 rpc__cn_assoc_abort (assoc, &st); 4251 shutdown_or_abort = true; 4252 } 4253 } 4254 else 4255 { 4256 /* 4257 * The association has no active 4258 * references but also was not previously 4259 * scanned. Mark it as scanned now. 4260 */ 4261 assoc->assoc_flags |= RPC_C_CN_ASSOC_SCANNED; 4262 } 4263 4264 /* 4265 * Done with the shutdown attempt, so decrement the 4266 * reference count. This is done via the acb dealloc 4267 * routine. 4268 */ 4269 rpc__cn_assoc_acb_dealloc (assoc); 4270 } 4271 if (loop == false && shutdown_or_abort == true) 4272 return; 4273 RPC_LIST_NEXT (assoc, assoc, rpc_cn_assoc_p_t); 4274 } /* end while (assoc != NULL) */ 4275 } /* end if ((!RPC_CN_LOCAL_ID (...)) */ 4276 } /* end for (i = 0; ... ) */ 4277 } 4278} 4279 4280 4281/***********************************************************************/ 4282/* 4283**++ 4284** 4285** ROUTINE NAME: rpc__cn_assoc_acb_alloc 4286** 4287** SCOPE: INTERNAL - declared locally 4288** 4289** DESCRIPTION: 4290** 4291** This routine will create and initialize, if needed, an 4292** association control block by allocating one off the 4293** association lookaside list. 4294** 4295** INPUTS: 4296** 4297** wait A boolean indicating whether this routine is 4298** allowed to block waiting for memory if necessary. 4299** type The type of association requested (client or server). 4300** 4301** INPUTS/OUTPUTS: none 4302** 4303** OUTPUTS: 4304** 4305** st The return status of this routine. 4306** rpc_s_ok 4307** 4308** IMPLICIT INPUTS: none 4309** 4310** IMPLICIT OUTPUTS: none 4311** 4312** FUNCTION VALUE: 4313** 4314** assoc The initialized association. 4315** 4316** SIDE EFFECTS: none 4317** 4318**-- 4319**/ 4320 4321INTERNAL rpc_cn_assoc_t *rpc__cn_assoc_acb_alloc 4322( 4323 boolean32 wait, 4324 unsigned32 type, 4325 unsigned32 *st 4326) 4327{ 4328 rpc_cn_assoc_t *assoc; 4329 4330 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_acb_alloc); 4331 CODING_ERROR(st); 4332 4333 /* 4334 * Allocate an association control block. The returned block 4335 * will have a receiver thread assigned to it which will be 4336 * blocked on a the connection condition variable contained in the 4337 * association. Once a connection has been established this 4338 * condition variable will be set and the receiver thread will 4339 * begin waiting for data on the connection. 4340 */ 4341 assoc = (rpc_cn_assoc_t *) 4342 rpc__list_element_alloc (&rpc_g_cn_assoc_lookaside_list, wait); 4343 if (assoc == NULL) { 4344 *st = rpc_s_no_memory; 4345 return (NULL); 4346 } 4347 4348 assoc->cn_ctlblk.rpc_addr = NULL; 4349 4350 /* 4351 * Find out what type of association is being created and 4352 * initialize the state tables in the association accordingly. 4353 */ 4354 if (type == RPC_C_CN_ASSOC_CLIENT) 4355 { 4356 /* 4357 * Initialize the association with the client tables. 4358 */ 4359 rpc__cn_sm_init (rpc_g_cn_client_assoc_sm, 4360 rpc_g_cn_client_assoc_act_tbl, 4361 &(assoc->assoc_state), 4362 rpc_c_cn_cl_assoc ); 4363 } 4364 else 4365 { 4366 /* 4367 * Initialize the association with the server tables. 4368 */ 4369 rpc__cn_sm_init (rpc_g_cn_server_assoc_sm, 4370 rpc_g_cn_server_assoc_act_tbl, 4371 &(assoc->assoc_state), 4372 rpc_c_cn_svr_assoc ); 4373 } 4374 assoc->assoc_flags |= type; 4375 4376 /* 4377 * We use our version number until we negotiate different. 4378 */ 4379 assoc->assoc_vers_minor = RPC_C_CN_PROTO_VERS_MINOR; 4380 4381 *st = rpc_s_ok; 4382 return (assoc); 4383} 4384 4385 4386/***********************************************************************/ 4387/* 4388**++ 4389** 4390** ROUTINE NAME: rpc__cn_assoc_acb_dealloc 4391** 4392** SCOPE: PRIVATE - declared in cnassoc.h 4393** 4394** DESCRIPTION: 4395** 4396** This routine will return an association control block to the 4397** association lookaside list. 4398** 4399** INPUTS: 4400** 4401** assoc The association to be freed. 4402** 4403** INPUTS/OUTPUTS: none 4404** 4405** OUTPUTS: none 4406** 4407** IMPLICIT INPUTS: none 4408** 4409** IMPLICIT OUTPUTS: none 4410** 4411** FUNCTION VALUE: none 4412** 4413** SIDE EFFECTS: none 4414** 4415**-- 4416**/ 4417 4418PRIVATE void rpc__cn_assoc_acb_dealloc 4419( 4420 rpc_cn_assoc_p_t assoc 4421) 4422{ 4423 rpc_cn_fragbuf_t *fragbuf; 4424 rpc_cn_syntax_t *pres_context; 4425 rpc_cn_sec_context_t *sec_context; 4426 4427 RPC_LOG_CN_ASSOC_ACB_DEAL_NTR; 4428 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_acb_dealloc); 4429 4430 RPC_CN_ASSOC_ACB_DEC_REF (assoc); 4431 4432 if (assoc->assoc_acb_ref_count == 0) 4433 { 4434 /* 4435 * Clear the pointer to the endpoint of the socket 4436 * descriptor contained in the connection control block. 4437 * Note that this memory is NOT freed. It is used by all 4438 * connections which come in on the descriptor in the 4439 * select pool and as such cannot be freed until this 4440 * descriptor is removed (there is no way to remove it right 4441 * now.) 4442 */ 4443 assoc->cn_ctlblk.cn_listening_endpoint = NULL; 4444 4445 /* 4446 * Free all fragment buffers on the association message list 4447 * and clear the waiters field. 4448 */ 4449 assoc->assoc_msg_waiters = 0; 4450 RPC_LIST_FIRST (assoc->msg_list, 4451 fragbuf, 4452 rpc_cn_fragbuf_p_t); 4453 while (fragbuf != NULL) 4454 { 4455 rpc_cn_fragbuf_t *next_fragbuf; 4456 4457 RPC_LIST_NEXT (fragbuf, 4458 next_fragbuf, 4459 rpc_cn_fragbuf_p_t); 4460 if (fragbuf->fragbuf_dealloc != NULL) 4461 { 4462 (*fragbuf->fragbuf_dealloc)(fragbuf); 4463 } 4464 fragbuf = next_fragbuf; 4465 } 4466 RPC_LIST_INIT (assoc->msg_list); 4467 4468 /* 4469 * Free all the syntax elements on the association syntax 4470 * list. 4471 */ 4472 RPC_LIST_FIRST (assoc->syntax_list, 4473 pres_context, 4474 rpc_cn_syntax_p_t); 4475 while (pres_context != NULL) 4476 { 4477 rpc_cn_syntax_t *next_pres_context; 4478 4479 RPC_LIST_NEXT (pres_context, next_pres_context, rpc_cn_syntax_p_t); 4480 rpc__cn_assoc_syntax_free (&pres_context); 4481 pres_context = next_pres_context; 4482 } 4483 RPC_LIST_INIT (assoc->syntax_list); 4484 4485 /* 4486 * Free all the security context elements. 4487 */ 4488 RPC_LIST_FIRST (assoc->security.context_list, 4489 sec_context, 4490 rpc_cn_sec_context_p_t); 4491 while (sec_context != NULL) 4492 { 4493 rpc_cn_sec_context_t *next_sec_context; 4494 4495 RPC_LIST_NEXT (sec_context, next_sec_context, rpc_cn_sec_context_p_t); 4496 rpc__cn_assoc_sec_free (&sec_context); 4497 sec_context = next_sec_context; 4498 } 4499 RPC_LIST_INIT (assoc->security.context_list); 4500 4501 memset (&assoc->security, 0, sizeof (rpc_cn_assoc_sec_context_t)); 4502 4503 /* 4504 * Free the call rep on the assoc. 4505 */ 4506 if (assoc->call_rep != NULL) 4507 { 4508 /* 4509 * If this assoc is pointing to a call_rep that doesn't point 4510 * back to it then this assoc is probably a client assoc that 4511 * failed the presentation negotiation sequence and the call 4512 * rep already went back to the heap. Hence this call_rep is 4513 * probably paired with another association at this time and 4514 * so it would be wrong to release the assoc from it. 4515 */ 4516 if ( assoc->call_rep->assoc == assoc ) 4517 assoc->call_rep->assoc = NULL; 4518 assoc->call_rep = NULL; 4519 } 4520 4521 rpc__transport_info_release(assoc->transport_info); 4522 assoc->transport_info = NULL; 4523 assoc->cn_ctlblk.cn_state = RPC_C_SM_CLOSED_STATE; 4524 assoc->assoc_status = rpc_s_ok; 4525 assoc->assoc_local_status = rpc_s_ok; 4526 RPC_CN_LOCAL_ID_CLEAR (assoc->assoc_grp_id); 4527 assoc->assoc_flags = 0; 4528 RPC_CN_ASSOC_CONTEXT_ID (assoc) = 0; 4529 assoc->assoc_max_xmit_frag = 0; 4530 assoc->assoc_max_recv_frag = 0; 4531 assoc->assoc_vers_minor = RPC_C_CN_PROTO_VERS_MINOR; 4532 assoc->assoc_ref_count = 0; 4533 assoc->assoc_shutdown_req_count = 0; 4534 assoc->cn_ctlblk.exit_rcvr = false; 4535 assoc->cn_ctlblk.in_sendmsg = false; 4536 assoc->cn_ctlblk.waiting_for_sendmsg_complete = false; 4537 assoc->assoc_sm_work = NULL; 4538 4539 /* 4540 * Free the rpc addr memory of the assoc. 4541 */ 4542 { 4543 error_status_t st; 4544 4545 if (assoc->cn_ctlblk.rpc_addr) 4546 rpc__naf_addr_free (&assoc->cn_ctlblk.rpc_addr, &st); 4547 4548 assoc->cn_ctlblk.rpc_addr = NULL; 4549 } 4550 4551 /* 4552 * Finally free the association to the association lookaside 4553 * list. 4554 */ 4555 rpc__list_element_free (&rpc_g_cn_assoc_lookaside_list, 4556 (dce_pointer_t) assoc); 4557 } 4558 RPC_LOG_CN_ASSOC_ACB_DEAL_XIT; 4559} 4560 4561/******************************************************************************/ 4562 4563 4564/* 4565**++ 4566** 4567** ROUTINE NAME: rpc__cn_assoc_acb_create 4568** 4569** SCOPE: PRIVATE - declared in cnassoc.h 4570** 4571** DESCRIPTION: 4572** 4573** This routine will initialize an association control block 4574** which is allocated from heap by rpc__list_element_alloc. It 4575** will create the mutexes and condition variables as well as 4576** create the receiver thread. 4577** 4578** INPUTS: 4579** 4580** assoc The association control block to be initialized. 4581** 4582** INPUTS/OUTPUTS: none 4583** 4584** OUTPUTS: none 4585** 4586** IMPLICIT INPUTS: none 4587** 4588** IMPLICIT OUTPUTS: none 4589** 4590** FUNCTION VALUE: none 4591** 4592** SIDE EFFECTS: none 4593** 4594**-- 4595**/ 4596 4597PRIVATE void rpc__cn_assoc_acb_create 4598( 4599 rpc_cn_assoc_p_t assoc 4600) 4601{ 4602 RPC_LOG_CN_ASSOC_ACB_CR_NTR; 4603 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_acb_create); 4604 4605 memset (assoc, 0, sizeof (rpc_cn_assoc_t)); 4606 assoc->alter_call_id = -1; 4607 RPC_COND_INIT (assoc->cn_ctlblk.cn_rcvr_cond, rpc_g_global_mutex); 4608 RPC_COND_INIT (assoc->assoc_msg_cond, rpc_g_global_mutex); 4609 4610 /* 4611 * Create the receiver thread. 4612 */ 4613 RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS, 4614 ( "####### assoc->%p Created receiver thread\n", assoc )); 4615 4616 DCETHREAD_TRY { 4617 dcethread_create_throw (&(assoc->cn_ctlblk.cn_rcvr_thread_id), 4618 &rpc_g_default_dcethread_attr, 4619 (dcethread_startroutine) rpc__cn_network_receiver, 4620 (dcethread_addr) assoc); 4621 } DCETHREAD_CATCH_ALL(THIS_CATCH) { 4622 DCETHREAD_RERAISE; 4623 } DCETHREAD_ENDTRY 4624 4625 RPC_LOG_CN_ASSOC_ACB_CR_XIT; 4626} 4627 4628 4629/***********************************************************************/ 4630/* 4631**++ 4632** 4633** ROUTINE NAME: rpc__cn_assoc_acb_free 4634** 4635** SCOPE: PRIVATE - declared in cnassoc.h 4636** 4637** DESCRIPTION: 4638** 4639** This routine will free the mutexes, condition variables and 4640** receiver thread contained in an association control block before the 4641** rpc__list_element_free routine returns it to heap storage. 4642** 4643** INPUTS: 4644** 4645** assoc The association control block being freed. 4646** 4647** INPUTS/OUTPUTS: none 4648** 4649** OUTPUTS: none 4650** 4651** IMPLICIT INPUTS: none 4652** 4653** IMPLICIT OUTPUTS: none 4654** 4655** FUNCTION VALUE: none 4656** 4657** SIDE EFFECTS: none 4658** 4659**-- 4660**/ 4661 4662PRIVATE void rpc__cn_assoc_acb_free 4663( 4664 rpc_cn_assoc_p_t assoc 4665) 4666{ 4667 rpc_cn_ctlblk_t * volatile ccb; 4668 dcethread* current_thread_id; 4669 void * dcethread_exit_status; 4670 int prev_cancel_state; 4671 4672 //DO_NOT_CLOBBER(ccb); 4673 4674 RPC_LOG_CN_ASSOC_ACB_FR_NTR; 4675 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_acb_free); 4676 4677 /* 4678 * Get a pointer to the connection control block contained in 4679 * the association control block. 4680 */ 4681 ccb = &assoc->cn_ctlblk; 4682 4683#ifdef notdef 4684 if (ccb->cn_rcvr_thread_id == (dcethread*) NULL) 4685 { 4686 RPC_LOG_CN_ASSOC_ACB_FR_XIT; 4687 return; 4688 } 4689#endif 4690 4691 /* 4692 * Determine whether we are now running in the receiver thread. 4693 */ 4694 current_thread_id = dcethread_self(); 4695 if (dcethread_equal (current_thread_id, ccb->cn_rcvr_thread_id) ) 4696 { 4697 /* 4698 * We are the receiver thread. 4699 * Send a cancel to ourselves so we will exit out of 4700 * the while loop in rpc__cn_network_receiver() without 4701 * having to reference the assoc which are going to 4702 * (possibly) free soon. 4703 */ 4704 RPC_COND_DELETE (ccb->cn_rcvr_cond, rpc_g_global_mutex); 4705 RPC_COND_DELETE (assoc->assoc_msg_cond, rpc_g_global_mutex); 4706 ccb->exit_rcvr = true; 4707 dcethread_detach_throw (ccb->cn_rcvr_thread_id); 4708 dcethread_interrupt_throw (ccb->cn_rcvr_thread_id); 4709 } 4710 else 4711 { 4712 /* 4713 * The receiver thread is now running with the CN global mutex 4714 * locked. We don't want to blow away anything in the association 4715 * or connection control block until we're sure the receiver 4716 * thread has terminated. To ensure this send the receiver thread a 4717 * cancel and then wait until it exits by using the 4718 * dcethread_join() function. This function will not return 4719 * until the receiver thread has terminated. 4720 */ 4721 ccb->exit_rcvr = true; 4722 dcethread_interrupt_throw (ccb->cn_rcvr_thread_id); 4723 4724 /* 4725 * Since this is a cancellable operation we'll turn cancels 4726 * off here. There's nothing we can do with them at this point. 4727 * The CN mutex must be unlocked also while we do the join. 4728 * This is because the receiver thread may need to lock the CN 4729 * mutex in order to exit. For instance, the receiver thread 4730 * may be blocked on the condition variable waiting for a new 4731 * connection. The process of unblocking from this condition 4732 * variable by definition acquires the CN mutex. 4733 */ 4734 prev_cancel_state = dcethread_enableinterrupt_throw (0); 4735 RPC_CN_UNLOCK (); 4736 dcethread_join_throw (ccb->cn_rcvr_thread_id, 4737 &dcethread_exit_status); 4738 RPC_CN_LOCK (); 4739 dcethread_enableinterrupt_throw (prev_cancel_state); 4740 4741 /* 4742 * Now that the receiver thread has terminated we can delete the 4743 * receiver thread and association receive queue condition variable. 4744 */ 4745 RPC_COND_DELETE (ccb->cn_rcvr_cond, rpc_g_global_mutex); 4746 RPC_COND_DELETE (assoc->assoc_msg_cond, rpc_g_global_mutex); 4747 } 4748 4749 { 4750 error_status_t st; 4751 4752 if (ccb->rpc_addr) 4753 rpc__naf_addr_free (&ccb->rpc_addr, &st); 4754 } 4755 4756 RPC_LOG_CN_ASSOC_ACB_FR_XIT; 4757} 4758 4759/*****************************************************************************/ 4760/*****************************************************************************/ 4761/*****************************************************************************/ 4762 4763/*****************************************************************************/ 4764/* 4765**++ 4766** 4767** ROUTINE NAME: rpc__cn_assoc_grp_init 4768** 4769** SCOPE: INTERNAL - declared locally 4770** 4771** DESCRIPTION: 4772** 4773** This routine will initialize all the fields of the 4774** association group given. 4775** 4776** INPUTS: 4777** 4778** assoc_grp The association group to be initialized. 4779** index The index part of the local ID assigned to 4780** this group. 4781** 4782** INPUTS/OUTPUTS: none 4783** 4784** OUTPUTS: none 4785** 4786** IMPLICIT INPUTS: none 4787** 4788** IMPLICIT OUTPUTS: none 4789** 4790** FUNCTION VALUE: none 4791** 4792** SIDE EFFECTS: none 4793** 4794**-- 4795**/ 4796 4797INTERNAL void rpc__cn_assoc_grp_init 4798( 4799 rpc_cn_assoc_grp_p_t assoc_grp, 4800 unsigned32 index 4801) 4802{ 4803 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_init); 4804 4805 /* 4806 * Initialize all the fields in the association group given. 4807 */ 4808 memset (assoc_grp, 0, sizeof (rpc_cn_assoc_grp_t)); 4809 rpc__cn_gen_local_id (index, &assoc_grp->grp_id); 4810 assoc_grp->grp_max_assoc = (typeof(assoc_grp->grp_max_assoc))(RPC_C_ASSOC_GRP_MAX_ASSOCS_DEFAULT); 4811 RPC_COND_INIT (assoc_grp->grp_assoc_wt, rpc_g_global_mutex); 4812 RPC_CN_STATS_INCR (assoc_grps); 4813} 4814 4815 4816/******************************************************************************/ 4817/* 4818**++ 4819** 4820** ROUTINE NAME: rpc__cn_assoc_grp_create 4821** 4822** SCOPE: INTERNAL - declared locally 4823** 4824** DESCRIPTION: 4825** 4826** This routine will expand the existing assoc group table by a 4827** fixed amount. It does this by determining the size 4828** of the old table, allocating a piece of memory that size plus 4829** some increment and copying the old table into it. The 4830** old table is then freed. 4831** 4832** INPUTS: none 4833** 4834** INPUTS/OUTPUTS: none 4835** 4836** OUTPUTS: 4837** 4838** st The return status of this routine. 4839** rpc_s_ok 4840** 4841** IMPLICIT INPUTS: none 4842** 4843** IMPLICIT OUTPUTS: none 4844** 4845** FUNCTION VALUE: ID of the first association group in 4846** the expanded area of the new table. 4847** 4848** SIDE EFFECTS: none 4849** 4850**-- 4851**/ 4852 4853INTERNAL rpc_cn_local_id_t rpc__cn_assoc_grp_create 4854( 4855 unsigned32 *st 4856) 4857{ 4858 rpc_cn_assoc_grp_t *new_assoc_grp; 4859 rpc_cn_local_id_t grp_id; 4860 unsigned16 old_count; 4861 unsigned16 new_count; 4862 unsigned32 i; 4863 4864 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_create); 4865 CODING_ERROR (st); 4866 4867 /* 4868 * Compute the size of the new table. 4869 */ 4870 old_count = rpc_g_cn_assoc_grp_tbl.grp_count; 4871 new_count = old_count + RPC_C_ASSOC_GRP_ALLOC_SIZE; 4872 4873 /* 4874 * First allocate a new association group table larger than the 4875 * existing by a fixed amount. 4876 */ 4877 RPC_MEM_ALLOC (new_assoc_grp, 4878 rpc_cn_assoc_grp_p_t, 4879 sizeof(rpc_cn_assoc_grp_t) * new_count, 4880 RPC_C_MEM_CN_ASSOC_GRP_BLK, 4881 RPC_C_MEM_WAITOK); 4882 if (new_assoc_grp == NULL) { 4883 *st = rpc_s_no_memory; 4884 RPC_CN_LOCAL_ID_CLEAR (grp_id); 4885 return (grp_id); 4886 } 4887 4888 /* 4889 * If there is an old association group table copy it into the 4890 * new table and free it. 4891 */ 4892 if (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector != NULL) 4893 { 4894 memcpy (new_assoc_grp, 4895 rpc_g_cn_assoc_grp_tbl.assoc_grp_vector, 4896 (old_count * sizeof (rpc_cn_assoc_grp_t))); 4897 for (i = 0; i < old_count; i++) 4898 { 4899 /* 4900 * Relocate the "last" pointer in the head of the grp_assoc_list. 4901 * We don't check group's state because they must be all active. 4902 * Otherwise, this function never get called. (grp_assoc_list.next 4903 * shouldn't be NULL.) 4904 */ 4905 if (new_assoc_grp[i].grp_assoc_list.next != NULL) 4906 { 4907 ((rpc_list_p_t)(new_assoc_grp[i].grp_assoc_list.next))->last = 4908 (dce_pointer_t)&new_assoc_grp[i].grp_assoc_list; 4909 } 4910 } 4911 4912 RPC_MEM_FREE (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector, 4913 RPC_C_MEM_CN_ASSOC_GRP_BLK); 4914 } 4915 4916 /* 4917 * Update the count of association groups and point to the new 4918 * association group table. 4919 */ 4920 rpc_g_cn_assoc_grp_tbl.grp_count = new_count; 4921 rpc_g_cn_assoc_grp_tbl.assoc_grp_vector = new_assoc_grp; 4922 4923 /* 4924 * Initialize the association groups in the table just 4925 * allocated. 4926 */ 4927 for (i = old_count; i < new_count; i++) 4928 { 4929 rpc__cn_assoc_grp_init (&new_assoc_grp[i], i); 4930 } 4931 4932 /* 4933 * Return a pointer to the beginning of the new area in the 4934 * new table. 4935 */ 4936 grp_id = new_assoc_grp[old_count].grp_id; 4937 *st = rpc_s_ok; 4938 return (grp_id); 4939} 4940 4941 4942/******************************************************************************/ 4943/* 4944**++ 4945** 4946** ROUTINE NAME: rpc__cn_assoc_grp_alloc 4947** 4948** SCOPE: PRIVATE - declared in cnassoc.h 4949** 4950** DESCRIPTION: 4951** 4952** This routine will locate an inactive association group slot 4953** in the association table, possibly by increasing the 4954** size of the table. This association group slot will be 4955** initialized and the association will be added to the list. 4956** 4957** INPUTS: 4958** 4959** rpc_addr The primary RPC address of the group. 4960** type The type of associations on this group. 4961** rem_id The remote group ID. 4962** 4963** 4964** INPUTS/OUTPUTS: none 4965** 4966** OUTPUTS: 4967** 4968** st The return status of this routine. 4969** rpc_s_ok 4970** 4971** IMPLICIT INPUTS: none 4972** 4973** IMPLICIT OUTPUTS: none 4974** 4975** FUNCTION VALUE: none 4976** 4977** SIDE EFFECTS: none 4978** 4979**-- 4980**/ 4981 4982PRIVATE rpc_cn_local_id_t rpc__cn_assoc_grp_alloc 4983( 4984 rpc_addr_p_t rpc_addr, 4985 rpc_transport_info_p_t transport_info, 4986 unsigned32 type, 4987 unsigned32 rem_id, 4988 unsigned32 *st 4989) 4990{ 4991 rpc_cn_assoc_grp_t *assoc_grp; 4992 rpc_cn_local_id_t grp_id; 4993 unsigned32 i; 4994 boolean found_assoc_grp; 4995 4996 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_alloc); 4997 CODING_ERROR (st); 4998 4999#ifdef DEBUG 5000 if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_GRP_ALLOC)) 5001 { 5002 *st = RPC_S_CN_DBG_FAILURE; 5003 RPC_CN_LOCAL_ID_CLEAR (grp_id); 5004 return(grp_id); 5005 } 5006#endif 5007 5008 /* 5009 * Ideally we'd like to locate an association group in the 5010 * existing table which is not being used. Worst case we'll 5011 * increase the size of the table to get a new group. 5012 * 5013 * Get a pointer to the group vector so this code will be easier 5014 * to read. 5015 */ 5016 assoc_grp = rpc_g_cn_assoc_grp_tbl.assoc_grp_vector; 5017 for (i = 0, found_assoc_grp = false; 5018 i < rpc_g_cn_assoc_grp_tbl.grp_count; 5019 i++) 5020 { 5021 if (assoc_grp[i].grp_state.cur_state == RPC_C_ASSOC_GRP_CLOSED) 5022 { 5023 assoc_grp = &assoc_grp[i]; 5024 found_assoc_grp = true; 5025 break; 5026 } 5027 } 5028 5029 if (!found_assoc_grp) 5030 { 5031 /* 5032 * The association group table will have to be expanded to 5033 * get a free group. 5034 */ 5035 grp_id = rpc__cn_assoc_grp_create (st); 5036 if (!RPC_CN_LOCAL_ID_VALID (grp_id)) 5037 { 5038 return (grp_id); 5039 } 5040 else 5041 { 5042 assoc_grp = RPC_CN_ASSOC_GRP (grp_id); 5043 } 5044 } 5045 5046 /* 5047 * At this point we have a group which has just been initialized. 5048 * 5049 * Copy the RPC address, if given, into the group. 5050 */ 5051 if (rpc_addr != NULL) 5052 { 5053 rpc__naf_addr_copy (rpc_addr, &assoc_grp->grp_address, st); 5054 assert(assoc_grp != NULL); 5055 assoc_grp->grp_secaddr = NULL; 5056 if (*st != rpc_s_ok) 5057 { 5058 RPC_CN_LOCAL_ID_CLEAR (grp_id); 5059 return (grp_id); 5060 } 5061 } 5062 5063 assert(assoc_grp != NULL); 5064 assoc_grp->grp_transport_info = transport_info; 5065 5066 if (transport_info) 5067 { 5068 rpc__transport_info_retain(transport_info); 5069 } 5070 5071 /* 5072 * Set up the type of this association group. 5073 */ 5074 assoc_grp->grp_flags |= type; 5075 5076 /* 5077 * Initialize the remote group id. 5078 */ 5079 assoc_grp->grp_remid.all = rem_id; 5080 5081 /* 5082 * Initialize the state machine control block in the group based 5083 * on its type. 5084 */ 5085 if (type == RPC_C_CN_ASSOC_GRP_CLIENT) 5086 { 5087 /* 5088 * Initialize with the client state tables. 5089 */ 5090 rpc__cn_sm_init (rpc_g_cn_client_grp_sm, 5091 rpc_g_cn_client_grp_action_tbl, 5092 &(assoc_grp->grp_state), 5093 rpc_c_cn_cl_a_g ); 5094 } 5095 else 5096 { 5097 /* 5098 * Initialize with the server state tables. 5099 */ 5100 rpc__cn_sm_init (rpc_g_cn_server_grp_sm, 5101 rpc_g_cn_server_grp_action_tbl, 5102 &(assoc_grp->grp_state), 5103 rpc_c_cn_svr_a_g ); 5104 } 5105 5106 /* 5107 * Finally send a new association event through the group state 5108 * machine. 5109 */ 5110 RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp, 5111 RPC_C_ASSOC_GRP_NEW, 5112 NULL, 5113 assoc_grp->grp_status); 5114 5115 /* 5116 * Increment the the number of active groups in the association 5117 * group table. 5118 */ 5119 rpc_g_cn_assoc_grp_tbl.grp_active_count++; 5120 *st = assoc_grp->grp_status; 5121 grp_id = assoc_grp->grp_id; 5122 return (grp_id); 5123} 5124 5125 5126/******************************************************************************/ 5127/* 5128**++ 5129** 5130** ROUTINE NAME: rpc__cn_assoc_grp_dealloc 5131** 5132** SCOPE: PRIVATE - declared in cnassoc.h 5133** 5134** DESCRIPTION: 5135** 5136** This routine will any resources on an association group. It 5137** is assumed the association list is empty. 5138** 5139** INPUTS: 5140** 5141** grp_id The id of the group being deallocated. 5142** 5143** 5144** INPUTS/OUTPUTS: none 5145** 5146** OUTPUTS: none 5147** 5148** IMPLICIT INPUTS: none 5149** 5150** IMPLICIT OUTPUTS: none 5151** 5152** FUNCTION VALUE: none 5153** 5154** SIDE EFFECTS: none 5155** 5156**-- 5157**/ 5158 5159PRIVATE void rpc__cn_assoc_grp_dealloc 5160( 5161 rpc_cn_local_id_t grp_id 5162) 5163{ 5164 rpc_cn_assoc_grp_t *assoc_grp; 5165 rpc_addr_p_t rpc_addr; 5166 unsigned32 st; 5167 5168 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_dealloc); 5169 5170 /* 5171 * Check whether a primary RPC address exists on the group. 5172 */ 5173 assoc_grp = RPC_CN_ASSOC_GRP (grp_id); 5174 assert(assoc_grp != NULL); 5175 if ((rpc_addr = assoc_grp->grp_address) != NULL) 5176 { 5177 /* 5178 * Free the RPC address. 5179 */ 5180 rpc__naf_addr_free (&assoc_grp->grp_address, &st); 5181 } 5182 5183 /* 5184 * Check whether a secondary RPC address exists on the group. 5185 */ 5186 if ((rpc_addr != assoc_grp->grp_secaddr) 5187 && 5188 (assoc_grp->grp_secaddr != NULL)) 5189 { 5190 /* 5191 * Free the RPC address. 5192 */ 5193 rpc__naf_addr_free (&assoc_grp->grp_secaddr, &st); 5194 } 5195 5196 if (assoc_grp->grp_transport_info) 5197 { 5198 rpc__transport_info_release(assoc_grp->grp_transport_info); 5199 assoc_grp->grp_transport_info = NULL; 5200 } 5201 5202 /* 5203 * Set up other fields in the group for the next time it is 5204 * allocated. 5205 */ 5206 RPC_CN_LOCAL_ID_CLEAR (assoc_grp->grp_remid); 5207 assoc_grp->grp_flags = 0; 5208 assoc_grp->grp_address = NULL; 5209 assoc_grp->grp_secaddr = NULL; 5210 assoc_grp->grp_refcnt = 0; 5211 assoc_grp->grp_max_assoc = (typeof(assoc_grp->grp_max_assoc))(RPC_C_ASSOC_GRP_MAX_ASSOCS_DEFAULT); 5212 assoc_grp->grp_cur_assoc = 0; 5213 assoc_grp->grp_assoc_waiters = 0; 5214 assoc_grp->grp_status = rpc_s_ok; 5215 assoc_grp->grp_next_key_id = 0; 5216 RPC_LIST_INIT (assoc_grp->grp_assoc_list); 5217 assoc_grp->grp_liveness_mntr = NULL; 5218 assoc_grp->grp_callcnt = 0; 5219 5220 /* 5221 * Regenerate the local ID since there may still be bindings 5222 * which have the old ID of this association group in it. 5223 */ 5224 rpc__cn_gen_local_id (assoc_grp->grp_id.parts.id_index, &assoc_grp->grp_id); 5225 5226 /* 5227 * Decrement the the number of active groups in the association 5228 * group table. 5229 */ 5230 rpc_g_cn_assoc_grp_tbl.grp_active_count--; 5231} 5232 5233 5234/******************************************************************************/ 5235/* 5236**++ 5237** 5238** ROUTINE NAME: rpc__cn_assoc_grp_add_assoc 5239** 5240** SCOPE: PRIVATE - declared in cnassoc.h 5241** 5242** DESCRIPTION: 5243** 5244** This routine will add the specified association to the 5245** association list in the group. 5246** 5247** INPUTS: 5248** 5249** grp_id The association group id. 5250** assoc The association to be added. 5251** 5252** INPUTS/OUTPUTS: none 5253** 5254** OUTPUTS: none 5255** 5256** IMPLICIT INPUTS: none 5257** 5258** IMPLICIT OUTPUTS: none 5259** 5260** FUNCTION VALUE: none 5261** 5262** SIDE EFFECTS: none 5263** 5264**-- 5265**/ 5266 5267PRIVATE void rpc__cn_assoc_grp_add_assoc 5268( 5269 rpc_cn_local_id_t grp_id, 5270 rpc_cn_assoc_p_t assoc 5271) 5272{ 5273 rpc_cn_assoc_grp_t *assoc_grp; 5274 5275 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_add_assoc); 5276 5277 /* 5278 * Add the new association to the group by sending an add 5279 * association to group event through the group state machine. 5280 */ 5281 assoc_grp = RPC_CN_ASSOC_GRP (grp_id); 5282 assert(assoc_grp != NULL); 5283 RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp, 5284 RPC_C_ASSOC_GRP_ADD_ASSOC, 5285 assoc, 5286 assoc_grp->grp_status); 5287} 5288 5289 5290/******************************************************************************/ 5291/* 5292**++ 5293** 5294** ROUTINE NAME: rpc__cn_assoc_grp_rem_assoc 5295** 5296** SCOPE: PRIVATE - declared in cnassoc.h 5297** 5298** DESCRIPTION: 5299** 5300** This routine will remove an association from the association 5301** list on a group. If this results in the list becoming empty 5302** the RPC address on the association group is freed and the 5303** group is initialized. 5304** 5305** INPUTS: 5306** 5307** grp_id The association group id. 5308** assoc The association to be removed. 5309** 5310** 5311** INPUTS/OUTPUTS: none 5312** 5313** OUTPUTS: 5314** 5315** st The return status of this routine. 5316** rpc_s_ok 5317** 5318** IMPLICIT INPUTS: none 5319** 5320** IMPLICIT OUTPUTS: none 5321** 5322** FUNCTION VALUE: none 5323** 5324** SIDE EFFECTS: none 5325** 5326**-- 5327**/ 5328 5329PRIVATE void rpc__cn_assoc_grp_rem_assoc 5330( 5331 rpc_cn_local_id_t grp_id, 5332 rpc_cn_assoc_p_t assoc 5333) 5334{ 5335 rpc_cn_assoc_grp_t *assoc_grp; 5336 5337 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_rem_assoc); 5338 5339 /* 5340 * If the association group passed in is NULL then this 5341 * operation is a no-op. 5342 */ 5343 if (RPC_CN_LOCAL_ID_VALID (grp_id)) 5344 { 5345 /* 5346 * Remove the association from the group by sending a remove 5347 * association from group event through the group state machine. 5348 */ 5349 assoc_grp = RPC_CN_ASSOC_GRP (grp_id); 5350 assert(assoc_grp != NULL); 5351 RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp, 5352 RPC_C_ASSOC_GRP_REM_ASSOC, 5353 assoc, 5354 assoc_grp->grp_status); 5355 5356 /* 5357 * If this is a server association group and there are no 5358 * calls currently running on this association group and we 5359 * are in the call wait state then post a no calls 5360 * indication event to the group state machine. 5361 */ 5362 if ((assoc_grp->grp_flags & RPC_C_CN_ASSOC_GRP_SERVER) 5363 && 5364 (assoc_grp->grp_callcnt == 0) 5365 && 5366 (assoc_grp->grp_state.cur_state == 5367 RPC_C_SERVER_ASSOC_GRP_CALL_WAIT)) 5368 { 5369 RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp, 5370 RPC_C_ASSOC_GRP_NO_CALLS_IND, 5371 assoc, 5372 assoc_grp->grp_status); 5373 } 5374 } 5375} 5376 5377 5378/******************************************************************************/ 5379/* 5380**++ 5381** 5382** ROUTINE NAME: rpc__cn_assoc_grp_lkup_by_addr 5383** 5384** SCOPE: PRIVATE - declared in cnassoc.h 5385** 5386** DESCRIPTION: 5387** 5388** This routine will scan the association group table for a 5389** group which is active and whose RPC address matches that given 5390** as an input argument. If a matching group is found a pointer to it is 5391** returned otherwise a NULL is returned. 5392** 5393** INPUTS: 5394** 5395** rpc_addr The address of a remote address space. 5396** type The type of association group (client or server). 5397** 5398** INPUTS/OUTPUTS: none 5399** 5400** OUTPUTS: 5401** 5402** st The return status of this routine. 5403** rpc_s_ok 5404** rpc_s_assoc_grp_not_found 5405** 5406** IMPLICIT INPUTS: none 5407** 5408** IMPLICIT OUTPUTS: none 5409** 5410** FUNCTION VALUE: 5411** 5412** return The id of the association group pointer found. 5413** 5414** SIDE EFFECTS: none 5415** 5416**-- 5417**/ 5418 5419PRIVATE rpc_cn_local_id_t rpc__cn_assoc_grp_lkup_by_addr 5420( 5421 rpc_addr_p_t rpc_addr, 5422 rpc_transport_info_p_t transport_info, 5423 unsigned32 type, 5424 unsigned32 *st 5425) 5426{ 5427 boolean addrs_equal; 5428 unsigned32 i; 5429 rpc_cn_assoc_grp_t *assoc_grp; 5430 rpc_cn_local_id_t grp_id; 5431 5432 RPC_LOG_CN_GRP_ADDR_LKUP_NTR; 5433 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_lkup_by_addr); 5434 CODING_ERROR (st); 5435 5436 /* 5437 * Check whether a valid RPC address was given for the lookup. 5438 */ 5439 if (rpc_addr != NULL) 5440 { 5441 /* 5442 * Get a pointer to the group vector so this code will be easier 5443 * to read. 5444 */ 5445 assoc_grp = rpc_g_cn_assoc_grp_tbl.assoc_grp_vector; 5446 5447 /* 5448 * An association group will be located by using the RPC address 5449 * given. 5450 */ 5451 for (i = 0; i < rpc_g_cn_assoc_grp_tbl.grp_count; i++) 5452 { 5453 /* 5454 * Check all groups which are the right type and are active 5455 */ 5456 if ((assoc_grp[i].grp_flags & type) 5457 && 5458 (assoc_grp[i].grp_state.cur_state == RPC_C_ASSOC_GRP_ACTIVE)) 5459 { 5460 5461 /* 5462 * The association group has associations. Compare the RPC 5463 * address given against the primary address in the 5464 * association group. 5465 */ 5466 addrs_equal = rpc__naf_addr_compare (rpc_addr, 5467 assoc_grp[i].grp_address, 5468 st); 5469 /* 5470 * If the input argument RPC address matched that in 5471 * the association group return it. 5472 */ 5473 if (!addrs_equal) 5474 { 5475 /* address do not match, so continue searching */ 5476 continue; 5477 } 5478#ifndef __APPLE__ 5479 if (!transport_info) 5480 { 5481 /* addresses matched, but no transport_info to check, so 5482 go ahead and use this group */ 5483 *st = rpc_s_ok; 5484 return (assoc_grp[i].grp_id); 5485 } 5486#endif 5487 if (rpc__transport_info_equal(assoc_grp[i].grp_transport_info, transport_info)) 5488 { 5489 /* addresses matched and transport_info matched, so 5490 go ahead and use this group */ 5491 *st = rpc_s_ok; 5492 return (assoc_grp[i].grp_id); 5493 } 5494 } 5495 } 5496 } 5497 5498 /* 5499 * There were no matching association groups. Return NULL. 5500 */ 5501 *st = rpc_s_assoc_grp_not_found; 5502 RPC_CN_LOCAL_ID_CLEAR (grp_id); 5503 RPC_LOG_CN_GRP_ADDR_LKUP_XIT; 5504 return (grp_id); 5505} 5506 5507 5508/******************************************************************************/ 5509/* 5510**++ 5511** 5512** ROUTINE NAME: rpc__cn_assoc_grp_lkup_by_remid 5513** 5514** SCOPE: PRIVATE - declared in cnassoc.h 5515** 5516** DESCRIPTION: 5517** 5518** This routine will scan the association group table for a 5519** group whose remote group id matches that given as an input 5520** argument. If a matching group is found a pointer to it is 5521** returned otherwise a NULL is returned. 5522** 5523** INPUTS: 5524** 5525** rem_id The remote group id. 5526** type The type of association group (client or server). 5527** rpc_addr The address of the server to which the 5528** association was established. 5529** 5530** INPUTS/OUTPUTS: none 5531** 5532** OUTPUTS: 5533** 5534** st The return status of this routine. 5535** rpc_s_ok 5536** rpc_s_assoc_grp_not_found 5537** 5538** IMPLICIT INPUTS: none 5539** 5540** IMPLICIT OUTPUTS: none 5541** 5542** FUNCTION VALUE: 5543** 5544** return The id of the association group pointer found. 5545** 5546** SIDE EFFECTS: none 5547** 5548**-- 5549**/ 5550 5551PRIVATE rpc_cn_local_id_t rpc__cn_assoc_grp_lkup_by_remid 5552( 5553 unsigned32 rem_id, 5554 unsigned32 type, 5555 rpc_addr_p_t rpc_addr, 5556 unsigned32 *st 5557) 5558{ 5559 unsigned32 i; 5560 rpc_cn_assoc_grp_t *assoc_grp; 5561 rpc_cn_local_id_t grp_id; 5562 5563 RPC_LOG_CN_GRP_REMID_LKUP_NTR; 5564 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_lkup_by_remid); 5565 CODING_ERROR (st); 5566 5567 /* 5568 * Get a pointer to the group vector so this code will be easier 5569 * to read. 5570 */ 5571 assoc_grp = rpc_g_cn_assoc_grp_tbl.assoc_grp_vector; 5572 5573 /* 5574 * An association group will be located by using the RPC address 5575 * given. 5576 */ 5577 for (i = 0; i < rpc_g_cn_assoc_grp_tbl.grp_count; i++) 5578 { 5579 /* 5580 * Check all groups which are the right type and are active. 5581 */ 5582 if ((assoc_grp[i].grp_flags & type) 5583 && 5584 (assoc_grp[i].grp_state.cur_state == RPC_C_ASSOC_GRP_ACTIVE)) 5585 { 5586 /* 5587 * The association group has associations. Compare the remote 5588 * group id given against the remote group id in the 5589 * association group. 5590 */ 5591 if (assoc_grp[i].grp_remid.all == rem_id) 5592 { 5593 boolean addrs_equal; 5594 5595 /* 5596 * Check whether the primary address on the 5597 * association group matches that to which the 5598 * association was established. 5599 */ 5600 addrs_equal = rpc__naf_addr_compare (rpc_addr, 5601 assoc_grp[i].grp_address, 5602 st); 5603 if (addrs_equal) 5604 { 5605 *st = rpc_s_ok; 5606 RPC_LOG_CN_GRP_REMID_LKUP_XIT; 5607 return (assoc_grp[i].grp_id); 5608 } 5609 } 5610 } 5611 } 5612 5613 /* 5614 * There were no matching association groups. Return NULL. 5615 */ 5616 *st = rpc_s_assoc_grp_not_found; 5617 RPC_CN_LOCAL_ID_CLEAR (grp_id); 5618 return (grp_id); 5619} 5620 5621 5622/******************************************************************************/ 5623/* 5624**++ 5625** 5626** ROUTINE NAME: rpc__cn_assoc_grp_lkup_by_id 5627** 5628** SCOPE: PRIVATE - declared in cnassoc.h 5629** 5630** DESCRIPTION: 5631** 5632** This routine will match the group ID given against the entry 5633** in the association group table. If the group is active and 5634** entire group ID given matches that in the association group that 5635** group is returned otherwise an invalid local id is returned. 5636** 5637** INPUTS: 5638** 5639** grp_id The association group ID to compare against. 5640** type The type of association group (client or server). 5641** 5642** INPUTS/OUTPUTS: none 5643** 5644** OUTPUTS: 5645** 5646** st The return status of this routine. 5647** rpc_s_ok 5648** rpc_s_assoc_grp_not_found 5649** 5650** IMPLICIT INPUTS: none 5651** 5652** IMPLICIT OUTPUTS: none 5653** 5654** FUNCTION VALUE: 5655** 5656** return The id of the association group pointer found. 5657** 5658** SIDE EFFECTS: none 5659** 5660**-- 5661**/ 5662 5663PRIVATE rpc_cn_local_id_t rpc__cn_assoc_grp_lkup_by_id 5664( 5665 rpc_cn_local_id_t grp_id, 5666 unsigned32 type, 5667 rpc_transport_info_p_t transport_info, 5668 unsigned32 *st 5669) 5670{ 5671 rpc_cn_assoc_grp_t *assoc_grp; 5672 rpc_cn_local_id_t ret_grp_id; 5673 5674 RPC_LOG_CN_GRP_ID_LKUP_NTR; 5675 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_lkup_by_id); 5676 CODING_ERROR (st); 5677 5678#ifdef DEBUG 5679 if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, 5680 RPC_C_CN_DBG_GRP_LKUP_BY_ID)) 5681 { 5682 *st = rpc_s_assoc_grp_not_found; 5683 RPC_CN_LOCAL_ID_CLEAR (ret_grp_id); 5684 return (ret_grp_id); 5685 } 5686#endif 5687 5688 /* 5689 * First determine if we were given a valid group ID. 5690 */ 5691 if (RPC_CN_LOCAL_ID_VALID (grp_id) && 5692 grp_id.parts.id_index < rpc_g_cn_assoc_grp_tbl.grp_count) 5693 { 5694 /* 5695 * An association group will be located by using the lower 16 5696 * bits of the id as an index into the association group table. 5697 */ 5698 assoc_grp = RPC_CN_ASSOC_GRP (grp_id); 5699 5700 /* 5701 * To use this association group the entire group id must match 5702 * and must be the right type. 5703 */ 5704 assert(assoc_grp != NULL); 5705 if ( RPC_CN_LOCAL_ID_EQUAL (assoc_grp->grp_id, grp_id) && 5706 (assoc_grp->grp_flags & type) && 5707 (assoc_grp->grp_state.cur_state == RPC_C_ASSOC_GRP_ACTIVE) ) 5708 { 5709#ifndef __APPLE__ 5710 if (!transport_info) 5711 { 5712 /* grp_ids matched, but no transport_info to check, so 5713 go ahead and use this group */ 5714 *st = rpc_s_ok; 5715 RPC_LOG_CN_GRP_ID_LKUP_XIT; 5716 return (grp_id); 5717 } 5718#endif 5719 if (rpc__transport_info_equal(assoc_grp->grp_transport_info, transport_info)) 5720 { 5721 /* grp_ids matched and transport_info matched, so 5722 go ahead and use this group */ 5723 *st = rpc_s_ok; 5724 RPC_LOG_CN_GRP_ID_LKUP_XIT; 5725 return (grp_id); 5726 } 5727 } 5728 } 5729 5730 *st = rpc_s_assoc_grp_not_found; 5731 RPC_CN_LOCAL_ID_CLEAR (ret_grp_id); 5732 return (ret_grp_id); 5733} 5734 5735 5736/******************************************************************************/ 5737/* 5738**++ 5739** 5740** ROUTINE NAME: rpc__cn_assoc_grp_tbl_init 5741** 5742** SCOPE: PRIVATE - declared in cnassoc.h 5743** 5744** DESCRIPTION: 5745** 5746** This routine will initialize the association group table. 5747** 5748** INPUTS: none 5749** 5750** INPUTS/OUTPUTS: none 5751** 5752** OUTPUTS: none 5753** 5754** IMPLICIT INPUTS: none 5755** 5756** IMPLICIT OUTPUTS: none 5757** 5758** FUNCTION VALUE: none 5759** 5760** SIDE EFFECTS: none 5761** 5762**-- 5763**/ 5764 5765PRIVATE void rpc__cn_assoc_grp_tbl_init (void) 5766{ 5767 unsigned32 st; 5768 unsigned32 server_disc_time = 0; 5769 unsigned32 client_disc_time = 0; 5770 char *x; 5771 5772 RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_tbl_init); 5773 5774 /* 5775 * Init the new association condition variable, count and wakeup 5776 * variables internal to this module. 5777 */ 5778 RPC_COND_INIT (grp_new_wt, 5779 rpc_g_global_mutex); 5780 grp_new_in_progress = false; 5781 grp_new_waiters = 0; 5782 5783 /* 5784 * Init the association group counts. 5785 */ 5786 rpc_g_cn_assoc_grp_tbl.grp_count = 0; 5787 rpc_g_cn_assoc_grp_tbl.grp_active_count = 0; 5788 5789 /* 5790 * Init the association group vector to NULL. 5791 */ 5792 rpc_g_cn_assoc_grp_tbl.assoc_grp_vector = NULL; 5793 5794 /* 5795 * Start the client and server reclaimation timers with the 5796 * values as specified in the NCA Connection Architecture 5797 * spec. 5798 */ 5799 x = getenv("RPC_CLIENT_DISC_TIME"); 5800 if (x != NULL) 5801 client_disc_time = (unsigned32)atoi(x); 5802 if (client_disc_time == 0) 5803 client_disc_time = RPC_C_ASSOC_CLIENT_DISC_TIMER; 5804 5805 rpc__timer_set (&rpc_g_cn_assoc_grp_tbl.grp_client_timer, 5806 (rpc_timer_proc_p_t) rpc__cn_assoc_timer_reclaim, 5807 (dce_pointer_t) RPC_C_CN_ASSOC_GRP_CLIENT, 5808 RPC_CLOCK_SEC (client_disc_time)); 5809 5810 x = getenv("RPC_SERVER_DISC_TIME"); 5811 if (x != NULL) 5812 server_disc_time = (unsigned32)atoi(x); 5813 if (server_disc_time == 0) 5814 server_disc_time = RPC_C_ASSOC_SERVER_DISC_TIMER; 5815 5816 rpc__timer_set (&rpc_g_cn_assoc_grp_tbl.grp_server_timer, 5817 (rpc_timer_proc_p_t) rpc__cn_assoc_timer_reclaim, 5818 (dce_pointer_t) RPC_C_CN_ASSOC_GRP_SERVER, 5819 RPC_CLOCK_SEC (server_disc_time)); 5820 5821 /* 5822 * Put some association groups in the table so this doesn't have 5823 * to be done on the first RPC. 5824 */ 5825 (void) rpc__cn_assoc_grp_create (&st); 5826} 5827 5828 5829/***********************************************************************/ 5830/* 5831**++ 5832** 5833** ROUTINE NAME: rpc__cn_grp_sm_protocol_error 5834** 5835** SCOPE: PRIVATE 5836** 5837** DESCRIPTION: 5838** 5839** Action routine invoked when an illegal transition is detected. 5840** This routine writes an error message to stdout and DIEs. 5841** 5842** INPUTS: 5843** 5844** spc_struct The special structure which is passed to the 5845** state machine event evaluation routine. 5846** This is assumed to be the assoc grp. 5847** 5848** event_param The event specific argument. 5849** 5850** INPUTS/OUTPUTS: 5851** sm The control block from the event 5852** evaluation routine. Input is the current 5853** status and event for the control block. 5854** Output is the next state or updated 5855** current state, for the control block. 5856** 5857** OUTPUTS: none 5858** 5859** IMPLICIT INPUTS: none 5860** 5861** IMPLICIT OUTPUTS: none 5862** 5863** FUNCTION VALUE: unsigned32 5864** 5865** SIDE EFFECTS: output is printed on stdout. 5866** 5867**-- 5868**/ 5869 5870PRIVATE unsigned32 rpc__cn_grp_sm_protocol_error 5871( 5872 dce_pointer_t spc_struct, 5873 dce_pointer_t event_param ATTRIBUTE_UNUSED, 5874 dce_pointer_t sm ATTRIBUTE_UNUSED 5875) 5876{ 5877 rpc_cn_assoc_grp_t *assoc_grp; 5878 5879 RPC_CN_DBG_RTN_PRINTF(rpc__cn_grp_sm_protocol_error); 5880 assoc_grp = (rpc_cn_assoc_grp_t *) spc_struct; 5881 5882 /* 5883 * "Illegal state transition detected in CN {server|client} association 5884 * group state machine [cur_state: %d, cur_event: %d, grp: %x]" 5885 */ 5886 rpc_dce_svc_printf ( 5887 __FILE__, __LINE__, 5888 "%d %d %x", 5889 rpc_svc_cn_state, 5890 svc_c_sev_fatal | svc_c_action_abort, 5891 (assoc_grp->grp_flags & RPC_C_CN_ASSOC_GRP_SERVER) ? 5892 rpc_m_cn_ill_state_trans_sg : rpc_m_cn_ill_state_trans_cg, 5893 assoc_grp->grp_state.cur_state, 5894 assoc_grp->grp_state.cur_event, 5895 assoc_grp ); 5896 return 0; 5897} 5898