connection.c 51.4 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2005 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * 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>.
 */
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor. The name of the University
 * may not be used to endorse or promote products derived from this
 * software without specific prior written permission. This software
 * is provided ``as is'' without express or implied warranty.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
24
25
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
26
#include "portable.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
28

#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
29
#ifdef HAVE_LIMITS_H
Kurt Zeilenga's avatar
Kurt Zeilenga committed
30
#include <limits.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
31
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
32

33
#include <ac/socket.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
35
36
#include <ac/errno.h>
#include <ac/string.h>
#include <ac/time.h>
Pierangelo Masarati's avatar
Pierangelo Masarati committed
37
#include <ac/unistd.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
38

Kurt Zeilenga's avatar
Kurt Zeilenga committed
39
#include "lutil.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
40
41
#include "slap.h"

42
#ifdef LDAP_SLAPI
43
#include "slapi/slapi.h"
44
45
#endif

46
47
48
49
50
51

#ifdef SLAP_MULTI_CONN_ARRAY
/* for Multiple Connection Arrary (MCA) Support */
static ldap_pvt_thread_mutex_t* connections_mutex;
static Connection **connections = NULL;

52
/* set to the number of processors (round up to a power of 2) */
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
53
#	define NUM_CONNECTION_ARRAY 4
54
55

/* partition the array in a modulo manner */
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
56
57
#	define MCA_conn_array_id(fd)		((int)(fd)%NUM_CONNECTION_ARRAY)
#	define MCA_conn_array_element_id(fd)	((int)(fd)/NUM_CONNECTION_ARRAY)
58
#	define MCA_GET_CONNECTION(fd) (&(connections[MCA_conn_array_id(fd)]) \
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
59
60
		[MCA_conn_array_element_id(fd)])
#	define MCA_GET_CONN_MUTEX(fd) (&connections_mutex[MCA_conn_array_id(fd)])
61
62

#else
63
64
65
/* protected by connections_mutex */
static ldap_pvt_thread_mutex_t connections_mutex;
static Connection *connections = NULL;
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
66
67
68

#	define MCA_GET_CONNECTION(fd) (&connections[s])
#	define MCA_GET_CONN_MUTEX(fd) (&connections_mutex)
69
#endif
70
71

static ldap_pvt_thread_mutex_t conn_nextid_mutex;
72
static unsigned long conn_nextid = 0;
73

74
75
static const char conn_lost_str[] = "connection lost";

76
/* structure state (protected by connections_mutex) */
77
78
79
#define SLAP_C_UNINITIALIZED	0x00	/* MUST BE ZERO (0) */
#define SLAP_C_UNUSED			0x01
#define SLAP_C_USED				0x02
80
81

/* connection state (protected by c_mutex ) */
82
83
84
85
86
#define SLAP_C_INVALID			0x00	/* MUST BE ZERO (0) */
#define SLAP_C_INACTIVE			0x01	/* zero threads */
#define SLAP_C_ACTIVE			0x02	/* one or more threads */
#define SLAP_C_BINDING			0x03	/* binding */
#define SLAP_C_CLOSING			0x04	/* closing */
87
#define SLAP_C_CLIENT			0x05	/* outbound client conn */
88

89
90
91
const char *
connection_state2str( int state )
{
92
	switch( state ) {
93
94
95
	case SLAP_C_INVALID:	return "!";
	case SLAP_C_INACTIVE:	return "|";
	case SLAP_C_ACTIVE:		return "";
96
	case SLAP_C_BINDING:	return "B";
97
98
	case SLAP_C_CLOSING:	return "C";
	case SLAP_C_CLIENT:		return "L";
99
100
101
102
103
	}

	return "?";
}

104
static Connection* connection_get( ber_socket_t s );
105

106
#ifdef SLAP_LIGHTWEIGHT_DISPATCHER
107
108
static int connection_input( Connection *c, Operation** op );
#else
109
static int connection_input( Connection *c );
110
#endif
111
static void connection_close( Connection *c );
112

