connection.c 18.1 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"

Gary Williams's avatar
NT port    
Gary Williams committed
13
14
15
16
#ifdef HAVE_WINSOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#endif

17
18
19
20
21
22
/* 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;

23
24
25
26
27
28
29
30
31
32
33
34
/* 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
35
void slapd_remove(int s);
36
37
38
39
static Connection* connection_get( int s );

static int connection_input( Connection *c );

40
41
42
static int connection_op_activate( Connection *conn, Operation *op );
static int connection_resched( Connection *conn );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
43
44
45
46
47
struct co_arg {
	Connection	*co_conn;
	Operation	*co_op;
};

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
{
	int i;

	assert( connections == NULL );

	if( connections != NULL) { /* probably should assert this */
		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
75
76
77
	for ( i = 0; i < dtblsize; i++ )
		memset( &connections[i], 0, sizeof(Connection) );

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}

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
107
			if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
108
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
109
				assert( connections[i].c_sb.sb_sd == 0 );
110
111
112
				break;
			}

Gary Williams's avatar
NT port    
Gary Williams committed
113
			if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
114
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
115
				assert( connections[i].c_sb.sb_sd == -1 );
116
117
118
				continue;
			}

Gary Williams's avatar
NT port    
Gary Williams committed
119
			assert( connections[i].c_struct_state == SLAP_C_USED );
120
			assert( connections[i].c_conn_state != SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
121
			assert( connections[i].c_sb.sb_sd != -1 );
122
123

			if( connections[i].c_sb.sb_sd == s ) {
Gary Williams's avatar
NT port    
Gary Williams committed
124
				c = &connections[i];
125
126
127
128
129
				break;
			}
		}
	}
#endif
130

131
	if( c != NULL ) {
132
133
134
135
136
		/* 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 );

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
		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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
        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;
        }
    }
197
198
#endif

Gary Williams's avatar
NT port    
Gary Williams committed
199
200
201
    assert( c != NULL );
    assert( c->c_struct_state != SLAP_C_USED );
    assert( c->c_conn_state == SLAP_C_INVALID );
202

Gary Williams's avatar
NT port    
Gary Williams committed
203
204
205
206
207
208
209
    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;
210

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

Gary Williams's avatar
NT port    
Gary Williams committed
213
214
215
216
        /* 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 );
217

Gary Williams's avatar
NT port    
Gary Williams committed
218
219
        c->c_struct_state = SLAP_C_UNUSED;
    }
220

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

Gary Williams's avatar
NT port    
Gary Williams committed
223
224
225
226
227
228
229
    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 );
230

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

Gary Williams's avatar
NT port    
Gary Williams committed
234
    c->c_n_ops_received = 0;
235
#ifdef LDAP_COUNTERS
Gary Williams's avatar
NT port    
Gary Williams committed
236
237
238
    c->c_n_ops_executing = 0;
    c->c_n_ops_pending = 0;
    c->c_n_ops_completed = 0;
239
240
#endif

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

Gary Williams's avatar
NT port    
Gary Williams committed
243
244
    lber_pvt_sb_set_desc( &c->c_sb, s );
    lber_pvt_sb_set_io( &c->c_sb, &lber_pvt_sb_io_tcp, NULL );
245

Gary Williams's avatar
NT port    
Gary Williams committed
246
247
248
249
250
    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);
    }
251

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

Gary Williams's avatar
NT port    
Gary Williams committed
254
255
    c->c_conn_state = SLAP_C_INACTIVE;
    c->c_struct_state = SLAP_C_USED;
256

Gary Williams's avatar
NT port    
Gary Williams committed
257
258
    ldap_pvt_thread_mutex_unlock( &c->c_mutex );
    ldap_pvt_thread_mutex_unlock( &connections_mutex );
259

Gary Williams's avatar
NT port    
Gary Williams committed
260
    return id;
261
262
263
264
265
}

static void
connection_destroy( Connection *c )
{
Gary Williams's avatar
NT port    
Gary Williams committed
266
267
268
269
270
    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 );
271

Gary Williams's avatar
NT port    
Gary Williams committed
272
273
    c->c_struct_state = SLAP_C_UNUSED;
    c->c_conn_state = SLAP_C_INVALID;
274

Gary Williams's avatar
NT port    
Gary Williams committed
275
276
    c->c_version = 0;
    c->c_protocol = 0;
277

Gary Williams's avatar
NT port    
Gary Williams committed
278
    c->c_starttime = 0;
279

Gary Williams's avatar
NT port    
Gary Williams committed
280
281
282
283
    if(c->c_dn != NULL) {
        free(c->c_dn);
        c->c_dn = NULL;
    }
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
	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 );
}

311
312
313
314
315
316
317
318
319
int connection_state_closing( Connection *c )
{
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );
	assert( c->c_conn_state != SLAP_C_INVALID );

	return c->c_conn_state == SLAP_C_CLOSING;
}

320
321
322
323
324
325
326
327
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 ) {
328
329
330
331
332
333
		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 );

334
335
336
		/* don't listen on this port anymore */
		slapd_clr_read( c->c_sb.sb_sd, 1 );
		c->c_conn_state = SLAP_C_CLOSING;
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356

		/* 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 */
		ldap_pvt_thread_cond_signal( &c->c_write_cv );
357
358
359
	}
}

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
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
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
460
461
462
463
464
465
/*
 * 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.
 */

