From 6c0f267e26db5b71d06e90f5884be08168baaf30 Mon Sep 17 00:00:00 2001 From: David Barksdale Date: Mon, 6 Jan 2020 18:03:07 -0600 Subject: WIP: WebRTC transport --- .../packages/gnunet/gnunet/files/configuration.js | 2 +- .../gnunet/gnunet/files/plugin_transport_webrtc.c | 96 +++++++++++++++++----- .../gnunet/files/plugin_transport_webrtc_int.js | 66 ++++++++++----- src/cljs/gnunet_web/service.cljs | 6 +- src/cljs/gnunet_web/webrtc.cljs | 68 +++++++++++++++ 5 files changed, 194 insertions(+), 44 deletions(-) create mode 100644 src/cljs/gnunet_web/webrtc.cljs diff --git a/gnunet-build/packages/gnunet/gnunet/files/configuration.js b/gnunet-build/packages/gnunet/gnunet/files/configuration.js index d67d53f..f227ec6 100644 --- a/gnunet-build/packages/gnunet/gnunet/files/configuration.js +++ b/gnunet-build/packages/gnunet/gnunet/files/configuration.js @@ -25,7 +25,7 @@ mergeInto(LibraryManager.library, { transport: { UNIXPATH: 'transport', NEIGHBOUR_LIMIT: 50, - PLUGINS: 'http_client', + PLUGINS: 'http_client webrtc', }, ats: { UNIXPATH: 'ats', diff --git a/gnunet-build/packages/gnunet/gnunet/files/plugin_transport_webrtc.c b/gnunet-build/packages/gnunet/gnunet/files/plugin_transport_webrtc.c index cea8633..f20e3b1 100644 --- a/gnunet-build/packages/gnunet/gnunet/files/plugin_transport_webrtc.c +++ b/gnunet-build/packages/gnunet/gnunet/files/plugin_transport_webrtc.c @@ -442,8 +442,25 @@ webrtc_plugin_string_to_address (void *cls, static void -create_offer_cb(void *cls, - char *offer) +offer_cb(void *cls, + char *offer) +{ + struct GNUNET_ATS_Session *s = cls; + struct GNUNET_MQ_Handle *mq = GNUNET_CADET_get_mq (s->channel); + size_t offer_len = strlen (offer); + struct GNUNET_MessageHeader *msg; + struct GNUNET_MQ_Envelope *env = GNUNET_MQ_msg_extra (msg, offer_len, MESSAGE_TYPE_WEBRTC_OFFER); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending our offer `%s'\n", + offer); + memcpy (&msg[1], offer, offer_len); + GNUNET_MQ_send (mq, env); +} + + +static void +message_cb(void *cls, uint8_t *data, int length) { struct GNUNET_ATS_Session *s = cls; GNUNET_break (0); @@ -466,6 +483,9 @@ check_answer (void *cls, } +extern void set_remote_answer(int, void *, int); + + /** * Functions with this signature are called whenever a complete answer * is received. @@ -478,6 +498,8 @@ handle_answer (void *cls, const struct GNUNET_MessageHeader *message) { struct GNUNET_ATS_Session *s = cls; + uint16_t size = ntohs(message->size); + set_remote_answer(s->rtc_peer_connection, &message[1], size - sizeof(*message)); GNUNET_break (0); } @@ -522,6 +544,7 @@ out_disconnect_cb (void *cls, GNUNET_break (0); } +extern int peer_connect(void *, void *, void *, void *, int, void *); /** * Create a new session to transmit data to the target @@ -571,20 +594,7 @@ webrtc_plugin_get_session (void *cls, out_disconnect_cb, handlers); GNUNET_assert (s->channel != NULL); - - extern int create_connection(void *, void *); - - s->rtc_peer_connection = create_connection(create_offer_cb, s); - /* Create RTCPeerConnection, call createOffer, when the returned promise is fulfilled, send it: - struct GNUNET_MessageHeader msg; - struct GNUNET_MQ_Envelope *env = GNUNET_MQ_msg (msg, MESSAGE_TYPE_WEBRTC_OFFER); - - GNUNET_MQ_notify_sent (env, - &transmit_pending, - mh); - GNUNET_MQ_send (mq, - env); - */ + s->rtc_peer_connection = peer_connect(offer_cb, NULL, message_cb, NULL, 0, s); notify_session_monitor (plugin, s, GNUNET_TRANSPORT_SS_INIT); @@ -661,6 +671,23 @@ webrtc_plugin_setup_monitor (void *cls, } +static void +answer_cb(void *cls, + char *answer) +{ + struct GNUNET_ATS_Session *s = cls; + struct GNUNET_MQ_Handle *mq = GNUNET_CADET_get_mq (s->channel); + size_t answer_len = strlen (answer); + struct GNUNET_MessageHeader *msg; + struct GNUNET_MQ_Envelope *env = GNUNET_MQ_msg_extra (msg, answer_len, MESSAGE_TYPE_WEBRTC_ANSWER); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending our answer `%s'\n", + answer); + memcpy (&msg[1], answer, answer_len); + GNUNET_MQ_send (mq, env); +} + /** * Check if payload is sane (size contains payload). * @@ -688,6 +715,12 @@ static void handle_offer (void *cls, const struct GNUNET_MessageHeader *message) { + struct GNUNET_ATS_Session *s = cls; // XXX right? + LOG (GNUNET_ERROR_TYPE_DEBUG, + "handle_offer called with session %p\n", + s); + uint16_t size = ntohs(message->size); + s->rtc_peer_connection = peer_connect(NULL, answer_cb, message_cb, &message[1], size - sizeof(*message), s); GNUNET_break (0); } @@ -699,15 +732,40 @@ handle_offer (void *cls, * @param channel the channel representing the cadet * @param initiator the identity of the peer who wants to establish a cadet * with us; NULL on binding error - * @return initial channel context (our `struct CadetClient`) + * @return initial channel context (our `struct GNUNET_ATS_Session`) */ static void * connect_cb (void *cls, struct GNUNET_CADET_Channel *channel, const struct GNUNET_PeerIdentity *initiator) { - GNUNET_break (0); - return NULL; + struct Plugin *plugin = cls; + struct GNUNET_ATS_Session *s; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got CADET connection from peer `%s'\n", + GNUNET_i2s (initiator)); + /* find existing session */ + s = GNUNET_CONTAINER_multipeermap_get (plugin->sessions, + initiator); + if (NULL == s) + { + GNUNET_break (0); + return s; + } + s = GNUNET_new (struct GNUNET_ATS_Session); + s->plugin = plugin; + s->peer = *initiator; + s->channel = channel; + /* add new session */ + (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessions, + &s->peer, + s, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Returning session %p\n", + s); + return s; } diff --git a/gnunet-build/packages/gnunet/gnunet/files/plugin_transport_webrtc_int.js b/gnunet-build/packages/gnunet/gnunet/files/plugin_transport_webrtc_int.js index 33fd3c1..cafc2f7 100644 --- a/gnunet-build/packages/gnunet/gnunet/files/plugin_transport_webrtc_int.js +++ b/gnunet-build/packages/gnunet/gnunet/files/plugin_transport_webrtc_int.js @@ -15,33 +15,55 @@ // along with this program. If not, see . mergeInto(LibraryManager.library, { - $RTC_CONFIG: {iceServers: [{url: "stun:stun.l.google.com:19302"}]}, $CONNECTIONS: [], $NEXT_CONNECTION: 1, - create_connection__deps: ["$RTC_CONFIG", "$CONNECTIONS", "$NEXT_CONNECTION"], - create_connection: function(offer_cb, cls) { - var conn = new RTCPeerConnection(RTC_CONFIG); - chan = conn.createDataChannel("data", {ordered: false, - maxRetransmits: 0, - negotiated: true, - id: 1}); - chan.onopen = function(e) { - console.warn("channel open"); + peer_connect__deps: ["$CONNECTIONS", "$NEXT_CONNECTION"], + peer_connect: function(offer_cb, answer_cb, message_cb, offer_ptr, offer_size, cls) { + var offer; + if (0 != offer_ptr) { + offer = Pointer_stringify(offer_ptr, offer_size); + } + var channel = new MessageChannel(); + var port = channel.port1; + port.onmessage = function(e) { + if ('offer' == e.data.type && 0 != offer_cb) { + ccallFunc( + getFuncWrapper(offer_cb, 'vii'), + 'void', + ['number', 'string'], + [cls, e.data.sdp]); + } else if ('answer' == e.data.type && 0 != answer_cb) { + ccallFunc( + getFuncWrapper(answer_cb, 'vii'), + 'void', + ['number', 'string'], + [cls, e.data.sdp]); + } else if ('message' == e.data.type) { + console.error('got webrtc message:', e.data); + } else { + console.error('unhandled message on webrtc message channel', e.data); + } }; - chan.onmessage = function(e) { - console.warn("channel got message:", e); - }; - offer = conn.createOffer(); - offer.then(function(e) { - console.warn("created offer:", e); - ccallFunc( - getFuncWrapper(offer_cb, 'vii'), - 'void', - ['number', 'string'], - [cls, e.sdp]); + do_to_window(function(w) { + w.postMessage({ + type: 'peer_connect', + offer: offer, + message_port: channel.port2}, [channel.port2]); }); - CONNECTIONS[NEXT_CONNECTION] = {conn: conn, chan: chan}; + CONNECTIONS[NEXT_CONNECTION] = port; return NEXT_CONNECTION++; + }, + set_remote_answer__deps: ["$CONNECTIONS"], + set_remote_answer: function(num, answer_ptr, answer_size) { + var port = CONNECTIONS[num]; + port.postMessage({type: 'answer', sdp: Pointer_stringify(answer_ptr, answer_size)}); + }, + peer_disconnect__deps: ["$CONNECTIONS"], + peer_disconnect: function(num) { + var port = CONNECTIONS[num]; + port.postMessage({type: 'disconnect'}); + port.close(); + delete CONNECTIONS[num]; } }); diff --git a/src/cljs/gnunet_web/service.cljs b/src/cljs/gnunet_web/service.cljs index e7e8254..0eea5a2 100644 --- a/src/cljs/gnunet_web/service.cljs +++ b/src/cljs/gnunet_web/service.cljs @@ -1,5 +1,5 @@ ;; service.cljs - service manager for gnunet-web website -;; Copyright (C) 2013-2015 David Barksdale +;; Copyright (C) 2013-2018 David Barksdale ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -15,7 +15,8 @@ ;; along with this program. If not, see . (ns gnunet-web.service - (:require [cognitect.transit :as t])) + (:require [cognitect.transit :as t] + [gnunet-web.webrtc :refer [peer-connect]])) (def private-key ;; XXX This has no synchronization! @@ -68,6 +69,7 @@ "client_connect" (client-connect (aget data "service_name") (aget data "client_name") (aget data "message_port")) + "peer_connect" (peer-connect (aget data "message_port") (aget data "offer")) (.warn js/console worker-name data)))) (catch :default e (js/console.error "REKT" e)))) diff --git a/src/cljs/gnunet_web/webrtc.cljs b/src/cljs/gnunet_web/webrtc.cljs new file mode 100644 index 0000000..d43292e --- /dev/null +++ b/src/cljs/gnunet_web/webrtc.cljs @@ -0,0 +1,68 @@ +;; webrtc.cljs - WebRTC functions for gnunet-web +;; Copyright (C) 2018 David Barksdale +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +(ns gnunet-web.webrtc) + +(def rtc-config + (clj->js + {:ice-servers [{:url "stun:stun.l.google.com:19302"}]})) + +(def data-channel-config + (clj->js + {:ordered false + :maxRetransmits 0 + :negotiated true + :id 1})) + +(defn peer-connect + [message-port offer] + (.debug js/console "peer-connect called with offer:" offer) + (let [connection (js/RTCPeerConnection. rtc-config) + channel (.createDataChannel connection + "data" + data-channel-config)] + (set! (.-onopen channel) + nil) + (set! (.-onmessage channel) + nil) + (if (empty? offer) + (.then (.createOffer connection) + (fn [offer] + (.debug js/console "created offer:" offer) + (.setLocalDescription connection offer) + (.postMessage message-port + (js-obj "type" "offer" + "sdp" (.-sdp offer))))) + (.then (.setRemoteDescription connection + (js-obj "type" "offer" + "sdp" offer)) + (fn [] + (.then (.createAnswer connection) + (fn [answer] + (.debug js/console "created answer:" answer) + (.setLocalDescription connection answer) + (.postMessage message-port + (js-obj "type" "answer" + "sdp" (.-sdp answer)))))))) + (set! (.-onmessage message-port) + (fn [e] + (.debug js/console "got webrtc message-channel message" e) + (let [data (.-data e)] + (condp = (.-type data) + "answer" (.then (.setRemoteDescription connection + (js-obj "type" "answer" + "sdp" (.-sdp data))) + (fn [])))))))) -- cgit v1.2.3-18-g5258