connection.c 19.3 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
#include "portable.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
4
5
6
7
8
9
10

#include <stdio.h>

#include <ac/errno.h>
#include <ac/signal.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
11
12
#include "slap.h"

13
14
15
16
17
18
/* protected by connections_mutex */
static ldap_pvt_thread_mutex_t connections_mutex;
static Connection *connections = NULL;
static int conn_index = -1;
static long conn_nextid = 0;

19
20
21
22
23
24
25
26
27
28
29
30
/* structure state (protected by connections_mutex) */
#define SLAP_C_UNINITIALIZED	0x0	/* MUST BE ZERO (0) */
#define SLAP_C_UNUSED			0x1
#define SLAP_C_USED				0x2

/* connection state (protected by c_mutex ) */
#define SLAP_C_INVALID			0x0	/* MUST BE ZERO (0) */
#define SLAP_C_INACTIVE			0x1	/* zero threads */
#define SLAP_C_ACTIVE			0x2 /* one or more threads */
#define SLAP_C_BINDING			0x3	/* binding */
#define SLAP_C_CLOSING			0x4	/* closing */

Gary Williams's avatar
NT port    
Gary Williams committed
31
void slapd_remove(int s);
32
33
34
static Connection* connection_get( int s );

static int connection_input( Connection *c );
35
static void connection_close( Connection *c );
36

37
38
39
static int connection_op_activate( Connection *conn, Operation *op );
static int connection_resched( Connection *conn );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
40
41
42
43
44
struct co_arg {
	Connection	*co_conn;
	Operation	*co_op;
};

