@cryptotaxi247 / netdata-1 / commits / de75ef2f6

add support for the info parameter to all external plugin functions (#16915)

* add support for the info parameter to all functions * add SO_CLOEXEC to inbound connections * network-connections aggregated view for servers with dozens of thousands of connections * optimized /proc/net files parsing; aggregated view of network-connections returns sorted sockets to avoid dancing visualization * local-sockets is now using aral * lower the payload returned by network-connections

Costa Tsaousis committed Feb 2, 2024 at 22:44 UTC de75ef2f6dccfa1d357d14b86179b8174c3745a5
20 files changed +760 -391
collectors/apps.plugin/apps_plugin.c
+12 -10
@@ -4399,10 +4399,11 @@ static void apps_plugin_function_processes_help(const char *transaction) {
4399 buffer_json_add_array_item_double(wb, _tmp); \
4400 } while(0)
4401
4402 -static void function_processes(const char *transaction, char *function __maybe_unused,
4402 +static void function_processes(const char *transaction, char *function,
4403 usec_t *stop_monotonic_ut __maybe_unused, bool *cancelled __maybe_unused,
4404 BUFFER *payload __maybe_unused, HTTP_ACCESS access,
4405 const char *source __maybe_unused, void *data __maybe_unused) {
4406 + time_t now_s = now_realtime_sec();
4407 struct pid_stat *p;
4408
4409 bool show_cmdline = http_access_user_has_enough_access_level_for_endpoint(
@@ -4418,6 +4419,7 @@ static void function_processes(const char *transaction, char *function __maybe_u
4419 pid_t pid = 0;
4420 uid_t uid = 0;
4421 gid_t gid = 0;
4422 + bool info = false;
4423
4424 bool filter_pid = false, filter_uid = false, filter_gid = false;
4425
@@ -4468,16 +4470,11 @@ static void function_processes(const char *transaction, char *function __maybe_u
4470 apps_plugin_function_processes_help(transaction);
4471 return;
4472 }
4471 - else {
4472 - char msg[1024];
4473 - snprintfz(msg, sizeof(msg), "Invalid parameter '%s'", keyword);
4474 - pluginsd_function_json_error_to_stdout(transaction, HTTP_RESP_BAD_REQUEST, msg);
4475 - return;
4473 + else if(strcmp(keyword, "info") == 0) {
4474 + info = true;
4475 }
4476 }
4477
4479 - time_t expires = now_realtime_sec() + update_every;
4480 -
4478 unsigned int cpu_divisor = time_factor * RATES_DETAIL / 100;
4479 unsigned int memory_divisor = 1024;
4480 unsigned int io_divisor = 1024 * RATES_DETAIL;
@@ -4487,9 +4484,13 @@ static void function_processes(const char *transaction, char *function __maybe_u
4484 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
4485 buffer_json_member_add_string(wb, "type", "table");
4486 buffer_json_member_add_time_t(wb, "update_every", update_every);
4487 + buffer_json_member_add_boolean(wb, "has_history", false);
4488 buffer_json_member_add_string(wb, "help", APPS_PLUGIN_PROCESSES_FUNCTION_DESCRIPTION);
4489 buffer_json_member_add_array(wb, "data");
4490
4491 + if(info)
4492 + goto close_and_send;
4493 +
4494 NETDATA_DOUBLE
4495 UserCPU_max = 0.0
4496 , SysCPU_max = 0.0
@@ -5251,10 +5252,11 @@ static void function_processes(const char *transaction, char *function __maybe_u
5252 }
5253 buffer_json_object_close(wb); // group_by
5254
5254 - buffer_json_member_add_time_t(wb, "expires", expires);
5255 +close_and_send:
5256 + buffer_json_member_add_time_t(wb, "expires", now_s + update_every);
5257 buffer_json_finalize(wb);
5258
5257 - pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", expires, wb);
5259 + pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", now_s + update_every, wb);
5260
5261 buffer_free(wb);
5262 }
collectors/cgroups.plugin/cgroup-top.c
+2
@@ -107,6 +107,7 @@ int cgroup_function_cgroup_top(BUFFER *wb, const char *function __maybe_unused)
107 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
108 buffer_json_member_add_string(wb, "type", "table");
109 buffer_json_member_add_time_t(wb, "update_every", 1);
110 + buffer_json_member_add_boolean(wb, "has_history", false);
111 buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_CGTOP_HELP);
112 buffer_json_member_add_array(wb, "data");
113
@@ -349,6 +350,7 @@ int cgroup_function_systemd_top(BUFFER *wb, const char *function __maybe_unused)
350 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
351 buffer_json_member_add_string(wb, "type", "table");
352 buffer_json_member_add_time_t(wb, "update_every", 1);
353 + buffer_json_member_add_boolean(wb, "has_history", false);
354 buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_CGTOP_HELP);
355 buffer_json_member_add_array(wb, "data");
356
collectors/diskspace.plugin/plugin_diskspace.c
+1
@@ -645,6 +645,7 @@ int diskspace_function_mount_points(BUFFER *wb, const char *function __maybe_unu
645 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
646 buffer_json_member_add_string(wb, "type", "table");
647 buffer_json_member_add_time_t(wb, "update_every", 1);
648 + buffer_json_member_add_boolean(wb, "has_history", false);
649 buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_DISKSPACE_HELP);
650 buffer_json_member_add_array(wb, "data");
651
collectors/ebpf.plugin/ebpf_functions.c
+12 -4
@@ -292,6 +292,9 @@ static void ebpf_function_socket_manipulation(const char *transaction,
292 rw_spinlock_write_lock(&ebpf_judy_pid.index.rw_spinlock);
293 network_viewer_opt.enabled = CONFIG_BOOLEAN_YES;
294 uint32_t previous;
295 + bool info = false;
296 + time_t now_s = now_realtime_sec();
297 +
298 static const char *socket_help = {
299 "ebpf.plugin / socket\n"
300 "\n"
@@ -413,7 +416,8 @@ for (int i = 1; i < PLUGINSD_MAX_WORDS; i++) {
416 ebpf_function_help(transaction, socket_help);
417 rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
418 return;
416 - }
419 + } else if (strncmp(keyword, "info", 4) == 0)
420 + info = true;
421 }
422 rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
423
@@ -443,8 +447,12 @@ for (int i = 1; i < PLUGINSD_MAX_WORDS; i++) {
447 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
448 buffer_json_member_add_string(wb, "type", "table");
449 buffer_json_member_add_time_t(wb, "update_every", em->update_every);
450 + buffer_json_member_add_boolean(wb, "has_history", false);
451 buffer_json_member_add_string(wb, "help", EBPF_PLUGIN_SOCKET_FUNCTION_DESCRIPTION);
452
453 + if(info)
454 + goto close_and_send;
455 +
456 // Collect data
457 buffer_json_member_add_array(wb, "data");
458 ebpf_socket_read_open_connections(wb, em);
@@ -652,12 +660,12 @@ for (int i = 1; i < PLUGINSD_MAX_WORDS; i++) {
660 }
661 buffer_json_object_close(wb); // group_by
662
655 - time_t expires = now_realtime_sec() + em->update_every;
656 - buffer_json_member_add_time_t(wb, "expires", expires);
663 +close_and_send:
664 + buffer_json_member_add_time_t(wb, "expires", now_s + em->update_every);
665 buffer_json_finalize(wb);
666
667 // Lock necessary to avoid race condition
660 - pluginsd_function_result_begin_to_stdout(transaction, HTTP_RESP_OK, "application/json", expires);
668 + pluginsd_function_result_begin_to_stdout(transaction, HTTP_RESP_OK, "application/json", now_s + em->update_every);
669
670 fwrite(buffer_tostring(wb), buffer_strlen(wb), 1, stdout);
671
collectors/freeipmi.plugin/freeipmi_plugin.c
+21 -3
@@ -1475,14 +1475,31 @@ static void freeimi_function_sensors(const char *transaction, char *function __m
1475 usec_t *stop_monotonic_ut __maybe_unused, bool *cancelled __maybe_unused,
1476 BUFFER *payload __maybe_unused, HTTP_ACCESS access __maybe_unused,
1477 const char *source __maybe_unused, void *data __maybe_unused) {
1478 - time_t expires = now_realtime_sec() + update_every;
1478 + time_t now_s = now_realtime_sec();
1479
1480 BUFFER *wb = buffer_create(4096, NULL);
1481 buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS);
1482 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
1483 buffer_json_member_add_string(wb, "type", "table");
1484 buffer_json_member_add_time_t(wb, "update_every", update_every);
1485 + buffer_json_member_add_boolean(wb, "has_history", false);
1486 buffer_json_member_add_string(wb, "help", "View IPMI sensor readings and its state");
1487 +
1488 + char function_copy[strlen(function) + 1];
1489 + memcpy(function_copy, function, sizeof(function_copy));
1490 + char *words[1024];
1491 + size_t num_words = quoted_strings_splitter_pluginsd(function_copy, words, 1024);
1492 + for(size_t i = 1; i < num_words ;i++) {
1493 + char *param = get_word(words, num_words, i);
1494 + if(strcmp(param, "info") == 0) {
1495 + buffer_json_member_add_array(wb, "accepted_params");
1496 + buffer_json_array_close(wb); // accepted_params
1497 + buffer_json_member_add_array(wb, "required_params");
1498 + buffer_json_array_close(wb); // required_params
1499 + goto close_and_send;
1500 + }
1501 + }
1502 +
1503 buffer_json_member_add_array(wb, "data");
1504
1505 struct sensor *sn;
@@ -1608,10 +1625,11 @@ static void freeimi_function_sensors(const char *transaction, char *function __m
1625 }
1626 buffer_json_array_close(wb);
1627
1611 - buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
1628 +close_and_send:
1629 + buffer_json_member_add_time_t(wb, "expires", now_s + update_every);
1630 buffer_json_finalize(wb);
1631
1614 - pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", expires, wb);
1632 + pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", now_s + update_every, wb);
1633
1634 buffer_free(wb);
1635 }
collectors/network-viewer.plugin/network-connections-chart.html
+26 -2
@@ -557,15 +557,39 @@
557
558 const app = updateApps(svg, data, w, h, borderPadding, theme);
559
560 + app.transition().duration(5000)
561 +
562 simulation = d3.forceSimulation(data)
563 //.force('center', d3.forceCenter(cw, ch).strength(1))
562 - .force("x", d3.forceX(d => d.d3.x).strength(0.05))
563 - .force("y", d3.forceY(d => d.d3.y).strength(0.05))
564 + .force("x", d3.forceX(d => d.d3.x).strength(d => {
565 + if(d.counts.listen === d.counts.total)
566 + return 0.5
567 + else
568 + return 0.05
569 + }))
570 + .force("y", d3.forceY(d => d.d3.y).strength(d => {
571 + if(d.counts.listen === d.counts.total)
572 + return 0.5
573 + else
574 + return 0.05
575 + }))
576 //.force("charge", d3.forceManyBody().strength(-0.05))
577 .force("collide", d3.forceCollide(d => d.d3.size * 1.1 + 15).strength(1))
578 .on('tick', ticked);
579
580 function ticked() {
581 + data.forEach(d => {
582 + if(d.x > w - d.d3.size)
583 + d.x = w - d.d3.size;
584 + else if(d.x < 0)
585 + d.x = 0;
586 +
587 + if(d.y > h - d.d3.size)
588 + d.y = h - d.d3.size;
589 + else if(d.y < 0)
590 + d.y = 0;
591 + });
592 +
593 app.attr('transform', d => `translate(${d.x}, ${d.y})`);
594 }
595
collectors/network-viewer.plugin/network-viewer.c
+548 -316
@@ -3,12 +3,23 @@
3 #include "collectors/all.h"
4 #include "libnetdata/libnetdata.h"
5 #include "libnetdata/required_dummies.h"
6 +
7 +#define LOCAL_SOCKETS_EXTENDED_MEMBERS struct { \
8 + size_t count; \
9 + const char *local_address_space; \
10 + const char *remote_address_space; \
11 + } network_viewer;
12 +
13 #include "libnetdata/maps/local-sockets.h"
14 #include "libnetdata/maps/system-users.h"
15
16 #define NETWORK_CONNECTIONS_VIEWER_FUNCTION "network-connections"
17 #define NETWORK_CONNECTIONS_VIEWER_HELP "Network connections explorer"
18
19 +#define SIMPLE_HASHTABLE_VALUE_TYPE LOCAL_SOCKET
20 +#define SIMPLE_HASHTABLE_NAME _AGGREGATED_SOCKETS
21 +#include "libnetdata/simple_hashtable.h"
22 +
23 netdata_mutex_t stdout_mutex = NETDATA_MUTEX_INITIALIZER;
24 static bool plugin_should_exit = false;
25 static USERNAMES_CACHE *uc;
@@ -44,10 +55,7 @@ ENUM_STR_MAP_DEFINE(TCP_STATE) = {
55 };
56 ENUM_STR_DEFINE_FUNCTIONS(TCP_STATE, 0, "unknown");
57
47 -
48 -static void local_socket_to_array(struct local_socket_state *ls, struct local_socket *n, void *data) {
49 - BUFFER *wb = data;
50 -
58 +static void local_socket_to_json_array(BUFFER *wb, LOCAL_SOCKET *n, uint64_t proc_self_net_ns_inode, bool aggregated) {
59 char local_address[INET6_ADDRSTRLEN];
60 char remote_address[INET6_ADDRSTRLEN];
61 char *protocol;
@@ -66,7 +74,7 @@ static void local_socket_to_array(struct local_socket_state *ls, struct local_so
74 return;
75
76 const char *type;
69 - if(n->net_ns_inode == ls->proc_self_net_ns_inode)
77 + if(n->net_ns_inode == proc_self_net_ns_inode)
78 type = "system";
79 else if(n->net_ns_inode == 0)
80 type = "[unknown]";
@@ -90,55 +98,141 @@ static void local_socket_to_array(struct local_socket_state *ls, struct local_so
98 else
99 buffer_json_add_array_item_string(wb, n->comm);
100
93 - buffer_json_add_array_item_string(wb, n->cmdline);
101 + // buffer_json_add_array_item_string(wb, string2str(n->cmdline));
102
103 if(n->uid == UID_UNSET) {
96 - buffer_json_add_array_item_uint64(wb, n->uid);
104 + // buffer_json_add_array_item_uint64(wb, n->uid);
105 buffer_json_add_array_item_string(wb, "[unknown]");
106 }
107 else {
100 - buffer_json_add_array_item_uint64(wb, n->uid);
108 + // buffer_json_add_array_item_uint64(wb, n->uid);
109 STRING *u = system_usernames_cache_lookup_uid(uc, n->uid);
110 buffer_json_add_array_item_string(wb, string2str(u));
111 string_freez(u);
112 }
113
106 - buffer_json_add_array_item_string(wb, local_address);
107 - buffer_json_add_array_item_uint64(wb, n->local.port);
108 - buffer_json_add_array_item_string(wb, local_sockets_address_space(&n->local));
109 - buffer_json_add_array_item_string(wb, remote_address);
110 - buffer_json_add_array_item_uint64(wb, n->remote.port);
111 - buffer_json_add_array_item_string(wb, local_sockets_address_space(&n->remote));
114 + if(!aggregated) {
115 + buffer_json_add_array_item_string(wb, local_address);
116 + buffer_json_add_array_item_uint64(wb, n->local.port);
117 + }
118 + buffer_json_add_array_item_string(wb, n->network_viewer.local_address_space);
119 +
120 + if(!aggregated) {
121 + buffer_json_add_array_item_string(wb, remote_address);
122 + buffer_json_add_array_item_uint64(wb, n->remote.port);
123 + }
124 + buffer_json_add_array_item_string(wb, n->network_viewer.remote_address_space);
125
126 uint16_t server_port;
114 - switch(n->direction) {
127 + const char *server_address;
128 + const char *client_address_space;
129 + const char *server_address_space;
130 + switch (n->direction) {
131 case SOCKET_DIRECTION_LISTEN:
132 case SOCKET_DIRECTION_INBOUND:
133 case SOCKET_DIRECTION_LOCAL_INBOUND:
134 server_port = n->local.port;
135 + server_address = local_address;
136 + server_address_space = n->network_viewer.local_address_space;
137 + client_address_space = n->network_viewer.remote_address_space;
138 break;
139
140 case SOCKET_DIRECTION_OUTBOUND:
141 case SOCKET_DIRECTION_LOCAL_OUTBOUND:
142 server_port = n->remote.port;
143 + server_address = remote_address;
144 + server_address_space = n->network_viewer.remote_address_space;
145 + client_address_space = n->network_viewer.local_address_space;
146 break;
147
148 case SOCKET_DIRECTION_NONE:
149 break;
150 }
151 + if(aggregated)
152 + buffer_json_add_array_item_string(wb, server_address);
153 +
154 buffer_json_add_array_item_uint64(wb, server_port);
155
131 - buffer_json_add_array_item_uint64(wb, n->inode);
132 - buffer_json_add_array_item_uint64(wb, n->net_ns_inode);
133 - buffer_json_add_array_item_uint64(wb, 1); // count
156 + if(aggregated) {
157 + buffer_json_add_array_item_string(wb, client_address_space);
158 + buffer_json_add_array_item_string(wb, server_address_space);
159 + }
160 +
161 + // buffer_json_add_array_item_uint64(wb, n->inode);
162 + // buffer_json_add_array_item_uint64(wb, n->net_ns_inode);
163 + buffer_json_add_array_item_uint64(wb, n->network_viewer.count);
164 }
165 buffer_json_array_close(wb);
166 }
167
168 +static void local_sockets_cb_to_json(LS_STATE *ls, LOCAL_SOCKET *n, void *data) {
169 + n->network_viewer.count = 1;
170 + n->network_viewer.local_address_space = local_sockets_address_space(&n->local);
171 + n->network_viewer.remote_address_space = local_sockets_address_space(&n->remote);
172 + local_socket_to_json_array(data, n, ls->proc_self_net_ns_inode, false);
173 +}
174 +
175 +static void local_sockets_cb_to_aggregation(LS_STATE *ls __maybe_unused, LOCAL_SOCKET *n, void *data) {
176 + SIMPLE_HASHTABLE_AGGREGATED_SOCKETS *ht = data;
177 + n->network_viewer.count = 1;
178 + n->network_viewer.local_address_space = local_sockets_address_space(&n->local);
179 + n->network_viewer.remote_address_space = local_sockets_address_space(&n->remote);
180 +
181 + switch(n->direction) {
182 + case SOCKET_DIRECTION_INBOUND:
183 + case SOCKET_DIRECTION_LOCAL_INBOUND:
184 + case SOCKET_DIRECTION_LISTEN:
185 + memset(&n->remote.ip, 0, sizeof(n->remote.ip));
186 + n->remote.port = 0;
187 + break;
188 +
189 + case SOCKET_DIRECTION_OUTBOUND:
190 + case SOCKET_DIRECTION_LOCAL_OUTBOUND:
191 + memset(&n->local.ip, 0, sizeof(n->remote.ip));
192 + n->local.port = 0;
193 + break;
194 +
195 + case SOCKET_DIRECTION_NONE:
196 + return;
197 + }
198 +
199 + n->inode = 0;
200 + n->local_ip_hash = 0;
201 + n->remote_ip_hash = 0;
202 + n->local_port_hash = 0;
203 + n->timer = 0;
204 + n->retransmits = 0;
205 + n->expires = 0;
206 + n->rqueue = 0;
207 + n->wqueue = 0;
208 + memset(&n->local_port_key, 0, sizeof(n->local_port_key));
209 +
210 + XXH64_hash_t hash = XXH3_64bits(n, sizeof(*n));
211 + SIMPLE_HASHTABLE_SLOT_AGGREGATED_SOCKETS *sl = simple_hashtable_get_slot_AGGREGATED_SOCKETS(ht, hash, n, true);
212 + LOCAL_SOCKET *t = SIMPLE_HASHTABLE_SLOT_DATA(sl);
213 + if(t) {
214 + t->network_viewer.count++;
215 + }
216 + else {
217 + t = mallocz(sizeof(*t));
218 + memcpy(t, n, sizeof(*t));
219 + t->cmdline = string_dup(t->cmdline);
220 + simple_hashtable_set_slot_AGGREGATED_SOCKETS(ht, sl, hash, t);
221 + }
222 +}
223 +
224 +static int local_sockets_compar(const void *a, const void *b) {
225 + LOCAL_SOCKET *n1 = *(LOCAL_SOCKET **)a, *n2 = *(LOCAL_SOCKET **)b;
226 + return strcmp(n1->comm, n2->comm);
227 +}
228 +
229 void network_viewer_function(const char *transaction, char *function __maybe_unused, usec_t *stop_monotonic_ut __maybe_unused,
230 bool *cancelled __maybe_unused, BUFFER *payload __maybe_unused, HTTP_ACCESS access __maybe_unused,
231 const char *source __maybe_unused, void *data __maybe_unused) {
232
233 + time_t now_s = now_realtime_sec();
234 + bool aggregated = false;
235 +
236 CLEAN_BUFFER *wb = buffer_create(0, NULL);
237 buffer_flush(wb);
238 wb->content_type = CT_APPLICATION_JSON;
@@ -147,360 +241,483 @@ void network_viewer_function(const char *transaction, char *function __maybe_unu
241 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
242 buffer_json_member_add_string(wb, "type", "table");
243 buffer_json_member_add_time_t(wb, "update_every", 5);
244 + buffer_json_member_add_boolean(wb, "has_history", false);
245 buffer_json_member_add_string(wb, "help", NETWORK_CONNECTIONS_VIEWER_HELP);
151 - buffer_json_member_add_array(wb, "data");
152 -
153 - LS_STATE ls = {
154 - .config = {
155 - .listening = true,
156 - .inbound = true,
157 - .outbound = true,
158 - .local = true,
159 - .tcp4 = true,
160 - .tcp6 = true,
161 - .udp4 = true,
162 - .udp6 = true,
163 - .pid = true,
164 - .uid = true,
165 - .cmdline = true,
166 - .comm = true,
167 - .namespaces = true,
168 -
169 - .max_errors = 10,
170 -
171 - .cb = local_socket_to_array,
172 - .data = wb,
173 - },
174 - .stats = { 0 },
175 - .sockets_hashtable = { 0 },
176 - .local_ips_hashtable = { 0 },
177 - .listening_ports_hashtable = { 0 },
178 - };
179 -
180 - local_sockets_process(&ls);
246
182 - buffer_json_array_close(wb);
183 - buffer_json_member_add_object(wb, "columns");
247 +#ifdef ENABLE_DETAILED_VIEW
248 + buffer_json_member_add_array(wb, "accepted_params");
249 {
185 - size_t field_id = 0;
186 -
187 - // Direction
188 - buffer_rrdf_table_add_field(wb, field_id++, "Direction", "Socket Direction",
189 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
190 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
191 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
192 - RRDF_FIELD_OPTS_VISIBLE,
193 - NULL);
194 -
195 - // Protocol
196 - buffer_rrdf_table_add_field(wb, field_id++, "Protocol", "Socket Protocol",
197 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
198 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
199 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
200 - RRDF_FIELD_OPTS_VISIBLE,
201 - NULL);
202 -
203 - // Type
204 - buffer_rrdf_table_add_field(wb, field_id++, "Namespace", "Namespace",
205 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
206 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
207 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
208 - RRDF_FIELD_OPTS_VISIBLE,
209 - NULL);
210 -
211 - // State
212 - buffer_rrdf_table_add_field(wb, field_id++, "State", "Socket State",
213 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
214 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
215 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
216 - RRDF_FIELD_OPTS_VISIBLE,
217 - NULL);
218 -
219 - // Pid
220 - buffer_rrdf_table_add_field(wb, field_id++, "PID", "Process ID",
221 - RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
222 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
223 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
224 - RRDF_FIELD_OPTS_VISIBLE,
225 - NULL);
226 -
227 - // Comm
228 - buffer_rrdf_table_add_field(wb, field_id++, "Process", "Process Name",
229 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
230 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
231 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
232 - RRDF_FIELD_OPTS_VISIBLE|RRDF_FIELD_OPTS_FULL_WIDTH,
233 - NULL);
234 -
235 - // Cmdline
236 - buffer_rrdf_table_add_field(wb, field_id++, "CommandLine", "Command Line",
237 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
238 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
239 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
240 - RRDF_FIELD_OPTS_NONE|RRDF_FIELD_OPTS_FULL_WIDTH,
241 - NULL);
242 -
243 - // Uid
244 - buffer_rrdf_table_add_field(wb, field_id++, "UID", "User ID",
245 - RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
246 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
247 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
248 - RRDF_FIELD_OPTS_NONE,
249 - NULL);
250 -
251 - // Username
252 - buffer_rrdf_table_add_field(wb, field_id++, "User", "Username",
253 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
254 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
255 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
256 - RRDF_FIELD_OPTS_VISIBLE,
257 - NULL);
258 -
259 - // Local Address
260 - buffer_rrdf_table_add_field(wb, field_id++, "LocalIP", "Local IP Address",
261 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
262 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
263 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
264 - RRDF_FIELD_OPTS_VISIBLE|RRDF_FIELD_OPTS_FULL_WIDTH,
265 - NULL);
266 -
267 - // Local Port
268 - buffer_rrdf_table_add_field(wb, field_id++, "LocalPort", "Local Port",
269 - RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
270 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
271 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
272 - RRDF_FIELD_OPTS_VISIBLE,
273 - NULL);
274 -
275 - // Local Address Space
276 - buffer_rrdf_table_add_field(wb, field_id++, "LocalAddressSpace", "Local IP Address Space",
277 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
278 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
279 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
280 - RRDF_FIELD_OPTS_NONE,
281 - NULL);
282 -
283 - // Remote Address
284 - buffer_rrdf_table_add_field(wb, field_id++, "RemoteIP", "Remote IP Address",
285 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
286 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
287 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
288 - RRDF_FIELD_OPTS_VISIBLE|RRDF_FIELD_OPTS_FULL_WIDTH,
289 - NULL);
290 -
291 - // Remote Port
292 - buffer_rrdf_table_add_field(wb, field_id++, "RemotePort", "Remote Port",
293 - RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
294 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
295 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
296 - RRDF_FIELD_OPTS_VISIBLE,
297 - NULL);
298 -
299 - // Remote Address Space
300 - buffer_rrdf_table_add_field(wb, field_id++, "RemoteAddressSpace", "Remote IP Address Space",
301 - RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
302 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
303 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
304 - RRDF_FIELD_OPTS_NONE,
305 - NULL);
306 -
307 - // Server Port
308 - buffer_rrdf_table_add_field(wb, field_id++, "ServerPort", "Server Port",
309 - RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
310 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
311 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
312 - RRDF_FIELD_OPTS_NONE,
313 - NULL);
314 -
315 - // inode
316 - buffer_rrdf_table_add_field(wb, field_id++, "Inode", "Socket Inode",
317 - RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
318 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
319 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
320 - RRDF_FIELD_OPTS_NONE,
321 - NULL);
322 -
323 - // Namespace inode
324 - buffer_rrdf_table_add_field(wb, field_id++, "Namespace Inode", "Namespace Inode",
325 - RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
326 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
327 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
328 - RRDF_FIELD_OPTS_NONE,
329 - NULL);
330 -
331 - // Count
332 - buffer_rrdf_table_add_field(wb, field_id++, "Count", "Count",
333 - RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
334 - 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
335 - RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
336 - RRDF_FIELD_OPTS_NONE,
337 - NULL);
250 + buffer_json_add_array_item_string(wb, "sockets");
251 }
339 - buffer_json_object_close(wb); // columns
340 - buffer_json_member_add_string(wb, "default_sort_column", "Direction");
341 -
342 - buffer_json_member_add_object(wb, "custom_charts");
252 + buffer_json_array_close(wb); // accepted_params
253 + buffer_json_member_add_array(wb, "required_params");
254 {
344 - buffer_json_member_add_object(wb, "Network Map");
255 + buffer_json_add_array_item_object(wb);
256 {
346 - buffer_json_member_add_string(wb, "type", "network-viewer");
257 + buffer_json_member_add_string(wb, "id", "sockets");
258 + buffer_json_member_add_string(wb, "name", "Sockets");
259 + buffer_json_member_add_string(wb, "help", "Select the source type to query");
260 + buffer_json_member_add_string(wb, "type", "select");
261 + buffer_json_member_add_array(wb, "options");
262 + {
263 + buffer_json_add_array_item_object(wb);
264 + {
265 + buffer_json_member_add_string(wb, "id", "aggregated");
266 + buffer_json_member_add_string(wb, "name", "Aggregated view of sockets");
267 + }
268 + buffer_json_object_close(wb);
269 + buffer_json_add_array_item_object(wb);
270 + {
271 + buffer_json_member_add_string(wb, "id", "detailed");
272 + buffer_json_member_add_string(wb, "name", "Detailed view of all sockets");
273 + }
274 + buffer_json_object_close(wb);
275 + }
276 + buffer_json_array_close(wb); // options array
277 }
278 buffer_json_object_close(wb);
279 }
350 - buffer_json_object_close(wb); // custom_charts
280 + buffer_json_array_close(wb); // required_params
281 +#endif
282 +
283 + char function_copy[strlen(function) + 1];
284 + memcpy(function_copy, function, sizeof(function_copy));
285 + char *words[1024];
286 + size_t num_words = quoted_strings_splitter_pluginsd(function_copy, words, 1024);
287 + for(size_t i = 1; i < num_words ;i++) {
288 + char *param = get_word(words, num_words, i);
289 + if(strcmp(param, "sockets:aggregated") == 0) {
290 + aggregated = true;
291 + }
292 + else if(strcmp(param, "sockets:detailed") == 0) {
293 + aggregated = false;
294 + }
295 + else if(strcmp(param, "info") == 0) {
296 + goto close_and_send;
297 + }
298 + }
299
352 - buffer_json_member_add_object(wb, "charts");
300 {
354 - // Data Collection Age chart
355 - buffer_json_member_add_object(wb, "Count");
356 - {
357 - buffer_json_member_add_string(wb, "type", "stacked-bar");
358 - buffer_json_member_add_array(wb, "columns");
359 - {
360 - buffer_json_add_array_item_string(wb, "Direction");
361 - }
362 - buffer_json_array_close(wb);
301 + buffer_json_member_add_array(wb, "data");
302 +
303 + LS_STATE ls = {
304 + .config = {
305 + .listening = true,
306 + .inbound = true,
307 + .outbound = true,
308 + .local = true,
309 + .tcp4 = true,
310 + .tcp6 = true,
311 + .udp4 = true,
312 + .udp6 = true,
313 + .pid = true,
314 + .uid = true,
315 + .cmdline = true,
316 + .comm = true,
317 + .namespaces = true,
318 +
319 + .max_errors = 10,
320 + },
321 + .stats = { 0 },
322 + .sockets_hashtable = { 0 },
323 + .local_ips_hashtable = { 0 },
324 + .listening_ports_hashtable = { 0 },
325 + };
326 +
327 + SIMPLE_HASHTABLE_AGGREGATED_SOCKETS ht = { 0 };
328 + if(aggregated) {
329 + simple_hashtable_init_AGGREGATED_SOCKETS(&ht, 1024);
330 + ls.config.cb = local_sockets_cb_to_aggregation;
331 + ls.config.data = &ht;
332 + }
333 + else {
334 + ls.config.cb = local_sockets_cb_to_json;
335 + ls.config.data = wb;
336 }
364 - buffer_json_object_close(wb);
337
366 - // Streaming Age chart
367 - buffer_json_member_add_object(wb, "Count");
368 - {
369 - buffer_json_member_add_string(wb, "type", "stacked-bar");
370 - buffer_json_member_add_array(wb, "columns");
371 - {
372 - buffer_json_add_array_item_string(wb, "Process");
338 + local_sockets_process(&ls);
339 +
340 + if(aggregated) {
341 + LOCAL_SOCKET *array[ht.used];
342 + size_t added = 0;
343 + uint64_t proc_self_net_ns_inode = ls.proc_self_net_ns_inode;
344 + for(SIMPLE_HASHTABLE_SLOT_AGGREGATED_SOCKETS *sl = simple_hashtable_first_read_only_AGGREGATED_SOCKETS(&ht);
345 + sl;
346 + sl = simple_hashtable_next_read_only_AGGREGATED_SOCKETS(&ht, sl)) {
347 + LOCAL_SOCKET *n = SIMPLE_HASHTABLE_SLOT_DATA(sl);
348 + if(!n || added >= ht.used) continue;
349 +
350 + array[added++] = n;
351 }
374 - buffer_json_array_close(wb);
375 - }
376 - buffer_json_object_close(wb);
352
378 - // DB Duration
379 - buffer_json_member_add_object(wb, "Count");
380 - {
381 - buffer_json_member_add_string(wb, "type", "stacked-bar");
382 - buffer_json_member_add_array(wb, "columns");
383 - {
384 - buffer_json_add_array_item_string(wb, "Protocol");
353 + qsort(array, added, sizeof(LOCAL_SOCKET *), local_sockets_compar);
354 +
355 + for(size_t i = 0; i < added ;i++) {
356 + local_socket_to_json_array(wb, array[i], proc_self_net_ns_inode, true);
357 + string_freez(array[i]->cmdline);
358 + freez(array[i]);
359 }
386 - buffer_json_array_close(wb);
360 +
361 + simple_hashtable_destroy_AGGREGATED_SOCKETS(&ht);
362 }
388 - buffer_json_object_close(wb);
389 - }
390 - buffer_json_object_close(wb); // charts
363
392 - buffer_json_member_add_array(wb, "default_charts");
393 - {
394 - buffer_json_add_array_item_array(wb);
395 - buffer_json_add_array_item_string(wb, "Count");
396 - buffer_json_add_array_item_string(wb, "Direction");
364 buffer_json_array_close(wb);
365 + buffer_json_member_add_object(wb, "columns");
366 + {
367 + size_t field_id = 0;
368 +
369 + // Direction
370 + buffer_rrdf_table_add_field(wb, field_id++, "Direction", "Socket Direction",
371 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
372 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
373 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
374 + RRDF_FIELD_OPTS_VISIBLE,
375 + NULL);
376 +
377 + // Protocol
378 + buffer_rrdf_table_add_field(wb, field_id++, "Protocol", "Socket Protocol",
379 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
380 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
381 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
382 + RRDF_FIELD_OPTS_VISIBLE,
383 + NULL);
384 +
385 + // Type
386 + buffer_rrdf_table_add_field(wb, field_id++, "Namespace", "Namespace",
387 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
388 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
389 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
390 + RRDF_FIELD_OPTS_VISIBLE,
391 + NULL);
392 +
393 + // State
394 + buffer_rrdf_table_add_field(wb, field_id++, "State", "Socket State",
395 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
396 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
397 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
398 + RRDF_FIELD_OPTS_VISIBLE,
399 + NULL);
400 +
401 + // Pid
402 + buffer_rrdf_table_add_field(wb, field_id++, "PID", "Process ID",
403 + RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
404 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
405 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
406 + RRDF_FIELD_OPTS_VISIBLE,
407 + NULL);
408 +
409 + // Comm
410 + buffer_rrdf_table_add_field(wb, field_id++, "Process", "Process Name",
411 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
412 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
413 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
414 + RRDF_FIELD_OPTS_VISIBLE|RRDF_FIELD_OPTS_FULL_WIDTH,
415 + NULL);
416 +
417 +// // Cmdline
418 +// buffer_rrdf_table_add_field(wb, field_id++, "CommandLine", "Command Line",
419 +// RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
420 +// 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
421 +// RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
422 +// RRDF_FIELD_OPTS_NONE|RRDF_FIELD_OPTS_FULL_WIDTH,
423 +// NULL);
424 +
425 +// // Uid
426 +// buffer_rrdf_table_add_field(wb, field_id++, "UID", "User ID",
427 +// RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
428 +// 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
429 +// RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
430 +// RRDF_FIELD_OPTS_NONE,
431 +// NULL);
432 +
433 + // Username
434 + buffer_rrdf_table_add_field(wb, field_id++, "User", "Username",
435 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
436 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
437 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
438 + RRDF_FIELD_OPTS_VISIBLE,
439 + NULL);
440 +
441 + if(!aggregated) {
442 + // Local Address
443 + buffer_rrdf_table_add_field(wb, field_id++, "LocalIP", "Local IP Address",
444 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
445 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
446 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
447 + RRDF_FIELD_OPTS_VISIBLE|RRDF_FIELD_OPTS_FULL_WIDTH,
448 + NULL);
449 +
450 + // Local Port
451 + buffer_rrdf_table_add_field(wb, field_id++, "LocalPort", "Local Port",
452 + RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
453 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
454 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
455 + RRDF_FIELD_OPTS_VISIBLE,
456 + NULL);
457 + }
458
399 - buffer_json_add_array_item_array(wb);
400 - buffer_json_add_array_item_string(wb, "Count");
401 - buffer_json_add_array_item_string(wb, "Process");
402 - buffer_json_array_close(wb);
403 - }
404 - buffer_json_array_close(wb);
459 + // Local Address Space
460 + buffer_rrdf_table_add_field(wb, field_id++, "LocalAddressSpace", "Local IP Address Space",
461 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
462 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
463 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
464 + RRDF_FIELD_OPTS_NONE,
465 + NULL);
466 +
467 + if(!aggregated) {
468 + // Remote Address
469 + buffer_rrdf_table_add_field(wb, field_id++, "RemoteIP", "Remote IP Address",
470 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
471 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
472 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
473 + RRDF_FIELD_OPTS_VISIBLE|RRDF_FIELD_OPTS_FULL_WIDTH,
474 + NULL);
475 +
476 + // Remote Port
477 + buffer_rrdf_table_add_field(wb, field_id++, "RemotePort", "Remote Port",
478 + RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
479 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
480 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
481 + RRDF_FIELD_OPTS_VISIBLE,
482 + NULL);
483 + }
484
406 - buffer_json_member_add_object(wb, "group_by");
407 - {
408 - buffer_json_member_add_object(wb, "Direction");
409 - {
410 - buffer_json_member_add_string(wb, "name", "Direction");
411 - buffer_json_member_add_array(wb, "columns");
412 - {
413 - buffer_json_add_array_item_string(wb, "Direction");
485 + // Remote Address Space
486 + buffer_rrdf_table_add_field(wb, field_id++, "RemoteAddressSpace", "Remote IP Address Space",
487 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
488 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
489 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
490 + RRDF_FIELD_OPTS_NONE,
491 + NULL);
492 +
493 + if(aggregated) {
494 + // Server IP
495 + buffer_rrdf_table_add_field(wb, field_id++, "ServerIP", "Server IP Address",
496 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
497 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
498 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
499 + RRDF_FIELD_OPTS_FULL_WIDTH | (aggregated ? RRDF_FIELD_OPTS_VISIBLE : RRDF_FIELD_OPTS_NONE),
500 + NULL);
501 }
415 - buffer_json_array_close(wb);
502 +
503 + // Server Port
504 + buffer_rrdf_table_add_field(wb, field_id++, "ServerPort", "Server Port",
505 + RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
506 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
507 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
508 + aggregated ? RRDF_FIELD_OPTS_VISIBLE : RRDF_FIELD_OPTS_NONE,
509 + NULL);
510 +
511 + if(aggregated) {
512 + // Client Address Space
513 + buffer_rrdf_table_add_field(wb, field_id++, "ClientAddressSpace", "Client IP Address Space",
514 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
515 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
516 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
517 + RRDF_FIELD_OPTS_VISIBLE,
518 + NULL);
519 +
520 + // Server Address Space
521 + buffer_rrdf_table_add_field(wb, field_id++, "ServerAddressSpace", "Server IP Address Space",
522 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
523 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
524 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
525 + RRDF_FIELD_OPTS_VISIBLE,
526 + NULL);
527 + }
528 +
529 +// // inode
530 +// buffer_rrdf_table_add_field(wb, field_id++, "Inode", "Socket Inode",
531 +// RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
532 +// 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
533 +// RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
534 +// RRDF_FIELD_OPTS_NONE,
535 +// NULL);
536 +
537 +// // Namespace inode
538 +// buffer_rrdf_table_add_field(wb, field_id++, "Namespace Inode", "Namespace Inode",
539 +// RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
540 +// 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
541 +// RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
542 +// RRDF_FIELD_OPTS_NONE,
543 +// NULL);
544 +
545 + // Count
546 + buffer_rrdf_table_add_field(wb, field_id++, "Count", "Number of sockets like this",
547 + RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
548 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
549 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
550 + aggregated ? RRDF_FIELD_OPTS_VISIBLE : RRDF_FIELD_OPTS_NONE,
551 + NULL);
552 }
417 - buffer_json_object_close(wb);
553 + buffer_json_object_close(wb); // columns
554 + buffer_json_member_add_string(wb, "default_sort_column", "Direction");
555
419 - buffer_json_member_add_object(wb, "Protocol");
556 + buffer_json_member_add_object(wb, "custom_charts");
557 {
421 - buffer_json_member_add_string(wb, "name", "Protocol");
422 - buffer_json_member_add_array(wb, "columns");
558 + buffer_json_member_add_object(wb, "Network Map");
559 {
424 - buffer_json_add_array_item_string(wb, "Protocol");
560 + buffer_json_member_add_string(wb, "type", "network-viewer");
561 }
426 - buffer_json_array_close(wb);
562 + buffer_json_object_close(wb);
563 }
428 - buffer_json_object_close(wb);
564 + buffer_json_object_close(wb); // custom_charts
565
430 - buffer_json_member_add_object(wb, "Namespace");
566 + buffer_json_member_add_object(wb, "charts");
567 {
432 - buffer_json_member_add_string(wb, "name", "Namespace");
433 - buffer_json_member_add_array(wb, "columns");
568 + // Data Collection Age chart
569 + buffer_json_member_add_object(wb, "Count");
570 {
435 - buffer_json_add_array_item_string(wb, "Namespace");
571 + buffer_json_member_add_string(wb, "type", "stacked-bar");
572 + buffer_json_member_add_array(wb, "columns");
573 + {
574 + buffer_json_add_array_item_string(wb, "Direction");
575 + }
576 + buffer_json_array_close(wb);
577 }
437 - buffer_json_array_close(wb);
438 - }
439 - buffer_json_object_close(wb);
578 + buffer_json_object_close(wb);
579
441 - buffer_json_member_add_object(wb, "Process");
442 - {
443 - buffer_json_member_add_string(wb, "name", "Process");
444 - buffer_json_member_add_array(wb, "columns");
580 + // Streaming Age chart
581 + buffer_json_member_add_object(wb, "Count");
582 {
446 - buffer_json_add_array_item_string(wb, "Process");
583 + buffer_json_member_add_string(wb, "type", "stacked-bar");
584 + buffer_json_member_add_array(wb, "columns");
585 + {
586 + buffer_json_add_array_item_string(wb, "Process");
587 + }
588 + buffer_json_array_close(wb);
589 }
448 - buffer_json_array_close(wb);
449 - }
450 - buffer_json_object_close(wb);
590 + buffer_json_object_close(wb);
591
452 - buffer_json_member_add_object(wb, "LocalIP");
453 - {
454 - buffer_json_member_add_string(wb, "name", "Local IP");
455 - buffer_json_member_add_array(wb, "columns");
592 + // DB Duration
593 + buffer_json_member_add_object(wb, "Count");
594 {
457 - buffer_json_add_array_item_string(wb, "LocalIP");
595 + buffer_json_member_add_string(wb, "type", "stacked-bar");
596 + buffer_json_member_add_array(wb, "columns");
597 + {
598 + buffer_json_add_array_item_string(wb, "Protocol");
599 + }
600 + buffer_json_array_close(wb);
601 }
459 - buffer_json_array_close(wb);
602 + buffer_json_object_close(wb);
603 }
461 - buffer_json_object_close(wb);
604 + buffer_json_object_close(wb); // charts
605
463 - buffer_json_member_add_object(wb, "LocalPort");
606 + buffer_json_member_add_array(wb, "default_charts");
607 {
465 - buffer_json_member_add_string(wb, "name", "Local Port");
466 - buffer_json_member_add_array(wb, "columns");
467 - {
468 - buffer_json_add_array_item_string(wb, "LocalPort");
469 - }
608 + buffer_json_add_array_item_array(wb);
609 + buffer_json_add_array_item_string(wb, "Count");
610 + buffer_json_add_array_item_string(wb, "Direction");
611 + buffer_json_array_close(wb);
612 +
613 + buffer_json_add_array_item_array(wb);
614 + buffer_json_add_array_item_string(wb, "Count");
615 + buffer_json_add_array_item_string(wb, "Process");
616 buffer_json_array_close(wb);
617 }
472 - buffer_json_object_close(wb);
618 + buffer_json_array_close(wb);
619
474 - buffer_json_member_add_object(wb, "RemoteIP");
620 + buffer_json_member_add_object(wb, "group_by");
621 {
476 - buffer_json_member_add_string(wb, "name", "Remote IP");
477 - buffer_json_member_add_array(wb, "columns");
622 + buffer_json_member_add_object(wb, "Direction");
623 {
479 - buffer_json_add_array_item_string(wb, "RemoteIP");
624 + buffer_json_member_add_string(wb, "name", "Direction");
625 + buffer_json_member_add_array(wb, "columns");
626 + {
627 + buffer_json_add_array_item_string(wb, "Direction");
628 + }
629 + buffer_json_array_close(wb);
630 }
481 - buffer_json_array_close(wb);
482 - }
483 - buffer_json_object_close(wb);
631 + buffer_json_object_close(wb);
632
485 - buffer_json_member_add_object(wb, "RemotePort");
486 - {
487 - buffer_json_member_add_string(wb, "name", "Remote Port");
488 - buffer_json_member_add_array(wb, "columns");
633 + buffer_json_member_add_object(wb, "Protocol");
634 {
490 - buffer_json_add_array_item_string(wb, "RemotePort");
635 + buffer_json_member_add_string(wb, "name", "Protocol");
636 + buffer_json_member_add_array(wb, "columns");
637 + {
638 + buffer_json_add_array_item_string(wb, "Protocol");
639 + }
640 + buffer_json_array_close(wb);
641 + }
642 + buffer_json_object_close(wb);
643 +
644 + buffer_json_member_add_object(wb, "Namespace");
645 + {
646 + buffer_json_member_add_string(wb, "name", "Namespace");
647 + buffer_json_member_add_array(wb, "columns");
648 + {
649 + buffer_json_add_array_item_string(wb, "Namespace");
650 + }
651 + buffer_json_array_close(wb);
652 + }
653 + buffer_json_object_close(wb);
654 +
655 + buffer_json_member_add_object(wb, "Process");
656 + {
657 + buffer_json_member_add_string(wb, "name", "Process");
658 + buffer_json_member_add_array(wb, "columns");
659 + {
660 + buffer_json_add_array_item_string(wb, "Process");
661 + }
662 + buffer_json_array_close(wb);
663 + }
664 + buffer_json_object_close(wb);
665 +
666 + if(!aggregated) {
667 + buffer_json_member_add_object(wb, "LocalIP");
668 + {
669 + buffer_json_member_add_string(wb, "name", "Local IP");
670 + buffer_json_member_add_array(wb, "columns");
671 + {
672 + buffer_json_add_array_item_string(wb, "LocalIP");
673 + }
674 + buffer_json_array_close(wb);
675 + }
676 + buffer_json_object_close(wb);
677 +
678 + buffer_json_member_add_object(wb, "LocalPort");
679 + {
680 + buffer_json_member_add_string(wb, "name", "Local Port");
681 + buffer_json_member_add_array(wb, "columns");
682 + {
683 + buffer_json_add_array_item_string(wb, "LocalPort");
684 + }
685 + buffer_json_array_close(wb);
686 + }
687 + buffer_json_object_close(wb);
688 +
689 + buffer_json_member_add_object(wb, "RemoteIP");
690 + {
691 + buffer_json_member_add_string(wb, "name", "Remote IP");
692 + buffer_json_member_add_array(wb, "columns");
693 + {
694 + buffer_json_add_array_item_string(wb, "RemoteIP");
695 + }
696 + buffer_json_array_close(wb);
697 + }
698 + buffer_json_object_close(wb);
699 +
700 + buffer_json_member_add_object(wb, "RemotePort");
701 + {
702 + buffer_json_member_add_string(wb, "name", "Remote Port");
703 + buffer_json_member_add_array(wb, "columns");
704 + {
705 + buffer_json_add_array_item_string(wb, "RemotePort");
706 + }
707 + buffer_json_array_close(wb);
708 + }
709 + buffer_json_object_close(wb);
710 }
492 - buffer_json_array_close(wb);
711 }
494 - buffer_json_object_close(wb);
712 + buffer_json_object_close(wb); // group_by
713 }
496 - buffer_json_object_close(wb); // group_by
497 -
714
499 - buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
715 +close_and_send:
716 + buffer_json_member_add_time_t(wb, "expires", now_s + 1);
717 buffer_json_finalize(wb);
718
719 netdata_mutex_lock(&stdout_mutex);
503 - pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", now_realtime_sec(), wb);
720 + pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", now_s + 1, wb);
721 netdata_mutex_unlock(&stdout_mutex);
722 }
723
@@ -519,6 +736,21 @@ int main(int argc __maybe_unused, char **argv __maybe_unused) {
736
737 // ----------------------------------------------------------------------------------------------------------------
738
739 + if(argc == 2 && strcmp(argv[1], "debug") == 0) {
740 + bool cancelled = false;
741 + usec_t stop_monotonic_ut = now_monotonic_usec() + 600 * USEC_PER_SEC;
742 + char buf[] = "network-connections sockets:aggregated";
743 + network_viewer_function("123", buf, &stop_monotonic_ut, &cancelled,
744 + NULL, HTTP_ACCESS_ALL, NULL, NULL);
745 +
746 + char buf2[] = "network-connections sockets:detailed";
747 + network_viewer_function("123", buf2, &stop_monotonic_ut, &cancelled,
748 + NULL, HTTP_ACCESS_ALL, NULL, NULL);
749 + exit(1);
750 + }
751 +
752 + // ----------------------------------------------------------------------------------------------------------------
753 +
754 fprintf(stdout, PLUGINSD_KEYWORD_FUNCTION " GLOBAL \"%s\" %d \"%s\" \"top\" "HTTP_ACCESS_FORMAT" %d\n",
755 NETWORK_CONNECTIONS_VIEWER_FUNCTION, 60,
756 NETWORK_CONNECTIONS_VIEWER_HELP,
collectors/plugins.d/local_listeners.c
+1 -1
@@ -40,7 +40,7 @@ static void print_local_listeners(LS_STATE *ls __maybe_unused, LOCAL_SOCKET *n,
40 ipv6_address_to_txt(&n->remote.ip.ipv6, remote_address);
41 }
42
43 - printf("%s|%s|%u|%s\n", protocol_name(n), local_address, n->local.port, n->cmdline ? n->cmdline : "");
43 + printf("%s|%s|%u|%s\n", protocol_name(n), local_address, n->local.port, string2str(n->cmdline));
44 }
45
46 static void print_local_listeners_debug(LS_STATE *ls __maybe_unused, LOCAL_SOCKET *n, void *data __maybe_unused) {
collectors/plugins.d/pluginsd_functions.c
+4 -1
@@ -13,7 +13,7 @@ static void inflight_functions_insert_callback(const DICTIONARY_ITEM *item, void
13 PARSER *parser = parser_ptr;
14
15 // leave this code as default, so that when the dictionary is destroyed this will be sent back to the caller
16 - pf->code = HTTP_RESP_GATEWAY_TIMEOUT;
16 + pf->code = HTTP_RESP_SERVICE_UNAVAILABLE;
17
18 const char *transaction = dictionary_acquired_item_name(item);
19
@@ -93,6 +93,9 @@ static void inflight_functions_delete_callback(const DICTIONARY_ITEM *item __may
93 buffer_strlen(pf->result_body_wb),
94 pf->sent_monotonic_ut - pf->started_monotonic_ut, now_realtime_usec() - pf->sent_monotonic_ut);
95
96 + if(pf->code == HTTP_RESP_SERVICE_UNAVAILABLE && !buffer_strlen(pf->result_body_wb))
97 + rrd_call_function_error(pf->result_body_wb, "The plugin exited while servicing this call.", pf->code);
98 +
99 pf->result.cb(pf->result_body_wb, pf->code, pf->result.data);
100
101 string_freez(pf->function);
collectors/proc.plugin/proc_diskstats.c
+1
@@ -1042,6 +1042,7 @@ static int diskstats_function_block_devices(BUFFER *wb, const char *function __m
1042 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
1043 buffer_json_member_add_string(wb, "type", "table");
1044 buffer_json_member_add_time_t(wb, "update_every", 1);
1045 + buffer_json_member_add_boolean(wb, "has_history", false);
1046 buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_DISKSTATS_HELP);
1047 buffer_json_member_add_array(wb, "data");
1048
collectors/proc.plugin/proc_net_dev.c
+1
@@ -482,6 +482,7 @@ int netdev_function_net_interfaces(BUFFER *wb, const char *function __maybe_unus
482 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
483 buffer_json_member_add_string(wb, "type", "table");
484 buffer_json_member_add_time_t(wb, "update_every", 1);
485 + buffer_json_member_add_boolean(wb, "has_history", false);
486 buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_NETDEV_HELP);
487 buffer_json_member_add_array(wb, "data");
488
src/database/rrdfunctions-inflight.c
-1
@@ -427,7 +427,6 @@ int rrd_function_run(RRDHOST *host, BUFFER *result_wb, int timeout_s,
427
428 code = rrd_functions_find_by_name(host, result_wb, sanitized_cmd, sanitized_cmd_length, &host_function_acquired);
429 if(code != HTTP_RESP_OK) {
430 - rrd_call_function_error(result_wb, "not found", code);
430
431 if(result_cb)
432 result_cb(result_wb, code, result_cb_data);
src/database/rrdfunctions-streaming.c
+1
@@ -14,6 +14,7 @@ int rrdhost_function_streaming(BUFFER *wb, const char *function __maybe_unused)
14 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
15 buffer_json_member_add_string(wb, "type", "table");
16 buffer_json_member_add_time_t(wb, "update_every", 1);
17 + buffer_json_member_add_boolean(wb, "has_history", false);
18 buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_STREAMING_HELP);
19 buffer_json_member_add_array(wb, "data");
20
src/libnetdata/aral/aral.c
+6
@@ -464,6 +464,12 @@ static inline ARAL_PAGE *aral_acquire_a_free_slot(ARAL *ar TRACE_ALLOCATIONS_FUN
464 return page;
465 }
466
467 +void *aral_callocz_internal(ARAL *ar TRACE_ALLOCATIONS_FUNCTION_DEFINITION_PARAMS) {
468 + void *r = aral_mallocz_internal(ar TRACE_ALLOCATIONS_FUNCTION_CALL_PARAMS);
469 + memset(r, 0, ar->config.requested_element_size);
470 + return r;
471 +}
472 +
473 void *aral_mallocz_internal(ARAL *ar TRACE_ALLOCATIONS_FUNCTION_DEFINITION_PARAMS) {
474 #ifdef FSANITIZE_ADDRESS
475 return mallocz(ar->config.requested_element_size);
src/libnetdata/aral/aral.h
+4
@@ -46,10 +46,12 @@ int aral_unittest(size_t elements);
46
47 #ifdef NETDATA_TRACE_ALLOCATIONS
48
49 +#define aral_callocz(ar) aral_callocz_internal(ar, __FILE__, __FUNCTION__, __LINE__)
50 #define aral_mallocz(ar) aral_mallocz_internal(ar, __FILE__, __FUNCTION__, __LINE__)
51 #define aral_freez(ar, ptr) aral_freez_internal(ar, ptr, __FILE__, __FUNCTION__, __LINE__)
52 #define aral_destroy(ar) aral_destroy_internal(ar, __FILE__, __FUNCTION__, __LINE__)
53
54 +void *aral_callocz_internal(ARAL *ar, const char *file, const char *function, size_t line);
55 void *aral_mallocz_internal(ARAL *ar, const char *file, const char *function, size_t line);
56 void aral_freez_internal(ARAL *ar, void *ptr, const char *file, const char *function, size_t line);
57 void aral_destroy_internal(ARAL *ar, const char *file, const char *function, size_t line);
@@ -57,9 +59,11 @@ void aral_destroy_internal(ARAL *ar, const char *file, const char *function, siz
59 #else // NETDATA_TRACE_ALLOCATIONS
60
61 #define aral_mallocz(ar) aral_mallocz_internal(ar)
62 +#define aral_callocz(ar) aral_callocz_internal(ar)
63 #define aral_freez(ar, ptr) aral_freez_internal(ar, ptr)
64 #define aral_destroy(ar) aral_destroy_internal(ar)
65
66 +void *aral_callocz_internal(ARAL *ar);
67 void *aral_mallocz_internal(ARAL *ar);
68 void aral_freez_internal(ARAL *ar, void *ptr);
69 void aral_destroy_internal(ARAL *ar);
src/libnetdata/buffer/buffer.c
+4 -2
@@ -341,8 +341,10 @@ __attribute__((constructor)) void initialize_ascii_maps(void) {
341 base64_value_from_ascii[i] = 255;
342 }
343
344 - for(size_t i = 0; i < 16 ; i++)
345 - hex_value_from_ascii[(int)hex_digits[i]] = i;
344 + for(size_t i = 0; i < 16 ; i++) {
345 + hex_value_from_ascii[(int)toupper(hex_digits[i])] = i;
346 + hex_value_from_ascii[(int)tolower(hex_digits[i])] = i;
347 + }
348
349 for(size_t i = 0; i < 64 ; i++)
350 base64_value_from_ascii[(int)base64_digits[i]] = i;
src/libnetdata/inlined.h
+17 -1
@@ -204,12 +204,28 @@ static inline long long str2ll(const char *s, char **endptr) {
204 }
205 }
206
207 +static inline uint32_t str2uint32_hex(const char *src, char **endptr) {
208 + uint32_t num = 0;
209 + const unsigned char *s = (const unsigned char *)src;
210 + unsigned char c;
211 +
212 + while ((c = hex_value_from_ascii[(uint8_t)*s]) != 255) {
213 + num = (num << 4) | c;
214 + s++;
215 + }
216 +
217 + if(endptr)
218 + *endptr = (char *)s;
219 +
220 + return num;
221 +}
222 +
223 static inline uint64_t str2uint64_hex(const char *src, char **endptr) {
224 uint64_t num = 0;
225 const unsigned char *s = (const unsigned char *)src;
226 unsigned char c;
227
212 - while ((c = hex_value_from_ascii[toupper(*s)]) != 255) {
228 + while ((c = hex_value_from_ascii[(uint8_t)*s]) != 255) {
229 num = (num << 4) | c;
230 s++;
231 }
src/libnetdata/maps/local-sockets.h
+97 -49
@@ -104,6 +104,9 @@ typedef struct local_socket_state {
104 uint16_t tmp_protocol;
105 #endif
106
107 + ARAL *local_socket_aral;
108 + ARAL *pid_socket_aral;
109 +
110 uint64_t proc_self_net_ns_inode;
111
112 SIMPLE_HASHTABLE_NET_NS ns_hashtable;
@@ -162,7 +165,7 @@ static inline void ipv6_to_in6_addr(const char *ipv6_str, struct in6_addr *d) {
165 for (size_t k = 0; k < 4; ++k) {
166 memcpy(buf, ipv6_str + (k * 8), 8);
167 buf[sizeof(buf) - 1] = '\0';
165 - d->s6_addr32[k] = strtoul(buf, NULL, 16);
168 + d->s6_addr32[k] = str2uint32_hex(buf, NULL);
169 }
170 }
171
@@ -185,13 +188,17 @@ typedef struct local_socket {
188 uid_t uid;
189
190 char comm[TASK_COMM_LEN];
188 - char *cmdline;
191 + STRING *cmdline;
192
193 struct local_port local_port_key;
194
195 XXH64_hash_t local_ip_hash;
196 XXH64_hash_t remote_ip_hash;
197 XXH64_hash_t local_port_hash;
198 +
199 +#ifdef LOCAL_SOCKETS_EXTENDED_MEMBERS
200 + LOCAL_SOCKETS_EXTENDED_MEMBERS
201 +#endif
202 } LOCAL_SOCKET;
203
204 // --------------------------------------------------------------------------------------------------------------------
@@ -393,7 +400,7 @@ static inline bool local_sockets_find_all_sockets_in_proc(LS_STATE *ls, const ch
400 }
401
402 if(!ps)
396 - ps = callocz(1, sizeof(*ps));
403 + ps = aral_callocz(ls->pid_socket_aral);
404
405 ps->inode = inode;
406 ps->pid = pid;
@@ -559,7 +566,7 @@ static inline bool local_sockets_add_socket(LS_STATE *ls, LOCAL_SOCKET *tmp) {
566 return false;
567 }
568
562 - n = (LOCAL_SOCKET *)callocz(1, sizeof(LOCAL_SOCKET));
569 + n = aral_mallocz(ls->local_socket_aral);
570 *n = *tmp; // copy all contents
571
572 // fix the key
@@ -584,7 +591,8 @@ static inline bool local_sockets_add_socket(LS_STATE *ls, LOCAL_SOCKET *tmp) {
591 n->uid = ps->uid;
592
593 if(ps->cmdline)
587 - n->cmdline = strdupz(ps->cmdline);
594 + n->cmdline = string_strdupz(ps->cmdline);
595 +
596 strncpyz(n->comm, ps->comm, sizeof(n->comm) - 1);
597 }
598
@@ -731,18 +739,27 @@ static inline bool local_sockets_netlink_get_sockets(LS_STATE *ls, uint16_t fami
739 #endif // HAVE_LIBMNL
740
741 static inline bool local_sockets_read_proc_net_x(LS_STATE *ls, const char *filename, uint16_t family, uint16_t protocol) {
742 + static bool is_space[256] = {
743 + [':'] = true,
744 + [' '] = true,
745 + };
746 +
747 if(family != AF_INET && family != AF_INET6)
748 return false;
749
737 - FILE *fp;
738 - char *line = NULL;
739 - size_t len = 0;
740 - ssize_t read;
741 -
742 - fp = fopen(filename, "r");
750 + FILE *fp = fopen(filename, "r");
751 if (fp == NULL)
752 return false;
753
754 + char *line = malloc(1024); // no mallocz() here because getline() may resize
755 + if(!line) {
756 + fclose(fp);
757 + return false;
758 + }
759 +
760 + size_t len = 1024;
761 + ssize_t read;
762 +
763 ssize_t min_line_length = (family == AF_INET) ? 105 : 155;
764 size_t counter = 0;
765
@@ -755,49 +772,60 @@ static inline bool local_sockets_read_proc_net_x(LS_STATE *ls, const char *filen
772 continue;
773 }
774
758 - unsigned int local_address, local_port, state, remote_address, remote_port;
759 - uint64_t inode = 0;
760 - char local_address6[33], remote_address6[33];
761 -
762 - if(family == AF_INET) {
763 - if (sscanf(line, "%*d: %X:%X %X:%X %X %*X:%*X %*X:%*X %*X %*d %*d %"PRIu64,
764 - &local_address, &local_port, &remote_address, &remote_port, &state, &inode) != 6) {
765 - local_sockets_log(ls, "cannot parse ipv4 line No %zu of filename '%s': %s", counter, filename, line);
766 - continue;
767 - }
768 - }
769 - else if(family == AF_INET6) {
770 - if(sscanf(line, "%*d: %32[0-9A-Fa-f]:%X %32[0-9A-Fa-f]:%X %X %*X:%*X %*X:%*X %*X %*d %*d %"PRIu64,
771 - local_address6, &local_port, remote_address6, &remote_port, &state, &inode) != 6) {
772 - local_sockets_log(ls, "cannot parse ipv6 line No %zu of filename '%s': %s", counter, filename, line);
773 - continue;
774 - }
775 - }
776 -
775 LOCAL_SOCKET n = {
778 - .inode = inode,
776 .direction = SOCKET_DIRECTION_NONE,
780 - .state = (int)state,
777 .local = {
778 .family = family,
779 .protocol = protocol,
784 - .port = local_port,
780 },
781 .remote = {
782 .family = family,
783 .protocol = protocol,
789 - .port = remote_port,
784 },
785 .uid = UID_UNSET,
786 };
787
788 + char *words[32];
789 + size_t num_words = quoted_strings_splitter(line, words, 32, is_space);
790 + // char *sl_txt = get_word(words, num_words, 0);
791 + char *local_ip_txt = get_word(words, num_words, 1);
792 + char *local_port_txt = get_word(words, num_words, 2);
793 + char *remote_ip_txt = get_word(words, num_words, 3);
794 + char *remote_port_txt = get_word(words, num_words, 4);
795 + char *state_txt = get_word(words, num_words, 5);
796 + char *tx_queue_txt = get_word(words, num_words, 6);
797 + char *rx_queue_txt = get_word(words, num_words, 7);
798 + char *tr_txt = get_word(words, num_words, 8);
799 + char *tm_when_txt = get_word(words, num_words, 9);
800 + char *retrans_txt = get_word(words, num_words, 10);
801 + char *uid_txt = get_word(words, num_words, 11);
802 + // char *timeout_txt = get_word(words, num_words, 12);
803 + char *inode_txt = get_word(words, num_words, 13);
804 +
805 + if(!local_ip_txt || !local_port_txt || !remote_ip_txt || !remote_port_txt || !state_txt ||
806 + !tx_queue_txt || !rx_queue_txt || !tr_txt || !tm_when_txt || !retrans_txt || !uid_txt || !inode_txt) {
807 + local_sockets_log(ls, "cannot parse ipv4 line No %zu of filename '%s'", counter, filename);
808 + continue;
809 + }
810 +
811 + n.local.port = str2uint32_hex(local_port_txt, NULL);
812 + n.remote.port = str2uint32_hex(remote_port_txt, NULL);
813 + n.state = str2uint32_hex(state_txt, NULL);
814 + n.wqueue = str2uint32_hex(tx_queue_txt, NULL);
815 + n.rqueue = str2uint32_hex(rx_queue_txt, NULL);
816 + n.timer = str2uint32_hex(tr_txt, NULL);
817 + n.expires = str2uint32_hex(tm_when_txt, NULL);
818 + n.retransmits = str2uint32_hex(retrans_txt, NULL);
819 + n.uid = str2uint32_t(uid_txt, NULL);
820 + n.inode = str2uint64_t(inode_txt, NULL);
821 +
822 if(family == AF_INET) {
795 - n.local.ip.ipv4 = local_address;
796 - n.remote.ip.ipv4 = remote_address;
823 + n.local.ip.ipv4 = str2uint32_hex(local_ip_txt, NULL);
824 + n.remote.ip.ipv4 = str2uint32_hex(remote_ip_txt, NULL);
825 }
826 else if(family == AF_INET6) {
799 - ipv6_to_in6_addr(local_address6, &n.local.ip.ipv6);
800 - ipv6_to_in6_addr(remote_address6, &n.remote.ip.ipv6);
827 + ipv6_to_in6_addr(local_ip_txt, &n.local.ip.ipv6);
828 + ipv6_to_in6_addr(remote_ip_txt, &n.remote.ip.ipv6);
829 }
830
831 local_sockets_add_socket(ls, &n);
@@ -806,7 +834,7 @@ static inline bool local_sockets_read_proc_net_x(LS_STATE *ls, const char *filen
834 fclose(fp);
835
836 if (line)
809 - freez(line);
837 + free(line); // no freez() here because getline() may resize
838
839 return true;
840 }
@@ -881,6 +909,20 @@ static inline void local_sockets_init(LS_STATE *ls) {
909 simple_hashtable_init_LOCAL_SOCKET(&ls->sockets_hashtable, 65535);
910 simple_hashtable_init_LOCAL_IP(&ls->local_ips_hashtable, 4096);
911 simple_hashtable_init_LISTENING_PORT(&ls->listening_ports_hashtable, 4096);
912 +
913 + ls->local_socket_aral = aral_create(
914 + "local-sockets",
915 + sizeof(LOCAL_SOCKET),
916 + 65536,
917 + 65536,
918 + NULL, NULL, NULL, false, true);
919 +
920 + ls->pid_socket_aral = aral_create(
921 + "pid-sockets",
922 + sizeof(struct pid_socket),
923 + 65536,
924 + 65536,
925 + NULL, NULL, NULL, false, true);
926 }
927
928 static inline void local_sockets_cleanup(LS_STATE *ls) {
@@ -891,8 +933,8 @@ static inline void local_sockets_cleanup(LS_STATE *ls) {
933 LOCAL_SOCKET *n = SIMPLE_HASHTABLE_SLOT_DATA(sl);
934 if(!n) continue;
935
894 - freez(n->cmdline);
895 - freez(n);
936 + string_freez(n->cmdline);
937 + aral_freez(ls->local_socket_aral, n);
938 }
939
940 // free the pid_socket hashtable data
@@ -903,7 +945,7 @@ static inline void local_sockets_cleanup(LS_STATE *ls) {
945 if(!ps) continue;
946
947 freez(ps->cmdline);
906 - freez(ps);
948 + aral_freez(ls->pid_socket_aral, ps);
949 }
950
951 // free the hashtable
@@ -912,6 +954,9 @@ static inline void local_sockets_cleanup(LS_STATE *ls) {
954 simple_hashtable_destroy_LISTENING_PORT(&ls->listening_ports_hashtable);
955 simple_hashtable_destroy_LOCAL_IP(&ls->local_ips_hashtable);
956 simple_hashtable_destroy_LOCAL_SOCKET(&ls->sockets_hashtable);
957 +
958 + aral_destroy(ls->local_socket_aral);
959 + aral_destroy(ls->pid_socket_aral);
960 }
961
962 // --------------------------------------------------------------------------------------------------------------------
@@ -982,12 +1027,12 @@ static inline void local_sockets_send_to_parent(struct local_socket_state *ls __
1027 if(write(fd, n, sizeof(*n)) != sizeof(*n))
1028 local_sockets_log(ls, "failed to write local socket to pipe");
1029
985 - size_t len = n->cmdline ? strlen(n->cmdline) + 1 : 0;
1030 + size_t len = n->cmdline ? string_strlen(n->cmdline) + 1 : 0;
1031 if(write(fd, &len, sizeof(len)) != sizeof(len))
1032 local_sockets_log(ls, "failed to write cmdline length to pipe");
1033
1034 if(len)
990 - if(write(fd, n->cmdline, len) != (ssize_t)len)
1035 + if(write(fd, string2str(n->cmdline), len) != (ssize_t)len)
1036 local_sockets_log(ls, "failed to write cmdline to pipe");
1037 }
1038
@@ -1087,9 +1132,13 @@ static inline bool local_sockets_get_namespace_sockets(LS_STATE *ls, struct pid_
1132 local_sockets_log(ls, "failed to read cmdline length from pipe");
1133
1134 if(len) {
1090 - buf.cmdline = mallocz(len);
1091 - if(read(pipefd[0], buf.cmdline, len) != (ssize_t)len)
1135 + char cmdline[len + 1];
1136 + if(read(pipefd[0], cmdline, len) != (ssize_t)len)
1137 local_sockets_log(ls, "failed to read cmdline from pipe");
1138 + else {
1139 + cmdline[len] = '\0';
1140 + buf.cmdline = string_strdupz(cmdline);
1141 + }
1142 }
1143 else
1144 buf.cmdline = NULL;
@@ -1107,8 +1156,7 @@ static inline bool local_sockets_get_namespace_sockets(LS_STATE *ls, struct pid_
1156 SIMPLE_HASHTABLE_SLOT_LOCAL_SOCKET *sl = simple_hashtable_get_slot_LOCAL_SOCKET(&ls->sockets_hashtable, buf.inode, &buf, true);
1157 LOCAL_SOCKET *n = SIMPLE_HASHTABLE_SLOT_DATA(sl);
1158 if(n) {
1110 - if(buf.cmdline)
1111 - freez(buf.cmdline);
1159 + string_freez(buf.cmdline);
1160
1161 // local_sockets_log(ls,
1162 // "ns inode %" PRIu64" (comm: '%s', pid: %u, ns: %"PRIu64") already exists in hashtable (comm: '%s', pid: %u, ns: %"PRIu64") - ignoring duplicate",
@@ -1116,7 +1164,7 @@ static inline bool local_sockets_get_namespace_sockets(LS_STATE *ls, struct pid_
1164 continue;
1165 }
1166 else {
1119 - n = mallocz(sizeof(*n));
1167 + n = aral_mallocz(ls->local_socket_aral);
1168 memcpy(n, &buf, sizeof(*n));
1169 simple_hashtable_set_slot_LOCAL_SOCKET(&ls->sockets_hashtable, sl, n->inode, n);
1170
src/libnetdata/query_progress/progress.c
+1
@@ -408,6 +408,7 @@ int progress_function_result(BUFFER *wb, const char *hostname) {
408 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
409 buffer_json_member_add_string(wb, "type", "table");
410 buffer_json_member_add_time_t(wb, "update_every", 1);
411 + buffer_json_member_add_boolean(wb, "has_history", false);
412 buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_PROGRESS_HELP);
413 buffer_json_member_add_array(wb, "data");
414
src/libnetdata/socket/socket.c
+1 -1
@@ -1387,7 +1387,7 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien
1387 struct sockaddr_storage sadr;
1388 socklen_t addrlen = sizeof(sadr);
1389
1390 - int nfd = accept4(fd, (struct sockaddr *)&sadr, &addrlen, flags);
1390 + int nfd = accept4(fd, (struct sockaddr *)&sadr, &addrlen, flags | SOCK_CLOEXEC);
1391 if (likely(nfd >= 0)) {
1392 if (getnameinfo((struct sockaddr *)&sadr, addrlen, client_ip, (socklen_t)ipsize,
1393 client_port, (socklen_t)portsize, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {