1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME 80** 81** cncclsm.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** Client call State Machine for the Connection-based RPC runtime. 90** 91** 92*/ 93 94 95#include <commonp.h> /* Common declarations for all RPC runtime */ 96#include <com.h> /* Common communications services */ 97#include <comprot.h> /* Common protocol services */ 98#include <cnp.h> /* NCA Connection private declarations */ 99#include <cnfbuf.h> /* NCA Connection fragment buffer declarations */ 100#include <cnpkt.h> /* NCA Connection protocol header */ 101#include <cnassoc.h> /* NCA Connection association services */ 102#include <cnxfer.h> /* NCA Connection buffered data transfer routines */ 103#include <cnsm.h> /* NCA Connection state machine declarations */ 104#include <cncall.h> /* NCA connection call service */ 105#include <cnclsm.h> 106 107 108/******************************************************************************/ 109/* 110 * Global Definitions 111 */ 112#ifdef DEBUG 113GLOBAL const char *rpc_g_cn_call_client_events [] = 114{ 115 "TRANSMIT_REQ ", 116 "CONFIRM ", 117 "FAULT_DNE ", 118 "FAULT ", 119 "LOCAL_ALERT ", 120 "END ", 121 "ASSOC_ALLOC_ACK ", 122 "ASSOC_ALLOC_NAK ", 123 "START ", 124 "LAST_TRANSMIT_REQ", 125 "LOCAL_ERROR ", 126 "ALERT_TIMEOUT " 127}; 128 129GLOBAL const char *rpc_g_cn_call_client_states [] = 130{ 131 "INIT ", 132 "ASSOC_ALLOC_WAIT ", 133 "STUB_WAIT ", 134 "REQUEST ", 135 "RESPONSE ", 136 "CALL_COMPLETED ", 137 "CALL_FAILED_DNE ", 138 "CALL_FAILED " 139}; 140 141PRIVATE void rpc__cn_call_sm_trace 142( 143 rpc_cn_call_rep_t *crep, 144 unsigned32 event_id, 145 unsigned32 id, 146 const char *file ATTRIBUTE_UNUSED, 147 const char *funcname ATTRIBUTE_UNUSED, 148 int lineno ATTRIBUTE_UNUSED 149) 150{ 151 if (RPC_CALL_IS_CLIENT(&crep->common)) 152 { 153 RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE, 154 ("(%s) STATE CLIENT CALL: %d state->%s event->%s\n", 155 funcname, id, 156 RPC_CN_CALL_CLIENT_STATE((crep)->call_state.cur_state), 157 RPC_CN_CALL_CLIENT_EVENT(event_id))); 158 } 159 else 160 { 161 RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE, 162 ("(%s) STATE SERVER CALL: %d state->%s event->%s\n", 163 funcname, id, 164 RPC_CN_CALL_SERVER_STATE((crep)->call_state.cur_state), 165 RPC_CN_CALL_SERVER_EVENT(event_id))); 166 } 167} 168 169PRIVATE void rpc__cn_call_sm_trace_state 170( 171 rpc_cn_call_rep_t *crep, 172 unsigned32 id, 173 const char *file ATTRIBUTE_UNUSED, 174 const char *funcname ATTRIBUTE_UNUSED, 175 int lineno ATTRIBUTE_UNUSED 176) 177{ 178 if (RPC_CALL_IS_CLIENT(&crep->common)) 179 { 180 RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE, 181 ("(%s) STATE CLIENT CALL: %d new state->%s\n", 182 funcname, id, 183 RPC_CN_CALL_CLIENT_STATE(crep->call_state.cur_state))); 184 } 185 else 186 { 187 RPC_DBG_PRINTF (rpc_e_dbg_cn_state, RPC_C_CN_DBG_CALL_SM_TRACE, 188 ("(%s) STATE SERVER CALL: %d new state->%s\n", 189 funcname, id, 190 RPC_CN_CALL_SERVER_STATE(crep->call_state.cur_state))); 191 } 192} 193 194#endif /* DEBUG */ 195 196 197/***********************************************************************/ 198/* 199** C L I E N T C A L L P R E D I C A T E T A B L E 200**/ 201/* 202 * The predicates. 203 * As a performance enhancement, 204 * we have revamped many predicate routines as macros and have absorbed 205 * the predicates into the actions. Thus, there is no longer a need 206 * for the predicate table; the predicate declarations too, are 207 * modified. 208 */ 209/* 210#define MAYBE_SEMANTICS_PRED 0 211#define LAST_RECV_FRAG_PRED 1 212*/ 213/* 214 * The predicate routine prototypes. 215 */ 216INTERNAL unsigned8 maybe_semantics_pred_rtn ( 217 dce_pointer_t /*spc_struct*/, 218 dce_pointer_t /*event_param*/ 219 ) ATTRIBUTE_UNUSED; 220INTERNAL unsigned8 last_recv_frag_pred_rtn ( 221 dce_pointer_t /*spc_struct*/, 222 dce_pointer_t /*event_param*/ 223 ) ATTRIBUTE_UNUSED; 224 225 226/***********************************************************************/ 227/* 228** C L I E N T C A L L A C T I O N T A B L E 229**/ 230 231/***********************************************************************/ 232 233/* 234 * The actions. 235 * 236 * The QueueAlertTimeout action routine in the NCA CN arch spec 237 * is not listed here since cancel timeouts are handled outside the 238 * state machine. See the routine header of forward_alert_action_rtn 239 * for more details. 240 * 241 * The VerifySecurity action routine in the NCA CN arch spec is not 242 * listed here since this was embedded into existing action routines, 243 * where appropriate in this implementation. 244 */ 245#define TRANSMIT_REQ 0 246#define HANDLE_RECV_FRAG 1 247#define RAISE_FAULT 2 248#define FORWARD_ALERT 3 249#define ALLOCATE_ASSOC 4 250 251/* abort send = send_orphaned + deallocate assoc + raise fault */ 252#define ABORT_SEND 5 253 254#define ABORT_RECV 6 255#define SEND_LAST_FRAG 7 256#define PROTOCOL_ERROR 8 257 258/* 259 * The Action routine prototypes. 260 */ 261INTERNAL unsigned32 transmit_req_action_rtn ( 262 dce_pointer_t /*spc_struct*/, 263 dce_pointer_t /*event_param*/, 264 dce_pointer_t /*sm*/ 265 ); 266INTERNAL unsigned32 handle_recv_frag_action_rtn ( 267 dce_pointer_t /*spc_struct*/, 268 dce_pointer_t /*event_param*/, 269 dce_pointer_t /*sm*/ 270 ); 271INTERNAL unsigned32 raise_fault_action_rtn ( 272 dce_pointer_t /*spc_struct*/, 273 dce_pointer_t /*event_param*/, 274 dce_pointer_t /*sm*/ 275 ); 276INTERNAL unsigned32 forward_alert_action_rtn ( 277 dce_pointer_t /*spc_struct*/, 278 dce_pointer_t /*event_param*/, 279 dce_pointer_t /*sm*/ 280 ); 281INTERNAL unsigned32 allocate_assoc_action_rtn ( 282 dce_pointer_t /*spc_struct*/, 283 dce_pointer_t /*event_param*/, 284 dce_pointer_t /*sm*/ 285 ); 286INTERNAL unsigned32 abort_send_action_rtn ( 287 dce_pointer_t /*spc_struct*/, 288 dce_pointer_t /*event_param*/, 289 dce_pointer_t /*sm*/ 290 ); 291INTERNAL unsigned32 abort_recv_action_rtn ( 292 dce_pointer_t /*spc_struct*/, 293 dce_pointer_t /*event_param*/, 294 dce_pointer_t /*sm*/ 295 ); 296INTERNAL unsigned32 send_last_frag_action_rtn ( 297 dce_pointer_t /*spc_struct*/, 298 dce_pointer_t /*event_param*/, 299 dce_pointer_t /*sm*/ 300 ); 301 302/* 303 * The action table itself. 304 */ 305GLOBAL rpc_cn_sm_action_fn_t rpc_g_cn_client_call_action_tbl [] = 306{ 307 transmit_req_action_rtn, 308 handle_recv_frag_action_rtn, 309 raise_fault_action_rtn, 310 forward_alert_action_rtn, 311 allocate_assoc_action_rtn, 312 abort_send_action_rtn, 313 abort_recv_action_rtn, 314 send_last_frag_action_rtn, 315 rpc__cn_call_sm_protocol_error 316}; 317 318/***********************************************************************/ 319/* 320** C L I E N T C A L L S T A T E T A B L E 321**/ 322 323INTERNAL rpc_cn_sm_state_tbl_entry_t init_state = 324 325 /* state 0 - init */ 326 { 327 ILLEGAL_TRANSITION, /* event 0 */ 328 ILLEGAL_TRANSITION, /* event 1 */ 329 ILLEGAL_TRANSITION, /* event 2 */ 330 ILLEGAL_TRANSITION, /* event 3 */ 331 ILLEGAL_TRANSITION, /* event 4 */ 332 {RPC_C_CLIENT_CALL_CFDNE}, /* event 5 - call_end */ 333 ILLEGAL_TRANSITION, /* event 6 */ 334 ILLEGAL_TRANSITION, /* event 7 */ 335 {ALLOCATE_ASSOC}, /* event 8 - start_call */ 336 ILLEGAL_TRANSITION, /* event 9 */ 337 ILLEGAL_TRANSITION, /* event 10 */ 338 ILLEGAL_TRANSITION /* event 11 */ 339 }; 340 341 /* state 1 - assoc_alloc_wait */ 342INTERNAL rpc_cn_sm_state_tbl_entry_t assoc_alloc_wait_state = 343 { 344 ILLEGAL_TRANSITION, /* event 0 */ 345 ILLEGAL_TRANSITION, /* event 1 */ 346 ILLEGAL_TRANSITION, /* event 2 */ 347 ILLEGAL_TRANSITION, /* event 3 */ 348 ILLEGAL_TRANSITION, /* event 4 */ 349 {RPC_C_CLIENT_CALL_CFDNE}, /* event 5 - call_end */ 350 {RPC_C_CLIENT_CALL_STUB_WAIT}, /* event 6 - alloc_assoc_ack */ 351 {RPC_C_CLIENT_CALL_CFDNE}, /* event 7 - alloc_assoc_nak */ 352 ILLEGAL_TRANSITION, /* event 8 */ 353 ILLEGAL_TRANSITION, /* event 9 */ 354 ILLEGAL_TRANSITION, /* event 10 */ 355 ILLEGAL_TRANSITION /* event 11 */ 356 }; 357 358 /* state 2 - stub_wait */ 359INTERNAL rpc_cn_sm_state_tbl_entry_t stub_wait_state = 360 { 361 {TRANSMIT_REQ}, /* event 0 - transmit_req */ 362 ILLEGAL_TRANSITION, /* event 1 */ 363 ILLEGAL_TRANSITION, /* event 2 */ 364 ILLEGAL_TRANSITION, /* event 3 */ 365 ILLEGAL_TRANSITION, /* event 4 */ 366 {RPC_C_CLIENT_CALL_CFDNE}, /* event 5 - call_end */ 367 ILLEGAL_TRANSITION, /* event 6 */ 368 ILLEGAL_TRANSITION, /* event 7 */ 369 ILLEGAL_TRANSITION, /* event 8 */ 370 {SEND_LAST_FRAG}, /* event 9 - last_transmit_req */ 371 {RPC_C_CLIENT_CALL_CFDNE}, /* event 10 - local_err */ 372 ILLEGAL_TRANSITION, /* event 10 */ 373 ILLEGAL_TRANSITION /* event 11 */ 374 }; 375 376 /* state 3 - call_request */ 377INTERNAL rpc_cn_sm_state_tbl_entry_t call_request_state = 378 { 379 {TRANSMIT_REQ}, /* event 0 - transmit_req */ 380 ILLEGAL_TRANSITION, /* event 1 */ 381 {RAISE_FAULT}, /* event 2 - fault_dne */ 382 {RAISE_FAULT}, /* event 3 - fault */ 383 {FORWARD_ALERT}, /* event 4 - local alert */ 384 {ABORT_SEND}, /* event 5 - call_end */ 385 ILLEGAL_TRANSITION, /* event 6 */ 386 ILLEGAL_TRANSITION, /* event 7 */ 387 ILLEGAL_TRANSITION, /* event 8 */ 388 {SEND_LAST_FRAG}, /* event 9 - last_transmit_req */ 389 {ABORT_SEND}, /* event 10 - local_err */ 390 {ABORT_SEND} /* event 11 - alert timeout */ 391 }; 392 393 /* state 4 - call response */ 394INTERNAL rpc_cn_sm_state_tbl_entry_t call_response_state = 395 { 396 ILLEGAL_TRANSITION, /* event 0 */ 397 {HANDLE_RECV_FRAG}, /* event 1 - rpc_conf */ 398 {RAISE_FAULT}, /* event 2 - fault_dne */ 399 {RAISE_FAULT}, /* event 3 - fault */ 400 {FORWARD_ALERT}, /* event 4 - local alert */ 401 {ABORT_SEND}, /* event 5 - call_end */ 402 ILLEGAL_TRANSITION, /* event 6 */ 403 ILLEGAL_TRANSITION, /* event 7 */ 404 ILLEGAL_TRANSITION, /* event 8 */ 405 ILLEGAL_TRANSITION, /* event 9 */ 406 {ABORT_SEND}, /* event 10 - local_err */ 407 {ABORT_SEND} /* event 11 - alert timeout */ 408 }; 409 410 /* state 5 - call_completed */ 411INTERNAL rpc_cn_sm_state_tbl_entry_t call_completed_state = 412 { 413 ILLEGAL_TRANSITION, /* event 0 */ 414 ILLEGAL_TRANSITION, /* event 1 */ 415 ILLEGAL_TRANSITION, /* event 2 */ 416 ILLEGAL_TRANSITION, /* event 3 */ 417 {RPC_C_CLIENT_CALL_CALL_COMPLETED}, /* event 4 - local alert */ 418 {RPC_C_CLIENT_CALL_CALL_COMPLETED}, /* event 5 - call_end */ 419 ILLEGAL_TRANSITION, /* event 6 */ 420 ILLEGAL_TRANSITION, /* event 7 */ 421 ILLEGAL_TRANSITION, /* event 8 */ 422 ILLEGAL_TRANSITION, /* event 9 */ 423 ILLEGAL_TRANSITION, /* event 10 */ 424 ILLEGAL_TRANSITION /* event 11 */ 425 }; 426 427 /* state 6 - cfdne (call failed, did not execute) */ 428INTERNAL rpc_cn_sm_state_tbl_entry_t cfdne_state = 429 { 430 {RPC_C_CLIENT_CALL_CFDNE}, /* event 0 */ 431 ILLEGAL_TRANSITION, /* event 1 */ 432 ILLEGAL_TRANSITION, /* event 2 */ 433 ILLEGAL_TRANSITION, /* event 3 */ 434 {RPC_C_CLIENT_CALL_CFDNE}, /* event 4 - local alert */ 435 {RPC_C_CLIENT_CALL_CFDNE}, /* event 5 - call_end */ 436 ILLEGAL_TRANSITION, /* event 6 */ 437 ILLEGAL_TRANSITION, /* event 7 */ 438 ILLEGAL_TRANSITION, /* event 8 */ 439 {RPC_C_CLIENT_CALL_CFDNE}, /* event 9 */ 440 ILLEGAL_TRANSITION, /* event 10 */ 441 ILLEGAL_TRANSITION /* event 11 */ 442 }; 443 444 /* state 7 - call_failed */ 445INTERNAL rpc_cn_sm_state_tbl_entry_t call_failed_state = 446 { 447 {RPC_C_CLIENT_CALL_CALL_FAILED}, /* event 0 */ 448 ILLEGAL_TRANSITION, /* event 1 */ 449 ILLEGAL_TRANSITION, /* event 2 */ 450 ILLEGAL_TRANSITION, /* event 3 */ 451 {RPC_C_CLIENT_CALL_CALL_FAILED}, /* event 4 - local alert */ 452 {RPC_C_CLIENT_CALL_CALL_FAILED}, /* event 5 - call_end */ 453 ILLEGAL_TRANSITION, /* event 6 */ 454 ILLEGAL_TRANSITION, /* event 7 */ 455 ILLEGAL_TRANSITION, /* event 8 */ 456 {RPC_C_CLIENT_CALL_CALL_FAILED}, /* event 9 */ 457 ILLEGAL_TRANSITION, /* event 10 */ 458 ILLEGAL_TRANSITION /* event 11 */ 459 }; 460 461GLOBAL rpc_cn_sm_state_entry_p_t rpc_g_cn_client_call_sm [] = 462{ 463 init_state, /* state 0 - init */ 464 assoc_alloc_wait_state, /* state 1 - assoc_alloc_wait */ 465 stub_wait_state, /* state 2 - stub_wait */ 466 call_request_state, /* state 3 - call_request */ 467 call_response_state, /* state 4 - call_response */ 468 call_completed_state, /* state 5 - call_completed */ 469 cfdne_state, /* state 6 - call failed, dne */ 470 call_failed_state /* state 7 - call_failed */ 471 472}; 473 474 475/***********************************************************************/ 476/* 477** 478** C L I E N T C A L L P R E D I C A T E R O U T I N E S 479** 480**/ 481 482/***********************************************************************/ 483 484/* 485**++ 486** 487** ROUTINE NAME: maybe_semantics_pred_rtn 488** 489** SCOPE: INTERNAL 490** 491** DESCRIPTION: 492** 493** Predicate routine invoked from the Call Active State. 494** 495** INPUTS: 496** 497** spc_struct The call rep. Note that this is passed in as 498** the special structure which is passed to the 499** state machine event evaluation routine. 500** 501** event_param The special event related parameter which is 502** passed to the state machine event evaluation 503** routine. 504** This input argument is ignored. 505** 506** INPUTS/OUTPUTS: none 507** 508** OUTPUTS: none 509** 510** IMPLICIT INPUTS: none 511** 512** IMPLICIT OUTPUTS: none 513** 514** FUNCTION VALUE: 0 if MaybeSemantics is false 515** 1 if MaybeSemantics is true 516** 517** SIDE EFFECTS: none 518** 519**-- 520**/ 521 522INTERNAL unsigned8 maybe_semantics_pred_rtn 523( 524 dce_pointer_t spc_struct, 525 dce_pointer_t event_param ATTRIBUTE_UNUSED 526) 527{ 528 rpc_cn_packet_p_t header_p; 529 530 RPC_CN_DBG_RTN_PRINTF(CLIENT maybe_semantics_pred_rtn); 531 532 /* 533 * check the protocol header (cached in the callrep) to see if 534 * PFC_MAYBE is set. 535 */ 536 537 header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR ( 538 (rpc_cn_call_rep_p_t) spc_struct); 539 if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE) == 0) 540 { 541 return (0); 542 } 543 else 544 { 545 return (1); 546 } 547} 548 549 550/* 551**++ 552** 553** MACRO NAME: MAYBE_SEMANTICS_PRED 554** 555** SCOPE: INTERNAL 556** 557** DESCRIPTION: 558** 559** This is a macro version of maybe_semantics_pred_rtn, introduced for 560** performance reasons. The macro lets us avoid overhead associated with 561** calling the predicate routine from within the action routine. 562** Predicate macro is invoked from the Call Active State. 563** 564** INPUTS: 565** 566** spc_struct The association group. Note that this is passed in as 567** the special structure which is passed to the 568** state machine event evaluation routine. 569** 570** event_param The special event related parameter which is 571** passed to the state machine event evaluation 572** routine. 573** This input argument is ignored. 574** 575** status Instead of returning a value from the macro, 576** write the value calculated in the macro to 577** status. Status' scope includes the routine 578** calling the macro. Check status in the calling 579** routine to determine next state and in cases, 580** flow through the action routine. 581** 582** INPUTS/OUTPUTS: none 583** 584** OUTPUTS: 585** 586** status See explanation above. 587** 588** IMPLICIT INPUTS: none 589** 590** IMPLICIT OUTPUTS: none 591** 592** FUNCTION VALUE: 0 if MaybeSemantics is false 593** 1 if MaybeSemantics is true 594** 595** SIDE EFFECTS: none 596** 597**-- 598**/ 599#define MAYBE_SEMANTICS_PRED(spc_struct, event_param, status) \ 600{\ 601 RPC_CN_DBG_RTN_PRINTF(CLIENT maybe_semantics_pred_macro);\ 602 header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(\ 603 (rpc_cn_call_rep_p_t) spc_struct);\ 604 if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_MAYBE) == 0)\ 605 {\ 606 status = 0;\ 607 }\ 608 else\ 609 {\ 610 status = 1;\ 611 }\ 612} 613 614 615/* 616**++ 617** 618** ROUTINE NAME: last_recv_frag_pred_rtn 619** 620** SCOPE: INTERNAL 621** 622** DESCRIPTION: 623** 624** Predicate routine invoked from the Call Response state when an 625** RPCConf event occurs. 626** 627** INPUTS: 628** 629** spc_struct The callrep. This is passed as the 630** special structure which is passed to the 631** state machine event evaluation routine. 632** This argument is ignored. 633** 634** event_param The received packet contained in a fragment 635** buffer. This is passed in as the special 636** event related parameter by the state machine 637** event evaluation routine. 638** 639** INPUTS/OUTPUTS: none 640** 641** OUTPUTS: none 642** 643** IMPLICIT INPUTS: none 644** 645** IMPLICIT OUTPUTS: none 646** 647** FUNCTION VALUE: 0 if LastRecvFrag is false 648** 1 if LastRecvFrag is true 649** 650** SIDE EFFECTS: none 651** 652**-- 653**/ 654 655INTERNAL unsigned8 last_recv_frag_pred_rtn 656( 657 dce_pointer_t spc_struct ATTRIBUTE_UNUSED, 658 dce_pointer_t event_param 659) 660{ 661 rpc_cn_fragbuf_p_t fragbuf; 662 rpc_cn_packet_p_t header_p; 663 664 RPC_CN_DBG_RTN_PRINTF(CLIENT last_recv_frag_pred_rtn); 665 fragbuf = (rpc_cn_fragbuf_p_t) event_param; 666 667 /* 668 * The [unpacked] packet header starts off in the header_overhead 669 * area. 670 */ 671 header_p = (rpc_cn_packet_p_t) fragbuf->data_p; 672 673 if ((RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) == 0) 674 { 675 return (0); 676 } 677 else 678 { 679 return (1); 680 } 681 682} 683 684/***********************************************************************/ 685/* 686 * C L I E N T C A L L A C T I O N R O U T I N E S 687 */ 688/***********************************************************************/ 689 690/* 691**++ 692** 693** ROUTINE NAME: allocate_assoc_action_rtn 694** 695** SCOPE: INTERNAL 696** 697** DESCRIPTION: 698** 699** Action routine to allocate an association from the current 700** association group. 701** 702** INPUTS: 703** 704** spc_struct The call rep. Note that this is passed in as 705** the special structure which is passed to the 706** state machine event evaluation routine. 707** 708** event_param The if_spec_rep. This is passed in as the 709** special event related parameter which was 710** passed to the state machine evaluation routine. 711** 712** INPUTS/OUTPUTS: 713** 714** sm The control block from the event evaluation 715** routine. Input is the current state and 716** event for the control block. Output is the 717** next state or updated current state, for the 718** control block. 719** 720** OUTPUTS: none 721** 722** IMPLICIT INPUTS: none 723** 724** IMPLICIT OUTPUTS: none 725** 726** FUNCTION VALUE: completion status, one of: 727** rpc_s_ok, 728** 729** SIDE EFFECTS: Either alloc_assoc_ack or alloc_assoc_nak 730** event would be appended to the state 731** machine event evaluation list. 732** 733**-- 734**/ 735INTERNAL unsigned32 allocate_assoc_action_rtn 736( 737 dce_pointer_t spc_struct, 738 dce_pointer_t event_param, 739 dce_pointer_t sm 740) 741{ 742 rpc_cn_assoc_p_t assoc_p ATTRIBUTE_UNUSED; 743 rpc_cn_call_rep_p_t call_rep_p; 744 rpc_cn_sm_event_entry_t event_entry; 745 unsigned32 status; 746 rpc_cn_sm_ctlblk_t *sm_p; 747 748 RPC_CN_DBG_RTN_PRINTF(CLIENT allocate_assoc_action_rtn); 749 750 call_rep_p = (rpc_cn_call_rep_p_t) spc_struct; 751 752 /* 753 * Allocate the association. Pass in the binding rep, 754 * and interface spec rep and get back an association, it 755 * negotiated transfer syntax and its context id. 756 */ 757 if ((call_rep_p->assoc = rpc__cn_assoc_request 758 (call_rep_p, 759 (rpc_cn_binding_rep_t *) call_rep_p->binding_rep, 760 (rpc_if_rep_t *) event_param, 761 &call_rep_p->transfer_syntax, 762 &call_rep_p->context_id, 763 &call_rep_p->sec, 764 &status)) != NULL) 765 { 766 call_rep_p->max_seg_size = RPC_CN_ASSOC_MAX_XMIT_FRAG (call_rep_p->assoc); 767 rpc__cn_assoc_push_call (call_rep_p->assoc, call_rep_p, &status); 768 event_entry.event_id = RPC_C_CALL_ALLOC_ASSOC_ACK; 769 event_entry.event_param = (dce_pointer_t) NULL; 770 } 771 else 772 { 773 event_entry.event_id = RPC_C_CALL_ALLOC_ASSOC_NAK; 774 event_entry.event_param = (dce_pointer_t) NULL; 775 776 /* 777 * We will return the status returned by assoc_request. 778 * This status will be returned by the eval routine since 779 * we will invoke no action routine when we transtion to 780 * cfdne state. 781 */ 782 } 783 784 /* 785 * Insert the new event on the event queue for our state 786 * machine. 787 */ 788 rpc__cn_sm_insert_event (&event_entry, &(call_rep_p->call_state)); 789 sm_p = (rpc_cn_sm_ctlblk_t *)sm; 790 sm_p->cur_state = RPC_C_CLIENT_CALL_ASSOC_ALLOC_WAIT; 791 return (status); 792} 793 794 795/* 796**++ 797** 798** ROUTINE NAME: transmit_req_action_rtn 799** 800** SCOPE: INTERNAL 801** 802** DESCRIPTION: 803** 804** Action routine to send the call request PDU(s) to the server. 805** 806** INPUTS: 807** 808** spc_struct The call rep. Note that this is passed in as 809** the special structure which is passed to the 810** state machine event evaluation routine. 811** 812** event_param The iovector describing the data to be sent. 813** This is passed in as the special event related 814** parameter passed to the state machine event 815** evaluator. 816** 817** INPUTS/OUTPUTS: 818** 819** sm The control block from the event evaluation 820** routine. Input is the current state and 821** event for the control block. Output is the 822** next state or updated current state, for the 823** control block. 824** 825** OUTPUTS: none 826** 827** IMPLICIT INPUTS: none 828** 829** IMPLICIT OUTPUTS: none 830** 831** FUNCTION VALUE: rpc_s_ok if the send was completed successfully. 832** 833** SIDE EFFECTS: none 834** 835**-- 836**/ 837 838INTERNAL unsigned32 transmit_req_action_rtn 839( 840 dce_pointer_t spc_struct, 841 dce_pointer_t event_param, 842 dce_pointer_t sm 843) 844{ 845 846 rpc_cn_call_rep_p_t call_rep; 847 rpc_iovector_p_t stub_data_p; 848 rpc_iovector_elt_p_t iov_elt_p; 849 unsigned8 event ATTRIBUTE_UNUSED; 850 unsigned32 i; 851 unsigned32 status; 852 rpc_cn_sm_ctlblk_t *sm_p; 853 854 RPC_CN_DBG_RTN_PRINTF(CLIENT transmit_req_action_rtn); 855 856 status = rpc_s_ok; 857 858 call_rep = (rpc_cn_call_rep_p_t) spc_struct; 859 stub_data_p = (rpc_iovector_p_t) event_param; 860 sm_p = (rpc_cn_sm_ctlblk_t *)sm; 861 862 /* 863 * We set call_executed to true at this point. 864 * This is somewhat conservative; but it is correct. 865 * We will reset call_executed if we get back a 866 * fault_dne. 867 */ 868 call_rep->call_executed = true; 869 870 /* 871 * A call_transmit must have some stub data. If this RPC 872 * had no input arguments, then the first call should have 873 * been a call_transceive with no stub data. 874 */ 875#ifdef DEBUG 876 if (stub_data_p->num_elt <= 0) 877 { 878 status = rpc_s_coding_error; 879 } 880 else 881#endif 882 { 883 /* Fill in the alloc_hint */ 884 call_rep->alloc_hint = rpc__cn_get_alloc_hint(stub_data_p); 885 886 for (i = 0, 887 iov_elt_p = stub_data_p->elt; /* first iovector element */ 888 i < stub_data_p->num_elt; 889 i++, iov_elt_p++) 890 { 891 /* 892 * If the data_len is 0, just deallocate the iovector 893 * element. 894 */ 895 if (iov_elt_p->data_len == 0) 896 { 897 if (iov_elt_p->buff_dealloc != NULL) 898 { 899 (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr); 900 } 901 } 902 else 903 { 904 /* 905 * If the number of bytes < our bcopy_lim, 906 * copy the data and deallocate the buffer. 907 * copy_buffer will automatically transfer the 908 * data if the accumulated byte count reaches 909 * the segment size. 910 */ 911 if (iov_elt_p->data_len <= RPC_C_CN_BCOPY_LIM) 912 { 913 rpc__cn_copy_buffer (call_rep, iov_elt_p, &status); 914 if (iov_elt_p->buff_dealloc != NULL) 915 { 916 (iov_elt_p->buff_dealloc) (iov_elt_p->buff_addr); 917 } 918 } 919 else 920 { 921 /* 922 * If the buffer must be made immediately reusable, copy 923 * it also. 924 * Note that this can be optimized later so that we won't 925 * copy; just transmit the data; if certain criteria have 926 * been met. 927 */ 928 if (iov_elt_p->flags & rpc_c_iovector_elt_reused) 929 { 930 rpc__cn_copy_buffer (call_rep, iov_elt_p, &status); 931 if (status != rpc_s_ok) 932 { 933 goto done; 934 } 935 } 936 else 937 { 938#if 0 939 if (iov_elt_p->flags & rpc_c_iovector_elt_reused) 940 { 941 found_reusable = true; 942 } 943#endif 944 /* 945 * Don't copy, add this buffer as a new iovector 946 * element. 947 * add_new_vector_elmt will automatically transfer the 948 * data if the accumulated byte count reaches 949 * the segment size. 950 */ 951 rpc__cn_add_new_iovector_elmt (call_rep, iov_elt_p, &status); 952 if (status != rpc_s_ok) 953 { 954 goto done; 955 } 956 } 957 } 958 } 959 } 960 } 961 962#if 0 963 /* 964 * Finally, if there is any buffered data on the call rep flush 965 * any data that we'd have to copy if possible. 966 */ 967 if (found_reusable) 968 { 969 rpc__cn_flush_buffers (call_rep, &status); 970 } 971#endif 972 973done: 974; 975 sm_p->cur_state = RPC_C_CLIENT_CALL_REQUEST; 976 return (status); 977} 978 979 980/* 981**++ 982** 983** ROUTINE NAME: send_last_frag_action_rtn 984** 985** SCOPE: INTERNAL 986** 987** DESCRIPTION: 988** 989** Action routine to send the last call request fragment to the server. 990** 991** INPUTS: 992** 993** spc_struct The call rep. Note that this is passed in as 994** the special structure which is passed to the 995** state machine event evaluation routine. 996** 997** event_param The iovector describing the data to be sent. 998** This is passed in as the special event related 999** parameter passed to the state machine event 1000** evaluator. 1001** This parameter can be null for a transceive 1002** with no input arguments. 1003** 1004** INPUTS/OUTPUTS: 1005** 1006** sm The control block from the event evaluation 1007** routine. Input is the current state and 1008** event for the control block. Output is the 1009** next state or updated current state, for the 1010** control block. 1011** 1012** OUTPUTS: none 1013** 1014** IMPLICIT INPUTS: none 1015** 1016** IMPLICIT OUTPUTS: none 1017** 1018** FUNCTION VALUE: rpc_s_ok if the send was completed successfully. 1019** 1020** SIDE EFFECTS: none 1021** 1022**-- 1023**/ 1024 1025INTERNAL unsigned32 send_last_frag_action_rtn 1026( 1027 dce_pointer_t spc_struct, 1028 dce_pointer_t event_param, 1029 dce_pointer_t sm 1030) 1031{ 1032 1033 rpc_cn_call_rep_p_t call_rep; 1034 rpc_iovector_p_t stub_data_p; 1035 rpc_cn_packet_p_t header_p; 1036 unsigned32 status; 1037 rpc_cn_sm_ctlblk_t *sm_p; 1038 unsigned8 n_state; 1039 1040 RPC_CN_DBG_RTN_PRINTF(CLIENT send_last_frag_action_rtn); 1041 1042 sm_p = (rpc_cn_sm_ctlblk_t *)sm; 1043 status = rpc_s_ok; 1044 call_rep = (rpc_cn_call_rep_p_t) spc_struct; 1045 1046 /* 1047 * Status contains the result of the macro. 1048 */ 1049 MAYBE_SEMANTICS_PRED(spc_struct, event_param, status); 1050 if (status == 0) /* MaybeSemantics is false */ 1051 { 1052 n_state = RPC_C_CLIENT_CALL_RESPONSE; 1053 } 1054 else /* MaybeSemantics is true */ 1055 { 1056 n_state = RPC_C_CLIENT_CALL_CALL_COMPLETED; 1057 } 1058 1059 stub_data_p = (rpc_iovector_p_t) event_param; 1060 1061 /* 1062 * If there's stub data, we can process it just like a normal 1063 * call request. This might leave data buffered. 1064 * 1065 * Note that the absence of stub data is indicated by either 1066 * a null iovector pointer or an iovector with 0 elements. 1067 */ 1068 if ((stub_data_p != NULL) && (stub_data_p->num_elt > 0)) 1069 { 1070 /* 1071 * Note that since we are calling action routines from 1072 * within action routines, we need to update state as 1073 * a final step here. Otherwise, the action routines 1074 * would update sm->cur_state inappropriately for 1075 * the calling routine. 1076 */ 1077 status = 1078 transmit_req_action_rtn (spc_struct, event_param, sm); 1079 if (status != rpc_s_ok) 1080 { 1081 sm_p->cur_state = n_state; 1082 return (status); 1083 } 1084 } 1085 1086 /* 1087 * Set the last frag flag bit in the cached protocol header 1088 * and send it along with any buffered data. 1089 */ 1090 RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG; 1091 if (RPC_CN_CREP_ACC_BYTCNT (call_rep) >= RPC_CN_CREP_SIZEOF_HDR (call_rep)) 1092 { 1093 rpc__cn_transmit_buffers (call_rep, &status); 1094 rpc__cn_dealloc_buffered_data (call_rep); 1095 1096 /* 1097 * Set the length of the iov to 1. We don't use the general 1098 * FREE_ALL_EXCEPT_PROT_HEADER macro since we won't be 1099 * using the iov again. 1100 */ 1101 RPC_CN_CREP_IOVLEN (call_rep) = 1; 1102 if (status != rpc_s_ok) 1103 { 1104 sm_p->cur_state = n_state; 1105 call_rep->assoc->assoc_status = status; 1106 return (status); 1107 } 1108 } 1109 else 1110 { 1111 /* 1112 * If the accumulated bytecount field is less than at 1113 * least that of the request header, something is really 1114 * off. 1115 */ 1116 /* 1117 * rpc_m_invalid_accbytcnt 1118 * "(%s) Inconsistency in ACC_BYTCNT field" 1119 */ 1120 rpc_dce_svc_printf ( 1121 __FILE__, __LINE__, 1122 "%s", 1123 rpc_svc_cn_errors, 1124 svc_c_sev_fatal | svc_c_action_abort, 1125 rpc_m_invalid_accbytcnt, 1126 "send_last_frag_action_rtn" ); 1127 } 1128 1129 sm_p->cur_state = n_state; 1130 return (rpc_s_ok); 1131 1132} 1133 1134 1135/* 1136**++ 1137** 1138** ROUTINE NAME: handle_recv_frag_action_rtn 1139** 1140** SCOPE: INTERNAL 1141** 1142** DESCRIPTION: 1143** 1144** Action routine to make the (received) fragment data available 1145** to the stub for unmarshalling. 1146** 1147** INPUTS: 1148** 1149** spc_struct The call rep. Note that this is passed in as 1150** the special structure which is passed to the 1151** state machine event evaluation routine. 1152** 1153** event_param The fragment buffer containing the response 1154** message. This is passed in as the special 1155** event related parameter which was passed to 1156** the state machine event evaluation routine. 1157** 1158** INPUTS/OUTPUTS: 1159** 1160** sm The control block from the event evaluation 1161** routine. Input is the current state and 1162** event for the control block. Output is the 1163** next state or updated current state, for the 1164** control block. 1165** 1166** OUTPUTS: none 1167** 1168** IMPLICIT INPUTS: none 1169** 1170** IMPLICIT OUTPUTS: none 1171** 1172** FUNCTION VALUE: rpc_s_ok 1173** 1174** SIDE EFFECTS: Either a fault or fault_dne event may be 1175** appended to the state machine event list. 1176** 1177**-- 1178**/ 1179INTERNAL unsigned32 handle_recv_frag_action_rtn 1180( 1181 dce_pointer_t spc_struct, 1182 dce_pointer_t event_param, 1183 dce_pointer_t sm 1184) 1185{ 1186 unsigned32 status ATTRIBUTE_UNUSED; 1187 rpc_cn_fragbuf_p_t fragbuf; 1188 rpc_cn_packet_p_t header_p; 1189 rpc_cn_call_rep_p_t call_rep; 1190 rpc_cn_sm_ctlblk_t *sm_p; 1191 unsigned8 n_state = 0; 1192 1193 RPC_CN_DBG_RTN_PRINTF(CLIENT handle_recv_frag_action_rtn); 1194 1195 call_rep = (rpc_cn_call_rep_p_t) spc_struct; 1196 fragbuf = (rpc_cn_fragbuf_p_t) event_param; 1197 sm_p = (rpc_cn_sm_ctlblk_t *)sm; 1198 header_p = (rpc_cn_packet_p_t) fragbuf->data_p; 1199 1200 /* 1201 * We've got a proper response. Adjust data_size to describe 1202 * the stub data. 1203 * Note that we do not need to adjust data_p since that will 1204 * be done by rpc__cn_call_receive. 1205 */ 1206 fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) - 1207 RPC_CN_PKT_AUTH_TLR_LEN (header_p) - 1208 RPC_CN_PKT_SIZEOF_RESP_HDR; 1209 1210 /* 1211 * Determine whether this is the last response fragment. 1212 */ 1213 if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) 1214 { 1215 1216 /* 1217 * The predicate associated with this routine, 1218 * last_recv_frag_pred_rtn, checks the same 1219 * flags checked above in the if statement. 1220 * If RPC_CN_PKT_FLAGS & rpc_c_cn_flags_lastfrag 1221 * are 0, then set state to rpc_c_client_call 1222 * response, else set state to rpc_c_client_call_ 1223 * call_complete. 1224 */ 1225 n_state = RPC_C_CLIENT_CALL_CALL_COMPLETED; 1226 /* 1227 * If there is a timer running stop it since we've heard from 1228 * the server. 1229 */ 1230 rpc__cn_call_stop_cancel_timer (call_rep); 1231 1232 /* 1233 * Record whether the server finished with a pending alert. Note 1234 * that the alert count in the packet does not include the 1235 * alert forwarded by setting the PFC_PENDING_ALERT bit in the 1236 * first fragment of the request. 1237 */ 1238 if ((call_rep->u.client.cancel.server_count > RPC_CN_PKT_ALERT_COUNT (header_p)) || 1239 (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING)) 1240 { 1241 /* 1242 * Either the number of alerts forwarded by us is 1243 * greater than the number of alerts posted to the call 1244 * executor thread on the server OR the there was still an alert 1245 * pending in the call executor thread when the server 1246 * stub returned. In either case set the 1247 * server_had_pending flag in the call_rep to indicate an 1248 * alert should be posted to the client caller thread 1249 * before returning to the client stub. 1250 */ 1251 call_rep->u.client.cancel.server_had_pending = true; 1252#ifdef DEBUG 1253 if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING) 1254 { 1255 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 1256 ("(handle_recv_frag_action_rtn) call_rep->%p alert pending flag is set in header\n", call_rep)); 1257 } 1258 else 1259 { 1260 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 1261 ("(handle_recv_frag_action_rtn) call_rep->%p number alerts forwarded (%d) > alert count in header (%d)\n", 1262 call_rep, 1263 call_rep->u.client.cancel.server_count, 1264 RPC_CN_PKT_ALERT_COUNT (header_p))); 1265 } 1266#endif 1267 } 1268 } 1269 else 1270 { 1271 n_state = RPC_C_CLIENT_CALL_RESPONSE; 1272 } 1273 /* 1274 * We are currently executing in the receiver thread. 1275 * 1276 * If there is stub data, queue it on the association so that 1277 * the client call thread can get it. 1278 * If there is no stub data (e.g., no out arguments), just 1279 * deallocate the fragment buffer. 1280 * We make an exception for the first fragment; it is always 1281 * queued since the client call thread may already be blocked 1282 * on the condition variable. 1283 */ 1284 if (fragbuf->data_size || 1285 (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_FIRST_FRAG)) 1286 { 1287 rpc__cn_assoc_queue_frag (call_rep->assoc, fragbuf, true); 1288 } 1289 else 1290 { 1291 (* fragbuf->fragbuf_dealloc) (fragbuf); 1292 } 1293 1294 /* 1295 * Increment num_pkts in the call rep. This will be used in 1296 * determining when to check for pending cancels. 1297 */ 1298 call_rep->num_pkts++; 1299 1300 sm_p->cur_state = n_state; 1301 return (rpc_s_ok); 1302} 1303 1304 1305/* 1306**++ 1307** 1308** ROUTINE NAME: raise_fault_action_rtn 1309** 1310** SCOPE: INTERNAL 1311** 1312** DESCRIPTION: 1313** 1314** Action routine to deallocate the current association and raise 1315** fault. Operationally, this will store the address of the 1316** fragment buffer in the callrep (for later retrieval via the 1317** rpc__receive_fault). 1318** 1319** INPUTS: 1320** 1321** spc_struct The call rep. Note that this is passed in as 1322** the special structure which is passed to the 1323** state machine event evaluation routine. 1324** 1325** event_param The fault packet. This is passed in as the 1326** event specific structure. 1327** 1328** INPUTS/OUTPUTS: 1329** 1330** sm The control block from the event evaluation 1331** routine. Input is the current state and 1332** event for the control block. Output is the 1333** next state or updated current state, for the 1334** control block. 1335** 1336** OUTPUTS: none 1337** 1338** IMPLICIT INPUTS: none 1339** 1340** IMPLICIT OUTPUTS: none 1341** 1342** FUNCTION VALUE: rpc_s_call_faulted 1343** 1344** SIDE EFFECTS: none 1345** 1346**-- 1347**/ 1348INTERNAL unsigned32 raise_fault_action_rtn 1349( 1350 dce_pointer_t spc_struct, 1351 dce_pointer_t event_param, 1352 dce_pointer_t sm 1353) 1354{ 1355 unsigned32 status ATTRIBUTE_UNUSED; 1356 rpc_cn_fragbuf_p_t fragbuf; 1357 rpc_cn_packet_p_t header_p; 1358 rpc_cn_call_rep_p_t call_rep; 1359 rpc_cn_sm_ctlblk_t *sm_p; 1360 1361 RPC_CN_DBG_RTN_PRINTF(CLIENT raise_fault_action_rtn); 1362 1363 call_rep = (rpc_cn_call_rep_p_t) spc_struct; 1364 fragbuf = (rpc_cn_fragbuf_p_t) event_param; 1365 header_p = (rpc_cn_packet_p_t) fragbuf->data_p; 1366 sm_p = (rpc_cn_sm_ctlblk_t *)sm; 1367 1368 /* 1369 * We've got a proper response. Adjust data_size to describe 1370 * the stub data. 1371 * Note that we do not need to adjust data_p since that will 1372 * be done by rpc__cn_call_receive. 1373 */ 1374 fragbuf->data_size = RPC_CN_PKT_FRAG_LEN (header_p) - 1375 RPC_CN_PKT_AUTH_TLR_LEN (header_p) - 1376 RPC_CN_PKT_SIZEOF_FAULT_HDR; 1377 1378 /* 1379 * If there is a timer running stop it since we've heard from 1380 * the server. 1381 */ 1382 rpc__cn_call_stop_cancel_timer (call_rep); 1383 1384 /* 1385 * Determine whether this is the last fault fragment. 1386 */ 1387 if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_LAST_FRAG) 1388 { 1389 /* 1390 * Record whether the server finished with a pending alert. Note 1391 * that the alert count in the packet does not include the 1392 * alert forwarded by setting the PFC_PENDING_ALERT bit in the 1393 * first fragment of the request. 1394 */ 1395 if ((call_rep->u.client.cancel.server_count > RPC_CN_PKT_ALERT_COUNT (header_p)) || 1396 (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING)) 1397 { 1398 /* 1399 * Either the number of alerts forwarded by us is 1400 * greater than the number of alerts posted to the call 1401 * executor thread on the server OR the there was still an alert 1402 * pending in the call executor thread when the server 1403 * stub returned. In either case set the 1404 * server_had_pending flag in the call_rep to indicate an 1405 * alert should be posted to the client caller thread 1406 * before returning to the client stub. 1407 */ 1408 call_rep->u.client.cancel.server_had_pending = true; 1409#ifdef DEBUG 1410 if (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_ALERT_PENDING) 1411 { 1412 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 1413 ("(raise_fault_action_rtn) call_rep->%p alert pending flag is set in header\n", call_rep)); 1414 } 1415 else 1416 { 1417 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 1418 ("(raise_fault_action_rtn) call_rep->%p number alerts forwarded (%d) > alert count in header (%d)\n", 1419 call_rep, 1420 call_rep->u.client.cancel.server_count, 1421 RPC_CN_PKT_ALERT_COUNT (header_p))); 1422 } 1423#endif 1424 } 1425 } 1426 1427 /* 1428 * We are currently executing in the receiver thread. 1429 * 1430 * If there is stub data, queue it on the association so that 1431 * the client call thread can get it. 1432 * If there is no stub data (e.g., no out arguments), just 1433 * deallocate the fragment buffer. 1434 * We make an exception for the first fragment; it is always 1435 * queued since the client call thread may already be blocked 1436 * on the condition variable. 1437 */ 1438 if (fragbuf->data_size || 1439 (RPC_CN_PKT_FLAGS (header_p) & RPC_C_CN_FLAGS_FIRST_FRAG)) 1440 { 1441 rpc__cn_assoc_queue_frag (call_rep->assoc, fragbuf, true); 1442 } 1443 else 1444 { 1445 (* fragbuf->fragbuf_dealloc) (fragbuf); 1446 } 1447 1448 /* 1449 * There is no predicate associated with this routine but the 1450 * new value of sm->cur_state is determined by the value of 1451 * sm->cur_event coming into the routine. Note that 1452 * 2+statebase is event fault_dns; 3+statebase is event 1453 * fault. 1454 */ 1455 if (sm_p->cur_event == (2 + RPC_C_CN_STATEBASE )) 1456 sm_p->cur_state = RPC_C_CLIENT_CALL_CFDNE; 1457 else if (sm_p->cur_event == (3 + RPC_C_CN_STATEBASE )) 1458 sm_p->cur_state = RPC_C_CLIENT_CALL_CALL_FAILED; 1459 return (rpc_s_ok); 1460} 1461 1462 1463/* 1464**++ 1465** 1466** ROUTINE NAME: forward_alert_action_rtn 1467** 1468** SCOPE: INTERNAL 1469** 1470** DESCRIPTION: 1471** 1472** Action routine to forward an alert. The first alert that is 1473** forwarded will start the alert timer. This timer will run until 1474** either the call is completed or a reponse is received from the 1475** server. If the timer expires the call is orphaned. The alert 1476** timer setting, clearing and expiration handling is all done outside 1477** the state machine action routines, primarily in the 1478** rpc__cn_call_forward_cancel, rpc__cn_call_[start,stop]_cancel_timer 1479** and rpc__cn_call_cancel_timer. All cancellable operations made in 1480** the CN runtime are encompassed in cancel exception handlers. 1481** 1482** INPUTS: 1483** 1484** spc_struct The call rep. Note that this is passed in as 1485** the special structure which is passed to the 1486** state machine event evaluation routine. 1487** 1488** event_param The error_status to return. This is passed in 1489** as the special event related parameter which 1490** was passed to the state machine event 1491** evaluation routine. 1492** 1493** INPUTS/OUTPUTS: 1494** 1495** sm The control block from the event evaluation 1496** routine. Input is the current state and 1497** event for the control block. Output is the 1498** next state or updated current state, for the 1499** control block. 1500** 1501** OUTPUTS: none 1502** 1503** IMPLICIT INPUTS: none 1504** 1505** IMPLICIT OUTPUTS: none 1506** 1507** FUNCTION VALUE: rpc_s_call_faulted 1508** 1509** SIDE EFFECTS: none 1510** 1511**-- 1512**/ 1513INTERNAL unsigned32 forward_alert_action_rtn 1514( 1515 dce_pointer_t spc_struct, 1516 dce_pointer_t event_param ATTRIBUTE_UNUSED, 1517 dce_pointer_t sm 1518) 1519{ 1520 rpc_cn_call_rep_p_t call_rep; 1521 rpc_cn_packet_p_t header_p; 1522 struct 1523 { 1524 rpc_iovector_t iov; 1525 rpc_iovector_elt_t elt_1; 1526 } pdu; 1527 unsigned32 status; 1528 unsigned8 prev_ptype; 1529 rpc_cn_sm_ctlblk_t *sm_p; 1530 1531 RPC_CN_DBG_RTN_PRINTF(CLIENT forward_alert_action_rtn); 1532 1533 call_rep = (rpc_cn_call_rep_p_t) spc_struct; 1534 sm_p = (rpc_cn_sm_ctlblk_t *)sm; 1535 header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR (call_rep); 1536 1537 /* 1538 * The remote alert indication packet uses only the 1539 * common fields of the header. We can therefore just 1540 * use the current header. 1541 */ 1542 prev_ptype = RPC_CN_PKT_PTYPE (header_p); 1543 RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_REMOTE_ALERT; 1544 RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_ALERT_PENDING; 1545 1546 /* 1547 * If security was requested on this call an authentication 1548 * trailer will have to be added to the alert PDU. 1549 */ 1550 if (call_rep->sec == NULL) 1551 { 1552 RPC_CN_PKT_FRAG_LEN (header_p) = RPC_CN_PKT_SIZEOF_ALERT_HDR; 1553 pdu.iov.num_elt = 1; 1554 } 1555 else 1556 { 1557 RPC_CN_PKT_FRAG_LEN (header_p) = 1558 RPC_CN_PKT_SIZEOF_ALERT_HDR + 1559 call_rep->prot_tlr->data_size - 1560 RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep); 1561 pdu.iov.num_elt = 2; 1562 pdu.elt_1.buff_dealloc = NULL; 1563 pdu.elt_1.data_addr = (byte_p_t) call_rep->prot_tlr->data_p; 1564 pdu.elt_1.data_len = 1565 call_rep->prot_tlr->data_size - 1566 RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep); 1567 } 1568 1569 /* 1570 * Send the packet over. 1571 */ 1572 pdu.iov.elt[0].buff_dealloc = NULL; 1573 pdu.iov.elt[0].data_addr = (byte_p_t) header_p; 1574 pdu.iov.elt[0].data_len = RPC_CN_PKT_SIZEOF_ALERT_HDR; 1575 rpc__cn_assoc_send_frag (call_rep->assoc, &pdu.iov, call_rep->sec, &status); 1576 1577 /* 1578 * Restore the previous packet type. 1579 */ 1580 RPC_CN_PKT_PTYPE (header_p) = prev_ptype; 1581 1582 /* 1583 * Increment the count of forwarded cancels. 1584 */ 1585 call_rep->u.client.cancel.server_count++; 1586 RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL, 1587 ("(forward_alert_action_rtn) call_rep->%p forwarding cancel total so far = %d\n", 1588 call_rep, 1589 call_rep->u.client.cancel.server_count)); 1590 1591 /* 1592 * There is no predicate associated with this routine but the 1593 * new value of sm->cur_state is determined by the value of 1594 * sm->cur_state coming into the routine. In otherwords, 1595 * this action routine is called from 2 different states 1596 * and the value of that state determines the new value 1597 * for sm->cur_state. Note that 3+statebase is call_request; 1598 * 4+statebase is call_response. rpc_c_cn_statebase is 1599 * set to 100 to distinguish it from action routine 1600 * indexes used in the rpc__cn_sm_event_eval() routine. 1601 */ 1602 if (sm_p->cur_state == (3 + RPC_C_CN_STATEBASE)) 1603 sm_p->cur_state = RPC_C_CLIENT_CALL_REQUEST; 1604 else if (sm_p->cur_state == (4 + RPC_C_CN_STATEBASE)) 1605 sm_p->cur_state = RPC_C_CLIENT_CALL_RESPONSE; 1606 return (status); 1607} 1608 1609 1610/* 1611**++ 1612** 1613** ROUTINE NAME: abort_send_action_rtn 1614** 1615** SCOPE: INTERNAL 1616** 1617** DESCRIPTION: 1618** 1619** Action routine to abort a send. 1620** It sends an orphaned message, and then raises a fault by 1621** returning the error status back to the caller. 1622** 1623** INPUTS: 1624** 1625** spc_struct The call rep. Note that this is passed in as 1626** the special structure which is passed to the 1627** state machine event evaluation routine. 1628** 1629** event_param This parameter is ignored. It is passed in 1630** as the special event related parameter which 1631** was passed to the state machine event 1632** evaluation routine. 1633** 1634** INPUTS/OUTPUTS: 1635** 1636** sm The control block from the event evaluation 1637** routine. Input is the current state and 1638** event for the control block. Output is the 1639** next state or updated current state, for the 1640** control block. 1641** 1642** OUTPUTS: rpc_s_call_faulted 1643** 1644** IMPLICIT INPUTS: none 1645** 1646** IMPLICIT OUTPUTS: none 1647** 1648** FUNCTION VALUE: error_status reflecting the fault 1649** 1650** SIDE EFFECTS: none 1651** 1652**-- 1653**/ 1654INTERNAL unsigned32 abort_send_action_rtn 1655( 1656 dce_pointer_t spc_struct, 1657 dce_pointer_t event_param ATTRIBUTE_UNUSED, 1658 dce_pointer_t sm 1659) 1660{ 1661 rpc_cn_call_rep_p_t call_rep; 1662 rpc_cn_packet_p_t header_p; 1663 unsigned32 status; 1664 rpc_cn_sm_ctlblk_t *sm_p; 1665 1666 RPC_CN_DBG_RTN_PRINTF(CLIENT abort_send_action_rtn); 1667 1668 call_rep = (rpc_cn_call_rep_p_t) spc_struct; 1669 sm_p = (rpc_cn_sm_ctlblk_t *)sm; 1670 1671 /* 1672 * The call is going to be orphaned. The stub data bufferred 1673 * on the call rep will not be sent and can be released. 1674 */ 1675 rpc__cn_dealloc_buffered_data (call_rep); 1676 RPC_CN_FREE_ALL_EXCEPT_PROT_HDR (call_rep); 1677 1678 /* 1679 * Now prepare to send an orphaned packet to the server. 1680 */ 1681 header_p = (rpc_cn_packet_p_t) RPC_CN_CREP_SEND_HDR(call_rep); 1682 RPC_CN_PKT_PTYPE (header_p) = RPC_C_CN_PKT_ORPHANED; 1683 RPC_CN_PKT_FLAGS (header_p) |= RPC_C_CN_FLAGS_LAST_FRAG; 1684 RPC_DBG_PRINTF (rpc_e_dbg_orphan, RPC_C_CN_DBG_ORPHAN, 1685 ("(abort_send_action_rtn) call_rep->%p sending orphan packet ... call id = %x\n", 1686 call_rep, 1687 RPC_CN_PKT_CALL_ID (header_p))); 1688 1689 /* 1690 * If security was requested on this call an authentication 1691 * trailer will have to be added to the orphan PDU. 1692 */ 1693 if (call_rep->sec == NULL) 1694 { 1695 RPC_CN_PKT_FRAG_LEN (header_p) = RPC_CN_PKT_SIZEOF_ORPHANED_HDR; 1696 RPC_CN_CREP_IOVLEN (call_rep) = 1; 1697 } 1698 else 1699 { 1700 RPC_CN_PKT_FRAG_LEN (header_p) = 1701 RPC_CN_PKT_SIZEOF_ORPHANED_HDR + 1702 call_rep->prot_tlr->data_size - 1703 RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep); 1704 RPC_CN_CREP_IOVLEN (call_rep) = 2; 1705 RPC_CN_CREP_IOV (call_rep)[1].data_addr = (byte_p_t) call_rep->prot_tlr->data_p; 1706 RPC_CN_CREP_IOV (call_rep)[1].data_len = 1707 call_rep->prot_tlr->data_size - 1708 RPC_CN_CREP_SIZEOF_TLR_PAD (call_rep); 1709 RPC_CN_CREP_IOV (call_rep)[1].buff_dealloc = NULL; 1710 } 1711 1712 /* 1713 * Send the packet over. Note that the returned status is 1714 * ignored. 1715 */ 1716 RPC_CN_CREP_IOV (call_rep)[0].data_addr = (byte_p_t) header_p; 1717 RPC_CN_CREP_IOV (call_rep)[0].data_len = RPC_CN_PKT_SIZEOF_ORPHANED_HDR; 1718 rpc__cn_assoc_send_frag (call_rep->assoc, 1719 &(call_rep->buffered_output.iov), 1720 call_rep->sec, 1721 &status); 1722 /* 1723 * Now return to the caller (presumably rpc__cn_call_end) which 1724 * will deallocate the association on our end and clean up. 1725 */ 1726 sm_p->cur_state = RPC_C_CLIENT_CALL_CALL_FAILED; 1727 return (rpc_s_ok); 1728} 1729 1730/* 1731**++ 1732** 1733** ROUTINE NAME: abort_recv_action_rtn 1734** 1735** SCOPE: INTERNAL 1736** 1737** DESCRIPTION: 1738** 1739** Action routine to abort a receive. 1740** 1741** INPUTS: 1742** 1743** spc_struct The call rep. Note that this is passed in as 1744** the special structure which is passed to the 1745** state machine event evaluation routine. 1746** 1747** event_param The fault data. 1748** This is passed in as the special event related 1749** parameter which was passed to the state machine 1750** event evaluation routine. 1751** 1752** INPUTS/OUTPUTS: 1753** 1754** sm The control block from the event evaluation 1755** routine. Input is the current state and 1756** event for the control block. Output is the 1757** next state or updated current state, for the 1758** control block. 1759** 1760** OUTPUTS: none 1761** 1762** IMPLICIT INPUTS: none 1763** 1764** IMPLICIT OUTPUTS: none 1765** 1766** FUNCTION VALUE: completion status 1767** rpc_s_call_faulted 1768** 1769** SIDE EFFECTS: none 1770** 1771**-- 1772**/ 1773INTERNAL unsigned32 abort_recv_action_rtn 1774( 1775 dce_pointer_t spc_struct, 1776 dce_pointer_t event_param, 1777 dce_pointer_t sm 1778) 1779{ 1780 unsigned32 status; 1781 1782 RPC_CN_DBG_RTN_PRINTF(CLIENT abort_recv_action_rtn); 1783 /* 1784 * Note that we are getting state from raise_fault_action_rtn(). Also 1785 * note that it does not seem that we are actually using abort_recv_ 1786 * action_rtn in the state tables. 1787 * 1788 * Note, we don't need to chase down our receiver thread. 1789 * We will shortly deallocate the association. The receiver 1790 * thread will automatically discard fragments for non-existent 1791 * associations. 1792 * 1793 * We make this a separate action routine (instead of using 1794 * raise_fault_action_rtn) to leave room for future optimizations. 1795 */ 1796 1797 /* 1798 * Abort the association. 1799 */ 1800 rpc__cn_assoc_abort (((rpc_cn_call_rep_p_t) spc_struct)->assoc, &status); 1801 1802 /* 1803 * Raise the fault. 1804 */ 1805 return (raise_fault_action_rtn (spc_struct, event_param, sm )); 1806} 1807