connection.c 54.9 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-2006 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
62
63
#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 (round up to a power of 2) */
#	define NUM_CONNECTION_ARRAY 4

/* 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_ARRAY_SIZE			((int)(MCA_conn_array_element_id(dtblsize) + (MCA_conn_array_id(dtblsize) ? 1 : 0)))
#	define MCA_conn_check(fd)		(dtblsize > 0 && (fd) >= 0 && (fd) < (MCA_ARRAY_SIZE*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
64
65
66
/* protected by connections_mutex */
static ldap_pvt_thread_mutex_t connections_mutex;
static Connection *connections = NULL;
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
67

68
69
70
71
72
#	define MCA_conn_check(fd)		(dtblsize > 0 && (fd) < dtblsize)
#	define MCA_GET_CONNECTION(fd) (&connections[s])
#	define MCA_GET_CONN_MUTEX(fd) (&connections_mutex)
#endif

73
static ldap_pvt_thread_mutex_t conn_nextid_mutex;
74
static unsigned long conn_nextid = 0;
75

76
77
static const char conn_lost_str[] = "connection lost";

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

/* connection state (protected by c_mutex ) */
84
85
86
87
88
#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 */
89
#define SLAP_C_CLIENT			0x05	/* outbound client conn */
90

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

	return "?";
}

106
static Connection* connection_get( ber_socket_t s );
107

108
#ifdef SLAP_LIGHTWEIGHT_DISPATCHER
109
110
111
112
113
114
115
116
117

typedef struct conn_readinfo {
	Operation *op;
	ldap_pvt_thread_start_t *func;
	void *arg;
	int nullop;
} conn_readinfo;

static int connection_input( Connection *c, conn_readinfo *cri );
118
#else
119
static int connection_input( Connection *c );
120
#endif
121
static void connection_close( Connection *c );
122

123
static int connection_op_activate( Operation *op );
124
#ifdef SLAP_LIGHTWEIGHT_DISPATCHER
125
126
static void connection_op_queue( Operation *op );
#endif
127
static int connection_resched( Connection *conn );
128
static void connection_abandon( Connection *conn );
129
static void connection_destroy( Connection *c );
130

131
132
static ldap_pvt_thread_start_t connection_operation;

133
134
135
136
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#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 mutexes failed\n", 0, 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(
			MCA_ARRAY_SIZE, 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 < MCA_ARRAY_SIZE; j++ ) {
			conn[j].c_conn_idx = j;
		}
	}

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

	return 0;
}
#else
200
{
201
202
	int i;

203
204
	assert( connections == NULL );

205
	if( connections != NULL) {
206
207
208
209
210
211
212
		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 );
213
	ldap_pvt_thread_mutex_init( &conn_nextid_mutex );
214

215
	connections = (Connection *) ch_calloc( dtblsize, sizeof(Connection) );
216
217

	if( connections == NULL ) {
218
219
		Debug( LDAP_DEBUG_ANY, "connections_init: "
			"allocation (%d*%ld) of connection array failed\n",
220
			dtblsize, (long) sizeof(Connection), 0 );
221
222
223
		return -1;
	}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
224
	assert( connections[0].c_struct_state == SLAP_C_UNINITIALIZED );
225
	assert( connections[dtblsize-1].c_struct_state == SLAP_C_UNINITIALIZED );
226

227
	for (i=0; i<dtblsize; i++) connections[i].c_conn_idx = i;
228

229
230
231
232
233
234
235
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}
236
#endif
237

238
239
240
/*
 * Destroy connection management infrastructure.
 */
241

242
int connections_destroy(void)
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
275
276
277
278
279
280
281
282
283
284
285
286
#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 < MCA_ARRAY_SIZE; 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
				if ( slapi_plugins_used ) {
					slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION,
						&conn[j] );
				}
#endif
			}
		}
	}

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

	free( connections );
	free( connections_mutex );

	ldap_pvt_thread_mutex_destroy( &conn_nextid_mutex );

	return 0;

}
#else
287
{
288
	ber_socket_t i;
289
290
291
292
293
294
295
296
297

	/* should check return of every call */

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

298
	for ( i = 0; i < dtblsize; i++ ) {
299
		if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
300
			ber_sockbuf_free( connections[i].c_sb );
301
302
303
			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 );
304
#ifdef LDAP_SLAPI
305
			if ( slapi_plugins_used ) {
306
307
				slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION,
					&connections[i] );
Howard Chu's avatar
Howard Chu committed
308
			}
309
#endif
310
		}
