Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / p2p / client / basicportallocator.cc
index 7c285d1..12d70a3 100644 (file)
@@ -148,6 +148,9 @@ class AllocationSequence : public talk_base::MessageHandler,
                     const talk_base::PacketTime& packet_time);
 
   void OnPortDestroyed(PortInterface* port);
+  void OnResolvedTurnServerAddress(
+    TurnPort* port, const talk_base::SocketAddress& server_address,
+    const talk_base::SocketAddress& resolved_server_address);
 
   BasicPortAllocatorSession* session_;
   talk_base::Network* network_;
@@ -157,8 +160,10 @@ class AllocationSequence : public talk_base::MessageHandler,
   uint32 flags_;
   ProtocolList protocols_;
   talk_base::scoped_ptr<talk_base::AsyncPacketSocket> udp_socket_;
-  // Keeping a list of all UDP based ports.
-  std::deque<Port*> ports;
+  // There will be only one udp port per AllocationSequence.
+  Port* udp_port_;
+  // Keeping a map for turn ports keyed with server addresses.
+  std::map<talk_base::SocketAddress, Port*> turn_ports_;
   int phase_;
 };
 
@@ -693,6 +698,7 @@ AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
       state_(kInit),
       flags_(flags),
       udp_socket_(),
+      udp_port_(NULL),
       phase_(0) {
 }
 
@@ -855,18 +861,22 @@ void AllocationSequence::CreateUDPPorts() {
   }
 
   if (port) {
-    ports.push_back(port);
     // If shared socket is enabled, STUN candidate will be allocated by the
     // UDPPort.
-    if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
-        !IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
-      ASSERT(config_ && !config_->stun_address.IsNil());
-      if (!(config_ && !config_->stun_address.IsNil())) {
-        LOG(LS_WARNING)
-            << "AllocationSequence: No STUN server configured, skipping.";
-        return;
+    if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
+      udp_port_ = port;
+
+      // If STUN is not disabled, setting stun server address to port.
+      if (!IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
+        // If there is a TURN UDP server available, then we will use TURN port
+        // to get stun address, otherwise by UDP port.
+        // Shared socket mode is not used in GTURN mode.
+        if (config_ &&
+            !config_->SupportsProtocol(RELAY_TURN, PROTO_UDP) &&
+            !config_->stun_address.IsNil()) {
+          port->set_server_addr(config_->stun_address);
+        }
       }
-      port->set_server_addr(config_->stun_address);
     }
 
     session_->AddAllocatedPort(port, this, true);
@@ -992,17 +1002,41 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
   PortList::const_iterator relay_port;
   for (relay_port = config.ports.begin();
        relay_port != config.ports.end(); ++relay_port) {
-    TurnPort* port = TurnPort::Create(session_->network_thread(),
-                                      session_->socket_factory(),
-                                      network_, ip_,
-                                      session_->allocator()->min_port(),
-                                      session_->allocator()->max_port(),
-                                      session_->username(),
-                                      session_->password(),
-                                      *relay_port, config.credentials);
-    if (port) {
-      session_->AddAllocatedPort(port, this, true);
+    TurnPort* port = NULL;
+    // Shared socket mode must be enabled only for UDP based ports. Hence
+    // don't pass shared socket for ports which will create TCP sockets.
+    if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
+        relay_port->proto == PROTO_UDP) {
+      port = TurnPort::Create(session_->network_thread(),
+                              session_->socket_factory(),
+                              network_, udp_socket_.get(),
+                              session_->username(), session_->password(),
+                              *relay_port, config.credentials);
+      // If we are using shared socket for TURN and udp ports, we need to
+      // find a way to demux the packets to the correct port when received.
+      // Mapping against server_address is one way of doing this. When packet
+      // is received the remote_address will be checked against the map.
+      // If server address is not resolved, a signal will be sent from the port
+      // after the address is resolved. The map entry will updated with the
+      // resolved address when the signal is received from the port.
+      if ((*relay_port).address.IsUnresolved()) {
+        // If server address is not resolved then listen for signal from port.
+        port->SignalResolvedServerAddress.connect(
+            this, &AllocationSequence::OnResolvedTurnServerAddress);
+      }
+      turn_ports_[(*relay_port).address] = port;
+    } else {
+      port = TurnPort::Create(session_->network_thread(),
+                              session_->socket_factory(),
+                              network_, ip_,
+                              session_->allocator()->min_port(),
+                              session_->allocator()->max_port(),
+                              session_->username(),
+                              session_->password(),
+                              *relay_port, config.credentials);
     }
+    ASSERT(port != NULL);
+    session_->AddAllocatedPort(port, this, true);
   }
 }
 
