webrtc.c 26 KB

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