1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2021 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
14 */
15
16 #include "portable.h"
17
18 #include <ac/socket.h>
19 #include <ac/errno.h>
20 #include <ac/string.h>
21 #include <ac/time.h>
22 #include <ac/unistd.h>
23
24 #include "lutil.h"
25 #include "lload.h"
26
27 long lload_client_max_pending = 0;
28
29 lload_c_head clients = LDAP_CIRCLEQ_HEAD_INITIALIZER( clients );
30
31 ldap_pvt_thread_mutex_t clients_mutex;
32
33 static void client_unlink( LloadConnection *upstream );
34
35 int
request_abandon(LloadConnection * c,LloadOperation * op)36 request_abandon( LloadConnection *c, LloadOperation *op )
37 {
38 LloadOperation *request, needle = { .o_client_connid = c->c_connid };
39 int rc = LDAP_SUCCESS;
40
41 op->o_res = LLOAD_OP_COMPLETED;
42
43 if ( ber_decode_int( &op->o_request, &needle.o_client_msgid ) ) {
44 Debug( LDAP_DEBUG_STATS, "request_abandon: "
45 "connid=%lu msgid=%d invalid integer sent in abandon request\n",
46 c->c_connid, op->o_client_msgid );
47
48 operation_unlink( op );
49 CONNECTION_LOCK_DESTROY(c);
50 return -1;
51 }
52
53 CONNECTION_LOCK(c);
54 request = ldap_tavl_find( c->c_ops, &needle, operation_client_cmp );
55 if ( !request ) {
56 Debug( LDAP_DEBUG_STATS, "request_abandon: "
57 "connid=%lu msgid=%d requests abandon of an operation "
58 "msgid=%d not being processed anymore\n",
59 c->c_connid, op->o_client_msgid, needle.o_client_msgid );
60 CONNECTION_UNLOCK(c);
61 goto done;
62 } else if ( request->o_tag == LDAP_REQ_BIND ) {
63 /* RFC 4511 states we must not allow Abandon on Binds */
64 Debug( LDAP_DEBUG_STATS, "request_abandon: "
65 "connid=%lu msgid=%d requests abandon of a bind operation "
66 "msgid=%d\n",
67 c->c_connid, op->o_client_msgid, needle.o_client_msgid );
68 CONNECTION_UNLOCK(c);
69 goto done;
70 }
71 Debug( LDAP_DEBUG_STATS, "request_abandon: "
72 "connid=%lu msgid=%d abandoning %s msgid=%d\n",
73 c->c_connid, op->o_client_msgid,
74 lload_msgtype2str( request->o_tag ), needle.o_client_msgid );
75
76 if ( c->c_state == LLOAD_C_BINDING ) {
77 assert(0);
78 }
79
80 CONNECTION_UNLOCK(c);
81 operation_abandon( request );
82
83 done:
84 operation_unlink( op );
85 return rc;
86 }
87
88 int
request_process(LloadConnection * client,LloadOperation * op)89 request_process( LloadConnection *client, LloadOperation *op )
90 {
91 BerElement *output;
92 LloadConnection *upstream = NULL;
93 LloadBackend *b = NULL;
94 ber_int_t msgid;
95 int res = LDAP_UNAVAILABLE, rc = LDAP_SUCCESS;
96 char *message = "no connections available";
97 enum op_restriction client_restricted;
98
99 if ( lload_control_actions && !BER_BVISNULL( &op->o_ctrls ) ) {
100 BerElementBuffer copy_berbuf;
101 BerElement *copy = (BerElement *)©_berbuf;
102 struct berval control;
103
104 ber_init2( copy, &op->o_ctrls, 0 );
105
106 while ( ber_skip_element( copy, &control ) == LBER_SEQUENCE ) {
107 struct restriction_entry *entry, needle = {};
108 BerElementBuffer control_berbuf;
109 BerElement *control_ber = (BerElement *)&control_berbuf;
110
111 ber_init2( control_ber, &control, 0 );
112
113 if ( ber_skip_element( control_ber, &needle.oid ) == LBER_ERROR ) {
114 res = LDAP_PROTOCOL_ERROR;
115 message = "invalid control";
116
117 operation_send_reject( op, res, message, 1 );
118 goto fail;
119 }
120
121 entry = ldap_tavl_find(
122 lload_control_actions, &needle, lload_restriction_cmp );
123 if ( entry && op->o_restricted < entry->action ) {
124 op->o_restricted = entry->action;
125 }
126 }
127 }
128 if ( op->o_restricted < LLOAD_OP_RESTRICTED_WRITE &&
129 lload_write_coherence &&
130 op->o_tag != LDAP_REQ_SEARCH &&
131 op->o_tag != LDAP_REQ_COMPARE ) {
132 op->o_restricted = LLOAD_OP_RESTRICTED_WRITE;
133 }
134
135 if ( op->o_restricted == LLOAD_OP_RESTRICTED_REJECT ) {
136 res = LDAP_UNWILLING_TO_PERFORM;
137 message = "extended operation or control disallowed";
138
139 operation_send_reject( op, res, message, 1 );
140 goto fail;
141 }
142
143 CONNECTION_LOCK(client);
144 client_restricted = client->c_restricted;
145 if ( client_restricted ) {
146 if ( client_restricted == LLOAD_OP_RESTRICTED_WRITE &&
147 client->c_restricted_inflight == 0 &&
148 client->c_restricted_at >= 0 &&
149 client->c_restricted_at + lload_write_coherence <
150 op->o_start.tv_sec ) {
151 Debug( LDAP_DEBUG_TRACE, "request_process: "
152 "connid=%lu write coherence to backend '%s' expired\n",
153 client->c_connid, client->c_backend->b_name.bv_val );
154 client->c_backend = NULL;
155 client_restricted = client->c_restricted = LLOAD_OP_NOT_RESTRICTED;
156 }
157 switch ( client_restricted ) {
158 case LLOAD_OP_NOT_RESTRICTED:
159 break;
160 case LLOAD_OP_RESTRICTED_WRITE:
161 case LLOAD_OP_RESTRICTED_BACKEND:
162 b = client->c_backend;
163 assert( b );
164 break;
165 case LLOAD_OP_RESTRICTED_UPSTREAM:
166 case LLOAD_OP_RESTRICTED_ISOLATE:
167 upstream = client->c_linked_upstream;
168 assert( upstream );
169 break;
170 default:
171 assert(0);
172 break;
173 }
174 }
175 if ( op->o_restricted < client_restricted ) {
176 op->o_restricted = client_restricted;
177 }
178 CONNECTION_UNLOCK(client);
179
180 if ( upstream ) {
181 b = upstream->c_backend;
182 checked_lock( &b->b_mutex );
183 if ( !try_upstream( b, NULL, op, upstream, &res, &message ) ) {
184 upstream = NULL;
185 }
186 checked_unlock( &b->b_mutex );
187 } else if ( b ) {
188 backend_select( b, op, &upstream, &res, &message );
189 } else {
190 upstream_select( op, &upstream, &res, &message );
191 }
192
193 if ( !upstream ) {
194 Debug( LDAP_DEBUG_STATS, "request_process: "
195 "connid=%lu, msgid=%d no available connection found\n",
196 op->o_client_connid, op->o_client_msgid );
197
198 operation_send_reject( op, res, message, 1 );
199 goto fail;
200 }
201 CONNECTION_ASSERT_LOCKED(upstream);
202 assert_locked( &upstream->c_io_mutex );
203 op->o_upstream = upstream;
204 op->o_upstream_connid = upstream->c_connid;
205 op->o_res = LLOAD_OP_FAILED;
206
207 /* Was it unlinked in the meantime? No need to send a response since the
208 * client is dead */
209 if ( !IS_ALIVE( op, o_refcnt ) ) {
210 LloadBackend *b = upstream->c_backend;
211
212 upstream->c_n_ops_executing--;
213 checked_unlock( &upstream->c_io_mutex );
214 CONNECTION_UNLOCK(upstream);
215
216 checked_lock( &b->b_mutex );
217 b->b_n_ops_executing--;
218 checked_unlock( &b->b_mutex );
219
220 assert( !IS_ALIVE( client, c_live ) );
221 checked_lock( &op->o_link_mutex );
222 if ( op->o_upstream ) {
223 op->o_upstream = NULL;
224 }
225 checked_unlock( &op->o_link_mutex );
226 return -1;
227 }
228
229 output = upstream->c_pendingber;
230 if ( output == NULL && (output = ber_alloc()) == NULL ) {
231 LloadBackend *b = upstream->c_backend;
232
233 upstream->c_n_ops_executing--;
234 CONNECTION_UNLOCK(upstream);
235 checked_unlock( &upstream->c_io_mutex );
236
237 checked_lock( &b->b_mutex );
238 b->b_n_ops_executing--;
239 operation_update_backend_counters( op, b );
240 checked_unlock( &b->b_mutex );
241
242 Debug( LDAP_DEBUG_ANY, "request_process: "
243 "ber_alloc failed\n" );
244
245 rc = -1;
246 goto fail;
247 }
248 upstream->c_pendingber = output;
249
250 if ( client_restricted < LLOAD_OP_RESTRICTED_UPSTREAM &&
251 op->o_restricted >= LLOAD_OP_RESTRICTED_UPSTREAM ) {
252 rc = ldap_tavl_insert(
253 &upstream->c_linked, client, lload_upstream_entry_cmp,
254 ldap_avl_dup_error );
255 assert( rc == LDAP_SUCCESS );
256 }
257
258 op->o_upstream_msgid = msgid = upstream->c_next_msgid++;
259 rc = ldap_tavl_insert(
260 &upstream->c_ops, op, operation_upstream_cmp, ldap_avl_dup_error );
261
262 CONNECTION_UNLOCK(upstream);
263
264 Debug( LDAP_DEBUG_TRACE, "request_process: "
265 "client connid=%lu added %s msgid=%d to upstream connid=%lu as "
266 "msgid=%d\n",
267 op->o_client_connid, lload_msgtype2str( op->o_tag ),
268 op->o_client_msgid, op->o_upstream_connid, op->o_upstream_msgid );
269 assert( rc == LDAP_SUCCESS );
270
271 lload_stats.counters[LLOAD_STATS_OPS_OTHER].lc_ops_forwarded++;
272
273 if ( op->o_restricted > client_restricted ||
274 client_restricted == LLOAD_OP_RESTRICTED_WRITE ) {
275 CONNECTION_LOCK(client);
276 if ( op->o_restricted > client_restricted ) {
277 client->c_restricted = op->o_restricted;
278 }
279 if ( op->o_restricted == LLOAD_OP_RESTRICTED_WRITE ) {
280 client->c_restricted_inflight++;
281 }
282 if ( op->o_restricted >= LLOAD_OP_RESTRICTED_UPSTREAM ) {
283 if ( client_restricted < LLOAD_OP_RESTRICTED_UPSTREAM ) {
284 client->c_linked_upstream = upstream;
285 }
286 assert( client->c_linked_upstream == upstream );
287 client->c_backend = NULL;
288 } else if ( op->o_restricted >= LLOAD_OP_RESTRICTED_WRITE ) {
289 if ( client_restricted < LLOAD_OP_RESTRICTED_WRITE ) {
290 client->c_backend = upstream->c_backend;
291 }
292 assert( client->c_backend == upstream->c_backend );
293 }
294 CONNECTION_UNLOCK(client);
295 }
296
297 if ( (lload_features & LLOAD_FEATURE_PROXYAUTHZ) &&
298 client->c_type != LLOAD_C_PRIVILEGED ) {
299 CONNECTION_LOCK(client);
300 Debug( LDAP_DEBUG_TRACE, "request_process: "
301 "proxying identity %s to upstream\n",
302 client->c_auth.bv_val );
303 ber_printf( output, "t{titOt{{sbO}" /* "}}" */, LDAP_TAG_MESSAGE,
304 LDAP_TAG_MSGID, msgid,
305 op->o_tag, &op->o_request,
306 LDAP_TAG_CONTROLS,
307 LDAP_CONTROL_PROXY_AUTHZ, 1, &client->c_auth );
308 CONNECTION_UNLOCK(client);
309
310 if ( !BER_BVISNULL( &op->o_ctrls ) ) {
311 ber_write( output, op->o_ctrls.bv_val, op->o_ctrls.bv_len, 0 );
312 }
313
314 ber_printf( output, /* "{{" */ "}}" );
315 } else {
316 ber_printf( output, "t{titOtO}", LDAP_TAG_MESSAGE,
317 LDAP_TAG_MSGID, msgid,
318 op->o_tag, &op->o_request,
319 LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) );
320 }
321 checked_unlock( &upstream->c_io_mutex );
322
323 connection_write_cb( -1, 0, upstream );
324 return rc;
325
326 fail:
327 if ( upstream ) {
328 CONNECTION_LOCK_DESTROY(upstream);
329
330 /* We have not committed any restrictions in the end */
331 op->o_restricted = LLOAD_OP_NOT_RESTRICTED;
332 operation_send_reject( op, LDAP_OTHER, "internal error", 0 );
333 }
334
335 operation_unlink( op );
336 if ( rc ) {
337 CONNECTION_LOCK_DESTROY(client);
338 }
339 return rc;
340 }
341
342 int
handle_one_request(LloadConnection * c)343 handle_one_request( LloadConnection *c )
344 {
345 BerElement *ber;
346 LloadOperation *op = NULL;
347 RequestHandler handler = NULL;
348 int over_limit = 0;
349 enum sc_state state;
350 enum sc_io_state io_state;
351
352 ber = c->c_currentber;
353 c->c_currentber = NULL;
354
355 CONNECTION_LOCK(c);
356 op = operation_init( c, ber );
357 if ( !op ) {
358 Debug( LDAP_DEBUG_ANY, "handle_one_request: "
359 "connid=%lu, operation_init failed\n",
360 c->c_connid );
361 CONNECTION_DESTROY(c);
362 ber_free( ber, 1 );
363 return -1;
364 }
365 if ( lload_client_max_pending &&
366 c->c_n_ops_executing >= lload_client_max_pending ) {
367 over_limit = 1;
368 }
369
370 /*
371 * Remember the current state so we don't have to lock again,
372 * we're only screening whether we can keep going, e.g. noone can change
373 * state to LLOAD_C_BINDING from under us (would imply a new operation was
374 * received but that's us), but the opposite is possible - a Bind response
375 * could be received and processed in the meantime.
376 */
377 state = c->c_state;
378 CONNECTION_UNLOCK(c);
379
380 switch ( op->o_tag ) {
381 case LDAP_REQ_UNBIND:
382 /* There is never a response for this operation */
383 op->o_res = LLOAD_OP_COMPLETED;
384 operation_unlink( op );
385
386 Debug( LDAP_DEBUG_STATS, "handle_one_request: "
387 "received unbind, closing client connid=%lu\n",
388 c->c_connid );
389 CONNECTION_LOCK_DESTROY(c);
390 return -1;
391 case LDAP_REQ_BIND:
392 handler = request_bind;
393 break;
394 case LDAP_REQ_ABANDON:
395 /* We can't send a response to abandon requests even if a bind is
396 * currently in progress */
397 return request_abandon( c, op );
398 case LDAP_REQ_EXTENDED:
399 default:
400 if ( state == LLOAD_C_BINDING ) {
401 operation_send_reject(
402 op, LDAP_PROTOCOL_ERROR, "bind in progress", 0 );
403 return LDAP_SUCCESS;
404 }
405 if ( over_limit ) {
406 operation_send_reject( op, LDAP_BUSY,
407 "pending operation limit reached on this connection",
408 0 );
409 return LDAP_SUCCESS;
410 }
411
412 checked_lock( &c->c_io_mutex );
413 io_state = c->c_io_state;
414 checked_unlock( &c->c_io_mutex );
415 if ( io_state & LLOAD_C_READ_PAUSE ) {
416 operation_send_reject( op, LDAP_BUSY,
417 "writing side backlogged, please keep reading", 0 );
418 return LDAP_SUCCESS;
419 }
420
421 if ( op->o_tag == LDAP_REQ_EXTENDED ) {
422 handler = request_extended;
423 } else {
424 handler = request_process;
425 }
426 break;
427 }
428
429 if ( state == LLOAD_C_CLOSING ) {
430 operation_send_reject(
431 op, LDAP_UNAVAILABLE, "connection is shutting down", 0 );
432 return LDAP_SUCCESS;
433 }
434
435 return handler( c, op );
436 }
437
438 #ifdef HAVE_TLS
439 /*
440 * The connection has a token assigned to it when the callback is set up.
441 */
442 void
client_tls_handshake_cb(evutil_socket_t s,short what,void * arg)443 client_tls_handshake_cb( evutil_socket_t s, short what, void *arg )
444 {
445 LloadConnection *c = arg;
446 epoch_t epoch;
447 int rc = 0;
448
449 if ( what & EV_TIMEOUT ) {
450 Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: "
451 "connid=%lu, timeout reached, destroying\n",
452 c->c_connid );
453 goto fail;
454 }
455
456 /*
457 * In case of StartTLS, make sure we flush the response first.
458 * Also before we try to read anything from the connection, it isn't
459 * permitted to Abandon a StartTLS exop per RFC4511 anyway.
460 */
461 checked_lock( &c->c_io_mutex );
462 if ( c->c_pendingber ) {
463 checked_unlock( &c->c_io_mutex );
464 connection_write_cb( s, what, arg );
465
466 if ( !IS_ALIVE( c, c_live ) ) {
467 goto fail;
468 }
469
470 /* Do we still have data pending? If so, connection_write_cb would
471 * already have arranged the write callback to trigger again */
472 checked_lock( &c->c_io_mutex );
473 if ( c->c_pendingber ) {
474 checked_unlock( &c->c_io_mutex );
475 return;
476 }
477 }
478
479 rc = ldap_pvt_tls_accept( c->c_sb, LLOAD_TLS_CTX );
480 checked_unlock( &c->c_io_mutex );
481 if ( rc < 0 ) {
482 goto fail;
483 }
484
485 if ( rc == 0 ) {
486 struct event_base *base = event_get_base( c->c_read_event );
487
488 /*
489 * We're finished, replace the callbacks
490 *
491 * This is deadlock-safe, since both share the same base - the one
492 * that's just running us.
493 */
494 CONNECTION_LOCK(c);
495 event_del( c->c_read_event );
496 event_del( c->c_write_event );
497
498 c->c_read_timeout = NULL;
499 event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST,
500 connection_read_cb, c );
501 if ( IS_ALIVE( c, c_live ) ) {
502 event_add( c->c_read_event, c->c_read_timeout );
503 }
504
505 event_assign( c->c_write_event, base, c->c_fd, EV_WRITE,
506 connection_write_cb, c );
507 Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: "
508 "connid=%lu finished\n",
509 c->c_connid );
510
511 c->c_is_tls = LLOAD_TLS_ESTABLISHED;
512 CONNECTION_UNLOCK(c);
513 return;
514 } else if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) {
515 if ( IS_ALIVE( c, c_live ) ) {
516 CONNECTION_LOCK(c);
517 event_add( c->c_write_event, lload_write_timeout );
518 CONNECTION_UNLOCK(c);
519 }
520 Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: "
521 "connid=%lu need write rc=%d\n",
522 c->c_connid, rc );
523 }
524 return;
525
526 fail:
527 Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: "
528 "connid=%lu failed rc=%d\n",
529 c->c_connid, rc );
530
531 assert( c->c_ops == NULL );
532 epoch = epoch_join();
533 CONNECTION_LOCK_DESTROY(c);
534 epoch_leave( epoch );
535 }
536 #endif /* HAVE_TLS */
537
538 LloadConnection *
client_init(ber_socket_t s,const char * peername,struct event_base * base,int flags)539 client_init(
540 ber_socket_t s,
541 const char *peername,
542 struct event_base *base,
543 int flags )
544 {
545 LloadConnection *c;
546 struct event *event;
547 event_callback_fn read_cb = connection_read_cb,
548 write_cb = connection_write_cb;
549
550 if ( (c = lload_connection_init( s, peername, flags) ) == NULL ) {
551 return NULL;
552 }
553
554 {
555 ber_len_t max = sockbuf_max_incoming_client;
556 ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
557 }
558
559 c->c_state = LLOAD_C_READY;
560
561 if ( flags & CONN_IS_TLS ) {
562 #ifdef HAVE_TLS
563 int rc;
564
565 c->c_is_tls = LLOAD_LDAPS;
566
567 rc = ldap_pvt_tls_accept( c->c_sb, LLOAD_TLS_CTX );
568 if ( rc < 0 ) {
569 Debug( LDAP_DEBUG_CONNS, "client_init: "
570 "connid=%lu failed initial TLS accept rc=%d\n",
571 c->c_connid, rc );
572 CONNECTION_LOCK(c);
573 goto fail;
574 }
575
576 if ( rc ) {
577 c->c_read_timeout = lload_timeout_net;
578 read_cb = write_cb = client_tls_handshake_cb;
579 }
580 #else /* ! HAVE_TLS */
581 assert(0);
582 #endif /* ! HAVE_TLS */
583 }
584
585 event = event_new( base, s, EV_READ|EV_PERSIST, read_cb, c );
586 if ( !event ) {
587 Debug( LDAP_DEBUG_ANY, "client_init: "
588 "Read event could not be allocated\n" );
589 CONNECTION_LOCK(c);
590 goto fail;
591 }
592 c->c_read_event = event;
593
594 event = event_new( base, s, EV_WRITE, write_cb, c );
595 if ( !event ) {
596 Debug( LDAP_DEBUG_ANY, "client_init: "
597 "Write event could not be allocated\n" );
598 CONNECTION_LOCK(c);
599 goto fail;
600 }
601 c->c_write_event = event;
602
603 CONNECTION_LOCK(c);
604 #ifdef BALANCER_MODULE
605 if ( lload_monitor_client_subsys ) {
606 acquire_ref( &c->c_refcnt );
607 CONNECTION_UNLOCK(c);
608 if ( lload_monitor_conn_entry_create(
609 c, lload_monitor_client_subsys ) ) {
610 CONNECTION_LOCK(c);
611 RELEASE_REF( c, c_refcnt, c->c_destroy );
612 goto fail;
613 }
614 CONNECTION_LOCK(c);
615 RELEASE_REF( c, c_refcnt, c->c_destroy );
616 }
617 #endif /* BALANCER_MODULE */
618
619 c->c_destroy = client_destroy;
620 c->c_unlink = client_unlink;
621 c->c_pdu_cb = handle_one_request;
622
623 /* We only register the write event when we have data pending */
624 event_add( c->c_read_event, c->c_read_timeout );
625
626 checked_lock( &clients_mutex );
627 LDAP_CIRCLEQ_INSERT_TAIL( &clients, c, c_next );
628 checked_unlock( &clients_mutex );
629 CONNECTION_UNLOCK(c);
630
631 return c;
632 fail:
633 if ( !IS_ALIVE( c, c_live ) ) {
634 /*
635 * Released while we were unlocked, it's scheduled for destruction
636 * already
637 */
638 return NULL;
639 }
640
641 if ( c->c_write_event ) {
642 event_free( c->c_write_event );
643 c->c_write_event = NULL;
644 }
645 if ( c->c_read_event ) {
646 event_free( c->c_read_event );
647 c->c_read_event = NULL;
648 }
649
650 c->c_state = LLOAD_C_INVALID;
651 c->c_live--;
652 c->c_refcnt--;
653 connection_destroy( c );
654 return NULL;
655 }
656
657 void
client_reset(LloadConnection * c)658 client_reset( LloadConnection *c )
659 {
660 TAvlnode *root;
661 long freed = 0, executing;
662 LloadConnection *linked_upstream = NULL;
663 enum op_restriction restricted = c->c_restricted;
664
665 CONNECTION_ASSERT_LOCKED(c);
666 root = c->c_ops;
667 c->c_ops = NULL;
668 executing = c->c_n_ops_executing;
669 c->c_n_ops_executing = 0;
670
671 if ( !BER_BVISNULL( &c->c_auth ) ) {
672 ch_free( c->c_auth.bv_val );
673 BER_BVZERO( &c->c_auth );
674 }
675 if ( !BER_BVISNULL( &c->c_sasl_bind_mech ) ) {
676 ch_free( c->c_sasl_bind_mech.bv_val );
677 BER_BVZERO( &c->c_sasl_bind_mech );
678 }
679
680 if ( restricted && restricted < LLOAD_OP_RESTRICTED_ISOLATE ) {
681 if ( c->c_backend ) {
682 assert( c->c_restricted <= LLOAD_OP_RESTRICTED_BACKEND );
683 assert( c->c_restricted_inflight == 0 );
684 c->c_backend = NULL;
685 c->c_restricted_at = 0;
686 } else {
687 assert( c->c_restricted == LLOAD_OP_RESTRICTED_UPSTREAM );
688 assert( c->c_linked_upstream != NULL );
689 linked_upstream = c->c_linked_upstream;
690 c->c_linked_upstream = NULL;
691 }
692 }
693 CONNECTION_UNLOCK(c);
694
695 if ( root ) {
696 freed = ldap_tavl_free( root, (AVL_FREE)operation_abandon );
697 Debug( LDAP_DEBUG_TRACE, "client_reset: "
698 "dropped %ld operations\n",
699 freed );
700 }
701 assert( freed == executing );
702
703 if ( linked_upstream && restricted == LLOAD_OP_RESTRICTED_UPSTREAM ) {
704 LloadConnection *removed = ldap_tavl_delete(
705 &linked_upstream->c_linked, c, lload_upstream_entry_cmp );
706 assert( removed == c );
707 }
708
709 CONNECTION_LOCK(c);
710 CONNECTION_ASSERT_LOCKED(c);
711 }
712
713 void
client_unlink(LloadConnection * c)714 client_unlink( LloadConnection *c )
715 {
716 enum sc_state state;
717 struct event *read_event, *write_event;
718
719 Debug( LDAP_DEBUG_CONNS, "client_unlink: "
720 "removing client connid=%lu\n",
721 c->c_connid );
722
723 CONNECTION_ASSERT_LOCKED(c);
724 assert( c->c_state != LLOAD_C_INVALID );
725 assert( c->c_state != LLOAD_C_DYING );
726
727 state = c->c_state;
728 c->c_state = LLOAD_C_DYING;
729
730 if ( c->c_restricted == LLOAD_OP_RESTRICTED_ISOLATE ) {
731 /* Allow upstream connection to be severed in client_reset() */
732 c->c_restricted = LLOAD_OP_RESTRICTED_UPSTREAM;
733 }
734
735 read_event = c->c_read_event;
736 write_event = c->c_write_event;
737 CONNECTION_UNLOCK(c);
738
739 if ( read_event ) {
740 event_del( read_event );
741 }
742
743 if ( write_event ) {
744 event_del( write_event );
745 }
746
747 if ( state != LLOAD_C_DYING ) {
748 checked_lock( &clients_mutex );
749 LDAP_CIRCLEQ_REMOVE( &clients, c, c_next );
750 checked_unlock( &clients_mutex );
751 }
752
753 CONNECTION_LOCK(c);
754 client_reset( c );
755 CONNECTION_ASSERT_LOCKED(c);
756 }
757
758 void
client_destroy(LloadConnection * c)759 client_destroy( LloadConnection *c )
760 {
761 Debug( LDAP_DEBUG_CONNS, "client_destroy: "
762 "destroying client connid=%lu\n",
763 c->c_connid );
764
765 CONNECTION_LOCK(c);
766 assert( c->c_state == LLOAD_C_DYING );
767
768 #ifdef BALANCER_MODULE
769 /*
770 * Can't do this in client_unlink as that could be run from cn=monitor
771 * modify callback.
772 */
773 if ( !BER_BVISNULL( &c->c_monitor_dn ) ) {
774 lload_monitor_conn_unlink( c );
775 }
776 #endif /* BALANCER_MODULE */
777
778 c->c_state = LLOAD_C_INVALID;
779
780 assert( c->c_ops == NULL );
781
782 if ( c->c_read_event ) {
783 event_free( c->c_read_event );
784 c->c_read_event = NULL;
785 }
786
787 if ( c->c_write_event ) {
788 event_free( c->c_write_event );
789 c->c_write_event = NULL;
790 }
791
792 assert( c->c_refcnt == 0 );
793 connection_destroy( c );
794 }
795
796 void
clients_destroy(int gentle)797 clients_destroy( int gentle )
798 {
799 checked_lock( &clients_mutex );
800 connections_walk(
801 &clients_mutex, &clients, lload_connection_close, &gentle );
802 checked_unlock( &clients_mutex );
803 }
804