syncprov.c 94.4 KB
Newer Older
Howard Chu's avatar
Howard Chu committed
1
/* $OpenLDAP$ */
Howard Chu's avatar
Howard Chu committed
2
3
4
/* syncprov.c - syncrepl provider */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 2004-2017 The OpenLDAP Foundation.
Howard Chu's avatar
Howard Chu committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 * 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

Howard Chu's avatar
Howard Chu committed
25
26
#include <ac/string.h>
#include "lutil.h"
Howard Chu's avatar
Howard Chu committed
27
#include "slap.h"
Howard Chu's avatar
Howard Chu committed
28
#include "config.h"
29
#include "ldap_rq.h"
Howard Chu's avatar
Howard Chu committed
30

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
31
32
33
34
#ifdef LDAP_DEVEL
#define	CHECK_CSN	1
#endif

35
36
37
38
39
40
41
42
43
/* 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;
44
	struct berval mt_dn;
45
46
47
	ldap_pvt_thread_mutex_t mt_mutex;
} modtarget;

Howard Chu's avatar
Howard Chu committed
48
49
50
51
52
53
54
55
56
57
/* All the info of a psearch result that's shared between
 * multiple queues
 */
typedef struct resinfo {
	struct syncres *ri_list;
	Entry *ri_e;
	struct berval ri_dn;
	struct berval ri_ndn;
	struct berval ri_uuid;
	struct berval ri_csn;
Howard Chu's avatar
Howard Chu committed
58
	struct berval ri_cookie;
Howard Chu's avatar
Howard Chu committed
59
60
61
62
	char ri_isref;
	ldap_pvt_thread_mutex_t ri_mutex;
} resinfo;

Howard Chu's avatar
Howard Chu committed
63
64
/* A queued result of a persistent search */
typedef struct syncres {
Howard Chu's avatar
Howard Chu committed
65
66
67
	struct syncres *s_next;	/* list of results on this psearch queue */
	struct syncres *s_rilist;	/* list of psearches using this result */
	resinfo *s_info;
68
	char s_mode;
Howard Chu's avatar
Howard Chu committed
69
70
} syncres;

Howard Chu's avatar
Howard Chu committed
71
72
73
/* Record of a persistent search */
typedef struct syncops {
	struct syncops *s_next;
74
	struct syncprov_info_t *s_si;
Howard Chu's avatar
Howard Chu committed
75
76
77
	struct berval	s_base;		/* ndn of search base */
	ID		s_eid;		/* entryID of search base */
	Operation	*s_op;		/* search op */
78
	int		s_rid;
79
	int		s_sid;
Howard Chu's avatar
Howard Chu committed
80
	struct berval s_filterstr;
Howard Chu's avatar
Howard Chu committed
81
	int		s_flags;	/* search status */
Howard Chu's avatar
Howard Chu committed
82
83
84
85
#define	PS_IS_REFRESHING	0x01
#define	PS_IS_DETACHED		0x02
#define	PS_WROTE_BASE		0x04
#define	PS_FIND_BASE		0x08
86
#define	PS_FIX_FILTER		0x10
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
87
#define	PS_TASK_QUEUED		0x20
Howard Chu's avatar
Howard Chu committed
88

Howard Chu's avatar
Howard Chu committed
89
	int		s_inuse;	/* reference count */
Howard Chu's avatar
Howard Chu committed
90
91
92
	struct syncres *s_res;
	struct syncres *s_restail;
	ldap_pvt_thread_mutex_t	s_mutex;
Howard Chu's avatar
Howard Chu committed
93
94
} syncops;

95
96
97
98
99
100
/* A received sync control */
typedef struct sync_control {
	struct sync_cookie sr_state;
	int sr_rhint;
} sync_control;

101
102
103
#if 0 /* moved back to slap.h */
#define	o_sync	o_ctrlflag[slap_cids.sc_LDAPsync]
#endif
104
/* o_sync_mode uses data bits of o_sync */
105
#define	o_sync_mode	o_ctrlflag[slap_cids.sc_LDAPsync]
106
107
108
109
110
111

#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)

Howard Chu's avatar
Howard Chu committed
112
113
114
115
116
117
/* Record of which searches matched at premodify step */
typedef struct syncmatches {
	struct syncmatches *sm_next;
	syncops *sm_op;
} syncmatches;

118
119
120
121
122
/* Session log data */
typedef struct slog_entry {
	struct slog_entry *se_next;
	struct berval se_uuid;
	struct berval se_csn;
123
	int	se_sid;
124
125
126
127
	ber_tag_t	se_tag;
} slog_entry;

typedef struct sessionlog {
128
129
130
	BerVarray	sl_mincsn;
	int		*sl_sids;
	int		sl_numcsns;
131
132
	int		sl_num;
	int		sl_size;
133
	int		sl_playing;
134
135
136
137
138
	slog_entry *sl_head;
	slog_entry *sl_tail;
	ldap_pvt_thread_mutex_t sl_mutex;
} sessionlog;

