1 /* $NetBSD: operation.c,v 1.3 2025/09/05 21:16:24 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2024 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 18 #include <sys/cdefs.h> 19 __RCSID("$NetBSD: operation.c,v 1.3 2025/09/05 21:16:24 christos Exp $"); 20 21 #include "portable.h" 22 23 #include "lutil.h" 24 #include "lload.h" 25 26 ldap_pvt_thread_mutex_t lload_pin_mutex; 27 unsigned long lload_next_pin = 1; 28 29 TAvlnode *lload_control_actions = NULL; 30 TAvlnode *lload_exop_actions = NULL; 31 enum op_restriction lload_default_exop_action = LLOAD_OP_NOT_RESTRICTED; 32 33 ber_tag_t 34 slap_req2res( ber_tag_t tag ) 35 { 36 switch ( tag ) { 37 case LDAP_REQ_ADD: 38 case LDAP_REQ_BIND: 39 case LDAP_REQ_COMPARE: 40 case LDAP_REQ_EXTENDED: 41 case LDAP_REQ_MODIFY: 42 case LDAP_REQ_MODRDN: 43 tag++; 44 break; 45 46 case LDAP_REQ_DELETE: 47 tag = LDAP_RES_DELETE; 48 break; 49 50 case LDAP_REQ_ABANDON: 51 case LDAP_REQ_UNBIND: 52 tag = LBER_SEQUENCE; 53 break; 54 55 case LDAP_REQ_SEARCH: 56 tag = LDAP_RES_SEARCH_RESULT; 57 break; 58 59 default: 60 tag = LBER_SEQUENCE; 61 } 62 63 return tag; 64 } 65 66 const char * 67 lload_msgtype2str( ber_tag_t tag ) 68 { 69 switch ( tag ) { 70 case LDAP_REQ_ABANDON: return "abandon request"; 71 case LDAP_REQ_ADD: return "add request"; 72 case LDAP_REQ_BIND: return "bind request"; 73 case LDAP_REQ_COMPARE: return "compare request"; 74 case LDAP_REQ_DELETE: return "delete request"; 75 case LDAP_REQ_EXTENDED: return "extended request"; 76 case LDAP_REQ_MODIFY: return "modify request"; 77 case LDAP_REQ_RENAME: return "rename request"; 78 case LDAP_REQ_SEARCH: return "search request"; 79 case LDAP_REQ_UNBIND: return "unbind request"; 80 81 case LDAP_RES_ADD: return "add result"; 82 case LDAP_RES_BIND: return "bind result"; 83 case LDAP_RES_COMPARE: return "compare result"; 84 case LDAP_RES_DELETE: return "delete result"; 85 case LDAP_RES_EXTENDED: return "extended result"; 86 case LDAP_RES_INTERMEDIATE: return "intermediate response"; 87 case LDAP_RES_MODIFY: return "modify result"; 88 case LDAP_RES_RENAME: return "rename result"; 89 case LDAP_RES_SEARCH_ENTRY: return "search-entry response"; 90 case LDAP_RES_SEARCH_REFERENCE: return "search-reference response"; 91 case LDAP_RES_SEARCH_RESULT: return "search result"; 92 } 93 return "unknown message"; 94 } 95 96 int 97 lload_restriction_cmp( const void *left, const void *right ) 98 { 99 const struct restriction_entry *l = left, *r = right; 100 return ber_bvcmp( &l->oid, &r->oid ); 101 } 102 103 int 104 operation_client_cmp( const void *left, const void *right ) 105 { 106 const LloadOperation *l = left, *r = right; 107 108 assert( l->o_client_connid == r->o_client_connid ); 109 if ( l->o_client_msgid || r->o_client_msgid ) { 110 return ( l->o_client_msgid < r->o_client_msgid ) ? 111 -1 : 112 ( l->o_client_msgid > r->o_client_msgid ); 113 } else { 114 return ( l->o_pin_id < r->o_pin_id ) ? -1 : 115 ( l->o_pin_id > r->o_pin_id ); 116 } 117 } 118 119 int 120 operation_upstream_cmp( const void *left, const void *right ) 121 { 122 const LloadOperation *l = left, *r = right; 123 124 assert( l->o_upstream_connid == r->o_upstream_connid ); 125 if ( l->o_upstream_msgid || r->o_upstream_msgid ) { 126 return ( l->o_upstream_msgid < r->o_upstream_msgid ) ? 127 -1 : 128 ( l->o_upstream_msgid > r->o_upstream_msgid ); 129 } else { 130 return ( l->o_pin_id < r->o_pin_id ) ? -1 : 131 ( l->o_pin_id > r->o_pin_id ); 132 } 133 } 134 135 /* 136 * Entered holding c_mutex for now. 137 */ 138 LloadOperation * 139 operation_init( LloadConnection *c, BerElement *ber ) 140 { 141 LloadOperation *op; 142 ber_tag_t tag; 143 ber_len_t len; 144 int rc; 145 146 if ( !IS_ALIVE( c, c_live ) ) { 147 return NULL; 148 } 149 150 op = ch_calloc( 1, sizeof(LloadOperation) ); 151 op->o_client = c; 152 op->o_client_connid = c->c_connid; 153 op->o_ber = ber; 154 gettimeofday( &op->o_start, NULL ); 155 156 ldap_pvt_thread_mutex_init( &op->o_link_mutex ); 157 158 op->o_refcnt = 1; 159 160 tag = ber_get_int( ber, &op->o_client_msgid ); 161 if ( tag != LDAP_TAG_MSGID ) { 162 goto fail; 163 } 164 165 if ( !op->o_client_msgid ) { 166 goto fail; 167 } 168 169 CONNECTION_ASSERT_LOCKED(c); 170 rc = ldap_tavl_insert( &c->c_ops, op, operation_client_cmp, ldap_avl_dup_error ); 171 if ( rc ) { 172 Debug( LDAP_DEBUG_PACKETS, "operation_init: " 173 "several operations with same msgid=%d in-flight " 174 "from client connid=%lu\n", 175 op->o_client_msgid, op->o_client_connid ); 176 goto fail; 177 } 178 179 tag = op->o_tag = ber_skip_element( ber, &op->o_request ); 180 switch ( tag ) { 181 case LBER_ERROR: 182 rc = -1; 183 break; 184 } 185 if ( rc ) { 186 ldap_tavl_delete( &c->c_ops, op, operation_client_cmp ); 187 goto fail; 188 } 189 190 tag = ber_peek_tag( ber, &len ); 191 if ( tag == LDAP_TAG_CONTROLS ) { 192 ber_skip_element( ber, &op->o_ctrls ); 193 } 194 195 switch ( op->o_tag ) { 196 case LDAP_REQ_BIND: 197 lload_stats.counters[LLOAD_STATS_OPS_BIND].lc_ops_received++; 198 break; 199 default: 200 lload_stats.counters[LLOAD_STATS_OPS_OTHER].lc_ops_received++; 201 break; 202 } 203 204 Debug( LDAP_DEBUG_STATS, "operation_init: " 205 "received a new operation, %s with msgid=%d for client " 206 "connid=%lu\n", 207 lload_msgtype2str( op->o_tag ), op->o_client_msgid, 208 op->o_client_connid ); 209 210 c->c_n_ops_executing++; 211 return op; 212 213 fail: 214 ch_free( op ); 215 return NULL; 216 } 217 218 void 219 operation_destroy( LloadOperation *op ) 220 { 221 Debug( LDAP_DEBUG_TRACE, "operation_destroy: " 222 "op=%p destroyed operation from client connid=%lu, " 223 "client msgid=%d\n", 224 op, op->o_client_connid, op->o_client_msgid ); 225 226 assert( op->o_refcnt == 0 ); 227 assert( op->o_client == NULL ); 228 assert( op->o_upstream == NULL ); 229 230 ber_free( op->o_ber, 1 ); 231 ldap_pvt_thread_mutex_destroy( &op->o_link_mutex ); 232 ch_free( op ); 233 } 234 235 int 236 operation_unlink( LloadOperation *op ) 237 { 238 LloadConnection *client, *upstream; 239 uintptr_t prev_refcnt; 240 int result = 0; 241 242 assert( op->o_refcnt == 0 ); 243 244 Debug( LDAP_DEBUG_TRACE, "operation_unlink: " 245 "unlinking operation between client connid=%lu and upstream " 246 "connid=%lu " 247 "client msgid=%d\n", 248 op->o_client_connid, op->o_upstream_connid, op->o_client_msgid ); 249 250 checked_lock( &op->o_link_mutex ); 251 client = op->o_client; 252 upstream = op->o_upstream; 253 254 op->o_client = NULL; 255 op->o_upstream = NULL; 256 checked_unlock( &op->o_link_mutex ); 257 258 assert( client || upstream ); 259 260 if ( client ) { 261 result |= operation_unlink_client( op, client ); 262 operation_update_global_rejected( op ); 263 } 264 265 if ( upstream ) { 266 result |= operation_unlink_upstream( op, upstream ); 267 } 268 269 return result; 270 } 271 272 int 273 operation_unlink_client( LloadOperation *op, LloadConnection *client ) 274 { 275 LloadOperation *removed; 276 int result = 0; 277 278 Debug( LDAP_DEBUG_TRACE, "operation_unlink_client: " 279 "unlinking operation op=%p msgid=%d client connid=%lu\n", 280 op, op->o_client_msgid, op->o_client_connid ); 281 282 CONNECTION_LOCK(client); 283 if ( (removed = ldap_tavl_delete( 284 &client->c_ops, op, operation_client_cmp )) ) { 285 result = LLOAD_OP_DETACHING_CLIENT; 286 287 assert( op == removed ); 288 client->c_n_ops_executing--; 289 290 if ( op->o_restricted == LLOAD_OP_RESTRICTED_WRITE ) { 291 if ( !--client->c_restricted_inflight && 292 client->c_restricted_at >= 0 ) { 293 if ( lload_write_coherence < 0 ) { 294 client->c_restricted_at = -1; 295 } else if ( timerisset( &op->o_last_response ) ) { 296 client->c_restricted_at = op->o_last_response.tv_sec; 297 } else { 298 /* We have to default to o_start just in case we abandoned an 299 * operation that the backend actually processed */ 300 client->c_restricted_at = op->o_start.tv_sec; 301 } 302 } 303 } 304 305 if ( op->o_tag == LDAP_REQ_BIND && 306 client->c_state == LLOAD_C_BINDING ) { 307 client->c_state = LLOAD_C_READY; 308 if ( !BER_BVISNULL( &client->c_auth ) ) { 309 ber_memfree( client->c_auth.bv_val ); 310 BER_BVZERO( &client->c_auth ); 311 } 312 if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) { 313 ber_memfree( client->c_sasl_bind_mech.bv_val ); 314 BER_BVZERO( &client->c_sasl_bind_mech ); 315 } 316 if ( op->o_pin_id ) { 317 client->c_pin_id = 0; 318 } 319 } 320 } 321 if ( client->c_state == LLOAD_C_CLOSING && !client->c_ops ) { 322 CONNECTION_DESTROY(client); 323 } else { 324 CONNECTION_UNLOCK(client); 325 } 326 327 return result; 328 } 329 330 int 331 operation_unlink_upstream( LloadOperation *op, LloadConnection *upstream ) 332 { 333 LloadOperation *removed; 334 LloadBackend *b = NULL; 335 int result = 0; 336 337 Debug( LDAP_DEBUG_TRACE, "operation_unlink_upstream: " 338 "unlinking operation op=%p msgid=%d upstream connid=%lu\n", 339 op, op->o_upstream_msgid, op->o_upstream_connid ); 340 341 CONNECTION_LOCK(upstream); 342 if ( (removed = ldap_tavl_delete( 343 &upstream->c_ops, op, operation_upstream_cmp )) ) { 344 result |= LLOAD_OP_DETACHING_UPSTREAM; 345 346 assert( op == removed ); 347 upstream->c_n_ops_executing--; 348 349 if ( upstream->c_state == LLOAD_C_BINDING ) { 350 assert( op->o_tag == LDAP_REQ_BIND && upstream->c_ops == NULL ); 351 upstream->c_state = LLOAD_C_READY; 352 if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) { 353 ber_memfree( upstream->c_sasl_bind_mech.bv_val ); 354 BER_BVZERO( &upstream->c_sasl_bind_mech ); 355 } 356 } 357 operation_update_conn_counters( op, upstream ); 358 b = upstream->c_backend; 359 } 360 if ( upstream->c_state == LLOAD_C_CLOSING && !upstream->c_ops ) { 361 CONNECTION_DESTROY(upstream); 362 } else { 363 CONNECTION_UNLOCK(upstream); 364 } 365 366 if ( b ) { 367 checked_lock( &b->b_mutex ); 368 b->b_n_ops_executing--; 369 operation_update_backend_counters( op, b ); 370 checked_unlock( &b->b_mutex ); 371 } 372 373 return result; 374 } 375 376 int 377 operation_send_abandon( LloadOperation *op, LloadConnection *upstream ) 378 { 379 BerElement *ber; 380 int rc = -1; 381 382 if ( !IS_ALIVE( upstream, c_live ) ) { 383 return rc; 384 } 385 386 checked_lock( &upstream->c_io_mutex ); 387 ber = upstream->c_pendingber; 388 if ( ber == NULL && (ber = ber_alloc()) == NULL ) { 389 Debug( LDAP_DEBUG_ANY, "operation_send_abandon: " 390 "ber_alloc failed\n" ); 391 goto done; 392 } 393 upstream->c_pendingber = ber; 394 395 Debug( LDAP_DEBUG_TRACE, "operation_send_abandon: " 396 "abandoning %s msgid=%d on connid=%lu\n", 397 lload_msgtype2str( op->o_tag ), op->o_upstream_msgid, 398 op->o_upstream_connid ); 399 400 if ( op->o_tag == LDAP_REQ_BIND ) { 401 rc = ber_printf( ber, "t{tit{ist{s}}}", LDAP_TAG_MESSAGE, 402 LDAP_TAG_MSGID, upstream->c_next_msgid++, 403 LDAP_REQ_BIND, LDAP_VERSION3, "", LDAP_AUTH_SASL, "" ); 404 } else { 405 rc = ber_printf( ber, "t{titi}", LDAP_TAG_MESSAGE, 406 LDAP_TAG_MSGID, upstream->c_next_msgid++, 407 LDAP_REQ_ABANDON, op->o_upstream_msgid ); 408 } 409 410 if ( rc < 0 ) { 411 ber_free( ber, 1 ); 412 upstream->c_pendingber = NULL; 413 goto done; 414 } 415 rc = LDAP_SUCCESS; 416 417 done: 418 checked_unlock( &upstream->c_io_mutex ); 419 return rc; 420 } 421 422 /* 423 * Will remove the operation from its upstream and if it was still there, 424 * sends an abandon request. 425 * 426 * Being called from client_reset or request_abandon, the following hold: 427 * - noone else is processing the read part of the client connection (no new 428 * operations come in there - relevant for the c_state checks) 429 * - op->o_client_refcnt > op->o_client_live (and it follows that op->o_client != NULL) 430 */ 431 void 432 operation_abandon( LloadOperation *op ) 433 { 434 LloadConnection *c; 435 436 checked_lock( &op->o_link_mutex ); 437 c = op->o_upstream; 438 checked_unlock( &op->o_link_mutex ); 439 if ( !c || !IS_ALIVE( c, c_live ) ) { 440 goto done; 441 } 442 443 /* for now consider all abandoned operations completed, 444 * perhaps add a separate counter later */ 445 op->o_res = LLOAD_OP_COMPLETED; 446 if ( !operation_unlink_upstream( op, c ) ) { 447 /* The operation has already been abandoned or finished */ 448 Debug( LDAP_DEBUG_TRACE, "operation_abandon: " 449 "%s from connid=%lu msgid=%d not present in connid=%lu any " 450 "more\n", 451 lload_msgtype2str( op->o_tag ), op->o_client_connid, 452 op->o_client_msgid, op->o_upstream_connid ); 453 goto done; 454 } 455 456 if ( operation_send_abandon( op, c ) == LDAP_SUCCESS ) { 457 connection_write_cb( -1, 0, c ); 458 } 459 460 done: 461 OPERATION_UNLINK(op); 462 } 463 464 void 465 operation_send_reject( 466 LloadOperation *op, 467 int result, 468 const char *msg, 469 int send_anyway ) 470 { 471 LloadConnection *c; 472 BerElement *ber; 473 int found; 474 475 Debug( LDAP_DEBUG_TRACE, "operation_send_reject: " 476 "rejecting %s from client connid=%lu with message: \"%s\"\n", 477 lload_msgtype2str( op->o_tag ), op->o_client_connid, msg ); 478 479 checked_lock( &op->o_link_mutex ); 480 c = op->o_client; 481 checked_unlock( &op->o_link_mutex ); 482 if ( !c || !IS_ALIVE( c, c_live ) ) { 483 Debug( LDAP_DEBUG_TRACE, "operation_send_reject: " 484 "not sending msgid=%d, client connid=%lu is dead\n", 485 op->o_client_msgid, op->o_client_connid ); 486 487 goto done; 488 } 489 490 found = operation_unlink_client( op, c ); 491 if ( !found && !send_anyway ) { 492 Debug( LDAP_DEBUG_TRACE, "operation_send_reject: " 493 "msgid=%d not scheduled for client connid=%lu anymore, " 494 "not sending\n", 495 op->o_client_msgid, c->c_connid ); 496 goto done; 497 } 498 499 if ( op->o_client_msgid == 0 ) { 500 assert( op->o_saved_msgid == 0 && op->o_pin_id ); 501 Debug( LDAP_DEBUG_TRACE, "operation_send_reject: " 502 "operation pin=%lu is just a pin, not sending\n", 503 op->o_pin_id ); 504 goto done; 505 } 506 507 checked_lock( &c->c_io_mutex ); 508 ber = c->c_pendingber; 509 if ( ber == NULL && (ber = ber_alloc()) == NULL ) { 510 checked_unlock( &c->c_io_mutex ); 511 Debug( LDAP_DEBUG_ANY, "operation_send_reject: " 512 "ber_alloc failed, closing connid=%lu\n", 513 c->c_connid ); 514 CONNECTION_LOCK_DESTROY(c); 515 goto done; 516 } 517 c->c_pendingber = ber; 518 519 ber_printf( ber, "t{tit{ess}}", LDAP_TAG_MESSAGE, 520 LDAP_TAG_MSGID, op->o_client_msgid, 521 slap_req2res( op->o_tag ), result, "", msg ); 522 523 checked_unlock( &c->c_io_mutex ); 524 525 connection_write_cb( -1, 0, c ); 526 527 done: 528 OPERATION_UNLINK(op); 529 } 530 531 /* 532 * Upstream is shutting down, signal the client if necessary, but we have to 533 * call operation_destroy_from_upstream ourselves to detach upstream from the 534 * op. 535 * 536 * Only called from upstream_destroy. 537 */ 538 void 539 operation_lost_upstream( LloadOperation *op ) 540 { 541 operation_send_reject( op, LDAP_OTHER, 542 "connection to the remote server has been severed", 0 ); 543 } 544 545 int 546 connection_timeout( LloadConnection *upstream, void *arg ) 547 { 548 LloadOperation *op; 549 TAvlnode *ops = NULL, *node, *next; 550 LloadBackend *b = upstream->c_backend; 551 struct timeval *threshold = arg; 552 int rc, nops = 0; 553 554 CONNECTION_LOCK(upstream); 555 for ( node = ldap_tavl_end( upstream->c_ops, TAVL_DIR_LEFT ); 556 node && timercmp( &((LloadOperation *)node->avl_data)->o_start, 557 threshold, < ); /* shortcut */ 558 node = next ) { 559 LloadOperation *found_op; 560 561 next = ldap_tavl_next( node, TAVL_DIR_RIGHT ); 562 op = node->avl_data; 563 564 /* Have we received another response since? */ 565 if ( timerisset( &op->o_last_response ) && 566 !timercmp( &op->o_last_response, threshold, < ) ) { 567 continue; 568 } 569 570 op->o_res = LLOAD_OP_FAILED; 571 found_op = ldap_tavl_delete( &upstream->c_ops, op, operation_upstream_cmp ); 572 assert( op == found_op ); 573 574 if ( upstream->c_state == LLOAD_C_BINDING ) { 575 assert( op->o_tag == LDAP_REQ_BIND && upstream->c_ops == NULL ); 576 upstream->c_state = LLOAD_C_READY; 577 if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) { 578 ber_memfree( upstream->c_sasl_bind_mech.bv_val ); 579 BER_BVZERO( &upstream->c_sasl_bind_mech ); 580 } 581 } 582 583 rc = ldap_tavl_insert( &ops, op, operation_upstream_cmp, ldap_avl_dup_error ); 584 assert( rc == LDAP_SUCCESS ); 585 586 Debug( LDAP_DEBUG_STATS2, "connection_timeout: " 587 "timing out %s from connid=%lu msgid=%d sent to connid=%lu as " 588 "msgid=%d\n", 589 lload_msgtype2str( op->o_tag ), op->o_client_connid, 590 op->o_client_msgid, op->o_upstream_connid, 591 op->o_upstream_msgid ); 592 nops++; 593 } 594 595 if ( nops == 0 ) { 596 CONNECTION_UNLOCK(upstream); 597 return LDAP_SUCCESS; 598 } 599 upstream->c_n_ops_executing -= nops; 600 upstream->c_counters.lc_ops_failed += nops; 601 Debug( LDAP_DEBUG_STATS, "connection_timeout: " 602 "timing out %d operations for connid=%lu\n", 603 nops, upstream->c_connid ); 604 CONNECTION_UNLOCK(upstream); 605 606 checked_lock( &b->b_mutex ); 607 b->b_n_ops_executing -= nops; 608 checked_unlock( &b->b_mutex ); 609 610 for ( node = ldap_tavl_end( ops, TAVL_DIR_LEFT ); node; 611 node = ldap_tavl_next( node, TAVL_DIR_RIGHT ) ) { 612 op = node->avl_data; 613 614 operation_send_reject( op, 615 op->o_tag == LDAP_REQ_SEARCH ? LDAP_TIMELIMIT_EXCEEDED : 616 LDAP_ADMINLIMIT_EXCEEDED, 617 "upstream did not respond in time", 0 ); 618 619 if ( upstream->c_type != LLOAD_C_BIND && rc == LDAP_SUCCESS ) { 620 rc = operation_send_abandon( op, upstream ); 621 } 622 OPERATION_UNLINK(op); 623 } 624 625 if ( rc == LDAP_SUCCESS ) { 626 connection_write_cb( -1, 0, upstream ); 627 } 628 629 CONNECTION_LOCK(upstream); 630 /* ITS#9799: If a Bind timed out, connection is in an unknown state */ 631 if ( upstream->c_type == LLOAD_C_BIND || rc != LDAP_SUCCESS || 632 ( upstream->c_state == LLOAD_C_CLOSING && !upstream->c_ops ) ) { 633 CONNECTION_DESTROY(upstream); 634 } else { 635 CONNECTION_UNLOCK(upstream); 636 } 637 638 /* just dispose of the AVL, most operations should already be gone */ 639 ldap_tavl_free( ops, NULL ); 640 return LDAP_SUCCESS; 641 } 642 643 void 644 operations_timeout( evutil_socket_t s, short what, void *arg ) 645 { 646 struct event *self = arg; 647 LloadTier *tier; 648 time_t threshold; 649 650 Debug( LDAP_DEBUG_TRACE, "operations_timeout: " 651 "running timeout task\n" ); 652 if ( !lload_timeout_api ) goto done; 653 654 threshold = slap_get_time() - lload_timeout_api->tv_sec; 655 656 LDAP_STAILQ_FOREACH ( tier, &tiers, t_next ) { 657 LloadBackend *b; 658 659 LDAP_CIRCLEQ_FOREACH ( b, &tier->t_backends, b_next ) { 660 epoch_t epoch; 661 662 checked_lock( &b->b_mutex ); 663 if ( b->b_n_ops_executing == 0 ) { 664 checked_unlock( &b->b_mutex ); 665 continue; 666 } 667 668 epoch = epoch_join(); 669 670 Debug( LDAP_DEBUG_TRACE, "operations_timeout: " 671 "timing out binds for backend uri=%s\n", 672 b->b_uri.bv_val ); 673 connections_walk_last( &b->b_mutex, &b->b_bindconns, 674 b->b_last_bindconn, connection_timeout, &threshold ); 675 676 Debug( LDAP_DEBUG_TRACE, "operations_timeout: " 677 "timing out other operations for backend uri=%s\n", 678 b->b_uri.bv_val ); 679 connections_walk_last( &b->b_mutex, &b->b_conns, b->b_last_conn, 680 connection_timeout, &threshold ); 681 682 epoch_leave( epoch ); 683 checked_unlock( &b->b_mutex ); 684 } 685 } 686 done: 687 Debug( LDAP_DEBUG_TRACE, "operations_timeout: " 688 "timeout task finished\n" ); 689 evtimer_add( self, lload_timeout_api ); 690 } 691 692 void 693 operation_update_global_rejected( LloadOperation *op ) 694 { 695 if ( op->o_res == LLOAD_OP_REJECTED ) { 696 assert( op->o_upstream_connid == 0 ); 697 switch ( op->o_tag ) { 698 case LDAP_REQ_BIND: 699 lload_stats.counters[LLOAD_STATS_OPS_BIND].lc_ops_rejected++; 700 break; 701 default: 702 lload_stats.counters[LLOAD_STATS_OPS_OTHER].lc_ops_rejected++; 703 break; 704 } 705 } 706 } 707 708 void 709 operation_update_conn_counters( LloadOperation *op, LloadConnection *upstream ) 710 { 711 if ( op->o_res == LLOAD_OP_COMPLETED ) { 712 upstream->c_counters.lc_ops_completed++; 713 } else { 714 upstream->c_counters.lc_ops_failed++; 715 } 716 } 717 718 void 719 operation_update_backend_counters( LloadOperation *op, LloadBackend *b ) 720 { 721 int stat_type = op->o_tag == LDAP_REQ_BIND ? LLOAD_STATS_OPS_BIND : 722 LLOAD_STATS_OPS_OTHER; 723 724 assert( b != NULL ); 725 if ( op->o_res == LLOAD_OP_COMPLETED ) { 726 b->b_counters[stat_type].lc_ops_completed++; 727 } else { 728 b->b_counters[stat_type].lc_ops_failed++; 729 } 730 } 731