]> git.sur5r.net Git - openldap/blob - servers/slapd/back-monitor/conn.c
Use recursive mutex to avoid deadlocks
[openldap] / servers / slapd / back-monitor / conn.c
1 /* conn.c - deal with connection subsystem */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2001-2006 The OpenLDAP Foundation.
6  * Portions Copyright 2001-2003 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include <ac/string.h>
26
27 #include "slap.h"
28 #include "lutil.h"
29 #include "back-monitor.h"
30
31 #ifndef LDAP_DEVEL
32 #define MONITOR_LEGACY_CONN
33 #endif
34
35 static int
36 monitor_subsys_conn_update(
37         Operation               *op,
38         SlapReply               *rs,
39         Entry                   *e );
40
41 static int 
42 monitor_subsys_conn_create( 
43         Operation               *op,
44         SlapReply               *rs,
45         struct berval           *ndn,
46         Entry                   *e_parent,
47         Entry                   **ep );
48
49 int
50 monitor_subsys_conn_init(
51         BackendDB               *be,
52         monitor_subsys_t        *ms )
53 {
54         monitor_info_t  *mi;
55         Entry           *e, **ep, *e_conn;
56         monitor_entry_t *mp;
57         struct berval   bv;
58
59         assert( be != NULL );
60
61         ms->mss_update = monitor_subsys_conn_update;
62         ms->mss_create = monitor_subsys_conn_create;
63
64         mi = ( monitor_info_t * )be->be_private;
65
66         if ( monitor_cache_get( mi, &ms->mss_ndn, &e_conn ) ) {
67                 Debug( LDAP_DEBUG_ANY,
68                         "monitor_subsys_conn_init: "
69                         "unable to get entry \"%s\"\n",
70                         ms->mss_ndn.bv_val, 0, 0 );
71                 return( -1 );
72         }
73
74         mp = ( monitor_entry_t * )e_conn->e_private;
75         mp->mp_children = NULL;
76         ep = &mp->mp_children;
77
78         /*
79          * Total conns
80          */
81         BER_BVSTR( &bv, "cn=Total" );
82         e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
83                 mi->mi_oc_monitorCounterObject, mi, NULL, NULL );
84         
85         if ( e == NULL ) {
86                 Debug( LDAP_DEBUG_ANY,
87                         "monitor_subsys_conn_init: "
88                         "unable to create entry \"cn=Total,%s\"\n",
89                         ms->mss_ndn.bv_val, 0, 0 );
90                 return( -1 );
91         }
92         
93         BER_BVSTR( &bv, "0" );
94         attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, &bv );
95         
96         mp = monitor_entrypriv_create();
97         if ( mp == NULL ) {
98                 return -1;
99         }
100         e->e_private = ( void * )mp;
101         mp->mp_info = ms;
102         mp->mp_flags = ms->mss_flags \
103                 | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
104         mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
105
106         if ( monitor_cache_add( mi, e ) ) {
107                 Debug( LDAP_DEBUG_ANY,
108                         "monitor_subsys_conn_init: "
109                         "unable to add entry \"cn=Total,%s\"\n",
110                         ms->mss_ndn.bv_val, 0, 0 );
111                 return( -1 );
112         }
113
114         *ep = e;
115         ep = &mp->mp_next;
116         
117         /*
118          * Current conns
119          */
120         BER_BVSTR( &bv, "cn=Current" );
121         e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
122                 mi->mi_oc_monitorCounterObject, mi, NULL, NULL );
123
124         if ( e == NULL ) {
125                 Debug( LDAP_DEBUG_ANY,
126                         "monitor_subsys_conn_init: "
127                         "unable to create entry \"cn=Current,%s\"\n",
128                         ms->mss_ndn.bv_val, 0, 0 );
129                 return( -1 );
130         }
131         
132         BER_BVSTR( &bv, "0" );
133         attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, &bv );
134         
135         mp = monitor_entrypriv_create();
136         if ( mp == NULL ) {
137                 return -1;
138         }
139         e->e_private = ( void * )mp;
140         mp->mp_info = ms;
141         mp->mp_flags = ms->mss_flags \
142                 | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
143         mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
144
145         if ( monitor_cache_add( mi, e ) ) {
146                 Debug( LDAP_DEBUG_ANY,
147                         "monitor_subsys_conn_init: "
148                         "unable to add entry \"cn=Current,%s\"\n",
149                         ms->mss_ndn.bv_val, 0, 0 );
150                 return( -1 );
151         }
152         
153         *ep = e;
154         ep = &mp->mp_next;
155
156         monitor_cache_release( mi, e_conn );
157
158         return( 0 );
159 }
160
161 static int
162 monitor_subsys_conn_update(
163         Operation               *op,
164         SlapReply               *rs,
165         Entry                   *e )
166 {
167         monitor_info_t  *mi = ( monitor_info_t * )op->o_bd->be_private;
168
169         long                    n = -1;
170         static struct berval    total_bv = BER_BVC( "cn=total" ),
171                                 current_bv = BER_BVC( "cn=current" );
172         struct berval           rdn;
173
174         assert( mi != NULL );
175         assert( e != NULL );
176
177         dnRdn( &e->e_nname, &rdn );
178         
179         if ( dn_match( &rdn, &total_bv ) ) {
180                 n = connections_nextid();
181
182         } else if ( dn_match( &rdn, &current_bv ) ) {
183                 Connection      *c;
184                 int             connindex;
185
186                 for ( n = 0, c = connection_first( &connindex );
187                                 c != NULL;
188                                 n++, c = connection_next( c, &connindex ) ) {
189                         /* No Op */ ;
190                 }
191                 connection_done( c );
192         }
193
194         if ( n != -1 ) {
195                 Attribute       *a;
196                 char            buf[] = "+9223372036854775807L";
197                 ber_len_t       len;
198
199                 a = attr_find( e->e_attrs, mi->mi_ad_monitorCounter );
200                 if ( a == NULL ) {
201                         return( -1 );
202                 }
203
204                 snprintf( buf, sizeof( buf ), "%ld", n );
205                 len = strlen( buf );
206                 if ( len > a->a_vals[ 0 ].bv_len ) {
207                         a->a_vals[ 0 ].bv_val = ber_memrealloc( a->a_vals[ 0 ].bv_val, len + 1 );
208                 }
209                 a->a_vals[ 0 ].bv_len = len;
210                 AC_MEMCPY( a->a_vals[ 0 ].bv_val, buf, len + 1 );
211
212                 /* FIXME: touch modifyTimestamp? */
213         }
214
215         return SLAP_CB_CONTINUE;
216 }
217
218 static int
219 conn_create(
220         monitor_info_t          *mi,
221         Connection              *c,
222         Entry                   **ep,
223         monitor_subsys_t        *ms )
224 {
225         monitor_entry_t *mp;
226         struct tm       *tm;
227         char            buf[ BACKMONITOR_BUFSIZE ];
228         char            buf2[ LDAP_LUTIL_GENTIME_BUFSIZE ];
229         char            buf3[ LDAP_LUTIL_GENTIME_BUFSIZE ];
230
231         struct berval bv, ctmbv, mtmbv, bv2, bv3;
232         struct berval bv_unknown= BER_BVC("unknown");
233
234         Entry           *e;
235
236 #ifdef HACK_LOCAL_TIME
237         char            ctmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
238         char            mtmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
239 #endif
240 #ifdef HAVE_GMTIME_R
241         struct tm       tm_buf;
242 #endif /* HAVE_GMTIME_R */
243
244         assert( c != NULL );
245         assert( ep != NULL );
246
247 #ifndef HAVE_GMTIME_R
248         ldap_pvt_thread_mutex_lock( &gmtime_mutex );
249 #endif
250
251 #ifdef HAVE_GMTIME_R
252         tm = gmtime_r( &c->c_starttime, &tm_buf );
253 #else
254         tm = gmtime( &c->c_starttime );
255 #endif
256         bv2.bv_len = lutil_gentime( buf2, sizeof( buf2 ), tm );
257         bv2.bv_val = buf2;
258 #ifdef HACK_LOCAL_TIME
259 # ifdef HAVE_LOCALTIME_R
260         tm = localtime_r( &c->c_starttime, &tm_buf );
261 # else
262         tm = localtime( &c->c_starttime );
263 # endif
264         ctmbv.bv_len = lutil_localtime( ctmbuf, sizeof( ctmbuf ), tm, -timezone );
265         ctmbv.bv_val = ctmbuf;
266 #else /* !HACK_LOCAL_TIME */
267         ctmbv = bv2;
268 #endif
269
270 #ifdef HAVE_GMTIME_R
271         tm = gmtime_r( &c->c_activitytime, &tm_buf );
272 #else
273         tm = gmtime( &c->c_activitytime );
274 #endif
275         bv3.bv_len = lutil_gentime( buf3, sizeof( buf3 ), tm );
276         bv3.bv_val = buf3;
277 #ifdef HACK_LOCAL_TIME
278 # ifdef HAVE_LOCALTIME_R
279         tm = localtime_r( &c->c_activitytime, &tm_buf );
280 # else
281         tm = localtime( &c->c_activitytime );
282 # endif /* HAVE_LOCALTIME_R */
283         mtmbv.bv_len = lutil_localtime( mtmbuf, sizeof( mtmbuf ), tm, -timezone );
284         mtmbv.bv_val = mtmbuf;
285 #else /* !HACK_LOCAL_TIME */
286         mtmbv = bv3;
287 #endif
288
289 #ifndef HAVE_GMTIME_R
290         ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
291 #endif
292
293         bv.bv_len = snprintf( buf, sizeof( buf ),
294                 "cn=Connection %ld", c->c_connid );
295         bv.bv_val = buf;
296         e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv, 
297                 mi->mi_oc_monitorConnection, mi, &ctmbv, &mtmbv );
298
299         if ( e == NULL) {
300                 Debug( LDAP_DEBUG_ANY,
301                         "monitor_subsys_conn_create: "
302                         "unable to create entry "
303                         "\"cn=Connection %ld,%s\"\n",
304                         c->c_connid, 
305                         ms->mss_dn.bv_val, 0 );
306                 return( -1 );
307         }
308
309 #ifdef MONITOR_LEGACY_CONN
310         /* NOTE: this will disappear, as the exploded data
311          * has been moved to dedicated attributes */
312         bv.bv_len = snprintf( buf, sizeof( buf ),
313                         "%ld "
314                         ": %ld "
315                         ": %ld/%ld/%ld/%ld "
316                         ": %ld/%ld/%ld "
317                         ": %s%s%s%s%s%s "
318                         ": %s "
319                         ": %s "
320                         ": %s "
321                         ": %s "
322                         ": %s "
323                         ": %s "
324                         ": %s",
325                         c->c_connid,
326                         (long) c->c_protocol,
327                         c->c_n_ops_received, c->c_n_ops_executing,
328                                 c->c_n_ops_pending, c->c_n_ops_completed,
329                         
330                         /* add low-level counters here */
331                         c->c_n_get, c->c_n_read, c->c_n_write,
332                         
333                         c->c_currentber ? "r" : "",
334                         c->c_writewaiter ? "w" : "",
335                         LDAP_STAILQ_EMPTY( &c->c_ops ) ? "" : "x",
336                         LDAP_STAILQ_EMPTY( &c->c_pending_ops ) ? "" : "p",
337                         connection_state2str( c->c_conn_state ),
338                         c->c_sasl_bind_in_progress ? "S" : "",
339                         
340                         c->c_dn.bv_len ? c->c_dn.bv_val : SLAPD_ANONYMOUS,
341                         
342                         c->c_listener_url.bv_val,
343                         c->c_peer_domain.bv_val,
344                         c->c_peer_name.bv_val,
345                         c->c_sock_name.bv_val,
346                         
347                         buf2,
348                         buf3 );
349         attr_merge_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
350 #endif /* MONITOR_LEGACY_CONN */
351
352         bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", c->c_connid );
353         attr_merge_one( e, mi->mi_ad_monitorConnectionNumber, &bv, NULL );
354
355         bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", (long) c->c_protocol );
356         attr_merge_one( e, mi->mi_ad_monitorConnectionProtocol, &bv, NULL );
357
358         bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_received );
359         attr_merge_one( e, mi->mi_ad_monitorConnectionOpsReceived, &bv, NULL );
360
361         bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_executing );
362         attr_merge_one( e, mi->mi_ad_monitorConnectionOpsExecuting, &bv, NULL );
363
364         bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_pending );
365         attr_merge_one( e, mi->mi_ad_monitorConnectionOpsPending, &bv, NULL );
366
367         bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_completed );
368         attr_merge_one( e, mi->mi_ad_monitorConnectionOpsCompleted, &bv, NULL );
369
370         bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_get );
371         attr_merge_one( e, mi->mi_ad_monitorConnectionGet, &bv, NULL );
372
373         bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_read );
374         attr_merge_one( e, mi->mi_ad_monitorConnectionRead, &bv, NULL );
375
376         bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_write );
377         attr_merge_one( e, mi->mi_ad_monitorConnectionWrite, &bv, NULL );
378
379         bv.bv_len = snprintf( buf, sizeof( buf ), "%s%s%s%s%s%s",
380                         c->c_currentber ? "r" : "",
381                         c->c_writewaiter ? "w" : "",
382                         LDAP_STAILQ_EMPTY( &c->c_ops ) ? "" : "x",
383                         LDAP_STAILQ_EMPTY( &c->c_pending_ops ) ? "" : "p",
384                         connection_state2str( c->c_conn_state ),
385                         c->c_sasl_bind_in_progress ? "S" : "" );
386         attr_merge_one( e, mi->mi_ad_monitorConnectionMask, &bv, NULL );
387
388         attr_merge_one( e, mi->mi_ad_monitorConnectionAuthzDN,
389                 &c->c_dn, &c->c_ndn );
390
391         /* NOTE: client connections leave the c_peer_* fields NULL */
392         attr_merge_one( e, mi->mi_ad_monitorConnectionListener,
393                 &c->c_listener_url, NULL );
394
395         attr_merge_one( e, mi->mi_ad_monitorConnectionPeerDomain,
396                 BER_BVISNULL( &c->c_peer_domain ) ? &bv_unknown : &c->c_peer_domain,
397                 NULL );
398
399         attr_merge_one( e, mi->mi_ad_monitorConnectionPeerAddress,
400                 BER_BVISNULL( &c->c_peer_name ) ? &bv_unknown : &c->c_peer_name,
401                 NULL );
402
403         attr_merge_one( e, mi->mi_ad_monitorConnectionLocalAddress,
404                 &c->c_sock_name, NULL );
405
406         attr_merge_one( e, mi->mi_ad_monitorConnectionStartTime, &bv2, NULL );
407
408         attr_merge_one( e, mi->mi_ad_monitorConnectionActivityTime, &bv3, NULL );
409
410         mp = monitor_entrypriv_create();
411         if ( mp == NULL ) {
412                 return LDAP_OTHER;
413         }
414         e->e_private = ( void * )mp;
415         mp->mp_info = ms;
416         mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE;
417
418         *ep = e;
419
420         return SLAP_CB_CONTINUE;
421 }
422
423 static int 
424 monitor_subsys_conn_create( 
425         Operation               *op,
426         SlapReply               *rs,
427         struct berval           *ndn,
428         Entry                   *e_parent,
429         Entry                   **ep )
430 {
431         monitor_info_t  *mi = ( monitor_info_t * )op->o_bd->be_private;
432
433         Connection              *c;
434         int                     connindex;
435         monitor_entry_t         *mp;
436         int                     rc = SLAP_CB_CONTINUE;
437         monitor_subsys_t        *ms;
438
439         assert( mi != NULL );
440         assert( e_parent != NULL );
441         assert( ep != NULL );
442
443         ms = (( monitor_entry_t *)e_parent->e_private)->mp_info;
444
445         *ep = NULL;
446
447         if ( ndn == NULL ) {
448                 Entry   *e = NULL,
449                         *e_tmp = NULL;
450
451                 /* create all the children of e_parent */
452                 for ( c = connection_first( &connindex );
453                                 c != NULL;
454                                 c = connection_next( c, &connindex ) )
455                 {
456                         if ( conn_create( mi, c, &e, ms ) != SLAP_CB_CONTINUE
457                                         || e == NULL )
458                         {
459                                 for ( ; e_tmp != NULL; ) {
460                                         mp = ( monitor_entry_t * )e_tmp->e_private;
461                                         e = mp->mp_next;
462
463                                         ch_free( mp );
464                                         e_tmp->e_private = NULL;
465                                         entry_free( e_tmp );
466
467                                         e_tmp = e;
468                                 }
469                                 rc = rs->sr_err = LDAP_OTHER;
470                                 break;
471                         }
472                         mp = ( monitor_entry_t * )e->e_private;
473                         mp->mp_next = e_tmp;
474                         e_tmp = e;
475                 }
476                 connection_done( c );
477                 *ep = e;
478
479         } else {
480                 unsigned long           connid;
481                 char                    *next = NULL;
482                 static struct berval    nconn_bv = BER_BVC( "cn=connection " );
483
484                 rc = LDAP_NO_SUCH_OBJECT;
485                
486                 /* create exactly the required entry;
487                  * the normalized DN must start with "cn=connection ",
488                  * followed by the connection id, followed by
489                  * the RDN separator "," */
490                 if ( ndn->bv_len <= nconn_bv.bv_len
491                                 || strncmp( ndn->bv_val, nconn_bv.bv_val, nconn_bv.bv_len ) != 0 )
492                 {
493                         return -1;
494                 }
495                 
496                 connid = strtol( &ndn->bv_val[ nconn_bv.bv_len ], &next, 10 );
497                 if ( next[ 0 ] != ',' ) {
498                         return ( rs->sr_err = LDAP_OTHER );
499                 }
500
501                 for ( c = connection_first( &connindex );
502                                 c != NULL;
503                                 c = connection_next( c, &connindex ) )
504                 {
505                         if ( c->c_connid == connid ) {
506                                 rc = conn_create( mi, c, ep, ms );
507                                 if ( rc != SLAP_CB_CONTINUE ) {
508                                         rs->sr_err = rc;
509
510                                 } else if ( *ep == NULL ) {
511                                         rc = rs->sr_err = LDAP_OTHER;
512                                 }
513
514                                 break;
515                         }
516                 }
517                 
518                 connection_done( c );
519         }
520
521         return rc;
522 }
523