connection.c 17.1 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
#include "portable.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
4
5
6
7
8
9
10

#include <stdio.h>

#include <ac/errno.h>
#include <ac/signal.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
11
12
#include "slap.h"

Gary Williams's avatar
NT port    
Gary Williams committed
13
14
15
16
#ifdef HAVE_WINSOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#endif

17
18
19
20
21
22
/* protected by connections_mutex */
static ldap_pvt_thread_mutex_t connections_mutex;
static Connection *connections = NULL;
static int conn_index = -1;
static long conn_nextid = 0;

23
24
25
26
27
28
29
30
31
32
33
34
/* structure state (protected by connections_mutex) */
#define SLAP_C_UNINITIALIZED	0x0	/* MUST BE ZERO (0) */
#define SLAP_C_UNUSED			0x1
#define SLAP_C_USED				0x2

/* connection state (protected by c_mutex ) */
#define SLAP_C_INVALID			0x0	/* MUST BE ZERO (0) */
#define SLAP_C_INACTIVE			0x1	/* zero threads */
#define SLAP_C_ACTIVE			0x2 /* one or more threads */
#define SLAP_C_BINDING			0x3	/* binding */
#define SLAP_C_CLOSING			0x4	/* closing */

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

static int connection_input( Connection *c );

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
 * Initialize connection management infrastructure.
 */
int connections_init(void)
{
	int i;

	assert( connections == NULL );

	if( connections != NULL) { /* probably should assert this */
		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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
	/*
	 * per entry initialization of the Connection array initialization
	 * will be done by connection_init()
	 */ 

	return 0;
}

static Connection* connection_get( int s )
{
	Connection *c = NULL;

	assert( connections != NULL );

	if(s < 0) {
		return NULL;
	}

#ifndef HAVE_WINSOCK
	assert( connections[s].c_struct_state == SLAP_C_USED );
	assert( connections[s].c_conn_state != SLAP_C_INVALID );
	assert( connections[s].c_sb.sb_sd != -1 );

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

		for(i=0; i<dtblsize; i++) {
Gary Williams's avatar
NT port    
Gary Williams committed
107
			if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
108
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
109
				assert( connections[i].c_sb.sb_sd == 0 );
110
111
112
				break;
			}

Gary Williams's avatar
NT port    
Gary Williams committed
113
			if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
114
				assert( connections[i].c_conn_state == SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
115
				assert( connections[i].c_sb.sb_sd == -1 );
116
117
118
				continue;
			}

Gary Williams's avatar
NT port    
Gary Williams committed
119
			assert( connections[i].c_struct_state == SLAP_C_USED );
120
			assert( connections[i].c_conn_state != SLAP_C_INVALID );
Gary Williams's avatar
NT port    
Gary Williams committed
121
			assert( connections[i].c_sb.sb_sd != -1 );
122
123

			if( connections[i].c_sb.sb_sd == s ) {
Gary Williams's avatar
NT port    
Gary Williams committed
124
				c = &connections[i];
125
126
127
128
129
				break;
			}
		}
	}
#endif
130

