backend.c 19.5 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
    epoch_t epoch;
37
38
39
40
41

    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 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
42
43
44
45
46
47

    if ( s != conn->fd ) {
        /* backend_reset has been here first */
        goto preempted;
    }

48
49
    epoch = epoch_join();

50
51
52
53
54
55
56
57
58
    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 );
59
            epoch_leave( epoch );
60
61
62
            return;
        } else if ( error ) {
            goto done;
63
        } else if ( upstream_init( s, conn->backend ) == NULL ) {
64
65
66
67
68
69
            goto done;
        }
        rc = LDAP_SUCCESS;
    }

done:
70
71
    epoch_leave( epoch );

72
    LDAP_LIST_REMOVE( conn, next );
73
74
    if ( rc ) {
        evutil_closesocket( conn->fd );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
75
        b->b_opening--;
76
        b->b_failed++;
77
78
79
80
81
82
83
84
85
86
87
        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) ) : "" );
        }
88
        backend_retry( b );
89
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
90
preempted:
91
92
93
94
95
96
    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
97
98
99
static void
upstream_name_cb( int result, struct evutil_addrinfo *res, void *arg )
{
100
    LloadBackend *b = arg;
101
    ber_socket_t s = AC_SOCKET_INVALID;
102
    epoch_t epoch;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
103
104
    int rc;

105
106
107
108
109
    if ( result == EVUTIL_EAI_CANCEL ) {
        Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                "cancelled\n" );
        return;
    }
110

111
112
113
114
115
116
117
118
    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;
    }
119
    b->b_dns_req = NULL;
120

121
    epoch = epoch_join();
Ondřej Kuzník's avatar
Ondřej Kuzník committed
122
123
124
    if ( result || !res ) {
        Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                "name resolution failed for backend '%s': %s\n",
125
                b->b_uri.bv_val, evutil_gai_strerror( result ) );
126
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
127
128
    }

129
130
131
132
    /* 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
133
134
    }

135
136
    if ( ber_pvt_socket_set_nonblock( s, 1 ) ) {
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
137
138
139
140
141
142
143
144
145
146
147
    }

    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 );
    }
148
149
    /* Asynchronous connect */
    if ( rc ) {
150
        LloadPendingConnection *conn;
151
152
153
154
155
156
157
158
159

        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;
        }

160
        conn = ch_calloc( 1, sizeof(LloadPendingConnection) );
161
162
163
164
        LDAP_LIST_ENTRY_INIT( conn, next );
        conn->backend = b;
        conn->fd = s;

165
        conn->event = event_new( lload_get_base( s ), s, EV_WRITE|EV_PERSIST,
166
167
168
169
170
171
172
173
174
175
                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;
        }

176
        event_add( conn->event, lload_timeout_net );
177
178
179
        LDAP_LIST_INSERT_HEAD( &b->b_connecting, conn, next );
        Debug( LDAP_DEBUG_CONNS, "upstream_name_cb: "
                "connection to backend uri=%s in progress\n",
180
                b->b_uri.bv_val );
181
    } else if ( upstream_init( s, b ) == NULL ) {
182
183
        goto fail;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
184

Ondřej Kuzník's avatar
Ondřej Kuzník committed
185
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
186
    evutil_freeaddrinfo( res );
187
    epoch_leave( epoch );
188
189
190
191
192
193
194
    return;

fail:
    if ( s != AC_SOCKET_INVALID ) {
        evutil_closesocket( s );
    }
    b->b_opening--;
195
    b->b_failed++;
196
    backend_retry( b );
197
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
198
199
200
    if ( res ) {
        evutil_freeaddrinfo( res );
    }
201
    epoch_leave( epoch );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
202
203
}

