Fix an NPE when creating TurnPort with a NULL socket.

BUG=4827

Review URL: https://codereview.webrtc.org/1241943002

Cr-Commit-Position: refs/heads/master@{#9601}
diff --git a/webrtc/p2p/client/basicportallocator.cc b/webrtc/p2p/client/basicportallocator.cc
index 1965ad9..3f5aa0a 100644
--- a/webrtc/p2p/client/basicportallocator.cc
+++ b/webrtc/p2p/client/basicportallocator.cc
@@ -58,94 +58,9 @@
 }  // namespace
 
 namespace cricket {
-
 const uint32 DISABLE_ALL_PHASES =
-  PORTALLOCATOR_DISABLE_UDP
-  | PORTALLOCATOR_DISABLE_TCP
-  | PORTALLOCATOR_DISABLE_STUN
-  | PORTALLOCATOR_DISABLE_RELAY;
-
-// Performs the allocation of ports, in a sequenced (timed) manner, for a given
-// network and IP address.
-class AllocationSequence : public rtc::MessageHandler,
-                           public sigslot::has_slots<> {
- public:
-  enum State {
-    kInit,       // Initial state.
-    kRunning,    // Started allocating ports.
-    kStopped,    // Stopped from running.
-    kCompleted,  // All ports are allocated.
-
-    // kInit --> kRunning --> {kCompleted|kStopped}
-  };
-
-  AllocationSequence(BasicPortAllocatorSession* session,
-                     rtc::Network* network,
-                     PortConfiguration* config,
-                     uint32 flags);
-  ~AllocationSequence();
-  bool Init();
-  void Clear();
-
-  State state() const { return state_; }
-
-  // Disables the phases for a new sequence that this one already covers for an
-  // equivalent network setup.
-  void DisableEquivalentPhases(rtc::Network* network,
-      PortConfiguration* config, uint32* flags);
-
-  // Starts and stops the sequence.  When started, it will continue allocating
-  // new ports on its own timed schedule.
-  void Start();
-  void Stop();
-
-  // MessageHandler
-  void OnMessage(rtc::Message* msg);
-
-  void EnableProtocol(ProtocolType proto);
-  bool ProtocolEnabled(ProtocolType proto) const;
-
-  // Signal from AllocationSequence, when it's done with allocating ports.
-  // This signal is useful, when port allocation fails which doesn't result
-  // in any candidates. Using this signal BasicPortAllocatorSession can send
-  // its candidate discovery conclusion signal. Without this signal,
-  // BasicPortAllocatorSession doesn't have any event to trigger signal. This
-  // can also be achieved by starting timer in BPAS.
-  sigslot::signal1<AllocationSequence*> SignalPortAllocationComplete;
-
- private:
-  typedef std::vector<ProtocolType> ProtocolList;
-
-  bool IsFlagSet(uint32 flag) {
-    return ((flags_ & flag) != 0);
-  }
-  void CreateUDPPorts();
-  void CreateTCPPorts();
-  void CreateStunPorts();
-  void CreateRelayPorts();
-  void CreateGturnPort(const RelayServerConfig& config);
-  void CreateTurnPort(const RelayServerConfig& config);
-
-  void OnReadPacket(rtc::AsyncPacketSocket* socket,
-                    const char* data, size_t size,
-                    const rtc::SocketAddress& remote_addr,
-                    const rtc::PacketTime& packet_time);
-
-  void OnPortDestroyed(PortInterface* port);
-
-  BasicPortAllocatorSession* session_;
-  rtc::Network* network_;
-  rtc::IPAddress ip_;
-  PortConfiguration* config_;
-  State state_;
-  uint32 flags_;
-  ProtocolList protocols_;
-  rtc::scoped_ptr<rtc::AsyncPacketSocket> udp_socket_;
-  // There will be only one udp port per AllocationSequence.
-  UDPPort* udp_port_;
-  std::vector<TurnPort*> turn_ports_;
-  int phase_;
-};
+    PORTALLOCATOR_DISABLE_UDP | PORTALLOCATOR_DISABLE_TCP |
+    PORTALLOCATOR_DISABLE_STUN | PORTALLOCATOR_DISABLE_RELAY;
 
 // BasicPortAllocator
 BasicPortAllocator::BasicPortAllocator(
@@ -1059,7 +974,7 @@
     // TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled
     // due to webrtc bug https://code.google.com/p/webrtc/issues/detail?id=3537
     if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
-        relay_port->proto == PROTO_UDP) {
+        relay_port->proto == PROTO_UDP && udp_socket_) {
       port = TurnPort::Create(session_->network_thread(),
                               session_->socket_factory(),
                               network_, udp_socket_.get(),
diff --git a/webrtc/p2p/client/basicportallocator.h b/webrtc/p2p/client/basicportallocator.h
index f2d92ef..a27ff4c 100644
--- a/webrtc/p2p/client/basicportallocator.h
+++ b/webrtc/p2p/client/basicportallocator.h
@@ -237,6 +237,93 @@
       RelayType turn_type, ProtocolType type) const;
 };
 
+class UDPPort;
+class TurnPort;
+
+// Performs the allocation of ports, in a sequenced (timed) manner, for a given
+// network and IP address.
+class AllocationSequence : public rtc::MessageHandler,
+                           public sigslot::has_slots<> {
+ public:
+  enum State {
+    kInit,       // Initial state.
+    kRunning,    // Started allocating ports.
+    kStopped,    // Stopped from running.
+    kCompleted,  // All ports are allocated.
+
+    // kInit --> kRunning --> {kCompleted|kStopped}
+  };
+  AllocationSequence(BasicPortAllocatorSession* session,
+                     rtc::Network* network,
+                     PortConfiguration* config,
+                     uint32 flags);
+  ~AllocationSequence();
+  bool Init();
+  void Clear();
+
+  State state() const { return state_; }
+
+  // Disables the phases for a new sequence that this one already covers for an
+  // equivalent network setup.
+  void DisableEquivalentPhases(rtc::Network* network,
+                               PortConfiguration* config,
+                               uint32* flags);
+
+  // Starts and stops the sequence.  When started, it will continue allocating
+  // new ports on its own timed schedule.
+  void Start();
+  void Stop();
+
+  // MessageHandler
+  void OnMessage(rtc::Message* msg);
+
+  void EnableProtocol(ProtocolType proto);
+  bool ProtocolEnabled(ProtocolType proto) const;
+
+  // Signal from AllocationSequence, when it's done with allocating ports.
+  // This signal is useful, when port allocation fails which doesn't result
+  // in any candidates. Using this signal BasicPortAllocatorSession can send
+  // its candidate discovery conclusion signal. Without this signal,
+  // BasicPortAllocatorSession doesn't have any event to trigger signal. This
+  // can also be achieved by starting timer in BPAS.
+  sigslot::signal1<AllocationSequence*> SignalPortAllocationComplete;
+
+ protected:
+  // For testing.
+  void CreateTurnPort(const RelayServerConfig& config);
+
+ private:
+  typedef std::vector<ProtocolType> ProtocolList;
+
+  bool IsFlagSet(uint32 flag) { return ((flags_ & flag) != 0); }
+  void CreateUDPPorts();
+  void CreateTCPPorts();
+  void CreateStunPorts();
+  void CreateRelayPorts();
+  void CreateGturnPort(const RelayServerConfig& config);
+
+  void OnReadPacket(rtc::AsyncPacketSocket* socket,
+                    const char* data,
+                    size_t size,
+                    const rtc::SocketAddress& remote_addr,
+                    const rtc::PacketTime& packet_time);
+
+  void OnPortDestroyed(PortInterface* port);
+
+  BasicPortAllocatorSession* session_;
+  rtc::Network* network_;
+  rtc::IPAddress ip_;
+  PortConfiguration* config_;
+  State state_;
+  uint32 flags_;
+  ProtocolList protocols_;
+  rtc::scoped_ptr<rtc::AsyncPacketSocket> udp_socket_;
+  // There will be only one udp port per AllocationSequence.
+  UDPPort* udp_port_;
+  std::vector<TurnPort*> turn_ports_;
+  int phase_;
+};
+
 }  // namespace cricket
 
 #endif  // WEBRTC_P2P_CLIENT_BASICPORTALLOCATOR_H_
