Home | History | Annotate | Line # | Download | only in lloadd
      1 /*	$NetBSD: lload.h,v 1.3 2025/09/05 21:16:24 christos Exp $	*/
      2 
      3 /* lload.h - load balancer include file */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1998-2024 The OpenLDAP Foundation.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
     19  * All rights reserved.
     20  *
     21  * Redistribution and use in source and binary forms are permitted
     22  * provided that this notice is preserved and that due credit is given
     23  * to the University of Michigan at Ann Arbor. The name of the University
     24  * may not be used to endorse or promote products derived from this
     25  * software without specific prior written permission. This software
     26  * is provided ``as is'' without express or implied warranty.
     27  */
     28 
     29 #ifndef _LLOAD_H_
     30 #define _LLOAD_H_
     31 
     32 #include "ldap_defaults.h"
     33 
     34 #include <stdio.h>
     35 #include <ac/stdlib.h>
     36 
     37 #include <sys/types.h>
     38 #include <ac/syslog.h>
     39 #include <ac/regex.h>
     40 #include <ac/signal.h>
     41 #include <ac/socket.h>
     42 #include <ac/time.h>
     43 #include <ac/param.h>
     44 
     45 #include "ldap_avl.h"
     46 
     47 #include "../servers/slapd/slap.h"
     48 #include "../slapd/back-monitor/back-monitor.h"
     49 
     50 #ifndef ldap_debug
     51 #define ldap_debug slap_debug
     52 #endif
     53 
     54 #include "ldap_log.h"
     55 
     56 #include <ldap.h>
     57 #include <ldap_schema.h>
     58 
     59 #include "lber_pvt.h"
     60 #include "ldap_pvt.h"
     61 #include "ldap_pvt_thread.h"
     62 #include "ldap_queue.h"
     63 
     64 #include <event2/event.h>
     65 
     66 #ifdef HAVE_CYRUS_SASL
     67 #ifdef HAVE_SASL_SASL_H
     68 #include <sasl/sasl.h>
     69 #else
     70 #include <sasl.h>
     71 #endif
     72 #endif /* HAVE_CYRUS_SASL */
     73 
     74 LDAP_BEGIN_DECL
     75 
     76 #ifdef SERVICE_NAME
     77 #undef SERVICE_NAME
     78 #endif
     79 
     80 #define SERVICE_NAME OPENLDAP_PACKAGE "-lloadd"
     81 
     82 #define LLOAD_SB_MAX_INCOMING_CLIENT ( ( 1 << 24 ) - 1 )
     83 #define LLOAD_SB_MAX_INCOMING_UPSTREAM ( ( 1 << 24 ) - 1 )
     84 
     85 #define LLOAD_CONN_MAX_PDUS_PER_CYCLE_DEFAULT 10
     86 
     87 #define BER_BV_OPTIONAL( bv ) ( BER_BVISNULL( bv ) ? NULL : ( bv ) )
     88 
     89 #include <epoch.h>
     90 
     91 #define checked_lock( mutex ) \
     92     if ( ldap_pvt_thread_mutex_lock( mutex ) != 0 ) assert(0)
     93 #define checked_unlock( mutex ) \
     94     if ( ldap_pvt_thread_mutex_unlock( mutex ) != 0 ) assert(0)
     95 
     96 #ifdef LDAP_THREAD_DEBUG
     97 #define assert_locked( mutex ) \
     98     if ( ldap_pvt_thread_mutex_trylock( mutex ) == 0 ) assert(0)
     99 #else
    100 #define assert_locked( mutex ) ( (void)0 )
    101 #endif
    102 
    103 typedef struct LloadTier LloadTier;
    104 typedef struct LloadBackend LloadBackend;
    105 typedef struct LloadPendingConnection LloadPendingConnection;
    106 typedef struct LloadConnection LloadConnection;
    107 typedef struct LloadOperation LloadOperation;
    108 typedef struct LloadChange LloadChange;
    109 /* end of forward declarations */
    110 
    111 typedef LDAP_STAILQ_HEAD(TierSt, LloadTier) lload_t_head;
    112 typedef LDAP_CIRCLEQ_HEAD(BeSt, LloadBackend) lload_b_head;
    113 typedef LDAP_CIRCLEQ_HEAD(ConnSt, LloadConnection) lload_c_head;
    114 
    115 LDAP_SLAPD_V (lload_t_head) tiers;
    116 LDAP_SLAPD_V (lload_c_head) clients;
    117 LDAP_SLAPD_V (struct slap_bindconf) bindconf;
    118 LDAP_SLAPD_V (struct berval) lloadd_identity;
    119 
    120 /* Used to coordinate server (un)pause, shutdown */
    121 LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) lload_wait_mutex;
    122 LDAP_SLAPD_V (ldap_pvt_thread_cond_t) lload_pause_cond;
    123 LDAP_SLAPD_V (ldap_pvt_thread_cond_t) lload_wait_cond;
    124 
    125 typedef int lload_cf_aux_table_parse_x( struct berval *val,
    126         void *bc,
    127         slap_cf_aux_table *tab0,
    128         const char *tabmsg,
    129         int unparse );
    130 
    131 typedef struct LloadListener LloadListener;
    132 
    133 enum lc_type {
    134     LLOAD_CHANGE_UNDEFINED = 0,
    135     LLOAD_CHANGE_MODIFY,
    136     LLOAD_CHANGE_ADD,
    137     LLOAD_CHANGE_DEL,
    138 };
    139 
    140 enum lc_object {
    141     LLOAD_UNDEFINED = 0,
    142     LLOAD_DAEMON,
    143     /*
    144     LLOAD_BINDCONF,
    145     */
    146     LLOAD_TIER,
    147     LLOAD_BACKEND,
    148 };
    149 
    150 enum lcf_daemon {
    151     LLOAD_DAEMON_MOD_THREADS = 1 << 0,
    152     LLOAD_DAEMON_MOD_FEATURES = 1 << 1,
    153     LLOAD_DAEMON_MOD_TLS = 1 << 2,
    154     LLOAD_DAEMON_MOD_LISTENER_ADD = 1 << 3,
    155     LLOAD_DAEMON_MOD_LISTENER_REPLACE = 1 << 4,
    156     LLOAD_DAEMON_MOD_BINDCONF = 1 << 5,
    157 };
    158 
    159 enum lcf_tier {
    160     LLOAD_TIER_MOD_TYPE = 1 << 0,
    161 };
    162 
    163 enum lcf_backend {
    164     LLOAD_BACKEND_MOD_OTHER = 1 << 0,
    165     LLOAD_BACKEND_MOD_CONNS = 1 << 1,
    166 };
    167 
    168 struct LloadChange {
    169     enum lc_type type;
    170     enum lc_object object;
    171     union {
    172         int generic;
    173         enum lcf_daemon daemon;
    174         enum lcf_tier tier;
    175         enum lcf_backend backend;
    176     } flags;
    177     void *target;
    178 };
    179 
    180 typedef enum {
    181 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
    182     LLOAD_FEATURE_VC = 1 << 0,
    183 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
    184     LLOAD_FEATURE_PROXYAUTHZ = 1 << 1,
    185     LLOAD_FEATURE_PAUSE = 1 << 2,
    186 } lload_features_t;
    187 
    188 #define LLOAD_FEATURE_SUPPORTED_MASK ( \
    189     LLOAD_FEATURE_PROXYAUTHZ | \
    190     0 )
    191 
    192 #ifdef BALANCER_MODULE
    193 #define LLOAD_TLS_CTX ( lload_use_slap_tls_ctx ? slap_tls_ctx : lload_tls_ctx )
    194 #else
    195 #define LLOAD_TLS_CTX ( lload_tls_ctx )
    196 #endif
    197 
    198 enum lload_tls_type {
    199     LLOAD_CLEARTEXT = 0,
    200     LLOAD_LDAPS,
    201     LLOAD_STARTTLS_OPTIONAL,
    202     LLOAD_STARTTLS,
    203     LLOAD_TLS_ESTABLISHED,
    204 };
    205 
    206 struct LloadPendingConnection {
    207     LloadBackend *backend;
    208 
    209     struct event *event;
    210     ber_socket_t fd;
    211 
    212     LDAP_LIST_ENTRY(LloadPendingConnection) next;
    213 };
    214 
    215 typedef struct lload_counters_t {
    216     ldap_pvt_mp_t lc_ops_completed;
    217     ldap_pvt_mp_t lc_ops_received;
    218     ldap_pvt_mp_t lc_ops_forwarded;
    219     ldap_pvt_mp_t lc_ops_rejected;
    220     ldap_pvt_mp_t lc_ops_failed;
    221 } lload_counters_t;
    222 
    223 enum {
    224     LLOAD_STATS_OPS_BIND = 0,
    225     LLOAD_STATS_OPS_OTHER,
    226     LLOAD_STATS_OPS_LAST
    227 };
    228 
    229 typedef struct lload_global_stats_t {
    230     ldap_pvt_mp_t global_incoming;
    231     ldap_pvt_mp_t global_outgoing;
    232     lload_counters_t counters[LLOAD_STATS_OPS_LAST];
    233 } lload_global_stats_t;
    234 
    235 typedef LloadTier *(LloadTierInit)( void );
    236 typedef int (LloadTierConfigCb)( LloadTier *tier, char *arg );
    237 typedef int (LloadTierBackendConfigCb)( LloadTier *tier, LloadBackend *b, char *arg );
    238 typedef int (LloadTierCb)( LloadTier *tier );
    239 typedef int (LloadTierResetCb)( LloadTier *tier, int shutdown );
    240 typedef int (LloadTierBackendCb)( LloadTier *tier, LloadBackend *b );
    241 typedef void (LloadTierChange)( LloadTier *tier, LloadChange *change );
    242 typedef int (LloadTierSelect)( LloadTier *tier,
    243         LloadOperation *op,
    244         LloadConnection **cp,
    245         int *res,
    246         char **message );
    247 
    248 struct lload_tier_type {
    249     char *tier_name;
    250 
    251     struct berval tier_oc, tier_backend_oc;
    252 
    253     LloadTierInit *tier_init;
    254     LloadTierConfigCb *tier_config;
    255     LloadTierBackendConfigCb *tier_backend_config;
    256     LloadTierCb *tier_startup;
    257     LloadTierCb *tier_update;
    258     LloadTierResetCb *tier_reset;
    259     LloadTierCb *tier_destroy;
    260 
    261     LloadTierBackendCb *tier_add_backend;
    262     LloadTierBackendCb *tier_remove_backend;
    263     LloadTierChange *tier_change;
    264 
    265     LloadTierSelect *tier_select;
    266 };
    267 
    268 struct LloadTier {
    269     struct lload_tier_type t_type;
    270     ldap_pvt_thread_mutex_t t_mutex;
    271 
    272     lload_b_head t_backends;
    273     int t_nbackends;
    274 
    275     enum {
    276         LLOAD_TIER_EXCLUSIVE = 1 << 0, /* Reject if busy */
    277     } t_flags;
    278 
    279     struct berval t_name;
    280 #ifdef BALANCER_MODULE
    281     monitor_subsys_t *t_monitor;
    282 #endif /* BALANCER_MODULE */
    283 
    284     void *t_private;
    285     LDAP_STAILQ_ENTRY(LloadTier) t_next;
    286 };
    287 
    288 /* Can hold mutex when locking a linked connection */
    289 struct LloadBackend {
    290     ldap_pvt_thread_mutex_t b_mutex;
    291 
    292     struct berval b_name, b_uri;
    293     int b_proto, b_port;
    294     enum lload_tls_type b_tls, b_tls_conf;
    295     char *b_host;
    296 
    297     int b_retry_timeout, b_failed;
    298     struct event *b_retry_event;
    299     struct timeval b_retry_tv;
    300 
    301     int b_numconns, b_numbindconns;
    302     int b_bindavail, b_active, b_opening;
    303     lload_c_head b_conns, b_bindconns, b_preparing;
    304     LDAP_LIST_HEAD(ConnectingSt, LloadPendingConnection) b_connecting;
    305     LloadConnection *b_last_conn, *b_last_bindconn;
    306 
    307     long b_max_pending, b_max_conn_pending;
    308     long b_n_ops_executing;
    309 
    310     lload_counters_t b_counters[LLOAD_STATS_OPS_LAST];
    311 
    312     LloadTier *b_tier;
    313 
    314     time_t b_last_update;
    315     uintptr_t b_fitness;
    316     int b_weight;
    317 
    318     uintptr_t b_operation_count;
    319     uintptr_t b_operation_time;
    320 
    321 #ifdef BALANCER_MODULE
    322     monitor_subsys_t *b_monitor;
    323 #endif /* BALANCER_MODULE */
    324 
    325     struct evdns_getaddrinfo_request *b_dns_req;
    326     void *b_cookie;
    327 
    328     LDAP_CIRCLEQ_ENTRY(LloadBackend) b_next;
    329 };
    330 
    331 typedef int (*LloadOperationHandler)( LloadConnection *client,
    332         LloadOperation *op,
    333         BerElement *ber );
    334 typedef int (*RequestHandler)( LloadConnection *c, LloadOperation *op );
    335 typedef struct lload_exop_handlers_t {
    336     struct berval oid;
    337     RequestHandler func;
    338 } ExopHandler;
    339 
    340 typedef int (*CONNECTION_PDU_CB)( LloadConnection *c );
    341 typedef void (*CONNECTION_DESTROY_CB)( LloadConnection *c );
    342 
    343 /* connection state (protected by c_mutex) */
    344 enum sc_state {
    345     LLOAD_C_INVALID = 0, /* MUST BE ZERO (0) */
    346     LLOAD_C_READY,       /* ready */
    347     LLOAD_C_CLOSING,     /* closing */
    348     LLOAD_C_ACTIVE,      /* exclusive operation (tls setup, ...) in progress */
    349     LLOAD_C_BINDING,     /* binding */
    350     LLOAD_C_DYING,       /* part-processed dead waiting to be freed, someone
    351                           * might still be observing it */
    352 };
    353 enum sc_type {
    354     LLOAD_C_OPEN = 0,  /* regular connection */
    355     LLOAD_C_PREPARING, /* upstream connection not assigned yet */
    356     LLOAD_C_BIND, /* connection used to handle bind client requests if VC not enabled */
    357     LLOAD_C_PRIVILEGED, /* connection can override proxyauthz control */
    358 };
    359 enum sc_io_state {
    360     LLOAD_C_OPERATIONAL = 0,        /* all is good */
    361     LLOAD_C_READ_HANDOVER = 1 << 0, /* A task to process PDUs is scheduled or
    362                                      * running, do not re-enable c_read_event */
    363     LLOAD_C_READ_PAUSE = 1 << 1,    /* We want to pause reading until the client
    364                                      * has sufficiently caught up with what we
    365                                      * sent */
    366 };
    367 
    368 /* Tracking whether an operation might cause a client to restrict which
    369  * upstreams are eligible */
    370 enum op_restriction {
    371     LLOAD_OP_NOT_RESTRICTED, /* no restrictions in place */
    372     LLOAD_OP_RESTRICTED_WRITE, /* client is restricted to a certain backend with
    373                                 * a timeout attached */
    374     LLOAD_OP_RESTRICTED_BACKEND, /* client is restricted to a certain backend,
    375                                   * without a timeout */
    376     LLOAD_OP_RESTRICTED_UPSTREAM, /* client is restricted to a certain upstream */
    377     LLOAD_OP_RESTRICTED_ISOLATE, /* TODO: client is restricted to a certain
    378                                   * upstream and removes the upstream from the
    379                                   * pool */
    380     LLOAD_OP_RESTRICTED_REJECT, /* operation should not be forwarded to any
    381                                  * backend, either it is processed internally
    382                                  * or rejected */
    383 };
    384 
    385 /*
    386  * represents a connection from an ldap client/to ldap server
    387  */
    388 struct LloadConnection {
    389     enum sc_state c_state; /* connection state */
    390     enum sc_type c_type;
    391     enum sc_io_state c_io_state;
    392     ber_socket_t c_fd;
    393 
    394 /*
    395  * LloadConnection reference counting:
    396  * - connection has a reference counter in c_refcnt
    397  * - also a liveness/validity token is added to c_refcnt during
    398  *   lload_connection_init, its existence is tracked in c_live and is usually the
    399  *   only one that prevents it from being destroyed
    400  * - anyone who needs to be able to relock the connection after unlocking it has
    401  *   to use acquire_ref(), they need to make sure a matching
    402  *   RELEASE_REF( c, c_refcnt, c->c_destroy ); is run eventually
    403  * - when a connection is considered dead, use CONNECTION_DESTROY on a locked
    404  *   connection, it will be made unreachable from normal places and either
    405  *   scheduled for reclamation when safe to do so or if anyone still holds a
    406  *   reference, it just gets unlocked and reclaimed after the last ref is
    407  *   released
    408  * - CONNECTION_LOCK_DESTROY is a shorthand for locking and CONNECTION_DESTROY
    409  */
    410     ldap_pvt_thread_mutex_t c_mutex; /* protect the connection */
    411     uintptr_t c_refcnt, c_live;
    412     CONNECTION_DESTROY_CB c_unlink;
    413     CONNECTION_DESTROY_CB c_destroy;
    414     CONNECTION_PDU_CB c_pdu_cb;
    415 #define CONNECTION_ASSERT_LOCKED(c) assert_locked( &(c)->c_mutex )
    416 #define CONNECTION_LOCK(c) \
    417     do { \
    418         checked_lock( &(c)->c_mutex ); \
    419     } while (0)
    420 #define CONNECTION_UNLOCK(c) \
    421     do { \
    422         checked_unlock( &(c)->c_mutex ); \
    423     } while (0)
    424 #define CONNECTION_UNLINK_(c) \
    425     do { \
    426         if ( __atomic_exchange_n( &(c)->c_live, 0, __ATOMIC_ACQ_REL ) ) { \
    427             (c)->c_unlink( (c) ); \
    428             RELEASE_REF( (c), c_refcnt, c->c_destroy ); \
    429         } \
    430     } while (0)
    431 #define CONNECTION_DESTROY(c) \
    432     do { \
    433         CONNECTION_UNLINK_(c); \
    434         CONNECTION_UNLOCK(c); \
    435     } while (0)
    436 #define CONNECTION_LOCK_DESTROY(c) \
    437     do { \
    438         CONNECTION_LOCK(c); \
    439         CONNECTION_DESTROY(c); \
    440     } while (0);
    441 
    442     Sockbuf *c_sb; /* ber connection stuff */
    443 
    444     /* set by connection_init */
    445     unsigned long c_connid;    /* unique id of this connection */
    446     struct berval c_peer_name; /* peer name (trans=addr:port) */
    447     time_t c_starttime;        /* when the connection was opened */
    448 
    449     time_t c_activitytime;  /* when the connection was last used */
    450     ber_int_t c_next_msgid; /* msgid of the next message */
    451 
    452     /* must not be used while holding either mutex */
    453     struct event *c_read_event, *c_write_event;
    454     struct timeval *c_read_timeout;
    455 
    456     /* can only be changed by binding thread */
    457     struct berval c_sasl_bind_mech; /* mech in progress */
    458     struct berval c_auth;           /* authcDN (possibly in progress) */
    459 
    460     unsigned long c_pin_id;
    461 
    462 #ifdef HAVE_CYRUS_SASL
    463     sasl_conn_t *c_sasl_authctx;
    464     void *c_sasl_defaults;
    465 #ifdef SASL_CHANNEL_BINDING /* 2.1.25+ */
    466     sasl_channel_binding_t *c_sasl_cbinding; /* Else cyrus-sasl would happily
    467                                               * leak it on sasl_dispose */
    468 #endif /* SASL_CHANNEL_BINDING */
    469 #endif /* HAVE_CYRUS_SASL */
    470 
    471 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
    472     struct berval c_vc_cookie;
    473 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
    474 
    475     /* Can be held while acquiring c_mutex to inject things into c_ops or
    476      * destroy the connection */
    477     ldap_pvt_thread_mutex_t c_io_mutex; /* only one pdu written at a time */
    478 
    479     BerElement *c_currentber; /* ber we're attempting to read */
    480     BerElement *c_pendingber; /* ber we're attempting to write */
    481 
    482     TAvlnode *c_ops; /* Operations pending on the connection */
    483 
    484 #ifdef HAVE_TLS
    485     enum lload_tls_type c_is_tls; /* true if this LDAP over raw TLS */
    486 #endif
    487 
    488     long c_n_ops_executing;      /* num of ops currently executing */
    489     long c_n_ops_completed;      /* num of ops completed */
    490     lload_counters_t c_counters; /* per connection operation counters */
    491 
    492     enum op_restriction c_restricted;
    493     uintptr_t c_restricted_inflight;
    494     time_t c_restricted_at;
    495     LloadBackend *c_backend;
    496     LloadConnection *c_linked_upstream;
    497 
    498     TAvlnode *c_linked;
    499 
    500 #ifdef BALANCER_MODULE
    501     struct berval c_monitor_dn;
    502 #endif /* BALANCER_MODULE */
    503 
    504     /*
    505      * Protected by the CIRCLEQ mutex:
    506      * - Client: clients_mutex
    507      * - Upstream: b->b_mutex
    508      */
    509     LDAP_CIRCLEQ_ENTRY(LloadConnection) c_next;
    510 };
    511 
    512 enum op_state {
    513     LLOAD_OP_NOT_FREEING = 0,
    514     LLOAD_OP_DETACHING_CLIENT = 1 << 1,
    515     LLOAD_OP_DETACHING_UPSTREAM = 1 << 0,
    516 };
    517 
    518 #define LLOAD_OP_DETACHING_MASK \
    519     ( LLOAD_OP_DETACHING_UPSTREAM | LLOAD_OP_DETACHING_CLIENT )
    520 
    521 /* operation result for monitoring purposes */
    522 enum op_result {
    523     LLOAD_OP_REJECTED,  /* operation was not forwarded */
    524     LLOAD_OP_COMPLETED, /* operation sent and response received */
    525     LLOAD_OP_FAILED, /* operation was forwarded, but no response was received */
    526 };
    527 
    528 /*
    529  * Operation reference tracking:
    530  * - o_refcnt is set to 1, never incremented
    531  * - OPERATION_UNLINK sets it to 0 and on transition from 1 clears both
    532  *   connection links (o_client, o_upstream)
    533  */
    534 struct LloadOperation {
    535     uintptr_t o_refcnt;
    536 #define OPERATION_UNLINK(op) \
    537     try_release_ref( &(op)->o_refcnt, (op), \
    538             (dispose_cb *)operation_unlink, \
    539             (dispose_cb *)operation_destroy )
    540 
    541     LloadConnection *o_client;
    542     unsigned long o_client_connid;
    543     ber_int_t o_client_msgid;
    544     ber_int_t o_saved_msgid;
    545     enum op_restriction o_restricted;
    546 
    547     LloadConnection *o_upstream;
    548     unsigned long o_upstream_connid;
    549     ber_int_t o_upstream_msgid;
    550     struct timeval o_last_response;
    551 
    552     /* Protects o_client, o_upstream links */
    553     ldap_pvt_thread_mutex_t o_link_mutex;
    554 
    555     ber_tag_t o_tag;
    556     struct timeval o_start;
    557     unsigned long o_pin_id;
    558 
    559     enum op_result o_res;
    560     BerElement *o_ber;
    561     BerValue o_request, o_ctrls;
    562 };
    563 
    564 struct restriction_entry {
    565     struct berval oid;
    566     enum op_restriction action;
    567 };
    568 
    569 /*
    570  * listener; need to access it from monitor backend
    571  */
    572 struct LloadListener {
    573     struct berval sl_url;
    574     struct berval sl_name;
    575     mode_t sl_perms;
    576 #ifdef HAVE_TLS
    577     int sl_is_tls;
    578 #endif
    579     int sl_is_proxied;
    580     struct event_base *base;
    581     struct evconnlistener *listener;
    582     int sl_mute; /* Listener is temporarily disabled due to emfile */
    583     int sl_busy; /* Listener is busy (accept thread activated) */
    584     ber_socket_t sl_sd;
    585     Sockaddr sl_sa;
    586 #define sl_addr sl_sa.sa_in_addr
    587 #define LDAP_TCP_BUFFER
    588 #ifdef LDAP_TCP_BUFFER
    589     int sl_tcp_rmem; /* custom TCP read buffer size */
    590     int sl_tcp_wmem; /* custom TCP write buffer size */
    591 #endif
    592 };
    593 
    594 typedef int (*CONNCB)( LloadConnection *c, void *arg );
    595 
    596 /* config requires a bi_private with configuration data - dummy for now */
    597 struct lload_conf_info {
    598     int dummy;
    599 };
    600 LDAP_END_DECL
    601 
    602 #include "proto-lload.h"
    603 #endif /* _LLOAD_H_ */
    604