311
312
313
314
315
316
	}

	free( connections );
	connections = NULL;

	ldap_pvt_thread_mutex_destroy( &connections_mutex );
317
	ldap_pvt_thread_mutex_destroy( &conn_nextid_mutex );
318
319
	return 0;
}
320
#endif
321
322
323
324
325

/*
 * shutdown all connections
 */
int connections_shutdown(void)
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
#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 < MCA_ARRAY_SIZE; 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
359
{
360
	ber_socket_t i;
361

362
363
	ldap_pvt_thread_mutex_lock( &connections_mutex );

364
	for ( i = 0; i < dtblsize; i++ ) {
365
366
367
		if( connections[i].c_struct_state != SLAP_C_USED ) {
			continue;
		}
368
369
		/* give persistent clients a chance to cleanup */
		if( connections[i].c_conn_state == SLAP_C_CLIENT ) {
370
			ldap_pvt_thread_pool_submit( &connection_pool,
371
372
373
			connections[i].c_clientfunc, connections[i].c_clientarg );
			continue;
		}
374
375

		ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
376

377
		/* connections_mutex and c_mutex are locked */
378
		connection_closing( &connections[i], "slapd shutdown" );
379
		connection_close( &connections[i] );
380

381
382
383
		ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
	}

384
385
	ldap_pvt_thread_mutex_unlock( &connections_mutex );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
386
	return 0;
387
}
388
#endif
389

390
391
392
393
394
395
396
397
398
/*
 * Timeout idle connections.
 */
int connections_timeout_idle(time_t now)
{
	int i = 0;
	int connindex;
	Connection* c;

Gary Williams's avatar
Gary Williams committed
399
	for( c = connection_first( &connindex );
400
401
402
		c != NULL;
		c = connection_next( c, &connindex ) )
	{
403
404
		/* Don't timeout a slow-running request or a persistent
		 * outbound connection */
405
406
407
		if( c->c_n_ops_executing || c->c_conn_state == SLAP_C_CLIENT ) {
			continue;
		}
408

409
		if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
410
			/* close it */
411
			connection_closing( c, "idletimeout" );
412
413
414
415
416
417
418
419
420
			connection_close( c );
			i++;
		}
	}
	connection_done( c );

	return i;
}

421
static Connection* connection_get( ber_socket_t s )
422
{
423
424
	/* connections_mutex should be locked by caller */

425
426
427
	Connection *c;

	Debug( LDAP_DEBUG_ARGS,
428
429
		"connection_get(%ld)\n",
		(long) s, 0, 0 );
430
431
432

	assert( connections != NULL );

433
	if(s == AC_SOCKET_INVALID) return NULL;
434
435

#ifndef HAVE_WINSOCK
436
437
	assert( MCA_conn_check( s ) );
	c = MCA_GET_CONNECTION(s);
438

439
#else
440
	c = NULL;
441
	{
442
		ber_socket_t i, sd;
443

444
		for(i=0; i<dtblsize; i++) {
Gary Williams's avatar
NT port    
Gary Williams committed
445
			if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
446
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
447
				assert( connections[i].c_sb == 0 );
448
449
450
				break;
			}

451
452
453
			ber_sockbuf_ctrl( connections[i].c_sb,
				LBER_SB_OPT_GET_FD, &sd );

Gary Williams's avatar
NT port    
Gary Williams committed
454
			if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
455
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
456
				assert( sd == AC_SOCKET_INVALID );
457
458
459
				continue;
			}

460
461
462
			/* state can actually change from used -> unused by resched,
			 * so don't assert details here.
			 */
463

464
			if( sd == s ) {
Gary Williams's avatar
NT port    
Gary Williams committed
465
				c = &connections[i];
466
467
468
469
470
				break;
			}
		}
	}
#endif
471

472
	if( c != NULL ) {
473
474
		ber_socket_t	sd;

Howard Chu's avatar
Cleanup    
Howard Chu committed
475
476
		assert( c->c_struct_state != SLAP_C_UNINITIALIZED );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
477
478
		ldap_pvt_thread_mutex_lock( &c->c_mutex );

479
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
480
481
		if( c->c_struct_state != SLAP_C_USED ) {
			/* connection must have been closed due to resched */
482

483
			assert( c->c_conn_state == SLAP_C_INVALID );
484
			assert( sd == AC_SOCKET_INVALID );
485
486

			Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
487
488
				"connection_get(%d): connection not used\n",
				s, 0, 0 );
489

490
			ldap_pvt_thread_mutex_unlock( &c->c_mutex );
491
492
493
			return NULL;
		}

