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/core/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 "modules/mediastream/RTCPeerConnection.h" 34 #include "public/platform/WebRTCPeerConnectionHandler.h" 35 #include "wtf/ArrayBuffer.h" 36 #include "wtf/ArrayBufferView.h" 37 38 namespace blink { 39 40 static void throwNotOpenException(ExceptionState& exceptionState) 41 { 42 exceptionState.throwDOMException(InvalidStateError, "RTCDataChannel.readyState is not 'open'"); 43 } 44 45 static void throwCouldNotSendDataException(ExceptionState& exceptionState) 46 { 47 exceptionState.throwDOMException(NetworkError, "Could not send data"); 48 } 49 50 static void throwNoBlobSupportException(ExceptionState& exceptionState) 51 { 52 exceptionState.throwDOMException(NotSupportedError, "Blob support not implemented yet"); 53 } 54 55 RTCDataChannel* RTCDataChannel::create(ExecutionContext* context, RTCPeerConnection* connection, PassOwnPtr<WebRTCDataChannelHandler> handler) 56 { 57 ASSERT(handler); 58 return adoptRefCountedGarbageCollectedWillBeNoop(new RTCDataChannel(context, connection, handler)); 59 } 60 61 RTCDataChannel* RTCDataChannel::create(ExecutionContext* context, RTCPeerConnection* connection, WebRTCPeerConnectionHandler* peerConnectionHandler, const String& label, const WebRTCDataChannelInit& init, ExceptionState& exceptionState) 62 { 63 OwnPtr<WebRTCDataChannelHandler> handler = adoptPtr(peerConnectionHandler->createDataChannel(label, init)); 64 if (!handler) { 65 exceptionState.throwDOMException(NotSupportedError, "RTCDataChannel is not supported"); 66 return nullptr; 67 } 68 return adoptRefCountedGarbageCollectedWillBeNoop(new RTCDataChannel(context, connection, handler.release())); 69 } 70 71 RTCDataChannel::RTCDataChannel(ExecutionContext* context, RTCPeerConnection* connection, PassOwnPtr<WebRTCDataChannelHandler> handler) 72 : m_executionContext(context) 73 , m_handler(handler) 74 , m_stopped(false) 75 , m_readyState(ReadyStateConnecting) 76 , m_binaryType(BinaryTypeArrayBuffer) 77 , m_scheduledEventTimer(this, &RTCDataChannel::scheduledEventTimerFired) 78 , m_connection(connection) 79 { 80 m_handler->setClient(this); 81 } 82 83 RTCDataChannel::~RTCDataChannel() 84 { 85 // If the peer connection and the data channel die in the same 86 // GC cycle stop has not been called and we need to notify the 87 // client that the channel is gone. 88 if (!m_stopped) 89 m_handler->setClient(0); 90 } 91 92 String RTCDataChannel::label() const 93 { 94 return m_handler->label(); 95 } 96 97 bool RTCDataChannel::reliable() const 98 { 99 return m_handler->isReliable(); 100 } 101 102 bool RTCDataChannel::ordered() const 103 { 104 return m_handler->ordered(); 105 } 106 107 unsigned short RTCDataChannel::maxRetransmitTime() const 108 { 109 return m_handler->maxRetransmitTime(); 110 } 111 112 unsigned short RTCDataChannel::maxRetransmits() const 113 { 114 return m_handler->maxRetransmits(); 115 } 116 117 String RTCDataChannel::protocol() const 118 { 119 return m_handler->protocol(); 120 } 121 122 bool RTCDataChannel::negotiated() const 123 { 124 return m_handler->negotiated(); 125 } 126 127 unsigned short RTCDataChannel::id() const 128 { 129 return m_handler->id(); 130 } 131 132 String RTCDataChannel::readyState() const 133 { 134 switch (m_readyState) { 135 case ReadyStateConnecting: 136 return "connecting"; 137 case ReadyStateOpen: 138 return "open"; 139 case ReadyStateClosing: 140 return "closing"; 141 case ReadyStateClosed: 142 return "closed"; 143 } 144 145 ASSERT_NOT_REACHED(); 146 return String(); 147 } 148 149 unsigned long RTCDataChannel::bufferedAmount() const 150 { 151 return m_handler->bufferedAmount(); 152 } 153 154 String RTCDataChannel::binaryType() const 155 { 156 switch (m_binaryType) { 157 case BinaryTypeBlob: 158 return "blob"; 159 case BinaryTypeArrayBuffer: 160 return "arraybuffer"; 161 } 162 ASSERT_NOT_REACHED(); 163 return String(); 164 } 165 166 void RTCDataChannel::setBinaryType(const String& binaryType, ExceptionState& exceptionState) 167 { 168 if (binaryType == "blob") 169 throwNoBlobSupportException(exceptionState); 170 else if (binaryType == "arraybuffer") 171 m_binaryType = BinaryTypeArrayBuffer; 172 else 173 exceptionState.throwDOMException(TypeMismatchError, "Unknown binary type : " + binaryType); 174 } 175 176 void RTCDataChannel::send(const String& data, ExceptionState& exceptionState) 177 { 178 if (m_readyState != ReadyStateOpen) { 179 throwNotOpenException(exceptionState); 180 return; 181 } 182 if (!m_handler->sendStringData(data)) { 183 // FIXME: This should not throw an exception but instead forcefully close the data channel. 184 throwCouldNotSendDataException(exceptionState); 185 } 186 } 187 188 void RTCDataChannel::send(PassRefPtr<ArrayBuffer> prpData, ExceptionState& exceptionState) 189 { 190 if (m_readyState != ReadyStateOpen) { 191 throwNotOpenException(exceptionState); 192 return; 193 } 194 195 RefPtr<ArrayBuffer> data = prpData; 196 197 size_t dataLength = data->byteLength(); 198 if (!dataLength) 199 return; 200 201 if (!m_handler->sendRawData(static_cast<const char*>((data->data())), dataLength)) { 202 // FIXME: This should not throw an exception but instead forcefully close the data channel. 203 throwCouldNotSendDataException(exceptionState); 204 } 205 } 206 207 void RTCDataChannel::send(PassRefPtr<ArrayBufferView> data, ExceptionState& exceptionState) 208 { 209 if (!m_handler->sendRawData(static_cast<const char*>(data->baseAddress()), data->byteLength())) { 210 // FIXME: This should not throw an exception but instead forcefully close the data channel. 211 throwCouldNotSendDataException(exceptionState); 212 } 213 } 214 215 void RTCDataChannel::send(PassRefPtrWillBeRawPtr<Blob> data, ExceptionState& exceptionState) 216 { 217 // FIXME: implement 218 throwNoBlobSupportException(exceptionState); 219 } 220 221 void RTCDataChannel::close() 222 { 223 if (m_stopped) 224 return; 225 226 m_handler->close(); 227 } 228 229 void RTCDataChannel::didChangeReadyState(WebRTCDataChannelHandlerClient::ReadyState newState) 230 { 231 if (m_stopped || m_readyState == ReadyStateClosed) 232 return; 233 234 m_readyState = newState; 235 236 switch (m_readyState) { 237 case ReadyStateOpen: 238 scheduleDispatchEvent(Event::create(EventTypeNames::open)); 239 break; 240 case ReadyStateClosed: 241 scheduleDispatchEvent(Event::create(EventTypeNames::close)); 242 break; 243 default: 244 break; 245 } 246 } 247 248 void RTCDataChannel::didReceiveStringData(const WebString& text) 249 { 250 if (m_stopped) 251 return; 252 253 scheduleDispatchEvent(MessageEvent::create(text)); 254 } 255 256 void RTCDataChannel::didReceiveRawData(const char* data, size_t dataLength) 257 { 258 if (m_stopped) 259 return; 260 261 if (m_binaryType == BinaryTypeBlob) { 262 // FIXME: Implement. 263 return; 264 } 265 if (m_binaryType == BinaryTypeArrayBuffer) { 266 RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(data, dataLength); 267 scheduleDispatchEvent(MessageEvent::create(buffer.release())); 268 return; 269 } 270 ASSERT_NOT_REACHED(); 271 } 272 273 void RTCDataChannel::didDetectError() 274 { 275 if (m_stopped) 276 return; 277 278 scheduleDispatchEvent(Event::create(EventTypeNames::error)); 279 } 280 281 const AtomicString& RTCDataChannel::interfaceName() const 282 { 283 return EventTargetNames::RTCDataChannel; 284 } 285 286 ExecutionContext* RTCDataChannel::executionContext() const 287 { 288 return m_executionContext; 289 } 290 291 void RTCDataChannel::stop() 292 { 293 m_stopped = true; 294 m_readyState = ReadyStateClosed; 295 m_handler->setClient(0); 296 m_executionContext = 0; 297 } 298 299 void RTCDataChannel::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 300 { 301 m_scheduledEvents.append(event); 302 303 if (!m_scheduledEventTimer.isActive()) 304 m_scheduledEventTimer.startOneShot(0, FROM_HERE); 305 } 306 307 void RTCDataChannel::scheduledEventTimerFired(Timer<RTCDataChannel>*) 308 { 309 if (m_stopped) 310 return; 311 312 WillBeHeapVector<RefPtrWillBeMember<Event> > events; 313 events.swap(m_scheduledEvents); 314 315 WillBeHeapVector<RefPtrWillBeMember<Event> >::iterator it = events.begin(); 316 for (; it != events.end(); ++it) 317 dispatchEvent((*it).release()); 318 319 events.clear(); 320 } 321 322 void RTCDataChannel::clearWeakMembers(Visitor* visitor) 323 { 324 if (visitor->isAlive(m_connection)) 325 return; 326 stop(); 327 m_connection = nullptr; 328 } 329 330 void RTCDataChannel::trace(Visitor* visitor) 331 { 332 visitor->trace(m_scheduledEvents); 333 visitor->registerWeakMembers<RTCDataChannel, &RTCDataChannel::clearWeakMembers>(this); 334 EventTargetWithInlineData::trace(visitor); 335 } 336 337 } // namespace blink 338