]> git.sur5r.net Git - openldap/blob - servers/slapd/connection.c
For dynamic modules, must explicitly zero BackendInfo structure in
[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* url,
275         const char* dnsname,
276         const char* peername,
277         const char* sockname,
278         int use_tls )
279 {
280         unsigned long id;
281         Connection *c;
282
283         assert( connections != NULL );
284
285         assert( dnsname != NULL );
286         assert( peername != NULL );
287         assert( sockname != NULL );
288
289 #ifndef HAVE_TLS
290         assert( !use_tls );
291 #endif
292
293         if( s == AC_SOCKET_INVALID ) {
294         Debug( LDAP_DEBUG_ANY,
295                         "connection_init(%ld): invalid.\n",
296                         (long) s, 0, 0 );
297                 return -1;
298         }
299
300         assert( s >= 0 );
301 #ifndef HAVE_WINSOCK
302         assert( s < dtblsize );
303 #endif
304
305         ldap_pvt_thread_mutex_lock( &connections_mutex );
306
307 #ifndef HAVE_WINSOCK
308         c = &connections[s];
309
310 #else
311         {
312                 unsigned int i;
313
314                 c = NULL;
315
316         for( i=0; i < dtblsize; i++) {
317             if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
318                 assert( connections[i].c_sb == 0 );
319                 c = &connections[i];
320                 break;
321             }
322
323             if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
324                 assert( !ber_pvt_sb_in_use( connections[i].c_sb ));
325                 c = &connections[i];
326                 break;
327             }
328
329             assert( connections[i].c_struct_state == SLAP_C_USED );
330             assert( connections[i].c_conn_state != SLAP_C_INVALID );
331             assert( ber_pvt_sb_in_use( connections[i].c_sb ));
332         }
333
334         if( c == NULL ) {
335                 Debug( LDAP_DEBUG_ANY,
336                                 "connection_init(%d): connection table full (%d/%d).\n",
337                                 s, i, dtblsize);
338             ldap_pvt_thread_mutex_unlock( &connections_mutex );
339             return -1;
340         }
341     }
342 #endif
343
344     assert( c != NULL );
345     assert( c->c_struct_state != SLAP_C_USED );
346     assert( c->c_conn_state == SLAP_C_INVALID );
347
348     if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
349         c->c_dn = NULL;
350         c->c_cdn = NULL;
351
352                 c->c_listener_url = NULL;
353                 c->c_peer_domain = NULL;
354         c->c_peer_name = NULL;
355         c->c_sock_name = NULL;
356
357         c->c_ops = NULL;
358         c->c_pending_ops = NULL;
359                 c->c_authmech = NULL;
360                 c->c_authstate = NULL;
361
362 #ifdef HAVE_CYRUS_SASL
363                 c->c_sasl_context = NULL;
364 #endif
365
366         c->c_sb = ber_sockbuf_alloc( );
367
368         /* should check status of thread calls */
369         ldap_pvt_thread_mutex_init( &c->c_mutex );
370         ldap_pvt_thread_mutex_init( &c->c_write_mutex );
371         ldap_pvt_thread_cond_init( &c->c_write_cv );
372
373         c->c_struct_state = SLAP_C_UNUSED;
374     }
375
376     ldap_pvt_thread_mutex_lock( &c->c_mutex );
377
378     assert( c->c_struct_state == SLAP_C_UNUSED );
379     assert(     c->c_dn == NULL );
380     assert(     c->c_cdn == NULL );
381     assert( c->c_listener_url == NULL );
382     assert( c->c_peer_domain == NULL );
383     assert( c->c_peer_name == NULL );
384     assert( c->c_sock_name == NULL );
385     assert( c->c_ops == NULL );
386     assert( c->c_pending_ops == NULL );
387         assert( c->c_authmech == NULL );
388         assert( c->c_authstate == NULL );
389 #ifdef HAVE_CYRUS_SASL
390         assert( c->c_sasl_context == NULL );
391 #endif
392
393         c->c_listener_url = ch_strdup( url  );
394         c->c_peer_domain = ch_strdup( dnsname  );
395     c->c_peer_name = ch_strdup( peername  );
396     c->c_sock_name = ch_strdup( sockname );
397
398     c->c_n_ops_received = 0;
399     c->c_n_ops_executing = 0;
400     c->c_n_ops_pending = 0;
401     c->c_n_ops_completed = 0;
402
403         c->c_n_get = 0;
404         c->c_n_read = 0;
405         c->c_n_write = 0;
406
407     c->c_activitytime = c->c_starttime = slap_get_time();
408
409     ber_pvt_sb_set_desc( c->c_sb, s );
410     ber_pvt_sb_set_io( c->c_sb, &ber_pvt_sb_io_tcp, NULL );
411
412     if( ber_pvt_sb_set_nonblock( c->c_sb, 1 ) < 0 ) {
413         Debug( LDAP_DEBUG_ANY,
414             "connection_init(%d, %s): set nonblocking failed\n",
415             s, c->c_peer_name,0 );
416     }
417
418     id = c->c_connid = conn_nextid++;
419
420     c->c_conn_state = SLAP_C_INACTIVE;
421     c->c_struct_state = SLAP_C_USED;
422
423 #ifdef HAVE_TLS
424     if ( use_tls ) {
425             c->c_is_tls = 1;
426             c->c_needs_tls_accept = 1;
427     }
428 #endif
429
430     ldap_pvt_thread_mutex_unlock( &c->c_mutex );
431     ldap_pvt_thread_mutex_unlock( &connections_mutex );
432
433     backend_connection_init(c);
434
435     return id;
436 }
437
438 static void
439 connection_destroy( Connection *c )
440 {
441         /* note: connections_mutex should be locked by caller */
442
443     assert( connections != NULL );
444     assert( c != NULL );
445     assert( c->c_struct_state != SLAP_C_UNUSED );
446     assert( c->c_conn_state != SLAP_C_INVALID );
447     assert( c->c_ops == NULL );
448
449     backend_connection_destroy(c);
450
451     c->c_protocol = 0;
452     c->c_connid = -1;
453
454     c->c_activitytime = c->c_starttime = 0;
455
456     if(c->c_dn != NULL) {
457         free(c->c_dn);
458         c->c_dn = NULL;
459     }
460         if(c->c_cdn != NULL) {
461                 free(c->c_cdn);
462                 c->c_cdn = NULL;
463         }
464         if(c->c_listener_url != NULL) {
465                 free(c->c_listener_url);
466                 c->c_listener_url = NULL;
467         }
468         if(c->c_peer_domain != NULL) {
469                 free(c->c_peer_domain);
470                 c->c_peer_domain = NULL;
471         }
472         if(c->c_peer_name != NULL) {
473                 free(c->c_peer_name);
474                 c->c_peer_name = NULL;
475         }
476         if(c->c_sock_name != NULL) {
477                 free(c->c_sock_name);
478                 c->c_sock_name = NULL;
479         }
480         if(c->c_authmech != NULL ) {
481                 free(c->c_authmech);
482                 c->c_authmech = NULL;
483         }
484         if(c->c_authstate != NULL ) {
485                 free(c->c_authstate);
486                 c->c_authstate = NULL;
487         }
488
489 #ifdef HAVE_CYRUS_SASL
490         if(c->c_sasl_context != NULL ) {
491                 sasl_dispose( &c->c_sasl_context );
492                 c->c_sasl_context = NULL;
493         }
494 #endif
495
496         if ( ber_pvt_sb_in_use(c->c_sb) ) {
497                 int sd = ber_pvt_sb_get_desc(c->c_sb);
498
499                 slapd_remove( sd, 0 );
500                 ber_pvt_sb_close( c->c_sb );
501
502                 Statslog( LDAP_DEBUG_STATS,
503                     "conn=%d fd=%d closed.\n",
504                         c->c_connid, sd, 0, 0, 0 );
505         }
506
507         ber_pvt_sb_destroy( c->c_sb );
508
509     c->c_conn_state = SLAP_C_INVALID;
510     c->c_struct_state = SLAP_C_UNUSED;
511 }
512
513 int connection_state_closing( Connection *c )
514 {
515         /* c_mutex must be locked by caller */
516
517         int state;
518         assert( c != NULL );
519         assert( c->c_struct_state == SLAP_C_USED );
520
521         state = c->c_conn_state;
522
523         assert( state != SLAP_C_INVALID );
524
525         return state == SLAP_C_CLOSING;
526 }
527
528 static void connection_abandon( Connection *c )
529 {
530         /* c_mutex must be locked by caller */
531
532         Operation *o;
533
534         for( o = c->c_ops; o != NULL; o = o->o_next ) {
535                 ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
536                 o->o_abandon = 1;
537                 ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
538         }
539
540         /* remove pending operations */
541         for( o = slap_op_pop( &c->c_pending_ops );
542                 o != NULL;
543                 o = slap_op_pop( &c->c_pending_ops ) )
544         {
545                 slap_op_free( o );
546         }
547 }
548
549 void connection_closing( Connection *c )
550 {
551         assert( connections != NULL );
552         assert( c != NULL );
553         assert( c->c_struct_state == SLAP_C_USED );
554         assert( c->c_conn_state != SLAP_C_INVALID );
555
556         /* c_mutex must be locked by caller */
557
558         if( c->c_conn_state != SLAP_C_CLOSING ) {
559
560                 Debug( LDAP_DEBUG_TRACE,
561                         "connection_closing: readying conn=%ld sd=%d for close.\n",
562                         c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
563
564                 /* update state to closing */
565                 c->c_conn_state = SLAP_C_CLOSING;
566
567                 /* don't listen on this port anymore */
568                 slapd_clr_read( ber_pvt_sb_get_desc( c->c_sb ), 1 );
569
570                 /* shutdown I/O -- not yet implemented */
571
572                 /* abandon active operations */
573                 connection_abandon( c );
574
575                 /* wake write blocked operations */
576                 slapd_clr_write( ber_pvt_sb_get_desc(c->c_sb), 1 );
577                 ldap_pvt_thread_cond_signal( &c->c_write_cv );
578         }
579 }
580
581 static void connection_close( Connection *c )
582 {
583         assert( connections != NULL );
584         assert( c != NULL );
585         assert( c->c_struct_state == SLAP_C_USED );
586         assert( c->c_conn_state == SLAP_C_CLOSING );
587
588         /* note: connections_mutex and c_mutex should be locked by caller */
589
590         if( c->c_ops != NULL ) {
591                 Debug( LDAP_DEBUG_TRACE,
592                         "connection_close: deferring conn=%ld sd=%d.\n",
593                         c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
594
595                 return;
596         }
597
598         Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n",
599                 c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
600
601         connection_destroy( c );
602 }
603
604 unsigned long connections_nextid(void)
605 {
606         unsigned long id;
607         assert( connections != NULL );
608
609         ldap_pvt_thread_mutex_lock( &connections_mutex );
610
611         id = conn_nextid;
612
613         ldap_pvt_thread_mutex_unlock( &connections_mutex );
614
615         return id;
616 }
617
618 Connection* connection_first( ber_socket_t *index )
619 {
620         assert( connections != NULL );
621         assert( index != NULL );
622
623         ldap_pvt_thread_mutex_lock( &connections_mutex );
624
625         *index = 0;
626
627         return connection_next(NULL, index);
628 }
629
630 Connection* connection_next( Connection *c, ber_socket_t *index )
631 {
632         assert( connections != NULL );
633         assert( index != NULL );
634         assert( *index <= dtblsize );
635
636         if( c != NULL ) {
637                 ldap_pvt_thread_mutex_unlock( &c->c_mutex );
638         }
639
640         c = NULL;
641
642         for(; *index < dtblsize; (*index)++) {
643                 if( connections[*index].c_struct_state == SLAP_C_UNINITIALIZED ) {
644                         assert( connections[*index].c_conn_state == SLAP_C_INVALID );
645 #ifndef HAVE_WINSOCK
646                         continue;
647 #else
648                         break;
649 #endif
650                 }
651
652                 if( connections[*index].c_struct_state == SLAP_C_USED ) {
653                         assert( connections[*index].c_conn_state != SLAP_C_INVALID );
654                         c = &connections[(*index)++];
655                         break;
656                 }
657
658                 assert( connections[*index].c_struct_state == SLAP_C_UNUSED );
659                 assert( connections[*index].c_conn_state == SLAP_C_INVALID );
660         }
661
662         if( c != NULL ) {
663                 ldap_pvt_thread_mutex_lock( &c->c_mutex );
664         }
665
666         return c;
667 }
668
669 void connection_done( Connection *c )
670 {
671         assert( connections != NULL );
672
673         if( c != NULL ) {
674                 ldap_pvt_thread_mutex_unlock( &c->c_mutex );
675         }
676
677         ldap_pvt_thread_mutex_unlock( &connections_mutex );
678 }
679
680 /*
681  * connection_activity - handle the request operation op on connection
682  * conn.  This routine figures out what kind of operation it is and
683  * calls the appropriate stub to handle it.
684  */
685
686 static void *
687 connection_operation( void *arg_v )
688 {
689         int rc;
690         struct co_arg   *arg = arg_v;
691         ber_tag_t tag = arg->co_op->o_tag;
692         Connection *conn = arg->co_conn;
693
694         ldap_pvt_thread_mutex_lock( &num_ops_mutex );
695         num_ops_initiated++;
696         ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
697
698         switch ( tag ) {
699         case LDAP_REQ_BIND:
700                 rc = do_bind( conn, arg->co_op );
701                 break;
702
703         case LDAP_REQ_UNBIND:
704                 rc = do_unbind( conn, arg->co_op );
705                 break;
706
707         case LDAP_REQ_ADD:
708                 rc = do_add( conn, arg->co_op );
709                 break;
710
711         case LDAP_REQ_DELETE:
712                 rc = do_delete( conn, arg->co_op );
713                 break;
714
715         case LDAP_REQ_MODRDN:
716                 rc = do_modrdn( conn, arg->co_op );
717                 break;
718
719         case LDAP_REQ_MODIFY:
720                 rc = do_modify( conn, arg->co_op );
721                 break;
722
723         case LDAP_REQ_COMPARE:
724                 rc = do_compare( conn, arg->co_op );
725                 break;
726
727         case LDAP_REQ_SEARCH:
728                 rc = do_search( conn, arg->co_op );
729                 break;
730
731         case LDAP_REQ_ABANDON:
732                 rc = do_abandon( conn, arg->co_op );
733                 break;
734
735         case LDAP_REQ_EXTENDED:
736                 rc = do_extended( conn, arg->co_op );
737                 break;
738
739         default:
740                 Debug( LDAP_DEBUG_ANY, "unknown LDAP request 0x%lx\n",
741                     tag, 0, 0 );
742                 arg->co_op->o_tag = LBER_ERROR;
743                 send_ldap_disconnect( conn, arg->co_op,
744                         LDAP_PROTOCOL_ERROR, "unknown LDAP request" );
745                 rc = -1;
746                 break;
747         }
748
749         if( rc == -1 ) tag = LBER_ERROR;
750
751         ldap_pvt_thread_mutex_lock( &num_ops_mutex );
752         num_ops_completed++;
753         ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
754
755         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
756
757         conn->c_n_ops_executing--;
758         conn->c_n_ops_completed++;
759
760         slap_op_remove( &conn->c_ops, arg->co_op );
761         slap_op_free( arg->co_op );
762         arg->co_op = NULL;
763         arg->co_conn = NULL;
764         free( (char *) arg );
765         arg = NULL;
766
767         switch( tag ) {
768         case LBER_ERROR:
769         case LDAP_REQ_UNBIND:
770                 /* c_mutex is locked */
771                 connection_closing( conn );
772                 break;
773
774         case LDAP_REQ_BIND:
775                 if( conn->c_conn_state == SLAP_C_BINDING) {
776                         conn->c_conn_state = SLAP_C_ACTIVE;
777                 }
778                 conn->c_bind_in_progress = ( rc == LDAP_SASL_BIND_IN_PROGRESS );
779         }
780
781         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
782         active_threads--;
783         if( active_threads < 1 ) {
784                 ldap_pvt_thread_cond_signal(&active_threads_cond);
785         }
786         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
787
788         connection_resched( conn );
789
790         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
791
792         return NULL;
793 }
794
795 int connection_read(ber_socket_t s)
796 {
797         int rc = 0;
798         Connection *c;
799         assert( connections != NULL );
800
801         ldap_pvt_thread_mutex_lock( &connections_mutex );
802
803         /* get (locked) connection */
804         c = connection_get( s );
805
806         if( c == NULL ) {
807                 Debug( LDAP_DEBUG_ANY,
808                         "connection_read(%ld): no connection!\n",
809                         (long) s, 0, 0 );
810
811                 slapd_remove(s, 0);
812
813                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
814                 return -1;
815         }
816
817         c->c_n_read++;
818
819         if( c->c_conn_state == SLAP_C_CLOSING ) {
820                 Debug( LDAP_DEBUG_TRACE,
821                         "connection_read(%d): closing, ignoring input for id=%ld\n",
822                         s, c->c_connid, 0 );
823
824                 connection_return( c );
825                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
826                 return 0;
827         }
828
829         Debug( LDAP_DEBUG_TRACE,
830                 "connection_read(%d): checking for input on id=%ld\n",
831                 s, c->c_connid, 0 );
832
833 #ifdef HAVE_TLS
834         if ( c->c_is_tls && c->c_needs_tls_accept ) {
835                 rc = ldap_pvt_tls_accept( c->c_sb, NULL );
836                 if ( rc < 0 ) {
837                         Debug( LDAP_DEBUG_TRACE,
838                                "connection_read(%d): TLS accept error error=%d id=%ld, closing.\n",
839                                s, rc, c->c_connid );
840
841                         c->c_needs_tls_accept = 0;
842                         /* connections_mutex and c_mutex are locked */
843                         connection_closing( c );
844                         connection_close( c );
845                 } else if ( rc == 0 ) {
846                         c->c_needs_tls_accept = 0;
847                 }
848                 connection_return( c );
849                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
850                 return 0;
851         }
852 #endif
853
854 #define CONNECTION_INPUT_LOOP 1
855
856 #ifdef DATA_READY_LOOP
857         while(!rc && ber_pvt_sb_data_ready(&c->c_sb))
858 #elif CONNECTION_INPUT_LOOP
859         while(!rc)
860 #endif
861         {
862                 /* How do we do this without getting into a busy loop ? */
863                 rc = connection_input( c );
864         }
865
866         if( rc < 0 ) {
867                 Debug( LDAP_DEBUG_TRACE,
868                         "connection_read(%d): input error=%d id=%ld, closing.\n",
869                         s, rc, c->c_connid );
870
871                 /* connections_mutex and c_mutex are locked */
872                 connection_closing( c );
873                 connection_close( c );
874         }
875
876         if ( ber_pvt_sb_needs_read( c->c_sb ) )
877                 slapd_set_read( s, 1 );
878         if ( ber_pvt_sb_needs_write( c->c_sb ) )
879                 slapd_set_write( s, 1 );
880         connection_return( c );
881         ldap_pvt_thread_mutex_unlock( &connections_mutex );
882         return 0;
883 }
884
885 static int
886 connection_input(
887     Connection *conn
888 )
889 {
890         Operation *op;
891         ber_tag_t       tag;
892         ber_len_t       len;
893         ber_int_t       msgid;
894         BerElement      *ber;
895
896         if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
897             == NULL ) {
898                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
899                 return -1;
900         }
901
902         errno = 0;
903         if ( (tag = ber_get_next( conn->c_sb, &len, conn->c_currentber ))
904             != LDAP_TAG_MESSAGE )
905         {
906                 int err = errno;
907
908                 Debug( LDAP_DEBUG_TRACE,
909                         "ber_get_next on fd %d failed errno %d (%s)\n",
910                         ber_pvt_sb_get_desc( conn->c_sb ), err,
911                         err > -1 && err < sys_nerr ?  sys_errlist[err] : "unknown" );
912                 Debug( LDAP_DEBUG_TRACE,
913                         "\t*** got %ld of %lu so far\n",
914                         (long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf),
915                         conn->c_currentber->ber_len, 0 );
916
917                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
918                         /* log, close and send error */
919                         ber_free( conn->c_currentber, 1 );
920                         conn->c_currentber = NULL;
921
922                         return -2;
923                 }
924                 return 1;
925         }
926
927         ber = conn->c_currentber;
928         conn->c_currentber = NULL;
929
930         if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
931                 /* log, close and send error */
932                 Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0,
933                     0 );
934                 ber_free( ber, 1 );
935                 return -1;
936         }
937
938         if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
939                 /* log, close and send error */
940                 Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%lx\n", tag, 0,
941                     0 );
942                 ber_free( ber, 1 );
943
944                 return -1;
945         }
946
947         if(tag == LDAP_REQ_BIND) {
948                 /* immediately abandon all exiting operations upon BIND */
949                 connection_abandon( conn );
950         }
951
952         op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
953
954         if ( conn->c_conn_state == SLAP_C_BINDING
955                 || conn->c_conn_state == SLAP_C_CLOSING )
956         {
957                 Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 );
958                 conn->c_n_ops_pending++;
959                 slap_op_add( &conn->c_pending_ops, op );
960
961         } else {
962                 conn->c_n_ops_executing++;
963                 connection_op_activate( conn, op );
964         }
965
966 #ifdef NO_THREADS
967         if ( conn->c_struct_state != SLAP_C_USED ) {
968                 /* connection must have got closed underneath us */
969                 return 1;
970         }
971 #endif
972         assert( conn->c_struct_state == SLAP_C_USED );
973
974         return 0;
975 }
976
977 static int
978 connection_resched( Connection *conn )
979 {
980         Operation *op;
981
982         if( conn->c_conn_state == SLAP_C_CLOSING ) {
983                 Debug( LDAP_DEBUG_TRACE,
984                         "connection_resched: attempting closing conn=%ld sd=%d.\n",
985                         conn->c_connid, ber_pvt_sb_get_desc( conn->c_sb ), 0 );
986
987                 connection_close( conn );
988                 return 0;
989         }
990
991         if( conn->c_conn_state != SLAP_C_ACTIVE ) {
992                 /* other states need different handling */
993                 return 0;
994         }
995
996         for( op = slap_op_pop( &conn->c_pending_ops );
997                 op != NULL;
998                 op = slap_op_pop( &conn->c_pending_ops ) )
999         {
1000                 /* pending operations should not be marked for abandonment */
1001                 assert(!op->o_abandon);
1002
1003                 conn->c_n_ops_pending--;
1004                 conn->c_n_ops_executing++;
1005
1006                 connection_op_activate( conn, op );
1007
1008                 if ( conn->c_conn_state == SLAP_C_BINDING ) {
1009                         break;
1010                 }
1011         }
1012         return 0;
1013 }
1014
1015 static int connection_op_activate( Connection *conn, Operation *op )
1016 {
1017         struct co_arg *arg;
1018         char *tmpdn;
1019         int status;
1020         ber_tag_t tag = op->o_tag;
1021
1022         if(tag == LDAP_REQ_BIND) {
1023                 conn->c_conn_state = SLAP_C_BINDING;
1024         }
1025
1026         if ( conn->c_dn != NULL ) {
1027                 tmpdn = ch_strdup( conn->c_dn );
1028         } else {
1029                 tmpdn = NULL;
1030         }
1031
1032         arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
1033         arg->co_conn = conn;
1034         arg->co_op = op;
1035
1036         arg->co_op->o_bind_in_progress = conn->c_bind_in_progress;
1037
1038         arg->co_op->o_dn = ch_strdup( tmpdn != NULL ? tmpdn : "" );
1039         arg->co_op->o_ndn = ch_strdup( arg->co_op->o_dn );
1040         (void) dn_normalize_case( arg->co_op->o_ndn );
1041
1042         arg->co_op->o_protocol = conn->c_protocol;
1043         arg->co_op->o_connid = conn->c_connid;
1044
1045         arg->co_op->o_authtype = conn->c_authtype;
1046         arg->co_op->o_authmech = conn->c_authmech != NULL
1047                 ?  ch_strdup( conn->c_authmech ) : NULL;
1048         
1049         slap_op_add( &conn->c_ops, arg->co_op );
1050
1051         if( tmpdn != NULL ) {
1052                 free( tmpdn );
1053         }
1054
1055         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
1056         active_threads++;
1057         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
1058
1059         status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
1060                                          connection_operation, (void *) arg );
1061
1062         if ( status != 0 ) {
1063                 Debug( LDAP_DEBUG_ANY,
1064                 "ldap_pvt_thread_create failed (%d)\n", status, 0, 0 );
1065
1066                 /* should move op to pending list */
1067         }
1068
1069         return status;
1070 }
1071
1072 int connection_write(ber_socket_t s)
1073 {
1074         Connection *c;
1075         assert( connections != NULL );
1076
1077         ldap_pvt_thread_mutex_lock( &connections_mutex );
1078
1079         c = connection_get( s );
1080
1081         slapd_clr_write( s, 0);
1082
1083         if( c == NULL ) {
1084                 Debug( LDAP_DEBUG_ANY,
1085                         "connection_write(%ld): no connection!\n",
1086                         (long) s, 0, 0 );
1087                 slapd_remove(s, 0);
1088                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
1089                 return -1;
1090         }
1091
1092         c->c_n_write++;
1093
1094         Debug( LDAP_DEBUG_TRACE,
1095                 "connection_write(%d): waking output for id=%ld\n",
1096                 s, c->c_connid, 0 );
1097
1098         ldap_pvt_thread_cond_signal( &c->c_write_cv );
1099
1100         if ( ber_pvt_sb_needs_read( c->c_sb ) )
1101                 slapd_set_read( s, 1 );
1102         if ( ber_pvt_sb_needs_write( c->c_sb ) )
1103                 slapd_set_write( s, 1 );
1104         connection_return( c );
1105         ldap_pvt_thread_mutex_unlock( &connections_mutex );
1106         return 0;
1107 }