113
static int connection_op_activate( Operation *op );
114
#ifdef SLAP_LIGHTWEIGHT_DISPATCHER
115
116
static void connection_op_queue( Operation *op );
#endif
117
static int connection_resched( Connection *conn );
118
static void connection_abandon( Connection *conn );
119
static void connection_destroy( Connection *c );
120

121
122
static ldap_pvt_thread_start_t connection_operation;

123
124
125
126
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
127
128
129
130
131
132
133
134
135
136
137
138
139
#ifdef SLAP_MULTI_CONN_ARRAY
{
	int i, j;
	Connection* conn;

	assert( connections == NULL );

	if( connections != NULL) {
		Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n",
			0, 0, 0 );
		return -1;
	}

140
141
	connections_mutex = (ldap_pvt_thread_mutex_t*) ch_calloc(
		NUM_CONNECTION_ARRAY, sizeof(ldap_pvt_thread_mutex_t) );
142
	if( connections_mutex == NULL ) {
143
144
		Debug( LDAP_DEBUG_ANY, "connections_init: "
			"allocation of connection mutex[%d] failed\n", i, 0, 0 );
145
146
147
		return -1;
	}

148
149
	connections = (Connection**) ch_calloc(
		NUM_CONNECTION_ARRAY, sizeof(Connection*));
150
	if( connections == NULL ) {
151
152
		Debug( LDAP_DEBUG_ANY, "connections_init: "
			"allocation of connection[%d] failed\n", 0, 0, 0 );
153
154
155
156
157
		return -1;
	}

	for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) {
		ldap_pvt_thread_mutex_init( connections_mutex+i );
158
159
		connections[i] = (Connection*) ch_calloc(
			dtblsize/NUM_CONNECTION_ARRAY, sizeof(Connection) );
160
		if( connections[i] == NULL ) {
161
162
			Debug( LDAP_DEBUG_ANY, "connections_init: "
				"allocation (%d*%ld) of connection array[%d] failed\n",
163
164
165
166
167
168
169
170
171
				dtblsize, (long) sizeof(Connection), i );
			return -1;
		}
	}

	/* should check return of every call */
	ldap_pvt_thread_mutex_init( &conn_nextid_mutex );

	assert( connections[0]->c_struct_state == SLAP_C_UNINITIALIZED );
172
173
	assert( connections[NUM_CONNECTION_ARRAY-1]->c_struct_state ==
		SLAP_C_UNINITIALIZED );
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

	for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) {
		conn = connections[i];
		for ( j = 0; j < (dtblsize/NUM_CONNECTION_ARRAY); j++ ) {
			conn[j].c_conn_idx = j;
		}
	}

	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}
#else
190
{
191
192
	int i;

193
194
	assert( connections == NULL );

195
	if( connections != NULL) {
196
197
198
199
200
201
202
		Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n",
			0, 0, 0 );
		return -1;
	}

	/* should check return of every call */
	ldap_pvt_thread_mutex_init( &connections_mutex );
203
	ldap_pvt_thread_mutex_init( &conn_nextid_mutex );
204

205
	connections = (Connection *) ch_calloc( dtblsize, sizeof(Connection) );
206
207

	if( connections == NULL ) {
208
209
		Debug( LDAP_DEBUG_ANY, "connections_init: "
			"allocation (%d*%ld) of connection array failed\n",
210
			dtblsize, (long) sizeof(Connection), 0 );
211
212
213
		return -1;
	}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
214
	assert( connections[0].c_struct_state == SLAP_C_UNINITIALIZED );
215
	assert( connections[dtblsize-1].c_struct_state == SLAP_C_UNINITIALIZED );
216

217
	for (i=0; i<dtblsize; i++) connections[i].c_conn_idx = i;
218

219
220
221
222
223
224
225
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}
226
#endif
227

228
229
230
/*
 * Destroy connection management infrastructure.
 */
231

