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** dgclive.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** Routines for maintaining liveness of clients. 90** 91** 92*/ 93 94#include <dg.h> 95#include <dgglob.h> 96 97#include <dce/conv.h> 98#include <dce/convc.h> 99 100/* =============================================================================== */ 101 102/* 103 * Define a linked list element which the client runtime can use to keep 104 * track of which servers it needs to maintain liveness with. 105 * 106 * Here's the list elements... 107 */ 108typedef struct maint_elt_t 109{ 110 struct maint_elt_t *next; /* -> to next entry in list. */ 111 rpc_binding_rep_p_t shand; /* -> to server binding handle */ 112 unsigned8 refcnt; /* -> # of entries for this server */ 113} maint_elt_t, *maint_elt_p_t; 114 115/* 116 * And here's the head of the list... 117 */ 118INTERNAL maint_elt_p_t maint_head; 119 120/* 121 * And here's the mutex that protects the list... 122 */ 123INTERNAL rpc_mutex_t rpc_g_maint_mutex; 124INTERNAL rpc_cond_t maintain_cond; 125 126INTERNAL boolean maintain_thread_running = false; 127INTERNAL boolean maintain_thread_was_running = false; 128INTERNAL boolean stop_maintain_thread = false; 129 130INTERNAL dcethread* maintain_task; 131 132/* 133 * Mutex lock macros 134 */ 135 136#define RPC_MAINT_LOCK_INIT() RPC_MUTEX_INIT (rpc_g_maint_mutex) 137#define RPC_MAINT_LOCK() RPC_MUTEX_LOCK (rpc_g_maint_mutex) 138#define RPC_MAINT_UNLOCK() RPC_MUTEX_UNLOCK (rpc_g_maint_mutex) 139 140/* ========================================================================= */ 141 142INTERNAL void * network_maintain_liveness (void*); 143 144/* ========================================================================= */ 145 146/* 147 * R P C _ _ D G _ N E T W O R K _ M A I N T 148 * 149 * This function is called, via the network listener service, by a client 150 * stub which needs to maintain context with a server. A copy of the 151 * binding handle is made and entered into a list associated with a timer 152 * monitor. This monitor will then periodically send an identifier to 153 * the server to assure it that this client is still alive. 154 */ 155 156PRIVATE void rpc__dg_network_maint 157( 158 rpc_binding_rep_p_t binding_r, 159 unsigned32 *st 160) 161{ 162 maint_elt_p_t maint; 163 rpc_dg_binding_client_p_t chand = (rpc_dg_binding_client_p_t) binding_r; 164 165 *st = rpc_s_ok; 166 167 RPC_MAINT_LOCK(); 168 169 /* 170 * First, we need to traverse the list of maintained contexts to see 171 * if this server is already on it. If we find a matching address, 172 * we can just return. 173 */ 174 175 for (maint = maint_head; maint != NULL; maint = maint->next) 176 { 177 if (rpc__naf_addr_compare(maint->shand->rpc_addr, binding_r->rpc_addr, st)) 178 { 179 /* 180 * If we find a matching element, store a pointer to it in the 181 * client binding handle (so we don't have to do these compares 182 * when maint_stop gets called) and note the reference. 183 */ 184 185 chand->maint_binding = maint->shand; 186 maint->refcnt++; 187 RPC_MAINT_UNLOCK(); 188 return; 189 } 190 } 191 192 /* 193 * Need to make a new entry in the maintain list. Alloc up a 194 * list element. 195 */ 196 197 RPC_MEM_ALLOC(maint, maint_elt_p_t, sizeof *maint, 198 RPC_C_MEM_DG_MAINT, RPC_C_MEM_NOWAIT); 199 200 /* 201 * Make our own copy of the binding handle (so we have a handle to 202 * send INDY's to this server). Reference the new binding in the 203 * client handle and note the reference. 204 */ 205 206 rpc_binding_copy((rpc_binding_handle_t) chand, 207 (rpc_binding_handle_t *) &maint->shand, st); 208 chand->maint_binding = maint->shand; 209 maint->refcnt = 1; 210 211 /* 212 * and thread it onto the head of the list. 213 */ 214 215 maint->next = maint_head; 216 maint_head = maint; 217 218 /* 219 * If the binding handle had any authentication info associated with 220 * it, free it up now. We don't want the convc_indy() calls using 221 * authentication. 222 */ 223 rpc_binding_set_auth_info((rpc_binding_handle_t) maint->shand, NULL, 224 rpc_c_protect_level_none, rpc_c_authn_none, NULL, 225 rpc_c_authz_none, st); 226 227 /* 228 * Finally, check to make sure the 'context maintainer' thread has 229 * been started, and if not, start it up. 230 */ 231 232 if (! maintain_thread_running) 233 { 234 maintain_thread_running = true; 235 dcethread_create_throw(&maintain_task, NULL, 236 (void*)network_maintain_liveness, 237 NULL); 238 } 239 240 RPC_MAINT_UNLOCK(); 241} 242 243/* 244 * R P C _ _ D G _ N E T W O R K _ S T O P _ M A I N T 245 * 246 * This routine is called, via the network listener service, by a client stub 247 * when it wishes to discontinue maintaining context with a server. 248 */ 249 250PRIVATE void rpc__dg_network_stop_maint 251( 252 rpc_binding_rep_p_t binding_r, 253 unsigned32 *st 254) 255{ 256 maint_elt_p_t maint, prev = NULL; 257 rpc_dg_binding_client_p_t chand = (rpc_dg_binding_client_p_t) binding_r; 258 259 RPC_MAINT_LOCK(); 260 261 /* 262 * Search through the list for the element which references this 263 * binding handle. 264 */ 265 266 for (maint = maint_head; maint != NULL; maint = maint->next) 267 { 268 if (chand->maint_binding == maint->shand) 269 { 270 /* 271 * Remove the reference from the binding handle, and decrement 272 * the reference count in the list element. If the count 273 * falls to 0, remove the element from the list. 274 */ 275 276 chand->maint_binding = NULL; 277 if (--maint->refcnt == 0) 278 { 279 if (prev == NULL) 280 maint_head = maint->next; 281 else 282 prev->next = maint->next; 283 rpc_binding_free((rpc_binding_handle_t *)&maint->shand, st); 284 RPC_MEM_FREE(maint, RPC_C_MEM_DG_MAINT); 285 } 286 *st = rpc_s_ok; 287 RPC_MAINT_UNLOCK(); 288 return; 289 } 290 prev = maint; 291 } 292 293 RPC_MAINT_UNLOCK(); 294 *st = -1; /*!!! didn't find it, need real error value here */ 295} 296 297/* 298 * R P C _ _ D G _ N E T W O R K _ C L O S E 299 * 300 * This routine is called, via the network listener service, by a client stub 301 * when it wishes to disconnect frmo a server. 302 */ 303 304PRIVATE void rpc__dg_network_close 305( 306 ATTRIBUTE_UNUSED rpc_binding_rep_p_t binding_r, 307 unsigned32 *st 308) 309{ 310 /* this is a NOOP for datagram transports */ 311 *st = rpc_s_ok; 312} 313 314/* 315 * N E T W O R K _ M A I N T A I N _ L I V E N E S S 316 * 317 * Base routine for the thread which periodically sends out the address 318 * space UUID of this process. This UUID uniquely identifies this 319 * particular instance of this particular client process for use in 320 * maintaing context with servers. 321 */ 322 323INTERNAL void * network_maintain_liveness(void * unused ATTRIBUTE_UNUSED) 324{ 325 maint_elt_p_t ptr; 326 struct timespec next_ts; 327 328 RPC_DBG_PRINTF(rpc_e_dbg_conv_thread, 1, 329 ("(network_maintain_liveness) starting up...\n")); 330 331 RPC_MAINT_LOCK(); 332 333 while (stop_maintain_thread == false) 334 { 335 /* 336 * Send out INDYs every 20 seconds. 337 */ 338 rpc__clock_timespec(rpc__clock_stamp()+20, &next_ts); 339 340 RPC_COND_TIMED_WAIT(maintain_cond, rpc_g_maint_mutex, &next_ts); 341 if (stop_maintain_thread == true) 342 break; 343 344 for (ptr = maint_head; ptr != NULL; ptr = ptr->next) 345 { 346 RPC_DBG_PRINTF(rpc_e_dbg_general, 3, 347 ("(maintain_liveness_timer) Doing convc_indy call\n")); 348 349 (*convc_v1_0_c_epv.convc_indy)((handle_t) ptr->shand, 350 &rpc_g_dg_my_cas_uuid); 351 } 352 353 /* 354 * See if the list is empty... 355 */ 356 357 if (maint_head == NULL) 358 { 359 /* 360 * Nothing left to do, so terminate the thread. 361 */ 362 /* FIXME: MNE */ 363 DCETHREAD_TRY { 364 dcethread_detach_throw(maintain_task); 365 } 366 DCETHREAD_CATCH_ALL(THIS_CATCH) { 367 fprintf(stderr, "XXX MIREK: %s: %s: %d: caught exception from detach\n", 368 __FILE__, __PRETTY_FUNCTION__, __LINE__); 369 DCETHREAD_RERAISE; 370 } 371 DCETHREAD_ENDTRY; 372 maintain_thread_running = false; 373 break; 374 } 375 } 376 RPC_DBG_PRINTF(rpc_e_dbg_conv_thread, 1, 377 ("(network_maintain_liveness) shutting down%s...\n", 378 (maint_head == NULL)?" (no active)":"")); 379 380 RPC_MAINT_UNLOCK(); 381 return NULL; 382} 383 384/* 385 * R P C _ _ D G _ M A I N T A I N _ I N I T 386 * 387 * This routine performs any initializations required for the network 388 * listener service maintain/monitor functions. Note that way2 liveness 389 * callbacks are handled by the conversation manager interface; we do 390 * not need to register the interfaces because the runtime intercepts 391 * and handles way2 callbacks as part of listener thread request 392 * processing. 393 */ 394 395PRIVATE void rpc__dg_maintain_init(void) 396{ 397 unsigned32 st; 398 399 /* 400 * Gen the address space UUID that we will send to servers 401 * to indicate that we're still alive. 402 */ 403 404 uuid_create(&rpc_g_dg_my_cas_uuid, &st); 405 if (st != rpc_s_ok) 406 { 407 /* 408 * rpc_m_cant_create_uuid 409 * "(%s) Can't create UUID" 410 */ 411 rpc_dce_svc_printf ( 412 __FILE__, __LINE__, 413 "%s", 414 rpc_svc_general, 415 svc_c_sev_fatal | svc_c_action_exit_bad, 416 rpc_m_cant_create_uuid, 417 "rpc__dg_maintain_init" ); 418 } 419 420 /* 421 * Initialize a private mutex. 422 */ 423 424 RPC_MAINT_LOCK_INIT(); 425 RPC_COND_INIT(maintain_cond, rpc_g_maint_mutex); 426 427 maint_head = NULL; 428 maintain_thread_running = false; 429 maintain_thread_was_running = false; 430 stop_maintain_thread = false; 431} 432 433#ifdef ATFORK_SUPPORTED 434/* 435 * R P C _ _ D G _ M A I N T A I N _ F O R K _ H A N D L E R 436 * 437 * Handle fork related processing for this module. 438 */ 439 440PRIVATE void rpc__dg_maintain_fork_handler 441( 442 rpc_fork_stage_id_t stage 443) 444{ 445 unsigned32 st; 446 447 switch ((int)stage) 448 { 449 case RPC_C_PREFORK: 450 RPC_MAINT_LOCK(); 451 maintain_thread_was_running = false; 452 453 if (maintain_thread_running) 454 { 455 stop_maintain_thread = true; 456 RPC_COND_SIGNAL(maintain_cond, rpc_g_maint_mutex); 457 RPC_MAINT_UNLOCK(); 458 dcethread_join_throw (maintain_task, (void**) &st); 459 RPC_MAINT_LOCK();/* FIXME: wtf 460 DCETHREAD_TRY { 461 dcethread_detach_throw(maintain_task); 462 } 463 DCETHREAD_CATCH(dcethread_use_error_e) { 464 } 465 DCETHREAD_ENDTRY; */ 466 maintain_thread_running = false; 467 maintain_thread_was_running = true; 468 } 469 break; 470 case RPC_C_POSTFORK_PARENT: 471 if (maintain_thread_was_running) 472 { 473 maintain_thread_was_running = false; 474 maintain_thread_running = true; 475 stop_maintain_thread = false; 476 dcethread_create_throw(&maintain_task, NULL, 477 network_maintain_liveness, 478 NULL); 479 } 480 RPC_MAINT_UNLOCK(); 481 break; 482 case RPC_C_POSTFORK_CHILD: 483 maintain_thread_was_running = false; 484 maintain_thread_running = false; 485 stop_maintain_thread = false; 486 487 /* 488 * Clear out the list... we should free resources... 489 */ 490 maint_head = NULL; 491 492 RPC_MAINT_UNLOCK(); 493 break; 494 } 495} 496#endif /* ATFORK_SUPPORTED */ 497