connection.c 19.9 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
/* protected by connections_mutex */
static ldap_pvt_thread_mutex_t connections_mutex;
static Connection *connections = NULL;
static long conn_nextid = 0;

21
/* structure state (protected by connections_mutex) */
22
23
24
#define SLAP_C_UNINITIALIZED	0x00	/* MUST BE ZERO (0) */
#define SLAP_C_UNUSED			0x01
#define SLAP_C_USED				0x02
25
26

/* connection state (protected by c_mutex ) */
27
28
29
30
31
#define SLAP_C_INVALID			0x00	/* MUST BE ZERO (0) */
#define SLAP_C_INACTIVE			0x01	/* zero threads */
#define SLAP_C_ACTIVE			0x02	/* one or more threads */
#define SLAP_C_BINDING			0x03	/* binding */
#define SLAP_C_CLOSING			0x04	/* closing */
32

Gary Williams's avatar
NT port    
Gary Williams committed
33
void slapd_remove(int s);
34
35
36
static Connection* connection_get( int s );

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

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

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

47
48
49
50
51
52
53
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
{
	assert( connections == NULL );

54
	if( connections != NULL) {
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
		Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n",
			0, 0, 0 );
		return -1;
	}

	/* should check return of every call */
	ldap_pvt_thread_mutex_init( &connections_mutex );

	connections = (Connection *) calloc( dtblsize, sizeof(Connection) );

	if( connections == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"connections_init: allocation (%d*%ld) of connection array failed.\n",
			dtblsize, (long) sizeof(Connection), 0 );
		return -1;
	}

72
73
74
    assert( connections[0].c_struct_state == SLAP_C_UNINITIALIZED );
    assert( connections[dtblsize-1].c_struct_state == SLAP_C_UNINITIALIZED );

75
76
77
78
79
80
81
82
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
 * Destroy connection management infrastructure.
 */
int connections_destroy(void)
{
	int i;

	/* should check return of every call */

	if( connections == NULL) {
		Debug( LDAP_DEBUG_ANY, "connections_destroy: nothing to destroy.\n",
			0, 0, 0 );
		return -1;
	}

	for ( i = 0; i < dtblsize; i++ ) {
99
100
101
102
103
		if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
			ldap_pvt_thread_mutex_destroy( &connections[i].c_mutex );
			ldap_pvt_thread_mutex_destroy( &connections[i].c_write_mutex );
			ldap_pvt_thread_cond_destroy( &connections[i].c_write_cv );
		}
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
	}

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

		/* connections_mutex and c_mutex are locked */
130
131
		connection_closing( &connections[i] );
		connection_close( &connections[i] );
132

133
134
135
136
		ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
	}

	ldap_pvt_thread_mutex_unlock( &connections_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
137
138

	return 0;
139
140
}

141
142
static Connection* connection_get( int s )
{
143
144
	/* connections_mutex should be locked by caller */

145
146
147
148
149
150
151
152
153
154
155
	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 );
156
	assert( ber_pvt_sb_in_use( connections[s].c_sb ) );
157
158
159
160
161
162
163

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

		for(i=0; i<dtblsize; i++) {
Gary Williams's avatar
NT port    
Gary Williams committed
164
			if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
165
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
166
				assert( connections[i].c_sb == 0 );
167
168
169
				break;
			}

Gary Williams's avatar
NT port    
Gary Williams committed
170
			if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
171
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172
				assert( !ber_pvt_sb_in_use( connections[i].c_sb ) );
173
174
175
				continue;
			}

Gary Williams's avatar
NT port    
Gary Williams committed
176
			assert( connections[i].c_struct_state == SLAP_C_USED );
177
			assert( connections[i].c_conn_state != SLAP_C_INVALID );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
178
			assert( ber_pvt_sb_in_use( connections[i].c_sb ) );
179

Kurt Zeilenga's avatar
Kurt Zeilenga committed
180
			if( ber_pvt_sb_get_desc( connections[i].c_sb ) == s ) {
Gary Williams's avatar
NT port    
Gary Williams committed
181
				c = &connections[i];
182
183
184
185
186
				break;
			}
		}
	}
#endif
187

