connection.c 52.6 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
52
53
54
55
56
57
58
59
60
61

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

/* set to the number of processors */
#define NUM_CONNECTION_ARRAY 2

/* partition the array in a modulo manner */
#define MCA_conn_array_id( fd ) ((int)fd%NUM_CONNECTION_ARRAY)
#define MCA_conn_array_element_id( fd ) ((int)fd/NUM_CONNECTION_ARRAY)

#define MCA_GET_CONNECTION(fd) &(connections[MCA_conn_array_id(fd)])[MCA_conn_array_element_id( fd )]
#define MCA_GET_CONN_MUTEX(fd) &connections_mutex[MCA_conn_array_id(fd)]
#else
62
63
64
/* protected by connections_mutex */
static ldap_pvt_thread_mutex_t connections_mutex;
static Connection *connections = NULL;
65
#endif
66
67

static ldap_pvt_thread_mutex_t conn_nextid_mutex;
68
static unsigned long conn_nextid = 0;
69

70
71
static const char conn_lost_str[] = "connection lost";

72
/* structure state (protected by connections_mutex) */
73
74
75
#define SLAP_C_UNINITIALIZED	0x00	/* MUST BE ZERO (0) */
#define SLAP_C_UNUSED			0x01
#define SLAP_C_USED				0x02
76
77

/* connection state (protected by c_mutex ) */
78
79
80
81
82
#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 */
83
#define SLAP_C_CLIENT			0x05	/* outbound client conn */
84

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

	return "?";
}

100
static Connection* connection_get( ber_socket_t s );
101

102
103
104
#ifdef SLAP_LIGHTWEIGHT_LISTENER
static int connection_input( Connection *c, Operation** op );
#else
105
static int connection_input( Connection *c );
106
#endif
107
static void connection_close( Connection *c );
108

109
static int connection_op_activate( Operation *op );
110
111
112
#ifdef SLAP_LIGHTWEIGHT_LISTENER
static void connection_op_queue( Operation *op );
#endif
113
static int connection_resched( Connection *conn );
114
static void connection_abandon( Connection *conn );
115
static void connection_destroy( Connection *c );
116

117
118
static ldap_pvt_thread_start_t connection_operation;

119
120
121
122
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#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;
	}

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

	connections = (Connection**) ch_calloc( NUM_CONNECTION_ARRAY, sizeof(Connection*));
	if( connections == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"connections_init: allocation of connection[%d] failed\n", 0, 0, 0 );
		return -1;
	}

	for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) {
		ldap_pvt_thread_mutex_init( connections_mutex+i );
		connections[i] = (Connection*) ch_calloc( (dtblsize/NUM_CONNECTION_ARRAY), sizeof(Connection) );
		if( connections[i] == NULL ) {
			Debug( LDAP_DEBUG_ANY,
				"connections_init: allocation (%d*%ld) of connection array[%d] failed\n",
				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 );
	assert( connections[NUM_CONNECTION_ARRAY-1]->c_struct_state == SLAP_C_UNINITIALIZED );

	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
182
{
183
184
	int i;

185
186
	assert( connections == NULL );

187
	if( connections != NULL) {
188
189
190
191
192
193
194
		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 );
195
	ldap_pvt_thread_mutex_init( &conn_nextid_mutex );
196

197
	connections = (Connection *) ch_calloc( dtblsize, sizeof(Connection) );
198
199
200

	if( connections == NULL ) {
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
201
			"connections_init: allocation (%d*%ld) of connection array failed\n",
202
			dtblsize, (long) sizeof(Connection), 0 );
203
204
205
		return -1;
	}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
206
	assert( connections[0].c_struct_state == SLAP_C_UNINITIALIZED );
207
	assert( connections[dtblsize-1].c_struct_state == SLAP_C_UNINITIALIZED );
208

209
	for (i=0; i<dtblsize; i++) connections[i].c_conn_idx = i;
210

211
212
213
214
215
216
217
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}
218
#endif
219

220
221
222
/*
 * Destroy connection management infrastructure.
 */
223

224
int connections_destroy(void)
225
226
227
228
229
230
231
232
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
#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
267
{
268
	ber_socket_t i;
269
270
271
272
273
274
275
276
277

	/* should check return of every call */

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

278
	for ( i = 0; i < dtblsize; i++ ) {
279
		if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
280
			ber_sockbuf_free( connections[i].c_sb );
281
282
283
			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 );
284
#ifdef LDAP_SLAPI
285
			if ( slapi_plugins_used ) {
286
287
				slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION,
					&connections[i] );
Howard Chu's avatar
Howard Chu committed
288
			}
289
#endif
290
		}