Howard Chu's avatar
Cleanup    
Howard Chu committed
139
/* The main state for this overlay */
Howard Chu's avatar
Howard Chu committed
140
141
typedef struct syncprov_info_t {
	syncops		*si_ops;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
142
	struct berval	si_contextdn;
143
	BerVarray	si_ctxcsn;	/* ldapsync context */
144
145
	int		*si_sids;
	int		si_numcsns;
146
147
148
	int		si_chkops;	/* checkpointing info */
	int		si_chktime;
	int		si_numops;	/* number of ops since last checkpoint */
149
	int		si_nopres;	/* Skip present phase */
150
	int		si_usehint;	/* use reload hint */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
151
	int		si_active;	/* True if there are active mods */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
152
153
	int		si_dirty;	/* True if the context is dirty, i.e changes
						 * have been made without updating the csn. */
154
	time_t	si_chklast;	/* time of last checkpoint */
155
	Avlnode	*si_mods;	/* entries being modified */
156
	sessionlog	*si_logs;
Howard Chu's avatar
Howard Chu committed
157
	ldap_pvt_thread_rdwr_t	si_csn_rwlock;
Howard Chu's avatar
Howard Chu committed
158
	ldap_pvt_thread_mutex_t	si_ops_mutex;
Howard Chu's avatar
Howard Chu committed
159
	ldap_pvt_thread_mutex_t	si_mods_mutex;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
160
	ldap_pvt_thread_mutex_t	si_resp_mutex;
Howard Chu's avatar
Howard Chu committed
161
162
163
164
165
} syncprov_info_t;

typedef struct opcookie {
	slap_overinst *son;
	syncmatches *smatches;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
166
	modtarget *smt;
167
	Entry *se;
168
169
170
171
	struct berval sdn;	/* DN of entry, for deletes */
	struct berval sndn;
	struct berval suuid;	/* UUID of entry */
	struct berval sctxcsn;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
172
173
174
	short osid;	/* sid of op csn */
	short rsid;	/* sid of relay */
	short sreference;	/* Is the entry a reference? */
Howard Chu's avatar
Howard Chu committed
175
	syncres ssres;
Howard Chu's avatar
Howard Chu committed
176
177
} opcookie;

178
typedef struct fbase_cookie {
179
180
181
182
	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 */
183
} fbase_cookie;
Howard Chu's avatar
Howard Chu committed
184

185
static AttributeName csn_anlist[3];
Howard Chu's avatar
Howard Chu committed
186
187
static AttributeName uuid_anlist[2];

Howard Chu's avatar
Cleanup    
Howard Chu committed
188
/* Build a LDAPsync intermediate state control */
189
190
191
192
193
static int
syncprov_state_ctrl(
	Operation	*op,
	SlapReply	*rs,
	Entry		*e,
194
	int		entry_sync_state,
195
	LDAPControl	**ctrls,
196
197
198
	int		num_ctrls,
	int		send_cookie,
	struct berval	*cookie )
199
200
201
202
203
204
{
	Attribute* a;
	int ret;

	BerElementBuffer berbuf;
	BerElement *ber = (BerElement *)&berbuf;
205
206
	LDAPControl *cp;
	struct berval bv;
207
	struct berval	entryuuid_bv = BER_BVNULL;
208
209
210
211

	ber_init2( ber, 0, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

212
213
214
215
216
	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;
217
		}
218
	}
219

220
221
	/* FIXME: what if entryuuid is NULL or empty ? */

222
223
224
225
226
227
	if ( send_cookie && cookie ) {
		ber_printf( ber, "{eOON}",
			entry_sync_state, &entryuuid_bv, cookie );
	} else {
		ber_printf( ber, "{eON}",
			entry_sync_state, &entryuuid_bv );
228
229
	}

230
231
232
233
234
235
236
237
238
239
	ret = ber_flatten2( ber, &bv, 0 );
	if ( ret == 0 ) {
		cp = op->o_tmpalloc( sizeof( LDAPControl ) + bv.bv_len, op->o_tmpmemctx );
		cp->ldctl_oid = LDAP_CONTROL_SYNC_STATE;
		cp->ldctl_iscritical = (op->o_sync == SLAP_CONTROL_CRITICAL);
		cp->ldctl_value.bv_val = (char *)&cp[1];
		cp->ldctl_value.bv_len = bv.bv_len;
		AC_MEMCPY( cp->ldctl_value.bv_val, bv.bv_val, bv.bv_len );
		ctrls[num_ctrls] = cp;
	}
240
241
242
243
	ber_free_buf( ber );

	if ( ret < 0 ) {
		Debug( LDAP_DEBUG_TRACE,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
244
245
			"slap_build_sync_ctrl: ber_flatten2 failed (%d)\n",
			ret, 0, 0 );
246
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
247
		return LDAP_OTHER;
248
249
250
251
252
	}

	return LDAP_SUCCESS;
}

Howard Chu's avatar
Cleanup    
Howard Chu committed
253
/* Build a LDAPsync final state control */
254
255
256
257
258
259
260
261
262
263
264
265
266
static int
syncprov_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;
267
268
	LDAPControl *cp;
	struct berval bv;
269
270
271
272
273
274
275
276
277
278
279

	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &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 );
	}
280
	ber_printf( ber, "N}" );
281

