backend.c 14.7 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
28
29
/* $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"
#include "slap.h"

30
31
32
33
34
static void
upstream_connect_cb( evutil_socket_t s, short what, void *arg )
{
    PendingConnection *conn = arg;
    Backend *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
53
54
55
56
57
58
59
60

    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;
        } else if ( !upstream_init( s, conn->backend ) ) {
            goto done;
        }
        rc = LDAP_SUCCESS;
    }

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

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

90
91
    ldap_pvt_thread_mutex_lock( &b->b_mutex );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
92
93
94
    if ( result || !res ) {
        Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                "name resolution failed for backend '%s': %s\n",
95
                b->b_uri.bv_val, evutil_gai_strerror( result ) );
96
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
97
98
    }

99
100
101
102
    /* 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
103
104
    }

105
106
    if ( ber_pvt_socket_set_nonblock( s, 1 ) ) {
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
107
108
109
110
111
112
113
114
115
116
117
    }

    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 );
    }
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
    /* Asynchronous connect */
    if ( rc ) {
        PendingConnection *conn;

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

        conn = ch_calloc( 1, sizeof(PendingConnection) );
        LDAP_LIST_ENTRY_INIT( conn, next );
        conn->backend = b;
        conn->fd = s;

        conn->event = event_new( slap_get_base( s ), s, EV_WRITE|EV_PERSIST,
                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;
        }

146
        event_add( conn->event, lload_timeout_net );
147
148
149
        LDAP_LIST_INSERT_HEAD( &b->b_connecting, conn, next );
        Debug( LDAP_DEBUG_CONNS, "upstream_name_cb: "
                "connection to backend uri=%s in progress\n",
150
                b->b_uri.bv_val );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
151
    } else if ( !upstream_init( s, b ) ) {
152
153
        goto fail;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
154

Ondřej Kuzník's avatar
Ondřej Kuzník committed
155
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
156
    evutil_freeaddrinfo( res );
157
158
159
160
161
162
163
    return;

fail:
    if ( s != AC_SOCKET_INVALID ) {
        evutil_closesocket( s );
    }
    b->b_opening--;
164
    b->b_failed++;
165
166
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
    backend_retry( b );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
167
168
169
    if ( res ) {
        evutil_freeaddrinfo( res );
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
170
171
172
173
174
}

Connection *
backend_select( Operation *op )
{
Ondřej Kuzník's avatar
Ondřej Kuzník committed
175
176
177
178
179
180
181
182
183
    Backend *b, *first, *next;

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

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

185
186
    /* 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
187
    do {
188
        struct ConnSt *head;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
189
190
        Connection *c;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
191
        ldap_pvt_thread_mutex_lock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
192
        next = LDAP_CIRCLEQ_LOOP_NEXT( &backend, b, b_next );
193
194
195
196

        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",
197
                    b->b_uri.bv_val );
198
            ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
199
            b = next;
200
201
202
            continue;
        }

203
204
205
206
207
        if ( op->o_tag == LDAP_REQ_BIND
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
                && !(lload_features & LLOAD_FEATURE_VC)
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
        ) {
208
209
210
211
212
            head = &b->b_bindconns;
        } else {
            head = &b->b_conns;
        }

213
        LDAP_CIRCLEQ_FOREACH ( c, head, c_next ) {
214
            ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
215
            CONNECTION_LOCK(c);
216
            if ( c->c_state == LLOAD_C_READY && !c->c_pendingber &&
217
218
                    ( b->b_max_conn_pending == 0 ||
                            c->c_n_ops_executing < b->b_max_conn_pending ) ) {
219
                Debug( LDAP_DEBUG_CONNS, "backend_select: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
220
221
                        "selected connection connid=%lu for client "
                        "connid=%lu msgid=%d\n",
222
223
                        c->c_connid, op->o_client_connid, op->o_client_msgid );

224
225
                /*
                 * Round-robin step:
Ondřej Kuzník's avatar
Ondřej Kuzník committed
226
227
                 * Rotate the queue to put this connection at the end, same for
                 * the backend.
228
229
230
                 */
                LDAP_CIRCLEQ_MAKE_TAIL( head, c, c_next );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
231
232
233
234
                ldap_pvt_thread_mutex_lock( &backend_mutex );
                current_backend = next;
                ldap_pvt_thread_mutex_unlock( &backend_mutex );

235
236
                b->b_n_ops_executing++;
                c->c_n_ops_executing++;
237
                CONNECTION_UNLOCK_INCREF(c);
238

239
240
241
                ldap_pvt_thread_mutex_unlock( &b->b_mutex );
                return c;
            }
242
            CONNECTION_UNLOCK(c);
243
            ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
244
        }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
