backend.c 19.1 KB
Newer Older
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
 * Copyright 1998-2020 The OpenLDAP Foundation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */

#include "portable.h"

#include <ac/socket.h>
#include <ac/errno.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>

#include <event2/event.h>
#include <event2/dns.h>

#include "lutil.h"
28
#include "lload.h"
Ondřej Kuzník's avatar
Ondřej Kuzník committed
29

30
31
32
static void
upstream_connect_cb( evutil_socket_t s, short what, void *arg )
{
33
34
    LloadPendingConnection *conn = arg;
    LloadBackend *b = conn->backend;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
35
    int error = 0, rc = -1;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

    ldap_pvt_thread_mutex_lock( &b->b_mutex );
    Debug( LDAP_DEBUG_CONNS, "upstream_connect_cb: "
            "fd=%d connection callback for backend uri='%s'\n",
            s, b->b_uri.bv_val );
    if ( what == EV_WRITE ) {
        socklen_t optlen = sizeof(error);

        if ( getsockopt( conn->fd, SOL_SOCKET, SO_ERROR, (void *)&error,
                     &optlen ) < 0 ) {
            goto done;
        }
        if ( error == EINTR || error == EINPROGRESS || error == EWOULDBLOCK ) {
            ldap_pvt_thread_mutex_unlock( &b->b_mutex );
            return;
        } else if ( error ) {
            goto done;
53
        } else if ( upstream_init( s, conn->backend ) == NULL ) {
54
55
56
57
58
59
            goto done;
        }
        rc = LDAP_SUCCESS;
    }

done:
60
    LDAP_LIST_REMOVE( conn, next );
61
62
    if ( rc ) {
        evutil_closesocket( conn->fd );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
63
        b->b_opening--;
64
        b->b_failed++;
65
66
67
68
69
70
71
72
73
74
75
        if ( what & EV_TIMEOUT ) {
            Debug( LDAP_DEBUG_ANY, "upstream_connect_cb: "
                    "fd=%d connection timed out\n",
                    s );
        } else {
            char ebuf[128];
            Debug( LDAP_DEBUG_ANY, "upstream_connect_cb: "
                    "fd=%d connection set up failed%s%s\n",
                    s, error ? ": " : "",
                    error ? sock_errstr( error, ebuf, sizeof(ebuf) ) : "" );
        }
76
        backend_retry( b );
77
78
79
80
81
82
83
84
85
    } else {
        b->b_failed = 0;
    }
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );

    event_free( conn->event );
    ch_free( conn );
}

Ondřej Kuzník's avatar
Ondřej Kuzník committed
86
87
88
static void
upstream_name_cb( int result, struct evutil_addrinfo *res, void *arg )
{
89
    LloadBackend *b = arg;
90
    ber_socket_t s = AC_SOCKET_INVALID;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
91
92
    int rc;

93
94
95
96
97
    if ( result == EVUTIL_EAI_CANCEL ) {
        Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                "cancelled\n" );
        return;
    }
98

99
100
101
102
103
104
105
106
    ldap_pvt_thread_mutex_lock( &b->b_mutex );
    /* We were already running when backend_reset tried to cancel us, but were
     * already stuck waiting for the mutex, nothing to do and b_opening has
     * been decremented as well */
    if ( b->b_dns_req == NULL ) {
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
        return;
    }
107
    b->b_dns_req = NULL;
108

Ondřej Kuzník's avatar
Ondřej Kuzník committed
109
110
111
    if ( result || !res ) {
        Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                "name resolution failed for backend '%s': %s\n",
112
                b->b_uri.bv_val, evutil_gai_strerror( result ) );
113
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
114
115
    }

116
117
118
119
    /* TODO: if we get failures, try the other addrinfos */
    if ( (s = socket( res->ai_family, SOCK_STREAM, 0 )) ==
            AC_SOCKET_INVALID ) {
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
120
121
    }

122
123
    if ( ber_pvt_socket_set_nonblock( s, 1 ) ) {
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
124
125
126
127
128
129
130
131
132
133
134
    }

    if ( res->ai_family == PF_INET ) {
        struct sockaddr_in *ai = (struct sockaddr_in *)res->ai_addr;
        ai->sin_port = htons( b->b_port );
        rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen );
    } else {
        struct sockaddr_in6 *ai = (struct sockaddr_in6 *)res->ai_addr;
        ai->sin6_port = htons( b->b_port );
        rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen );
    }