204
LloadConnection *
205
backend_select( LloadOperation *op, int *res )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
206
{
207
    LloadBackend *b, *first, *next;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
208
209
210
211
212

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

213
214
    *res = LDAP_UNAVAILABLE;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
215
216
217
    if ( !first ) {
        return NULL;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
218

219
220
    /* 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
221
    do {
222
223
        lload_c_head *head;
        LloadConnection *c;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
224

Ondřej Kuzník's avatar
Ondřej Kuzník committed
225
        ldap_pvt_thread_mutex_lock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
226
        next = LDAP_CIRCLEQ_LOOP_NEXT( &backend, b, b_next );
227
228
229
230

        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",
231
                    b->b_uri.bv_val );
232
            ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
233
            b = next;
234
            *res = LDAP_BUSY;
235
236
237
            continue;
        }

238
239
240
241
242
        if ( op->o_tag == LDAP_REQ_BIND
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
                && !(lload_features & LLOAD_FEATURE_VC)
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
        ) {
243
244
245
246
            head = &b->b_bindconns;
        } else {
            head = &b->b_conns;
        }
247
248
249
        if ( !LDAP_CIRCLEQ_EMPTY( head ) ) {
            *res = LDAP_BUSY;
        }
250

251
        LDAP_CIRCLEQ_FOREACH ( c, head, c_next ) {
252
            ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
253
            CONNECTION_LOCK(c);
254
            if ( c->c_state == LLOAD_C_READY && !c->c_pendingber &&
255
256
                    ( b->b_max_conn_pending == 0 ||
                            c->c_n_ops_executing < b->b_max_conn_pending ) ) {
257
                Debug( LDAP_DEBUG_CONNS, "backend_select: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
258
259
                        "selected connection connid=%lu for client "
                        "connid=%lu msgid=%d\n",
260
261
                        c->c_connid, op->o_client_connid, op->o_client_msgid );

262
263
264
                /* c_state is DYING if we're about to be unlinked */
                assert( IS_ALIVE( c, c_live ) );

265
266
                /*
                 * Round-robin step:
Ondřej Kuzník's avatar
Ondřej Kuzník committed
267
268
                 * Rotate the queue to put this connection at the end, same for
                 * the backend.
269
270
271
                 */
                LDAP_CIRCLEQ_MAKE_TAIL( head, c, c_next );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
272
273
274
275
                ldap_pvt_thread_mutex_lock( &backend_mutex );
                current_backend = next;
                ldap_pvt_thread_mutex_unlock( &backend_mutex );

276
                b->b_n_ops_executing++;
277
278
279
280
281
                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++;
                }
282
                c->c_n_ops_executing++;
283
                c->c_counters.lc_ops_received++;
284

285
                ldap_pvt_thread_mutex_unlock( &b->b_mutex );
286
                *res = LDAP_SUCCESS;
287
288
                return c;
            }
289
            CONNECTION_UNLOCK(c);
290
            ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
291
        }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
292
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
293
294
295

        b = next;
    } while ( b != first );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
296
297
298
299

    return NULL;
}

300
301
302
303
/*
 * 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.
 */
304
void
305
backend_retry( LloadBackend *b )
306
{
307
    int requested;
308

Ondřej Kuzník's avatar
Ondřej Kuzník committed
309
310
311
312
313
314
    if ( slapd_shutdown ) {
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "shutting down\n" );
        return;
    }

315
    requested = b->b_numconns;
316
317
318
319
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
    if ( !(lload_features & LLOAD_FEATURE_VC) )
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
    {
320
321
        requested += b->b_numbindconns;
    }
322
323

    if ( b->b_active + b->b_bindavail + b->b_opening >= requested ) {
324
325
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "no more connections needed for this backend\n" );
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
        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 );
361
362
363
    }
}

364
365
void
backend_connect( evutil_socket_t s, short what, void *arg )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
366
367
{
    struct evutil_addrinfo hints = {};
368
    LloadBackend *b = arg;
369
    struct evdns_getaddrinfo_request *request, *placeholder;
370
    char *hostname;
371
    epoch_t epoch;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
372

373
374
375
376
377
378
379
    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
380
381
382
    if ( slapd_shutdown ) {
        Debug( LDAP_DEBUG_CONNS, "backend_connect: "
                "doing nothing, shutdown in progress\n" );
383
384
        b->b_opening--;
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
385
386
387
        return;
    }

388
389
    epoch = epoch_join();

390
    Debug( LDAP_DEBUG_CONNS, "backend_connect: "
391
392
            "%sattempting connection to %s\n",
            (what & EV_TIMEOUT) ? "retry timeout finished, " : "",
393
394
            b->b_host );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
395
396
397
398
399
400
401
#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 ) {
402
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
403
404
405
406
407
        }

        rc = ber_pvt_socket_set_nonblock( s, 1 );
        if ( rc ) {
            evutil_closesocket( s );
408
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
409
410
411
412
        }

        if ( strlen( b->b_host ) > ( sizeof(addr.sun_path) - 1 ) ) {
            evutil_closesocket( s );
413
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
414
415
416
417
418
419
420
        }
        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) );
421
422
        /* Asynchronous connect */
        if ( rc ) {
423
            LloadPendingConnection *conn;
424
425
426
427
428
429

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

430
            conn = ch_calloc( 1, sizeof(LloadPendingConnection) );
431
432
433
434
            LDAP_LIST_ENTRY_INIT( conn, next );
            conn->backend = b;
            conn->fd = s;

435
            conn->event = event_new( lload_get_base( s ), s,
436
437
438
439
440
441
442
443
444
445
                    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;
            }

446
            event_add( conn->event, lload_timeout_net );
447
448
449
450
            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 );
451
        } else if ( upstream_init( s, b ) == NULL ) {
452
453
            goto fail;
        }
454

