]> git.sur5r.net Git - openldap/blob - servers/slapd/connection.c
Make Versionstr const.
[openldap] / servers / slapd / connection.c
1 #include "portable.h"
2
3 #include <stdio.h>
4
5 #include <ac/errno.h>
6 #include <ac/signal.h>
7 #include <ac/socket.h>
8 #include <ac/string.h>
9 #include <ac/time.h>
10
11 #include "slap.h"
12
13 #ifdef HAVE_WINSOCK
14 #define EWOULDBLOCK WSAEWOULDBLOCK
15 #endif
16
17 /* protected by connections_mutex */
18 static ldap_pvt_thread_mutex_t connections_mutex;
19 static Connection *connections = NULL;
20 static int conn_index = -1;
21 static long conn_nextid = 0;
22
23 /* structure state (protected by connections_mutex) */
24 #define SLAP_C_UNINITIALIZED    0x0     /* MUST BE ZERO (0) */
25 #define SLAP_C_UNUSED                   0x1
26 #define SLAP_C_USED                             0x2
27
28 /* connection state (protected by c_mutex ) */
29 #define SLAP_C_INVALID                  0x0     /* MUST BE ZERO (0) */
30 #define SLAP_C_INACTIVE                 0x1     /* zero threads */
31 #define SLAP_C_ACTIVE                   0x2 /* one or more threads */
32 #define SLAP_C_BINDING                  0x3     /* binding */
33 #define SLAP_C_CLOSING                  0x4     /* closing */
34
35 void slapd_remove(int s);
36 static Connection* connection_get( int s );
37
38 static int connection_input( Connection *c );
39 static void connection_close( Connection *c );
40
41 static int connection_op_activate( Connection *conn, Operation *op );
42 static int connection_resched( Connection *conn );
43
44 struct co_arg {
45         Connection      *co_conn;
46         Operation       *co_op;
47 };
48
49 /*
50  * Initialize connection management infrastructure.
51  */
52 int connections_init(void)
53 {
54         int i;
55
56         assert( connections == NULL );
57
58         if( connections != NULL) {
59                 Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n",
60                         0, 0, 0 );
61                 return -1;
62         }
63
64         /* should check return of every call */
65         ldap_pvt_thread_mutex_init( &connections_mutex );
66
67         connections = (Connection *) calloc( dtblsize, sizeof(Connection) );
68
69         if( connections == NULL ) {
70                 Debug( LDAP_DEBUG_ANY,
71                         "connections_init: allocation (%d*%ld) of connection array failed.\n",
72                         dtblsize, (long) sizeof(Connection), 0 );
73                 return -1;
74         }
75
76         for ( i = 0; i < dtblsize; i++ )
77                 memset( &connections[i], 0, sizeof(Connection) );
78
79         /*
80          * per entry initialization of the Connection array initialization
81          * will be done by connection_init()
82          */ 
83
84         return 0;
85 }
86
87 /*
88  * Destroy connection management infrastructure.
89  */
90 int connections_destroy(void)
91 {
92         int i;
93
94         /* should check return of every call */
95
96         if( connections == NULL) {
97                 Debug( LDAP_DEBUG_ANY, "connections_destroy: nothing to destroy.\n",
98                         0, 0, 0 );
99                 return -1;
100         }
101
102         for ( i = 0; i < dtblsize; i++ ) {
103                 if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
104                         ldap_pvt_thread_mutex_destroy( &connections[i].c_mutex );
105                         ldap_pvt_thread_mutex_destroy( &connections[i].c_write_mutex );
106                         ldap_pvt_thread_cond_destroy( &connections[i].c_write_cv );
107                 }
108
109                 free( &connections[i] );
110         }
111
112         free( connections );
113         connections = NULL;
114
115         ldap_pvt_thread_mutex_destroy( &connections_mutex );
116         return 0;
117 }
118
119 /*
120  * shutdown all connections
121  */
122 int connections_shutdown(void)
123 {
124         int i;
125
126         ldap_pvt_thread_mutex_lock( &connections_mutex );
127
128         for ( i = 0; i < dtblsize; i++ ) {
129                 if( connections[i].c_struct_state != SLAP_C_USED ) {
130                         continue;
131                 }
132
133                 ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
134                 connection_closing( &connections[i] );
135                 connection_close( &connections[i] );
136                 ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
137         }
138
139         ldap_pvt_thread_mutex_unlock( &connections_mutex );
140 }
141
142 static Connection* connection_get( int s )
143 {
144         Connection *c = NULL;
145
146         assert( connections != NULL );
147
148         if(s < 0) {
149                 return NULL;
150         }
151
152 #ifndef HAVE_WINSOCK
153         assert( connections[s].c_struct_state == SLAP_C_USED );
154         assert( connections[s].c_conn_state != SLAP_C_INVALID );
155         assert( connections[s].c_sb.sb_sd != -1 );
156
157         c = &connections[s];
158 #else
159         {
160                 int i;
161
162                 for(i=0; i<dtblsize; i++) {
163                         if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
164                                 assert( connections[i].c_conn_state == SLAP_C_INVALID );
165                                 assert( connections[i].c_sb.sb_sd == 0 );
166                                 break;
167                         }
168
169                         if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
170                                 assert( connections[i].c_conn_state == SLAP_C_INVALID );
171                                 assert( connections[i].c_sb.sb_sd == -1 );
172                                 continue;
173                         }
174
175                         assert( connections[i].c_struct_state == SLAP_C_USED );
176                         assert( connections[i].c_conn_state != SLAP_C_INVALID );
177                         assert( connections[i].c_sb.sb_sd != -1 );
178
179                         if( connections[i].c_sb.sb_sd == s ) {
180                                 c = &connections[i];
181                                 break;
182                         }
183                 }
184         }
185 #endif
186
187         if( c != NULL ) {
188                 /* we do this BEFORE locking to aid in debugging */
189                 Debug( LDAP_DEBUG_TRACE,
190                         "connection_get(%d): got connid=%ld\n",
191                         s, c->c_connid, 0 );
192
193                 ldap_pvt_thread_mutex_lock( &c->c_mutex );
194         }
195         return c;
196 }
197
198 static void connection_return( Connection *c )
199 {
200         ldap_pvt_thread_mutex_unlock( &c->c_mutex );
201 }
202
203 long connection_init(
204         int s,
205         const char* name,
206         const char* addr)
207 {
208         long id;
209         Connection *c;
210         assert( connections != NULL );
211
212         if( s < 0 ) {
213                 return -1;
214         }
215
216         assert( s >= 0 );
217 #ifndef HAVE_WINSOCK
218         assert( s < dtblsize );
219 #endif
220
221         ldap_pvt_thread_mutex_lock( &connections_mutex );
222
223 #ifndef HAVE_WINSOCK
224         c = &connections[s];
225
226 #else
227         {
228                 int i;
229
230         for( i=0; i < dtblsize; i++) {
231             if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
232                 assert( connections[i].c_sb.sb_sd == 0 );
233                 c = &connections[i];
234                 break;
235             }
236
237             if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
238                 assert( connections[i].c_sb.sb_sd == -1 );
239                 c = &connections[i];
240                 break;
241             }
242
243             assert( connections[i].c_struct_state == SLAP_C_USED );
244             assert( connections[i].c_conn_state != SLAP_C_INVALID );
245             assert( connections[i].c_sb.sb_sd != -1 );
246         }
247
248         if( c == NULL ) {
249             ldap_pvt_thread_mutex_unlock( &connections_mutex );
250             return -1;
251         }
252     }
253 #endif
254
255     assert( c != NULL );
256     assert( c->c_struct_state != SLAP_C_USED );
257     assert( c->c_conn_state == SLAP_C_INVALID );
258
259     if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
260         c->c_dn = NULL;
261         c->c_cdn = NULL;
262         c->c_client_name = NULL;
263         c->c_client_addr = NULL;
264         c->c_ops = NULL;
265         c->c_pending_ops = NULL;
266
267         lber_pvt_sb_init( &c->c_sb );
268
269         /* should check status of thread calls */
270         ldap_pvt_thread_mutex_init( &c->c_mutex );
271         ldap_pvt_thread_mutex_init( &c->c_write_mutex );
272         ldap_pvt_thread_cond_init( &c->c_write_cv );
273
274         c->c_struct_state = SLAP_C_UNUSED;
275     }
276
277     ldap_pvt_thread_mutex_lock( &c->c_mutex );
278
279     assert( c->c_struct_state == SLAP_C_UNUSED );
280     assert(     c->c_dn == NULL );
281     assert(     c->c_cdn == NULL );
282     assert( c->c_client_name == NULL );
283     assert( c->c_client_addr == NULL );
284     assert( c->c_ops == NULL );
285     assert( c->c_pending_ops == NULL );
286
287     c->c_client_name = ch_strdup( name == NULL ? "" : name );
288     c->c_client_addr = ch_strdup( addr );
289
290     c->c_n_ops_received = 0;
291 #ifdef LDAP_COUNTERS
292     c->c_n_ops_executing = 0;
293     c->c_n_ops_pending = 0;
294     c->c_n_ops_completed = 0;
295 #endif
296
297     c->c_starttime = slap_get_time();
298
299     lber_pvt_sb_set_desc( &c->c_sb, s );
300     lber_pvt_sb_set_io( &c->c_sb, &lber_pvt_sb_io_tcp, NULL );
301
302     if( lber_pvt_sb_set_nonblock( &c->c_sb, 1 ) < 0 ) {
303         Debug( LDAP_DEBUG_ANY,
304             "connection_init(%d, %s, %s): set nonblocking failed\n",
305             s, c->c_client_name, c->c_client_addr);
306     }
307
308     id = c->c_connid = conn_nextid++;
309
310     c->c_conn_state = SLAP_C_INACTIVE;
311     c->c_struct_state = SLAP_C_USED;
312
313     ldap_pvt_thread_mutex_unlock( &c->c_mutex );
314     ldap_pvt_thread_mutex_unlock( &connections_mutex );
315
316     return id;
317 }
318
319 static void
320 connection_destroy( Connection *c )
321 {
322     assert( connections != NULL );
323     assert( c != NULL );
324     assert( c->c_struct_state != SLAP_C_UNUSED );
325     assert( c->c_conn_state != SLAP_C_INVALID );
326     assert( c->c_ops == NULL );
327
328     c->c_struct_state = SLAP_C_UNUSED;
329     c->c_conn_state = SLAP_C_INVALID;
330
331     c->c_version = 0;
332     c->c_protocol = 0;
333
334     c->c_starttime = 0;
335
336     if(c->c_dn != NULL) {
337         free(c->c_dn);
338         c->c_dn = NULL;
339     }
340         if(c->c_cdn != NULL) {
341                 free(c->c_cdn);
342                 c->c_cdn = NULL;
343         }
344         if(c->c_client_name != NULL) {
345                 free(c->c_client_name);
346                 c->c_client_name = NULL;
347         }
348         if(c->c_client_addr != NULL) {
349                 free(c->c_client_addr);
350                 c->c_client_addr = NULL;
351         }
352
353         if ( lber_pvt_sb_in_use(&c->c_sb) ) {
354                 int sd = lber_pvt_sb_get_desc(&c->c_sb);
355
356                 slapd_remove( sd );
357                 lber_pvt_sb_close( &c->c_sb );
358
359                 Statslog( LDAP_DEBUG_STATS,
360                     "conn=%d fd=%d closed.\n",
361                         c->c_connid, sd, 0, 0, 0 );
362         }
363
364         lber_pvt_sb_destroy( &c->c_sb );
365 }
366
367 int connection_state_closing( Connection *c )
368 {
369         /* connection must be locked by caller */
370         int state;
371         assert( c != NULL );
372         assert( c->c_struct_state == SLAP_C_USED );
373
374         state = c->c_conn_state;
375
376         assert( state != SLAP_C_INVALID );
377
378         return state == SLAP_C_CLOSING;
379 }
380
381 void connection_closing( Connection *c )
382 {
383         assert( connections != NULL );
384         assert( c != NULL );
385         assert( c->c_struct_state == SLAP_C_USED );
386         assert( c->c_conn_state != SLAP_C_INVALID );
387
388         if( c->c_conn_state != SLAP_C_CLOSING ) {
389                 Operation *o;
390
391                 Debug( LDAP_DEBUG_TRACE,
392                         "connection_closing: readying conn=%ld sd=%d for close.\n",
393                         c->c_connid, c->c_sb.sb_sd, 0 );
394
395                 /* update state to closing */
396                 c->c_conn_state = SLAP_C_CLOSING;
397
398                 /* don't listen on this port anymore */
399                 slapd_clr_read( c->c_sb.sb_sd, 1 );
400
401                 /* shutdown I/O -- not yet implemented */
402
403                 /* abandon active operations */
404                 for( o = c->c_ops; o != NULL; o = o->o_next ) {
405                         ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
406                         o->o_abandon = 1;
407                         ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
408                 }
409
410                 /* remove pending operations */
411                 for( o = slap_op_pop( &c->c_pending_ops );
412                         o != NULL;
413                         o = slap_op_pop( &c->c_pending_ops ) )
414                 {
415                         slap_op_free( o );
416                 }
417
418                 /* wake write blocked operations */
419                 slapd_clr_write( c->c_sb.sb_sd, 1 );
420                 ldap_pvt_thread_cond_signal( &c->c_write_cv );
421         }
422 }
423
424 static void connection_close( Connection *c )
425 {
426         assert( connections != NULL );
427         assert( c != NULL );
428         assert( c->c_struct_state == SLAP_C_USED );
429         assert( c->c_conn_state == SLAP_C_CLOSING );
430
431         if( c->c_ops != NULL ) {
432                 Debug( LDAP_DEBUG_TRACE,
433                         "connection_close: deferring conn=%ld sd=%d.\n",
434                         c->c_connid, c->c_sb.sb_sd, 0 );
435
436                 return;
437         }
438
439         Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n",
440                 c->c_connid, c->c_sb.sb_sd, 0 );
441
442         connection_destroy( c );
443 }
444
445 long connections_nextid(void)
446 {
447         long id;
448         assert( connections != NULL );
449
450         ldap_pvt_thread_mutex_lock( &connections_mutex );
451
452         id = conn_nextid;
453
454         ldap_pvt_thread_mutex_unlock( &connections_mutex );
455
456         return id;
457 }
458
459 Connection* connection_first(void)
460 {
461         assert( connections != NULL );
462
463         ldap_pvt_thread_mutex_lock( &connections_mutex );
464
465         assert( conn_index == -1 );
466         conn_index = 0;
467
468         return connection_next(NULL);
469 }
470
471 Connection* connection_next(Connection *c)
472 {
473         assert( connections != NULL );
474         assert( conn_index != -1 );
475         assert( conn_index <= dtblsize );
476
477         if( c != NULL ) {
478                 ldap_pvt_thread_mutex_unlock( &c->c_mutex );
479         }
480
481         c = NULL;
482
483         for(; conn_index < dtblsize; conn_index++) {
484                 if( connections[conn_index].c_struct_state == SLAP_C_UNINITIALIZED ) {
485                         assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
486 #ifndef HAVE_WINSOCK
487                         continue;
488 #else
489                         break;
490 #endif
491                 }
492
493                 if( connections[conn_index].c_struct_state == SLAP_C_USED ) {
494                         assert( connections[conn_index].c_conn_state != SLAP_C_INVALID );
495                         c = &connections[conn_index++];
496                         break;
497                 }
498
499                 assert( connections[conn_index].c_struct_state == SLAP_C_UNUSED );
500                 assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
501         }
502
503         if( c != NULL ) {
504                 ldap_pvt_thread_mutex_lock( &c->c_mutex );
505         }
506
507         return c;
508 }
509
510 void connection_done(Connection *c)
511 {
512         assert( connections != NULL );
513         assert( conn_index != -1 );
514         assert( conn_index <= dtblsize );
515
516         if( c != NULL ) {
517                 ldap_pvt_thread_mutex_unlock( &c->c_mutex );
518         }
519
520         conn_index = -1;
521         ldap_pvt_thread_mutex_unlock( &connections_mutex );
522 }
523
524 /*
525  * connection_activity - handle the request operation op on connection
526  * conn.  This routine figures out what kind of operation it is and
527  * calls the appropriate stub to handle it.
528  */
529
530 static void *
531 connection_operation( void *arg_v )
532 {
533         struct co_arg   *arg = arg_v;
534         int tag = arg->co_op->o_tag;
535         Connection *conn = arg->co_conn;
536
537 #ifdef LDAP_COUNTERS
538         ldap_pvt_thread_mutex_lock( &num_ops_mutex );
539         num_ops_initiated++;
540         ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
541 #endif
542
543         switch ( tag ) {
544         case LDAP_REQ_BIND:
545                 do_bind( conn, arg->co_op );
546                 break;
547
548 #ifdef LDAP_COMPAT30
549         case LDAP_REQ_UNBIND_30:
550 #endif
551         case LDAP_REQ_UNBIND:
552                 do_unbind( conn, arg->co_op );
553                 break;
554
555         case LDAP_REQ_ADD:
556                 do_add( conn, arg->co_op );
557                 break;
558
559 #ifdef LDAP_COMPAT30
560         case LDAP_REQ_DELETE_30:
561 #endif
562         case LDAP_REQ_DELETE:
563                 do_delete( conn, arg->co_op );
564                 break;
565
566         case LDAP_REQ_MODRDN:
567                 do_modrdn( conn, arg->co_op );
568                 break;
569
570         case LDAP_REQ_MODIFY:
571                 do_modify( conn, arg->co_op );
572                 break;
573
574         case LDAP_REQ_COMPARE:
575                 do_compare( conn, arg->co_op );
576                 break;
577
578         case LDAP_REQ_SEARCH:
579                 do_search( conn, arg->co_op );
580                 break;
581
582 #ifdef LDAP_COMPAT30
583         case LDAP_REQ_ABANDON_30:
584 #endif
585         case LDAP_REQ_ABANDON:
586                 do_abandon( conn, arg->co_op );
587                 break;
588
589         default:
590                 Debug( LDAP_DEBUG_ANY, "unknown request 0x%lx\n",
591                     arg->co_op->o_tag, 0, 0 );
592                 break;
593         }
594
595 #ifdef LDAP_COUNTERS
596         ldap_pvt_thread_mutex_lock( &num_ops_mutex );
597         num_ops_completed++;
598         ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
599 #endif
600
601         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
602
603 #ifdef LDAP_COUNTERS
604         conn->c_n_ops_completed++;
605 #endif
606
607         slap_op_remove( &conn->c_ops, arg->co_op );
608         slap_op_free( arg->co_op );
609         arg->co_op = NULL;
610         arg->co_conn = NULL;
611         free( (char *) arg );
612         arg = NULL;
613
614         switch( tag ) {
615 #ifdef LDAP_COMPAT30
616         case LDAP_REQ_UNBIND_30:
617 #endif
618         case LDAP_REQ_UNBIND:
619                 connection_closing( conn );
620                 break;
621
622         case LDAP_REQ_BIND:
623                 if( conn->c_conn_state == SLAP_C_BINDING) {
624                         conn->c_conn_state = SLAP_C_ACTIVE;
625                 }
626         }
627
628         if( conn->c_conn_state == SLAP_C_CLOSING ) {
629                 Debug( LDAP_DEBUG_TRACE,
630                         "connection_operation: attempting closing conn=%ld sd=%d.\n",
631                         conn->c_connid, conn->c_sb.sb_sd, 0 );
632
633                 connection_close( conn );
634         }
635
636         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
637         active_threads--;
638         if( active_threads < 1 ) {
639                 ldap_pvt_thread_cond_signal(&active_threads_cond);
640         }
641         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
642
643         connection_resched( conn );
644
645         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
646
647         return NULL;
648 }
649
650 int connection_read(int s)
651 {
652         int rc = 0;
653         Connection *c;
654         assert( connections != NULL );
655
656         ldap_pvt_thread_mutex_lock( &connections_mutex );
657
658         c = connection_get( s );
659         if( c == NULL ) {
660                 Debug( LDAP_DEBUG_ANY,
661                         "connection_read(%d): no connection!\n",
662                         s, 0, 0 );
663                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
664                 return -1;
665         }
666
667         if( c->c_conn_state == SLAP_C_CLOSING ) {
668                 Debug( LDAP_DEBUG_TRACE,
669                         "connection_read(%d): closing, ignoring input for id=%ld\n",
670                         s, c->c_connid, 0 );
671
672                 connection_return( c );
673                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
674                 return 0;
675         }
676
677         Debug( LDAP_DEBUG_TRACE,
678                 "connection_read(%d): checking for input on id=%ld\n",
679                 s, c->c_connid, 0 );
680
681 #define CONNECTION_INPUT_LOOP 1
682
683 #ifdef DATA_READY_LOOP
684         while(!rc && lber_pvt_sb_data_ready(&c->c_sb))
685 #elif CONNECTION_INPUT_LOOP
686         while(!rc)
687 #endif
688         {
689                 rc = connection_input( c );
690         }
691
692         if( rc < 0 ) {
693                 Debug( LDAP_DEBUG_TRACE,
694                         "connection_read(%d): input error=%d id=%ld, closing.\n",
695                         s, rc, c->c_connid );
696
697                 connection_closing( c );
698                 connection_close( c );
699         }
700
701         connection_return( c );
702         ldap_pvt_thread_mutex_unlock( &connections_mutex );
703         return 0;
704 }
705
706 static int
707 connection_input(
708     Connection *conn
709 )
710 {
711         Operation *op;
712         unsigned long   tag, len;
713         long            msgid;
714         BerElement      *ber;
715
716         if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
717             == NULL ) {
718                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
719                 return -1;
720         }
721
722         errno = 0;
723         if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
724             != LDAP_TAG_MESSAGE )
725         {
726                 int err = errno;
727
728                 Debug( LDAP_DEBUG_TRACE,
729                         "ber_get_next on fd %d failed errno %d (%s)\n",
730                         lber_pvt_sb_get_desc(&conn->c_sb), err,
731                         err > -1 && err < sys_nerr ?  sys_errlist[err] : "unknown" );
732                 Debug( LDAP_DEBUG_TRACE,
733                         "\t*** got %ld of %lu so far\n",
734                         (long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf),
735                         conn->c_currentber->ber_len, 0 );
736
737                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
738                         /* log, close and send error */
739                         ber_free( conn->c_currentber, 1 );
740                         conn->c_currentber = NULL;
741
742                         return -2;
743                 }
744                 return 1;
745         }
746
747         ber = conn->c_currentber;
748         conn->c_currentber = NULL;
749
750         if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
751                 /* log, close and send error */
752                 Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0,
753                     0 );
754                 ber_free( ber, 1 );
755                 return -1;
756         }
757
758         if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
759                 /* log, close and send error */
760                 Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%lx\n", tag, 0,
761                     0 );
762                 ber_free( ber, 1 );
763
764                 return -1;
765         }
766
767 #ifdef LDAP_COMPAT30
768         if ( conn->c_version == 30 ) {
769                 (void) ber_skip_tag( ber, &len );
770         }
771 #endif
772
773         op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
774
775         if ( conn->c_conn_state == SLAP_C_BINDING
776                 || conn->c_conn_state == SLAP_C_CLOSING )
777         {
778                 Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 );
779                 slap_op_add( &conn->c_pending_ops, op );
780
781         } else {
782                 connection_op_activate( conn, op );
783         }
784
785 #ifdef NO_THREADS
786         if ( conn->c_struct_state != SLAP_C_USED ) {
787                 /* connection must have got closed underneath us */
788                 return 1;
789         }
790 #endif
791         assert( conn->c_struct_state == SLAP_C_USED );
792
793         return 0;
794 }
795
796 static int
797 connection_resched( Connection *conn )
798 {
799         Operation *op;
800
801         if( conn->c_conn_state != SLAP_C_ACTIVE ) {
802                 /* other states need different handling */
803                 return 0;
804         }
805
806         for( op = slap_op_pop( &conn->c_pending_ops );
807                 op != NULL;
808                 op = slap_op_pop( &conn->c_pending_ops ) )
809         {
810                 /* pending operations should not be marked for abandonment */
811                 assert(!op->o_abandon);
812
813                 connection_op_activate( conn, op );
814
815                 if ( conn->c_conn_state == SLAP_C_BINDING ) {
816                         break;
817                 }
818         }
819         return 0;
820 }
821
822 static int connection_op_activate( Connection *conn, Operation *op )
823 {
824         struct co_arg *arg;
825         char *tmpdn;
826         int status;
827         unsigned long tag = op->o_tag;
828
829         if ( conn->c_dn != NULL ) {
830                 tmpdn = ch_strdup( conn->c_dn );
831         } else {
832                 tmpdn = NULL;
833         }
834
835         arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
836         arg->co_conn = conn;
837         arg->co_op = op;
838
839         arg->co_op->o_dn = ch_strdup( tmpdn != NULL ? tmpdn : "" );
840         arg->co_op->o_ndn = dn_normalize_case( ch_strdup( arg->co_op->o_dn ) );
841
842         slap_op_add( &conn->c_ops, arg->co_op );
843
844         if(tag == LDAP_REQ_BIND) {
845                 conn->c_conn_state = SLAP_C_BINDING;
846         }
847
848         if ( tmpdn != NULL ) {
849                 free( tmpdn );
850         }
851
852         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
853         active_threads++;
854         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
855
856         status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
857                                          connection_operation, (void *) arg );
858
859         if ( status != 0 ) {
860                 Debug( LDAP_DEBUG_ANY,
861                 "ldap_pvt_thread_create failed (%d)\n", status, 0, 0 );
862
863                 /* should move op to pending list */
864         }
865
866         return status;
867 }
868
869 int connection_write(int s)
870 {
871         Connection *c;
872         assert( connections != NULL );
873
874         ldap_pvt_thread_mutex_lock( &connections_mutex );
875
876         c = connection_get( s );
877         if( c == NULL ) {
878                 Debug( LDAP_DEBUG_ANY,
879                         "connection_write(%d): no connection!\n",
880                         s, 0, 0 );
881                 ldap_pvt_thread_mutex_unlock( &connections_mutex );
882                 return -1;
883         }
884
885         Debug( LDAP_DEBUG_TRACE,
886                 "connection_write(%d): waking output for id=%ld\n",
887                 s, c->c_connid, 0 );
888
889         ldap_pvt_thread_cond_signal( &c->c_write_cv );
890
891         connection_return( c );
892         ldap_pvt_thread_mutex_unlock( &connections_mutex );
893         return 0;
894 }