OL_ARG_ENABLE(balancer, [AS_HELP_STRING([--enable-balancer], [enable load balancer])],
no, [no yes mod])
+dnl ----------------------------------------------------------------
+dnl TESTSUITE OPTIONS
+AC_ARG_ENABLE(testoptions,[
+Test suite Options:])
+OL_ARG_ENABLE(harness, [AS_HELP_STRING([--enable-harness], [enable mod_harness])],
+ no, [no yes])
+
dnl ----------------------------------------------------------------
AC_ARG_ENABLE(xxliboptions,[
Library Generation & Linking Options])
AC_MSG_WARN([slapd disabled, ignoring --enable-balancer=mod argument])
ol_enable_balancer=no
fi
+
+ if test $ol_enable_harness != no ; then
+ AC_MSG_WARN([slapd disabled, ignoring --enable-harness=$ol_enable_harness argument])
+ ol_enable_harness=no
+ fi
else
dnl If slapd enabled and loadable module support disabled
dnl then require at least one built-in backend
fi
done
- for i in $Pwmods; do
+ for i in harness $Pwmods; do
eval "ol_tmp=\$ol_enable_$i"
if test -n "$ol_tmp" && test "$ol_tmp" = yes ; then
AC_MSG_ERROR([--enable-$i=yes requires --enable-modules])
BUILD_PW_ARGON2=no
+BUILD_HARNESS=no
+
SLAPD_STATIC_OVERLAYS=
SLAPD_DYNAMIC_OVERLAYS=
fi
fi
+dnl ----------------------------------------------------------------
+dnl Test suite
+
+dnl We use 'yes' but mean 'mod' as far as our Makefile infra is concerned
+if test $ol_enable_harness != no; then
+ BUILD_HARNESS=mod
+fi
+
dnl ----------------------------------------------------------------
dnl
AC_SUBST(BUILD_BALANCER)
dnl pwmods
AC_SUBST(BUILD_PW_ARGON2)
+dnl test suite
+ AC_SUBST(BUILD_HARNESS)
AC_SUBST(LDAP_LIBS)
AC_SUBST(CLIENT_LIBS)
[servers/lloadd/Makefile.module:servers/lloadd/Makefile_module.in:build/mod.mk]
[tests/Makefile:build/top.mk:tests/Makefile.in:build/dir.mk]
[tests/run]
+[tests/modules/Makefile:build/top.mk:tests/modules/Makefile.in:build/dir.mk]
+[tests/modules/mod-harness/Makefile:build/top.mk:tests/modules/mod-harness/Makefile.in:build/mod.mk]
[tests/progs/Makefile:build/top.mk:tests/progs/Makefile.in:build/rules.mk])
AC_CONFIG_COMMANDS([default],[[
--- /dev/null
+/* config.c - configuration of the test harness backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2007-2019 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>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Ondřej Kuzník for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "slap.h"
+#include "slap-config.h"
+#include "mod-harness.h"
+
+static int config_generic(ConfigArgs *c);
+
+enum {
+ CFG_HOST = 1,
+ CFG_PORT,
+ CFG_IDENTIFIER,
+
+ CFG_LAST
+};
+
+static ConfigTable harness_cf_table[] = {
+ { "host", "hostname", 2, 2, 0, ARG_OFFSET|ARG_STRING|CFG_HOST,
+ (void *)offsetof(struct harness_conf_info, h_host),
+ "( OLcfgDbAt:14.1 NAME 'olcBkHarnessHost' "
+ "DESC 'Hostname to connect to' "
+ "EQUALITY caseIgnoreMatch "
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
+ { "port", "port", 2, 2, 0, ARG_MAGIC|ARG_UINT|CFG_PORT,
+ &config_generic,
+ "( OLcfgDbAt:14.2 NAME 'olcBkHarnessPort' "
+ "DESC 'Port to connect to' "
+ "EQUALITY integerMatch "
+ "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+ { "identifier", "identifier", 2, 2, 0, ARG_OFFSET|ARG_STRING|CFG_IDENTIFIER,
+ (void *)offsetof(struct harness_conf_info, h_identifier),
+ "( OLcfgDbAt:14.3 NAME 'olcBkHarnessIdentifier' "
+ "DESC 'A token identifying this server' "
+ "EQUALITY caseIgnoreMatch "
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
+ { NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL }
+};
+
+static ConfigOCs harness_ocs[] = {
+ { "( OLcfgBkOc:14.1 "
+ "NAME 'olcBkHarnessConfig' "
+ "DESC 'Harness module backend configuration' "
+ "SUP olcBackendConfig "
+ "MUST ( olcBkHarnessHost "
+ "$ olcBkHarnessPort "
+ "$ olcBkHarnessIdentifier "
+ ") )",
+ Cft_Backend, harness_cf_table,
+ },
+ { NULL, 0, NULL }
+};
+
+static int
+config_generic(ConfigArgs *c)
+{
+ struct harness_conf_info *hi = c->bi->bi_private;
+ int rc = LDAP_SUCCESS;
+
+ if ( c->op == SLAP_CONFIG_EMIT ) {
+ switch( c->type ) {
+ case CFG_PORT:
+ c->value_uint = hi->h_port;
+ break;
+ default:
+ rc = 1;
+ break;
+ }
+ return rc;
+
+ } else if ( c->op == LDAP_MOD_DELETE ) {
+ /* We don't allow removing/reconfiguration (yet) */
+ Debug( LDAP_DEBUG_ANY,
+ "%s: mod_harness doesn't support reconfiguration\n",
+ c->log );
+ return 1;
+ }
+
+ switch ( c->type ) {
+ case CFG_PORT:
+ if ( c->value_uint <= 0 || c->value_uint > 65535 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: port %d invalid\n",
+ c->log, c->value_uint );
+ rc = 1;
+ }
+ hi->h_port = c->value_uint;
+ break;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: unknown CFG_TYPE %d\n",
+ c->log, c->type );
+ return 1;
+ }
+
+ return rc;
+}
+
+int
+harness_back_init_cf( BackendInfo *bi )
+{
+ bi->bi_cf_ocs = harness_ocs;
+
+ /* Make sure we don't exceed the bits reserved for userland */
+ config_check_userland( CFG_LAST );
+
+ return config_register_schema( harness_cf_table, harness_ocs );
+}
--- /dev/null
+/* init.c - initialize test harness backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2007-2019 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>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Ondřej Kuzník for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/errno.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "mod-harness.h"
+
+struct harness_conf_info harness_info;
+
+static void *
+harness_ready( void *ctx, void *arg )
+{
+ BackendInfo *bi = arg;
+ struct harness_conf_info *hi = bi->bi_private;
+
+ ldap_pvt_thread_mutex_lock( &slapd_init_mutex );
+ while ( !slapd_ready && !slapd_shutdown ) {
+ ldap_pvt_thread_cond_wait( &slapd_init_cond, &slapd_init_mutex );
+ }
+ ldap_pvt_thread_mutex_unlock( &slapd_init_mutex );
+
+ if ( !slapd_shutdown ) {
+ dprintf( hi->h_conn->c_sd, "SLAPD READY\n" );
+ }
+ return NULL;
+}
+
+static int
+harness_resolve_addresses(
+ const char *host,
+ unsigned short port,
+ struct sockaddr ***sal )
+{
+ struct sockaddr **sap;
+
+#ifdef LDAP_PF_LOCAL
+ if ( port == 0 ) {
+ *sal = ch_malloc(2 * sizeof(void *));
+
+ sap = *sal;
+ *sap = ch_malloc(sizeof(struct sockaddr_un));
+ sap[1] = NULL;
+
+ if ( strlen(host) >
+ (sizeof(((struct sockaddr_un *)*sap)->sun_path) - 1) )
+ {
+ Debug( LDAP_DEBUG_ANY, "harness_resolve_addresses: "
+ "domain socket path (%s) too long in URL\n",
+ host );
+ goto errexit;
+ }
+
+ (void)memset( (void *)*sap, '\0', sizeof(struct sockaddr_un) );
+ (*sap)->sa_family = AF_LOCAL;
+ strcpy( ((struct sockaddr_un *)*sap)->sun_path, host );
+ } else
+#endif /* LDAP_PF_LOCAL */
+ {
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo hints, *res, *sai;
+ int n, err;
+ char serv[7];
+
+ memset( &hints, '\0', sizeof(hints) );
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = slap_inet4or6;
+ snprintf(serv, sizeof serv, "%d", port);
+
+ if ( (err = getaddrinfo(host, serv, &hints, &res)) ) {
+ Debug( LDAP_DEBUG_ANY, "harness_resolve_addresses: "
+ "getaddrinfo() failed: %s\n",
+ AC_GAI_STRERROR(err) );
+ return -1;
+ }
+
+ sai = res;
+ for (n=2; (sai = sai->ai_next) != NULL; n++) {
+ /* EMPTY */ ;
+ }
+ *sal = ch_calloc(n, sizeof(void *));
+ if (*sal == NULL) return -1;
+
+ sap = *sal;
+ *sap = NULL;
+
+ for ( sai=res; sai; sai=sai->ai_next ) {
+ if( sai->ai_addr == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "harness_resolve_addresses: "
+ "getaddrinfo ai_addr is NULL?\n" );
+ freeaddrinfo(res);
+ goto errexit;
+ }
+
+ switch ( sai->ai_family ) {
+# ifdef LDAP_PF_INET6
+ case AF_INET6:
+ *sap = ch_malloc(sizeof(struct sockaddr_in6));
+ *(struct sockaddr_in6 *)*sap =
+ *((struct sockaddr_in6 *)sai->ai_addr);
+ break;
+# endif /* LDAP_PF_INET6 */
+ case AF_INET:
+ *sap = ch_malloc(sizeof(struct sockaddr_in));
+ *(struct sockaddr_in *)*sap =
+ *((struct sockaddr_in *)sai->ai_addr);
+ break;
+ default:
+ *sap = NULL;
+ break;
+ }
+
+ if (*sap != NULL) {
+ (*sap)->sa_family = sai->ai_family;
+ sap++;
+ *sap = NULL;
+ }
+ }
+
+ freeaddrinfo(res);
+
+#else /* ! HAVE_GETADDRINFO */
+ int i, n = 1;
+ struct in_addr in;
+ struct hostent *he = NULL;
+
+ if ( !inet_aton( host, &in ) ) {
+ he = gethostbyname( host );
+ if( he == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "harness_resolve_addresses: "
+ "invalid host %s\n", host );
+ return -1;
+ }
+ for (n = 0; he->h_addr_list[n]; n++) /* empty */;
+ }
+
+ *sal = ch_malloc((n+1) * sizeof(void *));
+
+ sap = *sal;
+ for ( i = 0; i<n; i++ ) {
+ sap[i] = ch_malloc(sizeof(struct sockaddr_in));
+
+ (void)memset( (void *)sap[i], '\0', sizeof(struct sockaddr_in) );
+ sap[i]->sa_family = he->h_addrtype;
+ switch ( he->h_addrtype ) {
+ case AF_INET:
+ ((struct sockaddr_in *)sap[i])->sin_port = htons(port);
+ break;
+# ifdef LDAP_PF_INET6
+ case AF_INET6:
+ ((struct sockaddr_in6 *)sap[i])->sin6_port = htons(port);
+ break;
+# endif /* LDAP_PF_INET6 */
+ default:
+ Debug( LDAP_DEBUG_ANY, "harness_resolve_addresses: "
+ "unknown protocol family from gethostbyname\n" );
+ goto errexit;
+ }
+
+ AC_MEMCPY( &((struct sockaddr_in *)sap[i])->sin_addr,
+ he ? (struct in_addr *)he->h_addr_list[i] : &in,
+ sizeof(struct in_addr) );
+ }
+ sap[i] = NULL;
+#endif /* ! HAVE_GETADDRINFO */
+ }
+
+ return 0;
+
+errexit:
+ for (sap = *sal; *sap != NULL; sap++) ch_free(*sap);
+ ch_free(*sal);
+ return -1;
+}
+
+static int
+harness_connect( BackendInfo *bi )
+{
+ struct harness_conf_info *hi = bi->bi_private;
+ struct sockaddr **res, **sal;
+ int rc = -1;
+
+ if ( !hi->h_host || !hi->h_port ) {
+ Debug( LDAP_DEBUG_ANY, "harness_connect: "
+ "configuration incomplete, host or port missing\n" );
+ return rc;
+ }
+
+ if ( harness_resolve_addresses( hi->h_host, hi->h_port, &res ) ) {
+ return rc;
+ }
+
+ for ( sal=res; *sal; sal++ ) {
+ char ebuf[128];
+ Connection *c;
+ char *af;
+ ber_socket_t s;
+ socklen_t addrlen;
+
+ switch ( (*sal)->sa_family ) {
+ case AF_INET:
+ af = "IPv4";
+ addrlen = sizeof(struct sockaddr_in);
+ break;
+#ifdef LDAP_PF_INET6
+ case AF_INET6:
+ af = "IPv6";
+ addrlen = sizeof(struct sockaddr_in6);
+ break;
+#endif /* LDAP_PF_INET6 */
+#ifdef LDAP_PF_LOCAL
+ case AF_LOCAL:
+ af = "Local";
+ addrlen = sizeof(struct sockaddr_un);
+ break;
+#endif /* LDAP_PF_LOCAL */
+ default:
+ sal++;
+ continue;
+ }
+
+ s = socket( (*sal)->sa_family, SOCK_STREAM, 0 );
+ if ( s == AC_SOCKET_INVALID ) {
+ int err = sock_errno();
+ Debug( LDAP_DEBUG_ANY, "harness_connect: "
+ "%s socket() failed errno=%d (%s)\n",
+ af, err, sock_errstr( err, ebuf, sizeof(ebuf) ) );
+ continue;
+ }
+
+ if ( connect( s, (struct sockaddr *)*sal, addrlen ) == AC_SOCKET_ERROR ) {
+ int err = sock_errno();
+ Debug( LDAP_DEBUG_ANY, "harness_connect: "
+ "connect() failed errno=%d (%s)\n",
+ err, sock_errstr( err, ebuf, sizeof(ebuf) ) );
+ close( s );
+ continue;
+ }
+
+ c = connection_client_setup( s, harness_callback, hi );
+ if ( c == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "harness_connect: "
+ "could not allocate connection\n" );
+ close( s );
+ }
+
+ hi->h_conn = c;
+ dprintf( c->c_sd, "PID %d %s\n", getpid(), hi->h_identifier );
+ rc = 0;
+ break;
+ }
+
+ ch_free( res );
+ return rc;
+}
+
+static int
+harness_back_open( BackendInfo *bi )
+{
+ struct harness_conf_info *hi = bi->bi_private;
+ Listener **l;
+
+ if ( slapMode & SLAP_TOOL_MODE ) {
+ return 0;
+ }
+
+ if ( harness_connect( bi ) ) {
+ Debug( LDAP_DEBUG_ANY, "harness_back_open: "
+ "failed to contact test harness\n" );
+ return -1;
+ }
+
+ if ( ( l = slapd_get_listeners() ) == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "harness_back_open: "
+ "unable to get listeners\n" );
+ return -1;
+ }
+
+ /* FIXME: A temporary text protocol for human consumption */
+ dprintf( hi->h_conn->c_sd, "LISTENERS\n" );
+ for ( ; *l; l++ ) {
+ dprintf( hi->h_conn->c_sd, "URI=%s %s\n",
+ (*l)->sl_url.bv_val, (*l)->sl_name.bv_val );
+ }
+ dprintf( hi->h_conn->c_sd, "LISTENERS END\n" );
+
+ /* Contact harness as soon as startup finishes and slapd is running */
+ return ldap_pvt_thread_pool_submit( &connection_pool, harness_ready, bi );
+}
+
+static int
+harness_back_close( BackendInfo *bi )
+{
+ struct harness_conf_info *hi = bi->bi_private;
+
+ if ( slapMode & SLAP_TOOL_MODE ) {
+ return 0;
+ }
+
+ if ( slapd_shutdown ) {
+ dprintf( hi->h_conn->c_sd, "SLAPD SHUTDOWN\n" );
+ } else {
+ dprintf( hi->h_conn->c_sd, "MODULE STOPPED\n" );
+ }
+
+ return 0;
+}
+
+static int
+harness_global_init( void )
+{
+ return 0;
+}
+
+static int
+harness_global_destroy( BackendInfo *bi )
+{
+ return 0;
+}
+
+int
+harness_back_initialize( BackendInfo *bi )
+{
+ Debug( LDAP_DEBUG_TRACE, "harness_back_initialize: "
+ "module loaded\n" );
+
+ bi->bi_flags = SLAP_BFLAG_STANDALONE;
+ bi->bi_open = harness_back_open;
+ bi->bi_config = 0;
+ bi->bi_pause = 0;
+ bi->bi_unpause = 0;
+ bi->bi_close = harness_back_close;
+ bi->bi_destroy = harness_global_destroy;
+
+ bi->bi_db_init = 0;
+ bi->bi_db_config = 0;
+ bi->bi_db_open = 0;
+ bi->bi_db_close = 0;
+ bi->bi_db_destroy = 0;
+
+ bi->bi_op_bind = 0;
+ bi->bi_op_unbind = 0;
+ bi->bi_op_search = 0;
+ bi->bi_op_compare = 0;
+ bi->bi_op_modify = 0;
+ bi->bi_op_modrdn = 0;
+ bi->bi_op_add = 0;
+ bi->bi_op_delete = 0;
+ bi->bi_op_abandon = 0;
+
+ bi->bi_extended = 0;
+
+ bi->bi_chk_referrals = 0;
+
+ bi->bi_connection_init = 0;
+ bi->bi_connection_destroy = 0;
+
+ if ( harness_global_init() ) {
+ return -1;
+ }
+
+ bi->bi_private = &harness_info;
+ return harness_back_init_cf( bi );
+}
+
+SLAP_BACKEND_INIT_MODULE( harness )