backend.c 10.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
28
29
30
31
32
33
/* $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"

static void
upstream_name_cb( int result, struct evutil_addrinfo *res, void *arg )
{
    Backend *b = arg;
34
    ber_socket_t s = AC_SOCKET_INVALID;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
35
36
    int rc;

37
38
    ldap_pvt_thread_mutex_lock( &b->b_mutex );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
39
40
41
42
    if ( result || !res ) {
        Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                "name resolution failed for backend '%s': %s\n",
                b->b_bindconf.sb_uri.bv_val, evutil_gai_strerror( result ) );
43
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
44
45
    }

46
47
48
49
    /* 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
50
51
    }

52
53
    if ( ber_pvt_socket_set_nonblock( s, 1 ) ) {
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    }

    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 );
    }
    if ( rc && errno != EINPROGRESS && errno != EWOULDBLOCK ) {
        Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                "failed to connect to server '%s'\n",
                b->b_bindconf.sb_uri.bv_val );
69
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
70
71
    }

72
73
74
75
76
    if ( !upstream_init( s, b ) ) {
        goto fail;
    }
    b->b_opening--;
    b->b_failed = 0;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
77
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
78
    backend_retry( b );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
79
    free( res );
80
81
82
83
84
85
86
    return;

fail:
    if ( s != AC_SOCKET_INVALID ) {
        evutil_closesocket( s );
    }
    b->b_opening--;
87
    b->b_failed++;
88
89
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
    backend_retry( b );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
90
    free( res );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
91
92
93
94
95
}

Connection *
backend_select( Operation *op )
{
Ondřej Kuzník's avatar
Ondřej Kuzník committed
96
97
98
99
100
101
102
103
104
    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
105

106
107
    /* 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
108
    do {
109
        struct ConnSt *head;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
110
111
        Connection *c;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
112
        ldap_pvt_thread_mutex_lock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
113
        next = LDAP_CIRCLEQ_LOOP_NEXT( &backend, b, b_next );
114
115
116
117
118
119

        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",
                    b->b_bindconf.sb_uri.bv_val );
            ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
120
            b = next;
121
122
123
            continue;
        }

124
125
126
127
128
129
130
        if ( op->o_tag == LDAP_REQ_BIND &&
                !(lload_features & LLOAD_FEATURE_VC) ) {
            head = &b->b_bindconns;
        } else {
            head = &b->b_conns;
        }

131
        LDAP_CIRCLEQ_FOREACH ( c, head, c_next ) {
132
            ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
133
            CONNECTION_LOCK(c);
134
135
136
            if ( c->c_state == SLAP_C_READY && !c->c_pendingber &&
                    ( b->b_max_conn_pending == 0 ||
                            c->c_n_ops_executing < b->b_max_conn_pending ) ) {
137
138
                Debug( LDAP_DEBUG_CONNS, "backend_select: "
                        "selected connection %lu for client %lu msgid=%d\n",
139
140
                        c->c_connid, op->o_client_connid, op->o_client_msgid );

141
142
                /*
                 * Round-robin step:
Ondřej Kuzník's avatar
Ondřej Kuzník committed
143
144
                 * Rotate the queue to put this connection at the end, same for
                 * the backend.
145
146
147
                 */
                LDAP_CIRCLEQ_MAKE_TAIL( head, c, c_next );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
148
149
150
151
                ldap_pvt_thread_mutex_lock( &backend_mutex );
                current_backend = next;
                ldap_pvt_thread_mutex_unlock( &backend_mutex );

152
153
                b->b_n_ops_executing++;
                c->c_n_ops_executing++;
154
                CONNECTION_UNLOCK_INCREF(c);
155

156
157
158
                ldap_pvt_thread_mutex_unlock( &b->b_mutex );
                return c;
            }
159
            CONNECTION_UNLOCK(c);
160
            ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
161
        }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
162
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
163
164
165

        b = next;
    } while ( b != first );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
166
167
168
169

    return NULL;
}

170
171
172
173
174
void
backend_retry( Backend *b )
{
    int rc, requested;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
175
176
177
178
179
180
    if ( slapd_shutdown ) {
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "shutting down\n" );
        return;
    }

181
182
183
184
185
186
187
    ldap_pvt_thread_mutex_lock( &b->b_mutex );

    requested = b->b_numconns;
    if ( !(lload_features & LLOAD_FEATURE_VC) ) {
        requested += b->b_numbindconns;
    }
    if ( b->b_active + b->b_bindavail + b->b_opening < requested ) {
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
        if ( b->b_opening > 0 || b->b_failed > 0 ) {
            if ( !event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) {
                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: "
                        "retry already scheduled\n" );
            }
        } 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;
            }
212
        }