232
int connections_destroy(void)
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#ifdef SLAP_MULTI_CONN_ARRAY
{
	int i;
	ber_socket_t j;

	if( connections == NULL) {
		Debug( LDAP_DEBUG_ANY, "connections_destroy: nothing to destroy.\n",
			0, 0, 0 );
		return -1;
	}

    for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) {
		Connection* conn = connections[i];
		for ( j = 0; j < (dtblsize/NUM_CONNECTION_ARRAY); j++ ) {
			if( conn[j].c_struct_state != SLAP_C_UNINITIALIZED ) {
				ber_sockbuf_free( conn[j].c_sb );
				ldap_pvt_thread_mutex_destroy( &conn[j].c_mutex );
				ldap_pvt_thread_mutex_destroy( &conn[j].c_write_mutex );
				ldap_pvt_thread_cond_destroy( &conn[j].c_write_cv );
#ifdef LDAP_SLAPI
				/* FIX ME!! */
				if ( slapi_plugins_used ) {
					slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION,
						&connections[i] );
				}
#endif
			}
		}
	}

	for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) {
		free( connections[i] );
		connections[i] = NULL;
		ldap_pvt_thread_mutex_destroy( &connections_mutex[i] );
	}

	ldap_pvt_thread_mutex_destroy( &conn_nextid_mutex );

	return 0;

}
#else
275
{
276
	ber_socket_t i;
277
278
279
280
281
282
283
284
285

	/* should check return of every call */

	if( connections == NULL) {
		Debug( LDAP_DEBUG_ANY, "connections_destroy: nothing to destroy.\n",
			0, 0, 0 );
		return -1;
	}

286
	for ( i = 0; i < dtblsize; i++ ) {
287
		if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
288
			ber_sockbuf_free( connections[i].c_sb );
289
290
291
			ldap_pvt_thread_mutex_destroy( &connections[i].c_mutex );
			ldap_pvt_thread_mutex_destroy( &connections[i].c_write_mutex );
			ldap_pvt_thread_cond_destroy( &connections[i].c_write_cv );
292
#ifdef LDAP_SLAPI
293
			if ( slapi_plugins_used ) {
294
295
				slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION,
					&connections[i] );
Howard Chu's avatar
Howard Chu committed
296
			}
297
#endif
298
		}
299
300
301
302
303
304
	}

	free( connections );
	connections = NULL;

	ldap_pvt_thread_mutex_destroy( &connections_mutex );
305
	ldap_pvt_thread_mutex_destroy( &conn_nextid_mutex );
306
307
	return 0;
}
308
#endif
309
310
311
312
313

/*
 * shutdown all connections
 */
