connection.c 41.1 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-2004 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
#include <limits.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
30

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
37
#include "ldap_pvt.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
38
#include "lutil.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
39
40
#include "slap.h"

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

45
46
47
/* protected by connections_mutex */
static ldap_pvt_thread_mutex_t connections_mutex;
static Connection *connections = NULL;
48
49

static ldap_pvt_thread_mutex_t conn_nextid_mutex;
50
static unsigned long conn_nextid = 0;
51

52
/* structure state (protected by connections_mutex) */
53
54
55
#define SLAP_C_UNINITIALIZED	0x00	/* MUST BE ZERO (0) */
#define SLAP_C_UNUSED			0x01
#define SLAP_C_USED				0x02
56
57

/* connection state (protected by c_mutex ) */
58
59
60
61
62
#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 */
63
#define SLAP_C_CLIENT			0x05	/* outbound client conn */
64

65
66
67
const char *
connection_state2str( int state )
{
68
	switch( state ) {
69
70
71
	case SLAP_C_INVALID:	return "!";
	case SLAP_C_INACTIVE:	return "|";
	case SLAP_C_ACTIVE:		return "";
72
	case SLAP_C_BINDING:	return "B";
73
74
	case SLAP_C_CLOSING:	return "C";
	case SLAP_C_CLIENT:		return "L";
75
76
77
78
79
	}

	return "?";
}

80
static Connection* connection_get( ber_socket_t s );
81
82

static int connection_input( Connection *c );
83
static void connection_close( Connection *c );
84

85
static int connection_op_activate( Operation *op );
86
static int connection_resched( Connection *conn );
87
static void connection_abandon( Connection *conn );
88
static void connection_destroy( Connection *c );
89

90
91
static ldap_pvt_thread_start_t connection_operation;

92
93
94
95
96
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
{
97
98
	int i;

99
100
	assert( connections == NULL );

101
	if( connections != NULL) {
102
103
104
105
106
107
108
		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 );
109
	ldap_pvt_thread_mutex_init( &conn_nextid_mutex );
110

Howard Chu's avatar
Howard Chu committed
111
	connections = (Connection *) ch_calloc( dtblsize, sizeof(Connection) );
112
113
114

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

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
120
121
	assert( connections[0].c_struct_state == SLAP_C_UNINITIALIZED );
	assert( connections[dtblsize-1].c_struct_state == SLAP_C_UNINITIALIZED );
122

123
124
	for (i=0; i<dtblsize; i++) connections[i].c_conn_idx = i;

125
126
127
128
129
130
131
132
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}

133
134
135
136
137
/*
 * Destroy connection management infrastructure.
 */
int connections_destroy(void)
{
138
	ber_socket_t i;
139
140
141
142
143
144
145
146
147
148

	/* should check return of every call */

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

	for ( i = 0; i < dtblsize; i++ ) {
149
		if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
150
			ber_sockbuf_free( connections[i].c_sb );
151
152
153
			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 );
154
#ifdef LDAP_SLAPI
Howard Chu's avatar
Howard Chu committed
155
			if ( slapi_plugins_used ) {
156
				slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION, &connections[i] );
Howard Chu's avatar
Howard Chu committed
157
			}
158
#endif
159
		}
160
161
162
163
164
165
	}

	free( connections );
	connections = NULL;

	ldap_pvt_thread_mutex_destroy( &connections_mutex );
166
	ldap_pvt_thread_mutex_destroy( &conn_nextid_mutex );
167
168
169
170
171
172
173
174
	return 0;
}

/*
 * shutdown all connections
 */
