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