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