45
46
47
48
49
50
51
52
53
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
{
	int i;

	assert( connections == NULL );

54
	if( connections != NULL) {
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
		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 );

	connections = (Connection *) calloc( dtblsize, sizeof(Connection) );

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

Gary Williams's avatar
NT port    
Gary Williams committed
72
73
74
	for ( i = 0; i < dtblsize; i++ )
		memset( &connections[i], 0, sizeof(Connection) );

75
76
77
78
79
80
81
82
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
 * Destroy connection management infrastructure.
 */
int connections_destroy(void)
{
	int i;

	/* 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++ ) {
99
100
101
102
103
		if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
			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 );
		}
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

		free( &connections[i] );
	}

	free( connections );
	connections = NULL;

	ldap_pvt_thread_mutex_destroy( &connections_mutex );
	return 0;
}

/*
 * shutdown all connections
 */
int connections_shutdown(void)
{
	int i;

	ldap_pvt_thread_mutex_lock( &connections_mutex );

	for ( i = 0; i < dtblsize; i++ ) {
		if( connections[i].c_struct_state != SLAP_C_USED ) {
			continue;
		}

		ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
		connection_closing( &connections[i] );
		connection_close( &connections[i] );
		ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
	}

	ldap_pvt_thread_mutex_unlock( &connections_mutex );
}

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
static Connection* connection_get( int s )
{
	Connection *c = NULL;

	assert( connections != NULL );

	if(s < 0) {
		return NULL;
	}

#ifndef HAVE_WINSOCK
	assert( connections[s].c_struct_state == SLAP_C_USED );
	assert( connections[s].c_conn_state != SLAP_C_INVALID );
	assert( connections[s].c_sb.sb_sd != -1 );

	c = &connections[s];
#else
	{
		int i;

		for(i=0; i<dtblsize; i++) {
Gary Williams's avatar
NT port    
Gary Williams committed
159
			if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
160
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
161
				assert( connections[i].c_sb.sb_sd == 0 );
162
163
164
				break;
			}

Gary Williams's avatar
NT port    
Gary Williams committed
165
			if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
166
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
167
				assert( connections[i].c_sb.sb_sd == -1 );
168
169
170
				continue;
			}

Gary Williams's avatar
NT port    
Gary Williams committed
171
			assert( connections[i].c_struct_state == SLAP_C_USED );
172
			assert( connections[i].c_conn_state != SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
173
			assert( connections[i].c_sb.sb_sd != -1 );
174
175

			if( connections[i].c_sb.sb_sd == s ) {
Gary Williams's avatar
NT port    
Gary Williams committed
176
				c = &connections[i];
177
178
179
180
181
				break;
			}
		}
	}
#endif
182

183
	if( c != NULL ) {
184
185
186
187
188
		/* we do this BEFORE locking to aid in debugging */
		Debug( LDAP_DEBUG_TRACE,
			"connection_get(%d): got connid=%ld\n",
			s, c->c_connid, 0 );

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
		ldap_pvt_thread_mutex_lock( &c->c_mutex );
	}
	return c;
}

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

long connection_init(
	int s,
	const char* name,
	const char* addr)
{
	long id;
	Connection *c;
	assert( connections != NULL );

	if( s < 0 ) {
		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
	{
		int i;

Gary Williams's avatar
NT port    
Gary Williams committed
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
        for( i=0; i < dtblsize; i++) {
            if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
                assert( connections[i].c_sb.sb_sd == 0 );
                c = &connections[i];
                break;
            }

            if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
                assert( connections[i].c_sb.sb_sd == -1 );
                c = &connections[i];
                break;
            }

            assert( connections[i].c_struct_state == SLAP_C_USED );
            assert( connections[i].c_conn_state != SLAP_C_INVALID );
            assert( connections[i].c_sb.sb_sd != -1 );
        }

        if( c == NULL ) {
            ldap_pvt_thread_mutex_unlock( &connections_mutex );
            return -1;
        }
    }
249
250
#endif

Gary Williams's avatar
NT port    
Gary Williams committed
251
252
253
    assert( c != NULL );
    assert( c->c_struct_state != SLAP_C_USED );
    assert( c->c_conn_state == SLAP_C_INVALID );
254

Gary Williams's avatar
NT port    
Gary Williams committed
255
256
257
258
259
260
261
    if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
        c->c_dn = NULL;
        c->c_cdn = NULL;
        c->c_client_name = NULL;
        c->c_client_addr = NULL;
        c->c_ops = NULL;
        c->c_pending_ops = NULL;
262

Gary Williams's avatar
NT port    
Gary Williams committed
263
        lber_pvt_sb_init( &c->c_sb );
264

Gary Williams's avatar
NT port    
Gary Williams committed
265
266
267
268
        /* 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 );
269

Gary Williams's avatar
NT port    
Gary Williams committed
270
271
        c->c_struct_state = SLAP_C_UNUSED;
    }
272

Gary Williams's avatar
NT port    
Gary Williams committed
273
    ldap_pvt_thread_mutex_lock( &c->c_mutex );
274

Gary Williams's avatar
NT port    
Gary Williams committed
275
276
277
278
279
280
281
    assert( c->c_struct_state == SLAP_C_UNUSED );
    assert(	c->c_dn == NULL );
    assert(	c->c_cdn == NULL );
    assert( c->c_client_name == NULL );
    assert( c->c_client_addr == NULL );
    assert( c->c_ops == NULL );
    assert( c->c_pending_ops == NULL );
282

Gary Williams's avatar
NT port    
Gary Williams committed
283
284
    c->c_client_name = ch_strdup( name == NULL ? "" : name );
    c->c_client_addr = ch_strdup( addr );
285

Gary Williams's avatar
NT port    
Gary Williams committed
286
    c->c_n_ops_received = 0;
287
#ifdef LDAP_COUNTERS
Gary Williams's avatar
NT port    
Gary Williams committed
288
289
290
    c->c_n_ops_executing = 0;
    c->c_n_ops_pending = 0;
    c->c_n_ops_completed = 0;
291
292
#endif

Gary Williams's avatar
NT port    
Gary Williams committed
293
    c->c_starttime = slap_get_time();
294

Gary Williams's avatar
NT port    
Gary Williams committed
295
296
    lber_pvt_sb_set_desc( &c->c_sb, s );
    lber_pvt_sb_set_io( &c->c_sb, &lber_pvt_sb_io_tcp, NULL );
297

Gary Williams's avatar
NT port    
Gary Williams committed
298
299
300
301
302
    if( lber_pvt_sb_set_nonblock( &c->c_sb, 1 ) < 0 ) {
        Debug( LDAP_DEBUG_ANY,
            "connection_init(%d, %s, %s): set nonblocking failed\n",
            s, c->c_client_name, c->c_client_addr);
    }
303

Gary Williams's avatar
NT port    
Gary Williams committed
304
    id = c->c_connid = conn_nextid++;
305

Gary Williams's avatar
NT port    
Gary Williams committed
306
307
    c->c_conn_state = SLAP_C_INACTIVE;
    c->c_struct_state = SLAP_C_USED;
308

Gary Williams's avatar
NT port    
Gary Williams committed
309
310
    ldap_pvt_thread_mutex_unlock( &c->c_mutex );
    ldap_pvt_thread_mutex_unlock( &connections_mutex );
311

Gary Williams's avatar
NT port    
Gary Williams committed
312
    return id;
313
314
315
316
317
}

static void
connection_destroy( Connection *c )
{
Gary Williams's avatar
NT port    
Gary Williams committed
318
319
320
321
322
    assert( connections != NULL );
    assert( c != NULL );
    assert( c->c_struct_state != SLAP_C_UNUSED );
    assert( c->c_conn_state != SLAP_C_INVALID );
    assert( c->c_ops == NULL );
323

Gary Williams's avatar
NT port    
Gary Williams committed
324
325
    c->c_struct_state = SLAP_C_UNUSED;
    c->c_conn_state = SLAP_C_INVALID;
326

Gary Williams's avatar
NT port    
Gary Williams committed
327
328
    c->c_version = 0;
    c->c_protocol = 0;
329

Gary Williams's avatar
NT port    
Gary Williams committed
330
    c->c_starttime = 0;
331

Gary Williams's avatar
NT port    
Gary Williams committed
332
333
334
335
    if(c->c_dn != NULL) {
        free(c->c_dn);
        c->c_dn = NULL;
    }
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
	if(c->c_cdn != NULL) {
		free(c->c_cdn);
		c->c_cdn = NULL;
	}
	if(c->c_client_name != NULL) {
		free(c->c_client_name);
		c->c_client_name = NULL;
	}
	if(c->c_client_addr != NULL) {
		free(c->c_client_addr);
		c->c_client_addr = NULL;
	}

	if ( lber_pvt_sb_in_use(&c->c_sb) ) {
		int sd = lber_pvt_sb_get_desc(&c->c_sb);

		slapd_remove( sd );
	   	lber_pvt_sb_close( &c->c_sb );

		Statslog( LDAP_DEBUG_STATS,
		    "conn=%d fd=%d closed.\n",
			c->c_connid, sd, 0, 0, 0 );
	}

   	lber_pvt_sb_destroy( &c->c_sb );
}

363
364
int connection_state_closing( Connection *c )
{
365
	/* connection must be locked by caller */
366
	int state;
367
368
369
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );

370
371
372
373
374
	state = c->c_conn_state;

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
375
376
}

377
378
379
380
381
382
383
384
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 );

	if( c->c_conn_state != SLAP_C_CLOSING ) {
385
386
387
388
389
390
		Operation *o;

		Debug( LDAP_DEBUG_TRACE,
			"connection_closing: readying conn=%ld sd=%d for close.\n",
			c->c_connid, c->c_sb.sb_sd, 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
391
392
393
		/* update state to closing */
		c->c_conn_state = SLAP_C_CLOSING;

394
395
		/* don't listen on this port anymore */
		slapd_clr_read( c->c_sb.sb_sd, 1 );
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414

		/* shutdown I/O -- not yet implemented */

		/* abandon active operations */
		for( o = c->c_ops; o != NULL; o = o->o_next ) {
			ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
			o->o_abandon = 1;
			ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
		}

		/* remove pending operations */
		for( o = slap_op_pop( &c->c_pending_ops );
			o != NULL;
			o = slap_op_pop( &c->c_pending_ops ) )
		{
			slap_op_free( o );
		}

		/* wake write blocked operations */
415
		slapd_clr_write( c->c_sb.sb_sd, 1 );
416
		ldap_pvt_thread_cond_signal( &c->c_write_cv );
417
418
419
	}
}