135
136
    /* Asynchronous connect */
    if ( rc ) {
137
        LloadPendingConnection *conn;
138
139
140
141
142
143
144
145
146

        if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) {
            Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                    "failed to connect to server '%s'\n",
                    b->b_uri.bv_val );
            evutil_closesocket( s );
            goto fail;
        }

147
        conn = ch_calloc( 1, sizeof(LloadPendingConnection) );
148
149
150
151
        LDAP_LIST_ENTRY_INIT( conn, next );
        conn->backend = b;
        conn->fd = s;

152
        conn->event = event_new( lload_get_base( s ), s, EV_WRITE|EV_PERSIST,
153
154
155
156
157
158
159
160
161
162
                upstream_connect_cb, conn );
        if ( !conn->event ) {
            Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                    "failed to acquire an event to finish upstream "
                    "connection setup.\n" );
            ch_free( conn );
            evutil_closesocket( s );
            goto fail;
        }

163
        event_add( conn->event, lload_timeout_net );
164
165
166
        LDAP_LIST_INSERT_HEAD( &b->b_connecting, conn, next );
        Debug( LDAP_DEBUG_CONNS, "upstream_name_cb: "
                "connection to backend uri=%s in progress\n",
167
                b->b_uri.bv_val );
168
    } else if ( upstream_init( s, b ) == NULL ) {
169
170
        goto fail;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
171

Ondřej Kuzník's avatar
Ondřej Kuzník committed
172
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
173
    evutil_freeaddrinfo( res );
174
175
176
177
178
179
180
    return;

fail:
    if ( s != AC_SOCKET_INVALID ) {
        evutil_closesocket( s );
    }
    b->b_opening--;
181
    b->b_failed++;
182
    backend_retry( b );
183
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
184
185
186
    if ( res ) {
        evutil_freeaddrinfo( res );
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
187
188
}

189
LloadConnection *
190
backend_select( LloadOperation *op, int *res )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
191
{
192
    LloadBackend *b, *first, *next;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
193
194
195
196
197

    ldap_pvt_thread_mutex_lock( &backend_mutex );
    first = b = current_backend;
    ldap_pvt_thread_mutex_unlock( &backend_mutex );

198
199
    *res = LDAP_UNAVAILABLE;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
200
201
202
    if ( !first ) {
        return NULL;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
203

204
205
    /* TODO: Two runs, one with trylock, then one actually locked if we don't
     * find anything? */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
206
    do {
207
208
        lload_c_head *head;
        LloadConnection *c;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
209

Ondřej Kuzník's avatar
Ondřej Kuzník committed
210
        ldap_pvt_thread_mutex_lock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
211
        next = LDAP_CIRCLEQ_LOOP_NEXT( &backend, b, b_next );
212
213
214
215

        if ( b->b_max_pending && b->b_n_ops_executing >= b->b_max_pending ) {
            Debug( LDAP_DEBUG_CONNS, "backend_select: "
                    "backend %s too busy\n",
216
                    b->b_uri.bv_val );
217
            ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
218
            b = next;
219
            *res = LDAP_BUSY;
220
221
222
            continue;
        }

223
224
225
226
227
        if ( op->o_tag == LDAP_REQ_BIND
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
                && !(lload_features & LLOAD_FEATURE_VC)
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
        ) {
228
229
230
231
            head = &b->b_bindconns;
        } else {
            head = &b->b_conns;
        }
232
233
234
        if ( !LDAP_CIRCLEQ_EMPTY( head ) ) {
            *res = LDAP_BUSY;
        }
235

236
        LDAP_CIRCLEQ_FOREACH ( c, head, c_next ) {
237
            ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
238
            CONNECTION_LOCK(c);
239
            if ( c->c_state == LLOAD_C_READY && !c->c_pendingber &&
240
241
                    ( b->b_max_conn_pending == 0 ||
                            c->c_n_ops_executing < b->b_max_conn_pending ) ) {
242
                Debug( LDAP_DEBUG_CONNS, "backend_select: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
243
244
                        "selected connection connid=%lu for client "
                        "connid=%lu msgid=%d\n",
245
246
                        c->c_connid, op->o_client_connid, op->o_client_msgid );

247
248
                /*
                 * Round-robin step:
Ondřej Kuzník's avatar
Ondřej Kuzník committed
249
250
                 * Rotate the queue to put this connection at the end, same for
                 * the backend.
251
252
253
                 */
                LDAP_CIRCLEQ_MAKE_TAIL( head, c, c_next );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
254
255
256
257
                ldap_pvt_thread_mutex_lock( &backend_mutex );
                current_backend = next;
                ldap_pvt_thread_mutex_unlock( &backend_mutex );

258
                b->b_n_ops_executing++;
259
260
261
262
263
                if ( op->o_tag == LDAP_REQ_BIND ) {
                    b->b_counters[LLOAD_STATS_OPS_BIND].lc_ops_received++;
                } else {
                    b->b_counters[LLOAD_STATS_OPS_OTHER].lc_ops_received++;
                }
264
                c->c_n_ops_executing++;
265
                c->c_counters.lc_ops_received++;
266
                CONNECTION_UNLOCK_INCREF(c);
267

268
                ldap_pvt_thread_mutex_unlock( &b->b_mutex );
269
                *res = LDAP_SUCCESS;
270
271
                return c;
            }
272
            CONNECTION_UNLOCK(c);
273
            ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
274
        }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
275
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
276
277
278

        b = next;
    } while ( b != first );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
279
280
281
282

    return NULL;
}

283
284
285
286
/*
 * Will schedule a connection attempt if there is a need for it. Need exclusive
 * access to backend, its b_mutex is not touched here, though.
 */
287
void
288
backend_retry( LloadBackend *b )
289
{
290
    int requested;
291

Ondřej Kuzník's avatar
Ondřej Kuzník committed
292
293
294
295
296
297
    if ( slapd_shutdown ) {
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "shutting down\n" );
        return;
    }

298
    requested = b->b_numconns;
299
300
301
302
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
    if ( !(lload_features & LLOAD_FEATURE_VC) )
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
    {
303
304
        requested += b->b_numbindconns;
    }
305
306

    if ( b->b_active + b->b_bindavail + b->b_opening >= requested ) {
307
308
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "no more connections needed for this backend\n" );
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
        return;
    }

    if ( b->b_opening > 0 ) {
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "retry in progress already\n" );
        assert( b->b_opening == 1 );
        return;
    }

    /* We incremented b_opening when we activated the event, so it can't be
     * pending */
    assert( !event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) );
    b->b_opening++;

    if ( b->b_failed > 0 ) {
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "scheduling a retry in %d ms\n",
                b->b_retry_timeout );
        event_add( b->b_retry_event, &b->b_retry_tv );
        return;
    }

    Debug( LDAP_DEBUG_CONNS, "backend_retry: "
            "scheduling re-connection straight away\n" );

    if ( ldap_pvt_thread_pool_submit2(
                 &connection_pool, backend_connect_task, b, &b->b_cookie ) ) {
        Debug( LDAP_DEBUG_ANY, "backend_retry: "
                "failed to submit retry task, scheduling a retry instead\n" );
        /* The current implementation of ldap_pvt_thread_pool_submit2 can fail
         * and still set (an invalid) cookie */
        b->b_cookie = NULL;
        b->b_failed++;
        event_add( b->b_retry_event, &b->b_retry_tv );
344
345
346
    }
}

