summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/statechange
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/plugins/statechange
downloadds-ldapserver7x.tar.gz
ds-ldapserver7x.tar.xz
ds-ldapserver7x.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/plugins/statechange')
-rw-r--r--ldap/servers/plugins/statechange/Makefile78
-rw-r--r--ldap/servers/plugins/statechange/dllmain.c96
-rw-r--r--ldap/servers/plugins/statechange/statechange.c450
-rw-r--r--ldap/servers/plugins/statechange/statechange.def10
4 files changed, 634 insertions, 0 deletions
diff --git a/ldap/servers/plugins/statechange/Makefile b/ldap/servers/plugins/statechange/Makefile
new file mode 100644
index 00000000..bc04a3f0
--- /dev/null
+++ b/ldap/servers/plugins/statechange/Makefile
@@ -0,0 +1,78 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+LDAP_SRC = ../../..
+MCOM_ROOT = ../../../../..
+
+NOSTDCLEAN=true # don't let nsconfig.mk define target clean
+NOSTDSTRIP=true # don't let nsconfig.mk define target strip
+NSPR20=true # probably should be defined somewhere else (not sure where)
+
+OBJDEST = $(OBJDIR)/lib/libstatechange
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./statechange.def
+endif
+
+STATECHANGE_OBJS = statechange.o
+OBJS = $(addprefix $(OBJDEST)/, $(STATECHANGE_OBJS))
+
+STATECHANGE_DLL = statechange-plugin
+
+INCLUDES += -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD)
+EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD)
+STATECHANGE_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), AIX)
+LD=ld
+EXTRA_LIBS += $(LIBSLAPD)
+endif
+
+STATECHANGE= $(addprefix $(LIBDIR)/, $(STATECHANGE_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(STATECHANGE)
+
+ifeq ($(ARCH), WINNT)
+$(STATECHANGE): $(OBJS) $(STATECHANGE_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(STATECHANGE_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(STATECHANGE): $(OBJS) $(STATECHANGE_DLL_OBJ)
+ $(LINK_DLL) $(STATECHANGE_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(STATECHANGE_DLL_OBJ)
+endif
+ $(RM) $(STATECHANGE)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
diff --git a/ldap/servers/plugins/statechange/dllmain.c b/ldap/servers/plugins/statechange/dllmain.c
new file mode 100644
index 00000000..fabf8677
--- /dev/null
+++ b/ldap/servers/plugins/statechange/dllmain.c
@@ -0,0 +1,96 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/statechange/statechange.c b/ldap/servers/plugins/statechange/statechange.c
new file mode 100644
index 00000000..c0942b41
--- /dev/null
+++ b/ldap/servers/plugins/statechange/statechange.c
@@ -0,0 +1,450 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* plugin which provides a callback mechanism for state changes in the DS */
+
+#include <stdio.h>
+#include <string.h>
+#include "portable.h"
+#include "slapi-plugin.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+#include "statechange.h"
+
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+/* the circular list of systems to notify */
+typedef struct _statechange_notify
+{
+ char *caller_id;
+ char *dn;
+ char *filter;
+ Slapi_Filter *realfilter;
+ notify_callback func;
+ void *caller_data;
+ struct _statechange_notify *next;
+ struct _statechange_notify *prev;
+} SCNotify;
+
+static SCNotify *head; /* a place to start in the list */
+
+#define SCN_PLUGIN_SUBSYSTEM "statechange-plugin" /* used for logging */
+
+static void *api[5];
+static Slapi_Mutex *buffer_lock = 0;
+
+/* other function prototypes */
+int statechange_init( Slapi_PBlock *pb );
+static int statechange_start( Slapi_PBlock *pb );
+static int statechange_close( Slapi_PBlock *pb );
+static int statechange_post_op( Slapi_PBlock *pb, int modtype );
+static int statechange_mod_post_op( Slapi_PBlock *pb );
+static int statechange_modrdn_post_op( Slapi_PBlock *pb );
+static int statechange_add_post_op( Slapi_PBlock *pb );
+static int statechange_delete_post_op( Slapi_PBlock *pb );
+static int _statechange_register(char *caller_id, char *dn, char *filter, void *caller_data, notify_callback func);
+static void *_statechange_unregister(char *dn, char *filter, notify_callback func);
+static void _statechange_unregister_all(char *caller_id, caller_data_free_callback);
+static void _statechange_vattr_cache_invalidator_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data);
+static SCNotify *statechange_find_notify(char *dn, char *filter, notify_callback func);
+
+
+static Slapi_PluginDesc pdesc = { "statechange", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "state change notification service plugin" };
+
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+
+/*
+ statechange_init
+ --------
+ adds our callbacks to the list
+*/
+int statechange_init( Slapi_PBlock *pb )
+{
+ int ret = 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "--> statechange_init\n");
+
+ head = 0;
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) statechange_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
+ (void *) statechange_mod_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN,
+ (void *) statechange_modrdn_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
+ (void *) statechange_add_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
+ (void *) statechange_delete_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) statechange_close ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, SCN_PLUGIN_SUBSYSTEM,
+ "statechange_init: failed to register plugin\n" );
+ ret = -1;
+ }
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_init\n");
+ return ret;
+}
+
+
+/*
+ statechange_start
+ ---------
+ This function publishes the interface for this plugin
+*/
+static int statechange_start( Slapi_PBlock *pb )
+{
+ int ret = 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "--> statechange_start\n");
+
+ api[0] = 0; /* reserved for api broker use, must be zero */
+ api[1] = (void *)_statechange_register;
+ api[2] = (void *)_statechange_unregister;
+ api[3] = (void *)_statechange_unregister_all;
+ api[4] = (void *)_statechange_vattr_cache_invalidator_callback;
+
+ if(0 == (buffer_lock = slapi_new_mutex())) /* we never free this mutex */
+ {
+ /* badness */
+ slapi_log_error( SLAPI_LOG_FATAL, SCN_PLUGIN_SUBSYSTEM, "statechange: failed to create lock\n");
+ ret = -1;
+ }
+ else
+ {
+ if( slapi_apib_register(StateChange_v1_0_GUID, api) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, SCN_PLUGIN_SUBSYSTEM, "statechange: failed to publish state change interface\n");
+ ret = -1;
+ }
+ }
+
+ head = 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_start\n");
+ return ret;
+}
+
+/*
+ statechange_close
+ ---------
+ unregisters the interface for this plugin
+*/
+static int statechange_close( Slapi_PBlock *pb )
+{
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "--> statechange_close\n");
+
+ slapi_apib_unregister(StateChange_v1_0_GUID);
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_close\n");
+
+ return 0;
+}
+
+
+static int statechange_mod_post_op( Slapi_PBlock *pb )
+{
+ return statechange_post_op(pb, LDAP_CHANGETYPE_MODIFY);
+}
+
+static int statechange_modrdn_post_op( Slapi_PBlock *pb )
+{
+ return statechange_post_op(pb, LDAP_CHANGETYPE_MODDN);
+}
+
+static int statechange_add_post_op( Slapi_PBlock *pb )
+{
+ return statechange_post_op(pb, LDAP_CHANGETYPE_ADD);
+}
+
+static int statechange_delete_post_op( Slapi_PBlock *pb )
+{
+ return statechange_post_op(pb, LDAP_CHANGETYPE_DELETE);
+}
+
+
+/*
+ statechange_post_op
+ -----------
+ Catch all for all post operations that change entries
+ in some way - evaluate the change against the notification
+ entries and fire off the relevant callbacks - it is called
+ from the real postop functions which supply it with the
+ postop type
+*/
+static int statechange_post_op( Slapi_PBlock *pb, int modtype )
+{
+ SCNotify *notify = head;
+ int execute;
+ char *dn = NULL;
+ struct slapi_entry *e_before = NULL;
+ struct slapi_entry *e_after = NULL;
+
+ if(head == 0)
+ return 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "--> statechange_post_op\n");
+
+ /* evaluate this operation against the notification entries */
+
+ slapi_lock_mutex(buffer_lock);
+ if(head)
+ {
+ if(slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn ))
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, SCN_PLUGIN_SUBSYSTEM, "statechange_post_op: failed to get dn of changed entry");
+ goto bail;
+ }
+
+ slapi_dn_normalize( dn );
+
+ slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &e_before );
+ slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &e_after );
+
+ do
+ {
+ execute = 0;
+
+ /* first dn */
+ if(notify && notify->dn)
+ {
+ if(0 != slapi_dn_issuffix(dn, notify->dn))
+ execute = 1;
+ }
+ else
+ /* note, if supplied null for everything in the entry *all* ops match */
+ if(notify)
+ execute = 1;
+
+ if(execute && notify->filter)
+ {
+ /* next the filter */
+ int filter_test = 0;
+
+ /* need to test entry both before and after op */
+ if(e_before && !slapi_filter_test_simple( e_before, notify->realfilter))
+ filter_test = 1;
+
+ if(!filter_test && e_after && !slapi_filter_test_simple( e_after, notify->realfilter))
+ filter_test = 1;
+
+ if(!filter_test)
+ execute = 0;
+ }
+
+ if(execute)
+ {
+ if(e_after)
+ (notify->func)(e_after, dn, modtype, pb, notify->caller_data);
+ else
+ (notify->func)(e_before, dn, modtype, pb, notify->caller_data);
+ }
+
+ notify = notify->next;
+ }
+ while(notify != head);
+ }
+bail:
+ slapi_unlock_mutex(buffer_lock);
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_post_op\n");
+ return 0; /* always succeed */
+}
+
+
+static int _statechange_register(char *caller_id, char *dn, char *filter, void *caller_data, notify_callback func)
+{
+ int ret = -1;
+ SCNotify *item;
+
+ /* simple - we don't check for duplicates */
+
+ item = (SCNotify*)slapi_ch_malloc(sizeof(SCNotify));
+ if(item)
+ {
+ char *writable_filter = slapi_ch_strdup(filter);
+ item->caller_id = slapi_ch_strdup(caller_id);
+ if(dn)
+ {
+ item->dn = slapi_ch_strdup(dn);
+ slapi_dn_normalize( item->dn );
+ }
+ else
+ item->dn = 0;
+ item->filter = slapi_ch_strdup(filter);
+ item->caller_data = caller_data;
+ item->realfilter = slapi_str2filter(writable_filter);
+ item->func = func;
+
+ slapi_lock_mutex(buffer_lock);
+ if(head == NULL)
+ {
+ head = item;
+ head->next = head;
+ head->prev = head;
+ }
+ else
+ {
+ item->next = head;
+ item->prev = head->prev;
+ head->prev = item;
+ item->prev->next = item;
+ }
+ slapi_unlock_mutex(buffer_lock);
+ slapi_ch_free_string(&writable_filter);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void *_statechange_unregister(char *dn, char *filter, notify_callback thefunc)
+{
+ void *ret = NULL;
+ SCNotify *func = NULL;
+
+ if(buffer_lock == 0)
+ return ret;
+
+ slapi_lock_mutex(buffer_lock);
+
+ if(func = statechange_find_notify(dn, filter, thefunc))
+ {
+ func->prev->next = func->next;
+ func->next->prev = func->prev;
+
+ if(func == head)
+ {
+ head = func->next;
+ }
+
+ if(func == head) /* must be the last item, turn off the lights */
+ head = 0;
+
+ slapi_ch_free_string(&func->caller_id);
+ slapi_ch_free_string(&func->dn);
+ slapi_ch_free_string(&func->filter);
+ slapi_filter_free( func->realfilter, 1 );
+ ret = func->caller_data;
+ slapi_ch_free((void **)&func);
+ }
+
+ slapi_unlock_mutex(buffer_lock);
+
+ return ret;
+}
+
+static void _statechange_unregister_all(char *caller_id, caller_data_free_callback callback)
+{
+ SCNotify *notify = head;
+ SCNotify *start_notify = head;
+
+ if(buffer_lock == 0)
+ return;
+
+ slapi_lock_mutex(buffer_lock);
+
+
+ if(notify)
+ {
+ do
+ {
+ SCNotify *notify_next = notify->next;
+
+ if( slapi_utf8casecmp((unsigned char *)caller_id, (unsigned char *)notify->caller_id) )
+ {
+ notify->prev->next = notify->next;
+ notify->next->prev = notify->prev;
+
+ if(notify == head)
+ {
+ head = notify->next;
+ start_notify = notify->prev;
+ }
+
+ if(notify == head) /* must be the last item, turn off the lights */
+ head = 0;
+
+ if(callback)
+ callback(notify->caller_data);
+ slapi_ch_free_string(&notify->caller_id);
+ slapi_ch_free_string(&notify->dn);
+ slapi_ch_free_string(&notify->filter);
+ slapi_filter_free( notify->realfilter, 1 );
+ slapi_ch_free((void **)&notify);
+ }
+
+ notify = notify_next;
+ }
+ while(notify != start_notify && notify != NULL);
+ }
+
+ slapi_unlock_mutex(buffer_lock);
+}
+
+/* this func needs looking at to make work */
+static SCNotify *statechange_find_notify(char *dn, char *filter, notify_callback func)
+{
+ SCNotify *notify = head;
+ SCNotify *start_notify = head;
+
+ if(notify)
+ {
+ do
+ {
+ if( !slapi_utf8casecmp((unsigned char *)dn, (unsigned char *)notify->dn) &&
+ !slapi_utf8casecmp((unsigned char *)filter, (unsigned char *)notify->filter) && func == notify->func)
+ {
+ return notify;
+ }
+
+ notify = notify->next;
+ }
+ while(notify != start_notify);
+ }
+
+ return 0;
+}
+
+/* intended for use by vattr service providers
+ * to deal with significant vattr state changes
+ */
+static void _statechange_vattr_cache_invalidator_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data)
+{
+ /* simply get the significance data and act */
+ switch(*(int*)caller_data)
+ {
+ case STATECHANGE_VATTR_ENTRY_INVALIDATE:
+ if(e)
+ slapi_entry_vattrcache_watermark_invalidate(e);
+ break;
+
+ case STATECHANGE_VATTR_GLOBAL_INVALIDATE:
+ default:
+ slapi_entrycache_vattrcache_watermark_invalidate();
+ break;
+ }
+}
+
diff --git a/ldap/servers/plugins/statechange/statechange.def b/ldap/servers/plugins/statechange/statechange.def
new file mode 100644
index 00000000..ed6dca6b
--- /dev/null
+++ b/ldap/servers/plugins/statechange/statechange.def
@@ -0,0 +1,10 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 7.0 State Change Plugin'
+EXPORTS
+ statechange_init @2
+ plugin_init_debug_level @3