466
467
static void *
connection_operation( void *arg_v )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
468
{
469
	struct co_arg	*arg = arg_v;
470
471
	int tag = arg->co_op->o_tag;
	Connection *conn = arg->co_conn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
472

473
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
474
475
476
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_initiated++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
477
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
478

479
	switch ( tag ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
480
	case LDAP_REQ_BIND:
481
		do_bind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
482
483
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
484
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
485
486
487
	case LDAP_REQ_UNBIND_30:
#endif
	case LDAP_REQ_UNBIND:
488
		do_unbind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
489
490
491
		break;

	case LDAP_REQ_ADD:
492
		do_add( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
493
494
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
495
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
496
497
498
	case LDAP_REQ_DELETE_30:
#endif
	case LDAP_REQ_DELETE:
499
		do_delete( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
500
501
502
		break;

	case LDAP_REQ_MODRDN:
503
		do_modrdn( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
504
505
506
		break;

	case LDAP_REQ_MODIFY:
507
		do_modify( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
508
509
510
		break;

	case LDAP_REQ_COMPARE:
511
		do_compare( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
512
513
514
		break;

	case LDAP_REQ_SEARCH:
515
		do_search( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
516
517
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
518
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
519
520
521
	case LDAP_REQ_ABANDON_30:
#endif
	case LDAP_REQ_ABANDON:
522
		do_abandon( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
523
524
525
		break;

	default:
526
		Debug( LDAP_DEBUG_ANY, "unknown request 0x%lx\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
527
528
529
530
		    arg->co_op->o_tag, 0, 0 );
		break;
	}

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

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
538

539
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
540
	conn->c_n_ops_completed++;
541
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
542

543
544
545
	slap_op_remove( &conn->c_ops, arg->co_op );
	slap_op_free( arg->co_op );
	arg->co_op = NULL;
546
	arg->co_conn = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
547
	free( (char *) arg );
548
	arg = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549

550
551
552
553
554
	switch( tag ) {
#ifdef LDAP_COMPAT30
	case LDAP_REQ_UNBIND_30:
#endif
	case LDAP_REQ_UNBIND:
555
		connection_closing( conn );
556
557
558
559
560
561
		break;

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

564
565
566
567
568
569
570
	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
571

572
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
573
	active_threads--;
574
	if( active_threads < 1 ) {
575
		ldap_pvt_thread_cond_signal(&active_threads_cond);
576
	}
577
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
578
579
580

	connection_resched( conn );

581
582
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

583
	return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
584
585
}

586
587
588
589
590
591
592
593
594
595
596
597
598
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 );
599
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
600
601
602
		return -1;
	}

603
604
605
606
607
608
609
610
611
612
	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;
	}

613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
	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,
630
631
			"connection_read(%d): input error=%d id=%ld, closing.\n",
			s, rc, c->c_connid );
632

633
		connection_closing( c );
634
635
636
637
638
639
640
641
642
643
		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
644
645
646
    Connection *conn
)
{
647
	Operation *op;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
648
649
650
651
652
653
654
	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 );
655
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
656
657
658
659
	}

	errno = 0;
	if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
660
661
	    != LDAP_TAG_MESSAGE )
	{
662
663
		int err = errno;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
664
		Debug( LDAP_DEBUG_TRACE,
665
			"ber_get_next on fd %d failed errno %d (%s)\n",
666
667
			lber_pvt_sb_get_desc(&conn->c_sb), err,
			err > -1 && err < sys_nerr ?  sys_errlist[err] : "unknown" );
668
669
		Debug( LDAP_DEBUG_TRACE,
			"\t*** got %ld of %lu so far\n",
670
671
			(long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf),
			conn->c_currentber->ber_len, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
672

673
		if ( err != EWOULDBLOCK && err != EAGAIN ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
674
675
676
677
			/* log, close and send error */
			ber_free( conn->c_currentber, 1 );
			conn->c_currentber = NULL;

678
			return -2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
679
		}
680
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
681
	}
682

Kurt Zeilenga's avatar
Kurt Zeilenga committed
683
684
685
686
687
	ber = conn->c_currentber;
	conn->c_currentber = NULL;

	if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
		/* log, close and send error */
688
		Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
689
690
		    0 );
		ber_free( ber, 1 );
691
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
692
693
694
695
	}

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

