1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25 #include "config.h"
26 #include "modules/mediastream/RTCDataChannel.h"
27
28 #include "bindings/v8/ExceptionState.h"
29 #include "core/dom/ExceptionCode.h"
30 #include "core/dom/ExecutionContext.h"
31 #include "core/events/MessageEvent.h"
32 #include "core/fileapi/Blob.h"
33 #include "public/platform/WebRTCPeerConnectionHandler.h"
34 #include "wtf/ArrayBuffer.h"
35 #include "wtf/ArrayBufferView.h"
36
37 namespace WebCore {
38
throwNotOpenException(ExceptionState & exceptionState)39 static void throwNotOpenException(ExceptionState& exceptionState)
40 {
41 exceptionState.throwDOMException(InvalidStateError, "RTCDataChannel.readyState is not 'open'");
42 }
43
throwCouldNotSendDataException(ExceptionState & exceptionState)44 static void throwCouldNotSendDataException(ExceptionState& exceptionState)
45 {
46 exceptionState.throwDOMException(NetworkError, "Could not send data");
47 }
48
throwNoBlobSupportException(ExceptionState & exceptionState)49 static void throwNoBlobSupportException(ExceptionState& exceptionState)
50 {
51 exceptionState.throwDOMException(NotSupportedError, "Blob support not implemented yet");
52 }
53
create(ExecutionContext * context,RTCPeerConnection * connection,PassOwnPtr<blink::WebRTCDataChannelHandler> handler)54 PassRefPtrWillBeRawPtr<RTCDataChannel> RTCDataChannel::create(ExecutionContext* context, RTCPeerConnection* connection, PassOwnPtr<blink::WebRTCDataChannelHandler> handler)
55 {
56 ASSERT(handler);
57 return adoptRefWillBeRefCountedGarbageCollected(new RTCDataChannel(context, connection, handler));
58 }
59
create(ExecutionContext * context,RTCPeerConnection * connection,blink::WebRTCPeerConnectionHandler * peerConnectionHandler,const String & label,const blink::WebRTCDataChannelInit & init,ExceptionState & exceptionState)60 PassRefPtrWillBeRawPtr<RTCDataChannel> RTCDataChannel::create(ExecutionContext* context, RTCPeerConnection* connection, blink::WebRTCPeerConnectionHandler* peerConnectionHandler, const String& label, const blink::WebRTCDataChannelInit& init, ExceptionState& exceptionState)
61 {
62 OwnPtr<blink::WebRTCDataChannelHandler> handler = adoptPtr(peerConnectionHandler->createDataChannel(label, init));
63 if (!handler) {
64 exceptionState.throwDOMException(NotSupportedError, "RTCDataChannel is not supported");
65 return nullptr;
66 }
67 return adoptRefWillBeRefCountedGarbageCollected(new RTCDataChannel(context, connection, handler.release()));
68 }
69
RTCDataChannel(ExecutionContext * context,RTCPeerConnection * connection,PassOwnPtr<blink::WebRTCDataChannelHandler> handler)70 RTCDataChannel::RTCDataChannel(ExecutionContext* context, RTCPeerConnection* connection, PassOwnPtr<blink::WebRTCDataChannelHandler> handler)
71 : m_executionContext(context)
72 , m_handler(handler)
73 , m_stopped(false)
74 , m_readyState(ReadyStateConnecting)
75 , m_binaryType(BinaryTypeArrayBuffer)
76 , m_scheduledEventTimer(this, &RTCDataChannel::scheduledEventTimerFired)
77 #if ENABLE(OILPAN)
78 , m_connection(connection)
79 #endif
80 {
81 ScriptWrappable::init(this);
82 m_handler->setClient(this);
83 }
84
~RTCDataChannel()85 RTCDataChannel::~RTCDataChannel()
86 {
87 #if ENABLE(OILPAN)
88 // If the peer connection and the data channel die in the same
89 // GC cycle stop has not been called and we need to notify the
90 // client that the channel is gone.
91 if (!m_stopped)
92 m_handler->setClient(0);
93 #else
94 ASSERT(m_stopped);
95 #endif
96 }
97
label() const98 String RTCDataChannel::label() const
99 {
100 return m_handler->label();
101 }
102
reliable() const103 bool RTCDataChannel::reliable() const
104 {
105 return m_handler->isReliable();
106 }
107
ordered() const108 bool RTCDataChannel::ordered() const
109 {
110 return m_handler->ordered();
111 }
112
maxRetransmitTime() const113 unsigned short RTCDataChannel::maxRetransmitTime() const
114 {
115 return m_handler->maxRetransmitTime();
116 }
117
maxRetransmits() const118 unsigned short RTCDataChannel::maxRetransmits() const
119 {
120 return m_handler->maxRetransmits();
121 }
122
protocol() const123 String RTCDataChannel::protocol() const
124 {
125 return m_handler->protocol();
126 }
127
negotiated() const128 bool RTCDataChannel::negotiated() const
129 {
130 return m_handler->negotiated();
131 }
132
id() const133 unsigned short RTCDataChannel::id() const
134 {
135 return m_handler->id();
136 }
137
readyState() const138 String RTCDataChannel::readyState() const
139 {
140 switch (m_readyState) {
141 case ReadyStateConnecting:
142 return "connecting";
143 case ReadyStateOpen:
144 return "open";
145 case ReadyStateClosing:
146 return "closing";
147 case ReadyStateClosed:
148 return "closed";
149 }
150
151 ASSERT_NOT_REACHED();
152 return String();
153 }
154
bufferedAmount() const155 unsigned long RTCDataChannel::bufferedAmount() const
156 {
157 return m_handler->bufferedAmount();
158 }
159
binaryType() const160 String RTCDataChannel::binaryType() const
161 {
162 switch (m_binaryType) {
163 case BinaryTypeBlob:
164 return "blob";
165 case BinaryTypeArrayBuffer:
166 return "arraybuffer";
167 }
168 ASSERT_NOT_REACHED();
169 return String();
170 }
171
setBinaryType(const String & binaryType,ExceptionState & exceptionState)172 void RTCDataChannel::setBinaryType(const String& binaryType, ExceptionState& exceptionState)
173 {
174 if (binaryType == "blob")
175 throwNoBlobSupportException(exceptionState);
176 else if (binaryType == "arraybuffer")
177 m_binaryType = BinaryTypeArrayBuffer;
178 else
179 exceptionState.throwDOMException(TypeMismatchError, "Unknown binary type : " + binaryType);
180 }
181
send(const String & data,ExceptionState & exceptionState)182 void RTCDataChannel::send(const String& data, ExceptionState& exceptionState)
183 {
184 if (m_readyState != ReadyStateOpen) {
185 throwNotOpenException(exceptionState);
186 return;
187 }
188 if (!m_handler->sendStringData(data)) {
189 // FIXME: This should not throw an exception but instead forcefully close the data channel.
190 throwCouldNotSendDataException(exceptionState);
191 }
192 }
193
send(PassRefPtr<ArrayBuffer> prpData,ExceptionState & exceptionState)194 void RTCDataChannel::send(PassRefPtr<ArrayBuffer> prpData, ExceptionState& exceptionState)
195 {
196 if (m_readyState != ReadyStateOpen) {
197 throwNotOpenException(exceptionState);
198 return;
199 }
200
201 RefPtr<ArrayBuffer> data = prpData;
202
203 size_t dataLength = data->byteLength();
204 if (!dataLength)
205 return;
206
207 if (!m_handler->sendRawData(static_cast<const char*>((data->data())), dataLength)) {
208 // FIXME: This should not throw an exception but instead forcefully close the data channel.
209 throwCouldNotSendDataException(exceptionState);
210 }
211 }
212
send(PassRefPtr<ArrayBufferView> data,ExceptionState & exceptionState)213 void RTCDataChannel::send(PassRefPtr<ArrayBufferView> data, ExceptionState& exceptionState)
214 {
215 if (!m_handler->sendRawData(static_cast<const char*>(data->baseAddress()), data->byteLength())) {
216 // FIXME: This should not throw an exception but instead forcefully close the data channel.
217 throwCouldNotSendDataException(exceptionState);
218 }
219 }
220
send(PassRefPtrWillBeRawPtr<Blob> data,ExceptionState & exceptionState)221 void RTCDataChannel::send(PassRefPtrWillBeRawPtr<Blob> data, ExceptionState& exceptionState)
222 {
223 // FIXME: implement
224 throwNoBlobSupportException(exceptionState);
225 }
226
close()227 void RTCDataChannel::close()
228 {
229 if (m_stopped)
230 return;
231
232 m_handler->close();
233 }
234
didChangeReadyState(blink::WebRTCDataChannelHandlerClient::ReadyState newState)235 void RTCDataChannel::didChangeReadyState(blink::WebRTCDataChannelHandlerClient::ReadyState newState)
236 {
237 if (m_stopped || m_readyState == ReadyStateClosed)
238 return;
239
240 m_readyState = newState;
241
242 switch (m_readyState) {
243 case ReadyStateOpen:
244 scheduleDispatchEvent(Event::create(EventTypeNames::open));
245 break;
246 case ReadyStateClosed:
247 scheduleDispatchEvent(Event::create(EventTypeNames::close));
248 break;
249 default:
250 break;
251 }
252 }
253
didReceiveStringData(const blink::WebString & text)254 void RTCDataChannel::didReceiveStringData(const blink::WebString& text)
255 {
256 if (m_stopped)
257 return;
258
259 scheduleDispatchEvent(MessageEvent::create(text));
260 }
261
didReceiveRawData(const char * data,size_t dataLength)262 void RTCDataChannel::didReceiveRawData(const char* data, size_t dataLength)
263 {
264 if (m_stopped)
265 return;
266
267 if (m_binaryType == BinaryTypeBlob) {
268 // FIXME: Implement.
269 return;
270 }
271 if (m_binaryType == BinaryTypeArrayBuffer) {
272 RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(data, dataLength);
273 scheduleDispatchEvent(MessageEvent::create(buffer.release()));
274 return;
275 }
276 ASSERT_NOT_REACHED();
277 }
278
didDetectError()279 void RTCDataChannel::didDetectError()
280 {
281 if (m_stopped)
282 return;
283
284 scheduleDispatchEvent(Event::create(EventTypeNames::error));
285 }
286
interfaceName() const287 const AtomicString& RTCDataChannel::interfaceName() const
288 {
289 return EventTargetNames::RTCDataChannel;
290 }
291
executionContext() const292 ExecutionContext* RTCDataChannel::executionContext() const
293 {
294 return m_executionContext;
295 }
296
stop()297 void RTCDataChannel::stop()
298 {
299 m_stopped = true;
300 m_readyState = ReadyStateClosed;
301 m_handler->setClient(0);
302 m_executionContext = 0;
303 }
304
scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)305 void RTCDataChannel::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
306 {
307 m_scheduledEvents.append(event);
308
309 if (!m_scheduledEventTimer.isActive())
310 m_scheduledEventTimer.startOneShot(0, FROM_HERE);
311 }
312
scheduledEventTimerFired(Timer<RTCDataChannel> *)313 void RTCDataChannel::scheduledEventTimerFired(Timer<RTCDataChannel>*)
314 {
315 if (m_stopped)
316 return;
317
318 WillBeHeapVector<RefPtrWillBeMember<Event> > events;
319 events.swap(m_scheduledEvents);
320
321 WillBeHeapVector<RefPtrWillBeMember<Event> >::iterator it = events.begin();
322 for (; it != events.end(); ++it)
323 dispatchEvent((*it).release());
324
325 events.clear();
326 }
327
328 #if ENABLE(OILPAN)
clearWeakMembers(Visitor * visitor)329 void RTCDataChannel::clearWeakMembers(Visitor* visitor)
330 {
331 if (visitor->isAlive(m_connection))
332 return;
333 stop();
334 m_connection = nullptr;
335 }
336 #endif
337
trace(Visitor * visitor)338 void RTCDataChannel::trace(Visitor* visitor)
339 {
340 #if ENABLE(OILPAN)
341 visitor->trace(m_scheduledEvents);
342 visitor->registerWeakMembers<RTCDataChannel, &RTCDataChannel::clearWeakMembers>(this);
343 #endif
344 EventTargetWithInlineData::trace(visitor);
345 }
346
347 } // namespace WebCore
348