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, ¤t_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