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"

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
static Connection* connection_get( int s );

static int connection_input( Connection *c );
39
static void connection_close( Connection *c );
40

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

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

49
50
51
52
53
54
55
56
57
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
{
	int i;

	assert( connections == NULL );

58
	if( connections != NULL) {
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
		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
76
77
78
	for ( i = 0; i < dtblsize; i++ )
		memset( &connections[i], 0, sizeof(Connection) );

79
80
81
82
83
84
85
86
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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
138
139
/*
 * 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++ ) {
		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 );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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
363
364
	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 );
}

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

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

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
377
378
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
600

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

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

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

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

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

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

	connection_resched( conn );

643
644
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

811
812
		connection_op_activate( conn, op );

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

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

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

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

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

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

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

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

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

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