282
283
284
285
286
287
288
289
290
291
	ret = ber_flatten2( ber, &bv, 0 );
	if ( ret == 0 ) {
		cp = op->o_tmpalloc( sizeof( LDAPControl ) + bv.bv_len, op->o_tmpmemctx );
		cp->ldctl_oid = LDAP_CONTROL_SYNC_DONE;
		cp->ldctl_iscritical = (op->o_sync == SLAP_CONTROL_CRITICAL);
		cp->ldctl_value.bv_val = (char *)&cp[1];
		cp->ldctl_value.bv_len = bv.bv_len;
		AC_MEMCPY( cp->ldctl_value.bv_val, bv.bv_val, bv.bv_len );
		ctrls[num_ctrls] = cp;
	}
292
293
294
295
296

	ber_free_buf( ber );

	if ( ret < 0 ) {
		Debug( LDAP_DEBUG_TRACE,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
297
298
			"syncprov_done_ctrl: ber_flatten2 failed (%d)\n",
			ret, 0, 0 );
299
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
300
		return LDAP_OTHER;
301
302
303
304
305
	}

	return LDAP_SUCCESS;
}

Howard Chu's avatar
Howard Chu committed
306
static int
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
syncprov_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,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
364
365
			"syncprov_sendinfo: ber_flatten2 failed (%d)\n",
			ret, 0, 0 );
366
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
367
		return LDAP_OTHER;
368
369
	}

Howard Chu's avatar
Cleanup    
Howard Chu committed
370
	rs->sr_rspoid = LDAP_SYNC_INFO;
371
372
373
374
375
376
377
	rs->sr_rspdata = &rspdata;
	send_ldap_intermediate( op, rs );
	rs->sr_rspdata = NULL;
	ber_free_buf( ber );

	return LDAP_SUCCESS;
}
378

Howard Chu's avatar
Cleanup    
Howard Chu committed
379
/* Find a modtarget in an AVL tree */
380
381
382
383
384
385
386
static int
sp_avl_cmp( const void *c1, const void *c2 )
{
	const modtarget *m1, *m2;
	int rc;

	m1 = c1; m2 = c2;
387
	rc = m1->mt_dn.bv_len - m2->mt_dn.bv_len;
388
389

	if ( rc ) return rc;
390
	return ber_bvcmp( &m1->mt_dn, &m2->mt_dn );
391
392
}

393
394
395
396
397
398
399
400
401
/* 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.
 */
Howard Chu's avatar
Howard Chu committed
402
403
404
405
406
407
static int
findbase_cb( Operation *op, SlapReply *rs )
{
	slap_callback *sc = op->o_callback;

	if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) {
408
409
410
411
412
413
		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 ) {
Howard Chu's avatar
Howard Chu committed
414
			fc->fbase = 2;
415
416
			fc->fss->s_eid = rs->sr_entry->e_id;
			ber_dupbv( &fc->fss->s_base, &rs->sr_entry->e_nname );
417

418
		} else if ( rs->sr_entry->e_id == fc->fss->s_eid &&
Howard Chu's avatar
Howard Chu committed
419
			dn_match( &rs->sr_entry->e_nname, &fc->fss->s_base )) {
420

Howard Chu's avatar
Howard Chu committed
421
		/* OK, the DN is the same and the entryID is the same. */
Howard Chu's avatar
Howard Chu committed
422
423
			fc->fbase = 1;
		}
Howard Chu's avatar
Howard Chu committed
424
	}
425
426
427
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_ANY, "findbase failed! %d\n", rs->sr_err,0,0 );
	}
Howard Chu's avatar
Howard Chu committed
428
429
430
	return LDAP_SUCCESS;
}

Howard Chu's avatar
Howard Chu committed
431
432
433
static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL };
static struct berval generic_filterstr = BER_BVC("(objectclass=*)");

Howard Chu's avatar
Howard Chu committed
434
static int
435
syncprov_findbase( Operation *op, fbase_cookie *fc )
Howard Chu's avatar
Howard Chu committed
436
{
Howard Chu's avatar
Howard Chu committed
437
438
439
	/* Use basic parameters from syncrepl search, but use
	 * current op's threadctx / tmpmemctx
	 */
Howard Chu's avatar
Howard Chu committed
440
441
442
443
444
445
	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;
Howard Chu's avatar
Howard Chu committed
446

Howard Chu's avatar
Howard Chu committed
447
448
		fc->fss->s_flags ^= PS_FIND_BASE;
		ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex );
Howard Chu's avatar
Howard Chu committed
449

Howard Chu's avatar
Howard Chu committed
450
		fop = *fc->fss->s_op;
Howard Chu's avatar
Howard Chu committed
451

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
452
		fop.o_bd = fop.o_bd->bd_self;
Howard Chu's avatar
Howard Chu committed
453
454
455
		fop.o_hdr = op->o_hdr;
		fop.o_time = op->o_time;
		fop.o_tincr = op->o_tincr;
456
		fop.o_extra = op->o_extra;
Howard Chu's avatar
Howard Chu committed
457

Howard Chu's avatar
Howard Chu committed
458
459
		cb.sc_response = findbase_cb;
		cb.sc_private = fc;
Howard Chu's avatar
Howard Chu committed
460

Howard Chu's avatar
Howard Chu committed
461
462
463
464
465
466
467
468
469
470
		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;
