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 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
334
335
336
		/* update state to closing */
		c->c_conn_state = SLAP_C_CLOSING;

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

		/* 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 */
358
		slapd_clr_write( c->c_sb.sb_sd, 1 );
359
		ldap_pvt_thread_cond_signal( &c->c_write_cv );
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
460
461
462
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
463
464
465
466
467
468
/*
 * 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.
 */

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

476
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
477
478
479
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_initiated++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
480
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
481

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

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

	case LDAP_REQ_ADD:
495
		do_add( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
496
497
		break;

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

	case LDAP_REQ_MODRDN:
506
		do_modrdn( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
507
508
509
		break;

	case LDAP_REQ_MODIFY:
510
		do_modify( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
511
512
513
		break;

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

	case LDAP_REQ_SEARCH:
518
		do_search( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
519
520
		break;

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

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

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

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
541

542
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
543
	conn->c_n_ops_completed++;
544
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
545

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

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

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

567
568
569
570
571
572
573
	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
574

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

	connection_resched( conn );

584
585
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

586
	return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
587
588
}

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

606
607
608
609
610
611
612
613
614
615
	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;
	}

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

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

	errno = 0;
	if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
663
664
	    != LDAP_TAG_MESSAGE )
	{
665
666
		int err = errno;

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

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

681
			return -2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
682
		}
683
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
684
	}
685

Kurt Zeilenga's avatar
Kurt Zeilenga committed
686
687
688
689
690
	ber = conn->c_currentber;
	conn->c_currentber = NULL;

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

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

703
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
704
705
	}

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

712
	op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
713

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

720
721
722
	} else {
		connection_op_activate( conn, op );
	}
723

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

732
	return 0;
733
734
735
736
737
738
739
}

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

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

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

752
753
		connection_op_activate( conn, op );

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

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
767
768

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
787
788
789
790
	if ( tmpdn != NULL ) {
		free( tmpdn );
	}

791
792
793
794
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

795
796
	status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
					 connection_operation, (void *) arg );
797

798
	if ( status != 0 ) {
799
800
801
802
		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
803
	}
804
805

	return status;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
806
}
807
808
809
810
811
812
813
814
815
816
817
818
819

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