int connections_shutdown(void)
{
175
	ber_socket_t i;
176
177
178
179
180
181
182

	ldap_pvt_thread_mutex_lock( &connections_mutex );

	for ( i = 0; i < dtblsize; i++ ) {
		if( connections[i].c_struct_state != SLAP_C_USED ) {
			continue;
		}
183
184
185
186
187
188
		/* give persistent clients a chance to cleanup */
		if( connections[i].c_conn_state == SLAP_C_CLIENT ) {
			ldap_pvt_thread_pool_submit( &connection_pool,
			connections[i].c_clientfunc, connections[i].c_clientarg );
			continue;
		}
189
190

		ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
191
192

		/* connections_mutex and c_mutex are locked */
193
194
		connection_closing( &connections[i] );
		connection_close( &connections[i] );
195

196
197
198
199
		ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
	}

	ldap_pvt_thread_mutex_unlock( &connections_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
200
201

	return 0;
202
203
}

204
205
206
207
208
209
210
211
212
/*
 * Timeout idle connections.
 */
int connections_timeout_idle(time_t now)
{
	int i = 0;
	int connindex;
	Connection* c;

Gary Williams's avatar
Gary Williams committed
213
	for( c = connection_first( &connindex );
214
215
216
		c != NULL;
		c = connection_next( c, &connindex ) )
	{
217
218
219
220
		/* 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;
221

222
223
224
225
226
227
228
229
230
231
232
233
		if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
			/* close it */
			connection_closing( c );
			connection_close( c );
			i++;
		}
	}
	connection_done( c );

	return i;
}

234
static Connection* connection_get( ber_socket_t s )
235
{
236
237
	/* connections_mutex should be locked by caller */

238
239
240
	Connection *c;

	Debug( LDAP_DEBUG_ARGS,
241
242
		"connection_get(%ld)\n",
		(long) s, 0, 0 );
243
244
245

	assert( connections != NULL );

246
	if(s == AC_SOCKET_INVALID) {
247
248
249
250
251
		return NULL;
	}

#ifndef HAVE_WINSOCK
	c = &connections[s];
252

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

255
#else
256
	c = NULL;
257
	{
258
		ber_socket_t i, sd;
259
260

		for(i=0; i<dtblsize; i++) {
Gary Williams's avatar
NT port    
Gary Williams committed
261
			if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
262
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
263
				assert( connections[i].c_sb == 0 );
264
265
266
				break;
			}

267
268
269
			ber_sockbuf_ctrl( connections[i].c_sb,
				LBER_SB_OPT_GET_FD, &sd );

Gary Williams's avatar
NT port    
Gary Williams committed
270
			if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
271
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
272
				assert( sd == AC_SOCKET_INVALID );
273
274
275
				continue;
			}

276
277
278
			/* state can actually change from used -> unused by resched,
			 * so don't assert details here.
			 */
279

280
			if( sd == s ) {
Gary Williams's avatar
NT port    
Gary Williams committed
281
				c = &connections[i];
282
283
284
285
286
				break;
			}
		}
	}
#endif
287

288
	if( c != NULL ) {
289
290
		ber_socket_t	sd;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
291
292
		ldap_pvt_thread_mutex_lock( &c->c_mutex );

293
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
294
295
		if( c->c_struct_state != SLAP_C_USED ) {
			/* connection must have been closed due to resched */
296

297
			assert( c->c_conn_state == SLAP_C_INVALID );
298
			assert( sd == AC_SOCKET_INVALID );
299
300

			Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
301
302
				"connection_get(%d): connection not used\n",
				s, 0, 0 );
303

304
			ldap_pvt_thread_mutex_unlock( &c->c_mutex );
305
306
307
			return NULL;
		}

308
		Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
309
			"connection_get(%d): got connid=%lu\n",
310
			s, c->c_connid, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
311

312
313
		c->c_n_get++;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
314
315
		assert( c->c_struct_state == SLAP_C_USED );
		assert( c->c_conn_state != SLAP_C_INVALID );
316
		assert( sd != AC_SOCKET_INVALID );
317

318
319
320
321
322
323
324
#ifdef SLAPD_MONITOR
		c->c_activitytime = slap_get_time();
#else
		if( global_idletimeout > 0 ) {
			c->c_activitytime = slap_get_time();
		}
#endif
325
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
326

327
328
329
330
331
332
333
334
335
	return c;
}

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

long connection_init(
336
	ber_socket_t s,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
337
	Listener *listener,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
338
339
	const char* dnsname,
	const char* peername,
340
	int flags,
341
	slap_ssf_t ssf,
342
	struct berval *authid )