291
292
293
294
295
296
	}

	free( connections );
	connections = NULL;

	ldap_pvt_thread_mutex_destroy( &connections_mutex );
297
	ldap_pvt_thread_mutex_destroy( &conn_nextid_mutex );
298
299
	return 0;
}
300
#endif
301
302
303
304
305

/*
 * shutdown all connections
 */
int connections_shutdown(void)
306
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
#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
339
{
340
	ber_socket_t i;
341
342
343

	ldap_pvt_thread_mutex_lock( &connections_mutex );

344
	for ( i = 0; i < dtblsize; i++ ) {
345
346
347
		if( connections[i].c_struct_state != SLAP_C_USED ) {
			continue;
		}
348
349
		/* give persistent clients a chance to cleanup */
		if( connections[i].c_conn_state == SLAP_C_CLIENT ) {
350
			ldap_pvt_thread_pool_submit( &connection_pool,
351
352
353
			connections[i].c_clientfunc, connections[i].c_clientarg );
			continue;
		}
354
355

		ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
356
357

		/* connections_mutex and c_mutex are locked */
358
		connection_closing( &connections[i], "slapd shutdown" );
359
		connection_close( &connections[i] );
360

361
362
363
364
		ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
	}

	ldap_pvt_thread_mutex_unlock( &connections_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
365
366

	return 0;
367
}
368
#endif
369

370
371
372
373
374
375
376
377
378
/*
 * Timeout idle connections.
 */
int connections_timeout_idle(time_t now)
{
	int i = 0;
	int connindex;
	Connection* c;

Gary Williams's avatar
Gary Williams committed
379
	for( c = connection_first( &connindex );
380
381
382
		c != NULL;
		c = connection_next( c, &connindex ) )
	{
383
384
385
386
		/* Don't timeout a slow-running request or a persistent
		 * outbound connection */
		if( c->c_n_ops_executing ||
			c->c_conn_state == SLAP_C_CLIENT ) continue;
387

388
		if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
389
			/* close it */
390
			connection_closing( c, "idletimeout" );
391
392
393
394
395
396
397
398
399
			connection_close( c );
			i++;
		}
	}
	connection_done( c );

	return i;
}

400
static Connection* connection_get( ber_socket_t s )
401
{
402
403
	/* connections_mutex should be locked by caller */

404
405
406
	Connection *c;

	Debug( LDAP_DEBUG_ARGS,
407
408
		"connection_get(%ld)\n",
		(long) s, 0, 0 );
409
410
411

	assert( connections != NULL );

412
	if(s == AC_SOCKET_INVALID) {
413
414
415
416
		return NULL;
	}

#ifndef HAVE_WINSOCK
417
418
419
#ifdef SLAP_MULTI_CONN_ARRAY
	c = MCA_GET_CONNECTION(s);
#else
420
	c = &connections[s];
421
#endif
422

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

425
#else
426
	c = NULL;
427
	{
428
		ber_socket_t i, sd;
429

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

437
438
439
			ber_sockbuf_ctrl( connections[i].c_sb,
				LBER_SB_OPT_GET_FD, &sd );

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

446
447
448
			/* state can actually change from used -> unused by resched,
			 * so don't assert details here.
			 */
449

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

458
	if( c != NULL ) {
459
460
		ber_socket_t	sd;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
461
462
		ldap_pvt_thread_mutex_lock( &c->c_mutex );

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

467
			assert( c->c_conn_state == SLAP_C_INVALID );
468
			assert( sd == AC_SOCKET_INVALID );
469
470

			Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
471
472
				"connection_get(%d): connection not used\n",
				s, 0, 0 );
473

474
			ldap_pvt_thread_mutex_unlock( &c->c_mutex );
475
476
477
			return NULL;
		}

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

482
483
		c->c_n_get++;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
484
485
		assert( c->c_struct_state == SLAP_C_USED );
		assert( c->c_conn_state != SLAP_C_INVALID );
486
		assert( sd != AC_SOCKET_INVALID );
487

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

496
497
498
499
500
501
502
503
504
	return c;
}

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

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

