connection.c 19.4 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
#include "portable.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
4

#include <stdio.h>

5
#include <ac/socket.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
#include <ac/errno.h>
#include <ac/signal.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

		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 );
136
    return 0;
137
138
}

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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
160
			if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
161
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
162
				assert( connections[i].c_sb.sb_sd == 0 );
163
164
165
				break;
			}

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

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

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

184
	if( c != NULL ) {
185
186
187
188
189
		/* 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 );

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
226
		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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
        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;
        }
    }
250
251
#endif

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

Gary Williams's avatar
NT port    
Gary Williams committed
256
257
258
259
260
261
262
    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;
263

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

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

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

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

Gary Williams's avatar
NT port    
Gary Williams committed
276
277
278
279
280
281
282
    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 );
283

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

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

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

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

Gary Williams's avatar
NT port    
Gary Williams committed
299
300
301
302
303
    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);
    }
304

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

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

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

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

static void
connection_destroy( Connection *c )
{
Gary Williams's avatar
NT port    
Gary Williams committed
319
320
321
322
323
    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 );
324

325
	ldap_pvt_thread_mutex_lock( &connections_mutex );
Gary Williams's avatar
NT port    
Gary Williams committed
326
327
    c->c_struct_state = SLAP_C_UNUSED;
    c->c_conn_state = SLAP_C_INVALID;
328

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

Gary Williams's avatar
NT port    
Gary Williams committed
332
    c->c_starttime = 0;
333

Gary Williams's avatar
NT port    
Gary Williams committed
334
335
336
337
    if(c->c_dn != NULL) {
        free(c->c_dn);
        c->c_dn = NULL;
    }
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
	ldap_pvt_thread_mutex_unlock( &connections_mutex );
364
365
}

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

373
374
375
376
377
	state = c->c_conn_state;

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
378
379
}

380
381
382
383
384
385
386
387
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 ) {
388
389
390
391
392
393
		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
394
395
396
		/* update state to closing */
		c->c_conn_state = SLAP_C_CLOSING;

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

		/* 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 */
418
		slapd_clr_write( c->c_sb.sb_sd, 1 );
419
		ldap_pvt_thread_cond_signal( &c->c_write_cv );
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
520
521
522
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
523
524
525
526
527
528
/*
 * 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.
 */

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

536
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
537
538
539
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_initiated++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
540
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
541

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

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

	case LDAP_REQ_ADD:
555
		do_add( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
557
		break;

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

	case LDAP_REQ_MODRDN:
566
		do_modrdn( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
567
568
569
		break;

	case LDAP_REQ_MODIFY:
570
		do_modify( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
571
572
573
		break;

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

	case LDAP_REQ_SEARCH:
578
		do_search( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
579
580
		break;

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

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

594
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
595
596
597
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_completed++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
598
599
600
#endif

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
601

602
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
603
	conn->c_n_ops_completed++;
604
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
605

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

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

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

627
628
629
630
631
632
633
	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
634

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

	connection_resched( conn );

644
645
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

646
	return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
647
648
}

649
650
651
652
653
654
655
656
657
658
659
660
661
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 );
662
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
663
664
665
		return -1;
	}

666
667
668
669
670
671
672
673
674
675
	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;
	}

676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
	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,
693
694
			"connection_read(%d): input error=%d id=%ld, closing.\n",
			s, rc, c->c_connid );
695

696
		connection_closing( c );
697
698
699
700
701
702
703
704
705
706
		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
707
708
709
    Connection *conn
)
{
710
	Operation *op;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
711
712
713
714
715
716
717
	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 );
718
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
719
720
721
722
	}

	errno = 0;
	if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
723
724
	    != LDAP_TAG_MESSAGE )
	{
725
726
		int err = errno;

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

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

741
			return -2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
742
		}
743
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
744
	}
745

Kurt Zeilenga's avatar
Kurt Zeilenga committed
746
747
748
749
750
	ber = conn->c_currentber;
	conn->c_currentber = NULL;

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

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

763
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
764
765
	}

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

772
	op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
773

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

780
781
782
	} else {
		connection_op_activate( conn, op );
	}
783

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

792
	return 0;
793
794
795
796
797
798
799
}

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

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

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

812
813
		connection_op_activate( conn, op );

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

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
827
828

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

834
835
836
837
838
839
840
841
842
843
	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) {
844
		conn->c_conn_state = SLAP_C_BINDING;
845
846
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
847
848
849
850
	if ( tmpdn != NULL ) {
		free( tmpdn );
	}

851
852
853
854
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

855
856
	status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
					 connection_operation, (void *) arg );
857

858
	if ( status != 0 ) {
859
860
861
862
		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
863
	}
864
865

	return status;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
866
}
867
868
869
870
871
872
873
874
875
876
877
878
879

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 );
880
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
881
882
883
884
885
886
887
888
889
890
891
892
893
		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;
}