245
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
246
247
248

        b = next;
    } while ( b != first );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
249
250
251
252

    return NULL;
}

253
254
255
256
257
void
backend_retry( Backend *b )
{
    int rc, requested;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
258
259
260
261
262
263
    if ( slapd_shutdown ) {
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "shutting down\n" );
        return;
    }

264
265
266
    ldap_pvt_thread_mutex_lock( &b->b_mutex );

    requested = b->b_numconns;
267
268
269
270
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
    if ( !(lload_features & LLOAD_FEATURE_VC) )
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
    {
271
272
273
        requested += b->b_numbindconns;
    }
    if ( b->b_active + b->b_bindavail + b->b_opening < requested ) {
274
        if ( b->b_opening > 0 || b->b_failed > 0 ) {
275
276
            if ( b->b_failed > 0 &&
                    !event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) {
277
278
279
280
281
282
283
284
285
                Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                        "scheduling a retry in %d ms\n",
                        b->b_retry_timeout );
                b->b_opening++;
                event_add( b->b_retry_event, &b->b_retry_tv );
                ldap_pvt_thread_mutex_unlock( &b->b_mutex );
                return;
            } else {
                Debug( LDAP_DEBUG_CONNS, "backend_retry: "
286
                        "retry in progress already\n" );
287
288
289
290
291
292
293
294
295
296
297
298
            }
        } else {
            Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                    "scheduling re-connection straight away\n" );
            b->b_opening++;
            rc = ldap_pvt_thread_pool_submit(
                    &connection_pool, backend_connect_task, b );
            if ( rc ) {
                ldap_pvt_thread_mutex_unlock( &b->b_mutex );
                backend_connect( -1, 0, b );
                return;
            }
299
        }
300
301
302
    } else {
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "no more connections needed for this backend\n" );
303
304
305
306
    }
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
}

307
308
void
backend_connect( evutil_socket_t s, short what, void *arg )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
309
310
{
    struct evutil_addrinfo hints = {};
311
    Backend *b = arg;
312
    char *hostname;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
313

Ondřej Kuzník's avatar
Ondřej Kuzník committed
314
315
316
317
318
319
    if ( slapd_shutdown ) {
        Debug( LDAP_DEBUG_CONNS, "backend_connect: "
                "doing nothing, shutdown in progress\n" );
        return;
    }

320
    ldap_pvt_thread_mutex_lock( &b->b_mutex );
321
    Debug( LDAP_DEBUG_CONNS, "backend_connect: "
322
323
            "%sattempting connection to %s\n",
            (what & EV_TIMEOUT) ? "retry timeout finished, " : "",
324
325
            b->b_host );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
326
327
328
329
330
331
332
#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 ) {
333
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
334
335
336
337
338
        }

        rc = ber_pvt_socket_set_nonblock( s, 1 );
        if ( rc ) {
            evutil_closesocket( s );
339
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
340
341
342
343
        }

        if ( strlen( b->b_host ) > ( sizeof(addr.sun_path) - 1 ) ) {
            evutil_closesocket( s );
344
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
345
346
347
348
349
350
351
        }
        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) );
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
        /* Asynchronous connect */
        if ( rc ) {
            PendingConnection *conn;

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

            conn = ch_calloc( 1, sizeof(PendingConnection) );
            LDAP_LIST_ENTRY_INIT( conn, next );
            conn->backend = b;
            conn->fd = s;

            conn->event = event_new( slap_get_base( s ), s,
                    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;
            }

377
            event_add( conn->event, lload_timeout_net );
378
379
380
381
382
            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 );
        } else if ( !upstream_init( s, b ) ) {
383
384
            goto fail;
        }