Howard Chu's avatar
Howard Chu committed
471
472
		fop.ors_filter = &generic_filter;
		fop.ors_filterstr = generic_filterstr;
Howard Chu's avatar
Howard Chu committed
473

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
474
		rc = fop.o_bd->be_search( &fop, &frs );
Howard Chu's avatar
Howard Chu committed
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
	} 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;
Howard Chu's avatar
Howard Chu committed
503
504
505
506
507
508

	/* If entryID has changed, then the base of this search has
	 * changed. Invalidate the psearch.
	 */
	return LDAP_NO_SUCH_OBJECT;
}
Howard Chu's avatar
Howard Chu committed
509

510
/* syncprov_findcsn:
511
 *   This function has three different purposes, but they all use a search
512
 * that filters on entryCSN so they're combined here.
513
514
515
516
517
 * 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
Howard Chu's avatar
Howard Chu committed
518
519
 * 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.
520
 *
521
 * 3: during a refresh phase, we search for all entries with CSN <= the cookie
522
523
524
 * CSN, and generate Present records for them. We always collect this result
 * in SyncID sets, even if there's only one match.
 */
525
526
527
528
529
typedef enum find_csn_t {
	FIND_MAXCSN	= 1,
	FIND_CSN	= 2,
	FIND_PRESENT	= 3
} find_csn_t;
530
531
532
533
534
535
536
537
538

static int
findmax_cb( Operation *op, SlapReply *rs )
{
	if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) {
		struct berval *maxcsn = op->o_callback->sc_private;
		Attribute *a = attr_find( rs->sr_entry->e_attrs,
			slap_schema.si_ad_entryCSN );

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
539
540
		if ( a && ber_bvcmp( &a->a_vals[0], maxcsn ) > 0 &&
			slap_parse_csn_sid( &a->a_vals[0] ) == slap_serverID ) {
541
542
543
544
545
546
			maxcsn->bv_len = a->a_vals[0].bv_len;
			strcpy( maxcsn->bv_val, a->a_vals[0].bv_val );
		}
	}
	return LDAP_SUCCESS;
}
Howard Chu's avatar
Howard Chu committed
547
548
549
550
551
552

static int
findcsn_cb( Operation *op, SlapReply *rs )
{
	slap_callback *sc = op->o_callback;

Howard Chu's avatar
Howard Chu committed
553
554
555
556
557
	/* We just want to know that at least one exists, so it's OK if
	 * we exceed the unchecked limit.
	 */
	if ( rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED ||
		(rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS )) {
558
		sc->sc_private = (void *)1;
Howard Chu's avatar
Howard Chu committed
559
560
561
562
	}
	return LDAP_SUCCESS;
}

563
564
/* Build a list of entryUUIDs for sending in a SyncID set */

565
566
#define UUID_LEN	16

Howard Chu's avatar
Howard Chu committed
567
568
569
typedef struct fpres_cookie {
	int num;
	BerVarray uuids;
570
	char *last;
Howard Chu's avatar
Howard Chu committed
571
572
573
574
575
576
577
} fpres_cookie;

static int
findpres_cb( Operation *op, SlapReply *rs )
{
	slap_callback *sc = op->o_callback;
	fpres_cookie *pc = sc->sc_private;
578
	Attribute *a;
Howard Chu's avatar
Howard Chu committed
579
	int ret = SLAP_CB_CONTINUE;
Howard Chu's avatar
Howard Chu committed
580

581
582
583
	switch ( rs->sr_type ) {
	case REP_SEARCH:
		a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
584
585
586
587
		if ( a ) {
			pc->uuids[pc->num].bv_val = pc->last;
			AC_MEMCPY( pc->uuids[pc->num].bv_val, a->a_nvals[0].bv_val,
				pc->uuids[pc->num].bv_len );
Howard Chu's avatar
Howard Chu committed
588
			pc->num++;
589
590
			pc->last = pc->uuids[pc->num].bv_val;
			pc->uuids[pc->num].bv_val = NULL;
Howard Chu's avatar
Howard Chu committed
591
		}
592
		ret = LDAP_SUCCESS;
593
594
595
596
		if ( pc->num != SLAP_SYNCUUID_SET_SIZE )
			break;
		/* FALLTHRU */
	case REP_RESULT:
Howard Chu's avatar
Howard Chu committed
597
598
		ret = rs->sr_err;
		if ( pc->num ) {
599
			ret = syncprov_sendinfo( op, rs, LDAP_TAG_SYNC_ID_SET, NULL,
Howard Chu's avatar
Howard Chu committed
600
				0, pc->uuids, 0 );
601
			pc->uuids[pc->num].bv_val = pc->last;
Howard Chu's avatar
Howard Chu committed
602
			pc->num = 0;
603
			pc->last = pc->uuids[0].bv_val;
Howard Chu's avatar
Howard Chu committed
604
		}
605
606
607
		break;
	default:
		break;
Howard Chu's avatar
Howard Chu committed
608
609
610
611
612
	}
	return ret;
}