188
	if( c != NULL ) {
189
190
191
192
193
		/* 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 );

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
228
229
230
		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
231
232
        for( i=0; i < dtblsize; i++) {
            if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
233
                assert( connections[i].c_sb == 0 );
Gary Williams's avatar
NT port    
Gary Williams committed
234
235
236
237
238
                c = &connections[i];
                break;
            }

            if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
239
                assert( !ber_pvt_sb_in_use( connections[i].c_sb ));
Gary Williams's avatar
NT port    
Gary Williams committed
240
241
242
243
244
245
                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
246
            assert( ber_pvt_sb_in_use( connections[i].c_sb ));
Gary Williams's avatar
NT port    
Gary Williams committed
247
248
249
250
251
252
253
        }

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

Gary Williams's avatar
NT port    
Gary Williams committed
256
257
258
    assert( c != NULL );
    assert( c->c_struct_state != SLAP_C_USED );
    assert( c->c_conn_state == SLAP_C_INVALID );
259

Gary Williams's avatar
NT port    
Gary Williams committed
260
261
262
263
264
265
266
    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;
267

Kurt Zeilenga's avatar
Kurt Zeilenga committed
268
        c->c_sb = ber_sockbuf_alloc( );
269

Gary Williams's avatar
NT port    
Gary Williams committed
270
271
272
273
        /* 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 );
274

Gary Williams's avatar
NT port    
Gary Williams committed
275
276
        c->c_struct_state = SLAP_C_UNUSED;
    }
277

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

Gary Williams's avatar
NT port    
Gary Williams committed
280
281
282
283
284
285
286
    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 );
287

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

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
300
301
    ber_pvt_sb_set_desc( c->c_sb, s );
    ber_pvt_sb_set_io( c->c_sb, &ber_pvt_sb_io_tcp, NULL );
302

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

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

Gary Williams's avatar
NT port    
Gary Williams committed
311
312
    c->c_conn_state = SLAP_C_INACTIVE;
    c->c_struct_state = SLAP_C_USED;
313

Gary Williams's avatar
NT port    
Gary Williams committed
314
315
    ldap_pvt_thread_mutex_unlock( &c->c_mutex );
    ldap_pvt_thread_mutex_unlock( &connections_mutex );
316

Gary Williams's avatar
NT port    
Gary Williams committed
317
    return id;
318
319
320
321
322
}

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

Gary Williams's avatar
NT port    
Gary Williams committed
325
326
327
328
329
    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 );
330

Gary Williams's avatar
NT port    
Gary Williams committed
331
332
    c->c_struct_state = SLAP_C_UNUSED;
    c->c_conn_state = SLAP_C_INVALID;
333

Kurt Zeilenga's avatar
ldap.h:    
Kurt Zeilenga committed
334
#ifdef LDAP_COMPAT30
Gary Williams's avatar
NT port    
Gary Williams committed
335
    c->c_version = 0;
Kurt Zeilenga's avatar
ldap.h:    
Kurt Zeilenga committed
336
#endif
Gary Williams's avatar
NT port    
Gary Williams committed
337
    c->c_protocol = 0;
338

Gary Williams's avatar
NT port    
Gary Williams committed
339
    c->c_starttime = 0;
340

Gary Williams's avatar
NT port    
Gary Williams committed
341
342
343
344
    if(c->c_dn != NULL) {
        free(c->c_dn);
        c->c_dn = NULL;
    }
345
346
347
348
349
350
351
352
353
354
355
356
357
	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
358
359
	if ( ber_pvt_sb_in_use(c->c_sb) ) {
		int sd = ber_pvt_sb_get_desc(c->c_sb);
360
361

		slapd_remove( sd );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
362
	   	ber_pvt_sb_close( c->c_sb );
363
364
365
366
367
368

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
369
   	ber_pvt_sb_destroy( c->c_sb );
370
371
}

372
373
int connection_state_closing( Connection *c )
{
374
375
	/* c_mutex must be locked by caller */

376
	int state;
377
378
379
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );

380
381
382
383
384
	state = c->c_conn_state;

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
385
386
}

387
388
389
390
391
392
393
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 );

394
395
	/* c_mutex must be locked by caller */