347
348
void
backend_connect( evutil_socket_t s, short what, void *arg )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
349
350
{
    struct evutil_addrinfo hints = {};
351
    LloadBackend *b = arg;
352
    struct evdns_getaddrinfo_request *request, *placeholder;
353
    char *hostname;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
354

355
356
357
358
359
360
361
    ldap_pvt_thread_mutex_lock( &b->b_mutex );
    assert( b->b_dns_req == NULL );

    if ( b->b_cookie ) {
        b->b_cookie = NULL;
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
362
363
364
    if ( slapd_shutdown ) {
        Debug( LDAP_DEBUG_CONNS, "backend_connect: "
                "doing nothing, shutdown in progress\n" );
365
366
        b->b_opening--;
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
367
368
369
        return;
    }

370
    Debug( LDAP_DEBUG_CONNS, "backend_connect: "
371
372
            "%sattempting connection to %s\n",
            (what & EV_TIMEOUT) ? "retry timeout finished, " : "",
373
374
            b->b_host );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
375
376
377
378
379
380
381
#ifdef LDAP_PF_LOCAL
    if ( b->b_proto == LDAP_PROTO_IPC ) {
        struct sockaddr_un addr;
        ber_socket_t s = socket( PF_LOCAL, SOCK_STREAM, 0 );
        int rc;

        if ( s == AC_SOCKET_INVALID ) {
382
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
383
384
385
386
387
        }

        rc = ber_pvt_socket_set_nonblock( s, 1 );
        if ( rc ) {
            evutil_closesocket( s );
388
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
389
390
391
392
        }

        if ( strlen( b->b_host ) > ( sizeof(addr.sun_path) - 1 ) ) {
            evutil_closesocket( s );
393
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
394
395
396
397
398
399
400
        }
        memset( &addr, '\0', sizeof(addr) );
        addr.sun_family = AF_LOCAL;
        strcpy( addr.sun_path, b->b_host );

        rc = connect(
                s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un) );
401
402
        /* Asynchronous connect */
        if ( rc ) {
403
            LloadPendingConnection *conn;
404
405
406
407
408
409

            if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) {
                evutil_closesocket( s );
                goto fail;
            }

410
            conn = ch_calloc( 1, sizeof(LloadPendingConnection) );
411
412
413
414
            LDAP_LIST_ENTRY_INIT( conn, next );
            conn->backend = b;
            conn->fd = s;

415
            conn->event = event_new( lload_get_base( s ), s,
416
417
418
419
420
421
422
423
424
425
                    EV_WRITE|EV_PERSIST, upstream_connect_cb, conn );
            if ( !conn->event ) {
                Debug( LDAP_DEBUG_ANY, "backend_connect: "
                        "failed to acquire an event to finish upstream "
                        "connection setup.\n" );
                ch_free( conn );
                evutil_closesocket( s );
                goto fail;
            }

426
            event_add( conn->event, lload_timeout_net );
427
428
429
430
            LDAP_LIST_INSERT_HEAD( &b->b_connecting, conn, next );
            Debug( LDAP_DEBUG_CONNS, "backend_connect: "
                    "connection to backend uri=%s in progress\n",
                    b->b_uri.bv_val );
431
        } else if ( upstream_init( s, b ) == NULL ) {
432
433
            goto fail;
        }
434

435
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
436
        return;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
437
438
439
440
441
442
443
444
    }