420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
static void connection_close( Connection *c )
{
	assert( connections != NULL );
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );
	assert( c->c_conn_state == SLAP_C_CLOSING );

	if( c->c_ops != NULL ) {
		Debug( LDAP_DEBUG_TRACE,
			"connection_close: deferring conn=%ld sd=%d.\n",
			c->c_connid, c->c_sb.sb_sd, 0 );

		return;
	}

	Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n",
		c->c_connid, c->c_sb.sb_sd, 0 );

	connection_destroy( c );
}

long connections_nextid(void)
{
	long id;
	assert( connections != NULL );

	ldap_pvt_thread_mutex_lock( &connections_mutex );

	id = conn_nextid;

	ldap_pvt_thread_mutex_unlock( &connections_mutex );

	return id;
}

Connection* connection_first(void)
{
	assert( connections != NULL );

	ldap_pvt_thread_mutex_lock( &connections_mutex );

	assert( conn_index == -1 );
	conn_index = 0;

	return connection_next(NULL);
}

Connection* connection_next(Connection *c)
{
	assert( connections != NULL );
	assert( conn_index != -1 );
	assert( conn_index <= dtblsize );

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

	c = NULL;

	for(; conn_index < dtblsize; conn_index++) {
		if( connections[conn_index].c_struct_state == SLAP_C_UNINITIALIZED ) {
			assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
#ifndef HAVE_WINSOCK
			continue;
#else
			break;
#endif
		}

		if( connections[conn_index].c_struct_state == SLAP_C_USED ) {
			assert( connections[conn_index].c_conn_state != SLAP_C_INVALID );
			c = &connections[conn_index++];
			break;
		}

		assert( connections[conn_index].c_struct_state == SLAP_C_UNUSED );
		assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
	}

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

	return c;
}

