connection.c 19.5 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
		Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n",
			0, 0, 0 );
		return -1;
	}

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

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

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

Gary Williams's avatar
NT port    
Gary Williams committed
75
76
77
	for ( i = 0; i < dtblsize; i++ )
		memset( &connections[i], 0, sizeof(Connection) );

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

	return 0;
}

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

	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
137
138

	return 0;
139
140
}

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

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

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

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

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

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

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

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

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

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

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
266
        c->c_sb = ber_sockbuf_alloc( );
267

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	assert( state != SLAP_C_INVALID );

	return state == SLAP_C_CLOSING;
380
381
}

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

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

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

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

		/* 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
420
		slapd_clr_write( ber_pvt_sb_get_desc(c->c_sb), 1 );
421
		ldap_pvt_thread_cond_signal( &c->c_write_cv );
422
423
424
	}
}

425
426
427
428
429
430
431
432
433
434
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",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
435
			c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
436
437
438
439
440

		return;
	}

	Debug( LDAP_DEBUG_TRACE, "connection_close: 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
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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
603

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

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

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

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

629
630
631
	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
632
			conn->c_connid, ber_pvt_sb_get_desc( conn->c_sb ), 0 );
633
634
635

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

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

	connection_resched( conn );

646
647
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

814
815
		connection_op_activate( conn, op );

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

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

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

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

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

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

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

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

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

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