516
517
	assert( connections != NULL );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
518
	assert( listener != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
519
520
521
	assert( dnsname != NULL );
	assert( peername != NULL );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
522
#ifndef HAVE_TLS
523
	assert( flags != CONN_IS_TLS );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
524
525
#endif

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

	assert( s >= 0 );
#ifndef HAVE_WINSOCK
534
	assert( s < dtblsize );
535
536
#endif

537
538
539
#ifdef SLAP_MULTI_CONN_ARRAY
	ldap_pvt_thread_mutex_lock( MCA_GET_CONN_MUTEX(s) );
#else
540
	ldap_pvt_thread_mutex_lock( &connections_mutex );
541
#endif
542
543

#ifndef HAVE_WINSOCK
544
545
546
#ifdef SLAP_MULTI_CONN_ARRAY
	c = MCA_GET_CONNECTION(s);
#else
547
	c = &connections[s];
548
#endif
549
550
551

#else
	{
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
552
		ber_socket_t i;
553
554
		c = NULL;

555
		for( i=0; i < dtblsize; i++) {
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
556
			ber_socket_t	sd;
557

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
558
559
560
561
562
			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
563

564
			sd = AC_SOCKET_INVALID;
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
565
566
567
568
			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
569

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
570
571
572
573
574
			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
575

576
577
578
579
			if( connections[i].c_conn_state == SLAP_C_CLIENT ) {
				continue;
			}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
580
581
582
583
584
585
586
			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,
587
				"connection_init(%d): connection table full "
588
				"(%d/%d)\n", s, i, dtblsize);
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
589
590
591
			ldap_pvt_thread_mutex_unlock( &connections_mutex );
			return -1;
		}
Gary Williams's avatar
Gary Williams committed
592
	}
593
594
#endif

595
	assert( c != NULL );
596

597
	if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
598
599
600
601
		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;
602
603
#ifdef LDAP_RES_INTERMEDIATE
		c->c_send_ldap_intermediate = slap_send_ldap_intermediate;
604
#endif
605

606
607
608
		BER_BVZERO( &c->c_authmech );
		BER_BVZERO( &c->c_dn );
		BER_BVZERO( &c->c_ndn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
609

Pierangelo Masarati's avatar
Pierangelo Masarati committed
610
		c->c_listener = NULL;
611
612
		BER_BVZERO( &c->c_peer_domain );
		BER_BVZERO( &c->c_peer_name );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
613

614
615
		LDAP_STAILQ_INIT(&c->c_ops);
		LDAP_STAILQ_INIT(&c->c_pending_ops);
616

617
		BER_BVZERO( &c->c_sasl_bind_mech );
618
619
620
		c->c_sasl_done = 0;
		c->c_sasl_authctx = NULL;
		c->c_sasl_sockctx = NULL;
621
		c->c_sasl_extra = NULL;
622
		c->c_sasl_bindop = NULL;
623

624
625
626
		c->c_sb = ber_sockbuf_alloc( );

		{
627
			ber_len_t max = sockbuf_max_incoming;
628
629
630
			ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
631
		c->c_currentber = NULL;
632

633
634
635
636
		/* 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 );
637

638
#ifdef LDAP_SLAPI
639
		if ( slapi_plugins_used ) {
640
			slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, c );
641
		}
642
643
#endif

644
645
		c->c_struct_state = SLAP_C_UNUSED;
	}
646

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

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
649
	assert( c->c_struct_state == SLAP_C_UNUSED );
650
651
652
	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
653
	assert( c->c_listener == NULL );
654
655
	assert( BER_BVISNULL( &c->c_peer_domain ) );
	assert( BER_BVISNULL( &c->c_peer_name ) );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
656
657
	assert( LDAP_STAILQ_EMPTY(&c->c_ops) );
	assert( LDAP_STAILQ_EMPTY(&c->c_pending_ops) );
658
	assert( BER_BVISNULL( &c->c_sasl_bind_mech ) );
659
660
661
	assert( c->c_sasl_done == 0 );
	assert( c->c_sasl_authctx == NULL );
	assert( c->c_sasl_sockctx == NULL );
662
	assert( c->c_sasl_extra == NULL );
663
	assert( c->c_sasl_bindop == NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
664
	assert( c->c_currentber == NULL );
665
	assert( c->c_writewaiter == 0);
666

Pierangelo Masarati's avatar
Pierangelo Masarati committed
667
	c->c_listener = listener;
668
669
670
671

	if ( flags == CONN_IS_CLIENT ) {
		c->c_conn_state = SLAP_C_CLIENT;
		c->c_struct_state = SLAP_C_USED;
672
		c->c_close_reason = "?";			/* should never be needed */
673
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s );
674
		ldap_pvt_thread_mutex_unlock( &c->c_mutex );
675
676
677
#ifdef SLAP_MULTI_CONN_ARRAY
		ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) );
