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