213
214
215
    } else {
        Debug( LDAP_DEBUG_CONNS, "backend_retry: "
                "no more connections needed for this backend\n" );
216
217
218
219
    }
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
}

220
221
void
backend_connect( evutil_socket_t s, short what, void *arg )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
222
223
{
    struct evutil_addrinfo hints = {};
224
    Backend *b = arg;
225
    char *hostname;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
226

Ondřej Kuzník's avatar
Ondřej Kuzník committed
227
228
229
230
231
232
    if ( slapd_shutdown ) {
        Debug( LDAP_DEBUG_CONNS, "backend_connect: "
                "doing nothing, shutdown in progress\n" );
        return;
    }

233
    ldap_pvt_thread_mutex_lock( &b->b_mutex );
234
235
236
237
    Debug( LDAP_DEBUG_CONNS, "backend_connect: "
            "attempting connection to %s\n",
            b->b_host );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
238
239
240
241
242
243
244
#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 ) {
245
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
246
247
248
249
250
        }

        rc = ber_pvt_socket_set_nonblock( s, 1 );
        if ( rc ) {
            evutil_closesocket( s );
251
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
252
253
254
255
        }

        if ( strlen( b->b_host ) > ( sizeof(addr.sun_path) - 1 ) ) {
            evutil_closesocket( s );
256
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
257
258
259
260
261
262
263
264
265
        }
        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) );
        if ( rc && errno != EINPROGRESS && errno != EWOULDBLOCK ) {
            evutil_closesocket( s );
266
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
267
268
        }

269
270
271
272
273
        if ( !upstream_init( s, b ) ) {
            goto fail;
        }
        b->b_opening--;
        b->b_failed = 0;
274
275
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
        backend_retry( b );
276
        return;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
277
278
279
280
281
282
283
284
    }
#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;

285
286
287
288
    hostname = b->b_host;
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );

    evdns_getaddrinfo( dnsbase, hostname, NULL, &hints, upstream_name_cb, b );
289
    return;
290
291
292

fail:
    b->b_opening--;
293
    b->b_failed++;
294
295
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
    backend_retry( b );
296
297
298
299
300
301
302
}

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
303
}
Ondřej Kuzník's avatar
Ondřej Kuzník committed
304
305
306
307

void
backends_destroy( void )
{
308
309
    while ( !LDAP_CIRCLEQ_EMPTY( &backend ) ) {
        Backend *b = LDAP_CIRCLEQ_FIRST( &backend );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
310
311
312
313
314

        Debug( LDAP_DEBUG_CONNS, "backends_destroy: "
                "destroying backend uri='%s', numconns=%d, numbindconns=%d\n",
                b->b_bindconf.sb_uri.bv_val, b->b_numconns, b->b_numbindconns );

315
316
        while ( !LDAP_CIRCLEQ_EMPTY( &b->b_bindconns ) ) {
            Connection *c = LDAP_CIRCLEQ_FIRST( &b->b_bindconns );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
317
318
319
            CONNECTION_LOCK(c);
            UPSTREAM_DESTROY(c);
        }
320
321
        while ( !LDAP_CIRCLEQ_EMPTY( &b->b_conns ) ) {
            Connection *c = LDAP_CIRCLEQ_FIRST( &b->b_conns );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
322
323
324
325
            CONNECTION_LOCK(c);
            UPSTREAM_DESTROY(c);
        }

326
        LDAP_CIRCLEQ_REMOVE( &backend, b, b_next );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
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
        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 );
        ch_free( b->b_bindconf.sb_uri.bv_val );
        ch_free( b->b_bindconf.sb_binddn.bv_val );
        ch_free( b->b_bindconf.sb_cred.bv_val );
        ch_free( b->b_bindconf.sb_saslmech.bv_val );
        ch_free( b->b_bindconf.sb_secprops );
        ch_free( b->b_bindconf.sb_realm.bv_val );
        ch_free( b->b_bindconf.sb_authcId.bv_val );
        ch_free( b->b_bindconf.sb_authzId.bv_val );

#ifdef HAVE_TLS
        ch_free( b->b_bindconf.sb_tls_cert );
        ch_free( b->b_bindconf.sb_tls_key );
        ch_free( b->b_bindconf.sb_tls_cacert );
        ch_free( b->b_bindconf.sb_tls_cacertdir );
        ch_free( b->b_bindconf.sb_tls_reqcert );
        ch_free( b->b_bindconf.sb_tls_cipher_suite );
        ch_free( b->b_bindconf.sb_tls_protocol_min );
#ifdef HAVE_OPENSSL_CRL
        ch_free( b->b_bindconf.sb_tls_crlcheck );
#endif
#endif
        ch_free( b );
    }
}