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-2011 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
31static int
32monitor_subsys_conn_update(
33	Operation		*op,
34	SlapReply		*rs,
35	Entry                   *e );
36
37static int
38monitor_subsys_conn_create(
39	Operation		*op,
40	SlapReply		*rs,
41	struct berval		*ndn,
42	Entry 			*e_parent,
43	Entry			**ep );
44
45int
46monitor_subsys_conn_init(
47	BackendDB		*be,
48	monitor_subsys_t	*ms )
49{
50	monitor_info_t	*mi;
51	Entry		*e, **ep, *e_conn;
52	monitor_entry_t	*mp;
53	char		buf[ BACKMONITOR_BUFSIZE ];
54	struct berval	bv;
55
56	assert( be != NULL );
57
58	ms->mss_update = monitor_subsys_conn_update;
59	ms->mss_create = monitor_subsys_conn_create;
60
61	mi = ( monitor_info_t * )be->be_private;
62
63	if ( monitor_cache_get( mi, &ms->mss_ndn, &e_conn ) ) {
64		Debug( LDAP_DEBUG_ANY,
65			"monitor_subsys_conn_init: "
66			"unable to get entry \"%s\"\n",
67			ms->mss_ndn.bv_val, 0, 0 );
68		return( -1 );
69	}
70
71	mp = ( monitor_entry_t * )e_conn->e_private;
72	mp->mp_children = NULL;
73	ep = &mp->mp_children;
74
75	/*
76	 * Max file descriptors
77	 */
78	BER_BVSTR( &bv, "cn=Max File Descriptors" );
79	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
80		mi->mi_oc_monitorCounterObject, mi, NULL, NULL );
81
82	if ( e == NULL ) {
83		Debug( LDAP_DEBUG_ANY,
84			"monitor_subsys_conn_init: "
85			"unable to create entry \"%s,%s\"\n",
86			bv.bv_val, ms->mss_ndn.bv_val, 0 );
87		return( -1 );
88	}
89
90	if ( dtblsize ) {
91		bv.bv_val = buf;
92		bv.bv_len = snprintf( buf, sizeof( buf ), "%d", dtblsize );
93
94	} else {
95		BER_BVSTR( &bv, "0" );
96	}
97	attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
98
99	mp = monitor_entrypriv_create();
100	if ( mp == NULL ) {
101		return -1;
102	}
103	e->e_private = ( void * )mp;
104	mp->mp_info = ms;
105	mp->mp_flags = ms->mss_flags \
106		| MONITOR_F_SUB | MONITOR_F_PERSISTENT;
107	mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
108
109	if ( monitor_cache_add( mi, e ) ) {
110		Debug( LDAP_DEBUG_ANY,
111			"monitor_subsys_conn_init: "
112			"unable to add entry \"cn=Total,%s\"\n",
113			ms->mss_ndn.bv_val, 0, 0 );
114		return( -1 );
115	}
116
117	*ep = e;
118	ep = &mp->mp_next;
119
120	/*
121	 * Total conns
122	 */
123	BER_BVSTR( &bv, "cn=Total" );
124	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
125		mi->mi_oc_monitorCounterObject, mi, NULL, NULL );
126
127	if ( e == NULL ) {
128		Debug( LDAP_DEBUG_ANY,
129			"monitor_subsys_conn_init: "
130			"unable to create entry \"cn=Total,%s\"\n",
131			ms->mss_ndn.bv_val, 0, 0 );
132		return( -1 );
133	}
134
135	BER_BVSTR( &bv, "-1" );
136	attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
137
138	mp = monitor_entrypriv_create();
139	if ( mp == NULL ) {
140		return -1;
141	}
142	e->e_private = ( void * )mp;
143	mp->mp_info = ms;
144	mp->mp_flags = ms->mss_flags \
145		| MONITOR_F_SUB | MONITOR_F_PERSISTENT;
146	mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
147
148	if ( monitor_cache_add( mi, e ) ) {
149		Debug( LDAP_DEBUG_ANY,
150			"monitor_subsys_conn_init: "
151			"unable to add entry \"cn=Total,%s\"\n",
152			ms->mss_ndn.bv_val, 0, 0 );
153		return( -1 );
154	}
155
156	*ep = e;
157	ep = &mp->mp_next;
158
159	/*
160	 * Current conns
161	 */
162	BER_BVSTR( &bv, "cn=Current" );
163	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
164		mi->mi_oc_monitorCounterObject, mi, NULL, NULL );
165
166	if ( e == NULL ) {
167		Debug( LDAP_DEBUG_ANY,
168			"monitor_subsys_conn_init: "
169			"unable to create entry \"cn=Current,%s\"\n",
170			ms->mss_ndn.bv_val, 0, 0 );
171		return( -1 );
172	}
173
174	BER_BVSTR( &bv, "0" );
175	attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
176
177	mp = monitor_entrypriv_create();
178	if ( mp == NULL ) {
179		return -1;
180	}
181	e->e_private = ( void * )mp;
182	mp->mp_info = ms;
183	mp->mp_flags = ms->mss_flags \
184		| MONITOR_F_SUB | MONITOR_F_PERSISTENT;
185	mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
186
187	if ( monitor_cache_add( mi, e ) ) {
188		Debug( LDAP_DEBUG_ANY,
189			"monitor_subsys_conn_init: "
190			"unable to add entry \"cn=Current,%s\"\n",
191			ms->mss_ndn.bv_val, 0, 0 );
192		return( -1 );
193	}
194
195	*ep = e;
196	ep = &mp->mp_next;
197
198	monitor_cache_release( mi, e_conn );
199
200	return( 0 );
201}
202
203static int
204monitor_subsys_conn_update(
205	Operation		*op,
206	SlapReply		*rs,
207	Entry                   *e )
208{
209	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
210
211	long 			n = -1;
212	static struct berval	total_bv = BER_BVC( "cn=total" ),
213				current_bv = BER_BVC( "cn=current" );
214	struct berval		rdn;
215
216	assert( mi != NULL );
217	assert( e != NULL );
218
219	dnRdn( &e->e_nname, &rdn );
220
221	if ( dn_match( &rdn, &total_bv ) ) {
222		n = connections_nextid();
223
224	} else if ( dn_match( &rdn, &current_bv ) ) {
225		Connection	*c;
226		int		connindex;
227
228		for ( n = 0, c = connection_first( &connindex );
229				c != NULL;
230				n++, c = connection_next( c, &connindex ) )
231		{
232			/* No Op */ ;
233		}
234		connection_done( c );
235	}
236
237	if ( n != -1 ) {
238		Attribute	*a;
239		char		buf[LDAP_PVT_INTTYPE_CHARS(long)];
240		ber_len_t	len;
241
242		a = attr_find( e->e_attrs, mi->mi_ad_monitorCounter );
243		if ( a == NULL ) {
244			return( -1 );
245		}
246
247		snprintf( buf, sizeof( buf ), "%ld", n );
248		len = strlen( buf );
249		if ( len > a->a_vals[ 0 ].bv_len ) {
250			a->a_vals[ 0 ].bv_val = ber_memrealloc( a->a_vals[ 0 ].bv_val, len + 1 );
251		}
252		a->a_vals[ 0 ].bv_len = len;
253		AC_MEMCPY( a->a_vals[ 0 ].bv_val, buf, len + 1 );
254
255		/* FIXME: touch modifyTimestamp? */
256	}
257
258	return SLAP_CB_CONTINUE;
259}
260
261static int
262conn_create(
263	monitor_info_t		*mi,
264	Connection		*c,
265	Entry			**ep,
266	monitor_subsys_t	*ms )
267{
268	monitor_entry_t *mp;
269	struct tm	tm;
270	char		buf[ BACKMONITOR_BUFSIZE ];
271	char		buf2[ LDAP_LUTIL_GENTIME_BUFSIZE ];
272	char		buf3[ LDAP_LUTIL_GENTIME_BUFSIZE ];
273
274	struct berval bv, ctmbv, mtmbv;
275	struct berval bv_unknown= BER_BVC("unknown");
276
277	Entry		*e;
278
279	assert( c != NULL );
280	assert( ep != NULL );
281
282	ldap_pvt_gmtime( &c->c_starttime, &tm );
283
284	ctmbv.bv_len = lutil_gentime( buf2, sizeof( buf2 ), &tm );
285	ctmbv.bv_val = buf2;
286
287	ldap_pvt_gmtime( &c->c_activitytime, &tm );
288	mtmbv.bv_len = lutil_gentime( buf3, sizeof( buf3 ), &tm );
289	mtmbv.bv_val = buf3;
290
291	bv.bv_len = snprintf( buf, sizeof( buf ),
292		"cn=Connection %ld", c->c_connid );
293	bv.bv_val = buf;
294	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
295		mi->mi_oc_monitorConnection, mi, &ctmbv, &mtmbv );
296
297	if ( e == NULL) {
298		Debug( LDAP_DEBUG_ANY,
299			"monitor_subsys_conn_create: "
300			"unable to create entry "
301			"\"cn=Connection %ld,%s\"\n",
302			c->c_connid,
303			ms->mss_dn.bv_val, 0 );
304		return( -1 );
305	}
306
307#ifdef MONITOR_LEGACY_CONN
308	/* NOTE: this will disappear, as the exploded data
309	 * has been moved to dedicated attributes */
310	bv.bv_len = snprintf( buf, sizeof( buf ),
311			"%ld "
312			": %ld "
313			": %ld/%ld/%ld/%ld "
314			": %ld/%ld/%ld "
315			": %s%s%s%s%s%s "
316			": %s "
317			": %s "
318			": %s "
319			": %s "
320			": %s "
321			": %s "
322			": %s",
323			c->c_connid,
324			(long) c->c_protocol,
325			c->c_n_ops_received, c->c_n_ops_executing,
326				c->c_n_ops_pending, c->c_n_ops_completed,
327
328			/* add low-level counters here */
329			c->c_n_get, c->c_n_read, c->c_n_write,
330
331			c->c_currentber ? "r" : "",
332			c->c_writewaiter ? "w" : "",
333			LDAP_STAILQ_EMPTY( &c->c_ops ) ? "" : "x",
334			LDAP_STAILQ_EMPTY( &c->c_pending_ops ) ? "" : "p",
335			connection_state2str( c->c_conn_state ),
336			c->c_sasl_bind_in_progress ? "S" : "",
337
338			c->c_dn.bv_len ? c->c_dn.bv_val : SLAPD_ANONYMOUS,
339
340			c->c_listener_url.bv_val,
341			BER_BVISNULL( &c->c_peer_domain )
342				? "" : c->c_peer_domain.bv_val,
343			BER_BVISNULL( &c->c_peer_name )
344				? "" : c->c_peer_name.bv_val,
345			c->c_sock_name.bv_val,
346
347			buf2,
348			buf3 );
349	attr_merge_normalize_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_normalize_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_normalize_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	assert( !BER_BVISNULL( &c->c_listener_url ) );
393	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionListener,
394		&c->c_listener_url, NULL );
395
396	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionPeerDomain,
397		BER_BVISNULL( &c->c_peer_domain ) ? &bv_unknown : &c->c_peer_domain,
398		NULL );
399
400	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionPeerAddress,
401		BER_BVISNULL( &c->c_peer_name ) ? &bv_unknown : &c->c_peer_name,
402		NULL );
403
404	assert( !BER_BVISNULL( &c->c_sock_name ) );
405	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionLocalAddress,
406		&c->c_sock_name, NULL );
407
408	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionStartTime, &ctmbv, NULL );
409
410	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionActivityTime, &mtmbv, NULL );
411
412	mp = monitor_entrypriv_create();
413	if ( mp == NULL ) {
414		return LDAP_OTHER;
415	}
416	e->e_private = ( void * )mp;
417	mp->mp_info = ms;
418	mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE;
419
420	*ep = e;
421
422	return SLAP_CB_CONTINUE;
423}
424
425static int
426monitor_subsys_conn_create(
427	Operation		*op,
428	SlapReply		*rs,
429	struct berval		*ndn,
430	Entry 			*e_parent,
431	Entry			**ep )
432{
433	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
434
435	int			rc = SLAP_CB_CONTINUE;
436	monitor_subsys_t	*ms;
437
438	assert( mi != NULL );
439	assert( e_parent != NULL );
440	assert( ep != NULL );
441
442	ms = (( monitor_entry_t *)e_parent->e_private)->mp_info;
443
444	*ep = NULL;
445
446	if ( ndn == NULL ) {
447		Connection	*c;
448		int		connindex;
449		Entry		*e = NULL,
450				*e_tmp = NULL;
451
452		/* create all the children of e_parent */
453		for ( c = connection_first( &connindex );
454				c != NULL;
455				c = connection_next( c, &connindex ) )
456		{
457			monitor_entry_t 	*mp;
458
459			if ( conn_create( mi, c, &e, ms ) != SLAP_CB_CONTINUE
460					|| e == NULL )
461			{
462				for ( ; e_tmp != NULL; ) {
463					mp = ( monitor_entry_t * )e_tmp->e_private;
464					e = mp->mp_next;
465
466					ch_free( mp );
467					e_tmp->e_private = NULL;
468					entry_free( e_tmp );
469
470					e_tmp = e;
471				}
472				rc = rs->sr_err = LDAP_OTHER;
473				break;
474			}
475			mp = ( monitor_entry_t * )e->e_private;
476			mp->mp_next = e_tmp;
477			e_tmp = e;
478		}
479		connection_done( c );
480		*ep = e;
481
482	} else {
483		Connection		*c;
484		int			connindex;
485		unsigned long 		connid;
486		char			*next = NULL;
487		static struct berval	nconn_bv = BER_BVC( "cn=connection " );
488
489		rc = LDAP_NO_SUCH_OBJECT;
490
491		/* create exactly the required entry;
492		 * the normalized DN must start with "cn=connection ",
493		 * followed by the connection id, followed by
494		 * the RDN separator "," */
495		if ( ndn->bv_len <= nconn_bv.bv_len
496				|| strncmp( ndn->bv_val, nconn_bv.bv_val, nconn_bv.bv_len ) != 0 )
497		{
498			return -1;
499		}
500
501		connid = strtol( &ndn->bv_val[ nconn_bv.bv_len ], &next, 10 );
502		if ( next[ 0 ] != ',' ) {
503			return ( rs->sr_err = LDAP_OTHER );
504		}
505
506		for ( c = connection_first( &connindex );
507				c != NULL;
508				c = connection_next( c, &connindex ) )
509		{
510			if ( c->c_connid == connid ) {
511				rc = conn_create( mi, c, ep, ms );
512				if ( rc != SLAP_CB_CONTINUE ) {
513					rs->sr_err = rc;
514
515				} else if ( *ep == NULL ) {
516					rc = rs->sr_err = LDAP_OTHER;
517				}
518
519				break;
520			}
521		}
522
523		connection_done( c );
524	}
525
526	return rc;
527}
528
529