Skip to main content

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