int connections_shutdown(void)
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
#ifdef SLAP_MULTI_CONN_ARRAY
{
	int i;
	ber_socket_t j;

	for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) {
		Connection* conn = connections[i];
		ldap_pvt_thread_mutex_lock( &connections_mutex[i] );
		for ( j = 0; j < (dtblsize/NUM_CONNECTION_ARRAY); j++ ) {
			if( conn[j].c_struct_state != SLAP_C_USED ) {
				continue;
			}
			/* give persistent clients a chance to cleanup */
			if( conn[j].c_conn_state == SLAP_C_CLIENT ) {
				ldap_pvt_thread_pool_submit( &connection_pool,
				conn[j].c_clientfunc, conn[j].c_clientarg );
				continue;
			}

			ldap_pvt_thread_mutex_lock( &conn[j].c_mutex );
			/* connections_mutex and c_mutex are locked */
			connection_closing( &conn[j], "connection shutdown" );
			connection_close( &conn[j] );
			ldap_pvt_thread_mutex_unlock( &conn[j].c_mutex );
		}

		ldap_pvt_thread_mutex_unlock( &connections_mutex[i] );
	}

	return 0;

}
#else
347
{
348
	ber_socket_t i;
349
350
351

	ldap_pvt_thread_mutex_lock( &connections_mutex );

352
	for ( i = 0; i < dtblsize; i++ ) {
353
354
355
		if( connections[i].c_struct_state != SLAP_C_USED ) {
			continue;
		}
356
357
		/* give persistent clients a chance to cleanup */
		if( connections[i].c_conn_state == SLAP_C_CLIENT ) {
358
			ldap_pvt_thread_pool_submit( &connection_pool,
359
360
361
			connections[i].c_clientfunc, connections[i].c_clientarg );
			continue;
		}
362
363

		ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
364
365

		/* connections_mutex and c_mutex are locked */
366
		connection_closing( &connections[i], "slapd shutdown" );
367
		connection_close( &connections[i] );
368

369
370
371
372
		ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
	}

	ldap_pvt_thread_mutex_unlock( &connections_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
373
374

	return 0;
375
}
376
#endif
377

378
379
380
381
382
383
384
385
386
/*
 * Timeout idle connections.
 */
int connections_timeout_idle(time_t now)
{
	int i = 0;
	int connindex;
	Connection* c;

Gary Williams's avatar
Gary Williams committed
387
	for( c = connection_first( &connindex );
388
389
390
		c != NULL;
		c = connection_next( c, &connindex ) )
	{
391
392
		/* Don't timeout a slow-running request or a persistent
		 * outbound connection */
393
394
395
		if( c->c_n_ops_executing || c->c_conn_state == SLAP_C_CLIENT ) {
			continue;
		}
396

397
		if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
398
			/* close it */
399
			connection_closing( c, "idletimeout" );
400
401
402
403
404
405
406
407
408
			connection_close( c );
			i++;
		}
	}
	connection_done( c );

	return i;
}

409
static Connection* connection_get( ber_socket_t s )
410
{
411
412
	/* connections_mutex should be locked by caller */

413
414
415
	Connection *c;

	Debug( LDAP_DEBUG_ARGS,
416
417
		"connection_get(%ld)\n",
		(long) s, 0, 0 );
418
419
420

	assert( connections != NULL );

421
	if(s == AC_SOCKET_INVALID) return NULL;
422
423

#ifndef HAVE_WINSOCK
424
	c = MCA_GET_CONNECTION(s);
425

Kurt Zeilenga's avatar
Kurt Zeilenga committed
426
	assert( c->c_struct_state != SLAP_C_UNINITIALIZED );
427

428
#else
429
	c = NULL;
430
	{
431
		ber_socket_t i, sd;
432

433
		for(i=0; i<dtblsize; i++) {
Gary Williams's avatar
NT port    
Gary Williams committed
434
			if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
435
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
436
				assert( connections[i].c_sb == 0 );
437
438
439
				break;
			}

440
441
442
			ber_sockbuf_ctrl( connections[i].c_sb,
				LBER_SB_OPT_GET_FD, &sd );

Gary Williams's avatar
NT port    
Gary Williams committed
443
			if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
444
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
445
				assert( sd == AC_SOCKET_INVALID );
446
447
448
				continue;
			}

449
450
451
			/* state can actually change from used -> unused by resched,
			 * so don't assert details here.
			 */
452

453
			if( sd == s ) {
Gary Williams's avatar
NT port    
Gary Williams committed
454
				c = &connections[i];
455
456
457
458
459
				break;
			}
		}
	}
#endif
460

461
	if( c != NULL ) {
462
463
		ber_socket_t	sd;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
464
465
		ldap_pvt_thread_mutex_lock( &c->c_mutex );

466
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
467
468
		if( c->c_struct_state != SLAP_C_USED ) {
			/* connection must have been closed due to resched */
469

470
			assert( c->c_conn_state == SLAP_C_INVALID );
471
			assert( sd == AC_SOCKET_INVALID );
472
473

			Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
474
475
				"connection_get(%d): connection not used\n",
				s, 0, 0 );
476

477
			ldap_pvt_thread_mutex_unlock( &c->c_mutex );
478
479
480
			return NULL;
		}