static int
cmikk@qwest.net's avatar
cmikk@qwest.net committed
613
syncprov_findcsn( Operation *op, find_csn_t mode, struct berval *csn )
Howard Chu's avatar
Howard Chu committed
614
615
616
617
618
619
620
{
	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
	syncprov_info_t		*si = on->on_bi.bi_private;

	slap_callback cb = {0};
	Operation fop;
	SlapReply frs = { REP_RESULT };
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
621
622
	char buf[LDAP_PVT_CSNSTR_BUFSIZE + STRLENOF("(entryCSN<=)")];
	char cbuf[LDAP_PVT_CSNSTR_BUFSIZE];
623
	struct berval maxcsn;
624
	Filter cf;
Ralf Haferkamp's avatar
Ralf Haferkamp committed
625
	AttributeAssertion eq = ATTRIBUTEASSERTION_INIT;
Howard Chu's avatar
Howard Chu committed
626
	fpres_cookie pcookie;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
627
	sync_control *srs = NULL;
628
629
	struct slap_limits_set fc_limits;
	int i, rc = LDAP_SUCCESS, findcsn_retry = 1;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
630
	int maxid;
631
632
633

	if ( mode != FIND_MAXCSN ) {
		srs = op->o_controls[slap_cids.sc_LDAPsync];
Howard Chu's avatar
Howard Chu committed
634
635
636
	}

	fop = *op;
637
	fop.o_sync_mode &= SLAP_CONTROL_MASK;	/* turn off sync_mode */
638
639
	/* We want pure entries, not referrals */
	fop.o_managedsait = SLAP_CONTROL_CRITICAL;
Howard Chu's avatar
Howard Chu committed
640

641
642
	cf.f_ava = &eq;
	cf.f_av_desc = slap_schema.si_ad_entryCSN;
643
	BER_BVZERO( &cf.f_av_value );
644
645
	cf.f_next = NULL;

646
647
648
649
	fop.o_callback = &cb;
	fop.ors_limit = NULL;
	fop.ors_tlimit = SLAP_NO_LIMIT;
	fop.ors_filter = &cf;
650
	fop.ors_filterstr.bv_val = buf;
651

Howard Chu's avatar
Howard Chu committed
652
again:
653
654
655
	switch( mode ) {
	case FIND_MAXCSN:
		cf.f_choice = LDAP_FILTER_GE;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
656
657
658
		/* If there are multiple CSNs, use the one with our serverID */
		for ( i=0; i<si->si_numcsns; i++) {
			if ( slap_serverID == si->si_sids[i] ) {
659
				maxid = i;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
660
				break;
661
662
			}
		}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
663
664
665
666
667
668
669
		if ( i == si->si_numcsns ) {
			/* No match: this is multimaster, and none of the content in the DB
			 * originated locally. Treat like no CSN.
			 */
			return LDAP_NO_SUCH_OBJECT;
		}
		cf.f_av_value = si->si_ctxcsn[maxid];
670
671
		fop.ors_filterstr.bv_len = snprintf( buf, sizeof( buf ),
			"(entryCSN>=%s)", cf.f_av_value.bv_val );
672
		if ( fop.ors_filterstr.bv_len >= sizeof( buf ) ) {
673
674
			return LDAP_OTHER;
		}
675
676
677
678
679
		fop.ors_attrsonly = 0;
		fop.ors_attrs = csn_anlist;
		fop.ors_slimit = SLAP_NO_LIMIT;
		cb.sc_private = &maxcsn;
		cb.sc_response = findmax_cb;
680
		strcpy( cbuf, cf.f_av_value.bv_val );
681
		maxcsn.bv_val = cbuf;
682
		maxcsn.bv_len = cf.f_av_value.bv_len;
683
684
		break;
	case FIND_CSN:
685
		if ( BER_BVISEMPTY( &cf.f_av_value )) {
cmikk@qwest.net's avatar
cmikk@qwest.net committed
686
			cf.f_av_value = *csn;
687
		}
cmikk@qwest.net's avatar
cmikk@qwest.net committed
688
689
690
691
		fop.o_dn = op->o_bd->be_rootdn;
		fop.o_ndn = op->o_bd->be_rootndn;
		fop.o_req_dn = op->o_bd->be_suffix[0];
		fop.o_req_ndn = op->o_bd->be_nsuffix[0];
Howard Chu's avatar
Howard Chu committed
692
693
694
		/* Look for exact match the first time */
		if ( findcsn_retry ) {
			cf.f_choice = LDAP_FILTER_EQUALITY;
695
696
			fop.ors_filterstr.bv_len = snprintf( buf, sizeof( buf ),
				"(entryCSN=%s)", cf.f_av_value.bv_val );
Howard Chu's avatar
Howard Chu committed
697
698
699
		/* On retry, look for <= */
		} else {
			cf.f_choice = LDAP_FILTER_LE;
700
			fop.ors_limit = &fc_limits;
701
			memset( &fc_limits, 0, sizeof( fc_limits ));
702
			fc_limits.lms_s_unchecked = 1;
703
704
705
			fop.ors_filterstr.bv_len = snprintf( buf, sizeof( buf ),
				"(entryCSN<=%s)", cf.f_av_value.bv_val );
		}
706
		if ( fop.ors_filterstr.bv_len >= sizeof( buf ) ) {
707
			return LDAP_OTHER;
Howard Chu's avatar
Howard Chu committed
708
		}
709
710
711
712
		fop.ors_attrsonly = 1;
		fop.ors_attrs = slap_anlist_no_attrs;
		fop.ors_slimit = 1;
		cb.sc_private = NULL;
Howard Chu's avatar
Howard Chu committed
713
		cb.sc_response = findcsn_cb;
714
715
		break;
	case FIND_PRESENT:
716
717
		fop.ors_filter = op->ors_filter;
		fop.ors_filterstr = op->ors_filterstr;
Howard Chu's avatar
Howard Chu committed
718
719
720
		fop.ors_attrsonly = 0;
		fop.ors_attrs = uuid_anlist;
		fop.ors_slimit = SLAP_NO_LIMIT;
Howard Chu's avatar
Howard Chu committed
721
		cb.sc_private = &pcookie;
Howard Chu's avatar
Howard Chu committed
722
723
		cb.sc_response = findpres_cb;
		pcookie.num = 0;
724
725
726
727
728
729
730
731
732
733
734
735

		/* preallocate storage for a full set */
		pcookie.uuids = op->o_tmpalloc( (SLAP_SYNCUUID_SET_SIZE+1) *
			sizeof(struct berval) + SLAP_SYNCUUID_SET_SIZE * UUID_LEN,
			op->o_tmpmemctx );
		pcookie.last = (char *)(pcookie.uuids + SLAP_SYNCUUID_SET_SIZE+1);
		pcookie.uuids[0].bv_val = pcookie.last;
		pcookie.uuids[0].bv_len = UUID_LEN;
		for (i=1; i<SLAP_SYNCUUID_SET_SIZE; i++) {
			pcookie.uuids[i].bv_val = pcookie.uuids[i-1].bv_val + UUID_LEN;
			pcookie.uuids[i].bv_len = UUID_LEN;
		}
736
		break;
Howard Chu's avatar
Howard Chu committed
737
738
	}

739
	fop.o_bd->bd_info = (BackendInfo *)on->on_info;
740
	fop.o_bd->be_search( &fop, &frs );
741
	fop.o_bd->bd_info = (BackendInfo *)on;
Howard Chu's avatar
Howard Chu committed
742

743
744
	switch( mode ) {
	case FIND_MAXCSN:
745
		if ( ber_bvcmp( &si->si_ctxcsn[maxid], &maxcsn )) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
746
747
748
749
#ifdef CHECK_CSN
			Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
			assert( !syn->ssyn_validate( syn, &maxcsn ));
#endif
750
751
752
			ber_bvreplace( &si->si_ctxcsn[maxid], &maxcsn );
			si->si_numops++;	/* ensure a checkpoint */
		}
753
754
755
		break;
	case FIND_CSN:
		/* If matching CSN was not found, invalidate the context. */
Howard Chu's avatar
Howard Chu committed
756
757
758
759
		if ( !cb.sc_private ) {
			/* If we didn't find an exact match, then try for <= */
			if ( findcsn_retry ) {
				findcsn_retry = 0;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
760
				rs_reinit( &frs, REP_RESULT );
Howard Chu's avatar
Howard Chu committed
761
762
763
764
				goto again;
			}
			rc = LDAP_NO_SUCH_OBJECT;
		}
765
766
		break;
	case FIND_PRESENT:
767
		op->o_tmpfree( pcookie.uuids, op->o_tmpmemctx );
768
		break;
Howard Chu's avatar
Howard Chu committed
769
770
	}

