webrtc.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  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. web_client_set_conn_webrtc(w);
  232. w->acl = HTTP_ACL_WEBRTC;
  233. char *path = (char *)request;
  234. if(strncmp(request, "POST ", 5) == 0) {
  235. w->mode = HTTP_REQUEST_MODE_POST;
  236. path += 10;
  237. }
  238. else if(strncmp(request, "GET ", 4) == 0) {
  239. w->mode = HTTP_REQUEST_MODE_GET;
  240. path += 4;
  241. }
  242. web_client_timeout_checkpoint_set(w, 0);
  243. web_client_decode_path_and_query_string(w, path);
  244. path = (char *)buffer_tostring(w->url_path_decoded);
  245. w->response.code = (short)web_client_api_request_with_node_selection(localhost, w, path);
  246. web_client_timeout_checkpoint_response_ready(w, NULL);
  247. size_t sent_bytes = 0;
  248. size_t response_size = buffer_strlen(w->response.data);
  249. bool send_plain = true;
  250. int max_message_size = (int)chan->conn->max_message_size - WEBRTC_COMPRESSED_HEADER_SIZE;
  251. if(!webrtc_dc_is_open(chan)) {
  252. internal_error(true, "WEBRTC[%d],DC[%d]: ignoring API response on closed data channel.", chan->conn->pc, chan->dc);
  253. goto cleanup;
  254. }
  255. else {
  256. internal_error(true, "WEBRTC[%d],DC[%d]: prepared response with code %d, size %zu.",
  257. chan->conn->pc, chan->dc, w->response.code, response_size);
  258. }
  259. #if defined(ENABLE_LZ4)
  260. int max_compressed_size = LZ4_compressBound((int)response_size);
  261. char *compressed = mallocz(max_compressed_size);
  262. int compressed_size = LZ4_compress_default(buffer_tostring(w->response.data), compressed,
  263. (int)response_size, max_compressed_size);
  264. if(compressed_size > 0) {
  265. send_plain = false;
  266. sent_bytes = webrtc_send_in_chunks(chan, compressed, compressed_size,
  267. w->response.code, "LZ4", w->response.data->content_type,
  268. max_message_size, true);
  269. }
  270. freez(compressed);
  271. #endif
  272. if(send_plain)
  273. sent_bytes = webrtc_send_in_chunks(chan, buffer_tostring(w->response.data), buffer_strlen(w->response.data),
  274. w->response.code, "PLAIN", w->response.data->content_type,
  275. max_message_size, false);
  276. w->statistics.sent_bytes = sent_bytes;
  277. cleanup:
  278. web_client_log_completed_request(w, false);
  279. web_client_release_to_cache(w);
  280. }
  281. // ----------------------------------------------------------------------------
  282. // webrtc data channel
  283. static void myOpenCallback(int id __maybe_unused, void *user_ptr) {
  284. webrtc_set_thread_name();
  285. WEBRTC_DC *chan = user_ptr;
  286. internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
  287. nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d],DC[%d]: %d DATA CHANNEL '%s' OPEN", chan->conn->pc, chan->dc, gettid(), chan->label);
  288. internal_error(true, "WEBRTC[%d],DC[%d]: data channel opened.", chan->conn->pc, chan->dc);
  289. chan->open = true;
  290. }
  291. static void myClosedCallback(int id __maybe_unused, void *user_ptr) {
  292. webrtc_set_thread_name();
  293. WEBRTC_DC *chan = user_ptr;
  294. internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
  295. __atomic_store_n(&chan->open, false, __ATOMIC_RELAXED);
  296. internal_error(true, "WEBRTC[%d],DC[%d]: data channel closed.", chan->conn->pc, chan->dc);
  297. spinlock_lock(&chan->conn->channels.spinlock);
  298. DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(chan->conn->channels.head, chan, link.prev, link.next);
  299. spinlock_unlock(&chan->conn->channels.spinlock);
  300. nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d],DC[%d]: %d DATA CHANNEL '%s' CLOSED", chan->conn->pc, chan->dc, gettid(), chan->label);
  301. freez(chan->label);
  302. freez(chan);
  303. }
  304. static void myErrorCallback(int id __maybe_unused, const char *error, void *user_ptr) {
  305. webrtc_set_thread_name();
  306. WEBRTC_DC *chan = user_ptr;
  307. internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
  308. netdata_log_error("WEBRTC[%d],DC[%d]: ERROR: '%s'", chan->conn->pc, chan->dc, error);
  309. }
  310. static void myMessageCallback(int id __maybe_unused, const char *message, int size, void *user_ptr) {
  311. webrtc_set_thread_name();
  312. WEBRTC_DC *chan = user_ptr;
  313. internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
  314. internal_fatal(!webrtc_dc_is_open(chan), "WEBRTC[%d],DC[%d]: received message on closed channel", chan->conn->pc, chan->dc);
  315. bool binary = (size >= 0);
  316. if(size < 0)
  317. size = -size;
  318. webrtc_execute_api_request(chan, message, size, binary);
  319. }
  320. //#define WEBRTC_MAX_REQUEST_SIZE 65536
  321. //
  322. //static void myAvailableCallback(int id, void *user_ptr) {
  323. // webrtc_set_thread_name();
  324. //
  325. // WEBRTC_DC *chan = user_ptr;
  326. // internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
  327. //
  328. // internal_fatal(!chan->open, "WEBRTC[%d],DC[%d]: received message on closed channel", chan->conn->pc, chan->dc);
  329. //
  330. // int size = WEBRTC_MAX_REQUEST_SIZE;
  331. // char buffer[WEBRTC_MAX_REQUEST_SIZE];
  332. // while(rtcReceiveMessage(id, buffer, &size) == RTC_ERR_SUCCESS) {
  333. // bool binary = (size >= 0);
  334. // if(size < 0)
  335. // size = -size;
  336. //
  337. // webrtc_execute_api_request(chan, message, size, binary);
  338. // }
  339. //}
  340. static void myDataChannelCallback(int pc __maybe_unused, int dc, void *user_ptr) {
  341. webrtc_set_thread_name();
  342. WEBRTC_CONN *conn = user_ptr;
  343. internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
  344. WEBRTC_DC *chan = callocz(1, sizeof(WEBRTC_DC));
  345. chan->dc = dc;
  346. chan->conn = conn;
  347. spinlock_lock(&conn->channels.spinlock);
  348. DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(conn->channels.head, chan, link.prev, link.next);
  349. spinlock_unlock(&conn->channels.spinlock);
  350. rtcSetUserPointer(dc, chan);
  351. char label[1024 + 1];
  352. rtcGetDataChannelLabel(dc, label, 1024);
  353. label[1024] = '\0';
  354. chan->label = strdupz(label);
  355. if(rtcSetOpenCallback(dc, myOpenCallback) != RTC_ERR_SUCCESS)
  356. netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetOpenCallback() failed.", conn->pc, chan->dc);
  357. if(rtcSetClosedCallback(dc, myClosedCallback) != RTC_ERR_SUCCESS)
  358. netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetClosedCallback() failed.", conn->pc, chan->dc);
  359. if(rtcSetErrorCallback(dc, myErrorCallback) != RTC_ERR_SUCCESS)
  360. netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetErrorCallback() failed.", conn->pc, chan->dc);
  361. if(rtcSetMessageCallback(dc, myMessageCallback) != RTC_ERR_SUCCESS)
  362. netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetMessageCallback() failed.", conn->pc, chan->dc);
  363. // if(rtcSetAvailableCallback(dc, myAvailableCallback) != RTC_ERR_SUCCESS)
  364. // netdata_log_error("WEBRTC[%d],DC[%d]: rtcSetAvailableCallback() failed.", conn->pc, chan->dc);
  365. internal_error(true, "WEBRTC[%d],DC[%d]: new data channel with label '%s'", chan->conn->pc, chan->dc, chan->label);
  366. }
  367. // ----------------------------------------------------------------------------
  368. // webrtc connection
  369. static inline void webrtc_destroy_connection_unsafe(WEBRTC_CONN *conn) {
  370. if(conn->state == RTC_CLOSED) {
  371. spinlock_lock(&conn->channels.spinlock);
  372. WEBRTC_DC *chan = conn->channels.head;
  373. spinlock_unlock(&conn->channels.spinlock);
  374. if(!chan) {
  375. internal_error(true, "WEBRTC[%d]: destroying connection", conn->pc);
  376. DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(webrtc_base.unsafe.head, conn, link.prev, link.next);
  377. freez(conn);
  378. }
  379. else {
  380. internal_error(true, "WEBRTC[%d]: not destroying closed connection because it has data channels running", conn->pc);
  381. }
  382. }
  383. }
  384. static void cleanupConnections() {
  385. spinlock_lock(&webrtc_base.unsafe.spinlock);
  386. WEBRTC_CONN *conn = webrtc_base.unsafe.head;
  387. while(conn) {
  388. WEBRTC_CONN *conn_next = conn->link.next;
  389. webrtc_destroy_connection_unsafe(conn);
  390. conn = conn_next;
  391. }
  392. spinlock_unlock(&webrtc_base.unsafe.spinlock);
  393. }
  394. static WEBRTC_CONN *webrtc_create_connection(void) {
  395. WEBRTC_CONN *conn = callocz(1, sizeof(WEBRTC_CONN));
  396. spinlock_init(&conn->response.spinlock);
  397. spinlock_init(&conn->channels.spinlock);
  398. spinlock_lock(&webrtc_base.unsafe.spinlock);
  399. DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(webrtc_base.unsafe.head, conn, link.prev, link.next);
  400. spinlock_unlock(&webrtc_base.unsafe.spinlock);
  401. return conn;
  402. }
  403. static void myDescriptionCallback(int pc __maybe_unused, const char *sdp, const char *type, void *user_ptr) {
  404. webrtc_set_thread_name();
  405. WEBRTC_CONN *conn = user_ptr;
  406. internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
  407. internal_error(true, "WEBRTC[%d]: local description type '%s': %s", conn->pc, type, sdp);
  408. spinlock_lock(&conn->response.spinlock);
  409. if(!conn->response.candidates) {
  410. buffer_json_member_add_string(conn->response.wb, "sdp", sdp);
  411. buffer_json_member_add_string(conn->response.wb, "type", type);
  412. conn->response.sdp = true;
  413. }
  414. spinlock_unlock(&conn->response.spinlock);
  415. conn->local_max_message_size = find_max_message_size_in_sdp(sdp);
  416. }
  417. static void myCandidateCallback(int pc __maybe_unused, const char *cand, const char *mid __maybe_unused, void *user_ptr) {
  418. webrtc_set_thread_name();
  419. WEBRTC_CONN *conn = user_ptr;
  420. internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
  421. spinlock_lock(&conn->response.spinlock);
  422. if(!conn->response.candidates) {
  423. buffer_json_member_add_array(conn->response.wb, "candidates");
  424. conn->response.candidates = true;
  425. }
  426. internal_error(true, "WEBRTC[%d]: local candidate '%s', mid '%s'", conn->pc, cand, mid);
  427. buffer_json_add_array_item_string(conn->response.wb, cand);
  428. spinlock_unlock(&conn->response.spinlock);
  429. }
  430. static void myStateChangeCallback(int pc __maybe_unused, rtcState state, void *user_ptr) {
  431. webrtc_set_thread_name();
  432. WEBRTC_CONN *conn = user_ptr;
  433. internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
  434. conn->state = state;
  435. switch(state) {
  436. case RTC_NEW:
  437. internal_error(true, "WEBRTC[%d]: new connection...", conn->pc);
  438. break;
  439. case RTC_CONNECTING:
  440. nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTING", conn->pc, gettid());
  441. internal_error(true, "WEBRTC[%d]: connecting...", conn->pc);
  442. break;
  443. case RTC_CONNECTED:
  444. nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTED", conn->pc, gettid());
  445. internal_error(true, "WEBRTC[%d]: connected!", conn->pc);
  446. break;
  447. case RTC_DISCONNECTED:
  448. nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d DISCONNECTED", conn->pc, gettid());
  449. internal_error(true, "WEBRTC[%d]: disconnected.", conn->pc);
  450. break;
  451. case RTC_FAILED:
  452. nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTION FAILED", conn->pc, gettid());
  453. internal_error(true, "WEBRTC[%d]: failed.", conn->pc);
  454. break;
  455. case RTC_CLOSED:
  456. nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTION CLOSED", conn->pc, gettid());
  457. internal_error(true, "WEBRTC[%d]: closed.", conn->pc);
  458. spinlock_lock(&webrtc_base.unsafe.spinlock);
  459. webrtc_destroy_connection_unsafe(conn);
  460. spinlock_unlock(&webrtc_base.unsafe.spinlock);
  461. break;
  462. }
  463. }
  464. static void myGatheringStateCallback(int pc __maybe_unused, rtcGatheringState state, void *user_ptr) {
  465. webrtc_set_thread_name();
  466. WEBRTC_CONN *conn = user_ptr;
  467. internal_fatal(conn->pc != pc, "WEBRTC[%d]: pc mismatch, expected %d, got %d", conn->pc, conn->pc, pc);
  468. conn->gathering_state = state;
  469. switch(state) {
  470. case RTC_GATHERING_NEW:
  471. internal_error(true, "WEBRTC[%d]: gathering...", conn->pc);
  472. break;
  473. case RTC_GATHERING_INPROGRESS:
  474. internal_error(true, "WEBRTC[%d]: gathering in progress...", conn->pc);
  475. break;
  476. case RTC_GATHERING_COMPLETE:
  477. internal_error(true, "WEBRTC[%d]: gathering complete!", conn->pc);
  478. break;
  479. }
  480. }
  481. int webrtc_new_connection(const char *sdp, BUFFER *wb) {
  482. if(unlikely(!webrtc_base.enabled)) {
  483. buffer_flush(wb);
  484. buffer_strcat(wb, "WebRTC is not enabled on this agent.");
  485. wb->content_type = CT_TEXT_PLAIN;
  486. return HTTP_RESP_BAD_REQUEST;
  487. }
  488. cleanupConnections();
  489. if(unlikely(!sdp || !*sdp)) {
  490. buffer_flush(wb);
  491. buffer_strcat(wb, "No SDP message posted with the request");
  492. wb->content_type = CT_TEXT_PLAIN;
  493. return HTTP_RESP_BAD_REQUEST;
  494. }
  495. buffer_flush(wb);
  496. buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
  497. wb->content_type = CT_APPLICATION_JSON;
  498. WEBRTC_CONN *conn = webrtc_create_connection();
  499. conn->response.wb = wb;
  500. conn->max_message_size = WEBRTC_DEFAULT_REMOTE_MAX_MESSAGE_SIZE;
  501. conn->local_max_message_size = WEBRTC_OUR_MAX_MESSAGE_SIZE;
  502. conn->remote_max_message_size = find_max_message_size_in_sdp(sdp);
  503. conn->config.iceServers = (const char **)webrtc_base.iceServers;
  504. conn->config.iceServersCount = webrtc_base.iceServersCount;
  505. conn->config.proxyServer = webrtc_base.proxyServer;
  506. conn->config.bindAddress = webrtc_base.bindAddress;
  507. conn->config.certificateType = RTC_CERTIFICATE_DEFAULT;
  508. conn->config.iceTransportPolicy = RTC_TRANSPORT_POLICY_ALL;
  509. conn->config.enableIceTcp = true; // libnice only
  510. conn->config.enableIceUdpMux = true; // libjuice only
  511. conn->config.disableAutoNegotiation = false;
  512. conn->config.forceMediaTransport = false;
  513. conn->config.portRangeBegin = 0; // 0 means automatic
  514. conn->config.portRangeEnd = 0; // 0 means automatic
  515. conn->config.mtu = 0; // <= 0 means automatic
  516. conn->config.maxMessageSize = WEBRTC_OUR_MAX_MESSAGE_SIZE; // <= 0 means default
  517. conn->pc = rtcCreatePeerConnection(&conn->config);
  518. rtcSetUserPointer(conn->pc, conn);
  519. if(rtcSetLocalDescriptionCallback(conn->pc, myDescriptionCallback) != RTC_ERR_SUCCESS)
  520. netdata_log_error("WEBRTC[%d]: rtcSetLocalDescriptionCallback() failed", conn->pc);
  521. if(rtcSetLocalCandidateCallback(conn->pc, myCandidateCallback) != RTC_ERR_SUCCESS)
  522. netdata_log_error("WEBRTC[%d]: rtcSetLocalCandidateCallback() failed", conn->pc);
  523. if(rtcSetStateChangeCallback(conn->pc, myStateChangeCallback) != RTC_ERR_SUCCESS)
  524. netdata_log_error("WEBRTC[%d]: rtcSetStateChangeCallback() failed", conn->pc);
  525. if(rtcSetGatheringStateChangeCallback(conn->pc, myGatheringStateCallback) != RTC_ERR_SUCCESS)
  526. netdata_log_error("WEBRTC[%d]: rtcSetGatheringStateChangeCallback() failed", conn->pc);
  527. if(rtcSetDataChannelCallback(conn->pc, myDataChannelCallback) != RTC_ERR_SUCCESS)
  528. netdata_log_error("WEBRTC[%d]: rtcSetDataChannelCallback() failed", conn->pc);
  529. // initialize the handshake
  530. internal_error(true, "WEBRTC[%d]: setting remote sdp: %s", conn->pc, sdp);
  531. if(rtcSetRemoteDescription(conn->pc, sdp, "offer") != RTC_ERR_SUCCESS)
  532. netdata_log_error("WEBRTC[%d]: rtcSetRemoteDescription() failed", conn->pc);
  533. // initiate the handshake process
  534. if(conn->config.disableAutoNegotiation) {
  535. if(rtcSetLocalDescription(conn->pc, NULL) != RTC_ERR_SUCCESS)
  536. netdata_log_error("WEBRTC[%d]: rtcSetLocalDescription() failed", conn->pc);
  537. }
  538. bool logged = false;
  539. while(conn->gathering_state != RTC_GATHERING_COMPLETE) {
  540. if(!logged) {
  541. logged = true;
  542. internal_error(true, "WEBRTC[%d]: Waiting for gathering to complete", conn->pc);
  543. }
  544. usleep(1000);
  545. }
  546. if(logged)
  547. internal_error(true, "WEBRTC[%d]: Gathering finished, our answer is ready", conn->pc);
  548. internal_fatal(!conn->response.sdp, "WEBRTC[%d]: response does not have an SDP: %s", conn->pc, buffer_tostring(conn->response.wb));
  549. internal_fatal(!conn->response.candidates, "WEBRTC[%d]: response does not have candidates: %s", conn->pc, buffer_tostring(conn->response.wb));
  550. conn->max_message_size = MIN(conn->local_max_message_size, conn->remote_max_message_size);
  551. if(conn->max_message_size < WEBRTC_COMPRESSED_HEADER_SIZE)
  552. conn->max_message_size = WEBRTC_COMPRESSED_HEADER_SIZE;
  553. buffer_json_finalize(wb);
  554. return HTTP_RESP_OK;
  555. }
  556. #else // ! HAVE_LIBDATACHANNEL
  557. void webrtc_initialize() {
  558. ;
  559. }
  560. int webrtc_new_connection(const char *sdp __maybe_unused, BUFFER *wb) {
  561. buffer_flush(wb);
  562. buffer_strcat(wb, "WEBRTC is not available on this server");
  563. wb->content_type = CT_TEXT_PLAIN;
  564. return HTTP_RESP_BAD_REQUEST;
  565. }
  566. void webrtc_close_all_connections() {
  567. ;
  568. }
  569. #endif // ! HAVE_LIBDATACHANNEL