481
		Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
482
			"connection_get(%d): got connid=%lu\n",
483
			s, c->c_connid, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
484

485
486
		c->c_n_get++;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
487
488
		assert( c->c_struct_state == SLAP_C_USED );
		assert( c->c_conn_state != SLAP_C_INVALID );
489
		assert( sd != AC_SOCKET_INVALID );
490

491
#ifndef SLAPD_MONITOR
492
		if ( global_idletimeout > 0 )
493
494
#endif /* ! SLAPD_MONITOR */
		{
495
496
			c->c_activitytime = slap_get_time();
		}
497
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
498

499
500
501
502
503
504
505
506
507
	return c;
}

static void connection_return( Connection *c )
{
	ldap_pvt_thread_mutex_unlock( &c->c_mutex );
}

long connection_init(
508
	ber_socket_t s,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
509
	Listener *listener,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
510
511
	const char* dnsname,
	const char* peername,
512
	int flags,
513
	slap_ssf_t ssf,
514
	struct berval *authid )
515
{
516
	unsigned long id;
517
	Connection *c;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
518

519
520
	assert( connections != NULL );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
521
	assert( listener != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
522
523
524
	assert( dnsname != NULL );
	assert( peername != NULL );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
525
#ifndef HAVE_TLS
526
	assert( flags != CONN_IS_TLS );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
527
528
#endif

529
	if( s == AC_SOCKET_INVALID ) {
Gary Williams's avatar
Gary Williams committed
530
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
531
			"connection_init: init of socket %ld invalid.\n", (long)s, 0, 0 );
532
533
534
535
536
		return -1;
	}

	assert( s >= 0 );
#ifndef HAVE_WINSOCK
537
	assert( s < dtblsize );
538
539
#endif

540
	ldap_pvt_thread_mutex_lock( MCA_GET_CONN_MUTEX(s) );
541
542

#ifndef HAVE_WINSOCK
543
	c = MCA_GET_CONNECTION(s);
544
545
#else
	{
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
546
		ber_socket_t i;
547
548
		c = NULL;

549
		for( i=0; i < dtblsize; i++) {
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
550
			ber_socket_t	sd;
551

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
552
553
554
555
556
			if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
				assert( connections[i].c_sb == 0 );
				c = &connections[i];
				break;
			}
Gary Williams's avatar
NT port    
Gary Williams committed
557

558
			sd = AC_SOCKET_INVALID;
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
559
560
561
562
			if (connections[i].c_sb != NULL) {
				ber_sockbuf_ctrl( connections[i].c_sb,
					LBER_SB_OPT_GET_FD, &sd );
			}
Gary Williams's avatar
Gary Williams committed
563

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
564
565
566
567
568
			if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
				assert( sd == AC_SOCKET_INVALID );
				c = &connections[i];
				break;
			}
Gary Williams's avatar
Gary Williams committed
569

570
			if( connections[i].c_conn_state == SLAP_C_CLIENT ) continue;
571

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
572
573
574
575
576
577
578
			assert( connections[i].c_struct_state == SLAP_C_USED );
			assert( connections[i].c_conn_state != SLAP_C_INVALID );
			assert( sd != AC_SOCKET_INVALID );
		}

		if( c == NULL ) {
			Debug( LDAP_DEBUG_ANY,
579
				"connection_init(%d): connection table full "
580
				"(%d/%d)\n", s, i, dtblsize);
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
581
582
583
			ldap_pvt_thread_mutex_unlock( &connections_mutex );
			return -1;
		}
Gary Williams's avatar
Gary Williams committed
584
	}
585
586
#endif

587
	assert( c != NULL );
588

589
	if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
590
591
592
593
		c->c_send_ldap_result = slap_send_ldap_result;
		c->c_send_search_entry = slap_send_search_entry;
		c->c_send_search_reference = slap_send_search_reference;
		c->c_send_ldap_extended = slap_send_ldap_extended;