771
	return rc;
Howard Chu's avatar
Howard Chu committed
772
773
}

Howard Chu's avatar
Howard Chu committed
774
static void free_resinfo( syncres *sr )
775
{
Howard Chu's avatar
Howard Chu committed
776
	syncres **st;
Howard Chu's avatar
Howard Chu committed
777
	int freeit = 0;
Howard Chu's avatar
Howard Chu committed
778
779
780
781
782
783
784
	ldap_pvt_thread_mutex_lock( &sr->s_info->ri_mutex );
	for (st = &sr->s_info->ri_list; *st; st = &(*st)->s_rilist) {
		if (*st == sr) {
			*st = sr->s_rilist;
			break;
		}
	}
Howard Chu's avatar
Howard Chu committed
785
786
	if ( !sr->s_info->ri_list )
		freeit = 1;
Howard Chu's avatar
Howard Chu committed
787
	ldap_pvt_thread_mutex_unlock( &sr->s_info->ri_mutex );
Howard Chu's avatar
Howard Chu committed
788
	if ( freeit ) {
Howard Chu's avatar
Howard Chu committed
789
790
791
		ldap_pvt_thread_mutex_destroy( &sr->s_info->ri_mutex );
		if ( sr->s_info->ri_e )
			entry_free( sr->s_info->ri_e );
Howard Chu's avatar
Howard Chu committed
792
793
		if ( !BER_BVISNULL( &sr->s_info->ri_cookie ))
			ch_free( sr->s_info->ri_cookie.bv_val );
Howard Chu's avatar
Howard Chu committed
794
		ch_free( sr->s_info );
795
796
797
	}
}

