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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
13
14
15
/* we need LBER internals */
#include "../../libraries/liblber/lber-int.h"

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

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

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

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
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
{
	int i;

	assert( connections == NULL );

57
	if( connections != NULL) {
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
		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;
	}

	/*
	 * 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
	}

	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 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
134
135

	return 0;
136
137
}

138
139
140
141
142
143
144
145
146
147
148
149
150
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 );
151
	assert( ber_pvt_sb_in_use( connections[s].c_sb ) );
152
153
154
155
156
157
158

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

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

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

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

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

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

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

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

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

	if( s < 0 ) {
		return -1;
	}

	assert( s >= 0 );
#ifndef HAVE_WINSOCK
	assert( s < dtblsize );
#endif

	ldap_pvt_thread_mutex_lock( &connections_mutex );

#ifndef HAVE_WINSOCK
	c = &connections[s];

#else
	{
		int i;

Gary Williams's avatar
NT port    
Gary Williams committed
226
227
        for( i=0; i < dtblsize; i++) {
            if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
228
                assert( connections[i].c_sb == 0 );
Gary Williams's avatar
NT port    
Gary Williams committed
229
230
231
232
233
                c = &connections[i];
                break;
            }

            if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
234
                assert( !ber_pvt_sb_in_use( connections[i].c_sb ));
Gary Williams's avatar
NT port    
Gary Williams committed
235
236
237
238
239
240
                c = &connections[i];
                break;
            }

            assert( connections[i].c_struct_state == SLAP_C_USED );
            assert( connections[i].c_conn_state != SLAP_C_INVALID );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
241
            assert( ber_pvt_sb_in_use( connections[i].c_sb ));
Gary Williams's avatar
NT port    
Gary Williams committed
242
243
244
245
246
247
248
        }

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

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
263
        c->c_sb = ber_sockbuf_alloc( );
264

Gary Williams's avatar
NT port    
Gary Williams committed
265
266
267
268
        /* should check status of thread calls */
        ldap_pvt_thread_mutex_init( &c->c_mutex );
        ldap_pvt_thread_mutex_init( &c->c_write_mutex );
        ldap_pvt_thread_cond_init( &c->c_write_cv );
269

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

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

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

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

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
295
296
    ber_pvt_sb_set_desc( c->c_sb, s );
    ber_pvt_sb_set_io( c->c_sb, &ber_pvt_sb_io_tcp, NULL );
297

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

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

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

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

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

static void
connection_destroy( Connection *c )
{
318
319
	/* note: connections_mutex should be locked by caller */

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

Kurt Zeilenga's avatar
ldap.h:    
Kurt Zeilenga committed
329
#ifdef LDAP_COMPAT30
Gary Williams's avatar
NT port    
Gary Williams committed
330
    c->c_version = 0;
Kurt Zeilenga's avatar
ldap.h:    
Kurt Zeilenga committed
331
#endif
Gary Williams's avatar
NT port    
Gary Williams committed
332
    c->c_protocol = 0;
333

Gary Williams's avatar
NT port    
Gary Williams committed
334
    c->c_starttime = 0;
335

Gary Williams's avatar
NT port    
Gary Williams committed
336
337
338
339
    if(c->c_dn != NULL) {
        free(c->c_dn);
        c->c_dn = NULL;
    }
340
341
342
343
344
345
346
347
348
349
350
351
352
	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;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
353
354
	if ( ber_pvt_sb_in_use(c->c_sb) ) {
		int sd = ber_pvt_sb_get_desc(c->c_sb);
355
356

		slapd_remove( sd );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
357
	   	ber_pvt_sb_close( c->c_sb );
358
359
360
361
362
363

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
364
   	ber_pvt_sb_destroy( c->c_sb );
365
366
}

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

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

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
379
380
}

381
382
383
384
385
386
387
388
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 ) {
389
390
391
392
		Operation *o;

		Debug( LDAP_DEBUG_TRACE,
			"connection_closing: readying conn=%ld sd=%d for close.\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
393
			c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
394

Kurt Zeilenga's avatar
Kurt Zeilenga committed
395
396
397
		/* update state to closing */
		c->c_conn_state = SLAP_C_CLOSING;

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

		/* 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 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
419
		slapd_clr_write( ber_pvt_sb_get_desc(c->c_sb), 1 );
420
		ldap_pvt_thread_cond_signal( &c->c_write_cv );
421
422
423
	}
}

424
425
426
427
428
429
430
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 );

431
432
	/* note: connections_mutex should be locked by caller */

433
434
435
	if( c->c_ops != NULL ) {
		Debug( LDAP_DEBUG_TRACE,
			"connection_close: deferring conn=%ld sd=%d.\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
436
			c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
437
438
439
440
441

		return;
	}

	Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
442
		c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
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
523
524
525

	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
526
527
528
529
530
531
/*
 * 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.
 */

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

539
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
540
541
542
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_initiated++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
543
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
544

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

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

	case LDAP_REQ_ADD:
558
		do_add( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
559
560
		break;

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

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

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

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

	case LDAP_REQ_SEARCH:
581
		do_search( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
582
583
		break;

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

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

597
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
598
599
600
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_completed++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
601
602
603
#endif

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
604

605
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
606
	conn->c_n_ops_completed++;
607
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
608

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

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

	case LDAP_REQ_BIND:
		if( conn->c_conn_state == SLAP_C_BINDING) {
			conn->c_conn_state = SLAP_C_ACTIVE;
		}
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",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
633
			conn->c_connid, ber_pvt_sb_get_desc( conn->c_sb ), 0 );
634
635
636

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

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

	connection_resched( conn );

647
648
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

649
	return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
650
651
}

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

669
670
671
672
673
674
675
676
677
678
	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;
	}

679
680
681
682
683
684
685
	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
Kurt Zeilenga's avatar
Kurt Zeilenga committed
686
	while(!rc && ber_pvt_sb_data_ready(&c->c_sb))
687
688
689
690
691
692
693
694
695
#elif CONNECTION_INPUT_LOOP
	while(!rc)
#endif
	{
		rc = connection_input( c );
	}

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

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

	errno = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
725
	if ( (tag = ber_get_next( conn->c_sb, &len, conn->c_currentber ))
726
727
	    != LDAP_TAG_MESSAGE )
	{
728
729
		int err = errno;

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

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

744
			return -2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
745
		}
746
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
747
	}
748

Kurt Zeilenga's avatar
Kurt Zeilenga committed
749
750
751
752
753
	ber = conn->c_currentber;
	conn->c_currentber = NULL;

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

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

766
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
767
768
	}

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

775
	op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
776

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

783
784
785
	} else {
		connection_op_activate( conn, op );
	}
786

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

795
	return 0;
796
797
798
799
800
801
802
}

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

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

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

815
816
		connection_op_activate( conn, op );

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

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
830
831

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
850
851
852
853
	if ( tmpdn != NULL ) {
		free( tmpdn );
	}

854
855
856
857
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

858
859
	status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
					 connection_operation, (void *) arg );
860

861
	if ( status != 0 ) {
862
863
864
865
		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
866
	}
867
868

	return status;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
869
}
870
871
872
873
874
875
876
877
878
879
880
881
882

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