594
595
#ifdef LDAP_RES_INTERMEDIATE
		c->c_send_ldap_intermediate = slap_send_ldap_intermediate;
596
#endif
597

598
599
600
		BER_BVZERO( &c->c_authmech );
		BER_BVZERO( &c->c_dn );
		BER_BVZERO( &c->c_ndn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
601

Pierangelo Masarati's avatar
Pierangelo Masarati committed
602
		c->c_listener = NULL;
603
604
		BER_BVZERO( &c->c_peer_domain );
		BER_BVZERO( &c->c_peer_name );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
605

606
607
		LDAP_STAILQ_INIT(&c->c_ops);
		LDAP_STAILQ_INIT(&c->c_pending_ops);
608

609
		BER_BVZERO( &c->c_sasl_bind_mech );
610
611
612
		c->c_sasl_done = 0;
		c->c_sasl_authctx = NULL;
		c->c_sasl_sockctx = NULL;
613
		c->c_sasl_extra = NULL;
614
		c->c_sasl_bindop = NULL;
615

616
617
618
		c->c_sb = ber_sockbuf_alloc( );

		{
619
			ber_len_t max = sockbuf_max_incoming;
620
621
622
			ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
623
		c->c_currentber = NULL;
624

625
626
627
628
		/* should check status of thread calls */
		ldap_pvt_thread_mutex_init( &c->c_mutex );
		ldap_pvt_thread_mutex_init( &c->c_write_mutex );
		ldap_pvt_thread_cond_init( &c->c_write_cv );
629

630
#ifdef LDAP_SLAPI
631
		if ( slapi_plugins_used ) {
632
			slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, c );
633
		}
634
635
#endif

636
637
		c->c_struct_state = SLAP_C_UNUSED;
	}
638

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
639
	ldap_pvt_thread_mutex_lock( &c->c_mutex );
640

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
641
	assert( c->c_struct_state == SLAP_C_UNUSED );
642
643
644
	assert( BER_BVISNULL( &c->c_authmech ) );
	assert( BER_BVISNULL( &c->c_dn ) );
	assert( BER_BVISNULL( &c->c_ndn ) );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
645
	assert( c->c_listener == NULL );
646
647
	assert( BER_BVISNULL( &c->c_peer_domain ) );
	assert( BER_BVISNULL( &c->c_peer_name ) );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
648
649
	assert( LDAP_STAILQ_EMPTY(&c->c_ops) );
	assert( LDAP_STAILQ_EMPTY(&c->c_pending_ops) );
650
	assert( BER_BVISNULL( &c->c_sasl_bind_mech ) );
651
652
653
	assert( c->c_sasl_done == 0 );
	assert( c->c_sasl_authctx == NULL );
	assert( c->c_sasl_sockctx == NULL );
654
	assert( c->c_sasl_extra == NULL );
655
	assert( c->c_sasl_bindop == NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
656
	assert( c->c_currentber == NULL );
657
	assert( c->c_writewaiter == 0);
658

Pierangelo Masarati's avatar
Pierangelo Masarati committed
659
	c->c_listener = listener;
660
661
662
663

	if ( flags == CONN_IS_CLIENT ) {
		c->c_conn_state = SLAP_C_CLIENT;
		c->c_struct_state = SLAP_C_USED;
664
		c->c_close_reason = "?";			/* should never be needed */
665
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s );
666
		ldap_pvt_thread_mutex_unlock( &c->c_mutex );
667
		ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) );
668
669
670
671

		return 0;
	}

672
673
	ber_str2bv( dnsname, 0, 1, &c->c_peer_domain );
	ber_str2bv( peername, 0, 1, &c->c_peer_name );
674

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
675
676
677
678
	c->c_n_ops_received = 0;
	c->c_n_ops_executing = 0;
	c->c_n_ops_pending = 0;
	c->c_n_ops_completed = 0;
679
680
681
682

	c->c_n_get = 0;
	c->c_n_read = 0;
	c->c_n_write = 0;
