⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syncprov.c

📁 ldap服务器源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/syncprov.c,v 1.56.2.42 2007/02/07 01:51:36 hyc Exp $ *//* syncprov.c - syncrepl provider *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 2004-2007 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 Howard Chu for inclusion in * OpenLDAP Software. */#include "portable.h"#ifdef SLAPD_OVER_SYNCPROV#include <ac/string.h>#include "lutil.h"#include "slap.h"#include "config.h"#include "ldap_rq.h"/* A modify request on a particular entry */typedef struct modinst {	struct modinst *mi_next;	Operation *mi_op;} modinst;typedef struct modtarget {	struct modinst *mt_mods;	struct modinst *mt_tail;	Operation *mt_op;	ldap_pvt_thread_mutex_t mt_mutex;} modtarget;/* A queued result of a persistent search */typedef struct syncres {	struct syncres *s_next;	struct berval s_dn;	struct berval s_ndn;	struct berval s_uuid;	struct berval s_csn;	char s_mode;	char s_isreference;} syncres;/* Record of a persistent search */typedef struct syncops {	struct syncops *s_next;	struct berval	s_base;		/* ndn of search base */	ID		s_eid;		/* entryID of search base */	Operation	*s_op;		/* search op */	int		s_rid;	struct berval s_filterstr;	int		s_flags;	/* search status */#define	PS_IS_REFRESHING	0x01#define	PS_IS_DETACHED		0x02#define	PS_WROTE_BASE		0x04#define	PS_FIND_BASE		0x08#define	PS_FIX_FILTER		0x10	int		s_inuse;	/* reference count */	struct syncres *s_res;	struct syncres *s_restail;	struct re_s	*s_qtask;	/* task for playing psearch responses */#define	RUNQ_INTERVAL	36000	/* a long time */	ldap_pvt_thread_mutex_t	s_mutex;} syncops;/* A received sync control */typedef struct sync_control {	struct sync_cookie sr_state;	int sr_rhint;} sync_control;#if 0 /* moved back to slap.h */#define	o_sync	o_ctrlflag[slap_cids.sc_LDAPsync]#endif/* o_sync_mode uses data bits of o_sync */#define	o_sync_mode	o_ctrlflag[slap_cids.sc_LDAPsync]#define SLAP_SYNC_NONE					(LDAP_SYNC_NONE<<SLAP_CONTROL_SHIFT)#define SLAP_SYNC_REFRESH				(LDAP_SYNC_REFRESH_ONLY<<SLAP_CONTROL_SHIFT)#define SLAP_SYNC_PERSIST				(LDAP_SYNC_RESERVED<<SLAP_CONTROL_SHIFT)#define SLAP_SYNC_REFRESH_AND_PERSIST	(LDAP_SYNC_REFRESH_AND_PERSIST<<SLAP_CONTROL_SHIFT)/* Record of which searches matched at premodify step */typedef struct syncmatches {	struct syncmatches *sm_next;	syncops *sm_op;} syncmatches;/* Session log data */typedef struct slog_entry {	struct slog_entry *se_next;	struct berval se_uuid;	struct berval se_csn;	ber_tag_t	se_tag;} slog_entry;typedef struct sessionlog {	struct berval	sl_mincsn;	int		sl_num;	int		sl_size;	slog_entry *sl_head;	slog_entry *sl_tail;	ldap_pvt_thread_mutex_t sl_mutex;} sessionlog;/* The main state for this overlay */typedef struct syncprov_info_t {	syncops		*si_ops;	struct berval	si_ctxcsn;	/* ldapsync context */	int		si_chkops;	/* checkpointing info */	int		si_chktime;	int		si_numops;	/* number of ops since last checkpoint */	int		si_nopres;	/* Skip present phase */	int		si_usehint;	/* use reload hint */	time_t	si_chklast;	/* time of last checkpoint */	Avlnode	*si_mods;	/* entries being modified */	sessionlog	*si_logs;	ldap_pvt_thread_rdwr_t	si_csn_rwlock;	ldap_pvt_thread_mutex_t	si_ops_mutex;	ldap_pvt_thread_mutex_t	si_mods_mutex;	char		si_ctxcsnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];} syncprov_info_t;typedef struct opcookie {	slap_overinst *son;	syncmatches *smatches;	struct berval sdn;	/* DN of entry, for deletes */	struct berval sndn;	struct berval suuid;	/* UUID of entry */	struct berval sctxcsn;	int sreference;	/* Is the entry a reference? */} opcookie;typedef struct fbase_cookie {	struct berval *fdn;	/* DN of a modified entry, for scope testing */	syncops *fss;	/* persistent search we're testing against */	int fbase;	/* if TRUE we found the search base and it's still valid */	int fscope;	/* if TRUE then fdn is within the psearch scope */} fbase_cookie;static AttributeName csn_anlist[3];static AttributeName uuid_anlist[2];/* Build a LDAPsync intermediate state control */static intsyncprov_state_ctrl(	Operation	*op,	SlapReply	*rs,	Entry		*e,	int		entry_sync_state,	LDAPControl	**ctrls,	int		num_ctrls,	int		send_cookie,	struct berval	*cookie ){	Attribute* a;	int ret;	BerElementBuffer berbuf;	BerElement *ber = (BerElement *)&berbuf;	struct berval	entryuuid_bv = BER_BVNULL;	ber_init2( ber, 0, LBER_USE_DER );	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );	ctrls[num_ctrls] = op->o_tmpalloc( sizeof ( LDAPControl ), op->o_tmpmemctx );	for ( a = e->e_attrs; a != NULL; a = a->a_next ) {		AttributeDescription *desc = a->a_desc;		if ( desc == slap_schema.si_ad_entryUUID ) {			entryuuid_bv = a->a_nvals[0];			break;		}	}	/* FIXME: what if entryuuid is NULL or empty ? */	if ( send_cookie && cookie ) {		ber_printf( ber, "{eOON}",			entry_sync_state, &entryuuid_bv, cookie );	} else {		ber_printf( ber, "{eON}",			entry_sync_state, &entryuuid_bv );	}	ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE;	ctrls[num_ctrls]->ldctl_iscritical = (op->o_sync == SLAP_CONTROL_CRITICAL);	ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );	ber_free_buf( ber );	if ( ret < 0 ) {		Debug( LDAP_DEBUG_TRACE,			"slap_build_sync_ctrl: ber_flatten2 failed\n",			0, 0, 0 );		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );		return ret;	}	return LDAP_SUCCESS;}/* Build a LDAPsync final state control */static intsyncprov_done_ctrl(	Operation	*op,	SlapReply	*rs,	LDAPControl	**ctrls,	int			num_ctrls,	int			send_cookie,	struct berval *cookie,	int			refreshDeletes ){	int ret;	BerElementBuffer berbuf;	BerElement *ber = (BerElement *)&berbuf;	ber_init2( ber, NULL, LBER_USE_DER );	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );	ctrls[num_ctrls] = op->o_tmpalloc( sizeof ( LDAPControl ), op->o_tmpmemctx );	ber_printf( ber, "{" );	if ( send_cookie && cookie ) {		ber_printf( ber, "O", cookie );	}	if ( refreshDeletes == LDAP_SYNC_REFRESH_DELETES ) {		ber_printf( ber, "b", refreshDeletes );	}	ber_printf( ber, "N}" );	ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_DONE;	ctrls[num_ctrls]->ldctl_iscritical = (op->o_sync == SLAP_CONTROL_CRITICAL);	ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );	ber_free_buf( ber );	if ( ret < 0 ) {		Debug( LDAP_DEBUG_TRACE,			"syncprov_done_ctrl: ber_flatten2 failed\n",			0, 0, 0 );		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );		return ret;	}	return LDAP_SUCCESS;}static intsyncprov_sendinfo(	Operation	*op,	SlapReply	*rs,	int			type,	struct berval *cookie,	int			refreshDone,	BerVarray	syncUUIDs,	int			refreshDeletes ){	BerElementBuffer berbuf;	BerElement *ber = (BerElement *)&berbuf;	struct berval rspdata;	int ret;	ber_init2( ber, NULL, LBER_USE_DER );	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );	if ( type ) {		switch ( type ) {		case LDAP_TAG_SYNC_NEW_COOKIE:			ber_printf( ber, "tO", type, cookie );			break;		case LDAP_TAG_SYNC_REFRESH_DELETE:		case LDAP_TAG_SYNC_REFRESH_PRESENT:			ber_printf( ber, "t{", type );			if ( cookie ) {				ber_printf( ber, "O", cookie );			}			if ( refreshDone == 0 ) {				ber_printf( ber, "b", refreshDone );			}			ber_printf( ber, "N}" );			break;		case LDAP_TAG_SYNC_ID_SET:			ber_printf( ber, "t{", type );			if ( cookie ) {				ber_printf( ber, "O", cookie );			}			if ( refreshDeletes == 1 ) {				ber_printf( ber, "b", refreshDeletes );			}			ber_printf( ber, "[W]", syncUUIDs );			ber_printf( ber, "N}" );			break;		default:			Debug( LDAP_DEBUG_TRACE,				"syncprov_sendinfo: invalid syncinfo type (%d)\n",				type, 0, 0 );			return LDAP_OTHER;		}	}	ret = ber_flatten2( ber, &rspdata, 0 );	if ( ret < 0 ) {		Debug( LDAP_DEBUG_TRACE,			"syncprov_sendinfo: ber_flatten2 failed\n",			0, 0, 0 );		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );		return ret;	}	rs->sr_rspoid = LDAP_SYNC_INFO;	rs->sr_rspdata = &rspdata;	send_ldap_intermediate( op, rs );	rs->sr_rspdata = NULL;	ber_free_buf( ber );	return LDAP_SUCCESS;}/* Find a modtarget in an AVL tree */static intsp_avl_cmp( const void *c1, const void *c2 ){	const modtarget *m1, *m2;	int rc;	m1 = c1; m2 = c2;	rc = m1->mt_op->o_req_ndn.bv_len - m2->mt_op->o_req_ndn.bv_len;	if ( rc ) return rc;	return ber_bvcmp( &m1->mt_op->o_req_ndn, &m2->mt_op->o_req_ndn );}/* syncprov_findbase: *   finds the true DN of the base of a search (with alias dereferencing) and * checks to make sure the base entry doesn't get replaced with a different * entry (e.g., swapping trees via ModDN, or retargeting an alias). If a * change is detected, any persistent search on this base must be terminated / * reloaded. *   On the first call, we just save the DN and entryID. On subsequent calls * we compare the DN and entryID with the saved values. */static intfindbase_cb( Operation *op, SlapReply *rs ){	slap_callback *sc = op->o_callback;	if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) {		fbase_cookie *fc = sc->sc_private;		/* If no entryID, we're looking for the first time.		 * Just store whatever we got.		 */		if ( fc->fss->s_eid == NOID ) {			fc->fbase = 2;			fc->fss->s_eid = rs->sr_entry->e_id;			ber_dupbv( &fc->fss->s_base, &rs->sr_entry->e_nname );		} else if ( rs->sr_entry->e_id == fc->fss->s_eid &&			dn_match( &rs->sr_entry->e_nname, &fc->fss->s_base )) {		/* OK, the DN is the same and the entryID is the same. */			fc->fbase = 1;		}	}	if ( rs->sr_err != LDAP_SUCCESS ) {		Debug( LDAP_DEBUG_ANY, "findbase failed! %d\n", rs->sr_err,0,0 );	}	return LDAP_SUCCESS;}static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL };static struct berval generic_filterstr = BER_BVC("(objectclass=*)");static intsyncprov_findbase( Operation *op, fbase_cookie *fc ){	opcookie *opc = op->o_callback->sc_private;	slap_overinst *on = opc->son;	/* Use basic parameters from syncrepl search, but use	 * current op's threadctx / tmpmemctx	 */	ldap_pvt_thread_mutex_lock( &fc->fss->s_mutex );	if ( fc->fss->s_flags & PS_FIND_BASE ) {		slap_callback cb = {0};		Operation fop;		SlapReply frs = { REP_RESULT };		int rc;		fc->fss->s_flags ^= PS_FIND_BASE;		ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex );		fop = *fc->fss->s_op;		fop.o_hdr = op->o_hdr;		fop.o_bd = op->o_bd;		fop.o_time = op->o_time;		fop.o_tincr = op->o_tincr;		cb.sc_response = findbase_cb;		cb.sc_private = fc;		fop.o_sync_mode = 0;	/* turn off sync mode */		fop.o_managedsait = SLAP_CONTROL_CRITICAL;		fop.o_callback = &cb;		fop.o_tag = LDAP_REQ_SEARCH;		fop.ors_scope = LDAP_SCOPE_BASE;		fop.ors_limit = NULL;		fop.ors_slimit = 1;		fop.ors_tlimit = SLAP_NO_LIMIT;		fop.ors_attrs = slap_anlist_no_attrs;		fop.ors_attrsonly = 1;		fop.ors_filter = &generic_filter;		fop.ors_filterstr = generic_filterstr;		fop.o_bd->bd_info = on->on_info->oi_orig;		rc = fop.o_bd->be_search( &fop, &frs );		fop.o_bd->bd_info = (BackendInfo *)on;	} else {		ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex );		fc->fbase = 1;	}	/* After the first call, see if the fdn resides in the scope */	if ( fc->fbase == 1 ) {		switch ( fc->fss->s_op->ors_scope ) {		case LDAP_SCOPE_BASE:			fc->fscope = dn_match( fc->fdn, &fc->fss->s_base );			break;		case LDAP_SCOPE_ONELEVEL: {			struct berval pdn;			dnParent( fc->fdn, &pdn );			fc->fscope = dn_match( &pdn, &fc->fss->s_base );			break; }		case LDAP_SCOPE_SUBTREE:			fc->fscope = dnIsSuffix( fc->fdn, &fc->fss->s_base );			break;		case LDAP_SCOPE_SUBORDINATE:			fc->fscope = dnIsSuffix( fc->fdn, &fc->fss->s_base ) &&				!dn_match( fc->fdn, &fc->fss->s_base );			break;		}	}	if ( fc->fbase )		return LDAP_SUCCESS;	/* If entryID has changed, then the base of this search has	 * changed. Invalidate the psearch.	 */	return LDAP_NO_SUCH_OBJECT;}/* syncprov_findcsn: *   This function has three different purposes, but they all use a search * that filters on entryCSN so they're combined here. * 1: at startup time, after a contextCSN has been read from the database, * we search for all entries with CSN >= contextCSN in case the contextCSN * was not checkpointed at the previous shutdown. * * 2: when the current contextCSN is known and we have a sync cookie, we search * for one entry with CSN = the cookie CSN. If not found, try <= cookie CSN. * If an entry is found, the cookie CSN is valid, otherwise it is stale. * * 3: during a refresh phase, we search for all entries with CSN <= the cookie * CSN, and generate Present records for them. We always collect this result * in SyncID sets, even if there's only one match. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -