script/dom/webrtc/
rtcdatachannel.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6use std::ptr;
7
8use constellation_traits::BlobImpl;
9use dom_struct::dom_struct;
10use js::jsapi::{JSAutoRealm, JSObject};
11use js::jsval::UndefinedValue;
12use js::rust::CustomAutoRooterGuard;
13use js::typedarray::{ArrayBuffer, ArrayBufferView, CreateWith};
14use script_bindings::conversions::SafeToJSValConvertible;
15use script_bindings::weakref::WeakRef;
16use servo_media::webrtc::{
17    DataChannelId, DataChannelInit, DataChannelMessage, DataChannelState, WebRtcError,
18};
19
20use crate::conversions::Convert;
21use crate::dom::bindings::cell::DomRefCell;
22use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::{
23    RTCDataChannelInit, RTCDataChannelMethods, RTCDataChannelState,
24};
25use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
26use crate::dom::bindings::error::{Error, Fallible};
27use crate::dom::bindings::inheritance::Castable;
28use crate::dom::bindings::reflector::{DomGlobal, DomObject, reflect_dom_object};
29use crate::dom::bindings::root::{Dom, DomRoot};
30use crate::dom::bindings::str::{DOMString, USVString};
31use crate::dom::blob::Blob;
32use crate::dom::event::{Event, EventBubbles, EventCancelable};
33use crate::dom::eventtarget::EventTarget;
34use crate::dom::globalscope::GlobalScope;
35use crate::dom::messageevent::MessageEvent;
36use crate::dom::rtcerror::RTCError;
37use crate::dom::rtcerrorevent::RTCErrorEvent;
38use crate::dom::rtcpeerconnection::RTCPeerConnection;
39use crate::script_runtime::CanGc;
40
41#[derive(JSTraceable, MallocSizeOf)]
42struct DroppableRTCDataChannel {
43    #[ignore_malloc_size_of = "defined in servo-media"]
44    servo_media_id: DataChannelId,
45    peer_connection: WeakRef<RTCPeerConnection>,
46}
47
48impl DroppableRTCDataChannel {
49    fn new(peer_connection: WeakRef<RTCPeerConnection>, servo_media_id: DataChannelId) -> Self {
50        DroppableRTCDataChannel {
51            servo_media_id,
52            peer_connection,
53        }
54    }
55
56    pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
57        self.servo_media_id
58    }
59}
60
61impl Drop for DroppableRTCDataChannel {
62    fn drop(&mut self) {
63        if let Some(root) = self.peer_connection.root() {
64            root.unregister_data_channel(&self.get_servo_media_id());
65        }
66    }
67}
68
69#[dom_struct]
70pub(crate) struct RTCDataChannel {
71    eventtarget: EventTarget,
72    label: USVString,
73    ordered: bool,
74    max_packet_life_time: Option<u16>,
75    max_retransmits: Option<u16>,
76    protocol: USVString,
77    negotiated: bool,
78    id: Option<u16>,
79    ready_state: Cell<RTCDataChannelState>,
80    binary_type: DomRefCell<DOMString>,
81    peer_connection: Dom<RTCPeerConnection>,
82    droppable: DroppableRTCDataChannel,
83}
84
85impl RTCDataChannel {
86    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
87    pub(crate) fn new_inherited(
88        peer_connection: &RTCPeerConnection,
89        label: USVString,
90        options: &RTCDataChannelInit,
91        servo_media_id: Option<DataChannelId>,
92    ) -> RTCDataChannel {
93        let mut init: DataChannelInit = options.convert();
94        init.label = label.to_string();
95
96        let controller = peer_connection.get_webrtc_controller().borrow();
97        let servo_media_id = servo_media_id.unwrap_or(
98            controller
99                .as_ref()
100                .unwrap()
101                .create_data_channel(init)
102                .expect("Expected data channel id"),
103        );
104
105        RTCDataChannel {
106            eventtarget: EventTarget::new_inherited(),
107            label,
108            ordered: options.ordered,
109            max_packet_life_time: options.maxPacketLifeTime,
110            max_retransmits: options.maxRetransmits,
111            protocol: options.protocol.clone(),
112            negotiated: options.negotiated,
113            id: options.id,
114            ready_state: Cell::new(RTCDataChannelState::Connecting),
115            binary_type: DomRefCell::new(DOMString::from("blob")),
116            peer_connection: Dom::from_ref(peer_connection),
117            droppable: DroppableRTCDataChannel::new(WeakRef::new(peer_connection), servo_media_id),
118        }
119    }
120
121    pub(crate) fn new(
122        global: &GlobalScope,
123        peer_connection: &RTCPeerConnection,
124        label: USVString,
125        options: &RTCDataChannelInit,
126        servo_media_id: Option<DataChannelId>,
127        can_gc: CanGc,
128    ) -> DomRoot<RTCDataChannel> {
129        let rtc_data_channel = reflect_dom_object(
130            Box::new(RTCDataChannel::new_inherited(
131                peer_connection,
132                label,
133                options,
134                servo_media_id,
135            )),
136            global,
137            can_gc,
138        );
139
140        peer_connection
141            .register_data_channel(rtc_data_channel.get_servo_media_id(), &rtc_data_channel);
142
143        rtc_data_channel
144    }
145
146    pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
147        self.droppable.get_servo_media_id()
148    }
149
150    pub(crate) fn on_open(&self, can_gc: CanGc) {
151        let event = Event::new(
152            &self.global(),
153            atom!("open"),
154            EventBubbles::DoesNotBubble,
155            EventCancelable::NotCancelable,
156            can_gc,
157        );
158        event.upcast::<Event>().fire(self.upcast(), can_gc);
159    }
160
161    pub(crate) fn on_close(&self, can_gc: CanGc) {
162        let event = Event::new(
163            &self.global(),
164            atom!("close"),
165            EventBubbles::DoesNotBubble,
166            EventCancelable::NotCancelable,
167            can_gc,
168        );
169        event.upcast::<Event>().fire(self.upcast(), can_gc);
170
171        self.peer_connection
172            .unregister_data_channel(&self.get_servo_media_id());
173    }
174
175    pub(crate) fn on_error(&self, error: WebRtcError, can_gc: CanGc) {
176        let global = self.global();
177        let window = global.as_window();
178        let cx = GlobalScope::get_cx();
179        let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
180        let init = RTCErrorInit {
181            errorDetail: RTCErrorDetailType::Data_channel_failure,
182            httpRequestStatusCode: None,
183            receivedAlert: None,
184            sctpCauseCode: None,
185            sdpLineNumber: None,
186            sentAlert: None,
187        };
188        let message = match error {
189            WebRtcError::Backend(message) => DOMString::from(message),
190        };
191        let error = RTCError::new(window, &init, message, can_gc);
192        let event = RTCErrorEvent::new(window, atom!("error"), false, false, &error, can_gc);
193        event.upcast::<Event>().fire(self.upcast(), can_gc);
194    }
195
196    #[allow(unsafe_code)]
197    pub(crate) fn on_message(&self, channel_message: DataChannelMessage, can_gc: CanGc) {
198        let global = self.global();
199        let cx = GlobalScope::get_cx();
200        let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
201        rooted!(in(*cx) let mut message = UndefinedValue());
202
203        match channel_message {
204            DataChannelMessage::Text(text) => {
205                text.safe_to_jsval(cx, message.handle_mut());
206            },
207            DataChannelMessage::Binary(data) => match &**self.binary_type.borrow() {
208                "blob" => {
209                    let blob = Blob::new(
210                        &global,
211                        BlobImpl::new_from_bytes(data, "".to_owned()),
212                        can_gc,
213                    );
214                    blob.safe_to_jsval(cx, message.handle_mut());
215                },
216                "arraybuffer" => {
217                    rooted!(in(*cx) let mut array_buffer = ptr::null_mut::<JSObject>());
218                    unsafe {
219                        assert!(
220                            ArrayBuffer::create(
221                                *cx,
222                                CreateWith::Slice(&data),
223                                array_buffer.handle_mut()
224                            )
225                            .is_ok()
226                        )
227                    };
228
229                    (*array_buffer).safe_to_jsval(cx, message.handle_mut());
230                },
231                _ => unreachable!(),
232            },
233        }
234
235        MessageEvent::dispatch_jsval(
236            self.upcast(),
237            &global,
238            message.handle(),
239            Some(&global.origin().immutable().ascii_serialization()),
240            None,
241            vec![],
242            can_gc,
243        );
244    }
245
246    pub(crate) fn on_state_change(&self, state: DataChannelState, can_gc: CanGc) {
247        if let DataChannelState::Closing = state {
248            let event = Event::new(
249                &self.global(),
250                atom!("closing"),
251                EventBubbles::DoesNotBubble,
252                EventCancelable::NotCancelable,
253                can_gc,
254            );
255            event.upcast::<Event>().fire(self.upcast(), can_gc);
256        };
257        self.ready_state.set(state.convert());
258    }
259
260    fn send(&self, source: &SendSource) -> Fallible<()> {
261        if self.ready_state.get() != RTCDataChannelState::Open {
262            return Err(Error::InvalidState);
263        }
264
265        let message = match source {
266            SendSource::String(string) => DataChannelMessage::Text(string.0.clone()),
267            SendSource::Blob(blob) => {
268                DataChannelMessage::Binary(blob.get_bytes().unwrap_or(vec![]))
269            },
270            SendSource::ArrayBuffer(array) => DataChannelMessage::Binary(array.to_vec()),
271            SendSource::ArrayBufferView(array) => DataChannelMessage::Binary(array.to_vec()),
272        };
273
274        let controller = self.peer_connection.get_webrtc_controller().borrow();
275        controller
276            .as_ref()
277            .unwrap()
278            .send_data_channel_message(&self.get_servo_media_id(), message);
279
280        Ok(())
281    }
282}
283
284enum SendSource<'a, 'b> {
285    String(&'a USVString),
286    Blob(&'a Blob),
287    ArrayBuffer(CustomAutoRooterGuard<'b, ArrayBuffer>),
288    ArrayBufferView(CustomAutoRooterGuard<'b, ArrayBufferView>),
289}
290
291impl RTCDataChannelMethods<crate::DomTypeHolder> for RTCDataChannel {
292    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen
293    event_handler!(open, GetOnopen, SetOnopen);
294    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onbufferedamountlow
295    event_handler!(
296        bufferedamountlow,
297        GetOnbufferedamountlow,
298        SetOnbufferedamountlow
299    );
300    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror
301    event_handler!(error, GetOnerror, SetOnerror);
302    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclosing
303    event_handler!(closing, GetOnclosing, SetOnclosing);
304    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclose
305    event_handler!(close, GetOnclose, SetOnclose);
306    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onmessage
307    event_handler!(message, GetOnmessage, SetOnmessage);
308
309    // https://www.w3.org/TR/webrtc/#dom-datachannel-label
310    fn Label(&self) -> USVString {
311        self.label.clone()
312    }
313    // https://www.w3.org/TR/webrtc/#dom-datachannel-ordered
314    fn Ordered(&self) -> bool {
315        self.ordered
316    }
317
318    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxpacketlifetime
319    fn GetMaxPacketLifeTime(&self) -> Option<u16> {
320        self.max_packet_life_time
321    }
322
323    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxretransmits
324    fn GetMaxRetransmits(&self) -> Option<u16> {
325        self.max_retransmits
326    }
327
328    // https://www.w3.org/TR/webrtc/#dom-datachannel-protocol
329    fn Protocol(&self) -> USVString {
330        self.protocol.clone()
331    }
332
333    // https://www.w3.org/TR/webrtc/#dom-datachannel-negotiated
334    fn Negotiated(&self) -> bool {
335        self.negotiated
336    }
337
338    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-id
339    fn GetId(&self) -> Option<u16> {
340        self.id
341    }
342
343    // https://www.w3.org/TR/webrtc/#dom-datachannel-readystate
344    fn ReadyState(&self) -> RTCDataChannelState {
345        self.ready_state.get()
346    }
347
348    // XXX We need a way to know when the underlying data transport
349    // actually sends data from its queue to decrease buffered amount.
350
351    //    fn BufferedAmount(&self) -> u32;
352    //    fn BufferedAmountLowThreshold(&self) -> u32;
353    //    fn SetBufferedAmountLowThreshold(&self, value: u32) -> ();
354
355    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-close
356    fn Close(&self) {
357        let controller = self.peer_connection.get_webrtc_controller().borrow();
358        controller
359            .as_ref()
360            .unwrap()
361            .close_data_channel(&self.get_servo_media_id());
362    }
363
364    // https://www.w3.org/TR/webrtc/#dom-datachannel-binarytype
365    fn BinaryType(&self) -> DOMString {
366        self.binary_type.borrow().clone()
367    }
368
369    // https://www.w3.org/TR/webrtc/#dom-datachannel-binarytype
370    fn SetBinaryType(&self, value: DOMString) -> Fallible<()> {
371        if value != "blob" || value != "arraybuffer" {
372            return Err(Error::Syntax(None));
373        }
374        *self.binary_type.borrow_mut() = value;
375        Ok(())
376    }
377
378    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send
379    fn Send(&self, data: USVString) -> Fallible<()> {
380        self.send(&SendSource::String(&data))
381    }
382
383    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-1
384    fn Send_(&self, data: &Blob) -> Fallible<()> {
385        self.send(&SendSource::Blob(data))
386    }
387
388    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-2
389    fn Send__(&self, data: CustomAutoRooterGuard<ArrayBuffer>) -> Fallible<()> {
390        self.send(&SendSource::ArrayBuffer(data))
391    }
392
393    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-3
394    fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> Fallible<()> {
395        self.send(&SendSource::ArrayBufferView(data))
396    }
397}
398
399impl Convert<DataChannelInit> for &RTCDataChannelInit {
400    fn convert(self) -> DataChannelInit {
401        DataChannelInit {
402            label: String::new(),
403            id: self.id,
404            max_packet_life_time: self.maxPacketLifeTime,
405            max_retransmits: self.maxRetransmits,
406            negotiated: self.negotiated,
407            ordered: self.ordered,
408            protocol: self.protocol.to_string(),
409        }
410    }
411}
412
413impl Convert<RTCDataChannelState> for DataChannelState {
414    fn convert(self) -> RTCDataChannelState {
415        match self {
416            DataChannelState::Connecting | DataChannelState::__Unknown(_) => {
417                RTCDataChannelState::Connecting
418            },
419            DataChannelState::Open => RTCDataChannelState::Open,
420            DataChannelState::Closing => RTCDataChannelState::Closing,
421            DataChannelState::Closed => RTCDataChannelState::Closed,
422        }
423    }
424}