Update talk to 55821645.

TEST=try bots
R=mallinath@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/3139004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5053 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/app/webrtc/datachannel.cc b/talk/app/webrtc/datachannel.cc
index 3de001b..3a6046e 100644
--- a/talk/app/webrtc/datachannel.cc
+++ b/talk/app/webrtc/datachannel.cc
@@ -31,6 +31,7 @@
 #include "talk/app/webrtc/mediastreamprovider.h"
 #include "talk/base/logging.h"
 #include "talk/base/refcount.h"
+#include "talk/media/sctp/sctputils.h"
 
 namespace webrtc {
 
@@ -68,36 +69,35 @@
 }
 
 bool DataChannel::Init(const DataChannelInit* config) {
-  if (config) {
-    if (data_channel_type_ == cricket::DCT_RTP &&
-        (config->reliable ||
-         config->id != -1 ||
-         config->maxRetransmits != -1 ||
-         config->maxRetransmitTime != -1)) {
-      LOG(LS_ERROR) << "Failed to initialize the RTP data channel due to "
+  if (data_channel_type_ == cricket::DCT_RTP &&
+      (config->reliable ||
+       config->id != -1 ||
+       config->maxRetransmits != -1 ||
+       config->maxRetransmitTime != -1)) {
+    LOG(LS_ERROR) << "Failed to initialize the RTP data channel due to "
+                  << "invalid DataChannelInit.";
+    return false;
+  } else if (data_channel_type_ == cricket::DCT_SCTP) {
+    if (config->id < -1 ||
+        config->maxRetransmits < -1 ||
+        config->maxRetransmitTime < -1) {
+      LOG(LS_ERROR) << "Failed to initialize the SCTP data channel due to "
                     << "invalid DataChannelInit.";
       return false;
-    } else if (data_channel_type_ == cricket::DCT_SCTP) {
-      if (config->id < -1 ||
-          config->maxRetransmits < -1 ||
-          config->maxRetransmitTime < -1) {
-        LOG(LS_ERROR) << "Failed to initialize the SCTP data channel due to "
-                      << "invalid DataChannelInit.";
-        return false;
-      }
-      if (config->maxRetransmits != -1 && config->maxRetransmitTime != -1) {
-        LOG(LS_ERROR) <<
-            "maxRetransmits and maxRetransmitTime should not be both set.";
-        return false;
-      }
+    }
+    if (config->maxRetransmits != -1 && config->maxRetransmitTime != -1) {
+      LOG(LS_ERROR) <<
+          "maxRetransmits and maxRetransmitTime should not be both set.";
+      return false;
     }
     config_ = *config;
-  }
-  return true;
-}
 
-bool DataChannel::HasNegotiationCompleted() {
-  return send_ssrc_set_ == receive_ssrc_set_;
+    // Try to connect to the transport in case the transport channel already
+    // exists.
+    OnTransportChannelCreated();
+  }
+
+  return true;
 }
 
 DataChannel::~DataChannel() {
@@ -169,16 +169,13 @@
   queued_control_data_.push(buffer);
 }
 
-bool DataChannel::SendControl(const talk_base::Buffer* buffer) {
-  if (data_channel_type_ == cricket::DCT_RTP) {
-    delete buffer;
-    return false;
-  }
+bool DataChannel::SendOpenMessage(const talk_base::Buffer* raw_buffer) {
+  ASSERT(data_channel_type_ == cricket::DCT_SCTP &&
+         was_ever_writable_ &&
+         config_.id >= 0 &&
+         !config_.negotiated);
 
-  if (state_ != kOpen) {
-    QueueControl(buffer);
-    return true;
-  }
+  talk_base::scoped_ptr<const talk_base::Buffer> buffer(raw_buffer);
 
   cricket::SendDataParams send_params;
   send_params.ssrc = config_.id;
@@ -189,18 +186,15 @@
   bool retval = provider_->SendData(send_params, *buffer, &send_result);
   if (!retval && send_result == cricket::SDR_BLOCK) {
     // Link is congested.  Queue for later.
-    QueueControl(buffer);
-  } else {
-    delete buffer;
+    QueueControl(buffer.release());
   }
   return retval;
 }
 
 void DataChannel::SetReceiveSsrc(uint32 receive_ssrc) {
+  ASSERT(data_channel_type_ == cricket::DCT_RTP);
+
   if (receive_ssrc_set_) {
-    ASSERT(data_channel_type_ == cricket::DCT_RTP ||
-           !send_ssrc_set_ ||
-           receive_ssrc_ == send_ssrc_);
     return;
   }
   receive_ssrc_ = receive_ssrc;
@@ -214,10 +208,8 @@
 }
 
 void DataChannel::SetSendSsrc(uint32 send_ssrc) {
+  ASSERT(data_channel_type_ == cricket::DCT_RTP);
   if (send_ssrc_set_) {
-    ASSERT(data_channel_type_ == cricket::DCT_RTP ||
-           !receive_ssrc_set_ ||
-           receive_ssrc_ == send_ssrc_);
     return;
   }
   send_ssrc_ = send_ssrc;
@@ -263,8 +255,18 @@
   // for sending and now unblocked, so send the queued data now.
   if (!was_ever_writable_) {
     was_ever_writable_ = true;
+
+    if (data_channel_type_ == cricket::DCT_SCTP && !config_.negotiated) {
+      talk_base::Buffer* payload = new talk_base::Buffer;
+      if (!cricket::WriteDataChannelOpenMessage(label_, config_, payload)) {
+        // TODO(jiayl): close the data channel on this error.
+        LOG(LS_ERROR) << "Could not write data channel OPEN message";
+        return;
+      }
+      SendOpenMessage(payload);
+    }
+
     UpdateState();
-    DeliverQueuedControlData();
     ASSERT(queued_send_data_.empty());
   } else if (state_ == kOpen) {
     DeliverQueuedSendData();
@@ -281,11 +283,15 @@
 void DataChannel::UpdateState() {
   switch (state_) {
     case kConnecting: {
-      if (HasNegotiationCompleted()) {
-        if (!connected_to_provider_) {
-          ConnectToDataSession();
+      if (send_ssrc_set_ == receive_ssrc_set_) {
+        if (data_channel_type_ == cricket::DCT_RTP && !connected_to_provider_) {
+          connected_to_provider_ = provider_->ConnectDataChannel(this);
+          provider_->AddRtpDataStream(send_ssrc_, receive_ssrc_);
         }
         if (was_ever_writable_) {
+          // TODO(jiayl): Do not transition to kOpen if we failed to send the
+          // OPEN message.
+          DeliverQueuedControlData();
           SetState(kOpen);
           // If we have received buffers before the channel got writable.
           // Deliver them now.
@@ -298,10 +304,9 @@
       break;
     }
     case kClosing: {
-      if (connected_to_provider_) {
-        DisconnectFromDataSession();
-      }
-      if (HasNegotiationCompleted()) {
+      DisconnectFromTransport();
+
+      if (!send_ssrc_set_ && !receive_ssrc_set_) {
         SetState(kClosed);
       }
       break;
@@ -318,13 +323,18 @@
   }
 }
 
-void DataChannel::ConnectToDataSession() {
-  connected_to_provider_ = provider_->ConnectDataChannel(this);
-}
+void DataChannel::DisconnectFromTransport() {
+  if (!connected_to_provider_)
+    return;
 
-void DataChannel::DisconnectFromDataSession() {
   provider_->DisconnectDataChannel(this);
   connected_to_provider_ = false;
+
+  if (data_channel_type_ == cricket::DCT_RTP) {
+    provider_->RemoveRtpDataStream(send_ssrc_, receive_ssrc_);
+  } else {
+    provider_->RemoveSctpDataStream(config_.id);
+  }
 }
 
 void DataChannel::DeliverQueuedReceivedData() {
@@ -349,10 +359,12 @@
 }
 
 void DataChannel::DeliverQueuedSendData() {
+  ASSERT(was_ever_writable_ && state_ == kOpen);
+
+  // TODO(jiayl): Sending OPEN message here contradicts with the pre-condition
+  // that the readyState is open. According to the standard, the channel should
+  // not become open before the OPEN message is sent.
   DeliverQueuedControlData();
-  if (!was_ever_writable_) {
-    return;
-  }
 
   while (!queued_send_data_.empty()) {
     DataBuffer* buffer = queued_send_data_.front();
@@ -376,12 +388,11 @@
 }
 
 void DataChannel::DeliverQueuedControlData() {
-  if (was_ever_writable_) {
-    while (!queued_control_data_.empty()) {
-      const talk_base::Buffer *buf = queued_control_data_.front();
-      queued_control_data_.pop();
-      SendControl(buf);
-    }
+  ASSERT(was_ever_writable_);
+  while (!queued_control_data_.empty()) {
+    const talk_base::Buffer* buf = queued_control_data_.front();
+    queued_control_data_.pop();
+    SendOpenMessage(buf);
   }
 }
 
@@ -417,4 +428,22 @@
   return true;
 }
 
+void DataChannel::SetSctpSid(int sid) {
+  ASSERT(config_.id < 0 && sid >= 0 && data_channel_type_ == cricket::DCT_SCTP);
+  config_.id = sid;
+  provider_->AddSctpDataStream(sid);
+}
+
+void DataChannel::OnTransportChannelCreated() {
+  ASSERT(data_channel_type_ == cricket::DCT_SCTP);
+  if (!connected_to_provider_) {
+    connected_to_provider_ = provider_->ConnectDataChannel(this);
+  }
+  // The sid may have been unassigned when provider_->ConnectDataChannel was
+  // done. So always add the streams even if connected_to_provider_ is true.
+  if (config_.id >= 0) {
+    provider_->AddSctpDataStream(config_.id);
+  }
+}
+
 }  // namespace webrtc