From bf66b48fe31cada8f6bf8066f34d0a44c9ecaff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Thu, 16 Mar 2017 12:11:45 +0000 Subject: [PATCH] Upstream connection setup --- servers/lloadd/Makefile.in | 4 +- servers/lloadd/backend.c | 149 ++++++++++++++++++++++++++++++++++++ servers/lloadd/client.c | 2 +- servers/lloadd/connection.c | 7 +- servers/lloadd/proto-slap.h | 15 +++- servers/lloadd/upstream.c | 114 +++++++++++++++++++++++++++ 6 files changed, 284 insertions(+), 7 deletions(-) create mode 100644 servers/lloadd/backend.c create mode 100644 servers/lloadd/upstream.c diff --git a/servers/lloadd/Makefile.in b/servers/lloadd/Makefile.in index 768d3e71e1..54beefffe9 100644 --- a/servers/lloadd/Makefile.in +++ b/servers/lloadd/Makefile.in @@ -21,8 +21,8 @@ XSRCS = version.c NT_SRCS = nt_svc.c NT_OBJS = nt_svc.o ../../libraries/liblutil/slapdmsg.res -SRCS = main.c globals.c config.c connection.c client.c daemon.c \ - ch_malloc.c init.c user.c sl_malloc.c value.c \ +SRCS = main.c globals.c backend.c config.c connection.c client.c daemon.c \ + ch_malloc.c init.c user.c sl_malloc.c upstream.c value.c \ libevent_support.c \ $(@PLAT@_SRCS) diff --git a/servers/lloadd/backend.c b/servers/lloadd/backend.c new file mode 100644 index 0000000000..9101c7b4a9 --- /dev/null +++ b/servers/lloadd/backend.c @@ -0,0 +1,149 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * 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 + * . + */ + +#include "portable.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "lutil.h" +#include "slap.h" + +static void +upstream_name_cb( int result, struct evutil_addrinfo *res, void *arg ) +{ + Backend *b = arg; + Connection *c; + ber_socket_t s; + int rc; + + if ( result || !res ) { + Debug( LDAP_DEBUG_ANY, "upstream_name_cb: " + "name resolution failed for backend '%s': %s\n", + b->b_bindconf.sb_uri.bv_val, evutil_gai_strerror( result ) ); + return; + } + + s = socket( res->ai_family, SOCK_STREAM, 0 ); + if ( s == AC_SOCKET_INVALID ) { + return; + } + + rc = ber_pvt_socket_set_nonblock( s, 1 ); + if ( rc ) { + evutil_closesocket( s ); + return; + } + + if ( res->ai_family == PF_INET ) { + struct sockaddr_in *ai = (struct sockaddr_in *)res->ai_addr; + ai->sin_port = htons( b->b_port ); + rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen ); + } else { + struct sockaddr_in6 *ai = (struct sockaddr_in6 *)res->ai_addr; + ai->sin6_port = htons( b->b_port ); + rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen ); + } + if ( rc && errno != EINPROGRESS && errno != EWOULDBLOCK ) { + Debug( LDAP_DEBUG_ANY, "upstream_name_cb: " + "failed to connect to server '%s'\n", + b->b_bindconf.sb_uri.bv_val ); + evutil_closesocket( s ); + return; + } + + c = upstream_init( s, b ); + ldap_pvt_thread_mutex_lock( &b->b_lock ); + b->b_conns = c; + ldap_pvt_thread_mutex_unlock( &b->b_lock ); +} + +Connection * +backend_select( Operation *op ) +{ + Backend *b; + + LDAP_STAILQ_FOREACH ( b, &backend, b_next ) { + Connection *c; + + ldap_pvt_thread_mutex_lock( &b->b_lock ); + c = b->b_conns; + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + if ( c->c_struct_state != SLAP_C_UNINITIALIZED && !c->c_pendingber ) { + ldap_pvt_thread_mutex_unlock( &b->b_lock ); + return b->b_conns; + } + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + ldap_pvt_thread_mutex_unlock( &b->b_lock ); + } + + return NULL; +} + +void * +backend_connect( Backend *b ) +{ + struct evutil_addrinfo hints = {}; + +#ifdef LDAP_PF_LOCAL + if ( b->b_proto == LDAP_PROTO_IPC ) { + struct sockaddr_un addr; + ber_socket_t s = socket( PF_LOCAL, SOCK_STREAM, 0 ); + int rc; + + if ( s == AC_SOCKET_INVALID ) { + return (void *)-1; + } + + rc = ber_pvt_socket_set_nonblock( s, 1 ); + if ( rc ) { + evutil_closesocket( s ); + return (void *)-1; + } + + if ( strlen( b->b_host ) > ( sizeof(addr.sun_path) - 1 ) ) { + evutil_closesocket( s ); + return (void *)-1; + } + memset( &addr, '\0', sizeof(addr) ); + addr.sun_family = AF_LOCAL; + strcpy( addr.sun_path, b->b_host ); + + rc = connect( + s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un) ); + if ( rc && errno != EINPROGRESS && errno != EWOULDBLOCK ) { + evutil_closesocket( s ); + return (void *)-1; + } + + b->b_conns = upstream_init( s, b ); + return NULL; + } +#endif /* LDAP_PF_LOCAL */ + + hints.ai_family = AF_UNSPEC; + hints.ai_flags = EVUTIL_AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + evdns_getaddrinfo( dnsbase, b->b_host, NULL, &hints, upstream_name_cb, b ); + return NULL; +} diff --git a/servers/lloadd/client.c b/servers/lloadd/client.c index d40fe49d87..7dfac6a486 100644 --- a/servers/lloadd/client.c +++ b/servers/lloadd/client.c @@ -38,7 +38,7 @@ client_read_cb( evutil_socket_t s, short what, void *arg ) client_destroy( c ); } -static void +void client_write_cb( evutil_socket_t s, short what, void *arg ) { Connection *c = arg; diff --git a/servers/lloadd/connection.c b/servers/lloadd/connection.c index 9824de2284..f86cce3f12 100644 --- a/servers/lloadd/connection.c +++ b/servers/lloadd/connection.c @@ -59,14 +59,17 @@ connection_destroy( Connection *c ) c->c_connid ); assert( c->c_struct_state == SLAP_C_UNINITIALIZED ); - evutil_closesocket( c->c_fd ); + ber_sockbuf_free( c->c_sb ); + + if ( c->c_currentber ) { + ber_free( c->c_currentber, 1 ); + } ldap_pvt_thread_mutex_unlock( &c->c_mutex ); ldap_pvt_thread_mutex_destroy( &c->c_io_mutex ); ldap_pvt_thread_mutex_destroy( &c->c_mutex ); - ber_sockbuf_free( c->c_sb ); ch_free( c ); } diff --git a/servers/lloadd/proto-slap.h b/servers/lloadd/proto-slap.h index 92464f7e28..869dbe9b0b 100644 --- a/servers/lloadd/proto-slap.h +++ b/servers/lloadd/proto-slap.h @@ -57,6 +57,12 @@ LDAP_SLAPD_F (void) ch_free( void * ); #define free ch_free #endif +/* + * client.c + */ +LDAP_SLAPD_F (Connection *) client_init( ber_socket_t s, Listener *url, const char *peername, struct event_base *base, int use_tls ); +LDAP_SLAPD_F (void) client_write_cb( evutil_socket_t s, short what, void *arg ); + /* * config.c */ @@ -70,8 +76,6 @@ LDAP_SLAPD_F (void) bindconf_free( slap_bindconf *bc ); * connection.c */ LDAP_SLAPD_F (Connection *) connection_init( ber_socket_t s, const char *peername, int use_tls ); -LDAP_SLAPD_F (Connection *) client_init( ber_socket_t s, Listener *url, const char *peername, struct event_base *base, int use_tls ); -LDAP_SLAPD_F (Connection *) upstream_init( ber_socket_t s, Backend *b ); LDAP_SLAPD_F (void) connection_destroy( Connection *c ); /* @@ -147,6 +151,13 @@ LDAP_SLAPD_F (void *) slap_sl_context( void *ptr ); /* assumes (x) > (y) returns 1 if true, 0 otherwise */ #define SLAP_PTRCMP(x, y) ( (x) < (y) ? -1 : (x) > (y) ) +/* + * upstream.c + */ +LDAP_SLAPD_F (void) upstream_write_cb( evutil_socket_t s, short what, void *arg ); +LDAP_SLAPD_F (void) upstream_read_cb( evutil_socket_t s, short what, void *arg ); +LDAP_SLAPD_F (Connection *) upstream_init( ber_socket_t s, Backend *b ); + /* * user.c */ diff --git a/servers/lloadd/upstream.c b/servers/lloadd/upstream.c new file mode 100644 index 0000000000..9702d5a523 --- /dev/null +++ b/servers/lloadd/upstream.c @@ -0,0 +1,114 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * 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 + * . + */ + +#include "portable.h" + +#include +#include +#include +#include +#include + +#include "lutil.h" +#include "slap.h" + +static void upstream_destroy( Connection *c ); + +void +upstream_read_cb( evutil_socket_t s, short what, void *arg ) +{ + Connection *c = arg; + + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + upstream_destroy( c ); +} + +void +upstream_write_cb( evutil_socket_t s, short what, void *arg ) +{ + Connection *c = arg; +} + +Connection * +upstream_init( ber_socket_t s, Backend *backend ) +{ + Connection *c; + struct event_base *base = slap_get_base( s ); + struct event *event; + int flags = (backend->b_tls == LLOAD_LDAPS) ? CONN_IS_TLS : 0; + + assert( backend != NULL ); + + c = connection_init( s, backend->b_host, flags ); + + event = event_new( base, s, EV_READ|EV_PERSIST, upstream_read_cb, c ); + if ( !event ) { + Debug( LDAP_DEBUG_ANY, "Read event could not be allocated\n" ); + goto fail; + } + event_add( event, NULL ); + c->c_read_event = event; + + event = event_new( base, s, EV_WRITE, upstream_write_cb, c ); + if ( !event ) { + Debug( LDAP_DEBUG_ANY, "Write event could not be allocated\n" ); + goto fail; + } + /* We only register the write event when we have data pending */ + c->c_write_event = event; + + c->c_private = backend; + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + + return c; +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 ); + } + connection_destroy( c ); + return NULL; +} + +static void +upstream_destroy( Connection *c ) +{ + Backend *b = c->c_private; + + c->c_struct_state = SLAP_C_UNINITIALIZED; + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + + ldap_pvt_thread_mutex_lock( &b->b_lock ); + if ( !(b->b_conns == c) ) { + ldap_pvt_thread_mutex_unlock( &b->b_lock ); + return; + } + b->b_conns = NULL; + ldap_pvt_thread_mutex_unlock( &b->b_lock ); + + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + + event_del( c->c_read_event ); + event_free( c->c_read_event ); + + event_del( c->c_write_event ); + event_free( c->c_write_event ); + + connection_destroy( c ); +}