343
{
344
	unsigned long id;
345
	Connection *c;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
346

347
348
	assert( connections != NULL );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
349
	assert( listener != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
350
351
352
	assert( dnsname != NULL );
	assert( peername != NULL );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
353
#ifndef HAVE_TLS
354
	assert( flags != CONN_IS_TLS );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
355
356
#endif

357
	if( s == AC_SOCKET_INVALID ) {
Gary Williams's avatar
Gary Williams committed
358
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
359
			"connection_init: init of socket %ld invalid.\n", (long)s, 0, 0 );
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
		return -1;
	}

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

	ldap_pvt_thread_mutex_lock( &connections_mutex );

#ifndef HAVE_WINSOCK
	c = &connections[s];

#else
	{
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
375
		ber_socket_t i;
376
377
		c = NULL;

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
378
379
		for( i=0; i < dtblsize; i++) {
			ber_socket_t	sd;
380

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
381
382
383
384
385
			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
386

387
			sd = AC_SOCKET_INVALID;
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
388
389
390
391
			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
392

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
393
394
395
396
397
			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
398

399
400
401
402
			if( connections[i].c_conn_state == SLAP_C_CLIENT ) {
				continue;
			}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
403
404
405
406
407
408
409
			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,
410
411
				"connection_init(%d): connection table full "
				"(%d/%d)\n", s, i, dtblsize);
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
412
413
414
			ldap_pvt_thread_mutex_unlock( &connections_mutex );
			return -1;
		}
Gary Williams's avatar
Gary Williams committed
415
	}
416
417
#endif

418
	assert( c != NULL );
419

420
	if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
421
422
423
424
		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;
425
426
#ifdef LDAP_RES_INTERMEDIATE
		c->c_send_ldap_intermediate = slap_send_ldap_intermediate;
427
#endif
428

429
430
431
		BER_BVZERO( &c->c_authmech );
		BER_BVZERO( &c->c_dn );
		BER_BVZERO( &c->c_ndn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
432

Pierangelo Masarati's avatar
Pierangelo Masarati committed
433
		c->c_listener = NULL;
434
435
		BER_BVZERO( &c->c_peer_domain );
		BER_BVZERO( &c->c_peer_name );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
436

437
438
		LDAP_STAILQ_INIT(&c->c_ops);
		LDAP_STAILQ_INIT(&c->c_pending_ops);
439

440
		BER_BVZERO( &c->c_sasl_bind_mech );
441
442
443
		c->c_sasl_done = 0;
		c->c_sasl_authctx = NULL;
		c->c_sasl_sockctx = NULL;
444
		c->c_sasl_extra = NULL;
445
		c->c_sasl_bindop = NULL;
446

447
448
449
		c->c_sb = ber_sockbuf_alloc( );

		{
450
			ber_len_t max = sockbuf_max_incoming;
451
452
453
			ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
454
		c->c_currentber = NULL;
455

456
457
458
459
		/* 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 );
460

461
#ifdef LDAP_SLAPI
462
		if ( slapi_plugins_used ) {
463
			slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, c );
464
		}
465
466
#endif

467
468
		c->c_struct_state = SLAP_C_UNUSED;
	}
469

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

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
472
	assert( c->c_struct_state == SLAP_C_UNUSED );
473
474
475
	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
476
	assert( c->c_listener == NULL );
477
478
	assert( BER_BVISNULL( &c->c_peer_domain ) );
	assert( BER_BVISNULL( &c->c_peer_name ) );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
479
480
	assert( LDAP_STAILQ_EMPTY(&c->c_ops) );
	assert( LDAP_STAILQ_EMPTY(&c->c_pending_ops) );
481
	assert( BER_BVISNULL( &c->c_sasl_bind_mech ) );
482
483
484
	assert( c->c_sasl_done == 0 );
	assert( c->c_sasl_authctx == NULL );
	assert( c->c_sasl_sockctx == NULL );
485
	assert( c->c_sasl_extra == NULL );
486
	assert( c->c_sasl_bindop == NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
487
	assert( c->c_currentber == NULL );
488
	assert( c->c_writewaiter == 0);
489

Pierangelo Masarati's avatar
Pierangelo Masarati committed
490
	c->c_listener = listener;
491
492
493
494

	if ( flags == CONN_IS_CLIENT ) {
		c->c_conn_state = SLAP_C_CLIENT;
		c->c_struct_state = SLAP_C_USED;
495
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s );
496
497
498
499
500
501
		ldap_pvt_thread_mutex_unlock( &c->c_mutex );
		ldap_pvt_thread_mutex_unlock( &connections_mutex );

		return 0;
	}

502
503
	ber_str2bv( dnsname, 0, 1, &c->c_peer_domain );
	ber_str2bv( peername, 0, 1, &c->c_peer_name );
504

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
505
506
507
508
	c->c_n_ops_received = 0;
	c->c_n_ops_executing = 0;
	c->c_n_ops_pending = 0;
	c->c_n_ops_completed = 0;
509
510
511
512

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

514
515
	/* set to zero until bind, implies LDAP_VERSION3 */
	c->c_protocol = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
516

517
518
519
520
521
522
523
#ifdef SLAPD_MONITOR
	c->c_activitytime = c->c_starttime = slap_get_time();
#else
	if( global_idletimeout > 0 ) {
		c->c_activitytime = c->c_starttime = slap_get_time();
	}
#endif
524

525
526
#ifdef LDAP_CONNECTIONLESS
	c->c_is_udp = 0;
527
	if( flags == CONN_IS_UDP ) {
528
529
		c->c_is_udp = 1;
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
530
531
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_PROVIDER, (void*)"udp_" );
532
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
533
534
535
536
		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 );
537
538
539
	} else
#endif
	{
540
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
541
542
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_PROVIDER, (void*)"tcp_" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
543
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
544
545
		ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp,
			LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
546
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
547
548
549
550

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
553
554
555
556
557
	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
558
			s, c->c_peer_name.bv_val, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
559
	}
560

561
	ldap_pvt_thread_mutex_lock( &conn_nextid_mutex );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
562
	id = c->c_connid = conn_nextid++;
563
	ldap_pvt_thread_mutex_unlock( &conn_nextid_mutex );
564

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
565
566
	c->c_conn_state = SLAP_C_INACTIVE;
	c->c_struct_state = SLAP_C_USED;
567

568
569
570
	c->c_ssf = c->c_transport_ssf = ssf;
	c->c_tls_ssf = 0;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
571
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
572
573
574
575
576
577
578
	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
579
#endif
580

581
	slap_sasl_open( c, 0 );
582
	slap_sasl_external( c, ssf, authid );
583

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
584
585
	ldap_pvt_thread_mutex_unlock( &c->c_mutex );
	ldap_pvt_thread_mutex_unlock( &connections_mutex );
586

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
587
	backend_connection_init(c);
588

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
589
	return id;
590
591
}

592
593
void connection2anonymous( Connection *c )
{
594
595
	assert( connections != NULL );
	assert( c != NULL );
596

597
598
599
600
601
	{
		ber_len_t max = sockbuf_max_incoming;
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
	}

602
603
	if(c->c_authmech.bv_val != NULL ) {
		free(c->c_authmech.bv_val);
604
	}
605
	BER_BVZERO( &c->c_authmech );
606

607
608
609
	if(c->c_dn.bv_val != NULL) {
		free(c->c_dn.bv_val);
	}
610
	BER_BVZERO( &c->c_dn );
611
612
613
	if(c->c_ndn.bv_val != NULL) {
		free(c->c_ndn.bv_val);
	}
614
	BER_BVZERO( &c->c_ndn );
615
616
617
618

	c->c_authz_backend = NULL;
}

619
620
621
static void
connection_destroy( Connection *c )
{
622
	/* note: connections_mutex should be locked by caller */
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
623
624
	ber_socket_t	sd;
	unsigned long	connid;
625

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
626
627
628
629
630
	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) );
631
	assert( c->c_writewaiter == 0);