void connection_done(Connection *c)
{
	assert( connections != NULL );
	assert( conn_index != -1 );
	assert( conn_index <= dtblsize );

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

	conn_index = -1;
	ldap_pvt_thread_mutex_unlock( &connections_mutex );
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
520
521
522
523
524
525
/*
 * 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.
 */

526
527
static void *
connection_operation( void *arg_v )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
528
{
529
	struct co_arg	*arg = arg_v;
530
531
	int tag = arg->co_op->o_tag;
	Connection *conn = arg->co_conn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
532

533
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
534
535
536
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_initiated++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
537
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
538

539
	switch ( tag ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
540
	case LDAP_REQ_BIND:
541
		do_bind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
542
543
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
544
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
545
546
547
	case LDAP_REQ_UNBIND_30:
#endif
	case LDAP_REQ_UNBIND:
548
		do_unbind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549
550
551
		break;

	case LDAP_REQ_ADD:
552
		do_add( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
553
554
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
555
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
557
558
	case LDAP_REQ_DELETE_30:
#endif
	case LDAP_REQ_DELETE:
559
		do_delete( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
560
561
562
		break;

	case LDAP_REQ_MODRDN:
563
		do_modrdn( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
564
565
566
		break;

	case LDAP_REQ_MODIFY:
567
		do_modify( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
568
569
570
		break;

	case LDAP_REQ_COMPARE:
571
		do_compare( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
572
573
574
		break;

	case LDAP_REQ_SEARCH:
575
		do_search( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
576
577
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
578
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
579
580
581
	case LDAP_REQ_ABANDON_30:
#endif
	case LDAP_REQ_ABANDON:
582
		do_abandon( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
583
584
585
		break;

	default:
586
		Debug( LDAP_DEBUG_ANY, "unknown request 0x%lx\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
587
588
589
590
		    arg->co_op->o_tag, 0, 0 );
		break;
	}

591
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
592
593
594
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_completed++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
595
596
597
#endif

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
598

599
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
600
	conn->c_n_ops_completed++;
601
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
602

603
604
605
	slap_op_remove( &conn->c_ops, arg->co_op );
	slap_op_free( arg->co_op );
	arg->co_op = NULL;
606
	arg->co_conn = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
607
	free( (char *) arg );
608
	arg = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
609

610
611
612
613
614
	switch( tag ) {
#ifdef LDAP_COMPAT30
	case LDAP_REQ_UNBIND_30:
#endif
	case LDAP_REQ_UNBIND:
615
		connection_closing( conn );
616
617
618
619
620
621
		break;

	case LDAP_REQ_BIND:
		if( conn->c_conn_state == SLAP_C_BINDING) {
			conn->c_conn_state = SLAP_C_ACTIVE;
		}
622
623
	}

624
625
626
627
628
629
630
	if( conn->c_conn_state == SLAP_C_CLOSING ) {
		Debug( LDAP_DEBUG_TRACE,
			"connection_operation: attempting closing conn=%ld sd=%d.\n",
			conn->c_connid, conn->c_sb.sb_sd, 0 );

		connection_close( conn );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
631

632
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
633
	active_threads--;
634
	if( active_threads < 1 ) {
635
		ldap_pvt_thread_cond_signal(&active_threads_cond);
636
	}
637
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
638
639
640

	connection_resched( conn );

641
642
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

643
	return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
644
645
}

646
647
648
649
650
651
652
653
654
655
656
657
658
int connection_read(int s)
{
	int rc = 0;
	Connection *c;
	assert( connections != NULL );

	ldap_pvt_thread_mutex_lock( &connections_mutex );

	c = connection_get( s );
	if( c == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"connection_read(%d): no connection!\n",
			s, 0, 0 );
659
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
660
661
662
		return -1;
	}

663
664
665
666
667
668
669
670
671
672
	if( c->c_conn_state == SLAP_C_CLOSING ) {
		Debug( LDAP_DEBUG_TRACE,
			"connection_read(%d): closing, ignoring input for id=%ld\n",
			s, c->c_connid, 0 );

		connection_return( c );
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
		return 0;
	}

673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
	Debug( LDAP_DEBUG_TRACE,
		"connection_read(%d): checking for input on id=%ld\n",
		s, c->c_connid, 0 );

#define CONNECTION_INPUT_LOOP 1

#ifdef DATA_READY_LOOP
	while(!rc && lber_pvt_sb_data_ready(&c->c_sb))
#elif CONNECTION_INPUT_LOOP
	while(!rc)
#endif
	{
		rc = connection_input( c );
	}

	if( rc < 0 ) {
		Debug( LDAP_DEBUG_TRACE,
690
691
			"connection_read(%d): input error=%d id=%ld, closing.\n",
			s, rc, c->c_connid );
692

693
		connection_closing( c );
694
695
696
697
698
699
700
701
702
703
		connection_close( c );
	}

	connection_return( c );
	ldap_pvt_thread_mutex_unlock( &connections_mutex );
	return 0;
}

static int
connection_input(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
704
705
706
    Connection *conn
)
{
707
	Operation *op;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
708
709
710
711
712
713
714
	unsigned long	tag, len;
	long		msgid;
	BerElement	*ber;

	if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
	    == NULL ) {
		Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
715
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
716
717
718
719
	}

	errno = 0;
	if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
720
721
	    != LDAP_TAG_MESSAGE )
	{
722
723
		int err = errno;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
724
		Debug( LDAP_DEBUG_TRACE,
725
			"ber_get_next on fd %d failed errno %d (%s)\n",
726
727
			lber_pvt_sb_get_desc(&conn->c_sb), err,
			err > -1 && err < sys_nerr ?  sys_errlist[err] : "unknown" );
728
729
		Debug( LDAP_DEBUG_TRACE,
			"\t*** got %ld of %lu so far\n",
730
731
			(long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf),
			conn->c_currentber->ber_len, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
732

733
		if ( err != EWOULDBLOCK && err != EAGAIN ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
734
735
736
737
			/* log, close and send error */
			ber_free( conn->c_currentber, 1 );
			conn->c_currentber = NULL;

738
			return -2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
739
		}
740
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
741
	}
742

Kurt Zeilenga's avatar
Kurt Zeilenga committed
743
744
745
746
747
	ber = conn->c_currentber;
	conn->c_currentber = NULL;

	if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
		/* log, close and send error */
748
		Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
749
750
		    0 );
		ber_free( ber, 1 );
751
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
752
753
754
755
	}

	if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
		/* log, close and send error */
756
		Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%lx\n", tag, 0,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
757
758
759
		    0 );
		ber_free( ber, 1 );

760
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
761
762
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
763
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
764
765
766
767
768
	if ( conn->c_version == 30 ) {
		(void) ber_skip_tag( ber, &len );
	}
#endif

769
	op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
770

771
772
773
	if ( conn->c_conn_state == SLAP_C_BINDING
		|| conn->c_conn_state == SLAP_C_CLOSING )
	{
774
		Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 );
775
		slap_op_add( &conn->c_pending_ops, op );
776

777
778
779
	} else {
		connection_op_activate( conn, op );
	}
780

781
782
783
784
#ifdef NO_THREADS
	if ( conn->c_struct_state != SLAP_C_USED ) {
		/* connection must have got closed underneath us */
		return 1;
785
	}
786
787
#endif
	assert( conn->c_struct_state == SLAP_C_USED );
788

789
	return 0;
790
791
792
793
794
795
796
}

static int
connection_resched( Connection *conn )
{
	Operation *op;

797
	if( conn->c_conn_state != SLAP_C_ACTIVE ) {
798
		/* other states need different handling */
Gary Williams's avatar
NT port    
Gary Williams committed
799
		return 0;
800
801
802
803
804
805
	}

	for( op = slap_op_pop( &conn->c_pending_ops );
		op != NULL;
		op = slap_op_pop( &conn->c_pending_ops ) )
	{
806
807
808
		/* pending operations should not be marked for abandonment */
		assert(!op->o_abandon);

809
810
		connection_op_activate( conn, op );

811
		if ( conn->c_conn_state == SLAP_C_BINDING ) {
812
813
814
			break;
		}
	}
Gary Williams's avatar
NT port    
Gary Williams committed
815
	return 0;
816
817
818
819
820
821
822
823
}

static int connection_op_activate( Connection *conn, Operation *op )
{
	struct co_arg *arg;
	char *tmpdn;
	int status;
	unsigned long tag = op->o_tag;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
824
825

	if ( conn->c_dn != NULL ) {
826
		tmpdn = ch_strdup( conn->c_dn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
827
828
829
830
	} else {
		tmpdn = NULL;
	}

831
832
833
834
835
836
837
838
839
840
	arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
	arg->co_conn = conn;
	arg->co_op = op;

	arg->co_op->o_dn = ch_strdup( tmpdn != NULL ? tmpdn : "" );
	arg->co_op->o_ndn = dn_normalize_case( ch_strdup( arg->co_op->o_dn ) );

	slap_op_add( &conn->c_ops, arg->co_op );

	if(tag == LDAP_REQ_BIND) {
841
		conn->c_conn_state = SLAP_C_BINDING;
842
843
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
844
845
846
847
	if ( tmpdn != NULL ) {
		free( tmpdn );
	}

848
849
850
851
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

852
853
	status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
					 connection_operation, (void *) arg );
854

855
	if ( status != 0 ) {
856
857
858
859
		Debug( LDAP_DEBUG_ANY,
		"ldap_pvt_thread_create failed (%d)\n", status, 0, 0 );

		/* should move op to pending list */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
860
	}
861
862

	return status;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
863
}
864
865
866
867
868
869
870
871
872
873
874
875
876

int connection_write(int s)
{
	Connection *c;
	assert( connections != NULL );

	ldap_pvt_thread_mutex_lock( &connections_mutex );

	c = connection_get( s );
	if( c == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"connection_write(%d): no connection!\n",
			s, 0, 0 );
877
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
878
879
880
881
882
883
884
885
886
887
888
889
890
		return -1;
	}

	Debug( LDAP_DEBUG_TRACE,
		"connection_write(%d): waking output for id=%ld\n",
		s, c->c_connid, 0 );

	ldap_pvt_thread_cond_signal( &c->c_write_cv );

	connection_return( c );
	ldap_pvt_thread_mutex_unlock( &connections_mutex );
	return 0;
}