connection.c 19.7 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
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
static Connection* connection_get( int s )
{
140
141
	/* connections_mutex should be locked by caller */

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

	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 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
163
				assert( connections[i].c_sb == 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 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
169
				assert( !ber_pvt_sb_in_use( connections[i].c_sb ) );
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 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
175
			assert( ber_pvt_sb_in_use( connections[i].c_sb ) );
176

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

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

        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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
265
        c->c_sb = ber_sockbuf_alloc( );
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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
300
    if( ber_pvt_sb_set_nonblock( c->c_sb, 1 ) < 0 ) {
Gary Williams's avatar
NT port    
Gary Williams committed
301
302
303
304
        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 )
{
320
321
	/* note: connections_mutex should be locked by caller */

Gary Williams's avatar
NT port    
Gary Williams committed
322
323
324
325
326
    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 );
327

Gary Williams's avatar
NT port    
Gary Williams committed
328
329
    c->c_struct_state = SLAP_C_UNUSED;
    c->c_conn_state = SLAP_C_INVALID;
330

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

Gary Williams's avatar
NT port    
Gary Williams committed
336
    c->c_starttime = 0;
337

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

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

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

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

369
370
int connection_state_closing( Connection *c )
{
371
372
	/* c_mutex must be locked by caller */

373
	int state;
374
375
376
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );

377
378
379
380
381
	state = c->c_conn_state;

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
382
383
}

384
385
386
387
388
389
390
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 );

391
392
	/* c_mutex must be locked by caller */

393
	if( c->c_conn_state != SLAP_C_CLOSING ) {
394
395
396
397
		Operation *o;

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
400
401
402
		/* update state to closing */
		c->c_conn_state = SLAP_C_CLOSING;

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

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

429
430
431
432
433
434
435
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 );

436
	/* note: connections_mutex and c_mutex should be locked by caller */
437

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

		return;
	}

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

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

466
Connection* connection_first( int *index )
467
468
{
	assert( connections != NULL );
469
	assert( index != NULL );
470
471
472

	ldap_pvt_thread_mutex_lock( &connections_mutex );

473
	*index = 0;
474

475
	return connection_next(NULL, index);
476
477
}

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

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

	c = NULL;

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

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

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

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

	return c;
}

517
void connection_done( Connection *c )
518
519
520
521
522
523
524
525
526
527
{
	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
528
529
530
531
532
533
/*
 * 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.
 */

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

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

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

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

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

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

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

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

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

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

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

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

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

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
606

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

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

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

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

632
633
634
	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
635
			conn->c_connid, ber_pvt_sb_get_desc( conn->c_sb ), 0 );
636
637
638

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

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

	connection_resched( conn );

649
650
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

651
	return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
652
653
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

817
818
		connection_op_activate( conn, op );

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

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
832
833

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

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

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

856
857
858
859
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

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

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

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

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