1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets-test-server - libwebsockets test implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2021 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci * 9d4afb5ceSopenharmony_ci * The person who associated a work with this deed has dedicated 10d4afb5ceSopenharmony_ci * the work to the public domain by waiving all of his or her rights 11d4afb5ceSopenharmony_ci * to the work worldwide under copyright law, including all related 12d4afb5ceSopenharmony_ci * and neighboring rights, to the extent allowed by law. You can copy, 13d4afb5ceSopenharmony_ci * modify, distribute and perform the work, even for commercial purposes, 14d4afb5ceSopenharmony_ci * all without asking permission. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * The test apps are intended to be adapted for use in your code, which 17d4afb5ceSopenharmony_ci * may be proprietary. So unlike the library itself, they are licensed 18d4afb5ceSopenharmony_ci * Public Domain. 19d4afb5ceSopenharmony_ci * 20d4afb5ceSopenharmony_ci * Scrapeable, proxiable OpenMetrics metrics (compatible with Prometheus) 21d4afb5ceSopenharmony_ci * 22d4afb5ceSopenharmony_ci * https://tools.ietf.org/html/draft-richih-opsawg-openmetrics-00 23d4afb5ceSopenharmony_ci * 24d4afb5ceSopenharmony_ci * This plugin provides four protocols related to openmetrics handling: 25d4afb5ceSopenharmony_ci * 26d4afb5ceSopenharmony_ci * 1) "lws-openmetrics" direct http listener so scraper can directly get metrics 27d4afb5ceSopenharmony_ci * 28d4afb5ceSopenharmony_ci * 2) "lws-openmetrics-prox-agg" metrics proxy server that scraper can connect 29d4afb5ceSopenharmony_ci * to locally to proxy through to connected remote clients at 3) 30d4afb5ceSopenharmony_ci * 31d4afb5ceSopenharmony_ci * 3) "lws-openmetrics-prox-server" metrics proxy server that remote clients can 32d4afb5ceSopenharmony_ci * connect to, providing a path where scrapers at 2) can get metrics from 33d4afb5ceSopenharmony_ci * clients connected us 34d4afb5ceSopenharmony_ci * 35d4afb5ceSopenharmony_ci * 4) "lws-openmetrics-prox-client" nailed-up metrics proxy client that tries to 36d4afb5ceSopenharmony_ci * keep up a connection to the server at 3), allowing to scraper to reach 37d4afb5ceSopenharmony_ci * clients that have no reachable way to serve. 38d4afb5ceSopenharmony_ci * 39d4afb5ceSopenharmony_ci * These are provided like this to maximize flexibility in being able to add 40d4afb5ceSopenharmony_ci * openmetrics serving, proxying, or client->proxy to existing lws code. 41d4afb5ceSopenharmony_ci * 42d4afb5ceSopenharmony_ci * Openmetrics supports a "metric" at the top of its report that describes the 43d4afb5ceSopenharmony_ci * source aka "target metadata". 44d4afb5ceSopenharmony_ci * 45d4afb5ceSopenharmony_ci * Since we want to enable collection from devices that are not externally 46d4afb5ceSopenharmony_ci * reachable, we must provide a reachable server that the clients can attach to 47d4afb5ceSopenharmony_ci * and have their stats aggregated and then read by Prometheus or whatever. 48d4afb5ceSopenharmony_ci * Openmetrics says that it wants to present the aggregated stats in a flat 49d4afb5ceSopenharmony_ci * summary with only the aggregator's "target metadata" and contributor targets 50d4afb5ceSopenharmony_ci * getting their data tagged with the source 51d4afb5ceSopenharmony_ci * 52d4afb5ceSopenharmony_ci * "The above discussion is in the context of individual exposers. An 53d4afb5ceSopenharmony_ci * exposition from a general purpose monitoring system may contain 54d4afb5ceSopenharmony_ci * metrics from many individual targets, and thus may expose multiple 55d4afb5ceSopenharmony_ci * target info Metrics. The metrics may already have had target 56d4afb5ceSopenharmony_ci * metadata added to them as labels as part of ingestion. The metric 57d4afb5ceSopenharmony_ci * names MUST NOT be varied based on target metadata. For example it 58d4afb5ceSopenharmony_ci * would be incorrect for all metrics to end up being prefixed with 59d4afb5ceSopenharmony_ci * staging_ even if they all originated from targets in a staging 60d4afb5ceSopenharmony_ci * environment)." 61d4afb5ceSopenharmony_ci */ 62d4afb5ceSopenharmony_ci 63d4afb5ceSopenharmony_ci#if !defined (LWS_PLUGIN_STATIC) 64d4afb5ceSopenharmony_ci#if !defined(LWS_DLL) 65d4afb5ceSopenharmony_ci#define LWS_DLL 66d4afb5ceSopenharmony_ci#endif 67d4afb5ceSopenharmony_ci#if !defined(LWS_INTERNAL) 68d4afb5ceSopenharmony_ci#define LWS_INTERNAL 69d4afb5ceSopenharmony_ci#endif 70d4afb5ceSopenharmony_ci#include <libwebsockets.h> 71d4afb5ceSopenharmony_ci#endif 72d4afb5ceSopenharmony_ci#include <string.h> 73d4afb5ceSopenharmony_ci#include <stdlib.h> 74d4afb5ceSopenharmony_ci#include <sys/stat.h> 75d4afb5ceSopenharmony_ci#include <fcntl.h> 76d4afb5ceSopenharmony_ci#if !defined(WIN32) 77d4afb5ceSopenharmony_ci#include <unistd.h> 78d4afb5ceSopenharmony_ci#endif 79d4afb5ceSopenharmony_ci#include <assert.h> 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_cistruct vhd { 82d4afb5ceSopenharmony_ci struct lws_context *cx; 83d4afb5ceSopenharmony_ci struct lws_vhost *vhost; 84d4afb5ceSopenharmony_ci 85d4afb5ceSopenharmony_ci char ws_server_uri[128]; 86d4afb5ceSopenharmony_ci char metrics_proxy_path[128]; 87d4afb5ceSopenharmony_ci char ba_secret[128]; 88d4afb5ceSopenharmony_ci 89d4afb5ceSopenharmony_ci const char *proxy_side_bind_name; 90d4afb5ceSopenharmony_ci /**< name used to bind the two halves of the proxy together, must be 91d4afb5ceSopenharmony_ci * the same name given in a pvo for both "lws-openmetrics-prox-agg" 92d4afb5ceSopenharmony_ci * (the side local to the scraper) and "lws-openmetrics-prox-server" 93d4afb5ceSopenharmony_ci * (the side the clients connect to) 94d4afb5ceSopenharmony_ci */ 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_ci char sanity[8]; 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci lws_dll2_owner_t clients; 99d4afb5ceSopenharmony_ci 100d4afb5ceSopenharmony_ci lws_sorted_usec_list_t sul; /* schedule connection retry */ 101d4afb5ceSopenharmony_ci 102d4afb5ceSopenharmony_ci struct vhd *bind_partner_vhd; 103d4afb5ceSopenharmony_ci 104d4afb5ceSopenharmony_ci struct lws *wsi; /* related wsi if any */ 105d4afb5ceSopenharmony_ci uint16_t retry_count; /* count of consequetive retries */ 106d4afb5ceSopenharmony_ci}; 107d4afb5ceSopenharmony_ci 108d4afb5ceSopenharmony_cistruct pss { 109d4afb5ceSopenharmony_ci lws_dll2_t list; 110d4afb5ceSopenharmony_ci char proxy_path[64]; 111d4afb5ceSopenharmony_ci struct lwsac *ac; /* the translated metrics, one ac per line */ 112d4afb5ceSopenharmony_ci struct lwsac *walk; /* iterator for ac when writing */ 113d4afb5ceSopenharmony_ci size_t tot; /* content-length computation */ 114d4afb5ceSopenharmony_ci struct lws *wsi; 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci uint8_t greet:1; /* set if client needs to send proxy path */ 117d4afb5ceSopenharmony_ci uint8_t trigger:1; /* we want to ask the client to dump */ 118d4afb5ceSopenharmony_ci}; 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 121d4afb5ceSopenharmony_cistatic const uint32_t backoff_ms[] = { 1000, 2000, 3000, 4000, 5000 }; 122d4afb5ceSopenharmony_ci 123d4afb5ceSopenharmony_cistatic const lws_retry_bo_t retry = { 124d4afb5ceSopenharmony_ci .retry_ms_table = backoff_ms, 125d4afb5ceSopenharmony_ci .retry_ms_table_count = LWS_ARRAY_SIZE(backoff_ms), 126d4afb5ceSopenharmony_ci .conceal_count = LWS_ARRAY_SIZE(backoff_ms), 127d4afb5ceSopenharmony_ci 128d4afb5ceSopenharmony_ci .secs_since_valid_ping = 400, /* force PINGs after secs idle */ 129d4afb5ceSopenharmony_ci .secs_since_valid_hangup = 400, /* hangup after secs idle */ 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_ci .jitter_percent = 0, 132d4afb5ceSopenharmony_ci}; 133d4afb5ceSopenharmony_ci 134d4afb5ceSopenharmony_cistatic void 135d4afb5ceSopenharmony_ciomc_connect_client(lws_sorted_usec_list_t *sul) 136d4afb5ceSopenharmony_ci{ 137d4afb5ceSopenharmony_ci struct vhd *vhd = lws_container_of(sul, struct vhd, sul); 138d4afb5ceSopenharmony_ci struct lws_client_connect_info i; 139d4afb5ceSopenharmony_ci const char *prot; 140d4afb5ceSopenharmony_ci char url[128]; 141d4afb5ceSopenharmony_ci 142d4afb5ceSopenharmony_ci memset(&i, 0, sizeof(i)); 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci lwsl_notice("%s: %s %s %s\n", __func__, vhd->ws_server_uri, vhd->metrics_proxy_path, vhd->ba_secret); 145d4afb5ceSopenharmony_ci 146d4afb5ceSopenharmony_ci lws_strncpy(url, vhd->ws_server_uri, sizeof(url)); 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci if (lws_parse_uri(url, &prot, &i.address, &i.port, &i.path)) { 149d4afb5ceSopenharmony_ci lwsl_err("%s: unable to parse uri %s\n", __func__, 150d4afb5ceSopenharmony_ci vhd->ws_server_uri); 151d4afb5ceSopenharmony_ci return; 152d4afb5ceSopenharmony_ci } 153d4afb5ceSopenharmony_ci 154d4afb5ceSopenharmony_ci i.context = vhd->cx; 155d4afb5ceSopenharmony_ci i.origin = i.address; 156d4afb5ceSopenharmony_ci i.host = i.address; 157d4afb5ceSopenharmony_ci i.ssl_connection = LCCSCF_USE_SSL; 158d4afb5ceSopenharmony_ci i.protocol = "lws-openmetrics-prox-server"; /* public subprot */ 159d4afb5ceSopenharmony_ci i.local_protocol_name = "lws-openmetrics-prox-client"; 160d4afb5ceSopenharmony_ci i.pwsi = &vhd->wsi; 161d4afb5ceSopenharmony_ci i.retry_and_idle_policy = &retry; 162d4afb5ceSopenharmony_ci i.userdata = vhd; 163d4afb5ceSopenharmony_ci i.vhost = vhd->vhost; 164d4afb5ceSopenharmony_ci 165d4afb5ceSopenharmony_ci lwsl_notice("%s: %s %u %s\n", __func__, i.address, i.port, i.path); 166d4afb5ceSopenharmony_ci 167d4afb5ceSopenharmony_ci if (lws_client_connect_via_info(&i)) 168d4afb5ceSopenharmony_ci return; 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_ci /* 171d4afb5ceSopenharmony_ci * Failed... schedule a retry... we can't use the _retry_wsi() 172d4afb5ceSopenharmony_ci * convenience wrapper api here because no valid wsi at this 173d4afb5ceSopenharmony_ci * point. 174d4afb5ceSopenharmony_ci */ 175d4afb5ceSopenharmony_ci if (!lws_retry_sul_schedule(vhd->cx, 0, sul, &retry, 176d4afb5ceSopenharmony_ci omc_connect_client, &vhd->retry_count)) 177d4afb5ceSopenharmony_ci return; 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci vhd->retry_count = 0; 180d4afb5ceSopenharmony_ci lws_retry_sul_schedule(vhd->cx, 0, sul, &retry, 181d4afb5ceSopenharmony_ci omc_connect_client, &vhd->retry_count); 182d4afb5ceSopenharmony_ci} 183d4afb5ceSopenharmony_ci#endif 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_cistatic void 186d4afb5ceSopenharmony_ciopenmetrics_san(char *nm, size_t nl) 187d4afb5ceSopenharmony_ci{ 188d4afb5ceSopenharmony_ci size_t m; 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci /* Openmetrics has a very restricted token charset */ 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_ci for (m = 0; m < nl; m++) 193d4afb5ceSopenharmony_ci if ((nm[m] < 'A' || nm[m] > 'Z') && 194d4afb5ceSopenharmony_ci (nm[m] < 'a' || nm[m] > 'z') && 195d4afb5ceSopenharmony_ci (nm[m] < '0' || nm[m] > '9') && 196d4afb5ceSopenharmony_ci nm[m] != '_') 197d4afb5ceSopenharmony_ci nm[m] = '_'; 198d4afb5ceSopenharmony_ci} 199d4afb5ceSopenharmony_ci 200d4afb5ceSopenharmony_cistatic int 201d4afb5ceSopenharmony_cilws_metrics_om_format_agg(lws_metric_pub_t *pub, const char *nm, lws_usec_t now, 202d4afb5ceSopenharmony_ci int gng, char *buf, size_t len) 203d4afb5ceSopenharmony_ci{ 204d4afb5ceSopenharmony_ci const char *_gng = gng ? "_nogo" : "_go"; 205d4afb5ceSopenharmony_ci char *end = buf + len - 1, *obuf = buf; 206d4afb5ceSopenharmony_ci 207d4afb5ceSopenharmony_ci if (pub->flags & LWSMTFL_REPORT_ONLY_GO) 208d4afb5ceSopenharmony_ci _gng = ""; 209d4afb5ceSopenharmony_ci 210d4afb5ceSopenharmony_ci if (!(pub->flags & LWSMTFL_REPORT_MEAN)) { 211d4afb5ceSopenharmony_ci /* only the sum is meaningful */ 212d4afb5ceSopenharmony_ci if (pub->flags & LWSMTFL_REPORT_DUTY_WALLCLOCK_US) { 213d4afb5ceSopenharmony_ci buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), 214d4afb5ceSopenharmony_ci "%s_count %u\n" 215d4afb5ceSopenharmony_ci "%s_us_sum %llu\n" 216d4afb5ceSopenharmony_ci "%s_created %lu.%06u\n", 217d4afb5ceSopenharmony_ci nm, (unsigned int)pub->u.agg.count[gng], 218d4afb5ceSopenharmony_ci nm, (unsigned long long)pub->u.agg.sum[gng], 219d4afb5ceSopenharmony_ci nm, (unsigned long)(pub->us_first / 1000000), 220d4afb5ceSopenharmony_ci (unsigned int)(pub->us_first % 1000000)); 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_ci return lws_ptr_diff(buf, obuf); 223d4afb5ceSopenharmony_ci } 224d4afb5ceSopenharmony_ci 225d4afb5ceSopenharmony_ci /* it's a monotonic ordinal, like total tx */ 226d4afb5ceSopenharmony_ci buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), 227d4afb5ceSopenharmony_ci "%s%s_count %u\n" 228d4afb5ceSopenharmony_ci "%s%s_sum %llu\n", 229d4afb5ceSopenharmony_ci nm, _gng, 230d4afb5ceSopenharmony_ci (unsigned int)pub->u.agg.count[gng], 231d4afb5ceSopenharmony_ci nm, _gng, 232d4afb5ceSopenharmony_ci (unsigned long long)pub->u.agg.sum[gng]); 233d4afb5ceSopenharmony_ci 234d4afb5ceSopenharmony_ci } else 235d4afb5ceSopenharmony_ci buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), 236d4afb5ceSopenharmony_ci "%s%s_count %u\n" 237d4afb5ceSopenharmony_ci "%s%s_mean %llu\n", 238d4afb5ceSopenharmony_ci nm, _gng, 239d4afb5ceSopenharmony_ci (unsigned int)pub->u.agg.count[gng], 240d4afb5ceSopenharmony_ci nm, _gng, (unsigned long long) 241d4afb5ceSopenharmony_ci (pub->u.agg.count[gng] ? 242d4afb5ceSopenharmony_ci pub->u.agg.sum[gng] / 243d4afb5ceSopenharmony_ci pub->u.agg.count[gng] : 0)); 244d4afb5ceSopenharmony_ci 245d4afb5ceSopenharmony_ci return lws_ptr_diff(buf, obuf); 246d4afb5ceSopenharmony_ci} 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_cistatic int 249d4afb5ceSopenharmony_cilws_metrics_om_ac_stash(struct pss *pss, const char *buf, size_t len) 250d4afb5ceSopenharmony_ci{ 251d4afb5ceSopenharmony_ci char *q; 252d4afb5ceSopenharmony_ci 253d4afb5ceSopenharmony_ci q = lwsac_use(&pss->ac, LWS_PRE + len + 2, LWS_PRE + len + 2); 254d4afb5ceSopenharmony_ci if (!q) { 255d4afb5ceSopenharmony_ci lwsac_free(&pss->ac); 256d4afb5ceSopenharmony_ci 257d4afb5ceSopenharmony_ci return -1; 258d4afb5ceSopenharmony_ci } 259d4afb5ceSopenharmony_ci q[LWS_PRE] = (char)((len >> 8) & 0xff); 260d4afb5ceSopenharmony_ci q[LWS_PRE + 1] = (char)(len & 0xff); 261d4afb5ceSopenharmony_ci memcpy(q + LWS_PRE + 2, buf, len); 262d4afb5ceSopenharmony_ci pss->tot += len; 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci return 0; 265d4afb5ceSopenharmony_ci} 266d4afb5ceSopenharmony_ci 267d4afb5ceSopenharmony_ci/* 268d4afb5ceSopenharmony_ci * We have to do the ac listing at this level, because there can be too large 269d4afb5ceSopenharmony_ci * a number to metrics tags to iterate that can fit in a reasonable buffer. 270d4afb5ceSopenharmony_ci */ 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_cistatic int 273d4afb5ceSopenharmony_cilws_metrics_om_format(struct pss *pss, lws_metric_pub_t *pub, const char *nm) 274d4afb5ceSopenharmony_ci{ 275d4afb5ceSopenharmony_ci char buf[1200], *p = buf, *end = buf + sizeof(buf) - 1, tmp[512]; 276d4afb5ceSopenharmony_ci lws_usec_t t = lws_now_usecs(); 277d4afb5ceSopenharmony_ci 278d4afb5ceSopenharmony_ci if (pub->flags & LWSMTFL_REPORT_HIST) { 279d4afb5ceSopenharmony_ci lws_metric_bucket_t *buck = pub->u.hist.head; 280d4afb5ceSopenharmony_ci 281d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 282d4afb5ceSopenharmony_ci "%s_count %llu\n", 283d4afb5ceSopenharmony_ci nm, (unsigned long long) 284d4afb5ceSopenharmony_ci pub->u.hist.total_count); 285d4afb5ceSopenharmony_ci 286d4afb5ceSopenharmony_ci while (buck) { 287d4afb5ceSopenharmony_ci lws_strncpy(tmp, lws_metric_bucket_name(buck), 288d4afb5ceSopenharmony_ci sizeof(tmp)); 289d4afb5ceSopenharmony_ci 290d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 291d4afb5ceSopenharmony_ci "%s{%s} %llu\n", nm, tmp, 292d4afb5ceSopenharmony_ci (unsigned long long)buck->count); 293d4afb5ceSopenharmony_ci 294d4afb5ceSopenharmony_ci lws_metrics_om_ac_stash(pss, buf, 295d4afb5ceSopenharmony_ci lws_ptr_diff_size_t(p, buf)); 296d4afb5ceSopenharmony_ci p = buf; 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_ci buck = buck->next; 299d4afb5ceSopenharmony_ci } 300d4afb5ceSopenharmony_ci 301d4afb5ceSopenharmony_ci goto happy; 302d4afb5ceSopenharmony_ci } 303d4afb5ceSopenharmony_ci 304d4afb5ceSopenharmony_ci if (!pub->u.agg.count[METRES_GO] && !pub->u.agg.count[METRES_NOGO]) 305d4afb5ceSopenharmony_ci return 0; 306d4afb5ceSopenharmony_ci 307d4afb5ceSopenharmony_ci if (pub->u.agg.count[METRES_GO]) 308d4afb5ceSopenharmony_ci p += lws_metrics_om_format_agg(pub, nm, t, METRES_GO, p, 309d4afb5ceSopenharmony_ci lws_ptr_diff_size_t(end, p)); 310d4afb5ceSopenharmony_ci 311d4afb5ceSopenharmony_ci if (!(pub->flags & LWSMTFL_REPORT_ONLY_GO) && 312d4afb5ceSopenharmony_ci pub->u.agg.count[METRES_NOGO]) 313d4afb5ceSopenharmony_ci p += lws_metrics_om_format_agg(pub, nm, t, METRES_NOGO, p, 314d4afb5ceSopenharmony_ci lws_ptr_diff_size_t(end, p)); 315d4afb5ceSopenharmony_ci 316d4afb5ceSopenharmony_ci if (pub->flags & LWSMTFL_REPORT_MEAN) 317d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 318d4afb5ceSopenharmony_ci "%s_min %llu\n" 319d4afb5ceSopenharmony_ci "%s_max %llu\n", 320d4afb5ceSopenharmony_ci nm, (unsigned long long)pub->u.agg.min, 321d4afb5ceSopenharmony_ci nm, (unsigned long long)pub->u.agg.max); 322d4afb5ceSopenharmony_ci 323d4afb5ceSopenharmony_cihappy: 324d4afb5ceSopenharmony_ci return lws_metrics_om_ac_stash(pss, buf, lws_ptr_diff_size_t(p, buf)); 325d4afb5ceSopenharmony_ci} 326d4afb5ceSopenharmony_ci 327d4afb5ceSopenharmony_cistatic int 328d4afb5ceSopenharmony_ciappend_om_metric(lws_metric_pub_t *pub, void *user) 329d4afb5ceSopenharmony_ci{ 330d4afb5ceSopenharmony_ci struct pss *pss = (struct pss *)user; 331d4afb5ceSopenharmony_ci char nm[64]; 332d4afb5ceSopenharmony_ci size_t nl; 333d4afb5ceSopenharmony_ci 334d4afb5ceSopenharmony_ci /* 335d4afb5ceSopenharmony_ci * Convert lws_metrics to openmetrics metrics data, stashing into an 336d4afb5ceSopenharmony_ci * lwsac without backfill. Since it's not backfilling, use areas are in 337d4afb5ceSopenharmony_ci * linear sequence simplifying walking them. Limiting the lwsac alloc 338d4afb5ceSopenharmony_ci * to less than a typical mtu means we can write one per write 339d4afb5ceSopenharmony_ci * efficiently 340d4afb5ceSopenharmony_ci */ 341d4afb5ceSopenharmony_ci 342d4afb5ceSopenharmony_ci lws_strncpy(nm, pub->name, sizeof(nm)); 343d4afb5ceSopenharmony_ci nl = strlen(nm); 344d4afb5ceSopenharmony_ci 345d4afb5ceSopenharmony_ci openmetrics_san(nm, nl); 346d4afb5ceSopenharmony_ci 347d4afb5ceSopenharmony_ci return lws_metrics_om_format(pss, pub, nm); 348d4afb5ceSopenharmony_ci} 349d4afb5ceSopenharmony_ci 350d4afb5ceSopenharmony_ci#if defined(__linux__) 351d4afb5ceSopenharmony_cistatic int 352d4afb5ceSopenharmony_cigrabfile(const char *fi, char *buf, size_t len) 353d4afb5ceSopenharmony_ci{ 354d4afb5ceSopenharmony_ci int n, fd = lws_open(fi, LWS_O_RDONLY); 355d4afb5ceSopenharmony_ci 356d4afb5ceSopenharmony_ci buf[0] = '\0'; 357d4afb5ceSopenharmony_ci if (fd < 0) 358d4afb5ceSopenharmony_ci return -1; 359d4afb5ceSopenharmony_ci 360d4afb5ceSopenharmony_ci n = (int)read(fd, buf, len - 1); 361d4afb5ceSopenharmony_ci close(fd); 362d4afb5ceSopenharmony_ci if (n < 0) { 363d4afb5ceSopenharmony_ci buf[0] = '\0'; 364d4afb5ceSopenharmony_ci return -1; 365d4afb5ceSopenharmony_ci } 366d4afb5ceSopenharmony_ci 367d4afb5ceSopenharmony_ci buf[n] = '\0'; 368d4afb5ceSopenharmony_ci if (n > 0 && buf[n - 1] == '\n') 369d4afb5ceSopenharmony_ci buf[--n] = '\0'; 370d4afb5ceSopenharmony_ci 371d4afb5ceSopenharmony_ci return n; 372d4afb5ceSopenharmony_ci} 373d4afb5ceSopenharmony_ci#endif 374d4afb5ceSopenharmony_ci 375d4afb5ceSopenharmony_ci/* 376d4afb5ceSopenharmony_ci * Let's pregenerate the output into an lwsac all at once and 377d4afb5ceSopenharmony_ci * then spool it back to the peer afterwards 378d4afb5ceSopenharmony_ci * 379d4afb5ceSopenharmony_ci * - there's not going to be that much of it (a few kB) 380d4afb5ceSopenharmony_ci * - we then know the content-length for the headers 381d4afb5ceSopenharmony_ci * - it's stretchy to arbitrary numbers of metrics 382d4afb5ceSopenharmony_ci * - lwsac block list provides the per-metric structure to 383d4afb5ceSopenharmony_ci * hold the data in a way we can walk to write it simply 384d4afb5ceSopenharmony_ci */ 385d4afb5ceSopenharmony_ci 386d4afb5ceSopenharmony_ciint 387d4afb5ceSopenharmony_ciome_prepare(struct lws_context *ctx, struct pss *pss) 388d4afb5ceSopenharmony_ci{ 389d4afb5ceSopenharmony_ci char buf[1224], *start = buf + LWS_PRE, *p = start, 390d4afb5ceSopenharmony_ci *end = buf + sizeof(buf) - 1; 391d4afb5ceSopenharmony_ci char hn[64]; 392d4afb5ceSopenharmony_ci 393d4afb5ceSopenharmony_ci pss->tot = 0; 394d4afb5ceSopenharmony_ci 395d4afb5ceSopenharmony_ci /* 396d4afb5ceSopenharmony_ci * Target metadata 397d4afb5ceSopenharmony_ci */ 398d4afb5ceSopenharmony_ci 399d4afb5ceSopenharmony_ci hn[0] = '\0'; 400d4afb5ceSopenharmony_ci gethostname(hn, sizeof(hn) - 1); 401d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 402d4afb5ceSopenharmony_ci "# TYPE target info\n" 403d4afb5ceSopenharmony_ci "# HELP target Target metadata\n" 404d4afb5ceSopenharmony_ci "target_info{hostname=\"%s\"", hn); 405d4afb5ceSopenharmony_ci 406d4afb5ceSopenharmony_ci#if defined(__linux__) 407d4afb5ceSopenharmony_ci if (grabfile("/proc/self/cmdline", hn, sizeof(hn))) 408d4afb5ceSopenharmony_ci p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), 409d4afb5ceSopenharmony_ci ",cmdline=\"%s\"", hn); 410d4afb5ceSopenharmony_ci#endif 411d4afb5ceSopenharmony_ci 412d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "} 1\n"); 413d4afb5ceSopenharmony_ci 414d4afb5ceSopenharmony_ci if (lws_metrics_om_ac_stash(pss, (const char *)buf + LWS_PRE, 415d4afb5ceSopenharmony_ci lws_ptr_diff_size_t(p, buf + LWS_PRE))) 416d4afb5ceSopenharmony_ci return 1; 417d4afb5ceSopenharmony_ci 418d4afb5ceSopenharmony_ci /* lws version */ 419d4afb5ceSopenharmony_ci 420d4afb5ceSopenharmony_ci p = start; 421d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 422d4afb5ceSopenharmony_ci "# TYPE lws_info info\n" 423d4afb5ceSopenharmony_ci "# HELP lws_info Version of lws producing this\n" 424d4afb5ceSopenharmony_ci "lws_info{version=\"%s\"} 1\n", LWS_BUILD_HASH); 425d4afb5ceSopenharmony_ci if (lws_metrics_om_ac_stash(pss, (const char *)buf + LWS_PRE, 426d4afb5ceSopenharmony_ci lws_ptr_diff_size_t(p, buf + LWS_PRE))) 427d4afb5ceSopenharmony_ci return 1; 428d4afb5ceSopenharmony_ci 429d4afb5ceSopenharmony_ci /* system scalars */ 430d4afb5ceSopenharmony_ci 431d4afb5ceSopenharmony_ci#if defined(__linux__) 432d4afb5ceSopenharmony_ci if (grabfile("/proc/loadavg", hn, sizeof(hn))) { 433d4afb5ceSopenharmony_ci char *sp = strchr(hn, ' '); 434d4afb5ceSopenharmony_ci if (sp) { 435d4afb5ceSopenharmony_ci p = start; 436d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 437d4afb5ceSopenharmony_ci "load_1m %.*s\n", 438d4afb5ceSopenharmony_ci lws_ptr_diff(sp, hn), hn); 439d4afb5ceSopenharmony_ci if (lws_metrics_om_ac_stash(pss, 440d4afb5ceSopenharmony_ci (char *)buf + LWS_PRE, 441d4afb5ceSopenharmony_ci lws_ptr_diff_size_t(p, 442d4afb5ceSopenharmony_ci start))) 443d4afb5ceSopenharmony_ci return 1; 444d4afb5ceSopenharmony_ci } 445d4afb5ceSopenharmony_ci } 446d4afb5ceSopenharmony_ci#endif 447d4afb5ceSopenharmony_ci 448d4afb5ceSopenharmony_ci if (lws_metrics_foreach(ctx, pss, append_om_metric)) 449d4afb5ceSopenharmony_ci return 1; 450d4afb5ceSopenharmony_ci 451d4afb5ceSopenharmony_ci p = start; 452d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 453d4afb5ceSopenharmony_ci "# EOF\n"); 454d4afb5ceSopenharmony_ci if (lws_metrics_om_ac_stash(pss, (char *)buf + LWS_PRE, 455d4afb5ceSopenharmony_ci lws_ptr_diff_size_t(p, buf + LWS_PRE))) 456d4afb5ceSopenharmony_ci return 1; 457d4afb5ceSopenharmony_ci 458d4afb5ceSopenharmony_ci pss->walk = pss->ac; 459d4afb5ceSopenharmony_ci 460d4afb5ceSopenharmony_ci return 0; 461d4afb5ceSopenharmony_ci} 462d4afb5ceSopenharmony_ci 463d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 464d4afb5ceSopenharmony_ci 465d4afb5ceSopenharmony_ci/* 1) direct http export for scraper */ 466d4afb5ceSopenharmony_ci 467d4afb5ceSopenharmony_cistatic int 468d4afb5ceSopenharmony_cicallback_lws_openmetrics_export(struct lws *wsi, 469d4afb5ceSopenharmony_ci enum lws_callback_reasons reason, 470d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 471d4afb5ceSopenharmony_ci{ 472d4afb5ceSopenharmony_ci unsigned char buf[1224], *start = buf + LWS_PRE, *p = start, 473d4afb5ceSopenharmony_ci *end = buf + sizeof(buf) - 1, *ip; 474d4afb5ceSopenharmony_ci struct lws_context *cx = lws_get_context(wsi); 475d4afb5ceSopenharmony_ci struct pss *pss = (struct pss *)user; 476d4afb5ceSopenharmony_ci unsigned int m, wm; 477d4afb5ceSopenharmony_ci 478d4afb5ceSopenharmony_ci switch (reason) { 479d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP: 480d4afb5ceSopenharmony_ci 481d4afb5ceSopenharmony_ci ome_prepare(cx, pss); 482d4afb5ceSopenharmony_ci 483d4afb5ceSopenharmony_ci p = start; 484d4afb5ceSopenharmony_ci if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, 485d4afb5ceSopenharmony_ci "application/openmetrics-text; " 486d4afb5ceSopenharmony_ci "version=1.0.0; charset=utf-8", 487d4afb5ceSopenharmony_ci pss->tot, &p, end) || 488d4afb5ceSopenharmony_ci lws_finalize_write_http_header(wsi, start, &p, end)) 489d4afb5ceSopenharmony_ci return 1; 490d4afb5ceSopenharmony_ci 491d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 492d4afb5ceSopenharmony_ci 493d4afb5ceSopenharmony_ci return 0; 494d4afb5ceSopenharmony_ci 495d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED_HTTP: 496d4afb5ceSopenharmony_ci lwsac_free(&pss->ac); 497d4afb5ceSopenharmony_ci break; 498d4afb5ceSopenharmony_ci 499d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP_WRITEABLE: 500d4afb5ceSopenharmony_ci if (!pss->walk) 501d4afb5ceSopenharmony_ci return 0; 502d4afb5ceSopenharmony_ci 503d4afb5ceSopenharmony_ci do { 504d4afb5ceSopenharmony_ci ip = (uint8_t *)pss->walk + 505d4afb5ceSopenharmony_ci lwsac_sizeof(pss->walk == pss->ac) + LWS_PRE; 506d4afb5ceSopenharmony_ci m = (unsigned int)((ip[0] << 8) | ip[1]); 507d4afb5ceSopenharmony_ci 508d4afb5ceSopenharmony_ci /* coverity */ 509d4afb5ceSopenharmony_ci if (m > lwsac_get_tail_pos(pss->walk) - 510d4afb5ceSopenharmony_ci lwsac_sizeof(pss->walk == pss->ac)) 511d4afb5ceSopenharmony_ci return -1; 512d4afb5ceSopenharmony_ci 513d4afb5ceSopenharmony_ci if (lws_ptr_diff_size_t(end, p) < m) 514d4afb5ceSopenharmony_ci break; 515d4afb5ceSopenharmony_ci 516d4afb5ceSopenharmony_ci memcpy(p, ip + 2, m); 517d4afb5ceSopenharmony_ci p += m; 518d4afb5ceSopenharmony_ci 519d4afb5ceSopenharmony_ci pss->walk = lwsac_get_next(pss->walk); 520d4afb5ceSopenharmony_ci } while (pss->walk); 521d4afb5ceSopenharmony_ci 522d4afb5ceSopenharmony_ci if (!lws_ptr_diff_size_t(p, start)) { 523d4afb5ceSopenharmony_ci lwsl_err("%s: stuck\n", __func__); 524d4afb5ceSopenharmony_ci return -1; 525d4afb5ceSopenharmony_ci } 526d4afb5ceSopenharmony_ci 527d4afb5ceSopenharmony_ci wm = pss->walk ? LWS_WRITE_HTTP : LWS_WRITE_HTTP_FINAL; 528d4afb5ceSopenharmony_ci 529d4afb5ceSopenharmony_ci if (lws_write(wsi, start, lws_ptr_diff_size_t(p, start), 530d4afb5ceSopenharmony_ci (enum lws_write_protocol)wm) < 0) 531d4afb5ceSopenharmony_ci return 1; 532d4afb5ceSopenharmony_ci 533d4afb5ceSopenharmony_ci if (!pss->walk) { 534d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 535d4afb5ceSopenharmony_ci return -1; 536d4afb5ceSopenharmony_ci } else 537d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 538d4afb5ceSopenharmony_ci 539d4afb5ceSopenharmony_ci return 0; 540d4afb5ceSopenharmony_ci 541d4afb5ceSopenharmony_ci default: 542d4afb5ceSopenharmony_ci break; 543d4afb5ceSopenharmony_ci } 544d4afb5ceSopenharmony_ci 545d4afb5ceSopenharmony_ci return lws_callback_http_dummy(wsi, reason, user, in, len); 546d4afb5ceSopenharmony_ci} 547d4afb5ceSopenharmony_ci 548d4afb5ceSopenharmony_cistatic struct pss * 549d4afb5ceSopenharmony_ciomc_lws_om_get_other_side_pss_client(struct vhd *vhd, struct pss *pss) 550d4afb5ceSopenharmony_ci{ 551d4afb5ceSopenharmony_ci /* 552d4afb5ceSopenharmony_ci * Search through our partner's clients list looking for one with the 553d4afb5ceSopenharmony_ci * same proxy path 554d4afb5ceSopenharmony_ci */ 555d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, d, 556d4afb5ceSopenharmony_ci vhd->bind_partner_vhd->clients.head) { 557d4afb5ceSopenharmony_ci struct pss *apss = lws_container_of(d, struct pss, list); 558d4afb5ceSopenharmony_ci 559d4afb5ceSopenharmony_ci if (!strcmp(pss->proxy_path, apss->proxy_path)) 560d4afb5ceSopenharmony_ci return apss; 561d4afb5ceSopenharmony_ci 562d4afb5ceSopenharmony_ci } lws_end_foreach_dll(d); 563d4afb5ceSopenharmony_ci 564d4afb5ceSopenharmony_ci return NULL; 565d4afb5ceSopenharmony_ci} 566d4afb5ceSopenharmony_ci 567d4afb5ceSopenharmony_ci/* 2) "lws-openmetrics-prox-agg": http server export via proxy to connected clients */ 568d4afb5ceSopenharmony_ci 569d4afb5ceSopenharmony_cistatic int 570d4afb5ceSopenharmony_cicallback_lws_openmetrics_prox_agg(struct lws *wsi, 571d4afb5ceSopenharmony_ci enum lws_callback_reasons reason, 572d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 573d4afb5ceSopenharmony_ci{ 574d4afb5ceSopenharmony_ci unsigned char buf[1224], *start = buf + LWS_PRE, *p = start, 575d4afb5ceSopenharmony_ci *end = buf + sizeof(buf) - 1, *ip; 576d4afb5ceSopenharmony_ci struct vhd *vhd = (struct vhd *)lws_protocol_vh_priv_get( 577d4afb5ceSopenharmony_ci lws_get_vhost(wsi), lws_get_protocol(wsi)); 578d4afb5ceSopenharmony_ci struct lws_context *cx = lws_get_context(wsi); 579d4afb5ceSopenharmony_ci struct pss *pss = (struct pss *)user, *partner_pss; 580d4afb5ceSopenharmony_ci unsigned int m, wm; 581d4afb5ceSopenharmony_ci 582d4afb5ceSopenharmony_ci switch (reason) { 583d4afb5ceSopenharmony_ci 584d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_INIT: 585d4afb5ceSopenharmony_ci lwsl_notice("%s: PROTOCOL_INIT on %s\n", __func__, lws_vh_tag(lws_get_vhost(wsi))); 586d4afb5ceSopenharmony_ci /* 587d4afb5ceSopenharmony_ci * We get told what to do when we are bound to the vhost 588d4afb5ceSopenharmony_ci */ 589d4afb5ceSopenharmony_ci vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), 590d4afb5ceSopenharmony_ci lws_get_protocol(wsi), sizeof(struct vhd)); 591d4afb5ceSopenharmony_ci if (!vhd) { 592d4afb5ceSopenharmony_ci lwsl_err("%s: vhd alloc failed\n", __func__); 593d4afb5ceSopenharmony_ci return 0; 594d4afb5ceSopenharmony_ci } 595d4afb5ceSopenharmony_ci 596d4afb5ceSopenharmony_ci vhd->cx = cx; 597d4afb5ceSopenharmony_ci 598d4afb5ceSopenharmony_ci /* 599d4afb5ceSopenharmony_ci * Try to bind to the counterpart server in the proxy, binding 600d4afb5ceSopenharmony_ci * to the right one by having a common bind name set in a pvo. 601d4afb5ceSopenharmony_ci * We don't know who will get instantiated last, so both parts 602d4afb5ceSopenharmony_ci * try to bind if not already bound 603d4afb5ceSopenharmony_ci */ 604d4afb5ceSopenharmony_ci 605d4afb5ceSopenharmony_ci if (!lws_pvo_get_str(in, "proxy-side-bind-name", 606d4afb5ceSopenharmony_ci &vhd->proxy_side_bind_name)) { 607d4afb5ceSopenharmony_ci /* 608d4afb5ceSopenharmony_ci * Attempt to find the vhd that belongs to a vhost 609d4afb5ceSopenharmony_ci * that has instantiated protocol 610d4afb5ceSopenharmony_ci * "lws-openmetrics-prox-server", and has set pvo 611d4afb5ceSopenharmony_ci * "proxy-side-bind-name" on it to whatever our 612d4afb5ceSopenharmony_ci * vhd->proxy_side_bind_name was also set to. 613d4afb5ceSopenharmony_ci * 614d4afb5ceSopenharmony_ci * If found, inform the two sides of the same proxy 615d4afb5ceSopenharmony_ci * what their partner vhd is 616d4afb5ceSopenharmony_ci */ 617d4afb5ceSopenharmony_ci lws_strncpy(vhd->sanity, "isagg", sizeof(vhd->sanity)); 618d4afb5ceSopenharmony_ci vhd->bind_partner_vhd = lws_vhd_find_by_pvo(cx, 619d4afb5ceSopenharmony_ci "lws-openmetrics-prox-server", 620d4afb5ceSopenharmony_ci "proxy-side-bind-name", 621d4afb5ceSopenharmony_ci vhd->proxy_side_bind_name); 622d4afb5ceSopenharmony_ci if (vhd->bind_partner_vhd) { 623d4afb5ceSopenharmony_ci assert(!strcmp(vhd->bind_partner_vhd->sanity, "isws")); 624d4afb5ceSopenharmony_ci lwsl_notice("%s: proxy binding OK\n", __func__); 625d4afb5ceSopenharmony_ci vhd->bind_partner_vhd->bind_partner_vhd = vhd; 626d4afb5ceSopenharmony_ci } 627d4afb5ceSopenharmony_ci } else { 628d4afb5ceSopenharmony_ci lwsl_warn("%s: proxy-side-bind-name required\n", __func__); 629d4afb5ceSopenharmony_ci return 0; 630d4afb5ceSopenharmony_ci } 631d4afb5ceSopenharmony_ci 632d4afb5ceSopenharmony_ci break; 633d4afb5ceSopenharmony_ci 634d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_DESTROY: 635d4afb5ceSopenharmony_ci if (vhd) 636d4afb5ceSopenharmony_ci lws_sul_cancel(&vhd->sul); 637d4afb5ceSopenharmony_ci break; 638d4afb5ceSopenharmony_ci 639d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP: 640d4afb5ceSopenharmony_ci 641d4afb5ceSopenharmony_ci /* 642d4afb5ceSopenharmony_ci * The scraper has connected to us, the local side of the proxy, 643d4afb5ceSopenharmony_ci * we need to match what it wants to 644d4afb5ceSopenharmony_ci */ 645d4afb5ceSopenharmony_ci 646d4afb5ceSopenharmony_ci if (!vhd->bind_partner_vhd) 647d4afb5ceSopenharmony_ci return 0; 648d4afb5ceSopenharmony_ci 649d4afb5ceSopenharmony_ci lws_strnncpy(pss->proxy_path, (const char *)in, len, 650d4afb5ceSopenharmony_ci sizeof(pss->proxy_path)); 651d4afb5ceSopenharmony_ci 652d4afb5ceSopenharmony_ci if (pss->list.owner) { 653d4afb5ceSopenharmony_ci lwsl_warn("%s: double HTTP?\n", __func__); 654d4afb5ceSopenharmony_ci return 0; 655d4afb5ceSopenharmony_ci } 656d4afb5ceSopenharmony_ci 657d4afb5ceSopenharmony_ci pss->wsi = wsi; 658d4afb5ceSopenharmony_ci 659d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, d, 660d4afb5ceSopenharmony_ci vhd->bind_partner_vhd->clients.head) { 661d4afb5ceSopenharmony_ci struct pss *apss = lws_container_of(d, struct pss, list); 662d4afb5ceSopenharmony_ci 663d4afb5ceSopenharmony_ci if (!strcmp((const char *)in, apss->proxy_path)) { 664d4afb5ceSopenharmony_ci apss->trigger = 1; 665d4afb5ceSopenharmony_ci lws_callback_on_writable(apss->wsi); 666d4afb5ceSopenharmony_ci 667d4afb5ceSopenharmony_ci /* let's add him on the http server vhd list */ 668d4afb5ceSopenharmony_ci 669d4afb5ceSopenharmony_ci lws_dll2_add_tail(&pss->list, &vhd->clients); 670d4afb5ceSopenharmony_ci return 0; 671d4afb5ceSopenharmony_ci } 672d4afb5ceSopenharmony_ci 673d4afb5ceSopenharmony_ci } lws_end_foreach_dll(d); 674d4afb5ceSopenharmony_ci 675d4afb5ceSopenharmony_ci return 0; 676d4afb5ceSopenharmony_ci 677d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED_HTTP: 678d4afb5ceSopenharmony_ci lwsac_free(&pss->ac); 679d4afb5ceSopenharmony_ci lws_dll2_remove(&pss->list); 680d4afb5ceSopenharmony_ci break; 681d4afb5ceSopenharmony_ci 682d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP_WRITEABLE: 683d4afb5ceSopenharmony_ci 684d4afb5ceSopenharmony_ci if (!pss->walk) 685d4afb5ceSopenharmony_ci return 0; 686d4afb5ceSopenharmony_ci 687d4afb5ceSopenharmony_ci /* locate the wss side if it's still around */ 688d4afb5ceSopenharmony_ci 689d4afb5ceSopenharmony_ci partner_pss = omc_lws_om_get_other_side_pss_client(vhd, pss); 690d4afb5ceSopenharmony_ci if (!partner_pss) 691d4afb5ceSopenharmony_ci return -1; 692d4afb5ceSopenharmony_ci 693d4afb5ceSopenharmony_ci do { 694d4afb5ceSopenharmony_ci ip = (uint8_t *)pss->walk + 695d4afb5ceSopenharmony_ci lwsac_sizeof(pss->walk == partner_pss->ac) + LWS_PRE; 696d4afb5ceSopenharmony_ci m = (unsigned int)((ip[0] << 8) | ip[1]); 697d4afb5ceSopenharmony_ci 698d4afb5ceSopenharmony_ci /* coverity */ 699d4afb5ceSopenharmony_ci if (m > lwsac_get_tail_pos(pss->walk) - 700d4afb5ceSopenharmony_ci lwsac_sizeof(pss->walk == partner_pss->ac)) 701d4afb5ceSopenharmony_ci return -1; 702d4afb5ceSopenharmony_ci 703d4afb5ceSopenharmony_ci if (lws_ptr_diff_size_t(end, p) < m) 704d4afb5ceSopenharmony_ci break; 705d4afb5ceSopenharmony_ci 706d4afb5ceSopenharmony_ci memcpy(p, ip + 2, m); 707d4afb5ceSopenharmony_ci p += m; 708d4afb5ceSopenharmony_ci 709d4afb5ceSopenharmony_ci pss->walk = lwsac_get_next(pss->walk); 710d4afb5ceSopenharmony_ci } while (pss->walk); 711d4afb5ceSopenharmony_ci 712d4afb5ceSopenharmony_ci if (!lws_ptr_diff_size_t(p, start)) { 713d4afb5ceSopenharmony_ci lwsl_err("%s: stuck\n", __func__); 714d4afb5ceSopenharmony_ci return -1; 715d4afb5ceSopenharmony_ci } 716d4afb5ceSopenharmony_ci 717d4afb5ceSopenharmony_ci wm = pss->walk ? LWS_WRITE_HTTP : LWS_WRITE_HTTP_FINAL; 718d4afb5ceSopenharmony_ci 719d4afb5ceSopenharmony_ci if (lws_write(wsi, start, lws_ptr_diff_size_t(p, start), 720d4afb5ceSopenharmony_ci (enum lws_write_protocol)wm) < 0) 721d4afb5ceSopenharmony_ci return 1; 722d4afb5ceSopenharmony_ci 723d4afb5ceSopenharmony_ci if (!pss->walk) { 724d4afb5ceSopenharmony_ci lwsl_info("%s: whole msg proxied to scraper\n", __func__); 725d4afb5ceSopenharmony_ci lws_dll2_remove(&pss->list); 726d4afb5ceSopenharmony_ci lwsac_free(&partner_pss->ac); 727d4afb5ceSopenharmony_ci// if (lws_http_transaction_completed(wsi)) 728d4afb5ceSopenharmony_ci return -1; 729d4afb5ceSopenharmony_ci } else 730d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 731d4afb5ceSopenharmony_ci 732d4afb5ceSopenharmony_ci return 0; 733d4afb5ceSopenharmony_ci 734d4afb5ceSopenharmony_ci default: 735d4afb5ceSopenharmony_ci break; 736d4afb5ceSopenharmony_ci } 737d4afb5ceSopenharmony_ci 738d4afb5ceSopenharmony_ci return lws_callback_http_dummy(wsi, reason, user, in, len); 739d4afb5ceSopenharmony_ci} 740d4afb5ceSopenharmony_ci 741d4afb5ceSopenharmony_ci/* 3) "lws-openmetrics-prox-server": ws server side of metrics proxy, for 742d4afb5ceSopenharmony_ci * ws clients to connect to */ 743d4afb5ceSopenharmony_ci 744d4afb5ceSopenharmony_cistatic int 745d4afb5ceSopenharmony_cicallback_lws_openmetrics_prox_server(struct lws *wsi, 746d4afb5ceSopenharmony_ci enum lws_callback_reasons reason, 747d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 748d4afb5ceSopenharmony_ci{ 749d4afb5ceSopenharmony_ci unsigned char buf[1224], *start = buf + LWS_PRE, *p = start, 750d4afb5ceSopenharmony_ci *end = buf + sizeof(buf) - 1; 751d4afb5ceSopenharmony_ci struct vhd *vhd = (struct vhd *)lws_protocol_vh_priv_get( 752d4afb5ceSopenharmony_ci lws_get_vhost(wsi), lws_get_protocol(wsi)); 753d4afb5ceSopenharmony_ci struct lws_context *cx = lws_get_context(wsi); 754d4afb5ceSopenharmony_ci struct pss *pss = (struct pss *)user, *partner_pss; 755d4afb5ceSopenharmony_ci 756d4afb5ceSopenharmony_ci switch (reason) { 757d4afb5ceSopenharmony_ci 758d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_INIT: 759d4afb5ceSopenharmony_ci /* 760d4afb5ceSopenharmony_ci * We get told what to do when we are bound to the vhost 761d4afb5ceSopenharmony_ci */ 762d4afb5ceSopenharmony_ci 763d4afb5ceSopenharmony_ci lwsl_notice("%s: PROTOCOL_INIT on %s\n", __func__, lws_vh_tag(lws_get_vhost(wsi))); 764d4afb5ceSopenharmony_ci 765d4afb5ceSopenharmony_ci vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), 766d4afb5ceSopenharmony_ci lws_get_protocol(wsi), sizeof(struct vhd)); 767d4afb5ceSopenharmony_ci if (!vhd) { 768d4afb5ceSopenharmony_ci lwsl_err("%s: vhd alloc failed\n", __func__); 769d4afb5ceSopenharmony_ci return 0; 770d4afb5ceSopenharmony_ci } 771d4afb5ceSopenharmony_ci 772d4afb5ceSopenharmony_ci vhd->cx = cx; 773d4afb5ceSopenharmony_ci 774d4afb5ceSopenharmony_ci /* 775d4afb5ceSopenharmony_ci * Try to bind to the counterpart server in the proxy, binding 776d4afb5ceSopenharmony_ci * to the right one by having a common bind name set in a pvo. 777d4afb5ceSopenharmony_ci * We don't know who will get instantiated last, so both parts 778d4afb5ceSopenharmony_ci * try to bind if not already bound 779d4afb5ceSopenharmony_ci */ 780d4afb5ceSopenharmony_ci 781d4afb5ceSopenharmony_ci if (!lws_pvo_get_str(in, "proxy-side-bind-name", 782d4afb5ceSopenharmony_ci &vhd->proxy_side_bind_name)) { 783d4afb5ceSopenharmony_ci /* 784d4afb5ceSopenharmony_ci * Attempt to find the vhd that belongs to a vhost 785d4afb5ceSopenharmony_ci * that has instantiated protocol 786d4afb5ceSopenharmony_ci * "lws-openmetrics-prox-server", and has set pvo 787d4afb5ceSopenharmony_ci * "proxy-side-bind-name" on it to whatever our 788d4afb5ceSopenharmony_ci * vhd->proxy_side_bind_name was also set to. 789d4afb5ceSopenharmony_ci * 790d4afb5ceSopenharmony_ci * If found, inform the two sides of the same proxy 791d4afb5ceSopenharmony_ci * what their partner vhd is 792d4afb5ceSopenharmony_ci */ 793d4afb5ceSopenharmony_ci lws_strncpy(vhd->sanity, "isws", sizeof(vhd->sanity)); 794d4afb5ceSopenharmony_ci vhd->bind_partner_vhd = lws_vhd_find_by_pvo(cx, 795d4afb5ceSopenharmony_ci "lws-openmetrics-prox-agg", 796d4afb5ceSopenharmony_ci "proxy-side-bind-name", 797d4afb5ceSopenharmony_ci vhd->proxy_side_bind_name); 798d4afb5ceSopenharmony_ci if (vhd->bind_partner_vhd) { 799d4afb5ceSopenharmony_ci assert(!strcmp(vhd->bind_partner_vhd->sanity, "isagg")); 800d4afb5ceSopenharmony_ci lwsl_notice("%s: proxy binding OK\n", __func__); 801d4afb5ceSopenharmony_ci vhd->bind_partner_vhd->bind_partner_vhd = vhd; 802d4afb5ceSopenharmony_ci } 803d4afb5ceSopenharmony_ci } else { 804d4afb5ceSopenharmony_ci lwsl_warn("%s: proxy-side-bind-name required\n", __func__); 805d4afb5ceSopenharmony_ci return 0; 806d4afb5ceSopenharmony_ci } 807d4afb5ceSopenharmony_ci 808d4afb5ceSopenharmony_ci break; 809d4afb5ceSopenharmony_ci 810d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_DESTROY: 811d4afb5ceSopenharmony_ci break; 812d4afb5ceSopenharmony_ci 813d4afb5ceSopenharmony_ci case LWS_CALLBACK_ESTABLISHED: 814d4afb5ceSopenharmony_ci /* 815d4afb5ceSopenharmony_ci * a client has joined... we need to add his pss to our list 816d4afb5ceSopenharmony_ci * of live, joined clients 817d4afb5ceSopenharmony_ci */ 818d4afb5ceSopenharmony_ci 819d4afb5ceSopenharmony_ci /* mark us as waiting for the reference name from the client */ 820d4afb5ceSopenharmony_ci pss->greet = 1; 821d4afb5ceSopenharmony_ci pss->wsi = wsi; 822d4afb5ceSopenharmony_ci lws_validity_confirmed(wsi); 823d4afb5ceSopenharmony_ci 824d4afb5ceSopenharmony_ci return 0; 825d4afb5ceSopenharmony_ci 826d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED: 827d4afb5ceSopenharmony_ci /* 828d4afb5ceSopenharmony_ci * a client has parted 829d4afb5ceSopenharmony_ci */ 830d4afb5ceSopenharmony_ci lws_dll2_remove(&pss->list); 831d4afb5ceSopenharmony_ci lwsl_warn("%s: client %s left (%u)\n", __func__, 832d4afb5ceSopenharmony_ci pss->proxy_path, 833d4afb5ceSopenharmony_ci (unsigned int)vhd->clients.count); 834d4afb5ceSopenharmony_ci lwsac_free(&pss->ac); 835d4afb5ceSopenharmony_ci 836d4afb5ceSopenharmony_ci /* let's kill the scraper connection accordingly, if still up */ 837d4afb5ceSopenharmony_ci partner_pss = omc_lws_om_get_other_side_pss_client(vhd, pss); 838d4afb5ceSopenharmony_ci if (partner_pss) 839d4afb5ceSopenharmony_ci lws_wsi_close(partner_pss->wsi, LWS_TO_KILL_ASYNC); 840d4afb5ceSopenharmony_ci break; 841d4afb5ceSopenharmony_ci 842d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE: 843d4afb5ceSopenharmony_ci if (pss->greet) { 844d4afb5ceSopenharmony_ci pss->greet = 0; 845d4afb5ceSopenharmony_ci lws_strnncpy(pss->proxy_path, (const char *)in, len, 846d4afb5ceSopenharmony_ci sizeof(pss->proxy_path)); 847d4afb5ceSopenharmony_ci 848d4afb5ceSopenharmony_ci lws_validity_confirmed(wsi); 849d4afb5ceSopenharmony_ci lwsl_notice("%s: received greet '%s'\n", __func__, 850d4afb5ceSopenharmony_ci pss->proxy_path); 851d4afb5ceSopenharmony_ci /* 852d4afb5ceSopenharmony_ci * we need to add his pss to our list of configured, 853d4afb5ceSopenharmony_ci * live, joined clients 854d4afb5ceSopenharmony_ci */ 855d4afb5ceSopenharmony_ci lws_dll2_add_tail(&pss->list, &vhd->clients); 856d4afb5ceSopenharmony_ci return 0; 857d4afb5ceSopenharmony_ci } 858d4afb5ceSopenharmony_ci 859d4afb5ceSopenharmony_ci /* 860d4afb5ceSopenharmony_ci * He's sending us his results... let's collect chunks into the 861d4afb5ceSopenharmony_ci * pss lwsac before worrying about anything else 862d4afb5ceSopenharmony_ci */ 863d4afb5ceSopenharmony_ci 864d4afb5ceSopenharmony_ci if (lws_is_first_fragment(wsi)) 865d4afb5ceSopenharmony_ci pss->tot = 0; 866d4afb5ceSopenharmony_ci 867d4afb5ceSopenharmony_ci lws_metrics_om_ac_stash(pss, (const char *)in, len); 868d4afb5ceSopenharmony_ci 869d4afb5ceSopenharmony_ci if (lws_is_final_fragment(wsi)) { 870d4afb5ceSopenharmony_ci struct pss *partner_pss; 871d4afb5ceSopenharmony_ci 872d4afb5ceSopenharmony_ci lwsl_info("%s: ws side received complete msg\n", 873d4afb5ceSopenharmony_ci __func__); 874d4afb5ceSopenharmony_ci 875d4afb5ceSopenharmony_ci /* the lwsac is complete */ 876d4afb5ceSopenharmony_ci pss->walk = pss->ac; 877d4afb5ceSopenharmony_ci partner_pss = omc_lws_om_get_other_side_pss_client(vhd, pss); 878d4afb5ceSopenharmony_ci if (!partner_pss) { 879d4afb5ceSopenharmony_ci lwsl_notice("%s: no partner A\n", __func__); 880d4afb5ceSopenharmony_ci return -1; 881d4afb5ceSopenharmony_ci } 882d4afb5ceSopenharmony_ci 883d4afb5ceSopenharmony_ci /* indicate to scraper side we want to issue now */ 884d4afb5ceSopenharmony_ci 885d4afb5ceSopenharmony_ci p = start; 886d4afb5ceSopenharmony_ci if (lws_add_http_common_headers(partner_pss->wsi, HTTP_STATUS_OK, 887d4afb5ceSopenharmony_ci "application/openmetrics-text; " 888d4afb5ceSopenharmony_ci "version=1.0.0; charset=utf-8", 889d4afb5ceSopenharmony_ci pss->tot, &p, end) || 890d4afb5ceSopenharmony_ci lws_finalize_write_http_header(partner_pss->wsi, 891d4afb5ceSopenharmony_ci start, &p, end)) 892d4afb5ceSopenharmony_ci return -1; 893d4afb5ceSopenharmony_ci 894d4afb5ceSopenharmony_ci /* indicate to scraper side we want to issue now */ 895d4afb5ceSopenharmony_ci 896d4afb5ceSopenharmony_ci partner_pss->walk = pss->ac; 897d4afb5ceSopenharmony_ci partner_pss->trigger = 1; 898d4afb5ceSopenharmony_ci lws_callback_on_writable(partner_pss->wsi); 899d4afb5ceSopenharmony_ci } 900d4afb5ceSopenharmony_ci 901d4afb5ceSopenharmony_ci return 0; 902d4afb5ceSopenharmony_ci 903d4afb5ceSopenharmony_ci case LWS_CALLBACK_SERVER_WRITEABLE: 904d4afb5ceSopenharmony_ci if (!pss->trigger) 905d4afb5ceSopenharmony_ci return 0; 906d4afb5ceSopenharmony_ci 907d4afb5ceSopenharmony_ci pss->trigger = 0; 908d4afb5ceSopenharmony_ci 909d4afb5ceSopenharmony_ci partner_pss = omc_lws_om_get_other_side_pss_client(vhd, pss); 910d4afb5ceSopenharmony_ci if (!partner_pss) { 911d4afb5ceSopenharmony_ci lwsl_err("%s: no partner\n", __func__); 912d4afb5ceSopenharmony_ci return 0; 913d4afb5ceSopenharmony_ci } 914d4afb5ceSopenharmony_ci 915d4afb5ceSopenharmony_ci lwsl_info("%s: sending trigger to client\n", __func__); 916d4afb5ceSopenharmony_ci 917d4afb5ceSopenharmony_ci *start = 'x'; 918d4afb5ceSopenharmony_ci if (lws_write(wsi, start, 1, 919d4afb5ceSopenharmony_ci (enum lws_write_protocol)LWS_WRITE_TEXT) < 0) 920d4afb5ceSopenharmony_ci return 1; 921d4afb5ceSopenharmony_ci 922d4afb5ceSopenharmony_ci lws_validity_confirmed(wsi); 923d4afb5ceSopenharmony_ci 924d4afb5ceSopenharmony_ci return 0; 925d4afb5ceSopenharmony_ci 926d4afb5ceSopenharmony_ci default: 927d4afb5ceSopenharmony_ci break; 928d4afb5ceSopenharmony_ci } 929d4afb5ceSopenharmony_ci 930d4afb5ceSopenharmony_ci return lws_callback_http_dummy(wsi, reason, user, in, len); 931d4afb5ceSopenharmony_ci} 932d4afb5ceSopenharmony_ci#endif 933d4afb5ceSopenharmony_ci 934d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) && defined(LWS_ROLE_WS) 935d4afb5ceSopenharmony_ci 936d4afb5ceSopenharmony_ci/* 4) ws client that keeps wss connection up to metrics proxy ws server */ 937d4afb5ceSopenharmony_ci 938d4afb5ceSopenharmony_cistatic int 939d4afb5ceSopenharmony_cicallback_lws_openmetrics_prox_client(struct lws *wsi, 940d4afb5ceSopenharmony_ci enum lws_callback_reasons reason, 941d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 942d4afb5ceSopenharmony_ci{ 943d4afb5ceSopenharmony_ci unsigned char buf[1224], *start = buf + LWS_PRE, *p = start, 944d4afb5ceSopenharmony_ci *end = buf + sizeof(buf) - 1, *ip; 945d4afb5ceSopenharmony_ci struct vhd *vhd = (struct vhd *)lws_protocol_vh_priv_get( 946d4afb5ceSopenharmony_ci lws_get_vhost(wsi), lws_get_protocol(wsi)); 947d4afb5ceSopenharmony_ci struct lws_context *cx = lws_get_context(wsi); 948d4afb5ceSopenharmony_ci struct pss *pss = (struct pss *)user; 949d4afb5ceSopenharmony_ci unsigned int m, wm; 950d4afb5ceSopenharmony_ci const char *cp; 951d4afb5ceSopenharmony_ci char first; 952d4afb5ceSopenharmony_ci 953d4afb5ceSopenharmony_ci switch (reason) { 954d4afb5ceSopenharmony_ci 955d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_INIT: 956d4afb5ceSopenharmony_ci 957d4afb5ceSopenharmony_ci lwsl_notice("%s: PROTOCOL_INIT on %s\n", __func__, 958d4afb5ceSopenharmony_ci lws_vh_tag(lws_get_vhost(wsi))); 959d4afb5ceSopenharmony_ci 960d4afb5ceSopenharmony_ci 961d4afb5ceSopenharmony_ci /* 962d4afb5ceSopenharmony_ci * We get told what to do when we are bound to the vhost 963d4afb5ceSopenharmony_ci */ 964d4afb5ceSopenharmony_ci vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), 965d4afb5ceSopenharmony_ci lws_get_protocol(wsi), sizeof(struct vhd)); 966d4afb5ceSopenharmony_ci if (!vhd) 967d4afb5ceSopenharmony_ci return 0; 968d4afb5ceSopenharmony_ci 969d4afb5ceSopenharmony_ci vhd->cx = cx; 970d4afb5ceSopenharmony_ci vhd->vhost = lws_get_vhost(wsi); 971d4afb5ceSopenharmony_ci 972d4afb5ceSopenharmony_ci /* the proxy server uri */ 973d4afb5ceSopenharmony_ci 974d4afb5ceSopenharmony_ci if (lws_pvo_get_str(in, "ws-server-uri", &cp) || !cp) { 975d4afb5ceSopenharmony_ci lwsl_warn("%s: ws-server-uri pvo required\n", __func__); 976d4afb5ceSopenharmony_ci 977d4afb5ceSopenharmony_ci return 0; 978d4afb5ceSopenharmony_ci } 979d4afb5ceSopenharmony_ci lws_strncpy(vhd->ws_server_uri, cp, sizeof(vhd->ws_server_uri)); 980d4afb5ceSopenharmony_ci 981d4afb5ceSopenharmony_ci /* how we should be referenced at the proxy */ 982d4afb5ceSopenharmony_ci 983d4afb5ceSopenharmony_ci if (lws_pvo_get_str(in, "metrics-proxy-path", &cp)) { 984d4afb5ceSopenharmony_ci lwsl_err("%s: metrics-proxy-path pvo required\n", __func__); 985d4afb5ceSopenharmony_ci 986d4afb5ceSopenharmony_ci return 1; 987d4afb5ceSopenharmony_ci } 988d4afb5ceSopenharmony_ci lws_strncpy(vhd->metrics_proxy_path, cp, sizeof(vhd->metrics_proxy_path)); 989d4afb5ceSopenharmony_ci 990d4afb5ceSopenharmony_ci /* the shared secret to authenticate us as allowed to join */ 991d4afb5ceSopenharmony_ci 992d4afb5ceSopenharmony_ci if (lws_pvo_get_str(in, "ba-secret", &cp)) { 993d4afb5ceSopenharmony_ci lwsl_err("%s: ba-secret pvo required\n", __func__); 994d4afb5ceSopenharmony_ci 995d4afb5ceSopenharmony_ci return 1; 996d4afb5ceSopenharmony_ci } 997d4afb5ceSopenharmony_ci lws_strncpy(vhd->ba_secret, cp, sizeof(vhd->ba_secret)); 998d4afb5ceSopenharmony_ci 999d4afb5ceSopenharmony_ci lwsl_notice("%s: scheduling connect %s %s %s\n", __func__, 1000d4afb5ceSopenharmony_ci vhd->ws_server_uri, vhd->metrics_proxy_path, vhd->ba_secret); 1001d4afb5ceSopenharmony_ci 1002d4afb5ceSopenharmony_ci lws_validity_confirmed(wsi); 1003d4afb5ceSopenharmony_ci lws_sul_schedule(cx, 0, &vhd->sul, omc_connect_client, 1); 1004d4afb5ceSopenharmony_ci break; 1005d4afb5ceSopenharmony_ci 1006d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_DESTROY: 1007d4afb5ceSopenharmony_ci if (vhd) 1008d4afb5ceSopenharmony_ci lws_sul_cancel(&vhd->sul); 1009d4afb5ceSopenharmony_ci break; 1010d4afb5ceSopenharmony_ci 1011d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: 1012d4afb5ceSopenharmony_ci { 1013d4afb5ceSopenharmony_ci unsigned char **pp = (unsigned char **)in, *pend = (*pp) + len; 1014d4afb5ceSopenharmony_ci char b[128]; 1015d4afb5ceSopenharmony_ci 1016d4afb5ceSopenharmony_ci /* authorize ourselves to the metrics proxy using basic auth */ 1017d4afb5ceSopenharmony_ci 1018d4afb5ceSopenharmony_ci if (lws_http_basic_auth_gen("metricsclient", vhd->ba_secret, 1019d4afb5ceSopenharmony_ci b, sizeof(b))) 1020d4afb5ceSopenharmony_ci break; 1021d4afb5ceSopenharmony_ci 1022d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 1023d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_AUTHORIZATION, 1024d4afb5ceSopenharmony_ci (unsigned char *)b, 1025d4afb5ceSopenharmony_ci (int)strlen(b), pp, pend)) 1026d4afb5ceSopenharmony_ci return -1; 1027d4afb5ceSopenharmony_ci 1028d4afb5ceSopenharmony_ci break; 1029d4afb5ceSopenharmony_ci } 1030d4afb5ceSopenharmony_ci 1031d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 1032d4afb5ceSopenharmony_ci lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", 1033d4afb5ceSopenharmony_ci in ? (char *)in : "(null)"); 1034d4afb5ceSopenharmony_ci goto do_retry; 1035d4afb5ceSopenharmony_ci 1036d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_ESTABLISHED: 1037d4afb5ceSopenharmony_ci lwsl_warn("%s: connected to ws metrics agg server\n", __func__); 1038d4afb5ceSopenharmony_ci pss->greet = 1; 1039d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 1040d4afb5ceSopenharmony_ci lws_validity_confirmed(wsi); 1041d4afb5ceSopenharmony_ci return 0; 1042d4afb5ceSopenharmony_ci 1043d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CLOSED: 1044d4afb5ceSopenharmony_ci lwsl_notice("%s: client closed\n", __func__); 1045d4afb5ceSopenharmony_ci lwsac_free(&pss->ac); 1046d4afb5ceSopenharmony_ci goto do_retry; 1047d4afb5ceSopenharmony_ci 1048d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_RECEIVE: 1049d4afb5ceSopenharmony_ci /* 1050d4afb5ceSopenharmony_ci * Proxy serverside sends us something to trigger us to create 1051d4afb5ceSopenharmony_ci * our metrics message and send it back over the ws link 1052d4afb5ceSopenharmony_ci */ 1053d4afb5ceSopenharmony_ci ome_prepare(cx, pss); 1054d4afb5ceSopenharmony_ci pss->walk = pss->ac; 1055d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 1056d4afb5ceSopenharmony_ci lwsl_info("%s: dump requested\n", __func__); 1057d4afb5ceSopenharmony_ci break; 1058d4afb5ceSopenharmony_ci 1059d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_WRITEABLE: 1060d4afb5ceSopenharmony_ci if (pss->greet) { 1061d4afb5ceSopenharmony_ci /* 1062d4afb5ceSopenharmony_ci * At first after establishing the we link, we send a 1063d4afb5ceSopenharmony_ci * message indicating to the metrics proxy how we 1064d4afb5ceSopenharmony_ci * should be referred to by the scraper to particularly 1065d4afb5ceSopenharmony_ci * select to talk to us 1066d4afb5ceSopenharmony_ci */ 1067d4afb5ceSopenharmony_ci lwsl_info("%s: sending greet '%s'\n", __func__, 1068d4afb5ceSopenharmony_ci vhd->metrics_proxy_path); 1069d4afb5ceSopenharmony_ci lws_strncpy((char *)start, vhd->metrics_proxy_path, 1070d4afb5ceSopenharmony_ci sizeof(buf) - LWS_PRE); 1071d4afb5ceSopenharmony_ci if (lws_write(wsi, start, 1072d4afb5ceSopenharmony_ci strlen(vhd->metrics_proxy_path), 1073d4afb5ceSopenharmony_ci LWS_WRITE_TEXT) < 0) 1074d4afb5ceSopenharmony_ci return 1; 1075d4afb5ceSopenharmony_ci 1076d4afb5ceSopenharmony_ci lws_validity_confirmed(wsi); 1077d4afb5ceSopenharmony_ci 1078d4afb5ceSopenharmony_ci pss->greet = 0; 1079d4afb5ceSopenharmony_ci return 0; 1080d4afb5ceSopenharmony_ci } 1081d4afb5ceSopenharmony_ci 1082d4afb5ceSopenharmony_ci if (!pss->walk) 1083d4afb5ceSopenharmony_ci return 0; 1084d4afb5ceSopenharmony_ci 1085d4afb5ceSopenharmony_ci /* 1086d4afb5ceSopenharmony_ci * We send the metrics dump in a single logical ws message, 1087d4afb5ceSopenharmony_ci * using ws fragmentation to split it around 1 mtu boundary 1088d4afb5ceSopenharmony_ci * and keep coming back until it's finished 1089d4afb5ceSopenharmony_ci */ 1090d4afb5ceSopenharmony_ci 1091d4afb5ceSopenharmony_ci first = pss->walk == pss->ac; 1092d4afb5ceSopenharmony_ci 1093d4afb5ceSopenharmony_ci do { 1094d4afb5ceSopenharmony_ci ip = (uint8_t *)pss->walk + 1095d4afb5ceSopenharmony_ci lwsac_sizeof(pss->walk == pss->ac) + LWS_PRE; 1096d4afb5ceSopenharmony_ci m = (unsigned int)((ip[0] << 8) | ip[1]); 1097d4afb5ceSopenharmony_ci 1098d4afb5ceSopenharmony_ci /* coverity */ 1099d4afb5ceSopenharmony_ci if (m > lwsac_get_tail_pos(pss->walk) - 1100d4afb5ceSopenharmony_ci lwsac_sizeof(pss->walk == pss->ac)) { 1101d4afb5ceSopenharmony_ci lwsl_err("%s: size blow\n", __func__); 1102d4afb5ceSopenharmony_ci return -1; 1103d4afb5ceSopenharmony_ci } 1104d4afb5ceSopenharmony_ci 1105d4afb5ceSopenharmony_ci if (lws_ptr_diff_size_t(end, p) < m) 1106d4afb5ceSopenharmony_ci break; 1107d4afb5ceSopenharmony_ci 1108d4afb5ceSopenharmony_ci memcpy(p, ip + 2, m); 1109d4afb5ceSopenharmony_ci p += m; 1110d4afb5ceSopenharmony_ci 1111d4afb5ceSopenharmony_ci pss->walk = lwsac_get_next(pss->walk); 1112d4afb5ceSopenharmony_ci } while (pss->walk); 1113d4afb5ceSopenharmony_ci 1114d4afb5ceSopenharmony_ci if (!lws_ptr_diff_size_t(p, start)) { 1115d4afb5ceSopenharmony_ci lwsl_err("%s: stuck\n", __func__); 1116d4afb5ceSopenharmony_ci return -1; 1117d4afb5ceSopenharmony_ci } 1118d4afb5ceSopenharmony_ci 1119d4afb5ceSopenharmony_ci wm = (unsigned int)lws_write_ws_flags(LWS_WRITE_TEXT, first, 1120d4afb5ceSopenharmony_ci !pss->walk); 1121d4afb5ceSopenharmony_ci 1122d4afb5ceSopenharmony_ci if (lws_write(wsi, start, lws_ptr_diff_size_t(p, start), 1123d4afb5ceSopenharmony_ci (enum lws_write_protocol)wm) < 0) { 1124d4afb5ceSopenharmony_ci lwsl_notice("%s: write fail\n", __func__); 1125d4afb5ceSopenharmony_ci return 1; 1126d4afb5ceSopenharmony_ci } 1127d4afb5ceSopenharmony_ci 1128d4afb5ceSopenharmony_ci lws_validity_confirmed(wsi); 1129d4afb5ceSopenharmony_ci lwsl_info("%s: forwarded %d\n", __func__, lws_ptr_diff(p, start)); 1130d4afb5ceSopenharmony_ci 1131d4afb5ceSopenharmony_ci if (!pss->walk) { 1132d4afb5ceSopenharmony_ci lwsl_info("%s: dump send completed\n", __func__); 1133d4afb5ceSopenharmony_ci lwsac_free(&pss->ac); 1134d4afb5ceSopenharmony_ci } else 1135d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 1136d4afb5ceSopenharmony_ci 1137d4afb5ceSopenharmony_ci return 0; 1138d4afb5ceSopenharmony_ci 1139d4afb5ceSopenharmony_ci default: 1140d4afb5ceSopenharmony_ci break; 1141d4afb5ceSopenharmony_ci } 1142d4afb5ceSopenharmony_ci 1143d4afb5ceSopenharmony_ci return lws_callback_http_dummy(wsi, reason, user, in, len); 1144d4afb5ceSopenharmony_ci 1145d4afb5ceSopenharmony_cido_retry: 1146d4afb5ceSopenharmony_ci if (!lws_retry_sul_schedule(cx, 0, &vhd->sul, &retry, 1147d4afb5ceSopenharmony_ci omc_connect_client, &vhd->retry_count)) 1148d4afb5ceSopenharmony_ci return 0; 1149d4afb5ceSopenharmony_ci 1150d4afb5ceSopenharmony_ci vhd->retry_count = 0; 1151d4afb5ceSopenharmony_ci lws_retry_sul_schedule(cx, 0, &vhd->sul, &retry, 1152d4afb5ceSopenharmony_ci omc_connect_client, &vhd->retry_count); 1153d4afb5ceSopenharmony_ci 1154d4afb5ceSopenharmony_ci return 0; 1155d4afb5ceSopenharmony_ci} 1156d4afb5ceSopenharmony_ci#endif 1157d4afb5ceSopenharmony_ci 1158d4afb5ceSopenharmony_ci 1159d4afb5ceSopenharmony_ciLWS_VISIBLE const struct lws_protocols lws_openmetrics_export_protocols[] = { 1160d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 1161d4afb5ceSopenharmony_ci { /* for scraper directly: http export on listen socket */ 1162d4afb5ceSopenharmony_ci "lws-openmetrics", 1163d4afb5ceSopenharmony_ci callback_lws_openmetrics_export, 1164d4afb5ceSopenharmony_ci sizeof(struct pss), 1165d4afb5ceSopenharmony_ci 1024, 0, NULL, 0 1166d4afb5ceSopenharmony_ci }, 1167d4afb5ceSopenharmony_ci { /* for scraper via ws proxy: http export on listen socket */ 1168d4afb5ceSopenharmony_ci "lws-openmetrics-prox-agg", 1169d4afb5ceSopenharmony_ci callback_lws_openmetrics_prox_agg, 1170d4afb5ceSopenharmony_ci sizeof(struct pss), 1171d4afb5ceSopenharmony_ci 1024, 0, NULL, 0 1172d4afb5ceSopenharmony_ci }, 1173d4afb5ceSopenharmony_ci { /* metrics proxy server side: ws server for clients to connect to */ 1174d4afb5ceSopenharmony_ci "lws-openmetrics-prox-server", 1175d4afb5ceSopenharmony_ci callback_lws_openmetrics_prox_server, 1176d4afb5ceSopenharmony_ci sizeof(struct pss), 1177d4afb5ceSopenharmony_ci 1024, 0, NULL, 0 1178d4afb5ceSopenharmony_ci }, 1179d4afb5ceSopenharmony_ci#endif 1180d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) && defined(LWS_ROLE_WS) 1181d4afb5ceSopenharmony_ci { /* client to metrics proxy: ws client to connect to metrics proxy*/ 1182d4afb5ceSopenharmony_ci "lws-openmetrics-prox-client", 1183d4afb5ceSopenharmony_ci callback_lws_openmetrics_prox_client, 1184d4afb5ceSopenharmony_ci sizeof(struct pss), 1185d4afb5ceSopenharmony_ci 1024, 0, NULL, 0 1186d4afb5ceSopenharmony_ci }, 1187d4afb5ceSopenharmony_ci#endif 1188d4afb5ceSopenharmony_ci}; 1189d4afb5ceSopenharmony_ci 1190d4afb5ceSopenharmony_ciLWS_VISIBLE const lws_plugin_protocol_t lws_openmetrics_export = { 1191d4afb5ceSopenharmony_ci .hdr = { 1192d4afb5ceSopenharmony_ci "lws OpenMetrics export", 1193d4afb5ceSopenharmony_ci "lws_protocol_plugin", 1194d4afb5ceSopenharmony_ci LWS_BUILD_HASH, 1195d4afb5ceSopenharmony_ci LWS_PLUGIN_API_MAGIC 1196d4afb5ceSopenharmony_ci }, 1197d4afb5ceSopenharmony_ci 1198d4afb5ceSopenharmony_ci .protocols = lws_openmetrics_export_protocols, 1199d4afb5ceSopenharmony_ci .count_protocols = LWS_ARRAY_SIZE(lws_openmetrics_export_protocols), 1200d4afb5ceSopenharmony_ci}; 1201