]> git.sur5r.net Git - openldap/blob - servers/slapd/connection.c
Backout the input exhaustion change, it loops. Still looking for
[openldap] / servers / slapd / connection.c
1 #include "portable.h"
2
3 #include <stdio.h>
4
5 #include <ac/socket.h>
6 #include <ac/errno.h>
7 #include <ac/signal.h>
8 #include <ac/string.h>
9 #include <ac/time.h>
10
11 #include "slap.h"
12
13 /* we need LBER internals */
14 #include "../../libraries/liblber/lber-int.h"
15
16 /* protected by connections_mutex */
17 static ldap_pvt_thread_mutex_t connections_mutex;
18 static Connection *connections = NULL;
19 static unsigned long conn_nextid = 0;
20
21 /* structure state (protected by connections_mutex) */
22 #define SLAP_C_UNINITIALIZED    0x00    /* MUST BE ZERO (0) */
23 #define SLAP_C_UNUSED                   0x01
24 #define SLAP_C_USED                             0x02
25
26 /* connection state (protected by c_mutex ) */
27 #define SLAP_C_INVALID                  0x00    /* MUST BE ZERO (0) */
28 #define SLAP_C_INACTIVE                 0x01    /* zero threads */
29 #define SLAP_C_ACTIVE                   0x02    /* one or more threads */
30 #define SLAP_C_BINDING                  0x03    /* binding */
31 #define SLAP_C_CLOSING                  0x04    /* closing */
32
33 char* connection_state2str( int state ) {
34         switch( state ) {
35         case SLAP_C_INVALID:    return "!";             
36         case SLAP_C_INACTIVE:   return "|";             
37         case SLAP_C_ACTIVE:             return "";                      
38         case SLAP_C_BINDING:    return "B";
39         case SLAP_C_CLOSING:    return "C";                     
40         }
41
42         return "?";
43 }
44
45 static Connection* connection_get( ber_socket_t s );
46
47 static int connection_input( Connection *c );
48 static void connection_close( Connection *c );
49
50 static int connection_op_activate( Connection *conn, Operation *op );
51 static int connection_resched( Connection *conn );
52 static void connection_abandon( Connection *conn );
53 static void connection_destroy( Connection *c );
54
55 struct co_arg {
56         Connection      *co_conn;
57         Operation       *co_op;
58 };
59
60 /*
61  * Initialize connection management infrastructure.
62  */
63 int connections_init(void)
64 {
65         assert( connections == NULL );
66
67         if( connections != NULL) {
68                 Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n",
69                         0, 0, 0 );
70                 return -1;
71         }
72
73         /* should check return of every call */
74         ldap_pvt_thread_mutex_init( &connections_mutex );
75
76         connections = (Connection *) calloc( dtblsize, sizeof(Connection) );
77
78         if( connections == NULL ) {
79                 Debug( LDAP_DEBUG_ANY,
80                         "connections_init: allocation (%d*%ld) of connection array failed.\n",
81                         dtblsize, (long) sizeof(Connection), 0 );
82                 return -1;
83         }
84
85     assert( connections[0].c_struct_state == SLAP_C_UNINITIALIZED );
86     assert( connections[dtblsize-1].c_struct_state == SLAP_C_UNINITIALIZED );
87
88         /*
89          * per entry initialization of the Connection array initialization
90          * will be done by connection_init()
91          */ 
92
93         return 0;
94 }
95
96 /*
97  * Destroy connection management infrastructure.
98  */
99 int connections_destroy(void)
100 {
101         ber_socket_t i;
102
103         /* should check return of every call */
104
105         if( connections == NULL) {
106                 Debug( LDAP_DEBUG_ANY, "connections_destroy: nothing to destroy.\n",
107                         0, 0, 0 );
108                 return -1;
109         }
110
111         for ( i = 0; i < dtblsize; i++ ) {
112                 if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
113                         ldap_pvt_thread_mutex_destroy( &connections[i].c_mutex );
114                         ldap_pvt_thread_mutex_destroy( &connections[i].c_write_mutex );
115                         ldap_pvt_thread_cond_destroy( &connections[i].c_write_cv );
116                 }
117         }
118
119         free( connections );
120         connections = NULL;
121
122         ldap_pvt_thread_mutex_destroy( &connections_mutex );
123         return 0;
124 }
125
126 /*
127  * shutdown all connections
128  */
129 int connections_shutdown(void)
130 {
131         ber_socket_t i;
132
133         ldap_pvt_thread_mutex_lock( &connections_mutex );
134
135         for ( i = 0; i < dtblsize; i++ ) {
136                 if( connections[i].c_struct_state != SLAP_C_USED ) {
137                         continue;
138                 }
139
140                 ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
141
142                 /* connections_mutex and c_mutex are locked */
143                 connection_closing( &connections[i] );
144                 connection_close( &connections[i] );
145
146                 ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
147         }
148
149         ldap_pvt_thread_mutex_unlock( &connections_mutex );
150
151         return 0;
152 }
153
154 /*
155  * Timeout idle connections.
156  */
157 int connections_timeout_idle(time_t now)
158 {
159         int i = 0;
160         int connindex;
161         Connection* c;
162
163         ldap_pvt_thread_mutex_lock( &connections_mutex );
164
165         for( c = connection_first( &connindex );
166                 c != NULL;
167                 c = connection_next( c, &connindex ) )
168         {
169                 if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
170                         /* close it */
171                         connection_closing( c );
172                         connection_close( c );
173                         i++;
174                 }
175         }
176         connection_done( c );
177
178         ldap_pvt_thread_mutex_unlock( &connections_mutex );
179
180         return i;
181 }
182
183 static Connection* connection_get( ber_socket_t s )
184 {
185         /* connections_mutex should be locked by caller */
186
187         Connection *c;
188
189         Debug( LDAP_DEBUG_ARGS,
190                 "connection_get(%ld)\n",
191                 (long) s, 0, 0 );
192
193         assert( connections != NULL );
194
195         if(s == AC_SOCKET_INVALID) {
196                 return NULL;
197         }
198
199 #ifndef HAVE_WINSOCK
200         c = &connections[s];
201
202         assert( c->c_struct_state != SLAP_C_UNINITIALIZED );
203
204 #else
205         c = NULL;
206         {
207                 ber_socket_t i;
208
209                 for(i=0; i<dtblsize; i++) {
210                         if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
211                                 assert( connections[i].c_conn_state == SLAP_C_INVALID );
212                                 assert( connections[i].c_sb == 0 );
213                                 break;
214                         }
215
216                         if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
217                                 assert( connections[i].c_conn_state == SLAP_C_INVALID );
218                                 assert( !ber_pvt_sb_in_use( connections[i].c_sb ) );
219                                 continue;
220                         }
221
222                         /* state can actually change from used -> unused by resched,
223                          * so don't assert details here.
224                          */
225
226                         if( ber_pvt_sb_get_desc( connections[i].c_sb ) == s ) {
227                                 c = &connections[i];
228                                 break;
229                         }
230                 }
231         }
232 #endif
233
234         if( c != NULL ) {
235                 ldap_pvt_thread_mutex_lock( &c->c_mutex );
236
237                 if( c->c_struct_state != SLAP_C_USED ) {
238                         /* connection must have been closed due to resched */
239
240                         assert( c->c_conn_state == SLAP_C_INVALID );
241                         assert( !ber_pvt_sb_in_use( c->c_sb ) );
242
243                         Debug( LDAP_DEBUG_TRACE,
244                                 "connection_get(%d): connection not used.\n",
245                                 s, c->c_connid, 0 );
246
247                         ldap_pvt_thread_mutex_unlock( &c->c_mutex );
248                         return NULL;
249                 }
250
251                 Debug( LDAP_DEBUG_TRACE,
252                         "connection_get(%d): got connid=%ld\n",
253                         s, c->c_connid, 0 );
254
255                 c->c_n_get++;
256
257                 assert( c->c_struct_state == SLAP_C_USED );
258                 assert( c->c_conn_state != SLAP_C_INVALID );
259                 assert( ber_pvt_sb_in_use( c->c_sb ) );
260
261         c->c_activitytime = slap_get_time();
262         }
263
264         return c;
265 }
266
267 static void connection_return( Connection *c )
268 {
269         ldap_pvt_thread_mutex_unlock( &c->c_mutex );
270 }
271
272 long connection_init(
273         ber_socket_t s,
274         const char* name,
275         const char* addr,
276         int use_tls )
277 {
278         unsigned long id;
279         Connection *c;
280         assert( connections != NULL );
281
282 #ifndef HAVE_TLS
283         assert( !use_tls );
284 #endif
285
286         if( s == AC_SOCKET_INVALID ) {
287         Debug( LDAP_DEBUG_ANY,
288                         "connection_init(%ld): invalid.\n",
289                         (long) s, 0, 0 );
290                 return -1;
291         }
292
293         assert( s >= 0 );
294 #ifndef HAVE_WINSOCK
295         assert( s < dtblsize );
296 #endif
297
298         ldap_pvt_thread_mutex_lock( &connections_mutex );
299
300 #ifndef HAVE_WINSOCK
301         c = &connections[s];
302
303 #else
304         {
305                 unsigned int i;
306
307                 c = NULL;
308
309         for( i=0; i < dtblsize; i++) {
310             if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
311                 assert( connections[i].c_sb == 0 );
312                 c = &connections[i];
313                 break;
314             }
315
316             if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
317                 assert( !ber_pvt_sb_in_use( connections[i].c_sb ));
318                 c = &connections[i];
319                 break;
320             }
321
322             assert( connections[i].c_struct_state == SLAP_C_USED );
323             assert( connections[i].c_conn_state != SLAP_C_INVALID );
324             assert( ber_pvt_sb_in_use( connections[i].c_sb ));
325         }
326
327         if( c == NULL ) {
328                 Debug( LDAP_DEBUG_ANY,
329                                 "connection_init(%d): connection table full (%d/%d).\n",
330                                 s, i, dtblsize);
331             ldap_pvt_thread_mutex_unlock( &connections_mutex );
332             return -1;
333         }
334     }
335 #endif
336
337     assert( c != NULL );
338     assert( c->c_struct_state != SLAP_C_USED );
339     assert( c->c_conn_state == SLAP_C_INVALID );
340
341     if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
342         c->c_dn = NULL;
343         c->c_cdn = NULL;
344         c->c_client_name = NULL;
345         c->c_client_addr = NULL;
346         c->c_ops = NULL;
347         c->c_pending_ops = NULL;
348                 c->c_authmech = NULL;
349                 c->c_authstate = NULL;
350
351         c->c_sb = ber_sockbuf_alloc( );
352
353         /* should check status of thread calls */
354         ldap_pvt_thread_mutex_init( &c->c_mutex );
355         ldap_pvt_thread_mutex_init( &c->c_write_mutex );
356         ldap_pvt_thread_cond_init( &c->c_write_cv );
357
358         c->c_struct_state = SLAP_C_UNUSED;
359     }
360
361     ldap_pvt_thread_mutex_lock( &c->c_mutex );
362
363     assert( c->c_struct_state == SLAP_C_UNUSED );
364     assert(     c->c_dn == NULL );
365     assert(     c->c_cdn == NULL );
366     assert( c->c_client_name == NULL );
367     assert( c->c_client_addr == NULL );
368     assert( c->c_ops == NULL );
369     assert( c->c_pending_ops == NULL );
370         assert( c->c_authmech == NULL );
371         assert( c->c_authstate == NULL );
372
373     c->c_client_name = ch_strdup( name == NULL ? "" : name );
374     c->c_client_addr = ch_strdup( addr );
375
376     c->c_n_ops_received = 0;
377     c->c_n_ops_executing = 0;
378     c->c_n_ops_pending = 0;
379     c->c_n_ops_completed = 0;
380
381         c->c_n_get = 0;
382         c->c_n_read = 0;
383         c->c_n_write = 0;
384
385     c->c_activitytime = c->c_starttime = slap_get_time();
386
387     ber_pvt_sb_set_desc( c->c_sb, s );
388     ber_pvt_sb_set_io( c->c_sb, &ber_pvt_sb_io_tcp, NULL );
389
390     if( ber_pvt_sb_set_nonblock( c->c_sb, 1 ) < 0 ) {
391         Debug( LDAP_DEBUG_ANY,
392             "connection_init(%d, %s, %s): set nonblocking failed\n",
393             s, c->c_client_name, c->c_client_addr);
394     }
395
396     id = c->c_connid = conn_nextid++;
397
398     c->c_conn_state = SLAP_C_INACTIVE;
399     c->c_struct_state = SLAP_C_USED;
400
401 #ifdef HAVE_TLS
402     if ( use_tls ) {
403             c->c_is_tls = 1;
404             c->c_needs_tls_accept = 1;
405     }
406 #endif
407
408     ldap_pvt_thread_mutex_unlock( &c->c_mutex );
409     ldap_pvt_thread_mutex_unlock( &connections_mutex );
410
411     backend_connection_init(c);
412
413     return id;
414 }
415
416 static void
417 connection_destroy( Connection *c )
418 {
419         /* note: connections_mutex should be locked by caller */
420
421     assert( connections != NULL );
422     assert( c != NULL );
423     assert( c->c_struct_state != SLAP_C_UNUSED );
424     assert( c->c_conn_state != SLAP_C_INVALID );
425     assert( c->c_ops == NULL );
426
427     backend_connection_destroy(c);
428
429     c->c_protocol = 0;
430     c->c_connid = -1;
431
432     c->c_activitytime = c->c_starttime = 0;
433
434     if(c->c_dn != NULL) {
435         free(c->c_dn);
436         c->c_dn = NULL;
437     }
438         if(c->c_cdn != NULL) {
439                 free(c->c_cdn);
440                 c->c_cdn = NULL;
441         }
442         if(c->c_client_name != NULL) {
443                 free(c->c_client_name);
444                 c->c_client_name = NULL;
445         }
446         if(c->c_client_addr != NULL) {
447                 free(c->c_client_addr);
448                 c->c_client_addr = NULL;
449         }
450         if(c->c_authmech != NULL ) {
451                 free(c->c_authmech);
452                 c->c_authmech = NULL;
453         }
454         if(c->c_authstate != NULL ) {
455                 free(c->c_authstate);
456                 c->c_authstate = NULL;
457         }
458
459         if ( ber_pvt_sb_in_use(c->c_sb) ) {
460                 int sd = ber_pvt_sb_get_desc(c->c_sb);
461
462                 slapd_remove( sd, 0 );
463                 ber_pvt_sb_close( c->c_sb );
464
465                 Statslog( LDAP_DEBUG_STATS,
466                     "conn=%d fd=%d closed.\n",
467                         c->c_connid, sd, 0, 0, 0 );
468         }
469
470         ber_pvt_sb_destroy( c->c_sb );
471
472     c->c_conn_state = SLAP_C_INVALID;
473     c->c_struct_state = SLAP_C_UNUSED;
474 }
475
476 int connection_state_closing( Connection *c )
477 {
478         /* c_mutex must be locked by caller */
479
480         int state;
481         assert( c != NULL );
482         assert( c->c_struct_state == SLAP_C_USED );
483
484         state = c->c_conn_state;
485
486         assert( state != SLAP_C_INVALID );
487
488         return state == SLAP_C_CLOSING;
489 }
490
491 static void connection_abandon( Connection *c )
492 {
493         /* c_mutex must be locked by caller */
494
495         Operation *o;
496
497         for( o = c->c_ops; o != NULL; o = o->o_next ) {
498                 ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
499                 o->o_abandon = 1;
500                 ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
501         }
502
503         /* remove pending operations */
504         for( o = slap_op_pop( &c->c_pending_ops );
505                 o != NULL;
506                 o = slap_op_pop( &c->c_pending_ops ) )
507         {
508                 slap_op_free( o );
509         }
510 }
511
512 void connection_closing( Connection *c )
513 {
514         assert( connections != NULL );
515         assert( c != NULL );
516         assert( c->c_struct_state == SLAP_C_USED );
517         assert( c->c_conn_state != SLAP_C_INVALID );
518
519         /* c_mutex must be locked by caller */
520
521         if( c->c_conn_state != SLAP_C_CLOSING ) {
522
523                 Debug( LDAP_DEBUG_TRACE,
524                         "connection_closing: readying conn=%ld sd=%d for close.\n",
525                         c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
526
527                 /* update state to closing */
528                 c->c_conn_state = SLAP_C_CLOSING;
529
530                 /* don't listen on this port anymore */
531                 slapd_clr_read( ber_pvt_sb_get_desc( c->c_sb ), 1 );
532
533                 /* shutdown I/O -- not yet implemented */
534
535                 /* abandon active operations */
536                 connection_abandon( c );
537
538                 /* wake write blocked operations */
539                 slapd_clr_write( ber_pvt_sb_get_desc(c->c_sb), 1 );
540                 ldap_pvt_thread_cond_signal( &c->c_write_cv );
541         }
542 }
543
544 static void connection_close( Connection *c )
545 {
546         assert( connections != NULL );
547         assert( c != NULL );
548         assert( c->c_struct_state == SLAP_C_USED );
549         assert( c->c_conn_state == SLAP_C_CLOSING );
550
551         /* note: connections_mutex and c_mutex should be locked by caller */
552
553         if( c->c_ops != NULL ) {
554                 Debug( LDAP_DEBUG_TRACE,
555                         "connection_close: deferring conn=%ld sd=%d.\n",
556                         c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
557
558                 return;
559         }
560
561         Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n",
562                 c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
563
564         connection_destroy( c );
565 }
566
567 unsigned long connections_nextid(void)
568 {
569         unsigned long id;
570         assert( connections != NULL );
571
572         ldap_pvt_thread_mutex_lock( &connections_mutex );
573
574         id = conn_nextid;
575
576         ldap_pvt_thread_mutex_unlock( &connections_mutex );
577
578         return id;
579 }
580
581 Connection* connection_first( ber_socket_t *index )
582 {
583         assert( connections != NULL );
584         assert( index != NULL );
585
586         ldap_pvt_thread_mutex_lock( &connections_mutex );
587
588         *index = 0;
589
590         return connection_next(NULL, index);
591 }
592
593 Connection* connection_next( Connection *c, ber_socket_t *index )
594 {
595         assert( connections != NULL );
596         assert( index != NULL );
597         assert( *index <= dtblsize );
598
599         if( c != NULL ) {
600                 ldap_pvt_thread_mutex_unlock( &c->c_mutex );
601         }
602
603         c = NULL;
604
605         for(; *index < dtblsize; (*index)++) {
606                 if( connections[*index].c_struct_state == SLAP_C_UNINITIALIZED ) {
607                         assert( connections[*index].c_conn_state == SLAP_C_INVALID );
608 #ifndef HAVE_WINSOCK
609                         continue;
610 #else
611                         break;
612 #endif
613                 }
614
615                 if( connections[*index].c_struct_state == SLAP_C_USED ) {
616                         assert( connections[*index].c_conn_state != SLAP_C_INVALID );
617                         c = &connections[(*index)++];
618                         break;
619                 }
620
621                 assert( connections[*index].c_struct_state == SLAP_C_UNUSED );
622                 assert( connections[*index].c_conn_state == SLAP_C_INVALID );
623         }
624
625         if( c != NULL ) {
626                 ldap_pvt_thread_mutex_lock( &c->c_mutex );
627         }
628
629         return c;
630 }
631
632 void connection_done( Connection *c )
633 {
634         assert( connections != NULL );
635
636         if( c != NULL ) {
637                 ldap_pvt_thread_mutex_unlock( &c->c_mutex );
638         }
639
640         ldap_pvt_thread_mutex_unlock( &connections_mutex );
641 }
642
643 /*
644  * connection_activity - handle the request operation op on connection
645  * conn.  This routine figures out what kind of operation it is and
646  * calls the appropriate stub to handle it.
647  */
648
649 static void *
650 connection_operation( void *arg_v )
651 {
652         int rc;
653         struct co_arg   *arg = arg_v;
654         ber_tag_t tag = arg->co_op->o_tag;
655         Connection *conn = arg->co_conn;
656
657         ldap_pvt_thread_mutex_lock( &num_ops_mutex );
658         num_ops_initiated++;
659         ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
660
661         switch ( tag ) {
662         case LDAP_REQ_BIND:
663                 rc = do_bind( conn, arg->co_op );
664                 break;
665
666         case LDAP_REQ_UNBIND:
667                 rc = do_unbind( conn, arg->co_op );
668                 break;
669
670         case LDAP_REQ_ADD:
671                 rc = do_add( conn, arg->co_op );
672                 break;
673
674         case LDAP_REQ_DELETE:
675                 rc = do_delete( conn, arg->co_op );
676                 break;
677
678         case LDAP_REQ_MODRDN:
679                 rc = do_modrdn( conn, arg->co_op );
680                 break;
681
682         case LDAP_REQ_MODIFY:
683                 rc = do_modify( conn, arg->co_op );
684                 break;
685
686         case LDAP_REQ_COMPARE:
687                 rc = do_compare( conn, arg->co_op );
688                 break;
689
690         case LDAP_REQ_SEARCH:
691                 rc = do_search( conn, arg->co_op );
692                 break;
693
694         case LDAP_REQ_ABANDON:
695                 rc = do_abandon( conn, arg->co_op );
696                 break;
697
698         case LDAP_REQ_EXTENDED:
699                 rc = do_extended( conn, arg->co_op );
700                 break;
701
702         default:
703                 Debug( LDAP_DEBUG_ANY, "unknown LDAP request 0x%lx\n",
704                     tag, 0, 0 );
705                 arg->co_op->o_tag = LBER_ERROR;
706                 send_ldap_disconnect( conn, arg->co_op,
707                         LDAP_PROTOCOL_ERROR, "unknown LDAP request" );
708                 rc = -1;
709                 break;
710         }
711
712         if( rc == -1 ) tag = LBER_ERROR;
713
714         ldap_pvt_thread_mutex_lock( &num_ops_mutex );
715         num_ops_completed++;
716         ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
717
718         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
719
720         conn->c_n_ops_executing--;
721         conn->c_n_ops_completed++;
722
723         slap_op_remove( &conn->c_ops, arg->co_op );
724         slap_op_free( arg->co_op );
725         arg->co_op = NULL;
726         arg->co_conn = NULL;
727         free( (char *) arg );
728         arg = NULL;
729
730         switch( tag ) {
731         case LBER_ERROR:
732         case LDAP_REQ_UNBIND:
733                 /* c_mutex is locked */
734                 connection_closing( conn );
735                 break;
736
737         case LDAP_REQ_BIND:
738                 if( conn->c_conn_state == SLAP_C_BINDING) {
739                         conn->c_conn_state = SLAP_C_ACTIVE;
740                 }
741                 conn->c_bind_in_progress = ( rc == LDAP_SASL_BIND_IN_PROGRESS );
742         }
743
744         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
745         active_threads--;
746         if( active_threads < 1 ) {
747                 ldap_pvt_thread_cond_signal(&active_threads_cond);
748         }
749         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
750
751         connection_resched( conn );
752
753         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
754
755         return NULL;
756 }
757
758 int connection_read(ber_socket_t s)
759 {
760         int rc = 0;
761         Connection *c;
762         assert( connections != NULL );
763
764         ldap_pvt_thread_mutex_lock( &connections_mutex );
765
766         /* get (locked) connection */
767         c = connection_get( s );
768
769         if( c == NULL ) {
770                 Debug( LDAP_DEBUG_ANY,
771                         "connection_read(%ld): no connection!\n",
772                         (long) s, 0, 0 );
773
774                 slapd_remove(s, 0);
775
776                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
777                 return -1;
778         }
779
780         c->c_n_read++;
781
782         if( c->c_conn_state == SLAP_C_CLOSING ) {
783                 Debug( LDAP_DEBUG_TRACE,
784                         "connection_read(%d): closing, ignoring input for id=%ld\n",
785                         s, c->c_connid, 0 );
786
787                 connection_return( c );
788                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
789                 return 0;
790         }
791
792         Debug( LDAP_DEBUG_TRACE,
793                 "connection_read(%d): checking for input on id=%ld\n",
794                 s, c->c_connid, 0 );
795
796 #ifdef HAVE_TLS
797         if ( c->c_is_tls && c->c_needs_tls_accept ) {
798                 rc = ldap_pvt_tls_accept( c->c_sb, NULL );
799                 if ( rc < 0 ) {
800                         Debug( LDAP_DEBUG_TRACE,
801                                "connection_read(%d): TLS accept error error=%d id=%ld, closing.\n",
802                                s, rc, c->c_connid );
803
804                         c->c_needs_tls_accept = 0;
805                         /* connections_mutex and c_mutex are locked */
806                         connection_closing( c );
807                         connection_close( c );
808                 } else if ( rc == 0 ) {
809                         c->c_needs_tls_accept = 0;
810                 }
811                 connection_return( c );
812                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
813                 return 0;
814         }
815 #endif
816
817 #define CONNECTION_INPUT_LOOP 1
818
819 #ifdef DATA_READY_LOOP
820         while(!rc && ber_pvt_sb_data_ready(&c->c_sb))
821 #elif CONNECTION_INPUT_LOOP
822         while(!rc)
823 #endif
824         {
825                 /* How do we do this without getting into a busy loop ? */
826                 rc = connection_input( c );
827         }
828
829         if( rc < 0 ) {
830                 Debug( LDAP_DEBUG_TRACE,
831                         "connection_read(%d): input error=%d id=%ld, closing.\n",
832                         s, rc, c->c_connid );
833
834                 /* connections_mutex and c_mutex are locked */
835                 connection_closing( c );
836                 connection_close( c );
837         }
838
839         if ( ber_pvt_sb_needs_read( c->c_sb ) )
840                 slapd_set_read( s, 1 );
841         if ( ber_pvt_sb_needs_write( c->c_sb ) )
842                 slapd_set_write( s, 1 );
843         connection_return( c );
844         ldap_pvt_thread_mutex_unlock( &connections_mutex );
845         return 0;
846 }
847
848 static int
849 connection_input(
850     Connection *conn
851 )
852 {
853         Operation *op;
854         ber_tag_t       tag;
855         ber_len_t       len;
856         ber_int_t       msgid;
857         BerElement      *ber;
858
859         if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
860             == NULL ) {
861                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
862                 return -1;
863         }
864
865         errno = 0;
866         if ( (tag = ber_get_next( conn->c_sb, &len, conn->c_currentber ))
867             != LDAP_TAG_MESSAGE )
868         {
869                 int err = errno;
870
871                 Debug( LDAP_DEBUG_TRACE,
872                         "ber_get_next on fd %d failed errno %d (%s)\n",
873                         ber_pvt_sb_get_desc( conn->c_sb ), err,
874                         err > -1 && err < sys_nerr ?  sys_errlist[err] : "unknown" );
875                 Debug( LDAP_DEBUG_TRACE,
876                         "\t*** got %ld of %lu so far\n",
877                         (long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf),
878                         conn->c_currentber->ber_len, 0 );
879
880                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
881                         /* log, close and send error */
882                         ber_free( conn->c_currentber, 1 );
883                         conn->c_currentber = NULL;
884
885                         return -2;
886                 }
887                 return 1;
888         }
889
890         ber = conn->c_currentber;
891         conn->c_currentber = NULL;
892
893         if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
894                 /* log, close and send error */
895                 Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0,
896                     0 );
897                 ber_free( ber, 1 );
898                 return -1;
899         }
900
901         if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
902                 /* log, close and send error */
903                 Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%lx\n", tag, 0,
904                     0 );
905                 ber_free( ber, 1 );
906
907                 return -1;
908         }
909
910         if(tag == LDAP_REQ_BIND) {
911                 /* immediately abandon all exiting operations upon BIND */
912                 connection_abandon( conn );
913         }
914
915         op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
916
917         if ( conn->c_conn_state == SLAP_C_BINDING
918                 || conn->c_conn_state == SLAP_C_CLOSING )
919         {
920                 Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 );
921                 conn->c_n_ops_pending++;
922                 slap_op_add( &conn->c_pending_ops, op );
923
924         } else {
925                 conn->c_n_ops_executing++;
926                 connection_op_activate( conn, op );
927         }
928
929 #ifdef NO_THREADS
930         if ( conn->c_struct_state != SLAP_C_USED ) {
931                 /* connection must have got closed underneath us */
932                 return 1;
933         }
934 #endif
935         assert( conn->c_struct_state == SLAP_C_USED );
936
937         return 0;
938 }
939
940 static int
941 connection_resched( Connection *conn )
942 {
943         Operation *op;
944
945         if( conn->c_conn_state == SLAP_C_CLOSING ) {
946                 Debug( LDAP_DEBUG_TRACE,
947                         "connection_resched: attempting closing conn=%ld sd=%d.\n",
948                         conn->c_connid, ber_pvt_sb_get_desc( conn->c_sb ), 0 );
949
950                 connection_close( conn );
951                 return 0;
952         }
953
954         if( conn->c_conn_state != SLAP_C_ACTIVE ) {
955                 /* other states need different handling */
956                 return 0;
957         }
958
959         for( op = slap_op_pop( &conn->c_pending_ops );
960                 op != NULL;
961                 op = slap_op_pop( &conn->c_pending_ops ) )
962         {
963                 /* pending operations should not be marked for abandonment */
964                 assert(!op->o_abandon);
965
966                 conn->c_n_ops_pending--;
967                 conn->c_n_ops_executing++;
968
969                 connection_op_activate( conn, op );
970
971                 if ( conn->c_conn_state == SLAP_C_BINDING ) {
972                         break;
973                 }
974         }
975         return 0;
976 }
977
978 static int connection_op_activate( Connection *conn, Operation *op )
979 {
980         struct co_arg *arg;
981         char *tmpdn;
982         int status;
983         ber_tag_t tag = op->o_tag;
984
985         if(tag == LDAP_REQ_BIND) {
986                 conn->c_conn_state = SLAP_C_BINDING;
987         }
988
989         if ( conn->c_dn != NULL ) {
990                 tmpdn = ch_strdup( conn->c_dn );
991         } else {
992                 tmpdn = NULL;
993         }
994
995         arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
996         arg->co_conn = conn;
997         arg->co_op = op;
998
999         arg->co_op->o_bind_in_progress = conn->c_bind_in_progress;
1000
1001         arg->co_op->o_dn = ch_strdup( tmpdn != NULL ? tmpdn : "" );
1002         arg->co_op->o_ndn = dn_normalize_case( ch_strdup( arg->co_op->o_dn ) );
1003
1004         arg->co_op->o_protocol = conn->c_protocol;
1005         arg->co_op->o_connid = conn->c_connid;
1006
1007         arg->co_op->o_authtype = conn->c_authtype;
1008         arg->co_op->o_authmech = conn->c_authmech != NULL
1009                 ?  ch_strdup( conn->c_authmech ) : NULL;
1010         
1011         slap_op_add( &conn->c_ops, arg->co_op );
1012
1013         if( tmpdn != NULL ) {
1014                 free( tmpdn );
1015         }
1016
1017         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
1018         active_threads++;
1019         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
1020
1021         status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
1022                                          connection_operation, (void *) arg );
1023
1024         if ( status != 0 ) {
1025                 Debug( LDAP_DEBUG_ANY,
1026                 "ldap_pvt_thread_create failed (%d)\n", status, 0, 0 );
1027
1028                 /* should move op to pending list */
1029         }
1030
1031         return status;
1032 }
1033
1034 int connection_write(ber_socket_t s)
1035 {
1036         Connection *c;
1037         assert( connections != NULL );
1038
1039         ldap_pvt_thread_mutex_lock( &connections_mutex );
1040
1041         c = connection_get( s );
1042
1043         slapd_clr_write( s, 0);
1044
1045         if( c == NULL ) {
1046                 Debug( LDAP_DEBUG_ANY,
1047                         "connection_write(%ld): no connection!\n",
1048                         (long) s, 0, 0 );
1049                 slapd_remove(s, 0);
1050                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
1051                 return -1;
1052         }
1053
1054         c->c_n_write++;
1055
1056         Debug( LDAP_DEBUG_TRACE,
1057                 "connection_write(%d): waking output for id=%ld\n",
1058                 s, c->c_connid, 0 );
1059
1060         ldap_pvt_thread_cond_signal( &c->c_write_cv );
1061
1062         if ( ber_pvt_sb_needs_read( c->c_sb ) )
1063                 slapd_set_read( s, 1 );
1064         if ( ber_pvt_sb_needs_write( c->c_sb ) )
1065                 slapd_set_write( s, 1 );
1066         connection_return( c );
1067         ldap_pvt_thread_mutex_unlock( &connections_mutex );
1068         return 0;
1069 }