upstream.c 30 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
/* $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 "lutil.h"
#include "slap.h"

Ondřej Kuzník's avatar
Ondřej Kuzník committed
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
static int
forward_response( Operation *op, BerElement *ber )
{
    Connection *c = op->o_client;
    BerElement *output;
    BerValue response, controls = BER_BVNULL;
    ber_tag_t tag, response_tag;
    ber_len_t len;

    response_tag = ber_skip_element( ber, &response );

    tag = ber_peek_tag( ber, &len );
    if ( tag == LDAP_TAG_CONTROLS ) {
        ber_skip_element( ber, &controls );
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
43
    Debug( LDAP_DEBUG_TRACE, "forward_response: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
44
            "%s to client connid=%lu request msgid=%d\n",
45
46
            slap_msgtype2str( response_tag ), op->o_client_connid,
            op->o_client_msgid );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

    ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
    output = c->c_pendingber;
    if ( output == NULL && (output = ber_alloc()) == NULL ) {
        ber_free( ber, 1 );
        ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
        return -1;
    }
    c->c_pendingber = output;

    ber_printf( output, "t{titOtO}", LDAP_TAG_MESSAGE,
            LDAP_TAG_MSGID, op->o_client_msgid,
            response_tag, &response,
            LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &controls ) );

    ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );

    ber_free( ber, 1 );
    client_write_cb( -1, 0, c );
    return 0;
}

static int
forward_final_response( Operation *op, BerElement *ber )
{
    int rc;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
74
    Debug( LDAP_DEBUG_STATS, "forward_final_response: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
75
76
77
            "connid=%lu msgid=%d finishing up with a request for "
            "client connid=%lu\n",
            op->o_upstream_connid, op->o_upstream_msgid, op->o_client_connid );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
78
    rc = forward_response( op, ber );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
79
80
81
    CONNECTION_LOCK_DECREF(op->o_upstream);
    operation_destroy_from_upstream( op );
    CONNECTION_UNLOCK_INCREF(op->o_upstream);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
82
83
84
85
86
87
88

    return rc;
}

static int
handle_bind_response( Operation *op, BerElement *ber )
{
Ondřej Kuzník's avatar
Ondřej Kuzník committed
89
    Connection *client = op->o_client, *upstream = op->o_upstream;
90
    BerValue response;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
91
    BerElement *copy;
92
    ber_int_t result;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
93
    ber_tag_t tag;
94
    int rc = LDAP_SUCCESS;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
95

96
    if ( (copy = ber_alloc()) == NULL ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
97
98
99
100
        rc = -1;
        goto done;
    }

101
102
103
104
105
106
    tag = ber_peek_element( ber, &response );
    assert( tag == LDAP_RES_BIND );

    ber_init2( copy, &response, 0 );

    tag = ber_get_enum( copy, &result );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
107
108
109
110
111
112
113
    ber_free( copy, 0 );

    if ( tag == LBER_ERROR ) {
        rc = -1;
        goto done;
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
114
115
116
117
    Debug( LDAP_DEBUG_STATS, "handle_bind_response: "
            "received response for bind request msgid=%d by client "
            "connid=%lu, result=%d\n",
            op->o_client_msgid, op->o_client_connid, result );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
118

Ondřej Kuzník's avatar
Ondřej Kuzník committed
119
120
121
122
123
124
125
    CONNECTION_LOCK(upstream);
    if ( result != LDAP_SASL_BIND_IN_PROGRESS ) {
        upstream->c_state = SLAP_C_READY;
    }
    CONNECTION_UNLOCK(upstream);

    CONNECTION_LOCK(client);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
126
127
128
129
130
    switch ( result ) {
        case LDAP_SASL_BIND_IN_PROGRESS:
            break;
        case LDAP_SUCCESS:
        default: {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
131
132
            client->c_state = SLAP_C_READY;
            client->c_type = SLAP_C_OPEN;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
133
            if ( result != LDAP_SUCCESS ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
134
135
136
137
138
                ber_memfree( client->c_auth.bv_val );
                BER_BVZERO( &client->c_auth );
            } else if ( !ber_bvstrcasecmp(
                                &client->c_auth, &lloadd_identity ) ) {
                client->c_type = SLAP_C_PRIVILEGED;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
139
            }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
140
141
142
            if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) {
                ber_memfree( client->c_sasl_bind_mech.bv_val );
                BER_BVZERO( &client->c_sasl_bind_mech );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
143
144
145
146
            }
            break;
        }
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
147
    CONNECTION_UNLOCK(client);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
148
149
150

done:
    if ( rc ) {
151
        operation_send_reject( op, LDAP_OTHER, "internal error", 0 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
152

Ondřej Kuzník's avatar
Ondřej Kuzník committed
153
        ber_free( ber, 1 );
154
        return LDAP_SUCCESS;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
155
156
157
158
    }
    return forward_final_response( op, ber );
}

159
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
Ondřej Kuzník's avatar
Ondřej Kuzník committed
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
static int
handle_vc_bind_response( Operation *op, BerElement *ber )
{
    Connection *c = op->o_client;
    BerElement *output;
    BerValue matched, diagmsg, creds = BER_BVNULL, controls = BER_BVNULL;
    ber_int_t result;
    ber_tag_t tag;
    ber_len_t len;
    int rc = 0;

    tag = ber_scanf( ber, "{emm" /* "}" */,
            &result, &matched, &diagmsg );
    if ( tag == LBER_ERROR ) {
        rc = -1;
        goto done;
    }

    tag = ber_peek_tag( ber, &len );
    if ( result == LDAP_PROTOCOL_ERROR ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
180
181
182
        Connection *upstream = op->o_upstream;
        Backend *b;

183
        CONNECTION_LOCK(upstream);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
184
        b = (Backend *)upstream->c_private;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
185
186
        Debug( LDAP_DEBUG_ANY, "handle_vc_bind_response: "
                "VC extended operation not supported on backend %s\n",
187
                b->b_uri.bv_val );
188
        CONNECTION_UNLOCK(upstream);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
189
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
190

Ondřej Kuzník's avatar
Ondřej Kuzník committed
191
192
193
194
    Debug( LDAP_DEBUG_STATS, "handle_vc_bind_response: "
            "received response for bind request msgid=%d by client "
            "connid=%lu, result=%d\n",
            op->o_client_msgid, op->o_client_connid, result );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
195

Ondřej Kuzník's avatar
Ondřej Kuzník committed
196
    CONNECTION_LOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
197
198
199
200
201
202
203
204

    if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE ) {
        if ( !BER_BVISNULL( &c->c_vc_cookie ) ) {
            ber_memfree( c->c_vc_cookie.bv_val );
        }
        tag = ber_scanf( ber, "o", &c->c_vc_cookie );
        if ( tag == LBER_ERROR ) {
            rc = -1;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
205
            CONNECTION_UNLOCK_INCREF(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
206
207
208
209
210
211
212
213
214
            goto done;
        }
        tag = ber_peek_tag( ber, &len );
    }

    if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_SCREDS ) {
        tag = ber_scanf( ber, "m", &creds );
        if ( tag == LBER_ERROR ) {
            rc = -1;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
215
            CONNECTION_UNLOCK_INCREF(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
216
217
218
219
220
221
222
223
224
            goto done;
        }
        tag = ber_peek_tag( ber, &len );
    }

    if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS ) {
        tag = ber_scanf( ber, "m", &controls );
        if ( tag == LBER_ERROR ) {
            rc = -1;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
225
            CONNECTION_UNLOCK_INCREF(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
226
227
228
229
230
231
232
233
234
235
            goto done;
        }
    }

    switch ( result ) {
        case LDAP_SASL_BIND_IN_PROGRESS:
            break;
        case LDAP_SUCCESS:
        default: {
            c->c_state = SLAP_C_READY;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
236
            c->c_type = SLAP_C_OPEN;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
237
238
239
            if ( result != LDAP_SUCCESS ) {
                ber_memfree( c->c_auth.bv_val );
                BER_BVZERO( &c->c_auth );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
240
241
            } else if ( !ber_bvstrcasecmp( &c->c_auth, &lloadd_identity ) ) {
                c->c_type = SLAP_C_PRIVILEGED;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
242
243
244
245
246
247
248
249
250
251
252
253
            }
            if ( !BER_BVISNULL( &c->c_vc_cookie ) ) {
                ber_memfree( c->c_vc_cookie.bv_val );
                BER_BVZERO( &c->c_vc_cookie );
            }
            if ( !BER_BVISNULL( &c->c_sasl_bind_mech ) ) {
                ber_memfree( c->c_sasl_bind_mech.bv_val );
                BER_BVZERO( &c->c_sasl_bind_mech );
            }
            break;
        }
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
254
    CONNECTION_UNLOCK_INCREF(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

    ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
    output = c->c_pendingber;
    if ( output == NULL && (output = ber_alloc()) == NULL ) {
        rc = -1;
        ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
        goto done;
    }
    c->c_pendingber = output;

    rc = ber_printf( output, "t{tit{eOOtO}tO}", LDAP_TAG_MESSAGE,
            LDAP_TAG_MSGID, op->o_client_msgid, LDAP_RES_BIND,
            result, &matched, &diagmsg,
            LDAP_TAG_SASL_RES_CREDS, BER_BV_OPTIONAL( &creds ),
            LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &controls ) );

    ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
    if ( rc >= 0 ) {
        client_write_cb( -1, 0, c );
        rc = 0;
    }

done:
Ondřej Kuzník's avatar
Ondřej Kuzník committed
278
279
280
    CONNECTION_LOCK_DECREF(c);
    operation_destroy_from_client( op );
    CLIENT_UNLOCK_OR_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
281
282
283
    ber_free( ber, 1 );
    return rc;
}
284
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
285
286
287
288

static int
handle_unsolicited( Connection *c, BerElement *ber )
{
289
    c->c_state = SLAP_C_CLOSING;
290

Ondřej Kuzník's avatar
Ondřej Kuzník committed
291
    Debug( LDAP_DEBUG_CONNS, "handle_unsolicited: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
292
            "teardown for upstream connection connid=%lu\n",
Ondřej Kuzník's avatar
Ondřej Kuzník committed
293
294
            c->c_connid );

295
    UPSTREAM_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
    ber_free( ber, 1 );

    return -1;
}

/*
 * Pull c->c_currentber from the connection and try to look up the operation on
 * the upstream.
 *
 * If it's a notice of disconnection, we won't find it and need to tear down
 * the connection and tell the clients, if we can't find the operation, ignore
 * the message (either client already disconnected/abandoned it or the upstream
 * is pulling our leg).
 *
 * Some responses need special handling:
 * - Bind response
 * - VC response where the client requested a Bind (both need to update the
 *   client's bind status)
 * - search entries/referrals and intermediate responses (will not trigger
 *   operation to be removed)
 *
 * If the worker pool is overloaded, we might be called directly from
 * upstream_read_cb, at that point, the connection hasn't been muted.
 *
 * TODO: when the client already has data pending on write, we should mute the
 * upstream.
 * - should record the BerElement on the Op and the Op on the client
Ondřej Kuzník's avatar
Ondřej Kuzník committed
323
324
325
326
327
 *
 * The following hold on entering any of the handlers:
 * - op->o_upstream_refcnt > 0
 * - op->o_upstream->c_refcnt > 0
 * - op->o_client->c_refcnt > 0
Ondřej Kuzník's avatar
Ondřej Kuzník committed
328
329
330
331
332
 */
static int
handle_one_response( Connection *c )
{
    BerElement *ber;
333
    Operation *op = NULL, needle = { .o_upstream_connid = c->c_connid };
Ondřej Kuzník's avatar
Ondřej Kuzník committed
334
335
336
    OperationHandler handler = NULL;
    ber_tag_t tag;
    ber_len_t len;
337
    int rc = LDAP_SUCCESS;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353

    ber = c->c_currentber;
    c->c_currentber = NULL;

    tag = ber_get_int( ber, &needle.o_upstream_msgid );
    if ( tag != LDAP_TAG_MSGID ) {
        rc = -1;
        ber_free( ber, 1 );
        goto fail;
    }

    if ( needle.o_upstream_msgid == 0 ) {
        return handle_unsolicited( c, ber );
    } else if ( !( op = tavl_find(
                           c->c_ops, &needle, operation_upstream_cmp ) ) ) {
        /* Already abandoned, do nothing */
354
355
        ber_free( ber, 1 );
        return rc;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
        /*
    } else if ( op->o_response_pending ) {
        c->c_pendingop = op;
        event_del( c->c_read_event );
    */
    } else {
        /*
        op->o_response_pending = ber;
        */

        tag = ber_peek_tag( ber, &len );
        switch ( tag ) {
            case LDAP_RES_SEARCH_ENTRY:
            case LDAP_RES_SEARCH_REFERENCE:
            case LDAP_RES_INTERMEDIATE:
                handler = forward_response;
                break;
            case LDAP_RES_BIND:
                handler = handle_bind_response;
                break;
            case LDAP_RES_EXTENDED:
377
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
Ondřej Kuzník's avatar
Ondřej Kuzník committed
378
379
380
                if ( op->o_tag == LDAP_REQ_BIND ) {
                    handler = handle_vc_bind_response;
                }
381
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
382
383
384
385
386
387
388
                break;
        }
        if ( !handler ) {
            handler = forward_final_response;
        }
    }
    if ( op ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
389
        Debug( LDAP_DEBUG_STATS2, "handle_one_response: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
390
391
                "upstream connid=%lu, processing response for "
                "client connid=%lu, msgid=%d\n",
392
                c->c_connid, op->o_client_connid, op->o_client_msgid );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
393
394
    } else {
        tag = ber_peek_tag( ber, &len );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
395
396
397
        Debug( LDAP_DEBUG_STATS2, "handle_one_response: "
                "upstream connid=%lu, %s, msgid=%d not for a pending "
                "operation\n",
Ondřej Kuzník's avatar
Ondřej Kuzník committed
398
399
400
401
                c->c_connid, slap_msgtype2str( tag ), needle.o_upstream_msgid );
    }

    if ( handler ) {
402
403
        Connection *client;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
404
405
        op->o_upstream_refcnt++;
        CONNECTION_UNLOCK_INCREF(c);
406
407
408
409
410

        ldap_pvt_thread_mutex_lock( &operation_mutex );
        client = op->o_client;
        if ( client ) {
            CONNECTION_LOCK(client);
411
            op->o_client_refcnt++;
412
413
414
415
416
417
418
            CONNECTION_UNLOCK_INCREF(client);
        }
        ldap_pvt_thread_mutex_unlock( &operation_mutex );

        if ( client ) {
            rc = handler( op, ber );
            CONNECTION_LOCK_DECREF(client);
419
420
421
422
            op->o_client_refcnt--;
            if ( !op->o_client_refcnt ) {
                operation_destroy_from_client( op );
            }
423
424
425
426
427
            CLIENT_UNLOCK_OR_DESTROY(client);
        } else {
            ber_free( ber, 1 );
        }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
428
429
        CONNECTION_LOCK_DECREF(c);
        op->o_upstream_refcnt--;
430
        if ( !client || !op->o_upstream_refcnt ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
431
432
            operation_destroy_from_upstream( op );
        }
433
434
    } else {
        ber_free( ber, 1 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
435
436
437
438
    }

fail:
    if ( rc ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
439
440
441
442
        Debug( LDAP_DEBUG_STATS, "handle_one_response: "
                "error on processing a response (%s) on upstream connection "
                "connid=%ld, tag=%lx\n",
                slap_msgtype2str( tag ), c->c_connid, tag );
443
        UPSTREAM_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
444
    }
445
    /* We leave the connection locked */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
    return rc;
}

/*
 * We start off with the upstream muted and c_currentber holding the response
 * we received.
 *
 * We run handle_one_response on each response, stopping once we hit an error,
 * have to wait on reading or process slap_conn_max_pdus_per_cycle responses so
 * as to maintain fairness and not hog the worker thread forever.
 *
 * If we've run out of responses from the upstream or hit the budget, we unmute
 * the connection and run handle_one_response, it might return an 'error' when
 * the client is blocked on writing, it's that client's job to wake us again.
 */
static void *
handle_responses( void *ctx, void *arg )
{
    Connection *c = arg;
    int responses_handled = 0;

467
    CONNECTION_LOCK_DECREF(c);
468
    for ( ;; ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
469
470
471
472
        BerElement *ber;
        ber_tag_t tag;
        ber_len_t len;

473
474
        /* handle_one_response may unlock the connection in the process, we
         * need to expect that might be our responsibility to destroy it */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
475
        if ( handle_one_response( c ) ) {
476
477
            /* Error, connection is unlocked and might already have been
             * destroyed */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
478
479
480
481
            return NULL;
        }
        /* Otherwise, handle_one_response leaves the connection locked */

482
483
484
485
486
        if ( ++responses_handled >= slap_conn_max_pdus_per_cycle ) {
            /* Do not read now, re-enable read event instead */
            break;
        }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
487
488
489
        if ( (ber = ber_alloc()) == NULL ) {
            Debug( LDAP_DEBUG_ANY, "handle_responses: "
                    "ber_alloc failed\n" );
490
            UPSTREAM_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
491
492
493
494
495
496
497
498
499
            return NULL;
        }
        c->c_currentber = ber;

        tag = ber_get_next( c->c_sb, &len, ber );
        if ( tag != LDAP_TAG_MESSAGE ) {
            int err = sock_errno();

            if ( err != EWOULDBLOCK && err != EAGAIN ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
500
501
502
503
504
505
506
507
508
509
510
511
                if ( err || tag == LBER_ERROR ) {
                    char ebuf[128];
                    Debug( LDAP_DEBUG_ANY, "handle_responses: "
                            "ber_get_next on fd=%d failed errno=%d (%s)\n",
                            c->c_fd, err,
                            sock_errstr( err, ebuf, sizeof(ebuf) ) );
                } else {
                    Debug( LDAP_DEBUG_STATS, "handle_responses: "
                            "ber_get_next on fd=%d connid=%lu received "
                            "a strange PDU tag=%lx\n",
                            c->c_fd, c->c_connid, tag );
                }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
512
513
514

                c->c_currentber = NULL;
                ber_free( ber, 1 );
515
                UPSTREAM_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
516
517
518
519
520
521
522
                return NULL;
            }
            break;
        }
    }

    event_add( c->c_read_event, NULL );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
523
524
525
    Debug( LDAP_DEBUG_CONNS, "handle_responses: "
            "re-enabled read event on connid=%lu\n",
            c->c_connid );
526
    UPSTREAM_UNLOCK_OR_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
527
528
529
530
531
532
533
534
535
536
    return NULL;
}

/*
 * Initial read on the upstream connection, if we get an LDAP PDU, submit the
 * processing of this and successive ones to the work queue.
 *
 * If we can't submit it to the queue (overload), process this one and return
 * to the event loop immediately after.
 */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
537
538
539
540
void
upstream_read_cb( evutil_socket_t s, short what, void *arg )
{
    Connection *c = arg;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
541
542
543
    BerElement *ber;
    ber_tag_t tag;
    ber_len_t len;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
544

545
    CONNECTION_LOCK(c);
546
547
    if ( !c->c_live ) {
        event_del( c->c_read_event );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
548
549
550
        Debug( LDAP_DEBUG_CONNS, "upstream_read_cb: "
                "suspended read event on a dead connid=%lu\n",
                c->c_connid );
551
552
553
        CONNECTION_UNLOCK(c);
        return;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
554
    Debug( LDAP_DEBUG_CONNS, "upstream_read_cb: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
555
            "connection connid=%lu ready to read\n",
Ondřej Kuzník's avatar
Ondřej Kuzník committed
556
557
558
559
            c->c_connid );

    ber = c->c_currentber;
    if ( ber == NULL && (ber = ber_alloc()) == NULL ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
560
561
        Debug( LDAP_DEBUG_ANY, "upstream_read_cb: "
                "ber_alloc failed\n" );
562
        UPSTREAM_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
563
564
        return;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
565
    c->c_currentber = ber;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
566
567
568
569
570
571

    tag = ber_get_next( c->c_sb, &len, ber );
    if ( tag != LDAP_TAG_MESSAGE ) {
        int err = sock_errno();

        if ( err != EWOULDBLOCK && err != EAGAIN ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
572
            if ( err || tag == LBER_ERROR ) {
573
574
                char ebuf[128];
                Debug( LDAP_DEBUG_ANY, "upstream_read_cb: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
575
                        "ber_get_next on fd=%d failed errno=%d (%s)\n",
576
577
                        c->c_fd, err,
                        sock_errstr( err, ebuf, sizeof(ebuf) ) );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
578
579
580
581
582
            } else {
                Debug( LDAP_DEBUG_STATS, "upstream_read_cb: "
                        "ber_get_next on fd=%d connid=%lu received "
                        "a strange PDU tag=%lx\n",
                        c->c_fd, c->c_connid, tag );
583
            }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
584
585

            c->c_currentber = NULL;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
586
            ber_free( ber, 1 );
587
588

            event_del( c->c_read_event );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
589
590
591
            Debug( LDAP_DEBUG_CONNS, "upstream_read_cb: "
                    "suspended read event on dying connid=%lu\n",
                    c->c_connid );
592
            UPSTREAM_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
593
            return;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
594
        }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
595
        event_add( c->c_read_event, NULL );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
596
597
598
        Debug( LDAP_DEBUG_CONNS, "upstream_read_cb: "
                "re-enabled read event on connid=%lu\n",
                c->c_connid );
599
        CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
600
601
602
        return;
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
603
604
605
606
    if ( !slap_conn_max_pdus_per_cycle ||
            ldap_pvt_thread_pool_submit(
                    &connection_pool, handle_responses, c ) ) {
        /* If we're overloaded or configured as such, process one and resume in
607
608
609
610
         * the next cycle.
         *
         * handle_one_response re-locks the mutex in the
         * process, need to test it's still alive */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
611
        if ( handle_one_response( c ) == LDAP_SUCCESS ) {
612
            UPSTREAM_UNLOCK_OR_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
613
614
615
616
        }
        return;
    }

617
618
619
620
621
    /* We have scheduled a call to handle_responses which takes care of
     * handling further requests, just make sure the connection sticks around
     * for that */
    event_del( c->c_read_event );
    CONNECTION_UNLOCK_INCREF(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
622
    return;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
623
624
}

625
int
626
627
628
629
630
631
632
upstream_finish( Connection *c )
{
    struct event_base *base;
    struct event *event;
    evutil_socket_t s = c->c_fd;

    Debug( LDAP_DEBUG_CONNS, "upstream_finish: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
633
            "connection connid=%lu is ready for use\n",
Ondřej Kuzník's avatar
Ondřej Kuzník committed
634
            c->c_connid );
635
636
637
638
639

    base = slap_get_base( s );

    event = event_new( base, s, EV_READ|EV_PERSIST, upstream_read_cb, c );
    if ( !event ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
640
641
        Debug( LDAP_DEBUG_ANY, "upstream_finish: "
                "Read event could not be allocated\n" );
642
        return -1;
643
644
645
646
647
648
649
650
651
652
    }
    event_add( event, NULL );
    if ( c->c_read_event ) {
        event_del( c->c_read_event );
        event_free( c->c_read_event );
    }
    c->c_read_event = event;

    c->c_state = SLAP_C_READY;

653
    return 0;
654
655
656
657
658
659
660
}

void
upstream_bind_cb( evutil_socket_t s, short what, void *arg )
{
    Connection *c = arg;
    BerElement *ber;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
661
    BerValue matcheddn, message;
662
663
664
665
    ber_tag_t tag;
    ber_len_t len;
    ber_int_t msgid, result;

666
    CONNECTION_LOCK(c);
667
    Debug( LDAP_DEBUG_CONNS, "upstream_bind_cb: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
668
            "connection connid=%lu ready to read\n",
669
670
671
672
            c->c_connid );

    ber = c->c_currentber;
    if ( ber == NULL && (ber = ber_alloc()) == NULL ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
673
674
        Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                "ber_alloc failed\n" );
675
        CONNECTION_UNLOCK(c);
676
677
        return;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
678
    c->c_currentber = ber;
679
680
681
682
683
684

    tag = ber_get_next( c->c_sb, &len, ber );
    if ( tag != LDAP_TAG_MESSAGE ) {
        int err = sock_errno();

        if ( err != EWOULDBLOCK && err != EAGAIN ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
685
686
687
688
689
690
691
692
693
694
695
696
            if ( err || tag == LBER_ERROR ) {
                char ebuf[128];
                Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                        "ber_get_next on fd=%d failed errno=%d (%s)\n",
                        c->c_fd, err,
                        sock_errstr( err, ebuf, sizeof(ebuf) ) );
            } else {
                Debug( LDAP_DEBUG_STATS, "upstream_bind_cb: "
                        "ber_get_next on fd=%d connid=%lu received "
                        "a strange PDU tag=%lx\n",
                        c->c_fd, c->c_connid, tag );
            }
697
698
699
700

            c->c_currentber = NULL;
            goto fail;
        }
701
        CONNECTION_UNLOCK(c);
702
703
704
705
706
        return;
    }
    c->c_currentber = NULL;

    if ( ber_scanf( ber, "it", &msgid, &tag ) == LBER_ERROR ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
707
708
        Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                "protocol violation from server\n" );
709
710
711
712
        goto fail;
    }

    if ( msgid != ( c->c_next_msgid - 1 ) || tag != LDAP_RES_BIND ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
713
714
        Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                "unexpected %s from server, msgid=%d\n",
715
                slap_msgtype2str( tag ), msgid );
716
717
718
        goto fail;
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
719
    if ( ber_scanf( ber, "{emm" /* "}" */, &result, &matcheddn, &message ) ==
720
                 LBER_ERROR ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
721
722
        Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                "response does not conform with a bind response\n" );
723
724
725
726
727
        goto fail;
    }

    switch ( result ) {
        case LDAP_SUCCESS:
728
729
730
            if ( upstream_finish( c ) ) {
                goto fail;
            }
731
732
733
734
735
736
737
738
            break;
#ifdef HAVE_CYRUS_SASL
        case LDAP_SASL_BIND_IN_PROGRESS:
            /* TODO: fallthrough until we implement SASL */
#endif /* HAVE_CYRUS_SASL */
        default:
            Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                    "upstream bind failed, rc=%d, message='%s'\n",
Ondřej Kuzník's avatar
Ondřej Kuzník committed
739
                    result, message.bv_val );
740
741
742
            goto fail;
    }

743
    CONNECTION_UNLOCK(c);
744

Ondřej Kuzník's avatar
Ondřej Kuzník committed
745
    ber_free( ber, 1 );
746
747
    return;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
748
fail:
749
    event_del( c->c_read_event );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
750
751
752
    Debug( LDAP_DEBUG_CONNS, "upstream_bind_cb: "
            "suspended read event on dying connid=%lu\n",
            c->c_connid );
753
    ber_free( ber, 1 );
754
    UPSTREAM_DESTROY(c);
755
756
}

Ondřej Kuzník's avatar
Ondřej Kuzník committed
757
758
759
760
void
upstream_write_cb( evutil_socket_t s, short what, void *arg )
{
    Connection *c = arg;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
761

762
    CONNECTION_LOCK(c);
763
764
765
766
    if ( !c->c_live ) {
        CONNECTION_UNLOCK(c);
        return;
    }
767
768
    CONNECTION_UNLOCK_INCREF(c);

769
770
771
    /* Before we acquire any locks */
    event_del( c->c_write_event );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
772
773
    ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
    Debug( LDAP_DEBUG_CONNS, "upstream_write_cb: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
774
            "have something to write to upstream connid=%lu\n",
Ondřej Kuzník's avatar
Ondřej Kuzník committed
775
776
            c->c_connid );

777
778
    /* We might have been beaten to flushing the data by another thread */
    if ( c->c_pendingber && ber_flush( c->c_sb, c->c_pendingber, 1 ) ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
779
        int err = sock_errno();
780

Ondřej Kuzník's avatar
Ondřej Kuzník committed
781
        if ( err != EWOULDBLOCK && err != EAGAIN ) {
782
            char ebuf[128];
Ondřej Kuzník's avatar
Ondřej Kuzník committed
783
            Debug( LDAP_DEBUG_ANY, "upstream_write_cb: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
784
                    "ber_flush on fd=%d failed errno=%d (%s)\n",
785
                    c->c_fd, err, sock_errstr( err, ebuf, sizeof(ebuf) ) );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
786
            ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
787
            UPSTREAM_LOCK_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
788
789
            return;
        }
790
        event_add( c->c_write_event, NULL );
791
792
    } else {
        c->c_pendingber = NULL;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
793
794
    }
    ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
795
796
797

    CONNECTION_LOCK_DECREF(c);
    UPSTREAM_UNLOCK_OR_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
798
799
}

800
801
void *
upstream_bind( void *ctx, void *arg )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
802
{
803
804
805
806
    Connection *c = arg;
    Backend *b;
    BerElement *ber = ber_alloc();
    struct event_base *base;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
807
    struct event *event;
808
809
    ber_int_t msgid;
    evutil_socket_t s;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
810

811
    assert( ber );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
812

813
    CONNECTION_LOCK(c);
814
815
816
    b = c->c_private;
    s = c->c_fd;
    base = slap_get_base( s );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
817

818
    event = event_new( base, s, EV_READ|EV_PERSIST, upstream_bind_cb, c );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
819
    if ( !event ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
820
821
        Debug( LDAP_DEBUG_ANY, "upstream_bind: "
                "Read event could not be allocated\n" );
822
        UPSTREAM_DESTROY(c);
823
        return NULL;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
824
825
    }
    event_add( event, NULL );
826
827
828
829
    if ( c->c_read_event ) {
        event_del( c->c_read_event );
        event_free( c->c_read_event );
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
830
831
    c->c_read_event = event;

832
833
    msgid = c->c_next_msgid++;

834
    CONNECTION_UNLOCK_INCREF(c);
835

Ondřej Kuzník's avatar
Ondřej Kuzník committed
836
    ldap_pvt_thread_mutex_lock( &b->b_mutex );
837
    if ( bindconf.sb_method == LDAP_AUTH_SIMPLE ) {
838
        /* simple bind */
839
        ber_printf( ber, "{it{iOtON}}",
840
                msgid, LDAP_REQ_BIND, LDAP_VERSION3,
841
842
                &bindconf.sb_binddn, LDAP_AUTH_SIMPLE,
                &bindconf.sb_cred );
843
844
845

#ifdef HAVE_CYRUS_SASL
    } else {
846
847
848
        BerValue cred = BER_BVNULL;
        ber_printf( ber, "{it{iOt{OON}N}}",
                msgid, LDAP_REQ_BIND, LDAP_VERSION3,
849
850
                &bindconf.sb_binddn, LDAP_AUTH_SASL,
                &bindconf.sb_saslmech, BER_BV_OPTIONAL( &cred ) );
851
852
#endif /* HAVE_CYRUS_SASL */
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
853
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
854
855
856
857
858
859
860

    ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
    c->c_pendingber = ber;
    ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );

    upstream_write_cb( -1, 0, c );

861
862
863
    CONNECTION_LOCK_DECREF(c);
    UPSTREAM_UNLOCK_OR_DESTROY(c);

864
865
866
    return NULL;
}

867
868
869
/*
 * We must already hold b->b_mutex when called.
 */
870
871
872
873
874
875
Connection *
upstream_init( ber_socket_t s, Backend *b )
{
    Connection *c;
    struct event_base *base = slap_get_base( s );
    struct event *event;
876
    int flags, is_bindconn = 0;
877
878
879

    assert( b != NULL );

880
    flags = (b->b_tls == LLOAD_LDAPS) ? CONN_IS_TLS : 0;
881
882
883
    c = connection_init( s, b->b_host, flags );
    c->c_private = b;

884
885
886
887
888
    {
        ber_len_t max = sockbuf_max_incoming_upstream;
        ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
889
890
    event = event_new( base, s, EV_WRITE, upstream_write_cb, c );
    if ( !event ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
891
892
        Debug( LDAP_DEBUG_ANY, "upstream_init: "
                "Write event could not be allocated\n" );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
893
894
895
896
897
        goto fail;
    }
    /* We only register the write event when we have data pending */
    c->c_write_event = event;

898
899
900
901
    /* Unless we are configured to use the VC exop, consider allocating the
     * connection into the bind conn pool. Start off by allocating one for
     * general use, then one for binds, then we start filling up the general
     * connection pool, finally the bind pool */
902
903
904
905
906
    if (
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
            !(lload_features & LLOAD_FEATURE_VC) &&
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
            b->b_active && b->b_numbindconns ) {
907
908
909
910
911
912
913
914
        if ( !b->b_bindavail ) {
            is_bindconn = 1;
        } else if ( b->b_active >= b->b_numconns &&
                b->b_bindavail < b->b_numbindconns ) {
            is_bindconn = 1;
        }
    }

915
    if ( is_bindconn || bindconf.sb_method == LDAP_AUTH_NONE ) {
916
917
918
        if ( upstream_finish( c ) ) {
            goto fail;
        }
919
920
921
    } else {
        ldap_pvt_thread_pool_submit( &connection_pool, upstream_bind, c );
    }
922

923
    if ( is_bindconn ) {
924
        LDAP_CIRCLEQ_INSERT_HEAD( &b->b_bindconns, c, c_next );
925
926
927
        c->c_type = SLAP_C_BIND;
        b->b_bindavail++;
    } else {
928
        LDAP_CIRCLEQ_INSERT_HEAD( &b->b_conns, c, c_next );
929
930
        b->b_active++;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
931

932
    CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
933
    return c;
934

Ondřej Kuzník's avatar
Ondřej Kuzník committed
935
936
937
938
939
940
941
942
943
fail:
    if ( c->c_write_event ) {
        event_del( c->c_write_event );
        event_free( c->c_write_event );
    }
    if ( c->c_read_event ) {
        event_del( c->c_read_event );
        event_free( c->c_read_event );
    }
944
    UPSTREAM_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
945
946
947
    return NULL;
}

Ondřej Kuzník's avatar
Ondřej Kuzník committed
948
void
Ondřej Kuzník's avatar
Ondřej Kuzník committed
949
950
951
upstream_destroy( Connection *c )
{
    Backend *b = c->c_private;
952
    struct event *read_event, *write_event;
953
    TAvlnode *root;
954
    long freed, executing;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
955

956
    Debug( LDAP_DEBUG_CONNS, "upstream_destroy: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
957
            "freeing connection connid=%lu\n",
958
959
            c->c_connid );

960
    c->c_state = SLAP_C_INVALID;
961

962
963
    root = c->c_ops;
    c->c_ops = NULL;
964
    executing = c->c_n_ops_executing;
965
    c->c_n_ops_executing = 0;
966

967
968
    read_event = c->c_read_event;
    write_event = c->c_write_event;
969

970
971
    CONNECTION_UNLOCK_INCREF(c);

972
    freed = tavl_free( root, (AVL_FREE)operation_lost_upstream );
973
    assert( freed == executing );
974

975
976
977
978
979
    /*
     * Avoid a deadlock:
     * event_del will block if the event is currently executing its callback,
     * that callback might be waiting to lock c->c_mutex
     */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
980
981
982
    if ( read_event ) {
        event_del( read_event );
    }
983

Ondřej Kuzník's avatar
Ondřej Kuzník committed
984
985
986
    if ( write_event ) {
        event_del( write_event );
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
987

Ondřej Kuzník's avatar
Ondřej Kuzník committed
988
    ldap_pvt_thread_mutex_lock( &b->b_mutex );
989
    if ( c->c_type == SLAP_C_BIND ) {
990
        LDAP_CIRCLEQ_REMOVE( &b->b_bindconns, c, c_next );
991
992
        b->b_bindavail--;
    } else {
993
        LDAP_CIRCLEQ_REMOVE( &b->b_conns, c, c_next );
994
        b->b_active--;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
995
    }
996
    b->b_n_ops_executing -= executing;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
997
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
998
    backend_retry( b );
999

1000
    CONNECTION_LOCK_DECREF(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1001

Ondřej Kuzník's avatar
Ondřej Kuzník committed
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
    if ( c->c_read_event ) {
        event_free( c->c_read_event );
        c->c_read_event = NULL;
    }

    if ( c->c_write_event ) {
        event_free( c->c_write_event );
        c->c_write_event = NULL;
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
    /*
     * If we attempted to destroy any operations, we might have lent a new
     * refcnt token for a thread that raced us to that, let them call us again
     * later
     */
    assert( c->c_refcnt >= 0 );
    if ( c->c_refcnt ) {
        c->c_state = SLAP_C_CLOSING;
        Debug( LDAP_DEBUG_CONNS, "upstream_destroy: "
                "connid=%lu aborting with refcnt=%d\n",
                c->c_connid, c->c_refcnt );
        CONNECTION_UNLOCK(c);
        return;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1026
1027
    connection_destroy( c );
}