494
		Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
495
			"connection_get(%d): got connid=%lu\n",
496
			s, c->c_connid, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
497

498
499
		c->c_n_get++;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
500
501
		assert( c->c_struct_state == SLAP_C_USED );
		assert( c->c_conn_state != SLAP_C_INVALID );
502
		assert( sd != AC_SOCKET_INVALID );
503

504
#ifndef SLAPD_MONITOR
505
		if ( global_idletimeout > 0 )
506
507
#endif /* ! SLAPD_MONITOR */
		{
508
509
			c->c_activitytime = slap_get_time();
		}
510
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
511

512
513
514
515
516
517
518
519
520
	return c;
}

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

long connection_init(
521
	ber_socket_t s,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
522
	Listener *listener,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
523
524
	const char* dnsname,
	const char* peername,
525
	int flags,
526
	slap_ssf_t ssf,
527
	struct berval *authid )
528
{
529
	unsigned long id;
530
	Connection *c;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
531

532
533
	assert( connections != NULL );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
534
	assert( listener != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
535
536
537
	assert( dnsname != NULL );
	assert( peername != NULL );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
538
#ifndef HAVE_TLS
539
	assert( flags != CONN_IS_TLS );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
540
541
#endif

542
	if( s == AC_SOCKET_INVALID ) {
Gary Williams's avatar
Gary Williams committed
543
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
544
			"connection_init: init of socket %ld invalid.\n", (long)s, 0, 0 );
545
546
547
548
549
		return -1;
	}

	assert( s >= 0 );
#ifndef HAVE_WINSOCK
550
	assert( s < dtblsize );
551
552
553
554
555
556
557
#endif

	ldap_pvt_thread_mutex_lock( MCA_GET_CONN_MUTEX(s) );

#ifndef HAVE_WINSOCK
	assert( MCA_conn_check( s ) );
	c = MCA_GET_CONNECTION(s);
558
559
#else
	{
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
560
		ber_socket_t i;
561
562
		c = NULL;

563
		for( i=0; i < dtblsize; i++) {
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
564
			ber_socket_t	sd;
565

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
566
567
568
569
570
			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
571

572
			sd = AC_SOCKET_INVALID;
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
573
574
575
576
			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
577

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
578
579
580
581
582
			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
583

584
			if( connections[i].c_conn_state == SLAP_C_CLIENT ) continue;
585

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

601
602
603
	assert( c != NULL );

	if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
604
605
606
607
		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;
608
		c->c_send_ldap_intermediate = slap_send_ldap_intermediate;
609

610
611
612
		BER_BVZERO( &c->c_authmech );
		BER_BVZERO( &c->c_dn );
		BER_BVZERO( &c->c_ndn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
613

Pierangelo Masarati's avatar
Pierangelo Masarati committed
614
		c->c_listener = NULL;
615
616
		BER_BVZERO( &c->c_peer_domain );
		BER_BVZERO( &c->c_peer_name );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
617

618
619
		LDAP_STAILQ_INIT(&c->c_ops);
		LDAP_STAILQ_INIT(&c->c_pending_ops);
620

Kurt Zeilenga's avatar
Kurt Zeilenga committed
621
#ifdef LDAP_X_TXN
Kurt Zeilenga's avatar
Kurt Zeilenga committed
622
		c->c_txn = CONN_TXN_INACTIVE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
623
624
625
626
		c->c_txn_backend = NULL;
		LDAP_STAILQ_INIT(&c->c_txn_ops);
#endif

627
		BER_BVZERO( &c->c_sasl_bind_mech );
628
629
630
		c->c_sasl_done = 0;
		c->c_sasl_authctx = NULL;
		c->c_sasl_sockctx = NULL;
631
		c->c_sasl_extra = NULL;
632
		c->c_sasl_bindop = NULL;
633

634
635
636
		c->c_sb = ber_sockbuf_alloc( );

		{
637
			ber_len_t max = sockbuf_max_incoming;
638
639
640
			ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
641
		c->c_currentber = NULL;
642

643
644
645
646
		/* 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 );
647

648
#ifdef LDAP_SLAPI
649
		if ( slapi_plugins_used ) {
650
			slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, c );
651
		}
652
#endif
653
654

		c->c_struct_state = SLAP_C_UNUSED;
655
	}
656

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

659
	assert( c->c_struct_state == SLAP_C_UNUSED );
660
661
662
	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
663
	assert( c->c_listener == NULL );
664
665
	assert( BER_BVISNULL( &c->c_peer_domain ) );
	assert( BER_BVISNULL( &c->c_peer_name ) );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
666
667
	assert( LDAP_STAILQ_EMPTY(&c->c_ops) );
	assert( LDAP_STAILQ_EMPTY(&c->c_pending_ops) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
668
#ifdef LDAP_X_TXN
Kurt Zeilenga's avatar
Kurt Zeilenga committed
669
	assert( c->c_txn == CONN_TXN_INACTIVE );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
670
671
672
	assert( c->c_txn_backend == NULL );
	assert( LDAP_STAILQ_EMPTY(&c->c_txn_ops) );
#endif
673
	assert( BER_BVISNULL( &c->c_sasl_bind_mech ) );
674
675
676
	assert( c->c_sasl_done == 0 );
	assert( c->c_sasl_authctx == NULL );
	assert( c->c_sasl_sockctx == NULL );
677
	assert( c->c_sasl_extra == NULL );
678
	assert( c->c_sasl_bindop == NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
679
	assert( c->c_currentber == NULL );
680
	assert( c->c_writewaiter == 0);
681

Pierangelo Masarati's avatar
Pierangelo Masarati committed
682
	c->c_listener = listener;
683
684
685
686

	if ( flags == CONN_IS_CLIENT ) {
		c->c_conn_state = SLAP_C_CLIENT;
		c->c_struct_state = SLAP_C_USED;
687
		c->c_close_reason = "?";			/* should never be needed */
688
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s );
689
		ldap_pvt_thread_mutex_unlock( &c->c_mutex );
690
		ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) );
691
692
693
694

		return 0;
	}

695
696
	ber_str2bv( dnsname, 0, 1, &c->c_peer_domain );
	ber_str2bv( peername, 0, 1, &c->c_peer_name );
697

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
698
699
700
701
	c->c_n_ops_received = 0;
	c->c_n_ops_executing = 0;
	c->c_n_ops_pending = 0;
	c->c_n_ops_completed = 0;
702
703
704
705

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

707
708
	/* set to zero until bind, implies LDAP_VERSION3 */
	c->c_protocol = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
709

710
#ifndef SLAPD_MONITOR
711
	if ( global_idletimeout > 0 )
712
713
#endif /* ! SLAPD_MONITOR */
	{
714
715
		c->c_activitytime = c->c_starttime = slap_get_time();
	}
716

717
718
#ifdef LDAP_CONNECTIONLESS
	c->c_is_udp = 0;
719
	if( flags == CONN_IS_UDP ) {
720
721
		c->c_is_udp = 1;
#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*)"udp_" );
724
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
725
726
727
728
		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 );
729
730
731
	} else