diff --git a/webrtc/p2p/client/portallocator_unittest.cc b/webrtc/p2p/client/portallocator_unittest.cc
index 6940ea1..7dc2514 100644
--- a/webrtc/p2p/client/portallocator_unittest.cc
+++ b/webrtc/p2p/client/portallocator_unittest.cc
@@ -20,6 +20,7 @@
 #include "webrtc/base/firewallsocketserver.h"
 #include "webrtc/base/gunit.h"
 #include "webrtc/base/helpers.h"
+#include "webrtc/base/ipaddress.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/natserver.h"
 #include "webrtc/base/natsocketfactory.h"
@@ -1159,3 +1160,34 @@
     (reinterpret_cast<cricket::Port*>(*it))->Destroy();
   }
 }
+
+class AllocationSequenceForTest : public cricket::AllocationSequence {
+ public:
+  AllocationSequenceForTest(cricket::BasicPortAllocatorSession* session,
+                            rtc::Network* network,
+                            cricket::PortConfiguration* config,
+                            uint32 flags)
+      : cricket::AllocationSequence(session, network, config, flags) {}
+  using cricket::AllocationSequence::CreateTurnPort;
+};
+
+TEST_F(PortAllocatorTest, TestCreateTurnPortWithNullSocket) {
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+
+  cricket::ServerAddresses stun_servers;
+  stun_servers.insert(kStunAddr);
+  cricket::PortConfiguration config(stun_servers, kIceUfrag0, kIcePwd0);
+  rtc::Network network1("test_eth0", "Test Network Adapter 1",
+                        rtc::IPAddress(0x12345600U), 24);
+  uint32 flag = cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
+  AllocationSequenceForTest alloc_sequence(
+      static_cast<cricket::BasicPortAllocatorSession*>(session_.get()),
+      &network1, &config, flag);
+  // This simply tests it will not crash if udp_socket_ in the
+  // AllocationSequence is null, which is chosen in the constructor.
+  cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
+  relay_server.ports.push_back(
+      cricket::ProtocolAddress(kTurnUdpIntAddr, cricket::PROTO_UDP, false));
+  alloc_sequence.CreateTurnPort(relay_server);
+}