#else
678
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
679
#endif
680
681
682
683

		return 0;
	}

684
685
	ber_str2bv( dnsname, 0, 1, &c->c_peer_domain );
	ber_str2bv( peername, 0, 1, &c->c_peer_name );
686

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
687
688
689
690
	c->c_n_ops_received = 0;
	c->c_n_ops_executing = 0;
	c->c_n_ops_pending = 0;
	c->c_n_ops_completed = 0;
691
692
693
694

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

696
697
	/* set to zero until bind, implies LDAP_VERSION3 */
	c->c_protocol = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
698

699
#ifndef SLAPD_MONITOR
700
	if ( global_idletimeout > 0 )
701
702
#endif /* ! SLAPD_MONITOR */
	{
703
704
		c->c_activitytime = c->c_starttime = slap_get_time();
	}
705

706
707
#ifdef LDAP_CONNECTIONLESS
	c->c_is_udp = 0;
708
	if( flags == CONN_IS_UDP ) {
709
710
		c->c_is_udp = 1;
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
711
712
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_PROVIDER, (void*)"udp_" );
713
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
714
715
716
717
		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 );
718
719
720
	} else
#endif
	{
721
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
722
723
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_PROVIDER, (void*)"tcp_" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
724
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
725
726
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp,
			LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
727
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
728
729
730
731

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
734
735
736
737
738
	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
739
			s, c->c_peer_name.bv_val, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
740
	}
741

742
	ldap_pvt_thread_mutex_lock( &conn_nextid_mutex );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
743
	id = c->c_connid = conn_nextid++;
744
	ldap_pvt_thread_mutex_unlock( &conn_nextid_mutex );
745

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
746
747
	c->c_conn_state = SLAP_C_INACTIVE;
	c->c_struct_state = SLAP_C_USED;
748
	c->c_close_reason = "?";			/* should never be needed */
749

750
751
752
	c->c_ssf = c->c_transport_ssf = ssf;
	c->c_tls_ssf = 0;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
753
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
754
755
756
757
758
759
760
	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
761
#endif
762

763
	slap_sasl_open( c, 0 );
764
	slap_sasl_external( c, ssf, authid );
765

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
766
	ldap_pvt_thread_mutex_unlock( &c->c_mutex );
767
768
769
#ifdef SLAP_MULTI_CONN_ARRAY
	ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) );
#else
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
770
	ldap_pvt_thread_mutex_unlock( &connections_mutex );
771
#endif
772

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
773
	backend_connection_init(c);
774

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
775
	return id;
776
777
}

778
779
void connection2anonymous( Connection *c )
{
780
781
	assert( connections != NULL );
	assert( c != NULL );
782

783
	{
784
		ber_len_t max = sockbuf_max_incoming;
785
786
787
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
	}

788
	if ( !BER_BVISNULL( &c->c_authmech ) ) {
789
		ch_free(c->c_authmech.bv_val);
790
	}
791
	BER_BVZERO( &c->c_authmech );
792

793
	if ( !BER_BVISNULL( &c->c_dn ) ) {
794
		ch_free(c->c_dn.bv_val);
795
	}
796
	BER_BVZERO( &c->c_dn );
797

798
	if ( !BER_BVISNULL( &c->c_ndn ) ) {
799
		ch_free(c->c_ndn.bv_val);
800
	}
801
	BER_BVZERO( &c->c_ndn );
802

803
804
	if ( !BER_BVISNULL( &c->c_sasl_authz_dn ) ) {
		ber_memfree_x( c->c_sasl_authz_dn.bv_val, NULL );
805
806
	}
	BER_BVZERO( &c->c_sasl_authz_dn );
807
808
809
810

	c->c_authz_backend = NULL;
}

