connection.c 51.2 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

#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 */
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
58
59
60
#	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)])
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
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
182
183
184
185
#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
186
{
187
188
	int i;

189
190
	assert( connections == NULL );

191
	if( connections != NULL) {
192
193
194
195
196
197
198
		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 );
199
	ldap_pvt_thread_mutex_init( &conn_nextid_mutex );
200

201
	connections = (Connection *) ch_calloc( dtblsize, sizeof(Connection) );
202
203
204

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

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
210
	assert( connections[0].c_struct_state == SLAP_C_UNINITIALIZED );
211
	assert( connections[dtblsize-1].c_struct_state == SLAP_C_UNINITIALIZED );
212

213
	for (i=0; i<dtblsize; i++) connections[i].c_conn_idx = i;
214

215
216
217
218
219
220
221
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}
222
#endif
223

224
225
226
/*
 * Destroy connection management infrastructure.
 */
227

228
int connections_destroy(void)
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
267
268
269
270
#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
271
{
272
	ber_socket_t i;
273
274
275
276
277
278
279
280
281

	/* should check return of every call */

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

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

	free( connections );
	connections = NULL;

	ldap_pvt_thread_mutex_destroy( &connections_mutex );
301
	ldap_pvt_thread_mutex_destroy( &conn_nextid_mutex );
302
303
	return 0;
}
304
#endif
305
306
307
308
309

/*
 * shutdown all connections
 */
int connections_shutdown(void)
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
#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
343
{
344
	ber_socket_t i;
345
346
347

	ldap_pvt_thread_mutex_lock( &connections_mutex );

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

		ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
360
361

		/* connections_mutex and c_mutex are locked */
362
		connection_closing( &connections[i], "slapd shutdown" );
363
		connection_close( &connections[i] );
364

365
366
367
368
		ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
	}

	ldap_pvt_thread_mutex_unlock( &connections_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
369
370

	return 0;
371
}
372
#endif
373

374
375
376
377
378
379
380
381
382
/*
 * Timeout idle connections.
 */
int connections_timeout_idle(time_t now)
{
	int i = 0;
	int connindex;
	Connection* c;

Gary Williams's avatar
Gary Williams committed
383
	for( c = connection_first( &connindex );
384
385
386
		c != NULL;
		c = connection_next( c, &connindex ) )
	{
387
388
389
390
		/* 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;
391

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

	return i;
}

404
static Connection* connection_get( ber_socket_t s )
405
{
406
407
	/* connections_mutex should be locked by caller */

408
409
410
	Connection *c;

	Debug( LDAP_DEBUG_ARGS,
411
412
		"connection_get(%ld)\n",
		(long) s, 0, 0 );
413
414
415

	assert( connections != NULL );

416
	if(s == AC_SOCKET_INVALID) {
417
418
419
420
		return NULL;
	}

#ifndef HAVE_WINSOCK
421
	c = MCA_GET_CONNECTION(s);
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
	ldap_pvt_thread_mutex_lock( MCA_GET_CONN_MUTEX(s) );
538
539

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

546
		for( i=0; i < dtblsize; i++) {
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
547
			ber_socket_t	sd;
548

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
549
550
551
552
553
			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
554

555
			sd = AC_SOCKET_INVALID;
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
556
557
558
559
			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
560

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
561
562
563
564
565
			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
566

567
568
569
570
			if( connections[i].c_conn_state == SLAP_C_CLIENT ) {
				continue;
			}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
571
572
573
574
575
576
577
			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,
578
				"connection_init(%d): connection table full "
579
				"(%d/%d)\n", s, i, dtblsize);
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
580
581
582
			ldap_pvt_thread_mutex_unlock( &connections_mutex );
			return -1;
		}
Gary Williams's avatar
Gary Williams committed
583
	}
584
585
#endif

586
	assert( c != NULL );
587

588
	if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
589
590
591
592
		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;
593
594
#ifdef LDAP_RES_INTERMEDIATE
		c->c_send_ldap_intermediate = slap_send_ldap_intermediate;
595
#endif
596

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

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

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

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

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

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

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

624
625
626
627
		/* 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 );
628

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

635
636
		c->c_struct_state = SLAP_C_UNUSED;
	}
637

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

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

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

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

		return 0;
	}

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

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

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

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

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

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
721
722
723
724
725
	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
726
			s, c->c_peer_name.bv_val, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
727
	}
728

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

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
740
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
741
742
743
744
745
746
747
	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
748
#endif
749

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

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

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

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

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

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

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

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

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

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

	c->c_authz_backend = NULL;
}

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

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
802
803
804
805
806
	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) );
807
	assert( c->c_writewaiter == 0);
808

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

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

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

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

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

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

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

	slap_sasl_close( c );
839

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

845
846
	ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
	if ( sd != AC_SOCKET_INVALID ) {
847
		slapd_remove( sd, 1, 0 );
848

849
850
851
852
		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 );
853
854
	}

Gary Williams's avatar
Gary Williams committed
855
	ber_sockbuf_free( c->c_sb );
856

857
	c->c_sb = ber_sockbuf_alloc( );
858

859
	{
860
		ber_len_t max = sockbuf_max_incoming;
861
862
863
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
	}

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

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

876
877
int connection_state_closing( Connection *c )
{
878
879
	/* c_mutex must be locked by caller */

880
	int state;
881
882
883
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );

884
885
886
887
888
	state = c->c_conn_state;

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
889
890
}

891
892
893
894
static void connection_abandon( Connection *c )
{
	/* c_mutex must be locked by caller */

895
	Operation *o, *next, op = {0};
Howard Chu's avatar
Howard Chu committed
896
	Opheader ohdr = {0};
897
	SlapReply rs = {0};
898

Howard Chu's avatar
Howard Chu committed
899
900
901
	op.o_hdr = &ohdr;
	op.o_conn = c;
	op.o_connid = c->c_connid;
902
903
904
905
	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;
906
		o->o_abandon = 1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
907
		op.o_bd = frontendDB;
908
		frontendDB->be_abandon( &op, &rs );
909
910
911
	}

	/* remove pending operations */
912
913
914
	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;
915
916
917
918
		slap_op_free( o );
	}
}

919
void connection_closing( Connection *c, const char *why )
920
921
922
923
924
925
{
	assert( connections != NULL );
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );
	assert( c->c_conn_state != SLAP_C_INVALID );

926
927
	/* c_mutex must be locked by caller */

928
	if( c->c_conn_state != SLAP_C_CLOSING ) {
929
930
931
		ber_socket_t	sd;

		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
932
		Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
933
			"connection_closing: readying conn=%lu sd=%d for close\n",