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