• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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