455
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
456
        epoch_leave( epoch );
457
        return;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
458
459
460
461
462
463
464
465
    }
#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;

466
    hostname = b->b_host;
467
468
469
470
471
472
473
474
475
476

    /*
     * 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;
477
478
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );

479
    request = evdns_getaddrinfo(
480
            dnsbase, hostname, NULL, &hints, upstream_name_cb, b );
481
482
483
484
485
486
487
488
489
490
491

    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 );
492
    epoch_leave( epoch );
493
    return;
494
495
496

fail:
    b->b_opening--;
497
    b->b_failed++;
498
    backend_retry( b );
499
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
500
    epoch_leave( epoch );
501
502
503
504
505
506
507
}

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
508
}
Ondřej Kuzník's avatar
Ondřej Kuzník committed
509

510
/*
Ondřej Kuzník's avatar
Ondřej Kuzník committed
511
512
513
514
515
 * Needs exclusive access to the backend and no other thread is allowed to call
 * backend_retry while we're handling this.
 *
 * If gentle == 0, a full pause must be in effect, else we risk deadlocking on
 * event_free().
516
 */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
517
void
Ondřej Kuzník's avatar
Ondřej Kuzník committed
518
backend_reset( LloadBackend *b, int gentle )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
519
{
520
    if ( b->b_cookie ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
521
522
523
524
525
526
527
528
529
530
531
532
533
534
        if ( ldap_pvt_thread_pool_retract( b->b_cookie ) ) {
            b->b_cookie = NULL;
            b->b_opening--;
        } else {
            /*
             * The task might not be cancelable because it just started
             * executing.
             *
             * Shutdown should be the only time when the thread pool is
             * in that state. Keep the cookie in to keep an eye on whether
             * it's finished yet.
             */
            assert( slapd_shutdown );
        }
535
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
536
537
    /* Not safe to hold our mutex and call event_del/free if the event's
     * callback is running, relinquish the mutex while we do so. */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
538
539
    if ( b->b_retry_event &&
            event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) {
540
        assert( b->b_failed );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
541
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
542
        event_del( b->b_retry_event );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
543
        ldap_pvt_thread_mutex_lock( &b->b_mutex );
544
545
546
547
548
549
550
        b->b_opening--;
    }
    if ( b->b_dns_req ) {
        evdns_getaddrinfo_cancel( b->b_dns_req );
        b->b_dns_req = NULL;
        b->b_opening--;
    }
551
552
    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
553

554
555
556
        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
557

Ondřej Kuzník's avatar
Ondřej Kuzník committed
558
        event_active( pending->event, EV_WRITE, 0 );
559
        evutil_closesocket( pending->fd );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
560
        pending->fd = -1;
561
        LDAP_LIST_REMOVE( pending, next );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
562
563
564
565
566
567
568
569

        if ( !gentle ) {
            /* None of the event bases are running, we're safe to free the
             * event right now and potentially free the backend itself */
            event_free( pending->event );
            ch_free( pending );
        }
        /* else, just let the event dispose of the resources on its own later */
570
        b->b_opening--;
571
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
572
573
574
    connections_walk(
            &b->b_mutex, &b->b_preparing, lload_connection_close, &gentle );
    assert( LDAP_CIRCLEQ_EMPTY( &b->b_preparing ) );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
575
    assert( b->b_opening == ( b->b_cookie ? 1 : 0 ) );
576
    b->b_failed = 0;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
577
578
579
580
581
582
583
584

    connections_walk_last( &b->b_mutex, &b->b_bindconns, b->b_last_bindconn,
            lload_connection_close, &gentle );
    assert( gentle || b->b_bindavail == 0 );

    connections_walk_last( &b->b_mutex, &b->b_conns, b->b_last_conn,
            lload_connection_close, &gentle );
    assert( gentle || b->b_active == 0 );
585
}
586

587
588
589
590
void
lload_backend_destroy( LloadBackend *b )
{
    LloadBackend *next = LDAP_CIRCLEQ_LOOP_NEXT( &backend, b, b_next );
591

592
593
594
595
    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 );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
596
    ldap_pvt_thread_mutex_lock( &b->b_mutex );
597
    b->b_numconns = b->b_numbindconns = 0;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
598
    backend_reset( b, 0 );
599
600
601
602
603
604
605
606

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

607
608
609
610
611
612
613
614
615
616
617
618
619
620
#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 */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
621
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
622
    ldap_pvt_thread_mutex_destroy( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
623

624
625
626
627
628
    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
629

630
631
    ch_free( b->b_host );
    ch_free( b->b_uri.bv_val );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
632
    ch_free( b->b_name.bv_val );
633
634
635
636
637
638
639
640
    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
641

642
        lload_backend_destroy( b );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
643
644
    }
}