#endif
	{
732
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
733
734
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_PROVIDER, (void*)"tcp_" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
735
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
736
737
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp,
			LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
738
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
739
740
741
742

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
745
746
747
748
749
	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
750
			s, c->c_peer_name.bv_val, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
751
	}
752

753
	ldap_pvt_thread_mutex_lock( &conn_nextid_mutex );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
754
	id = c->c_connid = conn_nextid++;
755
	ldap_pvt_thread_mutex_unlock( &conn_nextid_mutex );
756

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
757
758
	c->c_conn_state = SLAP_C_INACTIVE;
	c->c_struct_state = SLAP_C_USED;
759
	c->c_close_reason = "?";			/* should never be needed */
760

761
762
763
	c->c_ssf = c->c_transport_ssf = ssf;
	c->c_tls_ssf = 0;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
764
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
765
766
767
768
769
770
771
	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
772
#endif
773

774
	slap_sasl_open( c, 0 );
775
	slap_sasl_external( c, ssf, authid );
776

777
	slapd_add_internal( s, 1 );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
778
	ldap_pvt_thread_mutex_unlock( &c->c_mutex );
779
	ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) );
780

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
781
	backend_connection_init(c);
782

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
783
	return id;
784
785
}

786
787
void connection2anonymous( Connection *c )
{
788
789
	assert( connections != NULL );
	assert( c != NULL );
790

791
	{
792
		ber_len_t max = sockbuf_max_incoming;
793
794
795
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
	}

796
	if ( !BER_BVISNULL( &c->c_authmech ) ) {
797
		ch_free(c->c_authmech.bv_val);
798
	}
799
	BER_BVZERO( &c->c_authmech );
800

801
	if ( !BER_BVISNULL( &c->c_dn ) ) {
802
		ch_free(c->c_dn.bv_val);
803
	}
804
	BER_BVZERO( &c->c_dn );
805

806
	if ( !BER_BVISNULL( &c->c_ndn ) ) {
807
		ch_free(c->c_ndn.bv_val);
808
	}
809
	BER_BVZERO( &c->c_ndn );
810

811
812
	if ( !BER_BVISNULL( &c->c_sasl_authz_dn ) ) {
		ber_memfree_x( c->c_sasl_authz_dn.bv_val, NULL );
813
814
	}
	BER_BVZERO( &c->c_sasl_authz_dn );
815
816
817
818

	c->c_authz_backend = NULL;
}