683

684
685
	/* set to zero until bind, implies LDAP_VERSION3 */
	c->c_protocol = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
686

687
#ifndef SLAPD_MONITOR
688
	if ( global_idletimeout > 0 )
689
690
#endif /* ! SLAPD_MONITOR */
	{
691
692
		c->c_activitytime = c->c_starttime = slap_get_time();
	}
693

694
695
#ifdef LDAP_CONNECTIONLESS
	c->c_is_udp = 0;
696
	if( flags == CONN_IS_UDP ) {
697
698
		c->c_is_udp = 1;
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
699
700
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_PROVIDER, (void*)"udp_" );
701
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
702
703
704
705
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_udp,
			LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_readahead,
			LBER_SBIOD_LEVEL_PROVIDER, NULL );
706
707
708
	} else
#endif
	{
709
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
710
711
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_PROVIDER, (void*)"tcp_" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
712
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
713
714
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp,
			LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
715
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
716
717
718
719

#ifdef LDAP_DEBUG
	ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
		INT_MAX, (void*)"ldap_" );
720
#endif
721

Kurt Zeilenga's avatar
Kurt Zeilenga committed
722
723
724
725
726
	if( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_NONBLOCK,
		c /* non-NULL */ ) < 0 )
	{
		Debug( LDAP_DEBUG_ANY,
			"connection_init(%d, %s): set nonblocking failed\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
727
			s, c->c_peer_name.bv_val, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
728
	}
729

730
	ldap_pvt_thread_mutex_lock( &conn_nextid_mutex );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
731
	id = c->c_connid = conn_nextid++;
732
	ldap_pvt_thread_mutex_unlock( &conn_nextid_mutex );
733

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
734
735
	c->c_conn_state = SLAP_C_INACTIVE;
	c->c_struct_state = SLAP_C_USED;
736
	c->c_close_reason = "?";			/* should never be needed */
737

738
739
740
	c->c_ssf = c->c_transport_ssf = ssf;
	c->c_tls_ssf = 0;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
741
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
742
743
744
745
746
747
748
	if ( flags == CONN_IS_TLS ) {
		c->c_is_tls = 1;
		c->c_needs_tls_accept = 1;
	} else {
		c->c_is_tls = 0;
		c->c_needs_tls_accept = 0;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
749
#endif
750

751
	slap_sasl_open( c, 0 );
752
	slap_sasl_external( c, ssf, authid );
753

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
754
	ldap_pvt_thread_mutex_unlock( &c->c_mutex );
755
	ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) );
756

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
757
	backend_connection_init(c);
758

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
759
	return id;
760
761
}

762
763
void connection2anonymous( Connection *c )
{
764
765
	assert( connections != NULL );
	assert( c != NULL );
766

767
	{
768
		ber_len_t max = sockbuf_max_incoming;
769
770
771
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
	}

772
	if ( !BER_BVISNULL( &c->c_authmech ) ) {
773
		ch_free(c->c_authmech.bv_val);
774
	}
775
	BER_BVZERO( &c->c_authmech );
776

777
	if ( !BER_BVISNULL( &c->c_dn ) ) {
778
		ch_free(c->c_dn.bv_val);
779
	}
780
	BER_BVZERO( &c->c_dn );
781

782
	if ( !BER_BVISNULL( &c->c_ndn ) ) {
783
		ch_free(c->c_ndn.bv_val);
784
	}
785
	BER_BVZERO( &c->c_ndn );
786

787
788
	if ( !BER_BVISNULL( &c->c_sasl_authz_dn ) ) {
		ber_memfree_x( c->c_sasl_authz_dn.bv_val, NULL );
789
790
	}
	BER_BVZERO( &c->c_sasl_authz_dn );
791
792
793
794

	c->c_authz_backend = NULL;
}