632

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
633
634
	/* only for stats (print -1 as "%lu" may give unexpected results ;) */
	connid = c->c_connid;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
635

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
636
	backend_connection_destroy(c);
637

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
638
639
	c->c_protocol = 0;
	c->c_connid = -1;
640

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
641
	c->c_activitytime = c->c_starttime = 0;
642

643
	connection2anonymous( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
644
	c->c_listener = NULL;
645

646
647
	if(c->c_peer_domain.bv_val != NULL) {
		free(c->c_peer_domain.bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
648
	}
649
	BER_BVZERO( &c->c_peer_domain );
650
651
	if(c->c_peer_name.bv_val != NULL) {
		free(c->c_peer_name.bv_val);
652
	}
653
	BER_BVZERO( &c->c_peer_name );
654

655
	c->c_sasl_bind_in_progress = 0;
656
657
	if(c->c_sasl_bind_mech.bv_val != NULL) {
		free(c->c_sasl_bind_mech.bv_val);
658
	}
659
	BER_BVZERO( &c->c_sasl_bind_mech );
660
661

	slap_sasl_close( c );
662

Kurt Zeilenga's avatar
Kurt Zeilenga committed
663
664
665
666
667
	if ( c->c_currentber != NULL ) {
		ber_free( c->c_currentber, 1 );
		c->c_currentber = NULL;
	}

668
669
	ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
	if ( sd != AC_SOCKET_INVALID ) {
670
		slapd_remove( sd, 1, 0 );
671
672

		Statslog( LDAP_DEBUG_STATS,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
673
			"conn=%lu fd=%ld closed\n",
674
			connid, (long) sd, 0, 0, 0 );
675
676
	}

Gary Williams's avatar
Gary Williams committed
677
	ber_sockbuf_free( c->c_sb );
678

679
	c->c_sb = ber_sockbuf_alloc( );
680

681
	{
682
		ber_len_t max = sockbuf_max_incoming;
683
684
685
		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
	}

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
686
687
	c->c_conn_state = SLAP_C_INVALID;
	c->c_struct_state = SLAP_C_UNUSED;
688
689
690

#ifdef LDAP_SLAPI
	/* call destructors, then constructors; avoids unnecessary allocation */
691
	if ( slapi_plugins_used ) {
692
		slapi_int_clear_object_extensions( SLAPI_X_EXT_CONNECTION, c );
693
	}
694
#endif
695
696
}

697
698
int connection_state_closing( Connection *c )
{
699
700
	/* c_mutex must be locked by caller */

701
	int state;
702
703
704
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );

705
706
707
708
709
	state = c->c_conn_state;

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
710
711
}

712
713
714
715
716
717
static void connection_abandon( Connection *c )
{
	/* c_mutex must be locked by caller */

	Operation *o;

718
	LDAP_STAILQ_FOREACH(o, &c->c_ops, o_next) {
719
720
721
722
		o->o_abandon = 1;
	}

	/* remove pending operations */
723
724
725
	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;
726
727
728
729
		slap_op_free( o );
	}
}

730
731
732
733
734
735
736
void connection_closing( Connection *c )
{
	assert( connections != NULL );
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );
	assert( c->c_conn_state != SLAP_C_INVALID );

737
738
	/* c_mutex must be locked by caller */

739
	if( c->c_conn_state != SLAP_C_CLOSING ) {
740
741
742
		ber_socket_t	sd;

		ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
743
		Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
744
			"connection_closing: readying conn=%lu sd=%d for close\n",
745
			c->c_connid, sd, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
746
747
748
		/* update state to closing */
		c->c_conn_state = SLAP_C_CLOSING;

749
		/* don't listen on this port anymore */
750
		slapd_clr_read( sd, 1 );
751
752

		/* abandon active operations */
753
		connection_abandon( c );
754
755

		/* wake write blocked operations */
756
		slapd_clr_write( sd, 1 );
757
		ldap_pvt_thread_cond_signal( &c->c_write_cv );
758
759
760
	}
}