@@ -1011,22 +1045,51 @@ void AllocationSequence::OnReadPacket(
     const talk_base::SocketAddress& remote_addr,
     const talk_base::PacketTime& packet_time) {
   ASSERT(socket == udp_socket_.get());
-  for (std::deque<Port*>::iterator iter = ports.begin();
-       iter != ports.end(); ++iter) {
-    // We have only one port in the queue.
-    // TODO(mallinath) - Add shared socket support to Relay and Turn ports.
-    if ((*iter)->HandleIncomingPacket(
-        socket, data, size, remote_addr, packet_time)) {
-      break;
-    }
+  // If the packet is received from one of the TURN server in the config, then
+  // pass down the packet to that port, otherwise it will be handed down to
+  // the local udp port.
+  Port* port = NULL;
+  std::map<talk_base::SocketAddress, Port*>::iterator iter =
+      turn_ports_.find(remote_addr);
+  if (iter != turn_ports_.end()) {
+    port = iter->second;
+  } else if (udp_port_) {
+    port = udp_port_;
+  }
+  ASSERT(port != NULL);
+  if (port) {
+    port->HandleIncomingPacket(socket, data, size, remote_addr, packet_time);
   }
 }
 
 void AllocationSequence::OnPortDestroyed(PortInterface* port) {
-  std::deque<Port*>::iterator iter =
-      std::find(ports.begin(), ports.end(), port);
-  ASSERT(iter != ports.end());
-  ports.erase(iter);
+  if (udp_port_ == port) {
+    udp_port_ = NULL;
+  } else {
+    std::map<talk_base::SocketAddress, Port*>::iterator iter;
+    for (iter = turn_ports_.begin(); iter != turn_ports_.end(); ++iter) {
+      if (iter->second == port) {
+        turn_ports_.erase(iter);
+        break;
+      }
+    }
+  }
+}
+
+void AllocationSequence::OnResolvedTurnServerAddress(
+    TurnPort* port, const talk_base::SocketAddress& server_address,
+    const talk_base::SocketAddress& resolved_server_address) {
+  std::map<talk_base::SocketAddress, Port*>::iterator iter;
+  iter = turn_ports_.find(server_address);
+  if (iter == turn_ports_.end()) {
+    LOG(LS_INFO) << "TurnPort entry is not found in the map.";
+    return;
+  }
+
+  ASSERT(iter->second == port);
+  // Remove old entry and then insert using the resolved address as key.
+  turn_ports_.erase(iter);
+  turn_ports_[resolved_server_address] = port;
 }
 
 // PortConfiguration
@@ -1044,7 +1107,7 @@ void PortConfiguration::AddRelay(const RelayServerConfig& config) {
 }
 
 bool PortConfiguration::SupportsProtocol(
-    const RelayServerConfig& relay, ProtocolType type) {
+    const RelayServerConfig& relay, ProtocolType type) const {
   PortList::const_iterator relay_port;
   for (relay_port = relay.ports.begin();
         relay_port != relay.ports.end();
@@ -1055,4 +1118,14 @@ bool PortConfiguration::SupportsProtocol(
   return false;
 }
 
+bool PortConfiguration::SupportsProtocol(const RelayType turn_type,
+                                         ProtocolType type) const {
+  for (size_t i = 0; i < relays.size(); ++i) {
+    if (relays[i].type == turn_type &&
+        SupportsProtocol(relays[i], type))
+      return true;
+  }
+  return false;
+}
+
 }  // namespace cricket