131
	if( c != NULL ) {
132
133
134
135
136
		/* 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 );

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
		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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
        for( i=0; i < dtblsize; i++) {
            if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
                assert( connections[i].c_sb.sb_sd == 0 );
                c = &connections[i];
                break;
            }

            if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
                assert( connections[i].c_sb.sb_sd == -1 );
                c = &connections[i];
                break;
            }

            assert( connections[i].c_struct_state == SLAP_C_USED );
            assert( connections[i].c_conn_state != SLAP_C_INVALID );
            assert( connections[i].c_sb.sb_sd != -1 );
        }

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

Gary Williams's avatar
NT port    
Gary Williams committed
199
200
201
    assert( c != NULL );
    assert( c->c_struct_state != SLAP_C_USED );
    assert( c->c_conn_state == SLAP_C_INVALID );
202

Gary Williams's avatar
NT port    
Gary Williams committed
203
204
205
206
207
208
209
    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;
210

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

Gary Williams's avatar
NT port    
Gary Williams committed
213
214
215
216
        /* 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 );
217

Gary Williams's avatar
NT port    
Gary Williams committed
218
219
        c->c_struct_state = SLAP_C_UNUSED;
    }
220

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

Gary Williams's avatar
NT port    
Gary Williams committed
223
224
225
226
227
228
229
    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 );
230

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

Gary Williams's avatar
NT port    
Gary Williams committed
234
    c->c_n_ops_received = 0;
235
#ifdef LDAP_COUNTERS
Gary Williams's avatar
NT port    
Gary Williams committed
236
237
238
    c->c_n_ops_executing = 0;
    c->c_n_ops_pending = 0;
    c->c_n_ops_completed = 0;
239
240
#endif

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

Gary Williams's avatar
NT port    
Gary Williams committed
243
244
    lber_pvt_sb_set_desc( &c->c_sb, s );
    lber_pvt_sb_set_io( &c->c_sb, &lber_pvt_sb_io_tcp, NULL );
245

Gary Williams's avatar
NT port    
Gary Williams committed
246
247
248
249
250
    if( lber_pvt_sb_set_nonblock( &c->c_sb, 1 ) < 0 ) {
        Debug( LDAP_DEBUG_ANY,
            "connection_init(%d, %s, %s): set nonblocking failed\n",
            s, c->c_client_name, c->c_client_addr);
    }
251

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

Gary Williams's avatar
NT port    
Gary Williams committed
254
255
    c->c_conn_state = SLAP_C_INACTIVE;
    c->c_struct_state = SLAP_C_USED;
256

Gary Williams's avatar
NT port    
Gary Williams committed
257
258
    ldap_pvt_thread_mutex_unlock( &c->c_mutex );
    ldap_pvt_thread_mutex_unlock( &connections_mutex );
259

Gary Williams's avatar
NT port    
Gary Williams committed
260
    return id;
261
262
263
264
265
}

static void
connection_destroy( Connection *c )
{
Gary Williams's avatar
NT port    
Gary Williams committed
266
267
268
269
270
    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 );
271

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

Gary Williams's avatar
NT port    
Gary Williams committed
275
276
    c->c_version = 0;
    c->c_protocol = 0;
277

Gary Williams's avatar
NT port    
Gary Williams committed
278
    c->c_starttime = 0;
279

Gary Williams's avatar
NT port    
Gary Williams committed
280
281
282
283
    if(c->c_dn != NULL) {
        free(c->c_dn);
        c->c_dn = NULL;
    }
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
	if(c->c_cdn != NULL) {
		free(c->c_cdn);
		c->c_cdn = NULL;
	}
	if(c->c_client_name != NULL) {
		free(c->c_client_name);
		c->c_client_name = NULL;
	}
	if(c->c_client_addr != NULL) {
		free(c->c_client_addr);
		c->c_client_addr = NULL;
	}

	if ( lber_pvt_sb_in_use(&c->c_sb) ) {
		int sd = lber_pvt_sb_get_desc(&c->c_sb);

		slapd_remove( sd );
	   	lber_pvt_sb_close( &c->c_sb );

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

   	lber_pvt_sb_destroy( &c->c_sb );
}

311
312
313
314
315
316
317
318
319
320
321
322
323
324
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 ) {
		/* don't listen on this port anymore */
		slapd_clr_read( c->c_sb.sb_sd, 1 );
		c->c_conn_state = SLAP_C_CLOSING;
	}
}

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
static void connection_close( Connection *c )
{
	assert( connections != NULL );
	assert( c != NULL );
	assert( c->c_struct_state == SLAP_C_USED );
	assert( c->c_conn_state == SLAP_C_CLOSING );

	if( c->c_ops != NULL ) {
		Debug( LDAP_DEBUG_TRACE,
			"connection_close: deferring conn=%ld sd=%d.\n",
			c->c_connid, c->c_sb.sb_sd, 0 );

		return;
	}

	Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n",
		c->c_connid, c->c_sb.sb_sd, 0 );

	connection_destroy( c );
}

long connections_nextid(void)
{
	long id;
	assert( connections != NULL );

	ldap_pvt_thread_mutex_lock( &connections_mutex );

	id = conn_nextid;

	ldap_pvt_thread_mutex_unlock( &connections_mutex );

	return id;
}

Connection* connection_first(void)
{
	assert( connections != NULL );

	ldap_pvt_thread_mutex_lock( &connections_mutex );

	assert( conn_index == -1 );
	conn_index = 0;

	return connection_next(NULL);
}

Connection* connection_next(Connection *c)
{
	assert( connections != NULL );
	assert( conn_index != -1 );
	assert( conn_index <= dtblsize );

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

	c = NULL;

	for(; conn_index < dtblsize; conn_index++) {
		if( connections[conn_index].c_struct_state == SLAP_C_UNINITIALIZED ) {
			assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
#ifndef HAVE_WINSOCK
			continue;
#else
			break;
#endif
		}

		if( connections[conn_index].c_struct_state == SLAP_C_USED ) {
			assert( connections[conn_index].c_conn_state != SLAP_C_INVALID );
			c = &connections[conn_index++];
			break;
		}

		assert( connections[conn_index].c_struct_state == SLAP_C_UNUSED );
		assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
	}

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

	return c;
}

void connection_done(Connection *c)
{
	assert( connections != NULL );
	assert( conn_index != -1 );
	assert( conn_index <= dtblsize );

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

	conn_index = -1;
	ldap_pvt_thread_mutex_unlock( &connections_mutex );
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
425
426
427
428
429
430
/*
 * 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.
 */

431
432
static void *
connection_operation( void *arg_v )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
433
{
434
	struct co_arg	*arg = arg_v;
435
436
	int tag = arg->co_op->o_tag;
	Connection *conn = arg->co_conn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
437

438
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
439
440
441
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_initiated++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
442
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
443

444
	switch ( tag ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
445
	case LDAP_REQ_BIND:
446
		do_bind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
447
448
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
449
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
450
451
452
	case LDAP_REQ_UNBIND_30:
#endif
	case LDAP_REQ_UNBIND:
453
		do_unbind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
454
455
456
		break;

	case LDAP_REQ_ADD:
457
		do_add( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
458
459
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
460
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
461
462
463
	case LDAP_REQ_DELETE_30:
#endif
	case LDAP_REQ_DELETE:
464
		do_delete( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
465
466
467
		break;

	case LDAP_REQ_MODRDN:
468
		do_modrdn( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
469
470
471
		break;

	case LDAP_REQ_MODIFY:
472
		do_modify( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
473
474
475
		break;

	case LDAP_REQ_COMPARE:
476
		do_compare( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
477
478
479
		break;

	case LDAP_REQ_SEARCH:
480
		do_search( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
481
482
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
483
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
484
485
486
	case LDAP_REQ_ABANDON_30:
#endif
	case LDAP_REQ_ABANDON:
487
		do_abandon( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
488
489
490
		break;

	default:
491
		Debug( LDAP_DEBUG_ANY, "unknown request 0x%lx\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
492
493
494
495
		    arg->co_op->o_tag, 0, 0 );
		break;
	}

496
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
497
498
499
	ldap_pvt_thread_mutex_lock( &num_ops_mutex );
	num_ops_completed++;
	ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
500
501
502
#endif

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
503

504
#ifdef LDAP_COUNTERS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
505
	conn->c_n_ops_completed++;
506
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
507

508
509
510
	slap_op_remove( &conn->c_ops, arg->co_op );
	slap_op_free( arg->co_op );
	arg->co_op = NULL;
511
	arg->co_conn = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
512
	free( (char *) arg );
513
	arg = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
514

515
516
517
518
519
	switch( tag ) {
#ifdef LDAP_COMPAT30
	case LDAP_REQ_UNBIND_30:
#endif
	case LDAP_REQ_UNBIND:
520
		connection_closing( conn );
521
522
523
524
525
526
		break;

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

529
530
531
532
533
534
535
	if( conn->c_conn_state == SLAP_C_CLOSING ) {
		Debug( LDAP_DEBUG_TRACE,
			"connection_operation: attempting closing conn=%ld sd=%d.\n",
			conn->c_connid, conn->c_sb.sb_sd, 0 );

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

537
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
538
	active_threads--;
539
	if( active_threads < 1 ) {
540
		ldap_pvt_thread_cond_signal(&active_threads_cond);
541
	}
542
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
543
544
545

	connection_resched( conn );

546
547
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );

548
	return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549
550
}

551
552
553
554
555
556
557
558
559
560
561
562
563
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 );
564
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
565
566
567
		return -1;
	}

568
569
570
571
572
573
574
575
576
577
	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;
	}

578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
	Debug( LDAP_DEBUG_TRACE,
		"connection_read(%d): checking for input on id=%ld\n",
		s, c->c_connid, 0 );

#define CONNECTION_INPUT_LOOP 1

#ifdef DATA_READY_LOOP
	while(!rc && lber_pvt_sb_data_ready(&c->c_sb))
#elif CONNECTION_INPUT_LOOP
	while(!rc)
#endif
	{
		rc = connection_input( c );
	}

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

598
		connection_closing( c );
599
600
601
602
603
604
605
606
607
608
		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
609
610
611
    Connection *conn
)
{
612
	Operation *op;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
613
614
615
616
617
618
619
	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 );
620
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
621
622
623
624
	}

	errno = 0;
	if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
625
626
	    != LDAP_TAG_MESSAGE )
	{
627
628
		int err = errno;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
629
		Debug( LDAP_DEBUG_TRACE,
630
			"ber_get_next on fd %d failed errno %d (%s)\n",
631
632
			lber_pvt_sb_get_desc(&conn->c_sb), err,
			err > -1 && err < sys_nerr ?  sys_errlist[err] : "unknown" );
633
634
		Debug( LDAP_DEBUG_TRACE,
			"\t*** got %ld of %lu so far\n",
635
636
			(long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf),
			conn->c_currentber->ber_len, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
637

638
		if ( err != EWOULDBLOCK && err != EAGAIN ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
639
640
641
642
			/* log, close and send error */
			ber_free( conn->c_currentber, 1 );
			conn->c_currentber = NULL;

643
			return -2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
644
		}
645
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
646
	}
647

Kurt Zeilenga's avatar
Kurt Zeilenga committed
648
649
650
651
652
	ber = conn->c_currentber;
	conn->c_currentber = NULL;

	if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
		/* log, close and send error */
653
		Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
654
655
		    0 );
		ber_free( ber, 1 );
656
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
657
658
659
660
	}

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

665
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
666
667
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
668
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
669
670
671
672
673
	if ( conn->c_version == 30 ) {
		(void) ber_skip_tag( ber, &len );
	}
#endif

674
	op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
675

676
677
678
	if ( conn->c_conn_state == SLAP_C_BINDING
		|| conn->c_conn_state == SLAP_C_CLOSING )
	{
679
		Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 );
680
		slap_op_add( &conn->c_pending_ops, op );
681

682
683
684
	} else {
		connection_op_activate( conn, op );
	}
685

686
687
688
689
#ifdef NO_THREADS
	if ( conn->c_struct_state != SLAP_C_USED ) {
		/* connection must have got closed underneath us */
		return 1;
690
	}
691
692
#endif
	assert( conn->c_struct_state == SLAP_C_USED );
693

694
	return 0;
695
696
697
698
699
700
701
}

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

702
	if( conn->c_conn_state != SLAP_C_ACTIVE ) {
703
		/* other states need different handling */
Gary Williams's avatar
NT port    
Gary Williams committed
704
		return 0;
705
706
707
708
709
710
711
712
	}

	for( op = slap_op_pop( &conn->c_pending_ops );
		op != NULL;
		op = slap_op_pop( &conn->c_pending_ops ) )
	{
		connection_op_activate( conn, op );

713
		if ( conn->c_conn_state == SLAP_C_BINDING ) {
714
715
716
			break;
		}
	}
Gary Williams's avatar
NT port    
Gary Williams committed
717
	return 0;
718
719
720
721
722
723
724
725
}

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
726
727

	if ( conn->c_dn != NULL ) {
728
		tmpdn = ch_strdup( conn->c_dn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
729
730
731
732
	} else {
		tmpdn = NULL;
	}

733
734
735
736
737
738
739
740
741
742
	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) {
743
		conn->c_conn_state = SLAP_C_BINDING;
744
745
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
746
747
748
749
	if ( tmpdn != NULL ) {
		free( tmpdn );
	}

750
751
752
753
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

754
755
	status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
					 connection_operation, (void *) arg );
756

757
	if ( status != 0 ) {
758
759
760
761
		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
762
	}
763
764

	return status;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
765
}
766
767
768
769
770
771
772
773
774
775
776
777
778

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 );
779
		ldap_pvt_thread_mutex_unlock( &connections_mutex );
780
781
782
783
784
785
786
787
788
789
790
791
792
		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;
}