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