761
762
static void connection_close( Connection *c )
{
763
764
	ber_socket_t	sd;

765
766
767
768
769
	assert( connections != NULL );
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );
	assert( c->c_conn_state == SLAP_C_CLOSING );

770
	/* note: connections_mutex and c_mutex should be locked by caller */
771

772
	ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
773
	if( !LDAP_STAILQ_EMPTY(&c->c_ops) ) {
774
		Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
775
			"connection_close: deferring conn=%lu sd=%d\n",
776
			c->c_connid, sd, 0 );
777
778
779
		return;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
780
	Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%lu sd=%d\n",
781
		c->c_connid, sd, 0 );
782
783
784
	connection_destroy( c );
}

785
unsigned long connections_nextid(void)
786
{
787
	unsigned long id;
788
789
790
791
792
793
794
795
796
797
798
	assert( connections != NULL );

	ldap_pvt_thread_mutex_lock( &connections_mutex );

	id = conn_nextid;

	ldap_pvt_thread_mutex_unlock( &connections_mutex );

	return id;
}

799
Connection* connection_first( ber_socket_t *index )
800
801
{
	assert( connections != NULL );
802
	assert( index != NULL );
803
804
805

	ldap_pvt_thread_mutex_lock( &connections_mutex );

806
	*index = 0;
807

808
	return connection_next(NULL, index);
809
810
}

811
Connection* connection_next( Connection *c, ber_socket_t *index )
812
813
{
	assert( connections != NULL );
814
815
	assert( index != NULL );
	assert( *index <= dtblsize );
816
817
818
819
820
821
822

	if( c != NULL ) {
		ldap_pvt_thread_mutex_unlock( &c->c_mutex );
	}

	c = NULL;

823
824
825
	for(; *index < dtblsize; (*index)++) {
		if( connections[*index].c_struct_state == SLAP_C_UNINITIALIZED ) {
			assert( connections[*index].c_conn_state == SLAP_C_INVALID );
826
827
828
829
830
831
832
#ifndef HAVE_WINSOCK
			continue;
#else
			break;
#endif
		}

833
834
835
		if( connections[*index].c_struct_state == SLAP_C_USED ) {
			assert( connections[*index].c_conn_state != SLAP_C_INVALID );
			c = &connections[(*index)++];
836
837
838
			break;
		}

839
840
		assert( connections[*index].c_struct_state == SLAP_C_UNUSED );
		assert( connections[*index].c_conn_state == SLAP_C_INVALID );
841
842
843
844
845
846
847
848
849
	}

	if( c != NULL ) {
		ldap_pvt_thread_mutex_lock( &c->c_mutex );
	}

	return c;
}