385

386
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
387
        return;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
388
389
390
391
392
393
394
395
    }
#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;

396
397
398
399
    hostname = b->b_host;
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );

    evdns_getaddrinfo( dnsbase, hostname, NULL, &hints, upstream_name_cb, b );
400
    return;
401
402
403

fail:
    b->b_opening--;
404
    b->b_failed++;
405
406
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
    backend_retry( b );
407
408
409
410
411
412
413
}

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
414
}
Ondřej Kuzník's avatar
Ondřej Kuzník committed
415
416
417
418

void
backends_destroy( void )
{
419
420
    while ( !LDAP_CIRCLEQ_EMPTY( &backend ) ) {
        Backend *b = LDAP_CIRCLEQ_FIRST( &backend );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
421
422
423

        Debug( LDAP_DEBUG_CONNS, "backends_destroy: "
                "destroying backend uri='%s', numconns=%d, numbindconns=%d\n",
424
                b->b_uri.bv_val, b->b_numconns, b->b_numbindconns );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
425

426
427
428
429
430
431
432
433
434
435
436
437
        while ( !LDAP_LIST_EMPTY( &b->b_connecting ) ) {
            PendingConnection *pending = LDAP_LIST_FIRST( &b->b_connecting );

            Debug( LDAP_DEBUG_CONNS, "backends_destroy: "
                    "destroying socket pending connect() fd=%d\n",
                    pending->fd );

            event_free( pending->event );
            evutil_closesocket( pending->fd );
            LDAP_LIST_REMOVE( pending, next );
            ch_free( pending );
        }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
438
439
440
441
442
443
444
445
446
447
448
        while ( !LDAP_CIRCLEQ_EMPTY( &b->b_preparing ) ) {
            Connection *c = LDAP_CIRCLEQ_FIRST( &b->b_preparing );

            CONNECTION_LOCK(c);
            Debug( LDAP_DEBUG_CONNS, "backends_destroy: "
                    "destroying connection being set up connid=%lu\n",
                    c->c_connid );

            assert( c->c_live );
            CONNECTION_DESTROY(c);
        }
449
450
        while ( !LDAP_CIRCLEQ_EMPTY( &b->b_bindconns ) ) {
            Connection *c = LDAP_CIRCLEQ_FIRST( &b->b_bindconns );
451

Ondřej Kuzník's avatar
Ondřej Kuzník committed
452
            CONNECTION_LOCK(c);
453
454
455
456
457
            Debug( LDAP_DEBUG_CONNS, "backends_destroy: "
                    "destroying bind connection connid=%lu, pending ops=%ld\n",
                    c->c_connid, c->c_n_ops_executing );

            assert( c->c_live );
458
            CONNECTION_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
459
        }
460
461
        while ( !LDAP_CIRCLEQ_EMPTY( &b->b_conns ) ) {
            Connection *c = LDAP_CIRCLEQ_FIRST( &b->b_conns );
462

Ondřej Kuzník's avatar
Ondřej Kuzník committed
463
            CONNECTION_LOCK(c);
464
465
466
467
468
469
            Debug( LDAP_DEBUG_CONNS, "backends_destroy: "
                    "destroying regular connection connid=%lu, pending "
                    "ops=%ld\n",
                    c->c_connid, c->c_n_ops_executing );

            assert( c->c_live );
470
            CONNECTION_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
471
472
        }

473
        LDAP_CIRCLEQ_REMOVE( &backend, b, b_next );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
474
475
476
477
478
479
        ldap_pvt_thread_mutex_destroy( &b->b_mutex );

        event_del( b->b_retry_event );
        event_free( b->b_retry_event );

        ch_free( b->b_host );
480
        ch_free( b->b_uri.bv_val );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
481
482
483
        ch_free( b );
    }
}