819
820
821
static void
connection_destroy( Connection *c )
{
822
	/* note: connections_mutex should be locked by caller */
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
823
824
	ber_socket_t	sd;
	unsigned long	connid;
825
	const char		*close_reason;
826

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
827
828
829
830
831
	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) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
832
833
834
835
836
837
	assert( LDAP_STAILQ_EMPTY(&c->c_pending_ops) );
#ifdef LDAP_X_TXN
	assert( c->c_txn == CONN_TXN_INACTIVE );
	assert( c->c_txn_backend == NULL );
	assert( LDAP_STAILQ_EMPTY(&c->c_txn_ops) );
#endif
838
	assert( c->c_writewaiter == 0);
839

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

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
844
	backend_connection_destroy(c);
845

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
846
847
	c->c_protocol = 0;
	c->c_connid = -1;
848

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
849
	c->c_activitytime = c->c_starttime = 0;
850

851
	connection2anonymous( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
852
	c->c_listener = NULL;
853

854
855
	if(c->c_peer_domain.bv_val != NULL) {
		free(c->c_peer_domain.bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
856
	}
857
	BER_BVZERO( &c->c_peer_domain );
858
859
	if(c->c_peer_name.bv_val != NULL) {
		free(c->c_peer_name.bv_val);
860
	}
861
	BER_BVZERO( &c->c_peer_name );
862

863
	c->c_sasl_bind_in_progress = 0;
864
865
	if(c->c_sasl_bind_mech.bv_val != NULL) {
		free(c->c_sasl_bind_mech.bv_val);
866
	}
867
	BER_BVZERO( &c->c_sasl_bind_mech );
868
869

	slap_sasl_close( c );
870

Kurt Zeilenga's avatar
Kurt Zeilenga committed
871
872
873
874
875
	if ( c->c_currentber != NULL ) {
		ber_free( c->c_currentber, 1 );
		c->c_currentber = NULL;
	}

876
	ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
877
878
	slapd_sd_lock();
	ber_sockbuf_free( c->c_sb );
879
	if ( sd != AC_SOCKET_INVALID ) {
880
		slapd_remove( sd, 1, 0, 1 );
881

882
883
884
885
		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 );
886
887
	} else {
		slapd_sd_unlock();
888
889
	}

890
	c->c_sb = ber_sockbuf_alloc( );
891

892
	{
893
		ber_len_t max = sockbuf_max_incoming;
894
895
896
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
	}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
897
898
	c->c_conn_state = SLAP_C_INVALID;
	c->c_struct_state = SLAP_C_UNUSED;
899
	c->c_close_reason = "?";			/* should never be needed */
900
901
902

#ifdef LDAP_SLAPI
	/* call destructors, then constructors; avoids unnecessary allocation */
903
	if ( slapi_plugins_used ) {
904
		slapi_int_clear_object_extensions( SLAPI_X_EXT_CONNECTION, c );
905
	}
906
#endif
907
908
}

909
910
int connection_state_closing( Connection *c )
{
911
912
	/* c_mutex must be locked by caller */

913
	int state;
914
915
916
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );

917
918
919
920
921
	state = c->c_conn_state;

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
922
923
}

924
925
926
927
static void connection_abandon( Connection *c )
{
	/* c_mutex must be locked by caller */

928
	Operation *o, *next, op = {0};
Howard Chu's avatar
Howard Chu committed
929
	Opheader ohdr = {0};
930
	SlapReply rs = {0};
931

Howard Chu's avatar
Howard Chu committed
932
933
934
	op.o_hdr = &ohdr;
	op.o_conn = c;
	op.o_connid = c->c_connid;
935
	op.o_tag = LDAP_REQ_ABANDON;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
936

937
938
939
	for ( o = LDAP_STAILQ_FIRST( &c->c_ops ); o; o=next ) {
		next = LDAP_STAILQ_NEXT( o, o_next );
		op.orn_msgid = o->o_msgid;
940
		o->o_abandon = 1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
941
		op.o_bd = frontendDB;
942
		frontendDB->be_abandon( &op, &rs );
943
944