850
void connection_done( Connection *c )
851
852
853
854
855
856
857
858
859
860
{
	assert( connections != NULL );

	if( c != NULL ) {
		ldap_pvt_thread_mutex_unlock( &c->c_mutex );
	}

	ldap_pvt_thread_mutex_unlock( &connections_mutex );
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
861
862
863
864
865
866
/*
 * connection_activity - handle the request operation op on connection
 * conn.  This routine figures out what kind of operation it is and
 * calls the appropriate stub to handle it.
 */

867
#ifdef SLAPD_MONITOR
868
869
#ifdef HAVE_GMP
#define INCR_OP_INITIATED(index) \
870
	do { \
871
872
873
874
		ldap_pvt_thread_mutex_lock( &slap_counters.sc_ops_mutex ); \
		mpz_add_ui(slap_counters.sc_ops_initiated_[(index)], \
				slap_counters.sc_ops_initiated_[(index)], 1); \
		ldap_pvt_thread_mutex_unlock( &slap_counters.sc_ops_mutex ); \
875
	} while (0)
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
#define INCR_OP_COMPLETED(index) \
	do { \
		ldap_pvt_thread_mutex_lock( &slap_counters.sc_ops_mutex ); \
		mpz_add_ui(slap_counters.sc_ops_completed, \
				slap_counters.sc_ops_completed, 1); \
		mpz_add_ui(slap_counters.sc_ops_completed_[(index)], \
				slap_counters.sc_ops_completed_[(index)], 1); \
		ldap_pvt_thread_mutex_unlock( &slap_counters.sc_ops_mutex ); \
	} while (0)
#else /* ! HAVE_GMP */
#define INCR_OP_INITIATED(index) \
	do { \
		ldap_pvt_thread_mutex_lock( &slap_counters.sc_ops_mutex ); \
		slap_counters.sc_ops_initiated_[(index)]++; \
		ldap_pvt_thread_mutex_unlock( &slap_counters.sc_ops_mutex ); \
	} while (0)
#define INCR_OP_COMPLETED(index) \
	do { \
		ldap_pvt_thread_mutex_lock( &slap_counters.sc_ops_mutex ); \
		slap_counters.sc_ops_completed++; \
		slap_counters.sc_ops_completed_[(index)]++; \
		ldap_pvt_thread_mutex_unlock( &slap_counters.sc_ops_mutex ); \
	} while (0)
#endif /* ! HAVE_GMP */
900
#else /* !SLAPD_MONITOR */
901
902
#define INCR_OP_INITIATED(index) 
#define INCR_OP_COMPLETED(index) 
903
#endif /* !SLAPD_MONITOR */
904

905
static void *
906
connection_operation( void *ctx, void *arg_v )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
907
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
908
	int rc = LDAP_OTHER;
909
	Operation *op = arg_v;
910
	SlapReply rs = {REP_RESULT};
911
	ber_tag_t tag = op->o_tag;
912
913
914
#ifdef SLAPD_MONITOR
	ber_tag_t oldtag = tag;
#endif /* SLAPD_MONITOR */
915
	Connection *conn = op->o_conn;
916
	void *memctx = NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
917
	void *memctx_null = NULL;
Howard Chu's avatar
Howard Chu committed
918
	ber_len_t memsiz;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
919

920
921
922
923
924
925
926
	ldap_pvt_thread_mutex_lock( &slap_counters.sc_ops_mutex );
#ifdef HAVE_GMP
	mpz_add_ui(slap_counters.sc_ops_initiated, slap_counters.sc_ops_initiated, 1);
#else /* ! HAVE_GMP */
	slap_counters.sc_ops_initiated++;
#endif /* ! HAVE_GMP */
	ldap_pvt_thread_mutex_unlock( &slap_counters.sc_ops_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
927

928
	op->o_threadctx = ctx;
929

Kurt Zeilenga's avatar
Kurt Zeilenga committed
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
	switch ( tag ) {
	case LDAP_REQ_BIND:
	case LDAP_REQ_UNBIND:
	case LDAP_REQ_ADD:
	case LDAP_REQ_DELETE:
	case LDAP_REQ_MODRDN:
	case LDAP_REQ_MODIFY:
	case LDAP_REQ_COMPARE:
	case LDAP_REQ_SEARCH:
	case LDAP_REQ_ABANDON:
	case LDAP_REQ_EXTENDED:
		break;
	default:
		Debug( LDAP_DEBUG_ANY, "connection_operation: "
			"conn %lu unknown LDAP request 0x%lx\n",
			conn->c_connid, tag, 0 );
		op->o_tag = LBER_ERROR;
		rs.sr_err = LDAP_PROTOCOL_ERROR;
		rs.sr_text = "unknown LDAP request";
		send_ldap_disconnect( op, &rs );
		rc = SLAPD_DISCONNECT;
		goto operations_error;
	}

954
	if( conn->c_sasl_bind_in_progress && tag != LDAP_REQ_BIND ) {
955
956
957
		Debug( LDAP_DEBUG_ANY, "connection_operation: "
			"error: SASL bind in progress (tag=%ld).\n",
			(long) tag, 0, 0 );
958
959
		send_ldap_error( op, &rs, LDAP_OPERATIONS_ERROR,
			"SASL bind in progress" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
960
		rc = LDAP_OPERATIONS_ERROR;
961
962
963
		goto operations_error;
	}

964
965
	/* We can use Thread-Local storage for most mallocs. We can
	 * also use TL for ber parsing, but not on Add or Modify.
966