master
c 735 lines 25.9 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "webrtc.h"
4
5 #include "../server/web_client.h"
6 #include "../server/web_client_cache.h"
7
8 #ifdef HAVE_LIBDATACHANNEL
9
10 #include "rtc/rtc.h"
11
12 #define WEBRTC_OUR_MAX_MESSAGE_SIZE (5 * 1024 * 1024)
13 #define WEBRTC_DEFAULT_REMOTE_MAX_MESSAGE_SIZE (65536)
14 #define WEBRTC_COMPRESSED_HEADER_SIZE 200
15
16 static void webrtc_log(rtcLogLevel level, const char *message) {
17 switch(level) {
18 case RTC_LOG_NONE:
19 break;
20
21 case RTC_LOG_WARNING:
22 case RTC_LOG_ERROR:
23 case RTC_LOG_FATAL:
24 netdata_log_error("WEBRTC: %s", message);
25 break;
26
27 case RTC_LOG_INFO:
28 netdata_log_info("WEBRTC: %s", message);
29 break;
30
31 default:
32 case RTC_LOG_DEBUG:
33 case RTC_LOG_VERBOSE:
34 internal_error(true, "WEBRTC: %s", message);
35 break;
36
37 }
38 }
39
40 typedef struct webrtc_datachannel {
41 int dc;
42 char *label;
43 struct webrtc_connection *conn;
44
45 bool open; // atomic
46
47 struct {
48 struct webrtc_datachannel *prev;
49 struct webrtc_datachannel *next;
50 } link;
51 } WEBRTC_DC;
52
53 typedef struct webrtc_connection {
54 int pc;
55 rtcConfiguration config;
56 rtcState state;
57 rtcGatheringState gathering_state;
58
59 size_t max_message_size;
60 size_t local_max_message_size;
61 size_t remote_max_message_size;
62
63 struct {
64 SPINLOCK spinlock;
65 BUFFER *wb;
66 bool sdp;
67 bool candidates;
68 } response;
69
70 struct {
71 SPINLOCK spinlock;
72 WEBRTC_DC *head;
73 } channels;
74
75 struct {
76 struct webrtc_connection *prev;
77 struct webrtc_connection *next;
78 } link;
79 } WEBRTC_CONN;
80
81 #define WEBRTC_MAX_ICE_SERVERS 100
82
83 static struct {
84 bool enabled;
85 char *iceServers[WEBRTC_MAX_ICE_SERVERS];
86 int iceServersCount;
87 const char *proxyServer;
88 const char *bindAddress;
89
90 struct {
91 SPINLOCK spinlock;
92 WEBRTC_CONN *head;
93 } unsafe;
94
95 } webrtc_base = {
96 #ifdef NETDATA_INTERNAL_CHECKS
97 .enabled = true,
98 #else
99 .enabled = false,
100 #endif
101 .iceServers = {
102 // Format:
103 // [("stun"|"turn"|"turns") (":"|"://")][username ":" password "@"]hostname[":" port]["?transport=" ("udp"|"tcp"|"tls")]
104 //
105 // Note transports TCP and TLS are only available for a TURN server with libnice as ICE backend and govern only the
106 // TURN control connection, meaning relaying is always performed over UDP.
107 //
108 // If the username or password of a URI contains reserved special characters, they must be percent-encoded.
109 // In particular, ":" must be encoded as "%3A" and "@" must by encoded as "%40".
110
111 "stun://stun.l.google.com:19302",
112 NULL, // terminator
113 },
114 .iceServersCount = 1,
115 .proxyServer = NULL, // [("http"|"socks5") (":"|"://")][username ":" password "@"]hostname[" :" port]
116 .bindAddress = NULL,
117 .unsafe = {
118 .spinlock = SPINLOCK_INITIALIZER,
119 .head = NULL,
120 },
121 };
122
123 static inline bool webrtc_dc_is_open(WEBRTC_DC *chan) {
124 return __atomic_load_n(&chan->open, __ATOMIC_RELAXED);
125 }
126
127 static void webrtc_config_ice_servers(void) {
128 BUFFER *wb = buffer_create(0, NULL);
129
130 int i;
131 for(i = 0; i < WEBRTC_MAX_ICE_SERVERS ;i++) {
132 if (webrtc_base.iceServers[i]) {
133 if (buffer_strlen(wb))
134 buffer_strcat(wb, " ");
135
136 internal_error(true, "WEBRTC: default ice server No %d is: '%s'", i, webrtc_base.iceServers[i]);
137 buffer_strcat(wb, webrtc_base.iceServers[i]);
138 }
139 else
140 break;
141 }
142 webrtc_base.iceServersCount = i;
143 internal_error(true, "WEBRTC: there are %d default ice servers: '%s'", webrtc_base.iceServersCount, buffer_tostring(wb));
144
145 const char *servers = inicfg_get(&netdata_config, CONFIG_SECTION_WEBRTC, "ice servers", buffer_tostring(wb));
146
147 webrtc_base.iceServersCount = 0;
148 char tmp[strlen(servers) + 1];
149 strcpy(tmp, servers);
150 char *s = tmp, *e;
151 while(*s) {
152 if(isspace(*s))
153 s++;
154
155 e = s;
156 while(*e && !isspace(*e))
157 e++;
158
159 if(s != e && webrtc_base.iceServersCount < WEBRTC_MAX_ICE_SERVERS) {
160 char old = *e;
161 *e = '\0';
162 internal_error(true, "WEBRTC: ice server No %d is: '%s'", webrtc_base.iceServersCount, s);
163 webrtc_base.iceServers[webrtc_base.iceServersCount++] = strdupz(s);
164 *e = old;
165 }
166
167 if(*e)
168 s = e + 1;
169 else
170 break;
171 }
172
173 buffer_free(wb);
174 }
175
176 void webrtc_initialize() {
177 webrtc_base.enabled = inicfg_get_boolean(&netdata_config, CONFIG_SECTION_WEBRTC, "enabled", webrtc_base.enabled);
178 internal_error(true, "WEBRTC: is %s", webrtc_base.enabled ? "enabled" : "disabled");
179
180 webrtc_config_ice_servers();
181
182 webrtc_base.proxyServer = inicfg_get(&netdata_config, CONFIG_SECTION_WEBRTC, "proxy server", webrtc_base.proxyServer ? webrtc_base.proxyServer : "");
183 if(!webrtc_base.proxyServer || !*webrtc_base.proxyServer)
184 webrtc_base.proxyServer = NULL;
185
186 internal_error(true, "WEBRTC: proxy server is: '%s'", webrtc_base.proxyServer ? webrtc_base.proxyServer : "");
187
188 webrtc_base.bindAddress = inicfg_get(&netdata_config, CONFIG_SECTION_WEBRTC, "bind address", webrtc_base.bindAddress ? webrtc_base.bindAddress : "");
189 if(!webrtc_base.bindAddress || !*webrtc_base.bindAddress)
190 webrtc_base.bindAddress = NULL;
191
192 internal_error(true, "WEBRTC: bind address is: '%s'", webrtc_base.bindAddress ? webrtc_base.bindAddress : "");
193
194 if(!webrtc_base.enabled)
195 return;
196
197 rtcLogLevel level;
198 #ifdef NETDATA_INTERNAL_CHECKS
199 level = RTC_LOG_INFO;
200 #else
201 level = RTC_LOG_WARNING;
202 #endif
203
204 rtcInitLogger(level, webrtc_log);
205 rtcPreload();
206 }
207
208 void webrtc_close_all_connections() {
209 if(!webrtc_base.enabled)
210 return;
211
212 rtcCleanup();
213 }
214
215 size_t find_max_message_size_in_sdp(const char *sdp) {
216 char *s = strstr(sdp, "a=max-message-size:");
217 if(s)
218 return str2ul(&s[19]);
219
220 return WEBRTC_DEFAULT_REMOTE_MAX_MESSAGE_SIZE;
221 }
222
223 // ----------------------------------------------------------------------------
224 // execute web API requests
225
226 static bool web_client_stop_callback(struct web_client *w __maybe_unused, void *data) {
227 WEBRTC_DC *chan = data;
228 return !webrtc_dc_is_open(chan);
229 }
230
231 static size_t webrtc_send_in_chunks(WEBRTC_DC *chan, const char *data, size_t size, int code, const char *message_type, HTTP_CONTENT_TYPE content_type, size_t max_message_size, bool binary) {
232 size_t sent_bytes = 0;
233 size_t chunk = 0;
234 size_t total_chunks = size / max_message_size;
235 if(total_chunks * max_message_size < size)
236 total_chunks++;
237
238 char *send_buffer = mallocz(chan->conn->max_message_size);
239
240 char *s = (char *)data;
241 size_t remaining = size;
242 while(remaining > 0) {
243 chunk++;
244
245 size_t message_size = MIN(remaining, max_message_size);
246
247 int len = snprintfz(send_buffer, WEBRTC_COMPRESSED_HEADER_SIZE, "%d %s %zu %zu %zu %s\r\n",
248 code,
249 message_type,
250 message_size,
251 chunk,
252 total_chunks,
253 content_type_id2string(content_type)
254 );
255
256 internal_fatal((size_t)len != strlen(send_buffer), "WEBRTC compressed header line mismatch");
257 internal_fatal(len + message_size > chan->conn->max_message_size, "WEBRTC message exceeds max message size");
258
259 memcpy(&send_buffer[len], s, message_size);
260
261 int total_message_size = (int)(len + message_size);
262 sent_bytes += total_message_size;
263
264 if(!binary)
265 total_message_size = -total_message_size;
266
267 if(rtcSendMessage(chan->dc, send_buffer, total_message_size) != RTC_ERR_SUCCESS)
268 netdata_log_error("WEBRTC[%d],DC[%d]: failed to send LZ4 chunk %zu of %zu", chan->conn->pc, chan->dc, chunk, total_chunks);
269 else
270 internal_error(true, "WEBRTC[%d],DC[%d]: sent chunk %zu of %zu, size %zu (total %d)",
271 chan->conn->pc, chan->dc, chunk, total_chunks, message_size, total_message_size);
272
273 s = s + message_size;
274 remaining -= message_size;
275 }
276
277 internal_fatal(chunk != total_chunks, "WEBRTC number of compressed chunks mismatch");
278
279 freez(send_buffer);
280 return sent_bytes;
281 }
282
283 static void webrtc_execute_api_request(WEBRTC_DC *chan, const char *request, size_t size __maybe_unused, bool binary __maybe_unused) {
284 ND_LOG_STACK lgs[] = {
285 ND_LOG_FIELD_TXT(NDF_SRC_TRANSPORT, "webrtc"),
286 ND_LOG_FIELD_END(),
287 };
288 ND_LOG_STACK_PUSH(lgs);
289
290 internal_error(true, "WEBRTC[%d],DC[%d]: got request '%s' of size %zu and type %s.",
291 chan->conn->pc, chan->dc, request, size, binary?"binary":"text");
292
293 struct web_client *w = web_client_get_from_cache();
294 w->statistics.received_bytes = size;
295 w->interrupt.callback = web_client_stop_callback;
296 w->interrupt.callback_data = chan;
297 web_client_set_conn_webrtc(w);
298
299 w->port_acl = HTTP_ACL_WEBRTC | HTTP_ACL_ALL_FEATURES;
300 w->acl = w->port_acl;
301
302 char *path = (char *)request;
303 if(strncmp(request, "POST ", 5) == 0) {
304 w->mode = HTTP_REQUEST_MODE_POST;
305 path += 10;
306 }
307 else if(strncmp(request, "GET ", 4) == 0) {
308 w->mode = HTTP_REQUEST_MODE_GET;
309 path += 4;
310 }
311
312 web_client_timeout_checkpoint_set(w, 0);
313 web_client_decode_path_and_query_string(w, path);
314 path = (char *)buffer_tostring(w->url_path_decoded);
315
316 w->response.code = (short)web_client_api_request_with_node_selection(localhost, w, path);
317 web_client_timeout_checkpoint_response_ready(w, NULL);
318
319 size_t sent_bytes = 0;
320 size_t response_size = buffer_strlen(w->response.data);
321
322 bool send_plain = true;
323 int max_message_size = (int)chan->conn->max_message_size - WEBRTC_COMPRESSED_HEADER_SIZE;
324
325 if(!webrtc_dc_is_open(chan)) {
326 internal_error(true, "WEBRTC[%d],DC[%d]: ignoring API response on closed data channel.", chan->conn->pc, chan->dc);
327 goto cleanup;
328 }
329 else {
330 internal_error(true, "WEBRTC[%d],DC[%d]: prepared response with code %d, size %zu.",
331 chan->conn->pc, chan->dc, w->response.code, response_size);
332 }
333
334 #if defined(ENABLE_LZ4)
335 int max_compressed_size = LZ4_compressBound((int)response_size);
336 char *compressed = mallocz(max_compressed_size);
337
338 int compressed_size = LZ4_compress_default(buffer_tostring(w->response.data), compressed,
339 (int)response_size, max_compressed_size);
340
341 if(compressed_size > 0) {
342 send_plain = false;
343 sent_bytes = webrtc_send_in_chunks(chan, compressed, compressed_size,
344 w->response.code, "LZ4", w->response.data->content_type,
345 max_message_size, true);
346 }
347 freez(compressed);
348 #endif
349
350 if(send_plain)
351 sent_bytes = webrtc_send_in_chunks(chan, buffer_tostring(w->response.data), buffer_strlen(w->response.data),
352 w->response.code, "PLAIN", w->response.data->content_type,
353 max_message_size, false);
354
355 w->statistics.sent_bytes = sent_bytes;
356
357 cleanup:
358 web_client_log_completed_request(w, false);
359 web_client_release_to_cache(w);
360 }
361
362 // ----------------------------------------------------------------------------
363 // webrtc data channel
364
365 static void myOpenCallback(int id __maybe_unused, void *user_ptr) {
366 webrtc_set_thread_name();
367
368 WEBRTC_DC *chan = user_ptr;
369 internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
370
371 nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d],DC[%d]: %d DATA CHANNEL '%s' OPEN", chan->conn->pc, chan->dc, gettid_cached(), chan->label);
372 internal_error(true, "WEBRTC[%d],DC[%d]: data channel opened.", chan->conn->pc, chan->dc);
373 chan->open = true;
374 }
375
376 static void myClosedCallback(int id __maybe_unused, void *user_ptr) {
377 webrtc_set_thread_name();
378
379 WEBRTC_DC *chan = user_ptr;
380 internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
381
382 __atomic_store_n(&chan->open, false, __ATOMIC_RELAXED);
383 internal_error(true, "WEBRTC[%d],DC[%d]: data channel closed.", chan->conn->pc, chan->dc);
384
385 spinlock_lock(&chan->conn->channels.spinlock);
386 DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(chan->conn->channels.head, chan, link.prev, link.next);
387 spinlock_unlock(&chan->conn->channels.spinlock);
388
389 nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d],DC[%d]: %d DATA CHANNEL '%s' CLOSED", chan->conn->pc, chan->dc, gettid_cached(), chan->label);
390
391 freez(chan->label);
392 freez(chan);
393 }
394
395 static void myErrorCallback(int id __maybe_unused, const char *error, void *user_ptr) {
396 webrtc_set_thread_name();
397
398 WEBRTC_DC *chan = user_ptr;
399 internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
400
401 netdata_log_error("WEBRTC[%d],DC[%d]: ERROR: '%s'", chan->conn->pc, chan->dc, error);
402 }
403
404 static void myMessageCallback(int id __maybe_unused, const char *message, int size, void *user_ptr) {
405 webrtc_set_thread_name();
406
407 WEBRTC_DC *chan = user_ptr;
408 internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
409 internal_fatal(!webrtc_dc_is_open(chan), "WEBRTC[%d],DC[%d]: received message on closed channel", chan->conn->pc, chan->dc);
410
411 bool binary = (size >= 0);
412 if(size < 0)
413 size = -size;
414
415 webrtc_execute_api_request(chan, message, size, binary);
416 }
417
418 //#define WEBRTC_MAX_REQUEST_SIZE 65536
419 //
420 //static void myAvailableCallback(int id, void *user_ptr) {
421 // webrtc_set_thread_name();
422 //
423 // WEBRTC_DC *chan = user_ptr;
424 // internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
425 //
426 // internal_fatal(!chan->open, "WEBRTC[%d],DC[%d]: received message on closed channel", chan->conn->pc, chan->dc);
427 //
428 // int size = WEBRTC_MAX_REQUEST_SIZE;
429 // char buffer[WEBRTC_MAX_REQUEST_SIZE];
430 // while(rtcReceiveMessage(id, buffer, &size) == RTC_ERR_SUCCESS) {
431 // bool binary = (size >= 0);
432 // if(size < 0)
433 // size = -size;
434 //
435 // webrtc_execute_api_request(chan, message, size, binary);
436 // }
437 //}
438
439 static void myDataChannelCallback(int pc __maybe_unused, int dc, void *user_ptr) {
440 webrtc_set_thread_name();
441
442 WEBRTC_CONN *conn = user_ptr;
443 internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
444
445 WEBRTC_DC *chan = callocz(1, sizeof(WEBRTC_DC));
446 chan->dc = dc;
447 chan->conn = conn;
448
449 spinlock_lock(&conn->channels.spinlock);
450 DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(conn->channels.head, chan, link.prev, link.next);
451 spinlock_unlock(&conn->channels.spinlock);
452
453 rtcSetUserPointer(dc, chan);
454
455 char label[1024 + 1];
456 rtcGetDataChannelLabel(dc, label, 1024);
457 label[1024] = '\0';
458
459 chan->label = strdupz(label);
460
461 if(rtcSetOpenCallback(dc, myOpenCallback) != RTC_ERR_SUCCESS)
462 netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetOpenCallback() failed.", conn->pc, chan->dc);
463
464 if(rtcSetClosedCallback(dc, myClosedCallback) != RTC_ERR_SUCCESS)
465 netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetClosedCallback() failed.", conn->pc, chan->dc);
466
467 if(rtcSetErrorCallback(dc, myErrorCallback) != RTC_ERR_SUCCESS)
468 netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetErrorCallback() failed.", conn->pc, chan->dc);
469
470 if(rtcSetMessageCallback(dc, myMessageCallback) != RTC_ERR_SUCCESS)
471 netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetMessageCallback() failed.", conn->pc, chan->dc);
472
473 // if(rtcSetAvailableCallback(dc, myAvailableCallback) != RTC_ERR_SUCCESS)
474 // netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetAvailableCallback() failed.", conn->pc, chan->dc);
475
476 internal_error(true, "WEBRTC[%d],DC[%d]: new data channel with label '%s'", chan->conn->pc, chan->dc, chan->label);
477 }
478
479 // ----------------------------------------------------------------------------
480 // webrtc connection
481
482 static inline void webrtc_destroy_connection_unsafe(WEBRTC_CONN *conn) {
483 if(conn->state == RTC_CLOSED) {
484 spinlock_lock(&conn->channels.spinlock);
485 WEBRTC_DC *chan = conn->channels.head;
486 spinlock_unlock(&conn->channels.spinlock);
487
488 if(!chan) {
489 internal_error(true, "WEBRTC[%d]: destroying connection", conn->pc);
490 DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(webrtc_base.unsafe.head, conn, link.prev, link.next);
491 freez(conn);
492 }
493 else {
494 internal_error(true, "WEBRTC[%d]: not destroying closed connection because it has data channels running", conn->pc);
495 }
496 }
497 }
498
499 static void cleanupConnections() {
500 spinlock_lock(&webrtc_base.unsafe.spinlock);
501 WEBRTC_CONN *conn = webrtc_base.unsafe.head;
502 while(conn) {
503 WEBRTC_CONN *conn_next = conn->link.next;
504 webrtc_destroy_connection_unsafe(conn);
505 conn = conn_next;
506 }
507 spinlock_unlock(&webrtc_base.unsafe.spinlock);
508 }
509
510 static WEBRTC_CONN * webrtc_create_connection(void) {
511 WEBRTC_CONN *conn = callocz(1, sizeof(WEBRTC_CONN));
512
513 spinlock_init(&conn->response.spinlock);
514 spinlock_init(&conn->channels.spinlock);
515
516 spinlock_lock(&webrtc_base.unsafe.spinlock);
517 DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(webrtc_base.unsafe.head, conn, link.prev, link.next);
518 spinlock_unlock(&webrtc_base.unsafe.spinlock);
519 return conn;
520 }
521
522 static void myDescriptionCallback(int pc __maybe_unused, const char *sdp, const char *type, void *user_ptr) {
523 webrtc_set_thread_name();
524
525 WEBRTC_CONN *conn = user_ptr;
526 internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
527
528 internal_error(true, "WEBRTC[%d]: local description type '%s': %s", conn->pc, type, sdp);
529 spinlock_lock(&conn->response.spinlock);
530 if(!conn->response.candidates) {
531 buffer_json_member_add_string(conn->response.wb, "sdp", sdp);
532 buffer_json_member_add_string(conn->response.wb, "type", type);
533 conn->response.sdp = true;
534 }
535 spinlock_unlock(&conn->response.spinlock);
536
537 conn->local_max_message_size = find_max_message_size_in_sdp(sdp);
538 }
539
540 static void myCandidateCallback(int pc __maybe_unused, const char *cand, const char *mid __maybe_unused, void *user_ptr) {
541 webrtc_set_thread_name();
542
543 WEBRTC_CONN *conn = user_ptr;
544 internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
545
546 spinlock_lock(&conn->response.spinlock);
547 if(!conn->response.candidates) {
548 buffer_json_member_add_array(conn->response.wb, "candidates");
549 conn->response.candidates = true;
550 }
551
552 internal_error(true, "WEBRTC[%d]: local candidate '%s', mid '%s'", conn->pc, cand, mid);
553 buffer_json_add_array_item_string(conn->response.wb, cand);
554 spinlock_unlock(&conn->response.spinlock);
555 }
556
557 static void myStateChangeCallback(int pc __maybe_unused, rtcState state, void *user_ptr) {
558 webrtc_set_thread_name();
559
560 WEBRTC_CONN *conn = user_ptr;
561 internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
562
563 conn->state = state;
564
565 switch(state) {
566 case RTC_NEW:
567 internal_error(true, "WEBRTC[%d]: new connection...", conn->pc);
568 break;
569
570 case RTC_CONNECTING:
571 nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTING", conn->pc, gettid_cached());
572 internal_error(true, "WEBRTC[%d]: connecting...", conn->pc);
573 break;
574
575 case RTC_CONNECTED:
576 nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTED", conn->pc, gettid_cached());
577 internal_error(true, "WEBRTC[%d]: connected!", conn->pc);
578 break;
579
580 case RTC_DISCONNECTED:
581 nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d DISCONNECTED", conn->pc, gettid_cached());
582 internal_error(true, "WEBRTC[%d]: disconnected.", conn->pc);
583 break;
584
585 case RTC_FAILED:
586 nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTION FAILED", conn->pc, gettid_cached());
587 internal_error(true, "WEBRTC[%d]: failed.", conn->pc);
588 break;
589
590 case RTC_CLOSED:
591 nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTION CLOSED", conn->pc, gettid_cached());
592 internal_error(true, "WEBRTC[%d]: closed.", conn->pc);
593 spinlock_lock(&webrtc_base.unsafe.spinlock);
594 webrtc_destroy_connection_unsafe(conn);
595 spinlock_unlock(&webrtc_base.unsafe.spinlock);
596 break;
597 }
598 }
599
600 static void myGatheringStateCallback(int pc __maybe_unused, rtcGatheringState state, void *user_ptr) {
601 webrtc_set_thread_name();
602
603 WEBRTC_CONN *conn = user_ptr;
604 internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
605
606 conn->gathering_state = state;
607
608 switch(state) {
609 case RTC_GATHERING_NEW:
610 internal_error(true, "WEBRTC[%d]: gathering...", conn->pc);
611 break;
612
613 case RTC_GATHERING_INPROGRESS:
614 internal_error(true, "WEBRTC[%d]: gathering in progress...", conn->pc);
615 break;
616
617 case RTC_GATHERING_COMPLETE:
618 internal_error(true, "WEBRTC[%d]: gathering complete!", conn->pc);
619 break;
620 }
621 }
622
623 int webrtc_new_connection(const char *sdp, BUFFER *wb) {
624 if(unlikely(!webrtc_base.enabled)) {
625 buffer_flush(wb);
626 buffer_strcat(wb, "WebRTC is not enabled on this agent.");
627 wb->content_type = CT_TEXT_PLAIN;
628 return HTTP_RESP_BAD_REQUEST;
629 }
630
631 cleanupConnections();
632
633 if(unlikely(!sdp || !*sdp)) {
634 buffer_flush(wb);
635 buffer_strcat(wb, "No SDP message posted with the request");
636 wb->content_type = CT_TEXT_PLAIN;
637 return HTTP_RESP_BAD_REQUEST;
638 }
639
640 buffer_flush(wb);
641 buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
642 wb->content_type = CT_APPLICATION_JSON;
643
644 WEBRTC_CONN *conn = webrtc_create_connection();
645 conn->response.wb = wb;
646 conn->max_message_size = WEBRTC_DEFAULT_REMOTE_MAX_MESSAGE_SIZE;
647 conn->local_max_message_size = WEBRTC_OUR_MAX_MESSAGE_SIZE;
648 conn->remote_max_message_size = find_max_message_size_in_sdp(sdp);
649
650 conn->config.iceServers = (const char **)webrtc_base.iceServers;
651 conn->config.iceServersCount = webrtc_base.iceServersCount;
652 conn->config.proxyServer = webrtc_base.proxyServer;
653 conn->config.bindAddress = webrtc_base.bindAddress;
654 conn->config.certificateType = RTC_CERTIFICATE_DEFAULT;
655 conn->config.iceTransportPolicy = RTC_TRANSPORT_POLICY_ALL;
656 conn->config.enableIceTcp = true; // libnice only
657 conn->config.enableIceUdpMux = true; // libjuice only
658 conn->config.disableAutoNegotiation = false;
659 conn->config.forceMediaTransport = false;
660 conn->config.portRangeBegin = 0; // 0 means automatic
661 conn->config.portRangeEnd = 0; // 0 means automatic
662 conn->config.mtu = 0; // <= 0 means automatic
663 conn->config.maxMessageSize = WEBRTC_OUR_MAX_MESSAGE_SIZE; // <= 0 means default
664
665 conn->pc = rtcCreatePeerConnection(&conn->config);
666 rtcSetUserPointer(conn->pc, conn);
667
668 if(rtcSetLocalDescriptionCallback(conn->pc, myDescriptionCallback) != RTC_ERR_SUCCESS)
669 netdata_log_error("WEBRTC[%d]: rtcSetLocalDescriptionCallback() failed", conn->pc);
670
671 if(rtcSetLocalCandidateCallback(conn->pc, myCandidateCallback) != RTC_ERR_SUCCESS)
672 netdata_log_error("WEBRTC[%d]: rtcSetLocalCandidateCallback() failed", conn->pc);
673
674 if(rtcSetStateChangeCallback(conn->pc, myStateChangeCallback) != RTC_ERR_SUCCESS)
675 netdata_log_error("WEBRTC[%d]: rtcSetStateChangeCallback() failed", conn->pc);
676
677 if(rtcSetGatheringStateChangeCallback(conn->pc, myGatheringStateCallback) != RTC_ERR_SUCCESS)
678 netdata_log_error("WEBRTC[%d]: rtcSetGatheringStateChangeCallback() failed", conn->pc);
679
680 if(rtcSetDataChannelCallback(conn->pc, myDataChannelCallback) != RTC_ERR_SUCCESS)
681 netdata_log_error("WEBRTC[%d]: rtcSetDataChannelCallback() failed", conn->pc);
682
683 // initialize the handshake
684 internal_error(true, "WEBRTC[%d]: setting remote sdp: %s", conn->pc, sdp);
685 if(rtcSetRemoteDescription(conn->pc, sdp, "offer") != RTC_ERR_SUCCESS)
686 netdata_log_error("WEBRTC[%d]: rtcSetRemoteDescription() failed", conn->pc);
687
688 // initiate the handshake process
689 if(conn->config.disableAutoNegotiation) {
690 if(rtcSetLocalDescription(conn->pc, NULL) != RTC_ERR_SUCCESS)
691 netdata_log_error("WEBRTC[%d]: rtcSetLocalDescription() failed", conn->pc);
692 }
693
694 bool logged = false;
695 while(conn->gathering_state != RTC_GATHERING_COMPLETE) {
696 if(!logged) {
697 logged = true;
698 internal_error(true, "WEBRTC[%d]: Waiting for gathering to complete", conn->pc);
699 }
700 sleep_usec(1000);
701 }
702
703 if(logged)
704 internal_error(true, "WEBRTC[%d]: Gathering finished, our answer is ready", conn->pc);
705
706 internal_fatal(!conn->response.sdp, "WEBRTC[%d]: response does not have an SDP: %s", conn->pc, buffer_tostring(conn->response.wb));
707 internal_fatal(!conn->response.candidates, "WEBRTC[%d]: response does not have candidates: %s", conn->pc, buffer_tostring(conn->response.wb));
708
709 conn->max_message_size = MIN(conn->local_max_message_size, conn->remote_max_message_size);
710 if(conn->max_message_size < WEBRTC_COMPRESSED_HEADER_SIZE)
711 conn->max_message_size = WEBRTC_COMPRESSED_HEADER_SIZE;
712
713 buffer_json_finalize(wb);
714
715 return HTTP_RESP_OK;
716 }
717
718 #else // ! HAVE_LIBDATACHANNEL
719
720 void webrtc_initialize() {
721 ;
722 }
723
724 int webrtc_new_connection(const char *sdp __maybe_unused, BUFFER *wb) {
725 buffer_flush(wb);
726 buffer_strcat(wb, "WEBRTC is not available on this server");
727 wb->content_type = CT_TEXT_PLAIN;
728 return HTTP_RESP_BAD_REQUEST;
729 }
730
731 void webrtc_close_all_connections() {
732 ;
733 }
734
735 #endif // ! HAVE_LIBDATACHANNEL