#endif /* LDAP_PF_LOCAL */

    hints.ai_family = AF_UNSPEC;
    hints.ai_flags = EVUTIL_AI_CANONNAME;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

445
    hostname = b->b_host;
446
447
448
449
450
451
452
453
454
455

    /*
     * Picking any value on the stack. This is unique to our thread without
     * having to call ldap_pvt_thread_self.
     * We might have to revert to using ldap_pvt_thread_self eventually since
     * this betrays where exactly our stack lies - potentially weakening some
     * protections like ASLR.
     */
    placeholder = (struct evdns_getaddrinfo_request *)&request;
    b->b_dns_req = placeholder;
456
457
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );

458
    request = evdns_getaddrinfo(
459
            dnsbase, hostname, NULL, &hints, upstream_name_cb, b );
460
461
462
463
464
465
466
467
468
469
470

    ldap_pvt_thread_mutex_lock( &b->b_mutex );
    assert( request || b->b_dns_req != placeholder );

    /* Record the request, unless upstream_name_cb or another thread
     * cleared it. Another thread is usually backend_reset or backend_connect
     * if upstream_name_cb finished and scheduled another one */
    if ( b->b_dns_req == placeholder ) {
        b->b_dns_req = request;
    }
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
471
    return;
472
473
474

fail:
    b->b_opening--;
475
    b->b_failed++;
476
    backend_retry( b );
477
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
478
479
480
481
482
483
484
}

void *
backend_connect_task( void *ctx, void *arg )
{
    backend_connect( -1, 0, arg );
    return NULL;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
485
}
Ondřej Kuzník's avatar
Ondřej Kuzník committed
486

487
488
489
/*
 * Needs exclusive access to the backend.
 */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
490
void
491
backend_reset( LloadBackend *b )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
492
{
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
    if ( b->b_cookie ) {
        int rc;
        rc = ldap_pvt_thread_pool_retract( b->b_cookie );
        assert( rc == 1 );
        b->b_cookie = NULL;
        b->b_opening--;
    }
    if ( event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) {
        assert( b->b_failed );
        event_del( b->b_retry_event );
        b->b_opening--;
    }
    if ( b->b_dns_req ) {
        evdns_getaddrinfo_cancel( b->b_dns_req );
        b->b_dns_req = NULL;
        b->b_opening--;
    }
510
511
    while ( !LDAP_LIST_EMPTY( &b->b_connecting ) ) {
        LloadPendingConnection *pending = LDAP_LIST_FIRST( &b->b_connecting );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
512

513
514
515
        Debug( LDAP_DEBUG_CONNS, "backend_reset: "
                "destroying socket pending connect() fd=%d\n",
                pending->fd );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
516

517
518
519
520
        event_free( pending->event );
        evutil_closesocket( pending->fd );
        LDAP_LIST_REMOVE( pending, next );
        ch_free( pending );
521
        b->b_opening--;
522
523
524
    }
    while ( !LDAP_CIRCLEQ_EMPTY( &b->b_preparing ) ) {
        LloadConnection *c = LDAP_CIRCLEQ_FIRST( &b->b_preparing );
525

526
527
528
529
        CONNECTION_LOCK(c);
        Debug( LDAP_DEBUG_CONNS, "backend_reset: "
                "destroying connection being set up connid=%lu\n",
                c->c_connid );
530

531
532
533
534
535
536
        assert( c->c_live );
        CONNECTION_DESTROY(c);
        assert( !c );
    }
    while ( !LDAP_CIRCLEQ_EMPTY( &b->b_bindconns ) ) {
        LloadConnection *c = LDAP_CIRCLEQ_FIRST( &b->b_bindconns );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
537

538
539
540
541
        CONNECTION_LOCK(c);
        Debug( LDAP_DEBUG_CONNS, "backend_reset: "
                "destroying bind connection connid=%lu, pending ops=%ld\n",
                c->c_connid, c->c_n_ops_executing );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
542

543
544
545
546
547
548
        assert( c->c_live );
        CONNECTION_DESTROY(c);
        assert( !c );
    }
    while ( !LDAP_CIRCLEQ_EMPTY( &b->b_conns ) ) {
        LloadConnection *c = LDAP_CIRCLEQ_FIRST( &b->b_conns );
549

550
551
552
553
        CONNECTION_LOCK(c);
        Debug( LDAP_DEBUG_CONNS, "backend_reset: "
                "destroying regular connection connid=%lu, pending ops=%ld\n",
                c->c_connid, c->c_n_ops_executing );
554

555
556
557
558
        assert( c->c_live );
        CONNECTION_DESTROY(c);
        assert( !c );
    }
559
560
561
562
563
    if ( b->b_dns_req ) {
        evdns_getaddrinfo_cancel( b->b_dns_req );
        b->b_dns_req = NULL;
        b->b_opening--;
    }
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
    if ( b->b_cookie ) {
        int rc;
        rc = ldap_pvt_thread_pool_retract( b->b_cookie );
        assert( rc == 1 );
        b->b_cookie = NULL;
        b->b_opening--;
    }
    if ( b->b_retry_event &&
            event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) {
        assert( b->b_failed );
        event_del( b->b_retry_event );
        b->b_opening--;
    }
    assert( b->b_opening == 0 );
    assert( b->b_active == 0 );
    assert( b->b_bindavail == 0 );
    b->b_failed = 0;
581
}
582

583
584
585
586
void
lload_backend_destroy( LloadBackend *b )
{
    LloadBackend *next = LDAP_CIRCLEQ_LOOP_NEXT( &backend, b, b_next );
587

588
589
590
591
    Debug( LDAP_DEBUG_CONNS, "lload_backend_destroy: "
            "destroying backend uri='%s', numconns=%d, numbindconns=%d\n",
            b->b_uri.bv_val, b->b_numconns, b->b_numbindconns );

592
    b->b_numconns = b->b_numbindconns = 0;
593
594
595
596
597
598
599
600
601
    backend_reset( b );

    LDAP_CIRCLEQ_REMOVE( &backend, b, b_next );
    if ( b == next ) {
        current_backend = NULL;
    } else {
        current_backend = next;
    }

602
603
604
605
606
607
608
609
610
611
612
613
614
615
#ifdef BALANCER_MODULE
    if ( b->b_monitor ) {
        BackendDB *be;
        struct berval monitordn = BER_BVC("cn=monitor");
        int rc;

        be = select_backend( &monitordn, 0 );

        /* FIXME: implement proper subsys shutdown in back-monitor or make
         * backend just an entry, not a subsys */
        rc = b->b_monitor->mss_destroy( be, b->b_monitor );
        assert( rc == LDAP_SUCCESS );
    }
#endif /* BALANCER_MODULE */
616
    ldap_pvt_thread_mutex_destroy( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
617

618
619
620
621
622
    if ( b->b_retry_event ) {
        event_del( b->b_retry_event );
        event_free( b->b_retry_event );
        b->b_retry_event = NULL;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
623

624
625
    ch_free( b->b_host );
    ch_free( b->b_uri.bv_val );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
626
    ch_free( b->b_name.bv_val );
627
628
629
630
631
632
633
634
    ch_free( b );
}

void
lload_backends_destroy( void )
{
    while ( !LDAP_CIRCLEQ_EMPTY( &backend ) ) {
        LloadBackend *b = LDAP_CIRCLEQ_FIRST( &backend );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
635

636
        lload_backend_destroy( b );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
637
638
    }
}