798
static int
799
syncprov_free_syncop( syncops *so, int unlink )
800
801
802
803
804
{
	syncres *sr, *srnext;
	GroupAssertion *ga, *gnext;

	ldap_pvt_thread_mutex_lock( &so->s_mutex );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
805
806
	/* already being freed, or still in use */
	if ( !so->s_inuse || --so->s_inuse > 0 ) {
807
		ldap_pvt_thread_mutex_unlock( &so->s_mutex );
808
		return 0;
809
810
	}
	ldap_pvt_thread_mutex_unlock( &so->s_mutex );
811
812
813
814
815
816
817
818
819
820
821
	if ( unlink ) {
		syncops **sop;
		ldap_pvt_thread_mutex_lock( &so->s_si->si_ops_mutex );
		for ( sop = &so->s_si->si_ops; *sop; sop = &(*sop)->s_next ) {
			if ( *sop == so ) {
				*sop = so->s_next;
				break;
			}
		}
		ldap_pvt_thread_mutex_unlock( &so->s_si->si_ops_mutex );
	}
822
823
824
825
826
827
828
829
830
831
832
	if ( so->s_flags & PS_IS_DETACHED ) {
		filter_free( so->s_op->ors_filter );
		for ( ga = so->s_op->o_groups; ga; ga=gnext ) {
			gnext = ga->ga_next;
			ch_free( ga );
		}
		ch_free( so->s_op );
	}
	ch_free( so->s_base.bv_val );
	for ( sr=so->s_res; sr; sr=srnext ) {
		srnext = sr->s_next;
Howard Chu's avatar
Howard Chu committed
833
		free_resinfo( sr );
834
835
836
837
		ch_free( sr );
	}
	ldap_pvt_thread_mutex_destroy( &so->s_mutex );
	ch_free( so );
838
	return 1;
839
840
}

841
842
/* Send a persistent search response */
static int
Howard Chu's avatar
Howard Chu committed
843
syncprov_sendresp( Operation *op, resinfo *ri, syncops *so, int mode )
844
845
{
	SlapReply rs = { REP_SEARCH };
846
	struct berval cookie, csns[2];
847
848
849
	Entry e_uuid = {0};
	Attribute a_uuid = {0};

Howard Chu's avatar
Howard Chu committed
850
851
852
	if ( so->s_op->o_abandon )
		return SLAPD_ABANDON;

853
854
855
	rs.sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2, op->o_tmpmemctx );
	rs.sr_ctrls[1] = NULL;
	rs.sr_flags = REP_CTRLS_MUSTBEFREED;
Howard Chu's avatar
Howard Chu committed
856
	csns[0] = ri->ri_csn;
857
858
	BER_BVZERO( &csns[1] );
	slap_compose_sync_cookie( op, &cookie, csns, so->s_rid, slap_serverID ? slap_serverID : -1 );
859

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
860
#ifdef LDAP_DEBUG
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
861
862
	if ( so->s_sid > 0 ) {
		Debug( LDAP_DEBUG_SYNC, "syncprov_sendresp: to=%03x, cookie=%s\n",
863
			so->s_sid, cookie.bv_val, 0 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
864
865
	} else {
		Debug( LDAP_DEBUG_SYNC, "syncprov_sendresp: cookie=%s\n",
866
			cookie.bv_val, 0, 0 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
867
	}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
868
#endif
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
869

870
871
	e_uuid.e_attrs = &a_uuid;
	a_uuid.a_desc = slap_schema.si_ad_entryUUID;
Howard Chu's avatar
Howard Chu committed
872
	a_uuid.a_nvals = &ri->ri_uuid;
873
	rs.sr_err = syncprov_state_ctrl( op, &rs, &e_uuid,
874
		mode, rs.sr_ctrls, 0, 1, &cookie );
875
	op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx );
876

877
878
	rs.sr_entry = &e_uuid;
	if ( mode == LDAP_SYNC_ADD || mode == LDAP_SYNC_MODIFY ) {
Howard Chu's avatar
Howard Chu committed
879
		e_uuid = *ri->ri_e;
880
881
882
		e_uuid.e_private = NULL;
	}

883
884
	switch( mode ) {
	case LDAP_SYNC_ADD:
Howard Chu's avatar
Howard Chu committed
885
		if ( ri->ri_isref && so->s_op->o_managedsait <= SLAP_CONTROL_IGNORED ) {
886
			rs.sr_ref = get_entry_referrals( op, rs.sr_entry );
887
			rs.sr_err = send_search_reference( op, &rs );
888
889
890
891
892
			ber_bvarray_free( rs.sr_ref );
			break;
		}
		/* fallthru */
	case LDAP_SYNC_MODIFY:
893
		rs.sr_attrs = op->ors_attrs;
894
		rs.sr_err = send_search_entry( op, &rs );
895
896
897
		break;
	case LDAP_SYNC_DELETE:
		e_uuid.e_attrs = NULL;
Howard Chu's avatar
Howard Chu committed
898
899
900
		e_uuid.e_name = ri->ri_dn;
		e_uuid.e_nname = ri->ri_ndn;
		if ( ri->ri_isref && so->s_op->o_managedsait <= SLAP_CONTROL_IGNORED ) {
901
			struct berval bv = BER_BVNULL;
902
			rs.sr_ref = &bv;
903
			rs.sr_err = send_search_reference( op, &rs );
Howard Chu's avatar
Howard Chu committed
904
		} else {
905
			rs.sr_err = send_search_entry( op, &rs );
906
907
908
909
910
		}
		break;
	default:
		assert(0);
	}
911
912
913
	return rs.sr_err;
}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
914
915
916
static void
syncprov_qstart( syncops *so );

