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
595
596
597
	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,
			"connection_read(%d): input error id=%ld, closing.\n",
			s, c->c_connid, 0 );

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

		if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
			/* log, close and send error */
			ber_free( conn->c_currentber, 1 );
			conn->c_currentber = NULL;

641
			return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
642
		}
643
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
644
	}
645

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

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

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

663
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
664
665
	}

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

672
	op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
673

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

680
681
682
	} else {
		connection_op_activate( conn, op );
	}
683

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

692
	return 0;
693
694
695
696
697
698
699
}

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

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

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

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

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
724
725

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

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

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

748
749
750
751
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

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

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

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

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