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}
This commit is contained in:
honghaiz 2015-07-17 16:21:55 -07:00 committed by Commit bot
parent be37888b6d
commit f421bdc68d
3 changed files with 122 additions and 88 deletions

View File

@ -58,94 +58,9 @@ int ShakeDelay() {
} // 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 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
// 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(),

View File

@ -237,6 +237,93 @@ struct PortConfiguration : public rtc::MessageData {
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_

View File

@ -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 @@ TEST_F(PortAllocatorTest, TestDestroyPortsNonSharedSockets) {
(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);
}