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 39 static void throwNotOpenException(ExceptionState& exceptionState) 40 { 41 exceptionState.throwDOMException(InvalidStateError, "RTCDataChannel.readyState is not 'open'"); 42 } 43 44 static void throwCouldNotSendDataException(ExceptionState& exceptionState) 45 { 46 exceptionState.throwDOMException(NetworkError, "Could not send data"); 47 } 48 49 static void throwNoBlobSupportException(ExceptionState& exceptionState) 50 { 51 exceptionState.throwDOMException(NotSupportedError, "Blob support not implemented yet"); 52 } 53 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 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 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 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 98 String RTCDataChannel::label() const 99 { 100 return m_handler->label(); 101 } 102 103 bool RTCDataChannel::reliable() const 104 { 105 return m_handler->isReliable(); 106 } 107 108 bool RTCDataChannel::ordered() const 109 { 110 return m_handler->ordered(); 111 } 112 113 unsigned short RTCDataChannel::maxRetransmitTime() const 114 { 115 return m_handler->maxRetransmitTime(); 116 } 117 118 unsigned short RTCDataChannel::maxRetransmits() const 119 { 120 return m_handler->maxRetransmits(); 121 } 122 123 String RTCDataChannel::protocol() const 124 { 125 return m_handler->protocol(); 126 } 127 128 bool RTCDataChannel::negotiated() const 129 { 130 return m_handler->negotiated(); 131 } 132 133 unsigned short RTCDataChannel::id() const 134 { 135 return m_handler->id(); 136 } 137 138 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 155 unsigned long RTCDataChannel::bufferedAmount() const 156 { 157 return m_handler->bufferedAmount(); 158 } 159 160 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 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 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 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 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 221 void RTCDataChannel::send(PassRefPtrWillBeRawPtr<Blob> data, ExceptionState& exceptionState) 222 { 223 // FIXME: implement 224 throwNoBlobSupportException(exceptionState); 225 } 226 227 void RTCDataChannel::close() 228 { 229 if (m_stopped) 230 return; 231 232 m_handler->close(); 233 } 234 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 254 void RTCDataChannel::didReceiveStringData(const blink::WebString& text) 255 { 256 if (m_stopped) 257 return; 258 259 scheduleDispatchEvent(MessageEvent::create(text)); 260 } 261 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 279 void RTCDataChannel::didDetectError() 280 { 281 if (m_stopped) 282 return; 283 284 scheduleDispatchEvent(Event::create(EventTypeNames::error)); 285 } 286 287 const AtomicString& RTCDataChannel::interfaceName() const 288 { 289 return EventTargetNames::RTCDataChannel; 290 } 291 292 ExecutionContext* RTCDataChannel::executionContext() const 293 { 294 return m_executionContext; 295 } 296 297 void RTCDataChannel::stop() 298 { 299 m_stopped = true; 300 m_readyState = ReadyStateClosed; 301 m_handler->setClient(0); 302 m_executionContext = 0; 303 } 304 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 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) 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 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