917
918
/* Play back queued responses */
static int
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
919
syncprov_qplay( Operation *op, syncops *so )
920
921
{
	syncres *sr;
922
	int rc = 0;
923

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
924
	do {
925
		ldap_pvt_thread_mutex_lock( &so->s_mutex );
926
		sr = so->s_res;
Howard Chu's avatar
Howard Chu committed
927
		/* Exit loop with mutex held */
Howard Chu's avatar
Howard Chu committed
928
		if ( !sr )
929
			break;
Howard Chu's avatar
Howard Chu committed
930
931
932
		so->s_res = sr->s_next;
		if ( !so->s_res )
			so->s_restail = NULL;
Howard Chu's avatar
Howard Chu committed
933
		ldap_pvt_thread_mutex_unlock( &so->s_mutex );
934

935
		if ( !so->s_op->o_abandon ) {
936

937
938
			if ( sr->s_mode == LDAP_SYNC_NEW_COOKIE ) {
				SlapReply rs = { REP_INTERMEDIATE };
939

940
				rc = syncprov_sendinfo( op, &rs, LDAP_TAG_SYNC_NEW_COOKIE,
Howard Chu's avatar
Howard Chu committed
941
					&sr->s_info->ri_cookie, 0, NULL, 0 );
942
			} else {
Howard Chu's avatar
Howard Chu committed
943
				rc = syncprov_sendresp( op, sr->s_info, so, sr->s_mode );
944
			}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
945
		}
946

Howard Chu's avatar
Howard Chu committed
947
		free_resinfo( sr );
948
		ch_free( sr );
949

950
951
952
		if ( so->s_op->o_abandon )
			continue;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
953
954
		/* Exit loop with mutex held */
		ldap_pvt_thread_mutex_lock( &so->s_mutex );
955
		break;
Howard Chu's avatar
Howard Chu committed
956

957
	} while (1);
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
958
959
960
961
962

	/* We now only send one change at a time, to prevent one
	 * psearch from hogging all the CPU. Resubmit this task if
	 * there are more responses queued and no errors occurred.
	 */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
963

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
964
965
966
967
	if ( rc == 0 && so->s_res ) {
		syncprov_qstart( so );
	} else {
		so->s_flags ^= PS_TASK_QUEUED;
968
	}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
969

Howard Chu's avatar
Howard Chu committed
970
	ldap_pvt_thread_mutex_unlock( &so->s_mutex );
971
972
973
	return rc;
}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
974
/* task for playing back queued responses */
975
976
977
static void *
syncprov_qtask( void *ctx, void *arg )
{
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
978
	syncops *so = arg;
979
	OperationBuffer opbuf;
980
981
	Operation *op;
	BackendDB be;
982
	int rc;
983

984
	op = &opbuf.ob_op;
985
	*op = *so->s_op;
986
987
988
	op->o_hdr = &opbuf.ob_hdr;
	op->o_controls = opbuf.ob_controls;
	memset( op->o_controls, 0, sizeof(opbuf.ob_controls) );
989
	op->o_sync = SLAP_CONTROL_IGNORED;
990
991
992

	*op->o_hdr = *so->s_op->o_hdr;

993
	op->o_tmpmemctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 1);
994
995
996
997
998
999
1000
	op->o_tmpmfuncs = &slap_sl_mfuncs;
	op->o_threadctx = ctx;

	/* syncprov_qplay expects a fake db */
	be = *so->s_op->o_bd;
	be.be_flags |= SLAP_DBFLAG_OVERLAY;
	op->o_bd = &be;
Howard Chu's avatar
Howard Chu committed
1001
	LDAP_SLIST_FIRST(&op->o_extra) = NULL;
1002
1003
	op->o_callback = NULL;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1004
	rc = syncprov_qplay( op, so );
1005

1006
	/* decrement use count... */
1007
	syncprov_free_syncop( so, 1 );
1008

1009
1010
1011
	return NULL;
}

1012
1013
1014
1015
/* Start the task to play back queued psearch responses */
static void
syncprov_qstart( syncops *so )
{
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1016
1017
1018
1019
	so->s_flags |= PS_TASK_QUEUED;
	so->s_inuse++;
	ldap_pvt_thread_pool_submit( &connection_pool, 
		syncprov_qtask, so );
1020
1021
}

1022
1023
1024
1025
1026
/* Queue a persistent search response */
static int
syncprov_qresp( opcookie *opc, syncops *so, int mode )
{
	syncres *sr;
Howard Chu's avatar
Howard Chu committed
1027
	resinfo *ri;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1028
	int srsize;
Howard Chu's avatar
Howard Chu committed
1029
	struct berval csn = opc->sctxcsn;
1030

Howard Chu's avatar
Howard Chu committed
1031
	sr = ch_malloc( sizeof( syncres ));
1032
1033
	sr->s_next = NULL;
	sr->s_mode = mode;
Howard Chu's avatar
Howard Chu committed
1034
1035
1036
	if ( !opc->ssres.s_info ) {

		srsize =