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