1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2021 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 
16 #include "portable.h"
17 
18 #include <ac/socket.h>
19 #include <ac/errno.h>
20 #include <ac/string.h>
21 #include <ac/time.h>
22 #include <ac/unistd.h>
23 
24 #include <event2/event.h>
25 #include <event2/dns.h>
26 
27 #include "lutil.h"
28 #include "lload.h"
29 
30 static void
upstream_connect_cb(evutil_socket_t s,short what,void * arg)31 upstream_connect_cb( evutil_socket_t s, short what, void *arg )
32 {
33     LloadPendingConnection *conn = arg;
34     LloadBackend *b = conn->backend;
35     int error = 0, rc = -1;
36     epoch_t epoch;
37 
38     checked_lock( &b->b_mutex );
39     Debug( LDAP_DEBUG_CONNS, "upstream_connect_cb: "
40             "fd=%d connection callback for backend uri='%s'\n",
41             s, b->b_uri.bv_val );
42 
43     if ( s != conn->fd ) {
44         /* backend_reset has been here first */
45         goto preempted;
46     }
47 
48     epoch = epoch_join();
49 
50     if ( what == EV_WRITE ) {
51         socklen_t optlen = sizeof(error);
52 
53         if ( getsockopt( conn->fd, SOL_SOCKET, SO_ERROR, (void *)&error,
54                      &optlen ) < 0 ) {
55             goto done;
56         }
57         if ( error == EINTR || error == EINPROGRESS || error == EWOULDBLOCK ) {
58             checked_unlock( &b->b_mutex );
59             epoch_leave( epoch );
60             return;
61         } else if ( error ) {
62             goto done;
63         } else if ( upstream_init( s, conn->backend ) == NULL ) {
64             goto done;
65         }
66         rc = LDAP_SUCCESS;
67     }
68 
69 done:
70     epoch_leave( epoch );
71 
72     LDAP_LIST_REMOVE( conn, next );
73     if ( rc ) {
74         evutil_closesocket( conn->fd );
75         b->b_opening--;
76         b->b_failed++;
77         if ( what & EV_TIMEOUT ) {
78             Debug( LDAP_DEBUG_ANY, "upstream_connect_cb: "
79                     "fd=%d connection timed out\n",
80                     s );
81         } else {
82             char ebuf[128];
83             Debug( LDAP_DEBUG_ANY, "upstream_connect_cb: "
84                     "fd=%d connection set up failed%s%s\n",
85                     s, error ? ": " : "",
86                     error ? sock_errstr( error, ebuf, sizeof(ebuf) ) : "" );
87         }
88         backend_retry( b );
89     }
90 preempted:
91     checked_unlock( &b->b_mutex );
92 
93     event_free( conn->event );
94     ch_free( conn );
95 }
96 
97 static void
upstream_name_cb(int result,struct evutil_addrinfo * res,void * arg)98 upstream_name_cb( int result, struct evutil_addrinfo *res, void *arg )
99 {
100     LloadBackend *b = arg;
101     ber_socket_t s = AC_SOCKET_INVALID;
102     epoch_t epoch;
103     int rc;
104 
105     if ( result == EVUTIL_EAI_CANCEL ) {
106         Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
107                 "cancelled\n" );
108         return;
109     }
110 
111     checked_lock( &b->b_mutex );
112     /* We were already running when backend_reset tried to cancel us, but were
113      * already stuck waiting for the mutex, nothing to do and b_opening has
114      * been decremented as well */
115     if ( b->b_dns_req == NULL ) {
116         checked_unlock( &b->b_mutex );
117         return;
118     }
119     b->b_dns_req = NULL;
120 
121     epoch = epoch_join();
122     if ( result || !res ) {
123         Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
124                 "name resolution failed for backend '%s': %s\n",
125                 b->b_uri.bv_val, evutil_gai_strerror( result ) );
126         goto fail;
127     }
128 
129     /* TODO: if we get failures, try the other addrinfos */
130     if ( (s = socket( res->ai_family, SOCK_STREAM, 0 )) ==
131             AC_SOCKET_INVALID ) {
132         goto fail;
133     }
134 
135     if ( ber_pvt_socket_set_nonblock( s, 1 ) ) {
136         goto fail;
137     }
138 
139 #if defined(SO_KEEPALIVE) || defined(TCP_NODELAY)
140     if ( b->b_proto == LDAP_PROTO_TCP ) {
141         int dummy = 1;
142 #ifdef SO_KEEPALIVE
143         if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (char *)&dummy,
144                      sizeof(dummy) ) == AC_SOCKET_ERROR ) {
145             Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
146                     "setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n",
147                     s );
148         }
149         if ( bindconf.sb_keepalive.sk_idle > 0 ) {
150 #ifdef TCP_KEEPIDLE
151             if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPIDLE,
152                          (void *)&bindconf.sb_keepalive.sk_idle,
153                          sizeof(bindconf.sb_keepalive.sk_idle) ) ==
154                     AC_SOCKET_ERROR ) {
155                 Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
156                         "setsockopt(%d, TCP_KEEPIDLE) failed (ignored).\n",
157                         s );
158             }
159 #else
160             Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
161                     "sockopt TCP_KEEPIDLE not supported on this system.\n" );
162 #endif /* TCP_KEEPIDLE */
163         }
164         if ( bindconf.sb_keepalive.sk_probes > 0 ) {
165 #ifdef TCP_KEEPCNT
166             if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPCNT,
167                          (void *)&bindconf.sb_keepalive.sk_probes,
168                          sizeof(bindconf.sb_keepalive.sk_probes) ) ==
169                     AC_SOCKET_ERROR ) {
170                 Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
171                         "setsockopt(%d, TCP_KEEPCNT) failed (ignored).\n",
172                         s );
173             }
174 #else
175             Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
176                     "sockopt TCP_KEEPCNT not supported on this system.\n" );
177 #endif /* TCP_KEEPCNT */
178         }
179         if ( bindconf.sb_keepalive.sk_interval > 0 ) {
180 #ifdef TCP_KEEPINTVL
181             if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPINTVL,
182                          (void *)&bindconf.sb_keepalive.sk_interval,
183                          sizeof(bindconf.sb_keepalive.sk_interval) ) ==
184                     AC_SOCKET_ERROR ) {
185                 Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
186                         "setsockopt(%d, TCP_KEEPINTVL) failed (ignored).\n",
187                         s );
188             }
189 #else
190             Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
191                     "sockopt TCP_KEEPINTVL not supported on this system.\n" );
192 #endif /* TCP_KEEPINTVL */
193         }
194 #endif /* SO_KEEPALIVE */
195         if ( bindconf.sb_tcp_user_timeout > 0 ) {
196 #ifdef TCP_USER_TIMEOUT
197             if ( setsockopt( s, IPPROTO_TCP, TCP_USER_TIMEOUT,
198                          (void *)&bindconf.sb_tcp_user_timeout,
199                          sizeof(bindconf.sb_tcp_user_timeout) ) ==
200                     AC_SOCKET_ERROR ) {
201                 Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
202                         "setsockopt(%d, TCP_USER_TIMEOUT) failed (ignored).\n",
203                         s );
204             }
205 #else
206             Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
207                     "sockopt TCP_USER_TIMEOUT not supported on this "
208                     "system.\n" );
209 #endif /* TCP_USER_TIMEOUT */
210         }
211 #ifdef TCP_NODELAY
212         if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY, (char *)&dummy,
213                      sizeof(dummy) ) == AC_SOCKET_ERROR ) {
214             Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: "
215                     "setsockopt(%d, TCP_NODELAY) failed (ignored).\n",
216                     s );
217         }
218 #endif /* TCP_NODELAY */
219     }
220 #endif /* SO_KEEPALIVE || TCP_NODELAY */
221 
222     if ( res->ai_family == PF_INET ) {
223         struct sockaddr_in *ai = (struct sockaddr_in *)res->ai_addr;
224         ai->sin_port = htons( b->b_port );
225         rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen );
226     } else {
227         struct sockaddr_in6 *ai = (struct sockaddr_in6 *)res->ai_addr;
228         ai->sin6_port = htons( b->b_port );
229         rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen );
230     }
231     /* Asynchronous connect */
232     if ( rc ) {
233         LloadPendingConnection *conn;
234 
235         if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) {
236             Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
237                     "failed to connect to server '%s'\n",
238                     b->b_uri.bv_val );
239             evutil_closesocket( s );
240             goto fail;
241         }
242 
243         conn = ch_calloc( 1, sizeof(LloadPendingConnection) );
244         LDAP_LIST_ENTRY_INIT( conn, next );
245         conn->backend = b;
246         conn->fd = s;
247 
248         conn->event = event_new( lload_get_base( s ), s, EV_WRITE|EV_PERSIST,
249                 upstream_connect_cb, conn );
250         if ( !conn->event ) {
251             Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
252                     "failed to acquire an event to finish upstream "
253                     "connection setup.\n" );
254             ch_free( conn );
255             evutil_closesocket( s );
256             goto fail;
257         }
258 
259         event_add( conn->event, lload_timeout_net );
260         LDAP_LIST_INSERT_HEAD( &b->b_connecting, conn, next );
261         Debug( LDAP_DEBUG_CONNS, "upstream_name_cb: "
262                 "connection to backend uri=%s in progress\n",
263                 b->b_uri.bv_val );
264     } else if ( upstream_init( s, b ) == NULL ) {
265         goto fail;
266     }
267 
268     checked_unlock( &b->b_mutex );
269     evutil_freeaddrinfo( res );
270     epoch_leave( epoch );
271     return;
272 
273 fail:
274     if ( s != AC_SOCKET_INVALID ) {
275         evutil_closesocket( s );
276     }
277     b->b_opening--;
278     b->b_failed++;
279     backend_retry( b );
280     checked_unlock( &b->b_mutex );
281     if ( res ) {
282         evutil_freeaddrinfo( res );
283     }
284     epoch_leave( epoch );
285 }
286 
287 int
try_upstream(LloadBackend * b,lload_c_head * head,LloadOperation * op,LloadConnection * c,int * res,char ** message)288 try_upstream(
289     LloadBackend *b,
290     lload_c_head *head,
291     LloadOperation *op,
292     LloadConnection *c,
293     int *res,
294     char **message )
295 {
296     assert_locked( &b->b_mutex );
297 
298     checked_lock( &c->c_io_mutex );
299     CONNECTION_LOCK(c);
300     if ( c->c_state == LLOAD_C_READY && !c->c_pendingber &&
301             ( b->b_max_conn_pending == 0 ||
302                     c->c_n_ops_executing < b->b_max_conn_pending ) ) {
303         Debug( LDAP_DEBUG_CONNS, "try_upstream: "
304                 "selected connection connid=%lu for client "
305                 "connid=%lu msgid=%d\n",
306                 c->c_connid, op->o_client_connid, op->o_client_msgid );
307 
308         /* c_state is DYING if we're about to be unlinked */
309         assert( IS_ALIVE( c, c_live ) );
310 
311         if ( head ) {
312             /*
313              * Round-robin step:
314              * Rotate the queue to put this connection at the end.
315              */
316             LDAP_CIRCLEQ_MAKE_TAIL( head, c, c_next );
317         }
318 
319         b->b_n_ops_executing++;
320         if ( op->o_tag == LDAP_REQ_BIND ) {
321             b->b_counters[LLOAD_STATS_OPS_BIND].lc_ops_received++;
322         } else {
323             b->b_counters[LLOAD_STATS_OPS_OTHER].lc_ops_received++;
324         }
325         c->c_n_ops_executing++;
326         c->c_counters.lc_ops_received++;
327 
328         *res = LDAP_SUCCESS;
329         CONNECTION_ASSERT_LOCKED(c);
330         assert_locked( &c->c_io_mutex );
331         return 1;
332     }
333     CONNECTION_UNLOCK(c);
334     checked_unlock( &c->c_io_mutex );
335     return 0;
336 }
337 
338 int
backend_select(LloadBackend * b,LloadOperation * op,LloadConnection ** cp,int * res,char ** message)339 backend_select(
340         LloadBackend *b,
341         LloadOperation *op,
342         LloadConnection **cp,
343         int *res,
344         char **message )
345 {
346     lload_c_head *head;
347     LloadConnection *c;
348 
349     assert_locked( &b->b_mutex );
350     if ( b->b_max_pending && b->b_n_ops_executing >= b->b_max_pending ) {
351         Debug( LDAP_DEBUG_CONNS, "backend_select: "
352                 "backend %s too busy\n",
353                 b->b_uri.bv_val );
354         *res = LDAP_BUSY;
355         *message = "server busy";
356         return 1;
357     }
358 
359     if ( op->o_tag == LDAP_REQ_BIND
360 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
361             && !(lload_features & LLOAD_FEATURE_VC)
362 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
363             ) {
364         head = &b->b_bindconns;
365     } else {
366         head = &b->b_conns;
367     }
368 
369     if ( LDAP_CIRCLEQ_EMPTY( head ) ) {
370         return 0;
371     }
372 
373     *res = LDAP_BUSY;
374     *message = "server busy";
375 
376     LDAP_CIRCLEQ_FOREACH( c, head, c_next ) {
377         if ( try_upstream( b, head, op, c, res, message ) ) {
378             *cp = c;
379             CONNECTION_ASSERT_LOCKED(c);
380             assert_locked( &c->c_io_mutex );
381             return 1;
382         }
383     }
384 
385     return 1;
386 }
387 
388 int
upstream_select(LloadOperation * op,LloadConnection ** cp,int * res,char ** message)389 upstream_select(
390         LloadOperation *op,
391         LloadConnection **cp,
392         int *res,
393         char **message )
394 {
395     LloadTier *tier;
396     int finished = 0;
397 
398     LDAP_STAILQ_FOREACH( tier, &tiers, t_next ) {
399         if ( (finished = tier->t_type.tier_select(
400                        tier, op, cp, res, message )) ) {
401             break;
402         }
403     }
404 
405     return finished;
406 }
407 
408 /*
409  * Will schedule a connection attempt if there is a need for it. Need exclusive
410  * access to backend, its b_mutex is not touched here, though.
411  */
412 void
backend_retry(LloadBackend * b)413 backend_retry( LloadBackend *b )
414 {
415     int requested;
416 
417     if ( slapd_shutdown ) {
418         Debug( LDAP_DEBUG_CONNS, "backend_retry: "
419                 "shutting down\n" );
420         return;
421     }
422     assert_locked( &b->b_mutex );
423 
424     requested = b->b_numconns;
425 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
426     if ( !(lload_features & LLOAD_FEATURE_VC) )
427 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
428     {
429         requested += b->b_numbindconns;
430     }
431 
432     if ( b->b_active + b->b_bindavail + b->b_opening >= requested ) {
433         Debug( LDAP_DEBUG_CONNS, "backend_retry: "
434                 "no more connections needed for this backend\n" );
435         assert_locked( &b->b_mutex );
436         return;
437     }
438 
439     if ( b->b_opening > 0 ) {
440         Debug( LDAP_DEBUG_CONNS, "backend_retry: "
441                 "retry in progress already\n" );
442         assert( b->b_opening == 1 );
443         assert_locked( &b->b_mutex );
444         return;
445     }
446 
447     /* We incremented b_opening when we activated the event, so it can't be
448      * pending */
449     assert( !event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) );
450     b->b_opening++;
451 
452     if ( b->b_failed > 0 ) {
453         Debug( LDAP_DEBUG_CONNS, "backend_retry: "
454                 "scheduling a retry in %d ms\n",
455                 b->b_retry_timeout );
456         event_add( b->b_retry_event, &b->b_retry_tv );
457         assert_locked( &b->b_mutex );
458         return;
459     }
460 
461     Debug( LDAP_DEBUG_CONNS, "backend_retry: "
462             "scheduling re-connection straight away\n" );
463 
464     if ( ldap_pvt_thread_pool_submit2(
465                  &connection_pool, backend_connect_task, b, &b->b_cookie ) ) {
466         Debug( LDAP_DEBUG_ANY, "backend_retry: "
467                 "failed to submit retry task, scheduling a retry instead\n" );
468         /* The current implementation of ldap_pvt_thread_pool_submit2 can fail
469          * and still set (an invalid) cookie */
470         b->b_cookie = NULL;
471         b->b_failed++;
472         event_add( b->b_retry_event, &b->b_retry_tv );
473     }
474     assert_locked( &b->b_mutex );
475 }
476 
477 void
backend_connect(evutil_socket_t s,short what,void * arg)478 backend_connect( evutil_socket_t s, short what, void *arg )
479 {
480     struct evutil_addrinfo hints = {};
481     LloadBackend *b = arg;
482     struct evdns_getaddrinfo_request *request, *placeholder;
483     char *hostname;
484     epoch_t epoch;
485 
486     checked_lock( &b->b_mutex );
487     assert( b->b_dns_req == NULL );
488 
489     if ( b->b_cookie ) {
490         b->b_cookie = NULL;
491     }
492 
493     if ( slapd_shutdown ) {
494         Debug( LDAP_DEBUG_CONNS, "backend_connect: "
495                 "doing nothing, shutdown in progress\n" );
496         b->b_opening--;
497         checked_unlock( &b->b_mutex );
498         return;
499     }
500 
501     epoch = epoch_join();
502 
503     Debug( LDAP_DEBUG_CONNS, "backend_connect: "
504             "%sattempting connection to %s\n",
505             (what & EV_TIMEOUT) ? "retry timeout finished, " : "",
506             b->b_host );
507 
508 #ifdef LDAP_PF_LOCAL
509     if ( b->b_proto == LDAP_PROTO_IPC ) {
510         struct sockaddr_un addr;
511         ber_socket_t s = socket( PF_LOCAL, SOCK_STREAM, 0 );
512         int rc;
513 
514         if ( s == AC_SOCKET_INVALID ) {
515             goto fail;
516         }
517 
518         rc = ber_pvt_socket_set_nonblock( s, 1 );
519         if ( rc ) {
520             evutil_closesocket( s );
521             goto fail;
522         }
523 
524         if ( strlen( b->b_host ) > ( sizeof(addr.sun_path) - 1 ) ) {
525             evutil_closesocket( s );
526             goto fail;
527         }
528         memset( &addr, '\0', sizeof(addr) );
529         addr.sun_family = AF_LOCAL;
530         strcpy( addr.sun_path, b->b_host );
531 
532         rc = connect(
533                 s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un) );
534         /* Asynchronous connect */
535         if ( rc ) {
536             LloadPendingConnection *conn;
537 
538             if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) {
539                 evutil_closesocket( s );
540                 goto fail;
541             }
542 
543             conn = ch_calloc( 1, sizeof(LloadPendingConnection) );
544             LDAP_LIST_ENTRY_INIT( conn, next );
545             conn->backend = b;
546             conn->fd = s;
547 
548             conn->event = event_new( lload_get_base( s ), s,
549                     EV_WRITE|EV_PERSIST, upstream_connect_cb, conn );
550             if ( !conn->event ) {
551                 Debug( LDAP_DEBUG_ANY, "backend_connect: "
552                         "failed to acquire an event to finish upstream "
553                         "connection setup.\n" );
554                 ch_free( conn );
555                 evutil_closesocket( s );
556                 goto fail;
557             }
558 
559             event_add( conn->event, lload_timeout_net );
560             LDAP_LIST_INSERT_HEAD( &b->b_connecting, conn, next );
561             Debug( LDAP_DEBUG_CONNS, "backend_connect: "
562                     "connection to backend uri=%s in progress\n",
563                     b->b_uri.bv_val );
564         } else if ( upstream_init( s, b ) == NULL ) {
565             goto fail;
566         }
567 
568         checked_unlock( &b->b_mutex );
569         epoch_leave( epoch );
570         return;
571     }
572 #endif /* LDAP_PF_LOCAL */
573 
574     hints.ai_family = AF_UNSPEC;
575     hints.ai_flags = EVUTIL_AI_CANONNAME;
576     hints.ai_socktype = SOCK_STREAM;
577     hints.ai_protocol = IPPROTO_TCP;
578 
579     hostname = b->b_host;
580 
581     /*
582      * Picking any value on the stack. This is unique to our thread without
583      * having to call ldap_pvt_thread_self.
584      * We might have to revert to using ldap_pvt_thread_self eventually since
585      * this betrays where exactly our stack lies - potentially weakening some
586      * protections like ASLR.
587      */
588     placeholder = (struct evdns_getaddrinfo_request *)&request;
589     b->b_dns_req = placeholder;
590     checked_unlock( &b->b_mutex );
591 
592     request = evdns_getaddrinfo(
593             dnsbase, hostname, NULL, &hints, upstream_name_cb, b );
594 
595     checked_lock( &b->b_mutex );
596     assert( request || b->b_dns_req != placeholder );
597 
598     /* Record the request, unless upstream_name_cb or another thread
599      * cleared it. Another thread is usually backend_reset or backend_connect
600      * if upstream_name_cb finished and scheduled another one */
601     if ( b->b_dns_req == placeholder ) {
602         b->b_dns_req = request;
603     }
604     checked_unlock( &b->b_mutex );
605     epoch_leave( epoch );
606     return;
607 
608 fail:
609     b->b_opening--;
610     b->b_failed++;
611     backend_retry( b );
612     checked_unlock( &b->b_mutex );
613     epoch_leave( epoch );
614 }
615 
616 void *
backend_connect_task(void * ctx,void * arg)617 backend_connect_task( void *ctx, void *arg )
618 {
619     backend_connect( -1, 0, arg );
620     return NULL;
621 }
622 
623 /*
624  * Needs exclusive access to the backend and no other thread is allowed to call
625  * backend_retry while we're handling this.
626  *
627  * If gentle == 0, a full pause must be in effect, else we risk deadlocking on
628  * event_free().
629  */
630 void
backend_reset(LloadBackend * b,int gentle)631 backend_reset( LloadBackend *b, int gentle )
632 {
633     assert_locked( &b->b_mutex );
634     if ( b->b_cookie ) {
635         if ( ldap_pvt_thread_pool_retract( b->b_cookie ) ) {
636             b->b_cookie = NULL;
637             b->b_opening--;
638         } else {
639             /*
640              * The task might not be cancelable because it just started
641              * executing.
642              *
643              * Shutdown should be the only time when the thread pool is
644              * in that state. Keep the cookie in to keep an eye on whether
645              * it's finished yet.
646              */
647             assert( slapd_shutdown );
648         }
649     }
650     /* Not safe to hold our mutex and call event_del/free if the event's
651      * callback is running, relinquish the mutex while we do so. */
652     if ( b->b_retry_event &&
653             event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) {
654         assert( b->b_failed );
655         checked_unlock( &b->b_mutex );
656         event_del( b->b_retry_event );
657         checked_lock( &b->b_mutex );
658         b->b_opening--;
659     }
660     if ( b->b_dns_req ) {
661         evdns_getaddrinfo_cancel( b->b_dns_req );
662         b->b_dns_req = NULL;
663         b->b_opening--;
664     }
665     while ( !LDAP_LIST_EMPTY( &b->b_connecting ) ) {
666         LloadPendingConnection *pending = LDAP_LIST_FIRST( &b->b_connecting );
667 
668         Debug( LDAP_DEBUG_CONNS, "backend_reset: "
669                 "destroying socket pending connect() fd=%d\n",
670                 pending->fd );
671 
672         event_active( pending->event, EV_WRITE, 0 );
673         evutil_closesocket( pending->fd );
674         pending->fd = -1;
675         LDAP_LIST_REMOVE( pending, next );
676 
677         if ( !gentle ) {
678             /* None of the event bases are running, we're safe to free the
679              * event right now and potentially free the backend itself */
680             event_free( pending->event );
681             ch_free( pending );
682         }
683         /* else, just let the event dispose of the resources on its own later */
684         b->b_opening--;
685     }
686     connections_walk(
687             &b->b_mutex, &b->b_preparing, lload_connection_close, &gentle );
688     assert( LDAP_CIRCLEQ_EMPTY( &b->b_preparing ) );
689     assert( b->b_opening == ( b->b_cookie ? 1 : 0 ) );
690     b->b_failed = 0;
691 
692     connections_walk_last( &b->b_mutex, &b->b_bindconns, b->b_last_bindconn,
693             lload_connection_close, &gentle );
694     assert( gentle || b->b_bindavail == 0 );
695 
696     connections_walk_last( &b->b_mutex, &b->b_conns, b->b_last_conn,
697             lload_connection_close, &gentle );
698     assert( gentle || b->b_active == 0 );
699     assert_locked( &b->b_mutex );
700 }
701 
702 LloadBackend *
lload_backend_new(void)703 lload_backend_new( void )
704 {
705     LloadBackend *b;
706 
707     b = ch_calloc( 1, sizeof(LloadBackend) );
708 
709     LDAP_CIRCLEQ_INIT( &b->b_conns );
710     LDAP_CIRCLEQ_INIT( &b->b_bindconns );
711     LDAP_CIRCLEQ_INIT( &b->b_preparing );
712     LDAP_CIRCLEQ_ENTRY_INIT( b, b_next );
713 
714     b->b_numconns = 1;
715     b->b_numbindconns = 1;
716     b->b_weight = 1;
717 
718     b->b_retry_timeout = 5000;
719 
720     ldap_pvt_thread_mutex_init( &b->b_mutex );
721 
722     return b;
723 }
724 
725 void
lload_backend_destroy(LloadBackend * b)726 lload_backend_destroy( LloadBackend *b )
727 {
728     Debug( LDAP_DEBUG_CONNS, "lload_backend_destroy: "
729             "destroying backend uri='%s', numconns=%d, numbindconns=%d\n",
730             b->b_uri.bv_val, b->b_numconns, b->b_numbindconns );
731 
732     checked_lock( &b->b_mutex );
733     b->b_tier->t_type.tier_remove_backend( b->b_tier, b );
734     b->b_numconns = b->b_numbindconns = 0;
735     backend_reset( b, 0 );
736 
737 #ifdef BALANCER_MODULE
738     if ( b->b_monitor ) {
739         BackendDB *be;
740         struct berval monitordn = BER_BVC("cn=monitor");
741         int rc;
742 
743         be = select_backend( &monitordn, 0 );
744 
745         /* FIXME: implement proper subsys shutdown in back-monitor or make
746          * backend just an entry, not a subsys */
747         rc = b->b_monitor->mss_destroy( be, b->b_monitor );
748         assert( rc == LDAP_SUCCESS );
749     }
750 #endif /* BALANCER_MODULE */
751 
752     checked_unlock( &b->b_mutex );
753     ldap_pvt_thread_mutex_destroy( &b->b_mutex );
754 
755     if ( b->b_retry_event ) {
756         event_del( b->b_retry_event );
757         event_free( b->b_retry_event );
758         b->b_retry_event = NULL;
759     }
760 
761     ch_free( b->b_host );
762     ch_free( b->b_uri.bv_val );
763     ch_free( b->b_name.bv_val );
764     ch_free( b );
765 }
766