795
796
797
static void
connection_destroy( Connection *c )
{
798
	/* note: connections_mutex should be locked by caller */
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
799
800
	ber_socket_t	sd;
	unsigned long	connid;
801
	const char		*close_reason;
802

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
803
804
805
806
807
	assert( connections != NULL );
	assert( c != NULL );
	assert( c->c_struct_state != SLAP_C_UNUSED );
	assert( c->c_conn_state != SLAP_C_INVALID );
	assert( LDAP_STAILQ_EMPTY(&c->c_ops) );
808
	assert( c->c_writewaiter == 0);
809

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
810
811
	/* only for stats (print -1 as "%lu" may give unexpected results ;) */
	connid = c->c_connid;
812
	close_reason = c->c_close_reason;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
813

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
814
	backend_connection_destroy(c);
815

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
816
817
	c->c_protocol = 0;
	c->c_connid = -1;
818

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
819
	c->c_activitytime = c->c_starttime = 0;
820

821
	connection2anonymous( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
822
	c->c_listener = NULL;
823

824
825
	if(c->c_peer_domain.bv_val != NULL) {
		free(c->c_peer_domain.bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
826
	}
827
	BER_BVZERO( &c->c_peer_domain );
828
829
	if(c->c_peer_name.bv_val != NULL) {
		free(c->c_peer_name.bv_val);
830
	}
831
	BER_BVZERO( &c->c_peer_name );
832

833
	c->c_sasl_bind_in_progress = 0;
834
835
	if(c->c_sasl_bind_mech.bv_val != NULL) {
		free(c->c_sasl_bind_mech.bv_val);
836
	}
837
	BER_BVZERO( &c->c_sasl_bind_mech );
838
839

	slap_sasl_close( c );
840

Kurt Zeilenga's avatar
Kurt Zeilenga committed
841
842
843
844
845
	if ( c->c_currentber != NULL ) {
		ber_free( c->c_currentber, 1 );
		c->c_currentber = NULL;
	}

846
	ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
847
848
	slapd_sd_lock();
	ber_sockbuf_free( c->c_sb );
849
	if ( sd != AC_SOCKET_INVALID ) {
850
		slapd_remove( sd, 1, 0, 1 );
851

852
853
854
855
		Statslog( LDAP_DEBUG_STATS, (close_reason
									 ? "conn=%lu fd=%ld closed (%s)\n"
									 : "conn=%lu fd=%ld closed\n"),
			connid, (long) sd, close_reason, 0, 0 );
856
857
	} else {
		slapd_sd_unlock();
858
859
	}

860
	c->c_sb = ber_sockbuf_alloc( );
861

862
	{
863
		ber_len_t max = sockbuf_max_incoming;
864
865
866
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
	}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
867
868
	c->c_conn_state = SLAP_C_INVALID;
	c->c_struct_state = SLAP_C_UNUSED;
869
	c->c_close_reason = "?";			/* should never be needed */
870
871
872

#ifdef LDAP_SLAPI
	/* call destructors, then constructors; avoids unnecessary allocation */
873
	if ( slapi_plugins_used ) {
874
		slapi_int_clear_object_extensions( SLAPI_X_EXT_CONNECTION, c );
875
	}
876
#endif
877
878
}

879
880
int connection_state_closing( Connection *c )
{
881
882
	/* c_mutex must be locked by caller */

883
	int state;
884
885
886
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );

887
888
889
890
891
	state = c->c_conn_state;

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
892
893
}

894
895
896
897
static void connection_abandon( Connection *c )
{
	/* c_mutex must be locked by caller */

898
	Operation *o, *next, op = {0};
Howard Chu's avatar
Howard Chu committed
899
	Opheader ohdr = {0};
900
	SlapReply rs = {0};
901

Howard Chu's avatar
Howard Chu committed
902
903
904
	op.o_hdr = &ohdr;
	op.o_conn = c;
	op.o_connid = c->c_connid;
905
906
907
908
	op.o_tag = LDAP_REQ_ABANDON;
	for ( o = LDAP_STAILQ_FIRST( &c->c_ops