811
812
813
static void
connection_destroy( Connection *c )
{
814
	/* note: connections_mutex should be locked by caller */
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
815
816
	ber_socket_t	sd;
	unsigned long	connid;
817
	const char		*close_reason;
818

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
819
820
821
822
823
	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) );
824
	assert( c->c_writewaiter == 0);
825

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

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
830
	backend_connection_destroy(c);
831

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
832
833
	c->c_protocol = 0;
	c->c_connid = -1;
834

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
835
	c->c_activitytime = c->c_starttime = 0;
836

837
	connection2anonymous( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
838
	c->c_listener = NULL;
839

840
841
	if(c->c_peer_domain.bv_val != NULL) {
		free(c->c_peer_domain.bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
842
	}
843
	BER_BVZERO( &c->c_peer_domain );
844
845
	if(c->c_peer_name.bv_val != NULL) {
		free(c->c_peer_name.bv_val);
846
	}
847
	BER_BVZERO( &c->c_peer_name );
848

849
	c->c_sasl_bind_in_progress = 0;
850
851
	if(c->c_sasl_bind_mech.bv_val != NULL) {
		free(c->c_sasl_bind_mech.bv_val);
852
	}
853
	BER_BVZERO( &c->c_sasl_bind_mech );
854
855

	slap_sasl_close( c );
856

Kurt Zeilenga's avatar
Kurt Zeilenga committed
857
858
859
860
861
	if ( c->c_currentber != NULL ) {
		ber_free( c->c_currentber, 1 );
		c->c_currentber = NULL;
	}

862
863
	ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
	if ( sd != AC_SOCKET_INVALID ) {
864
		slapd_remove( sd, 1, 0 );
865

866
867
868
869
		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 );
870
871
	}

Gary Williams's avatar
Gary Williams committed
872
	ber_sockbuf_free( c->c_sb );
873

874
	c->c_sb = ber_sockbuf_alloc( );
875

876
	{
877
		ber_len_t max = sockbuf_max_incoming;
878
879
880
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
	}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
881
882
	c->c_conn_state = SLAP_C_INVALID;
	c->c_struct_state = SLAP_C_UNUSED;
883
	c->c_close_reason = "?";			/* should never be needed */
884
885
886

#ifdef LDAP_SLAPI
	/* call destructors, then constructors; avoids unnecessary allocation */
887
	if ( slapi_plugins_used ) {
888
		slapi_int_clear_object_extensions( SLAPI_X_EXT_CONNECTION, c );
889
	}
890
#endif
891
892
}

893
894
int connection_state_closing( Connection *c )
{
895
896
	/* c_mutex must be locked by caller */

897
	int state;
898
899
900
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );

901
902
903
904
905
	state = c->c_conn_state;

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
906
907
}

908
909
910
911
static void connection_abandon( Connection *c )
{
	/* c_mutex must be locked by caller */

912
	Operation *o, *next, op = {0};
Howard Chu's avatar
Howard Chu committed
913
	Opheader ohdr = {0};
914
	SlapReply rs = {0};
915

Howard Chu's avatar
Howard Chu committed
916
917
918
	op.o_hdr = &ohdr;
	op.o_conn = c;
	op.o_connid = c->c_connid;
919
920
921
922
	op.o_tag = LDAP_REQ_ABANDON;
	for ( o = LDAP_STAILQ_FIRST( &c->c_ops ); o; o=next ) {
		next = LDAP_STAILQ_NEXT( o, o_next );
		op.orn_msgid = o->o_msgid;
923
		o->o_abandon = 1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
924
		op.o_bd = frontendDB;
925
		frontendDB->be_abandon( &op, &rs );
926
927
928
	}

	/* remove pending operations */
929
930
931
	while ( (o = LDAP_STAILQ_FIRST( &c->c_pending_ops )) != NULL) {
		LDAP_STAILQ_REMOVE_HEAD( &c->c_pending_ops, o_next );
		LDAP_STAILQ_NEXT(o, o_next) = NULL;
932
933
934
935
		slap_op_free( o );
	}
}

936
void connection_closing( Connection *c, const char *why )
937
938
939
940
941
942
{
	assert( connections != NULL );
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );
	assert( c->c_conn_state != SLAP_C_INVALID );

943
944
	/* c_mutex must be locked by caller */