blob: 3de001b54353c9b0b0ea6c4456e22e4c1cfe6894 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2012, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27#include "talk/app/webrtc/datachannel.h"
28
29#include <string>
30
wu@webrtc.org78187522013-10-07 23:32:02 +000031#include "talk/app/webrtc/mediastreamprovider.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032#include "talk/base/logging.h"
33#include "talk/base/refcount.h"
34
35namespace webrtc {
36
wu@webrtc.orgd64719d2013-08-01 00:00:07 +000037static size_t kMaxQueuedReceivedDataPackets = 100;
38static size_t kMaxQueuedSendDataPackets = 100;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039
40talk_base::scoped_refptr<DataChannel> DataChannel::Create(
wu@webrtc.org78187522013-10-07 23:32:02 +000041 DataChannelProviderInterface* provider,
42 cricket::DataChannelType dct,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000043 const std::string& label,
44 const DataChannelInit* config) {
45 talk_base::scoped_refptr<DataChannel> channel(
wu@webrtc.org78187522013-10-07 23:32:02 +000046 new talk_base::RefCountedObject<DataChannel>(provider, dct, label));
henrike@webrtc.org28e20752013-07-10 00:45:36 +000047 if (!channel->Init(config)) {
48 return NULL;
49 }
50 return channel;
51}
52
wu@webrtc.org78187522013-10-07 23:32:02 +000053DataChannel::DataChannel(
54 DataChannelProviderInterface* provider,
55 cricket::DataChannelType dct,
56 const std::string& label)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057 : label_(label),
58 observer_(NULL),
59 state_(kConnecting),
60 was_ever_writable_(false),
wu@webrtc.org78187522013-10-07 23:32:02 +000061 connected_to_provider_(false),
62 data_channel_type_(dct),
63 provider_(provider),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000064 send_ssrc_set_(false),
65 send_ssrc_(0),
66 receive_ssrc_set_(false),
67 receive_ssrc_(0) {
68}
69
70bool DataChannel::Init(const DataChannelInit* config) {
71 if (config) {
wu@webrtc.org78187522013-10-07 23:32:02 +000072 if (data_channel_type_ == cricket::DCT_RTP &&
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073 (config->reliable ||
74 config->id != -1 ||
75 config->maxRetransmits != -1 ||
76 config->maxRetransmitTime != -1)) {
77 LOG(LS_ERROR) << "Failed to initialize the RTP data channel due to "
78 << "invalid DataChannelInit.";
79 return false;
wu@webrtc.org78187522013-10-07 23:32:02 +000080 } else if (data_channel_type_ == cricket::DCT_SCTP) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081 if (config->id < -1 ||
82 config->maxRetransmits < -1 ||
83 config->maxRetransmitTime < -1) {
84 LOG(LS_ERROR) << "Failed to initialize the SCTP data channel due to "
85 << "invalid DataChannelInit.";
86 return false;
87 }
88 if (config->maxRetransmits != -1 && config->maxRetransmitTime != -1) {
89 LOG(LS_ERROR) <<
90 "maxRetransmits and maxRetransmitTime should not be both set.";
91 return false;
92 }
93 }
94 config_ = *config;
95 }
96 return true;
97}
98
99bool DataChannel::HasNegotiationCompleted() {
100 return send_ssrc_set_ == receive_ssrc_set_;
101}
102
103DataChannel::~DataChannel() {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000104 ClearQueuedReceivedData();
105 ClearQueuedSendData();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000106 ClearQueuedControlData();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107}
108
109void DataChannel::RegisterObserver(DataChannelObserver* observer) {
110 observer_ = observer;
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000111 DeliverQueuedReceivedData();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112}
113
114void DataChannel::UnregisterObserver() {
115 observer_ = NULL;
116}
117
118bool DataChannel::reliable() const {
wu@webrtc.org78187522013-10-07 23:32:02 +0000119 if (data_channel_type_ == cricket::DCT_RTP) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120 return false;
121 } else {
122 return config_.maxRetransmits == -1 &&
123 config_.maxRetransmitTime == -1;
124 }
125}
126
127uint64 DataChannel::buffered_amount() const {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000128 uint64 buffered_amount = 0;
129 for (std::deque<DataBuffer*>::const_iterator it = queued_send_data_.begin();
130 it != queued_send_data_.end();
131 ++it) {
132 buffered_amount += (*it)->size();
133 }
134 return buffered_amount;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135}
136
137void DataChannel::Close() {
138 if (state_ == kClosed)
139 return;
140 send_ssrc_ = 0;
141 send_ssrc_set_ = false;
142 SetState(kClosing);
143 UpdateState();
144}
145
146bool DataChannel::Send(const DataBuffer& buffer) {
147 if (state_ != kOpen) {
148 return false;
149 }
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000150 // If the queue is non-empty, we're waiting for SignalReadyToSend,
151 // so just add to the end of the queue and keep waiting.
152 if (!queued_send_data_.empty()) {
153 return QueueSendData(buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155
156 cricket::SendDataResult send_result;
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000157 if (!InternalSendWithoutQueueing(buffer, &send_result)) {
158 if (send_result == cricket::SDR_BLOCK) {
159 return QueueSendData(buffer);
160 }
161 // Fail for other results.
162 // TODO(jiayl): We should close the data channel in this case.
163 return false;
164 }
165 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166}
167
wu@webrtc.org91053e72013-08-10 07:18:04 +0000168void DataChannel::QueueControl(const talk_base::Buffer* buffer) {
169 queued_control_data_.push(buffer);
170}
171
172bool DataChannel::SendControl(const talk_base::Buffer* buffer) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000173 if (data_channel_type_ == cricket::DCT_RTP) {
174 delete buffer;
175 return false;
176 }
177
wu@webrtc.org91053e72013-08-10 07:18:04 +0000178 if (state_ != kOpen) {
179 QueueControl(buffer);
180 return true;
181 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000182
183 cricket::SendDataParams send_params;
184 send_params.ssrc = config_.id;
185 send_params.ordered = true;
186 send_params.type = cricket::DMT_CONTROL;
187
188 cricket::SendDataResult send_result;
wu@webrtc.org78187522013-10-07 23:32:02 +0000189 bool retval = provider_->SendData(send_params, *buffer, &send_result);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000190 if (!retval && send_result == cricket::SDR_BLOCK) {
191 // Link is congested. Queue for later.
192 QueueControl(buffer);
193 } else {
194 delete buffer;
195 }
196 return retval;
197}
198
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199void DataChannel::SetReceiveSsrc(uint32 receive_ssrc) {
200 if (receive_ssrc_set_) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000201 ASSERT(data_channel_type_ == cricket::DCT_RTP ||
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000202 !send_ssrc_set_ ||
203 receive_ssrc_ == send_ssrc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000204 return;
205 }
206 receive_ssrc_ = receive_ssrc;
207 receive_ssrc_set_ = true;
208 UpdateState();
209}
210
211// The remote peer request that this channel shall be closed.
212void DataChannel::RemotePeerRequestClose() {
213 DoClose();
214}
215
216void DataChannel::SetSendSsrc(uint32 send_ssrc) {
217 if (send_ssrc_set_) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000218 ASSERT(data_channel_type_ == cricket::DCT_RTP ||
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000219 !receive_ssrc_set_ ||
220 receive_ssrc_ == send_ssrc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221 return;
222 }
223 send_ssrc_ = send_ssrc;
224 send_ssrc_set_ = true;
225 UpdateState();
226}
227
228// The underlaying data engine is closing.
wu@webrtc.org78187522013-10-07 23:32:02 +0000229// This function makes sure the DataChannel is disconnected and changes state to
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000230// kClosed.
231void DataChannel::OnDataEngineClose() {
232 DoClose();
233}
234
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000235void DataChannel::OnDataReceived(cricket::DataChannel* channel,
236 const cricket::ReceiveDataParams& params,
237 const talk_base::Buffer& payload) {
238 if (params.ssrc != receive_ssrc_) {
239 return;
240 }
241
242 bool binary = (params.type == cricket::DMT_BINARY);
243 talk_base::scoped_ptr<DataBuffer> buffer(new DataBuffer(payload, binary));
244 if (was_ever_writable_ && observer_) {
245 observer_->OnMessage(*buffer.get());
246 } else {
247 if (queued_received_data_.size() > kMaxQueuedReceivedDataPackets) {
248 // TODO(jiayl): We should close the data channel in this case.
249 LOG(LS_ERROR)
250 << "Queued received data exceeds the max number of packes.";
251 ClearQueuedReceivedData();
252 }
253 queued_received_data_.push(buffer.release());
254 }
255}
256
257void DataChannel::OnChannelReady(bool writable) {
258 if (!writable) {
259 return;
260 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000261 // Update the readyState and send the queued control message if the channel
262 // is writable for the first time; otherwise it means the channel was blocked
263 // for sending and now unblocked, so send the queued data now.
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000264 if (!was_ever_writable_) {
265 was_ever_writable_ = true;
266 UpdateState();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000267 DeliverQueuedControlData();
268 ASSERT(queued_send_data_.empty());
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000269 } else if (state_ == kOpen) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000270 DeliverQueuedSendData();
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000271 }
272}
273
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274void DataChannel::DoClose() {
275 receive_ssrc_set_ = false;
276 send_ssrc_set_ = false;
277 SetState(kClosing);
278 UpdateState();
279}
280
281void DataChannel::UpdateState() {
282 switch (state_) {
283 case kConnecting: {
284 if (HasNegotiationCompleted()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000285 if (!connected_to_provider_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286 ConnectToDataSession();
287 }
288 if (was_ever_writable_) {
289 SetState(kOpen);
290 // If we have received buffers before the channel got writable.
291 // Deliver them now.
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000292 DeliverQueuedReceivedData();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293 }
294 }
295 break;
296 }
297 case kOpen: {
298 break;
299 }
300 case kClosing: {
wu@webrtc.org78187522013-10-07 23:32:02 +0000301 if (connected_to_provider_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000302 DisconnectFromDataSession();
303 }
304 if (HasNegotiationCompleted()) {
305 SetState(kClosed);
306 }
307 break;
308 }
309 case kClosed:
310 break;
311 }
312}
313
314void DataChannel::SetState(DataState state) {
315 state_ = state;
316 if (observer_) {
317 observer_->OnStateChange();
318 }
319}
320
321void DataChannel::ConnectToDataSession() {
wu@webrtc.org78187522013-10-07 23:32:02 +0000322 connected_to_provider_ = provider_->ConnectDataChannel(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000323}
324
325void DataChannel::DisconnectFromDataSession() {
wu@webrtc.org78187522013-10-07 23:32:02 +0000326 provider_->DisconnectDataChannel(this);
327 connected_to_provider_ = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000328}
329
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000330void DataChannel::DeliverQueuedReceivedData() {
331 if (!was_ever_writable_ || !observer_) {
332 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000334
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000335 while (!queued_received_data_.empty()) {
336 DataBuffer* buffer = queued_received_data_.front();
337 observer_->OnMessage(*buffer);
338 queued_received_data_.pop();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000339 delete buffer;
340 }
341}
342
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000343void DataChannel::ClearQueuedReceivedData() {
344 while (!queued_received_data_.empty()) {
345 DataBuffer* buffer = queued_received_data_.front();
346 queued_received_data_.pop();
347 delete buffer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000348 }
349}
350
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000351void DataChannel::DeliverQueuedSendData() {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000352 DeliverQueuedControlData();
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000353 if (!was_ever_writable_) {
354 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000355 }
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000356
357 while (!queued_send_data_.empty()) {
358 DataBuffer* buffer = queued_send_data_.front();
359 cricket::SendDataResult send_result;
360 if (!InternalSendWithoutQueueing(*buffer, &send_result)) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000361 LOG(LS_WARNING) << "DeliverQueuedSendData aborted due to send_result "
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000362 << send_result;
363 break;
364 }
365 queued_send_data_.pop_front();
366 delete buffer;
367 }
368}
369
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000370void DataChannel::ClearQueuedControlData() {
371 while (!queued_control_data_.empty()) {
372 const talk_base::Buffer *buf = queued_control_data_.front();
373 queued_control_data_.pop();
374 delete buf;
375 }
376}
377
wu@webrtc.org91053e72013-08-10 07:18:04 +0000378void DataChannel::DeliverQueuedControlData() {
379 if (was_ever_writable_) {
380 while (!queued_control_data_.empty()) {
381 const talk_base::Buffer *buf = queued_control_data_.front();
382 queued_control_data_.pop();
383 SendControl(buf);
384 }
385 }
386}
387
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000388void DataChannel::ClearQueuedSendData() {
wu@webrtc.orga0545692013-08-01 22:08:14 +0000389 while (!queued_send_data_.empty()) {
390 DataBuffer* buffer = queued_send_data_.front();
391 queued_send_data_.pop_front();
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000392 delete buffer;
393 }
394}
395
396bool DataChannel::InternalSendWithoutQueueing(
397 const DataBuffer& buffer, cricket::SendDataResult* send_result) {
398 cricket::SendDataParams send_params;
399
400 send_params.ssrc = send_ssrc_;
wu@webrtc.org78187522013-10-07 23:32:02 +0000401 if (data_channel_type_ == cricket::DCT_SCTP) {
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000402 send_params.ordered = config_.ordered;
403 send_params.max_rtx_count = config_.maxRetransmits;
404 send_params.max_rtx_ms = config_.maxRetransmitTime;
405 }
406 send_params.type = buffer.binary ? cricket::DMT_BINARY : cricket::DMT_TEXT;
407
wu@webrtc.org78187522013-10-07 23:32:02 +0000408 return provider_->SendData(send_params, buffer.data, send_result);
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000409}
410
411bool DataChannel::QueueSendData(const DataBuffer& buffer) {
412 if (queued_send_data_.size() > kMaxQueuedSendDataPackets) {
413 LOG(LS_ERROR) << "Can't buffer any more data in the data channel.";
414 return false;
415 }
416 queued_send_data_.push_back(new DataBuffer(buffer));
417 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000418}
419
420} // namespace webrtc