700
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
701
702
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
703
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
704
705
706
707
708
	if ( conn->c_version == 30 ) {
		(void) ber_skip_tag( ber, &len );
	}
#endif

709
	op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
710

711
712
713
	if ( conn->c_conn_state == SLAP_C_BINDING
		|| conn->c_conn_state == SLAP_C_CLOSING )
	{
714
		Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 );
715
		slap_op_add( &conn->c_pending_ops, op );
716

717
718
719
	} else {
		connection_op_activate( conn, op );
	}
720

721
722
723
724
#ifdef NO_THREADS
	if ( conn->c_struct_state != SLAP_C_USED ) {
		/* connection must have got closed underneath us */
		return 1;
725
	}
726
727
#endif
	assert( conn->c_struct_state == SLAP_C_USED );
728

729
	return 0;
730
731
732
733
734
735
736
}

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

737
	if( conn->c_conn_state != SLAP_C_ACTIVE ) {
738
		/* other states need different handling */
Gary Williams's avatar
NT port    
Gary Williams committed
739
		return 0;
740
741
742
743
744
745
	}

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

749
750
		connection_op_activate( conn, op );

751
		if ( conn->c_conn_state == SLAP_C_BINDING ) {
752
753
754
			break;
		}
	}
Gary Williams's avatar
NT port    
Gary Williams committed
755
	return 0;
756
757
758
759
760
761
762
763
}

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
764
765

	if ( conn->c_dn != NULL ) {
766
		tmpdn = ch_strdup( conn->c_dn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
767
768
769
770
	} else {
		tmpdn = NULL;
	}

771
772
773
774
775
776
777
778
779
780
	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) {
781
		conn->c_conn_state = SLAP_C_BINDING;
782
783
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
784
785
786
787
	if ( tmpdn != NULL ) {
		free( tmpdn );
	}

788
789
790
791
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

792
793
	status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
					 connection_operation, (void *) arg );
794

795
	if ( status != 0 ) {
796
797
798
799
		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
800
	}
801
802

	return status;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
803
}
804
805
806
807
808
809
810
811
812
813
814
815
816

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 );
817
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
818
819
820
821
822
823
824
825
826
827
828
829
830
		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;
}