396
	if( c->c_conn_state != SLAP_C_CLOSING ) {
397
398
399
400
		Operation *o;

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
403
404
405
		/* update state to closing */
		c->c_conn_state = SLAP_C_CLOSING;

406
		/* don't listen on this port anymore */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
407
		slapd_clr_read( ber_pvt_sb_get_desc( c->c_sb ), 1 );
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

		/* 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
427
		slapd_clr_write( ber_pvt_sb_get_desc(c->c_sb), 1 );
428
		ldap_pvt_thread_cond_signal( &c->c_write_cv );
429
430
431
	}
}

432
433
434
435
436
437
438
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 );

439
	/* note: connections_mutex and c_mutex should be locked by caller */
440

441
442
443
	if( c->c_ops != NULL ) {
		Debug( LDAP_DEBUG_TRACE,
			"connection_close: deferring conn=%ld sd=%d.\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
444
			c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
445
446
447
448
449

		return;
	}

	Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
450
		c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468

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

469
Connection* connection_first( int *index )
470
471
{
	assert( connections != NULL );
472
	assert( index != NULL );
473
474
475

	ldap_pvt_thread_mutex_lock( &connections_mutex );

476
	*index = 0;
477

478
	return connection_next(NULL, index);
479
480
}

481
Connection* connection_next( Connection *c, int *index )
482
483
{
	assert( connections != NULL );
484
485
	assert( index != NULL );
	assert( *index <= dtblsize );
486
487
488
489
490
491
492

	if( c != NULL ) {
		ldap_pvt_thread_mutex_unlock( &c->c_mutex );
	}

	c = NULL;

493
494
495
	for(; *index < dtblsize; (*index)++) {
		if( connections[*index].c_struct_state == SLAP_C_UNINITIALIZED ) {
			assert( connections[*index].c_conn_state == SLAP_C_INVALID );
496
497
498
499
500
501
502
#ifndef HAVE_WINSOCK
			continue;
#else
			break;
#endif
		}

503
504
505
		if( connections[*index].c_struct_state == SLAP_C_USED ) {
			assert( connections[*index].c_conn_state != SLAP_C_INVALID );
			c = &connections[(*index)++];
506
507
508
			break;
		}

509
510
		assert( connections[*index].c_struct_state == SLAP_C_UNUSED );
		assert( connections[*index].c_conn_state == SLAP_C_INVALID );
511
512
513
514
515
516
517
518
519
	}

	if( c != NULL ) {
		ldap_pvt_thread_mutex_lock( &c->c_mutex );
	}

	return c;
}

520
void connection_done( Connection *c )
521
522
523
524
525
526
527
528
529
530
{
	assert( connections != NULL );

	if( c != NULL ) {
		ldap_pvt_thread_mutex_unlock( &c->c_mutex );
	}

	ldap_pvt_thread_mutex_unlock( &connections_mutex );
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
531
532
533
534
535
536
/*
 * 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.
 */

537
538
static void *
connection_operation( void *arg_v )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
539
{
540
	struct co_arg	*arg = arg_v;
541
542
	int tag = arg->co_op->o_tag;
	Connection *conn = arg->co_conn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
543

544
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
545
546
547
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_initiated++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
548
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549

550
	switch ( tag ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
551
	case LDAP_REQ_BIND:
552
		do_bind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
553
554
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
555
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
557
558
	case LDAP_REQ_UNBIND_30:
#endif
	case LDAP_REQ_UNBIND:
559
		do_unbind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
560
561
562
		break;

	case LDAP_REQ_ADD:
563
		do_add( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
564
565
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
566
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
567
568
569
	case LDAP_REQ_DELETE_30:
#endif
	case LDAP_REQ_DELETE:
570
		do_delete( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
571
572
573
		break;

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

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

	case LDAP_REQ_COMPARE:
582
		do_compare( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
583
584
585
		break;

	case LDAP_REQ_SEARCH:
586
		do_search( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
587
588
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
589
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
590
591
592
	case LDAP_REQ_ABANDON_30:
#endif
	case LDAP_REQ_ABANDON:
593
		do_abandon( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
594
595
596
		break;

	default:
597
		Debug( LDAP_DEBUG_ANY, "unknown request 0x%lx\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
598
599
600
601
		    arg->co_op->o_tag, 0, 0 );
		break;
	}

602
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
603
604
605
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_completed++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
606
607
608
#endif

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
609

610
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
611
	conn->c_n_ops_completed++;
612
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
613

614
615
616
	slap_op_remove( &conn->c_ops, arg->co_op );
	slap_op_free( arg->co_op );
	arg->co_op = NULL;
617
	arg->co_conn = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
618
	free( (char *) arg );
619
	arg = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
620

621
622
623
624
625
	switch( tag ) {
#ifdef LDAP_COMPAT30
	case LDAP_REQ_UNBIND_30:
#endif
	case LDAP_REQ_UNBIND:
626
		/* c_mutex is locked */
627
		connection_closing( conn );
628
629
630
631
632
633
		break;

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

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

	connection_resched( conn );

645
646
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

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

650
651
652
653
654
655
656
657
int connection_read(int s)
{
	int rc = 0;
	Connection *c;
	assert( connections != NULL );

	ldap_pvt_thread_mutex_lock( &connections_mutex );

658
	/* get (locked) connection */
659
	c = connection_get( s );
660

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

804
805
806
807
808
809
810
811
812
	if( conn->c_conn_state == SLAP_C_CLOSING ) {
		Debug( LDAP_DEBUG_TRACE,
			"connection_resched: attempting closing conn=%ld sd=%d.\n",
			conn->c_connid, ber_pvt_sb_get_desc( conn->c_sb ), 0 );

		connection_close( conn );
		return 0;
	}

813
	if( conn->c_conn_state != SLAP_C_ACTIVE ) {
814
		/* other states need different handling */
Gary Williams's avatar
NT port    
Gary Williams committed
815
		return 0;
816
817
818
819
820
821
	}

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

825
826
		connection_op_activate( conn, op );

827
		if ( conn->c_conn_state == SLAP_C_BINDING ) {
828
829
830
			break;
		}
	}
Gary Williams's avatar
NT port    
Gary Williams committed
831
	return 0;
832
833
834
835
836
837
838
839
}

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
840
841

	if ( conn->c_dn != NULL ) {
842
		tmpdn = ch_strdup( conn->c_dn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
843
844
845
846
	} else {
		tmpdn = NULL;
	}

847
848
849
850
851
852
853
854
855
856
	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) {
857
		conn->c_conn_state = SLAP_C_BINDING;
858
859
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
860
861
862
863
	if ( tmpdn != NULL ) {
		free( tmpdn );
	}

864
865
866
867
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

868
869
	status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
					 connection_operation, (void *) arg );
870

871
	if ( status != 0 ) {
872
873
874
875
		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
876
	}
877
878

	return status;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
879
}
880
881
882
883
884
885
886
887
888
889
890
891
892

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 );
893
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
894
895
896
897
898
899
900
901
902
903
904
905
906
		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;
}