]> git.sur5r.net Git - openldap/blob - servers/slapd/connection.c
4f2a5cec0073a3806518c35b762cd18a5b7a8100
[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 /* protected by connections_mutex */
14 static ldap_pvt_thread_mutex_t connections_mutex;
15 static Connection *connections = NULL;
16 static int conn_index = -1;
17 static long conn_nextid = 0;
18
19 static Connection* connection_get( int s );
20
21 static int connection_input( Connection *c );
22
23 static int connection_op_activate( Connection *conn, Operation *op );
24 static int connection_resched( Connection *conn );
25
26 struct co_arg {
27         Connection      *co_conn;
28         Operation       *co_op;
29 };
30
31 /*
32  * Initialize connection management infrastructure.
33  */
34 int connections_init(void)
35 {
36         int i;
37
38         assert( connections == NULL );
39
40         if( connections != NULL) { /* probably should assert this */
41                 Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n",
42                         0, 0, 0 );
43                 return -1;
44         }
45
46         /* should check return of every call */
47         ldap_pvt_thread_mutex_init( &connections_mutex );
48
49         connections = (Connection *) calloc( dtblsize, sizeof(Connection) );
50
51         if( connections == NULL ) {
52                 Debug( LDAP_DEBUG_ANY,
53                         "connections_init: allocation (%d*%ld) of connection array failed.\n",
54                         dtblsize, (long) sizeof(Connection), 0 );
55                 return -1;
56         }
57
58         /*
59          * per entry initialization of the Connection array initialization
60          * will be done by connection_init()
61          */ 
62
63         return 0;
64 }
65
66 static Connection* connection_get( int s )
67 {
68         Connection *c = NULL;
69
70         assert( connections != NULL );
71
72         if(s < 0) {
73                 return NULL;
74         }
75
76 #ifndef HAVE_WINSOCK
77         assert( connections[s].c_struct_state == SLAP_C_USED );
78         assert( connections[s].c_conn_state != SLAP_C_INVALID );
79         assert( connections[s].c_sb.sb_sd != -1 );
80
81         c = &connections[s];
82 #else
83         {
84                 int i;
85
86                 for(i=0; i<dtblsize; i++) {
87                         if( connections[i].c_struct_state == SLAP_C_STRUCT_UNINITIALIZED ) {
88                                 assert( connections[i].c_conn_state == SLAP_C_INVALID );
89                                 assert( connections[s].c_sb.sb_sd == 0 );
90                                 break;
91                         }
92
93                         if( connections[i].c_struct_state == SLAP_C_STRUCT_UNUSED ) {
94                                 assert( connections[i].c_conn_state == SLAP_C_INVALID );
95                                 assert( connections[s].c_sb.sb_sd == -1 );
96                                 continue;
97                         }
98
99                         assert( connections[i].c_struct_state == SLAP_C_STRUCT_USED );
100                         assert( connections[i].c_conn_state != SLAP_C_INVALID );
101                         assert( connections[s].c_sb.sb_sd != -1 );
102
103                         if( connections[i].c_sb.sb_sd == s ) {
104                                 c = &connections[s];
105                                 break;
106                         }
107                 }
108         }
109 #endif
110         if( c != NULL ) {
111                 ldap_pvt_thread_mutex_lock( &c->c_mutex );
112         }
113         return c;
114 }
115
116 static void connection_return( Connection *c )
117 {
118         ldap_pvt_thread_mutex_unlock( &c->c_mutex );
119 }
120
121 long connection_init(
122         int s,
123         const char* name,
124         const char* addr)
125 {
126         long id;
127         Connection *c;
128         assert( connections != NULL );
129
130         if( s < 0 ) {
131                 return -1;
132         }
133
134         assert( s >= 0 );
135 #ifndef HAVE_WINSOCK
136         assert( s < dtblsize );
137 #endif
138
139         ldap_pvt_thread_mutex_lock( &connections_mutex );
140
141 #ifndef HAVE_WINSOCK
142         c = &connections[s];
143
144 #else
145         {
146                 int i;
147
148                 for( i=0; i < dtblsize; i++ {
149                         if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
150                                 assert( connections[i].c_sb.sb_sd == 0 );
151                                 c = &connections[i];
152                                 break;
153                         }
154
155                         if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
156                                 assert( connections[i].c_sb.sb_sd == -1 );
157                                 c = &connections[i];
158                                 break;
159                         }
160
161                         assert( connections[i].c_struct_state == SLAP_C_USED );
162                         assert( connections[i].c_conn_state != SLAP_C_INVALID );
163                         assert( connections[i].c_sb.sb_sd != -1 );
164                 }
165
166                 if( c == NULL ) {
167                         ldap_pvt_thread_mutex_unlock( &connections_mutex );
168                         return -1;
169                 }
170         }
171 #endif
172
173         assert( c != NULL );
174         assert( c->c_struct_state != SLAP_C_USED );
175         assert( c->c_conn_state == SLAP_C_INVALID );
176
177         if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
178                 c->c_dn = NULL;
179                 c->c_cdn = NULL;
180                 c->c_client_name = NULL;
181                 c->c_client_addr = NULL;
182                 c->c_ops = NULL;
183                 c->c_pending_ops = NULL;
184
185                 lber_pvt_sb_init( &c->c_sb );
186
187                 /* should check status of thread calls */
188                 ldap_pvt_thread_mutex_init( &c->c_mutex );
189                 ldap_pvt_thread_mutex_init( &c->c_write_mutex );
190                 ldap_pvt_thread_cond_init( &c->c_write_cv );
191
192                 c->c_struct_state = SLAP_C_UNUSED;
193         }
194
195         ldap_pvt_thread_mutex_lock( &c->c_mutex );
196
197         assert( c->c_struct_state == SLAP_C_UNUSED );
198         assert( c->c_dn == NULL );
199         assert( c->c_cdn == NULL );
200         assert( c->c_client_name == NULL );
201         assert( c->c_client_addr == NULL );
202         assert( c->c_ops == NULL );
203         assert( c->c_pending_ops == NULL );
204
205         c->c_client_name = ch_strdup( name == NULL ? "" : name );
206         c->c_client_addr = ch_strdup( addr );
207
208         c->c_n_ops_received = 0;
209 #ifdef LDAP_COUNTERS
210         c->c_n_ops_executing = 0;
211         c->c_n_ops_pending = 0;
212         c->c_n_ops_completed = 0;
213 #endif
214
215         c->c_starttime = slap_get_time();
216
217         lber_pvt_sb_set_desc( &c->c_sb, s );
218         lber_pvt_sb_set_io( &c->c_sb, &lber_pvt_sb_io_tcp, NULL );
219
220         if( lber_pvt_sb_set_nonblock( &c->c_sb, 1 ) < 0 ) {
221                 Debug( LDAP_DEBUG_ANY,
222                         "connection_init(%d, %s, %s): set nonblocking failed\n",
223                         s, c->c_client_name, c->c_client_addr);
224         }
225
226         id = c->c_connid = conn_nextid++;
227
228         c->c_conn_state = SLAP_C_INACTIVE;
229         c->c_struct_state = SLAP_C_USED;
230
231         ldap_pvt_thread_mutex_unlock( &c->c_mutex );
232         ldap_pvt_thread_mutex_unlock( &connections_mutex );
233
234         return id;
235 }
236
237 static void
238 connection_destroy( Connection *c )
239 {
240         assert( connections != NULL );
241         assert( c != NULL );
242         assert( c->c_struct_state != SLAP_C_UNUSED );
243         assert( c->c_conn_state != SLAP_C_INVALID );
244         assert( c->c_ops == NULL );
245
246         c->c_struct_state = SLAP_C_UNUSED;
247         c->c_conn_state = SLAP_C_INVALID;
248
249         c->c_version = 0;
250         c->c_protocol = 0;
251
252         c->c_starttime = 0;
253
254         if(c->c_dn != NULL) {
255                 free(c->c_dn);
256                 c->c_dn = NULL;
257         }
258         if(c->c_cdn != NULL) {
259                 free(c->c_cdn);
260                 c->c_cdn = NULL;
261         }
262         if(c->c_client_name != NULL) {
263                 free(c->c_client_name);
264                 c->c_client_name = NULL;
265         }
266         if(c->c_client_addr != NULL) {
267                 free(c->c_client_addr);
268                 c->c_client_addr = NULL;
269         }
270
271         if ( lber_pvt_sb_in_use(&c->c_sb) ) {
272                 int sd = lber_pvt_sb_get_desc(&c->c_sb);
273
274                 slapd_remove( sd );
275                 lber_pvt_sb_close( &c->c_sb );
276
277                 Statslog( LDAP_DEBUG_STATS,
278                     "conn=%d fd=%d closed.\n",
279                         c->c_connid, sd, 0, 0, 0 );
280         }
281
282         lber_pvt_sb_destroy( &c->c_sb );
283 }
284
285 static void connection_close( Connection *c )
286 {
287         assert( connections != NULL );
288         assert( c != NULL );
289         assert( c->c_struct_state == SLAP_C_USED );
290         assert( c->c_conn_state == SLAP_C_CLOSING );
291
292         if( c->c_ops != NULL ) {
293                 Debug( LDAP_DEBUG_TRACE,
294                         "connection_close: deferring conn=%ld sd=%d.\n",
295                         c->c_connid, c->c_sb.sb_sd, 0 );
296
297                 return;
298         }
299
300         Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n",
301                 c->c_connid, c->c_sb.sb_sd, 0 );
302
303         connection_destroy( c );
304 }
305
306 long connections_nextid(void)
307 {
308         long id;
309         assert( connections != NULL );
310
311         ldap_pvt_thread_mutex_lock( &connections_mutex );
312
313         id = conn_nextid;
314
315         ldap_pvt_thread_mutex_unlock( &connections_mutex );
316
317         return id;
318 }
319
320 Connection* connection_first(void)
321 {
322         assert( connections != NULL );
323
324         ldap_pvt_thread_mutex_lock( &connections_mutex );
325
326         assert( conn_index == -1 );
327         conn_index = 0;
328
329         return connection_next(NULL);
330 }
331
332 Connection* connection_next(Connection *c)
333 {
334         assert( connections != NULL );
335         assert( conn_index != -1 );
336         assert( conn_index <= dtblsize );
337
338         if( c != NULL ) {
339                 ldap_pvt_thread_mutex_unlock( &c->c_mutex );
340         }
341
342         c = NULL;
343
344         for(; conn_index < dtblsize; conn_index++) {
345                 if( connections[conn_index].c_struct_state == SLAP_C_UNINITIALIZED ) {
346                         assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
347 #ifndef HAVE_WINSOCK
348                         continue;
349 #else
350                         break;
351 #endif
352                 }
353
354                 if( connections[conn_index].c_struct_state == SLAP_C_USED ) {
355                         assert( connections[conn_index].c_conn_state != SLAP_C_INVALID );
356                         c = &connections[conn_index++];
357                         break;
358                 }
359
360                 assert( connections[conn_index].c_struct_state == SLAP_C_UNUSED );
361                 assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
362         }
363
364         if( c != NULL ) {
365                 ldap_pvt_thread_mutex_lock( &c->c_mutex );
366         }
367
368         return c;
369 }
370
371 void connection_done(Connection *c)
372 {
373         assert( connections != NULL );
374         assert( conn_index != -1 );
375         assert( conn_index <= dtblsize );
376
377         if( c != NULL ) {
378                 ldap_pvt_thread_mutex_unlock( &c->c_mutex );
379         }
380
381         conn_index = -1;
382         ldap_pvt_thread_mutex_unlock( &connections_mutex );
383 }
384
385 /*
386  * connection_activity - handle the request operation op on connection
387  * conn.  This routine figures out what kind of operation it is and
388  * calls the appropriate stub to handle it.
389  */
390
391 static void *
392 connection_operation( void *arg_v )
393 {
394         struct co_arg   *arg = arg_v;
395         int tag = arg->co_op->o_tag;
396         Connection *conn = arg->co_conn;
397
398 #ifdef LDAP_COUNTERS
399         ldap_pvt_thread_mutex_lock( &ops_mutex );
400         ops_initiated++;
401         ldap_pvt_thread_mutex_unlock( &ops_mutex );
402 #endif
403
404         switch ( tag ) {
405         case LDAP_REQ_BIND:
406                 do_bind( conn, arg->co_op );
407                 break;
408
409 #ifdef LDAP_COMPAT30
410         case LDAP_REQ_UNBIND_30:
411 #endif
412         case LDAP_REQ_UNBIND:
413                 do_unbind( conn, arg->co_op );
414                 break;
415
416         case LDAP_REQ_ADD:
417                 do_add( conn, arg->co_op );
418                 break;
419
420 #ifdef LDAP_COMPAT30
421         case LDAP_REQ_DELETE_30:
422 #endif
423         case LDAP_REQ_DELETE:
424                 do_delete( conn, arg->co_op );
425                 break;
426
427         case LDAP_REQ_MODRDN:
428                 do_modrdn( conn, arg->co_op );
429                 break;
430
431         case LDAP_REQ_MODIFY:
432                 do_modify( conn, arg->co_op );
433                 break;
434
435         case LDAP_REQ_COMPARE:
436                 do_compare( conn, arg->co_op );
437                 break;
438
439         case LDAP_REQ_SEARCH:
440                 do_search( conn, arg->co_op );
441                 break;
442
443 #ifdef LDAP_COMPAT30
444         case LDAP_REQ_ABANDON_30:
445 #endif
446         case LDAP_REQ_ABANDON:
447                 do_abandon( conn, arg->co_op );
448                 break;
449
450         default:
451                 Debug( LDAP_DEBUG_ANY, "unknown request 0x%lx\n",
452                     arg->co_op->o_tag, 0, 0 );
453                 break;
454         }
455
456 #ifdef LDAP_COUNTERS
457         ldap_pvt_thread_mutex_lock( &ops_mutex );
458         ops_completed++;
459         ldap_pvt_thread_mutex_unlock( &ops_mutex );
460 #endif
461
462         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
463
464 #ifdef LDAP_COUNTERS
465         conn->c_ops_completed++;
466 #endif
467
468         slap_op_remove( &conn->c_ops, arg->co_op );
469         slap_op_free( arg->co_op );
470         arg->co_op = NULL;
471         arg->co_conn = NULL;
472         free( (char *) arg );
473         arg = NULL;
474
475         switch( tag ) {
476 #ifdef LDAP_COMPAT30
477         case LDAP_REQ_UNBIND_30:
478 #endif
479         case LDAP_REQ_UNBIND:
480                 conn->c_conn_state = SLAP_C_CLOSING;
481                 break;
482
483         case LDAP_REQ_BIND:
484                 if( conn->c_conn_state == SLAP_C_BINDING) {
485                         conn->c_conn_state = SLAP_C_ACTIVE;
486                 }
487         }
488
489         if( conn->c_conn_state == SLAP_C_CLOSING ) {
490                 Debug( LDAP_DEBUG_TRACE,
491                         "connection_operation: attempting closing conn=%ld sd=%d.\n",
492                         conn->c_connid, conn->c_sb.sb_sd, 0 );
493
494                 connection_close( conn );
495         }
496
497         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
498         active_threads--;
499         if( active_threads < 1 ) {
500                 ldap_pvt_thread_cond_signal(&active_threads_cond);
501         }
502         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
503
504         connection_resched( conn );
505
506         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
507
508         return NULL;
509 }
510
511 int connection_read(int s)
512 {
513         int rc = 0;
514         Connection *c;
515         assert( connections != NULL );
516
517         ldap_pvt_thread_mutex_lock( &connections_mutex );
518
519         c = connection_get( s );
520         if( c == NULL ) {
521                 Debug( LDAP_DEBUG_ANY,
522                         "connection_read(%d): no connection!\n",
523                         s, 0, 0 );
524                 return -1;
525         }
526
527         Debug( LDAP_DEBUG_TRACE,
528                 "connection_read(%d): checking for input on id=%ld\n",
529                 s, c->c_connid, 0 );
530
531 #define CONNECTION_INPUT_LOOP 1
532
533 #ifdef DATA_READY_LOOP
534         while(!rc && lber_pvt_sb_data_ready(&c->c_sb))
535 #elif CONNECTION_INPUT_LOOP
536         while(!rc)
537 #endif
538         {
539                 rc = connection_input( c );
540         }
541
542         if( rc < 0 ) {
543                 Debug( LDAP_DEBUG_TRACE,
544                         "connection_read(%d): input error id=%ld, closing.\n",
545                         s, c->c_connid, 0 );
546
547                 c->c_conn_state = SLAP_C_CLOSING;
548                 connection_close( c );
549         }
550
551         connection_return( c );
552         ldap_pvt_thread_mutex_unlock( &connections_mutex );
553         return 0;
554 }
555
556 static int
557 connection_input(
558     Connection *conn
559 )
560 {
561         Operation *op;
562         unsigned long   tag, len;
563         long            msgid;
564         BerElement      *ber;
565
566         if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
567             == NULL ) {
568                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
569                 return -1;
570         }
571
572         errno = 0;
573         if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
574             != LDAP_TAG_MESSAGE )
575         {
576                 Debug( LDAP_DEBUG_TRACE,
577                         "ber_get_next on fd %d failed errno %d (%s)\n",
578                         lber_pvt_sb_get_desc(&conn->c_sb), errno,
579                         errno > -1 && errno < sys_nerr ?  sys_errlist[errno] : "unknown" );
580                 Debug( LDAP_DEBUG_TRACE, "\t*** got %ld of %lu so far\n",
581                         (long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf),
582                         conn->c_currentber->ber_len, 0 );
583
584                 if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
585                         /* log, close and send error */
586                         ber_free( conn->c_currentber, 1 );
587                         conn->c_currentber = NULL;
588
589                         return -1;
590                 }
591
592                 return 1;
593         }
594
595         ber = conn->c_currentber;
596         conn->c_currentber = NULL;
597
598         if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
599                 /* log, close and send error */
600                 Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0,
601                     0 );
602                 ber_free( ber, 1 );
603                 return -1;
604         }
605
606         if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
607                 /* log, close and send error */
608                 Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%lx\n", tag, 0,
609                     0 );
610                 ber_free( ber, 1 );
611
612                 return -1;
613         }
614
615 #ifdef LDAP_COMPAT30
616         if ( conn->c_version == 30 ) {
617                 (void) ber_skip_tag( ber, &len );
618         }
619 #endif
620
621         op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
622
623         if ( conn->c_conn_state == SLAP_C_BINDING
624                 || conn->c_conn_state == SLAP_C_CLOSING )
625         {
626                 Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 );
627                 slap_op_add( &conn->c_pending_ops, op );
628
629         } else {
630                 connection_op_activate( conn, op );
631         }
632
633 #ifdef NO_THREADS
634         if ( conn->c_struct_state != SLAP_C_USED ) {
635                 /* connection must have got closed underneath us */
636                 return 1;
637         }
638 #endif
639         assert( conn->c_struct_state == SLAP_C_USED );
640
641         return 0;
642 }
643
644 static int
645 connection_resched( Connection *conn )
646 {
647         Operation *op;
648
649         if( conn->c_conn_state != SLAP_C_ACTIVE ) {
650                 /* other states need different handling */
651                 return;
652         }
653
654         for( op = slap_op_pop( &conn->c_pending_ops );
655                 op != NULL;
656                 op = slap_op_pop( &conn->c_pending_ops ) )
657         {
658                 connection_op_activate( conn, op );
659
660                 if ( conn->c_conn_state == SLAP_C_BINDING ) {
661                         break;
662                 }
663         }
664 }
665
666 static int connection_op_activate( Connection *conn, Operation *op )
667 {
668         struct co_arg *arg;
669         char *tmpdn;
670         int status;
671         unsigned long tag = op->o_tag;
672
673         if ( conn->c_dn != NULL ) {
674                 tmpdn = ch_strdup( conn->c_dn );
675         } else {
676                 tmpdn = NULL;
677         }
678
679         arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
680         arg->co_conn = conn;
681         arg->co_op = op;
682
683         arg->co_op->o_dn = ch_strdup( tmpdn != NULL ? tmpdn : "" );
684         arg->co_op->o_ndn = dn_normalize_case( ch_strdup( arg->co_op->o_dn ) );
685
686         slap_op_add( &conn->c_ops, arg->co_op );
687
688         if(tag == LDAP_REQ_BIND) {
689                 conn->c_conn_state = SLAP_C_BINDING;
690         }
691
692         if ( tmpdn != NULL ) {
693                 free( tmpdn );
694         }
695
696         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
697         active_threads++;
698         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
699
700         status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
701                                          connection_operation, (void *) arg );
702
703         if ( status != 0 ) {
704                 Debug( LDAP_DEBUG_ANY,
705                 "ldap_pvt_thread_create failed (%d)\n", status, 0, 0 );
706
707                 /* should move op to pending list */
708         }
709
710         return status;
711 }
712
713 int connection_write(int s)
714 {
715         Connection *c;
716         assert( connections != NULL );
717
718         ldap_pvt_thread_mutex_lock( &connections_mutex );
719
720         c = connection_get( s );
721         if( c == NULL ) {
722                 Debug( LDAP_DEBUG_ANY,
723                         "connection_write(%d): no connection!\n",
724                         s, 0, 0 );
725                 return -1;
726         }
727
728         Debug( LDAP_DEBUG_TRACE,
729                 "connection_write(%d): waking output for id=%ld\n",
730                 s, c->c_connid, 0 );
731
732         ldap_pvt_thread_cond_signal( &c->c_write_cv );
733
734         connection_return( c );
735         ldap_pvt_thread_mutex_unlock( &connections_mutex );
736         return 0;
737 }