1
// SPDX-License-Identifier: GPL-3.0-or-later
2
3
-#include "rrdpush.h"
4
-#include "common.h"
5
-#include "aclk/https_client.h"
6
-
7
-#define WORKER_SENDER_JOB_CONNECT 0
8
-#define WORKER_SENDER_JOB_PIPE_READ 1
9
-#define WORKER_SENDER_JOB_SOCKET_RECEIVE 2
10
-#define WORKER_SENDER_JOB_EXECUTE 3
11
-#define WORKER_SENDER_JOB_SOCKET_SEND 4
12
-#define WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE 5
13
-#define WORKER_SENDER_JOB_DISCONNECT_OVERFLOW 6
14
-#define WORKER_SENDER_JOB_DISCONNECT_TIMEOUT 7
15
-#define WORKER_SENDER_JOB_DISCONNECT_POLL_ERROR 8
16
-#define WORKER_SENDER_JOB_DISCONNECT_SOCKET_ERROR 9
17
-#define WORKER_SENDER_JOB_DISCONNECT_SSL_ERROR 10
18
-#define WORKER_SENDER_JOB_DISCONNECT_PARENT_CLOSED 11
19
-#define WORKER_SENDER_JOB_DISCONNECT_RECEIVE_ERROR 12
20
-#define WORKER_SENDER_JOB_DISCONNECT_SEND_ERROR 13
21
-#define WORKER_SENDER_JOB_DISCONNECT_NO_COMPRESSION 14
22
-#define WORKER_SENDER_JOB_BUFFER_RATIO 15
23
-#define WORKER_SENDER_JOB_BYTES_RECEIVED 16
24
-#define WORKER_SENDER_JOB_BYTES_SENT 17
25
-#define WORKER_SENDER_JOB_BYTES_COMPRESSED 18
26
-#define WORKER_SENDER_JOB_BYTES_UNCOMPRESSED 19
27
-#define WORKER_SENDER_JOB_BYTES_COMPRESSION_RATIO 20
28
-#define WORKER_SENDER_JOB_REPLAY_REQUEST 21
29
-#define WORKER_SENDER_JOB_FUNCTION_REQUEST 22
30
-#define WORKER_SENDER_JOB_REPLAY_DICT_SIZE 23
31
-#define WORKER_SENDER_JOB_DISCONNECT_CANT_UPGRADE_CONNECTION 24
32
-
33
-#if WORKER_UTILIZATION_MAX_JOB_TYPES < 25
34
-#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 25
35
-#endif
36
-
37
-extern struct config stream_config;
38
-extern char *netdata_ssl_ca_path;
39
-extern char *netdata_ssl_ca_file;
40
-
41
-static __thread BUFFER *sender_thread_buffer = NULL;
42
-static __thread bool sender_thread_buffer_used = false;
43
-static __thread time_t sender_thread_buffer_last_reset_s = 0;
44
-
45
-void sender_thread_buffer_free(void) {
46
- buffer_free(sender_thread_buffer);
47
- sender_thread_buffer = NULL;
48
- sender_thread_buffer_used = false;
49
-}
50
-
51
-// Collector thread starting a transmission
52
-BUFFER *sender_start(struct sender_state *s) {
53
- if(unlikely(sender_thread_buffer_used))
54
- fatal("STREAMING: thread buffer is used multiple times concurrently.");
55
-
56
- if(unlikely(rrdpush_sender_last_buffer_recreate_get(s) > sender_thread_buffer_last_reset_s)) {
57
- if(unlikely(sender_thread_buffer && sender_thread_buffer->size > THREAD_BUFFER_INITIAL_SIZE)) {
58
- buffer_free(sender_thread_buffer);
59
- sender_thread_buffer = NULL;
60
- }
61
- }
62
-
63
- if(unlikely(!sender_thread_buffer)) {
64
- sender_thread_buffer = buffer_create(THREAD_BUFFER_INITIAL_SIZE, &netdata_buffers_statistics.buffers_streaming);
65
- sender_thread_buffer_last_reset_s = rrdpush_sender_last_buffer_recreate_get(s);
66
- }
67
-
68
- sender_thread_buffer_used = true;
69
- buffer_flush(sender_thread_buffer);
70
- return sender_thread_buffer;
71
-}
72
-
73
-static inline void rrdpush_sender_thread_close_socket(RRDHOST *host);
74
-
75
-#define SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE 3
76
-
77
-// Collector thread finishing a transmission
78
-void sender_commit(struct sender_state *s, BUFFER *wb, STREAM_TRAFFIC_TYPE type) {
79
-
80
- if(unlikely(wb != sender_thread_buffer))
81
- fatal("STREAMING: sender is trying to commit a buffer that is not this thread's buffer.");
82
-
83
- if(unlikely(!sender_thread_buffer_used))
84
- fatal("STREAMING: sender is committing a buffer twice.");
85
-
86
- sender_thread_buffer_used = false;
87
-
88
- char *src = (char *)buffer_tostring(wb);
89
- size_t src_len = buffer_strlen(wb);
90
-
91
- if(unlikely(!src || !src_len))
92
- return;
93
-
94
- sender_lock(s);
95
-
96
-#ifdef NETDATA_LOG_STREAM_SENDER
97
- if(type == STREAM_TRAFFIC_TYPE_METADATA) {
98
- if(!s->stream_log_fp) {
99
- char filename[FILENAME_MAX + 1];
100
- snprintfz(filename, FILENAME_MAX, "/tmp/stream-sender-%s.txt", s->host ? rrdhost_hostname(s->host) : "unknown");
101
-
102
- s->stream_log_fp = fopen(filename, "w");
103
- }
104
-
105
- fprintf(s->stream_log_fp, "\n--- SEND MESSAGE START: %s ----\n"
106
- "%s"
107
- "--- SEND MESSAGE END ----------------------------------------\n"
108
- , rrdhost_hostname(s->host), src
109
- );
110
- }
111
-#endif
112
-
113
- if(unlikely(s->buffer->max_size < (src_len + 1) * SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE)) {
114
- netdata_log_info("STREAM %s [send to %s]: max buffer size of %zu is too small for a data message of size %zu. Increasing the max buffer size to %d times the max data message size.",
115
- rrdhost_hostname(s->host), s->connected_to, s->buffer->max_size, buffer_strlen(wb) + 1, SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE);
116
-
117
- s->buffer->max_size = (src_len + 1) * SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE;
118
- }
119
-
120
- if (s->compressor.initialized) {
121
- while(src_len) {
122
- size_t size_to_compress = src_len;
123
-
124
- if(unlikely(size_to_compress > COMPRESSION_MAX_MSG_SIZE)) {
125
- if (stream_has_capability(s, STREAM_CAP_BINARY))
126
- size_to_compress = COMPRESSION_MAX_MSG_SIZE;
127
- else {
128
- if (size_to_compress > COMPRESSION_MAX_MSG_SIZE) {
129
- // we need to find the last newline
130
- // so that the decompressor will have a whole line to work with
131
-
132
- const char *t = &src[COMPRESSION_MAX_MSG_SIZE];
133
- while (--t >= src)
134
- if (unlikely(*t == '\n'))
135
- break;
136
-
137
- if (t <= src) {
138
- size_to_compress = COMPRESSION_MAX_MSG_SIZE;
139
- } else
140
- size_to_compress = t - src + 1;
141
- }
142
- }
143
- }
144
-
145
- const char *dst;
146
- size_t dst_len = rrdpush_compress(&s->compressor, src, size_to_compress, &dst);
147
- if (!dst_len) {
148
- netdata_log_error("STREAM %s [send to %s]: COMPRESSION failed. Resetting compressor and re-trying",
149
- rrdhost_hostname(s->host), s->connected_to);
150
-
151
- rrdpush_compression_initialize(s);
152
- dst_len = rrdpush_compress(&s->compressor, src, size_to_compress, &dst);
153
- if(!dst_len) {
154
- netdata_log_error("STREAM %s [send to %s]: COMPRESSION failed again. Deactivating compression",
155
- rrdhost_hostname(s->host), s->connected_to);
156
-
157
- worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_NO_COMPRESSION);
158
- rrdpush_compression_deactivate(s);
159
- rrdpush_sender_thread_close_socket(s->host);
160
- sender_unlock(s);
161
- return;
162
- }
163
- }
164
-
165
- rrdpush_signature_t signature = rrdpush_compress_encode_signature(dst_len);
166
-
167
-#ifdef NETDATA_INTERNAL_CHECKS
168
- // check if reversing the signature provides the same length
169
- size_t decoded_dst_len = rrdpush_decompress_decode_signature((const char *)&signature, sizeof(signature));
170
- if(decoded_dst_len != dst_len)
171
- fatal("RRDPUSH COMPRESSION: invalid signature, original payload %zu bytes, "
172
- "compressed payload length %zu bytes, but signature says payload is %zu bytes",
173
- size_to_compress, dst_len, decoded_dst_len);
174
-#endif
175
-
176
- if(cbuffer_add_unsafe(s->buffer, (const char *)&signature, sizeof(signature)))
177
- s->flags |= SENDER_FLAG_OVERFLOW;
178
- else {
179
- if(cbuffer_add_unsafe(s->buffer, dst, dst_len))
180
- s->flags |= SENDER_FLAG_OVERFLOW;
181
- else
182
- s->sent_bytes_on_this_connection_per_type[type] += dst_len + sizeof(signature);
183
- }
184
-
185
- src = src + size_to_compress;
186
- src_len -= size_to_compress;
187
- }
188
- }
189
- else if(cbuffer_add_unsafe(s->buffer, src, src_len))
190
- s->flags |= SENDER_FLAG_OVERFLOW;
191
- else
192
- s->sent_bytes_on_this_connection_per_type[type] += src_len;
193
-
194
- replication_recalculate_buffer_used_ratio_unsafe(s);
195
-
196
- bool signal_sender = false;
197
- if(!rrdpush_sender_pipe_has_pending_data(s)) {
198
- rrdpush_sender_pipe_set_pending_data(s);
199
- signal_sender = true;
200
- }
201
-
202
- sender_unlock(s);
203
-
204
- if(signal_sender && (!stream_has_capability(s, STREAM_CAP_INTERPOLATED) || type != STREAM_TRAFFIC_TYPE_DATA))
205
- rrdpush_signal_sender_to_wake_up(s);
206
-}
3
+#include "sender_internals.h"
4
5
static inline void rrdpush_sender_add_host_variable_to_buffer(BUFFER *wb, const RRDVAR_ACQUIRED *rva) {
6
buffer_sprintf(
121
rrdpush_sender_replicating_charts_zero(host->sender);
122
}
123
327
-static void rrdpush_sender_on_connect(RRDHOST *host) {
124
+void rrdpush_sender_on_connect(RRDHOST *host) {
125
rrdpush_sender_cbuffer_flush(host);
126
rrdpush_sender_charts_and_replication_reset(host);
127
}
128
332
-static void rrdpush_sender_after_connect(RRDHOST *host) {
129
+void rrdpush_sender_after_connect(RRDHOST *host) {
130
rrdpush_sender_thread_send_custom_host_variables(host);
131
}
132
336
-static inline void rrdpush_sender_thread_close_socket(RRDHOST *host) {
337
- netdata_ssl_close(&host->sender->ssl);
133
+void rrdpush_sender_disconnect_and_cleanup(RRDHOST *host) {
134
+ rrdhost_flag_clear(host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED | RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
135
339
- if(host->sender->rrdpush_sender_socket != -1) {
340
- close(host->sender->rrdpush_sender_socket);
341
- host->sender->rrdpush_sender_socket = -1;
342
- }
136
+ rrdpush_sender_thread_close_socket(host);
137
344
- rrdhost_flag_clear(host, RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
345
- rrdhost_flag_clear(host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED);
138
+ // we have been connected to this parent - let's cleanup
139
140
// do not flush the circular buffer here
348
- // this function is called sometimes with the mutex lock, sometimes without the lock
141
+ // this function is called sometimes with the sender lock, sometimes without the lock
142
+
143
rrdpush_sender_charts_and_replication_reset(host);
144
145
// clear the parent's claim id
352
- rrdpush_sender_clear_child_claim_id(host);
146
+ rrdpush_sender_clear_parent_claim_id(host);
147
rrdpush_receiver_send_node_and_claim_id_to_child(host);
354
-}
355
-
356
-void rrdpush_encode_variable(stream_encoded_t *se, RRDHOST *host) {
357
- se->os_name = (host->system_info->host_os_name)?url_encode(host->system_info->host_os_name):strdupz("");
358
- se->os_id = (host->system_info->host_os_id)?url_encode(host->system_info->host_os_id):strdupz("");
359
- se->os_version = (host->system_info->host_os_version)?url_encode(host->system_info->host_os_version):strdupz("");
360
- se->kernel_name = (host->system_info->kernel_name)?url_encode(host->system_info->kernel_name):strdupz("");
361
- se->kernel_version = (host->system_info->kernel_version)?url_encode(host->system_info->kernel_version):strdupz("");
362
-}
363
-
364
-void rrdpush_clean_encoded(stream_encoded_t *se) {
365
- if (se->os_name) {
366
- freez(se->os_name);
367
- se->os_name = NULL;
368
- }
369
-
370
- if (se->os_id) {
371
- freez(se->os_id);
372
- se->os_id = NULL;
373
- }
374
-
375
- if (se->os_version) {
376
- freez(se->os_version);
377
- se->os_version = NULL;
378
- }
379
-
380
- if (se->kernel_name) {
381
- freez(se->kernel_name);
382
- se->kernel_name = NULL;
383
- }
384
-
385
- if (se->kernel_version) {
386
- freez(se->kernel_version);
387
- se->kernel_version = NULL;
388
- }
389
-}
390
-
391
-struct {
392
- const char *response;
393
- const char *status;
394
- size_t length;
395
- int32_t version;
396
- bool dynamic;
397
- const char *error;
398
- int worker_job_id;
399
- int postpone_reconnect_seconds;
400
- ND_LOG_FIELD_PRIORITY priority;
401
-} stream_responses[] = {
402
- {
403
- .response = START_STREAMING_PROMPT_VN,
404
- .length = sizeof(START_STREAMING_PROMPT_VN) - 1,
405
- .status = RRDPUSH_STATUS_CONNECTED,
406
- .version = STREAM_HANDSHAKE_OK_V3, // and above
407
- .dynamic = true, // dynamic = we will parse the version / capabilities
408
- .error = NULL,
409
- .worker_job_id = 0,
410
- .postpone_reconnect_seconds = 0,
411
- .priority = NDLP_INFO,
412
- },
413
- {
414
- .response = START_STREAMING_PROMPT_V2,
415
- .length = sizeof(START_STREAMING_PROMPT_V2) - 1,
416
- .status = RRDPUSH_STATUS_CONNECTED,
417
- .version = STREAM_HANDSHAKE_OK_V2,
418
- .dynamic = false,
419
- .error = NULL,
420
- .worker_job_id = 0,
421
- .postpone_reconnect_seconds = 0,
422
- .priority = NDLP_INFO,
423
- },
424
- {
425
- .response = START_STREAMING_PROMPT_V1,
426
- .length = sizeof(START_STREAMING_PROMPT_V1) - 1,
427
- .status = RRDPUSH_STATUS_CONNECTED,
428
- .version = STREAM_HANDSHAKE_OK_V1,
429
- .dynamic = false,
430
- .error = NULL,
431
- .worker_job_id = 0,
432
- .postpone_reconnect_seconds = 0,
433
- .priority = NDLP_INFO,
434
- },
435
- {
436
- .response = START_STREAMING_ERROR_SAME_LOCALHOST,
437
- .length = sizeof(START_STREAMING_ERROR_SAME_LOCALHOST) - 1,
438
- .status = RRDPUSH_STATUS_LOCALHOST,
439
- .version = STREAM_HANDSHAKE_ERROR_LOCALHOST,
440
- .dynamic = false,
441
- .error = "remote server rejected this stream, the host we are trying to stream is its localhost",
442
- .worker_job_id = WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE,
443
- .postpone_reconnect_seconds = 60 * 60, // the IP may change, try it every hour
444
- .priority = NDLP_DEBUG,
445
- },
446
- {
447
- .response = START_STREAMING_ERROR_ALREADY_STREAMING,
448
- .length = sizeof(START_STREAMING_ERROR_ALREADY_STREAMING) - 1,
449
- .status = RRDPUSH_STATUS_ALREADY_CONNECTED,
450
- .version = STREAM_HANDSHAKE_ERROR_ALREADY_CONNECTED,
451
- .dynamic = false,
452
- .error = "remote server rejected this stream, the host we are trying to stream is already streamed to it",
453
- .worker_job_id = WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE,
454
- .postpone_reconnect_seconds = 2 * 60, // 2 minutes
455
- .priority = NDLP_DEBUG,
456
- },
457
- {
458
- .response = START_STREAMING_ERROR_NOT_PERMITTED,
459
- .length = sizeof(START_STREAMING_ERROR_NOT_PERMITTED) - 1,
460
- .status = RRDPUSH_STATUS_PERMISSION_DENIED,
461
- .version = STREAM_HANDSHAKE_ERROR_DENIED,
462
- .dynamic = false,
463
- .error = "remote server denied access, probably we don't have the right API key?",
464
- .worker_job_id = WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE,
465
- .postpone_reconnect_seconds = 1 * 60, // 1 minute
466
- .priority = NDLP_ERR,
467
- },
468
- {
469
- .response = START_STREAMING_ERROR_BUSY_TRY_LATER,
470
- .length = sizeof(START_STREAMING_ERROR_BUSY_TRY_LATER) - 1,
471
- .status = RRDPUSH_STATUS_RATE_LIMIT,
472
- .version = STREAM_HANDSHAKE_BUSY_TRY_LATER,
473
- .dynamic = false,
474
- .error = "remote server is currently busy, we should try later",
475
- .worker_job_id = WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE,
476
- .postpone_reconnect_seconds = 2 * 60, // 2 minutes
477
- .priority = NDLP_NOTICE,
478
- },
479
- {
480
- .response = START_STREAMING_ERROR_INTERNAL_ERROR,
481
- .length = sizeof(START_STREAMING_ERROR_INTERNAL_ERROR) - 1,
482
- .status = RRDPUSH_STATUS_INTERNAL_SERVER_ERROR,
483
- .version = STREAM_HANDSHAKE_INTERNAL_ERROR,
484
- .dynamic = false,
485
- .error = "remote server is encountered an internal error, we should try later",
486
- .worker_job_id = WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE,
487
- .postpone_reconnect_seconds = 5 * 60, // 5 minutes
488
- .priority = NDLP_CRIT,
489
- },
490
- {
491
- .response = START_STREAMING_ERROR_INITIALIZATION,
492
- .length = sizeof(START_STREAMING_ERROR_INITIALIZATION) - 1,
493
- .status = RRDPUSH_STATUS_INITIALIZATION_IN_PROGRESS,
494
- .version = STREAM_HANDSHAKE_INITIALIZATION,
495
- .dynamic = false,
496
- .error = "remote server is initializing, we should try later",
497
- .worker_job_id = WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE,
498
- .postpone_reconnect_seconds = 2 * 60, // 2 minute
499
- .priority = NDLP_NOTICE,
500
- },
501
-
502
- // terminator
503
- {
504
- .response = NULL,
505
- .length = 0,
506
- .status = RRDPUSH_STATUS_BAD_HANDSHAKE,
507
- .version = STREAM_HANDSHAKE_ERROR_BAD_HANDSHAKE,
508
- .dynamic = false,
509
- .error = "remote node response is not understood, is it Netdata?",
510
- .worker_job_id = WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE,
511
- .postpone_reconnect_seconds = 1 * 60, // 1 minute
512
- .priority = NDLP_ERR,
513
- }
514
-};
515
-
516
-static inline bool rrdpush_sender_validate_response(RRDHOST *host, struct sender_state *s, char *http, size_t http_length) {
517
- int32_t version = STREAM_HANDSHAKE_ERROR_BAD_HANDSHAKE;
518
-
519
- int i;
520
- for(i = 0; stream_responses[i].response ; i++) {
521
- if(stream_responses[i].dynamic &&
522
- http_length > stream_responses[i].length && http_length < (stream_responses[i].length + 30) &&
523
- strncmp(http, stream_responses[i].response, stream_responses[i].length) == 0) {
524
-
525
- version = str2i(&http[stream_responses[i].length]);
526
- break;
527
- }
528
- else if(http_length == stream_responses[i].length && strcmp(http, stream_responses[i].response) == 0) {
529
- version = stream_responses[i].version;
530
-
531
- break;
532
- }
533
- }
534
-
535
- if(version >= STREAM_HANDSHAKE_OK_V1) {
536
- host->destination->reason = version;
537
- host->destination->postpone_reconnection_until = now_realtime_sec() + s->reconnect_delay;
538
- s->capabilities = convert_stream_version_to_capabilities(version, host, true);
539
- return true;
540
- }
541
-
542
- ND_LOG_FIELD_PRIORITY priority = stream_responses[i].priority;
543
- const char *error = stream_responses[i].error;
544
- const char *status = stream_responses[i].status;
545
- int worker_job_id = stream_responses[i].worker_job_id;
546
- int delay = stream_responses[i].postpone_reconnect_seconds;
547
-
548
- worker_is_busy(worker_job_id);
549
- rrdpush_sender_thread_close_socket(host);
550
- host->destination->reason = version;
551
- host->destination->postpone_reconnection_until = now_realtime_sec() + delay;
552
-
553
- ND_LOG_STACK lgs[] = {
554
- ND_LOG_FIELD_TXT(NDF_RESPONSE_CODE, status),
555
- ND_LOG_FIELD_END(),
556
- };
557
- ND_LOG_STACK_PUSH(lgs);
558
-
559
- char buf[RFC3339_MAX_LENGTH];
560
- rfc3339_datetime_ut(buf, sizeof(buf), host->destination->postpone_reconnection_until * USEC_PER_SEC, 0, false);
561
-
562
- nd_log(NDLS_DAEMON, priority,
563
- "STREAM %s [send to %s]: %s - will retry in %d secs, at %s",
564
- rrdhost_hostname(host), s->connected_to, error, delay, buf);
565
-
566
- return false;
567
-}
568
-
569
-unsigned char alpn_proto_list[] = {
570
- 18, 'n', 'e', 't', 'd', 'a', 't', 'a', '_', 's', 't', 'r', 'e', 'a', 'm', '/', '2', '.', '0',
571
- 8, 'h', 't', 't', 'p', '/', '1', '.', '1'
572
-};
573
-
574
-#define CONN_UPGRADE_VAL "upgrade"
575
-
576
-static bool rrdpush_sender_connect_ssl(struct sender_state *s __maybe_unused) {
577
- RRDHOST *host = s->host;
578
- bool ssl_required = host->destination && host->destination->ssl;
579
-
580
- netdata_ssl_close(&host->sender->ssl);
581
-
582
- if(!ssl_required)
583
- return true;
584
-
585
- if (netdata_ssl_open_ext(&host->sender->ssl, netdata_ssl_streaming_sender_ctx, s->rrdpush_sender_socket, alpn_proto_list, sizeof(alpn_proto_list))) {
586
- if(!netdata_ssl_connect(&host->sender->ssl)) {
587
- // couldn't connect
588
-
589
- ND_LOG_STACK lgs[] = {
590
- ND_LOG_FIELD_TXT(NDF_RESPONSE_CODE, RRDPUSH_STATUS_SSL_ERROR),
591
- ND_LOG_FIELD_END(),
592
- };
593
- ND_LOG_STACK_PUSH(lgs);
594
-
595
- worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SSL_ERROR);
596
- rrdpush_sender_thread_close_socket(host);
597
- host->destination->reason = STREAM_HANDSHAKE_ERROR_SSL_ERROR;
598
- host->destination->postpone_reconnection_until = now_realtime_sec() + 5 * 60;
599
- return false;
600
- }
601
-
602
- if (netdata_ssl_validate_certificate_sender &&
603
- security_test_certificate(host->sender->ssl.conn)) {
604
- // certificate is not valid
605
-
606
- ND_LOG_STACK lgs[] = {
607
- ND_LOG_FIELD_TXT(NDF_RESPONSE_CODE, RRDPUSH_STATUS_INVALID_SSL_CERTIFICATE),
608
- ND_LOG_FIELD_END(),
609
- };
610
- ND_LOG_STACK_PUSH(lgs);
611
-
612
- worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SSL_ERROR);
613
- netdata_log_error("SSL: closing the stream connection, because the server SSL certificate is not valid.");
614
- rrdpush_sender_thread_close_socket(host);
615
- host->destination->reason = STREAM_HANDSHAKE_ERROR_INVALID_CERTIFICATE;
616
- host->destination->postpone_reconnection_until = now_realtime_sec() + 5 * 60;
617
- return false;
618
- }
619
-
620
- return true;
621
- }
622
-
623
- ND_LOG_STACK lgs[] = {
624
- ND_LOG_FIELD_TXT(NDF_RESPONSE_CODE, RRDPUSH_STATUS_CANT_ESTABLISH_SSL_CONNECTION),
625
- ND_LOG_FIELD_END(),
626
- };
627
- ND_LOG_STACK_PUSH(lgs);
628
-
629
- netdata_log_error("SSL: failed to establish connection.");
630
- return false;
631
-}
632
-
633
-static int rrdpush_http_upgrade_prelude(RRDHOST *host, struct sender_state *s) {
634
-
635
- char http[HTTP_HEADER_SIZE + 1];
636
- snprintfz(http, HTTP_HEADER_SIZE,
637
- "GET " NETDATA_STREAM_URL HTTP_1_1 HTTP_ENDL
638
- "Upgrade: " NETDATA_STREAM_PROTO_NAME HTTP_ENDL
639
- "Connection: Upgrade"
640
- HTTP_HDR_END);
641
-
642
- ssize_t bytes = send_timeout(
643
- &host->sender->ssl,
644
- s->rrdpush_sender_socket,
645
- http,
646
- strlen(http),
647
- 0,
648
- 1000);
649
-
650
- bytes = recv_timeout(
651
- &host->sender->ssl,
652
- s->rrdpush_sender_socket,
653
- http,
654
- HTTP_HEADER_SIZE,
655
- 0,
656
- 1000);
657
-
658
- if (bytes <= 0) {
659
- error_report("Error reading from remote");
660
- return 1;
661
- }
662
-
663
- rbuf_t buf = rbuf_create(bytes);
664
- rbuf_push(buf, http, bytes);
665
-
666
- http_parse_ctx ctx;
667
- http_parse_ctx_create(&ctx, HTTP_PARSE_INITIAL);
668
- ctx.flags |= HTTP_PARSE_FLAG_DONT_WAIT_FOR_CONTENT;
669
-
670
- int rc;
671
-// while((rc = parse_http_response(buf, &ctx)) == HTTP_PARSE_NEED_MORE_DATA);
672
- rc = parse_http_response(buf, &ctx);
673
-
674
- if (rc != HTTP_PARSE_SUCCESS) {
675
- error_report("Failed to parse HTTP response sent. (%d)", rc);
676
- goto err_cleanup;
677
- }
678
- if (ctx.http_code == HTTP_RESP_MOVED_PERM) {
679
- const char *hdr = get_http_header_by_name(&ctx, "location");
680
- if (hdr)
681
- error_report("HTTP response is %d Moved Permanently (location: \"%s\") instead of expected %d Switching Protocols.", ctx.http_code, hdr, HTTP_RESP_SWITCH_PROTO);
682
- else
683
- error_report("HTTP response is %d instead of expected %d Switching Protocols.", ctx.http_code, HTTP_RESP_SWITCH_PROTO);
684
- goto err_cleanup;
685
- }
686
- if (ctx.http_code == HTTP_RESP_NOT_FOUND) {
687
- error_report("HTTP response is %d instead of expected %d Switching Protocols. Parent version too old.", ctx.http_code, HTTP_RESP_SWITCH_PROTO);
688
- // TODO set some flag here that will signify parent is older version
689
- // and to try connection without rrdpush_http_upgrade_prelude next time
690
- goto err_cleanup;
691
- }
692
- if (ctx.http_code != HTTP_RESP_SWITCH_PROTO) {
693
- error_report("HTTP response is %d instead of expected %d Switching Protocols", ctx.http_code, HTTP_RESP_SWITCH_PROTO);
694
- goto err_cleanup;
695
- }
696
-
697
- const char *hdr = get_http_header_by_name(&ctx, "connection");
698
- if (!hdr) {
699
- error_report("Missing \"connection\" header in reply");
700
- goto err_cleanup;
701
- }
702
- if (strncmp(hdr, CONN_UPGRADE_VAL, strlen(CONN_UPGRADE_VAL))) {
703
- error_report("Expected \"connection: " CONN_UPGRADE_VAL "\"");
704
- goto err_cleanup;
705
- }
706
-
707
- hdr = get_http_header_by_name(&ctx, "upgrade");
708
- if (!hdr) {
709
- error_report("Missing \"upgrade\" header in reply");
710
- goto err_cleanup;
711
- }
712
- if (strncmp(hdr, NETDATA_STREAM_PROTO_NAME, strlen(NETDATA_STREAM_PROTO_NAME))) {
713
- error_report("Expected \"upgrade: " NETDATA_STREAM_PROTO_NAME "\"");
714
- goto err_cleanup;
715
- }
716
-
717
- netdata_log_debug(D_STREAM, "Stream sender upgrade to \"" NETDATA_STREAM_PROTO_NAME "\" successful");
718
- rbuf_free(buf);
719
- http_parse_ctx_destroy(&ctx);
720
- return 0;
721
-err_cleanup:
722
- rbuf_free(buf);
723
- http_parse_ctx_destroy(&ctx);
724
- return 1;
725
-}
726
-
727
-static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_port, int timeout, struct sender_state *s) {
728
-
729
- struct timeval tv = {
730
- .tv_sec = timeout,
731
- .tv_usec = 0
732
- };
733
-
734
- // make sure the socket is closed
735
- rrdpush_sender_thread_close_socket(host);
736
-
737
- s->rrdpush_sender_socket = connect_to_one_of_destinations(
738
- host
739
- , default_port
740
- , &tv
741
- , &s->reconnects_counter
742
- , s->connected_to
743
- , sizeof(s->connected_to)-1
744
- , &host->destination
745
- );
746
-
747
- if(unlikely(s->rrdpush_sender_socket == -1)) {
748
- // netdata_log_error("STREAM %s [send to %s]: could not connect to parent node at this time.", rrdhost_hostname(host), host->rrdpush_send_destination);
749
- return false;
750
- }
751
-
752
- // netdata_log_info("STREAM %s [send to %s]: initializing communication...", rrdhost_hostname(host), s->connected_to);
753
-
754
- // reset our capabilities to default
755
- s->capabilities = stream_our_capabilities(host, true);
756
-
757
- /* TODO: During the implementation of #7265 switch the set of variables to HOST_* and CONTAINER_* if the
758
- version negotiation resulted in a high enough version.
759
- */
760
- stream_encoded_t se;
761
- rrdpush_encode_variable(&se, host);
762
-
763
- host->sender->hops = host->system_info->hops + 1;
764
-
765
- char http[HTTP_HEADER_SIZE + 1];
766
- int eol = snprintfz(http, HTTP_HEADER_SIZE,
767
- "STREAM "
768
- "key=%s"
769
- "&hostname=%s"
770
- "®istry_hostname=%s"
771
- "&machine_guid=%s"
772
- "&update_every=%d"
773
- "&os=%s"
774
- "&timezone=%s"
775
- "&abbrev_timezone=%s"
776
- "&utc_offset=%d"
777
- "&hops=%d"
778
- "&ml_capable=%d"
779
- "&ml_enabled=%d"
780
- "&mc_version=%d"
781
- "&ver=%u"
782
- "&NETDATA_INSTANCE_CLOUD_TYPE=%s"
783
- "&NETDATA_INSTANCE_CLOUD_INSTANCE_TYPE=%s"
784
- "&NETDATA_INSTANCE_CLOUD_INSTANCE_REGION=%s"
785
- "&NETDATA_SYSTEM_OS_NAME=%s"
786
- "&NETDATA_SYSTEM_OS_ID=%s"
787
- "&NETDATA_SYSTEM_OS_ID_LIKE=%s"
788
- "&NETDATA_SYSTEM_OS_VERSION=%s"
789
- "&NETDATA_SYSTEM_OS_VERSION_ID=%s"
790
- "&NETDATA_SYSTEM_OS_DETECTION=%s"
791
- "&NETDATA_HOST_IS_K8S_NODE=%s"
792
- "&NETDATA_SYSTEM_KERNEL_NAME=%s"
793
- "&NETDATA_SYSTEM_KERNEL_VERSION=%s"
794
- "&NETDATA_SYSTEM_ARCHITECTURE=%s"
795
- "&NETDATA_SYSTEM_VIRTUALIZATION=%s"
796
- "&NETDATA_SYSTEM_VIRT_DETECTION=%s"
797
- "&NETDATA_SYSTEM_CONTAINER=%s"
798
- "&NETDATA_SYSTEM_CONTAINER_DETECTION=%s"
799
- "&NETDATA_CONTAINER_OS_NAME=%s"
800
- "&NETDATA_CONTAINER_OS_ID=%s"
801
- "&NETDATA_CONTAINER_OS_ID_LIKE=%s"
802
- "&NETDATA_CONTAINER_OS_VERSION=%s"
803
- "&NETDATA_CONTAINER_OS_VERSION_ID=%s"
804
- "&NETDATA_CONTAINER_OS_DETECTION=%s"
805
- "&NETDATA_SYSTEM_CPU_LOGICAL_CPU_COUNT=%s"
806
- "&NETDATA_SYSTEM_CPU_FREQ=%s"
807
- "&NETDATA_SYSTEM_TOTAL_RAM=%s"
808
- "&NETDATA_SYSTEM_TOTAL_DISK_SIZE=%s"
809
- "&NETDATA_PROTOCOL_VERSION=%s"
810
- HTTP_1_1 HTTP_ENDL
811
- "User-Agent: %s/%s\r\n"
812
- "Accept: */*\r\n\r\n"
813
- , host->rrdpush.send.api_key
814
- , rrdhost_hostname(host)
815
- , rrdhost_registry_hostname(host)
816
- , host->machine_guid
817
- , default_rrd_update_every
818
- , rrdhost_os(host)
819
- , rrdhost_timezone(host)
820
- , rrdhost_abbrev_timezone(host)
821
- , host->utc_offset
822
- , host->sender->hops
823
- , host->system_info->ml_capable
824
- , host->system_info->ml_enabled
825
- , host->system_info->mc_version
826
- , s->capabilities
827
- , (host->system_info->cloud_provider_type) ? host->system_info->cloud_provider_type : ""
828
- , (host->system_info->cloud_instance_type) ? host->system_info->cloud_instance_type : ""
829
- , (host->system_info->cloud_instance_region) ? host->system_info->cloud_instance_region : ""
830
- , se.os_name
831
- , se.os_id
832
- , (host->system_info->host_os_id_like) ? host->system_info->host_os_id_like : ""
833
- , se.os_version
834
- , (host->system_info->host_os_version_id) ? host->system_info->host_os_version_id : ""
835
- , (host->system_info->host_os_detection) ? host->system_info->host_os_detection : ""
836
- , (host->system_info->is_k8s_node) ? host->system_info->is_k8s_node : ""
837
- , se.kernel_name
838
- , se.kernel_version
839
- , (host->system_info->architecture) ? host->system_info->architecture : ""
840
- , (host->system_info->virtualization) ? host->system_info->virtualization : ""
841
- , (host->system_info->virt_detection) ? host->system_info->virt_detection : ""
842
- , (host->system_info->container) ? host->system_info->container : ""
843
- , (host->system_info->container_detection) ? host->system_info->container_detection : ""
844
- , (host->system_info->container_os_name) ? host->system_info->container_os_name : ""
845
- , (host->system_info->container_os_id) ? host->system_info->container_os_id : ""
846
- , (host->system_info->container_os_id_like) ? host->system_info->container_os_id_like : ""
847
- , (host->system_info->container_os_version) ? host->system_info->container_os_version : ""
848
- , (host->system_info->container_os_version_id) ? host->system_info->container_os_version_id : ""
849
- , (host->system_info->container_os_detection) ? host->system_info->container_os_detection : ""
850
- , (host->system_info->host_cores) ? host->system_info->host_cores : ""
851
- , (host->system_info->host_cpu_freq) ? host->system_info->host_cpu_freq : ""
852
- , (host->system_info->host_ram_total) ? host->system_info->host_ram_total : ""
853
- , (host->system_info->host_disk_space) ? host->system_info->host_disk_space : ""
854
- , STREAMING_PROTOCOL_VERSION
855
- , rrdhost_program_name(host)
856
- , rrdhost_program_version(host)
857
- );
858
- http[eol] = 0x00;
859
- rrdpush_clean_encoded(&se);
860
-
861
- if(!rrdpush_sender_connect_ssl(s))
862
- return false;
863
-
864
- if (s->parent_using_h2o && rrdpush_http_upgrade_prelude(host, s)) {
865
- ND_LOG_STACK lgs[] = {
866
- ND_LOG_FIELD_TXT(NDF_RESPONSE_CODE, RRDPUSH_STATUS_CANT_UPGRADE_CONNECTION),
867
- ND_LOG_FIELD_END(),
868
- };
869
- ND_LOG_STACK_PUSH(lgs);
870
-
871
- worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_CANT_UPGRADE_CONNECTION);
872
- rrdpush_sender_thread_close_socket(host);
873
- host->destination->reason = STREAM_HANDSHAKE_ERROR_HTTP_UPGRADE;
874
- host->destination->postpone_reconnection_until = now_realtime_sec() + 1 * 60;
875
- return false;
876
- }
877
-
878
- ssize_t len = (ssize_t)strlen(http);
879
- ssize_t bytes = send_timeout(
880
- &host->sender->ssl,
881
- s->rrdpush_sender_socket,
882
- http,
883
- len,
884
- 0,
885
- timeout);
886
-
887
- if(bytes <= 0) { // timeout is 0
888
- ND_LOG_STACK lgs[] = {
889
- ND_LOG_FIELD_TXT(NDF_RESPONSE_CODE, RRDPUSH_STATUS_TIMEOUT),
890
- ND_LOG_FIELD_END(),
891
- };
892
- ND_LOG_STACK_PUSH(lgs);
893
-
894
- worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_TIMEOUT);
895
- rrdpush_sender_thread_close_socket(host);
896
-
897
- nd_log(NDLS_DAEMON, NDLP_ERR,
898
- "STREAM %s [send to %s]: failed to send HTTP header to remote netdata.",
899
- rrdhost_hostname(host), s->connected_to);
900
-
901
- host->destination->reason = STREAM_HANDSHAKE_ERROR_SEND_TIMEOUT;
902
- host->destination->postpone_reconnection_until = now_realtime_sec() + 1 * 60;
903
- return false;
904
- }
905
-
906
- bytes = recv_timeout(
907
- &host->sender->ssl,
908
- s->rrdpush_sender_socket,
909
- http,
910
- HTTP_HEADER_SIZE,
911
- 0,
912
- timeout);
913
-
914
- if(bytes <= 0) { // timeout is 0
915
- ND_LOG_STACK lgs[] = {
916
- ND_LOG_FIELD_TXT(NDF_RESPONSE_CODE, RRDPUSH_STATUS_TIMEOUT),
917
- ND_LOG_FIELD_END(),
918
- };
919
- ND_LOG_STACK_PUSH(lgs);
920
-
921
- worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_TIMEOUT);
922
- rrdpush_sender_thread_close_socket(host);
923
-
924
- nd_log(NDLS_DAEMON, NDLP_ERR,
925
- "STREAM %s [send to %s]: remote netdata does not respond.",
926
- rrdhost_hostname(host), s->connected_to);
927
-
928
- host->destination->reason = STREAM_HANDSHAKE_ERROR_RECEIVE_TIMEOUT;
929
- host->destination->postpone_reconnection_until = now_realtime_sec() + 30;
930
- return false;
931
- }
932
-
933
- if(sock_setnonblock(s->rrdpush_sender_socket) < 0)
934
- nd_log(NDLS_DAEMON, NDLP_WARNING,
935
- "STREAM %s [send to %s]: cannot set non-blocking mode for socket.",
936
- rrdhost_hostname(host), s->connected_to);
937
- sock_setcloexec(s->rrdpush_sender_socket);
148
939
- if(sock_enlarge_out(s->rrdpush_sender_socket) < 0)
940
- nd_log(NDLS_DAEMON, NDLP_WARNING,
941
- "STREAM %s [send to %s]: cannot enlarge the socket buffer.",
942
- rrdhost_hostname(host), s->connected_to);
943
-
944
- http[bytes] = '\0';
945
- if(!rrdpush_sender_validate_response(host, s, http, bytes))
946
- return false;
947
-
948
- rrdpush_compression_initialize(s);
949
-
950
- log_sender_capabilities(s);
951
-
952
- ND_LOG_STACK lgs[] = {
953
- ND_LOG_FIELD_TXT(NDF_RESPONSE_CODE, RRDPUSH_STATUS_CONNECTED),
954
- ND_LOG_FIELD_END(),
955
- };
956
- ND_LOG_STACK_PUSH(lgs);
957
-
958
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
959
- "STREAM %s: connected to %s...",
960
- rrdhost_hostname(host), s->connected_to);
961
-
962
- return true;
963
-}
964
-
965
-static bool attempt_to_connect(struct sender_state *state) {
966
- ND_LOG_STACK lgs[] = {
967
- ND_LOG_FIELD_UUID(NDF_MESSAGE_ID, &streaming_to_parent_msgid),
968
- ND_LOG_FIELD_END(),
969
- };
970
- ND_LOG_STACK_PUSH(lgs);
971
-
972
- state->send_attempts = 0;
973
-
974
- // reset the bytes we have sent for this session
975
- state->sent_bytes_on_this_connection = 0;
976
- memset(state->sent_bytes_on_this_connection_per_type, 0, sizeof(state->sent_bytes_on_this_connection_per_type));
977
-
978
- if(rrdpush_sender_thread_connect_to_parent(state->host, state->default_port, state->timeout, state)) {
979
- // reset the buffer, to properly send charts and metrics
980
- rrdpush_sender_on_connect(state->host);
981
-
982
- // send from the beginning
983
- state->begin = 0;
984
-
985
- // make sure the next reconnection will be immediate
986
- state->not_connected_loops = 0;
987
-
988
- // let the data collection threads know we are ready
989
- rrdhost_flag_set(state->host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED);
990
-
991
- rrdpush_sender_after_connect(state->host);
992
-
993
- return true;
994
- }
995
-
996
- // we couldn't connect
997
-
998
- // increase the failed connections counter
999
- state->not_connected_loops++;
1000
-
1001
- // slow re-connection on repeating errors
1002
- usec_t now_ut = now_monotonic_usec();
1003
- usec_t end_ut = now_ut + USEC_PER_SEC * state->reconnect_delay;
1004
- while(now_ut < end_ut) {
1005
- if(nd_thread_signaled_to_cancel())
1006
- return false;
1007
-
1008
- sleep_usec(100 * USEC_PER_MS); // seconds
1009
- now_ut = now_monotonic_usec();
1010
- }
1011
-
1012
- return false;
149
+ stream_path_parent_disconnected(host);
150
}
151
152
// TCP window is open, and we have data to transmit.
179
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SEND_ERROR);
180
netdata_log_debug(D_STREAM, "STREAM: Send failed - closing socket...");
181
netdata_log_error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", rrdhost_hostname(s->host), s->connected_to, s->sent_bytes_on_this_connection);
1045
- rrdpush_sender_thread_close_socket(s->host);
182
+ rrdpush_sender_disconnect_and_cleanup(s->host);
183
}
184
else
185
netdata_log_debug(D_STREAM, "STREAM: send() returned 0 -> no error but no transmission");
217
netdata_log_error("STREAM %s [send to %s]: error during receive (%zd) - closing connection.", rrdhost_hostname(s->host), s->connected_to, ret);
218
}
219
1083
- rrdpush_sender_thread_close_socket(s->host);
220
+ rrdpush_sender_disconnect_and_cleanup(s->host);
221
222
return ret;
223
}
224
1088
-struct inflight_stream_function {
1089
- struct sender_state *sender;
1090
- STRING *transaction;
1091
- usec_t received_ut;
1092
-};
1093
-
1094
-static void stream_execute_function_callback(BUFFER *func_wb, int code, void *data) {
1095
- struct inflight_stream_function *tmp = data;
1096
- struct sender_state *s = tmp->sender;
1097
-
1098
- if(rrdhost_can_send_definitions_to_parent(s->host)) {
1099
- BUFFER *wb = sender_start(s);
1100
-
1101
- pluginsd_function_result_begin_to_buffer(wb
1102
- , string2str(tmp->transaction)
1103
- , code
1104
- , content_type_id2string(func_wb->content_type)
1105
- , func_wb->expires);
1106
-
1107
- buffer_fast_strcat(wb, buffer_tostring(func_wb), buffer_strlen(func_wb));
1108
- pluginsd_function_result_end_to_buffer(wb);
1109
-
1110
- sender_commit(s, wb, STREAM_TRAFFIC_TYPE_FUNCTIONS);
1111
- sender_thread_buffer_free();
1112
-
1113
- internal_error(true, "STREAM %s [send to %s] FUNCTION transaction %s sending back response (%zu bytes, %"PRIu64" usec).",
1114
- rrdhost_hostname(s->host), s->connected_to,
1115
- string2str(tmp->transaction),
1116
- buffer_strlen(func_wb),
1117
- now_realtime_usec() - tmp->received_ut);
1118
- }
1119
-
1120
- string_freez(tmp->transaction);
1121
- buffer_free(func_wb);
1122
- freez(tmp);
1123
-}
1124
-
1125
-static void stream_execute_function_progress_callback(void *data, size_t done, size_t all) {
1126
- struct inflight_stream_function *tmp = data;
1127
- struct sender_state *s = tmp->sender;
1128
-
1129
- if(rrdhost_can_send_definitions_to_parent(s->host)) {
1130
- BUFFER *wb = sender_start(s);
1131
-
1132
- buffer_sprintf(wb, PLUGINSD_KEYWORD_FUNCTION_PROGRESS " '%s' %zu %zu\n",
1133
- string2str(tmp->transaction), done, all);
1134
-
1135
- sender_commit(s, wb, STREAM_TRAFFIC_TYPE_FUNCTIONS);
1136
- }
1137
-}
1138
-
1139
-static void execute_commands_function(struct sender_state *s, const char *command, const char *transaction, const char *timeout_s, const char *function, BUFFER *payload, const char *access, const char *source) {
1140
- worker_is_busy(WORKER_SENDER_JOB_FUNCTION_REQUEST);
1141
- nd_log(NDLS_ACCESS, NDLP_INFO, NULL);
1142
-
1143
- if(!transaction || !*transaction || !timeout_s || !*timeout_s || !function || !*function) {
1144
- netdata_log_error("STREAM %s [send to %s] %s execution command is incomplete (transaction = '%s', timeout = '%s', function = '%s'). Ignoring it.",
1145
- rrdhost_hostname(s->host), s->connected_to,
1146
- command,
1147
- transaction?transaction:"(unset)",
1148
- timeout_s?timeout_s:"(unset)",
1149
- function?function:"(unset)");
1150
- }
1151
- else {
1152
- int timeout = str2i(timeout_s);
1153
- if(timeout <= 0) timeout = PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT;
1154
-
1155
- struct inflight_stream_function *tmp = callocz(1, sizeof(struct inflight_stream_function));
1156
- tmp->received_ut = now_realtime_usec();
1157
- tmp->sender = s;
1158
- tmp->transaction = string_strdupz(transaction);
1159
- BUFFER *wb = buffer_create(1024, &netdata_buffers_statistics.buffers_functions);
1160
-
1161
- int code = rrd_function_run(s->host, wb, timeout,
1162
- http_access_from_hex_mapping_old_roles(access), function, false, transaction,
1163
- stream_execute_function_callback, tmp,
1164
- stream_has_capability(s, STREAM_CAP_PROGRESS) ? stream_execute_function_progress_callback : NULL,
1165
- stream_has_capability(s, STREAM_CAP_PROGRESS) ? tmp : NULL,
1166
- NULL, NULL, payload, source, true);
1167
-
1168
- if(code != HTTP_RESP_OK) {
1169
- if (!buffer_strlen(wb))
1170
- rrd_call_function_error(wb, "Failed to route request to collector", code);
1171
- }
1172
- }
1173
-}
1174
-
1175
-static void cleanup_intercepting_input(struct sender_state *s) {
1176
- freez((void *)s->functions.transaction);
1177
- freez((void *)s->functions.timeout_s);
1178
- freez((void *)s->functions.function);
1179
- freez((void *)s->functions.access);
1180
- freez((void *)s->functions.source);
1181
- buffer_free(s->functions.payload);
1182
-
1183
- s->functions.transaction = NULL;
1184
- s->functions.timeout_s = NULL;
1185
- s->functions.function = NULL;
1186
- s->functions.payload = NULL;
1187
- s->functions.access = NULL;
1188
- s->functions.source = NULL;
1189
- s->functions.intercept_input = false;
1190
-}
1191
-
1192
-static void execute_commands_cleanup(struct sender_state *s) {
1193
- cleanup_intercepting_input(s);
1194
-}
1195
-
1196
-// This is just a placeholder until the gap filling state machine is inserted
1197
-void execute_commands(struct sender_state *s) {
1198
- worker_is_busy(WORKER_SENDER_JOB_EXECUTE);
1199
-
1200
- ND_LOG_STACK lgs[] = {
1201
- ND_LOG_FIELD_CB(NDF_REQUEST, line_splitter_reconstruct_line, &s->line),
1202
- ND_LOG_FIELD_END(),
1203
- };
1204
- ND_LOG_STACK_PUSH(lgs);
1205
-
1206
- char *start = s->read_buffer, *end = &s->read_buffer[s->read_len], *newline;
1207
- *end = '\0';
1208
- for( ; start < end ; start = newline + 1) {
1209
- newline = strchr(start, '\n');
1210
-
1211
- if(!newline) {
1212
- if(s->functions.intercept_input) {
1213
- buffer_strcat(s->functions.payload, start);
1214
- start = end;
1215
- }
1216
- break;
1217
- }
1218
-
1219
- *newline = '\0';
1220
- s->line.count++;
1221
-
1222
- if(s->functions.intercept_input) {
1223
- if(strcmp(start, PLUGINSD_CALL_FUNCTION_PAYLOAD_END) == 0) {
1224
- execute_commands_function(s,
1225
- PLUGINSD_CALL_FUNCTION_PAYLOAD_END,
1226
- s->functions.transaction, s->functions.timeout_s,
1227
- s->functions.function, s->functions.payload,
1228
- s->functions.access, s->functions.source);
1229
-
1230
- cleanup_intercepting_input(s);
1231
- }
1232
- else {
1233
- buffer_strcat(s->functions.payload, start);
1234
- buffer_fast_charcat(s->functions.payload, '\n');
1235
- }
1236
-
1237
- continue;
1238
- }
1239
-
1240
- s->line.num_words = quoted_strings_splitter_pluginsd(start, s->line.words, PLUGINSD_MAX_WORDS);
1241
- const char *command = get_word(s->line.words, s->line.num_words, 0);
1242
-
1243
- if(command && strcmp(command, PLUGINSD_CALL_FUNCTION) == 0) {
1244
- char *transaction = get_word(s->line.words, s->line.num_words, 1);
1245
- char *timeout_s = get_word(s->line.words, s->line.num_words, 2);
1246
- char *function = get_word(s->line.words, s->line.num_words, 3);
1247
- char *access = get_word(s->line.words, s->line.num_words, 4);
1248
- char *source = get_word(s->line.words, s->line.num_words, 5);
1249
-
1250
- execute_commands_function(s, command, transaction, timeout_s, function, NULL, access, source);
1251
- }
1252
- else if(command && strcmp(command, PLUGINSD_CALL_FUNCTION_PAYLOAD_BEGIN) == 0) {
1253
- char *transaction = get_word(s->line.words, s->line.num_words, 1);
1254
- char *timeout_s = get_word(s->line.words, s->line.num_words, 2);
1255
- char *function = get_word(s->line.words, s->line.num_words, 3);
1256
- char *access = get_word(s->line.words, s->line.num_words, 4);
1257
- char *source = get_word(s->line.words, s->line.num_words, 5);
1258
- char *content_type = get_word(s->line.words, s->line.num_words, 6);
1259
-
1260
- s->functions.transaction = strdupz(transaction ? transaction : "");
1261
- s->functions.timeout_s = strdupz(timeout_s ? timeout_s : "");
1262
- s->functions.function = strdupz(function ? function : "");
1263
- s->functions.access = strdupz(access ? access : "");
1264
- s->functions.source = strdupz(source ? source : "");
1265
- s->functions.payload = buffer_create(0, NULL);
1266
- s->functions.payload->content_type = content_type_string2id(content_type);
1267
- s->functions.intercept_input = true;
1268
- }
1269
- else if(command && strcmp(command, PLUGINSD_CALL_FUNCTION_CANCEL) == 0) {
1270
- worker_is_busy(WORKER_SENDER_JOB_FUNCTION_REQUEST);
1271
- nd_log(NDLS_ACCESS, NDLP_DEBUG, NULL);
1272
-
1273
- char *transaction = get_word(s->line.words, s->line.num_words, 1);
1274
- if(transaction && *transaction)
1275
- rrd_function_cancel(transaction);
1276
- }
1277
- else if(command && strcmp(command, PLUGINSD_CALL_FUNCTION_PROGRESS) == 0) {
1278
- worker_is_busy(WORKER_SENDER_JOB_FUNCTION_REQUEST);
1279
- nd_log(NDLS_ACCESS, NDLP_DEBUG, NULL);
1280
-
1281
- char *transaction = get_word(s->line.words, s->line.num_words, 1);
1282
- if(transaction && *transaction)
1283
- rrd_function_progress(transaction);
1284
- }
1285
- else if (command && strcmp(command, PLUGINSD_KEYWORD_REPLAY_CHART) == 0) {
1286
- worker_is_busy(WORKER_SENDER_JOB_REPLAY_REQUEST);
1287
- nd_log(NDLS_ACCESS, NDLP_DEBUG, NULL);
1288
-
1289
- const char *chart_id = get_word(s->line.words, s->line.num_words, 1);
1290
- const char *start_streaming = get_word(s->line.words, s->line.num_words, 2);
1291
- const char *after = get_word(s->line.words, s->line.num_words, 3);
1292
- const char *before = get_word(s->line.words, s->line.num_words, 4);
1293
-
1294
- if (!chart_id || !start_streaming || !after || !before) {
1295
- netdata_log_error("STREAM %s [send to %s] %s command is incomplete"
1296
- " (chart=%s, start_streaming=%s, after=%s, before=%s)",
1297
- rrdhost_hostname(s->host), s->connected_to,
1298
- command,
1299
- chart_id ? chart_id : "(unset)",
1300
- start_streaming ? start_streaming : "(unset)",
1301
- after ? after : "(unset)",
1302
- before ? before : "(unset)");
1303
- }
1304
- else {
1305
- replication_add_request(s, chart_id,
1306
- strtoll(after, NULL, 0),
1307
- strtoll(before, NULL, 0),
1308
- !strcmp(start_streaming, "true")
1309
- );
1310
- }
1311
- }
1312
- else if(command && strcmp(command, PLUGINSD_KEYWORD_NODE_ID) == 0) {
1313
- rrdpush_sender_get_node_and_claim_id_from_parent(s);
1314
- }
1315
- else {
1316
- netdata_log_error("STREAM %s [send to %s] received unknown command over connection: %s",
1317
- rrdhost_hostname(s->host), s->connected_to, s->line.words[0]?s->line.words[0]:"(unset)");
1318
- }
1319
-
1320
- line_splitter_reset(&s->line);
1321
- worker_is_busy(WORKER_SENDER_JOB_EXECUTE);
1322
- }
1323
-
1324
- if (start < end) {
1325
- memmove(s->read_buffer, start, end-start);
1326
- s->read_len = end - start;
1327
- }
1328
- else {
1329
- s->read_buffer[0] = '\0';
1330
- s->read_len = 0;
1331
- }
1332
-}
1333
-
225
struct rrdpush_sender_thread_data {
226
RRDHOST *host;
227
char *pipe_buffer;
367
rrdhost_hostname(host),
368
host->sender->exit.reason != STREAM_HANDSHAKE_NEVER ? stream_handshake_error_to_string(host->sender->exit.reason) : "");
369
1479
- rrdpush_sender_thread_close_socket(host);
370
+ rrdpush_sender_disconnect_and_cleanup(host);
371
rrdpush_sender_pipe_close(host, host->sender->rrdpush_sender_pipe, false);
1481
- execute_commands_cleanup(host->sender);
372
+ rrdpush_sender_execute_commands_cleanup(host->sender);
373
374
rrdhost_clear_sender___while_having_sender_mutex(host);
375
531
&stream_config, CONFIG_SECTION_STREAM, "parent using h2o", false);
532
533
// initialize rrdpush globals
1643
- rrdhost_flag_clear(s->host, RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
1644
- rrdhost_flag_clear(s->host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED);
534
+ rrdhost_flag_clear(s->host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED | RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
535
536
int pipe_buffer_size = 10 * 1024;
537
#ifdef F_GETPIPE_SZ
563
564
now_s = now_monotonic_sec();
565
rrdpush_sender_cbuffer_recreate_timed(s, now_s, false, true);
1676
- execute_commands_cleanup(s);
566
+ rrdpush_sender_execute_commands_cleanup(s);
567
568
rrdhost_flag_clear(s->host, RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
569
s->flags &= ~SENDER_FLAG_OVERFLOW;
578
break;
579
580
now_s = s->last_traffic_seen_t = now_monotonic_sec();
581
+ stream_path_send_to_parent(s->host);
582
rrdpush_sender_send_claimed_id(s->host);
583
rrdpush_send_host_labels(s->host);
584
rrdpush_send_global_functions(s->host);
603
)) {
604
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_TIMEOUT);
605
netdata_log_error("STREAM %s [send to %s]: could not send metrics for %d seconds - closing connection - we have sent %zu bytes on this connection via %zu send attempts.", rrdhost_hostname(s->host), s->connected_to, s->timeout, s->sent_bytes_on_this_connection, s->send_attempts);
1715
- rrdpush_sender_thread_close_socket(s->host);
606
+ rrdpush_sender_disconnect_and_cleanup(s->host);
607
continue;
608
}
609
634
if(!rrdpush_sender_pipe_close(s->host, s->rrdpush_sender_pipe, true)) {
635
netdata_log_error("STREAM %s [send]: cannot create inter-thread communication pipe. Disabling streaming.",
636
rrdhost_hostname(s->host));
1746
- rrdpush_sender_thread_close_socket(s->host);
637
+ rrdpush_sender_disconnect_and_cleanup(s->host);
638
break;
639
}
640
}
685
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_POLL_ERROR);
686
netdata_log_error("STREAM %s [send to %s]: failed to poll(). Closing socket.", rrdhost_hostname(s->host), s->connected_to);
687
rrdpush_sender_pipe_close(s->host, s->rrdpush_sender_pipe, true);
1797
- rrdpush_sender_thread_close_socket(s->host);
688
+ rrdpush_sender_disconnect_and_cleanup(s->host);
689
continue;
690
}
691
719
}
720
721
if(unlikely(s->read_len))
1831
- execute_commands(s);
722
+ rrdpush_sender_execute_commands(s);
723
724
if(unlikely(fds[Collector].revents & (POLLERR|POLLHUP|POLLNVAL))) {
725
char *error = NULL;
752
worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SOCKET_ERROR);
753
netdata_log_error("STREAM %s [send to %s]: restarting connection: %s - %zu bytes transmitted.",
754
rrdhost_hostname(s->host), s->connected_to, error, s->sent_bytes_on_this_connection);
1864
- rrdpush_sender_thread_close_socket(s->host);
755
+ rrdpush_sender_disconnect_and_cleanup(s->host);
756
}
757
}
758
762
errno_clear();
763
netdata_log_error("STREAM %s [send to %s]: buffer full (allocated %zu bytes) after sending %zu bytes. Restarting connection",
764
rrdhost_hostname(s->host), s->connected_to, s->buffer->size, s->sent_bytes_on_this_connection);
1874
- rrdpush_sender_thread_close_socket(s->host);
765
+ rrdpush_sender_disconnect_and_cleanup(s->host);
766
}
767
768
worker_set_metric(WORKER_SENDER_JOB_REPLAY_DICT_SIZE, (NETDATA_DOUBLE) dictionary_entries(s->replication.requests));