return ((msg_type & 0xC000) == 0x4000);
}
-// IDs used for posted messages.
+// IDs used for posted messages for TurnServer::Allocation.
enum {
- MSG_TIMEOUT,
+ MSG_ALLOCATION_TIMEOUT,
};
// Encapsulates a TURN allocation.
: thread_(thread),
nonce_key_(rtc::CreateRandomString(kNonceKeySize)),
auth_hook_(NULL),
+ redirect_hook_(NULL),
enable_otu_nonce_(false) {
}
return;
}
+ if (redirect_hook_ != NULL && msg.type() == STUN_ALLOCATE_REQUEST) {
+ rtc::SocketAddress address;
+ if (redirect_hook_->ShouldRedirect(conn->src(), &address)) {
+ SendErrorResponseWithAlternateServer(
+ conn, &msg, address);
+ return;
+ }
+ }
+
// Look up the key that we'll use to validate the M-I. If we have an
// existing allocation, the key will already be cached.
Allocation* allocation = FindAllocation(conn);
}
if (!allocation && msg.type() == STUN_ALLOCATE_REQUEST) {
- // This is a new allocate request.
HandleAllocateRequest(conn, &msg, key);
} else if (allocation &&
(msg.type() != STUN_ALLOCATE_REQUEST ||
SendStun(conn, &resp);
}
+void TurnServer::SendErrorResponseWithAlternateServer(
+ Connection* conn, const StunMessage* msg,
+ const rtc::SocketAddress& addr) {
+ TurnMessage resp;
+ InitErrorResponse(msg, STUN_ERROR_TRY_ALTERNATE,
+ STUN_ERROR_REASON_TRY_ALTERNATE_SERVER, &resp);
+ VERIFY(resp.AddAttribute(new StunAddressAttribute(
+ STUN_ATTR_ALTERNATE_SERVER, addr)));
+ SendStun(conn, &resp);
+}
+
void TurnServer::SendStun(Connection* conn, StunMessage* msg) {
rtc::ByteBuffer buf;
// Add a SOFTWARE attribute if one is set.
InternalSocketMap::iterator iter = server_sockets_.find(socket);
if (iter != server_sockets_.end()) {
rtc::AsyncPacketSocket* socket = iter->first;
- delete socket;
+ // We must destroy the socket async to avoid invalidating the sigslot
+ // callback list iterator inside a sigslot callback.
+ rtc::Thread::Current()->Dispose(socket);
server_sockets_.erase(iter);
}
}
it != perms_.end(); ++it) {
delete *it;
}
- thread_->Clear(this, MSG_TIMEOUT);
+ thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
LOG_J(LS_INFO, this) << "Allocation destroyed";
}
// Figure out the lifetime and start the allocation timer.
int lifetime_secs = ComputeLifetime(msg);
- thread_->PostDelayed(lifetime_secs * 1000, this, MSG_TIMEOUT);
+ thread_->PostDelayed(lifetime_secs * 1000, this, MSG_ALLOCATION_TIMEOUT);
LOG_J(LS_INFO, this) << "Created allocation, lifetime=" << lifetime_secs;
int lifetime_secs = ComputeLifetime(msg);
// Reset the expiration timer.
- thread_->Clear(this, MSG_TIMEOUT);
- thread_->PostDelayed(lifetime_secs * 1000, this, MSG_TIMEOUT);
+ thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
+ thread_->PostDelayed(lifetime_secs * 1000, this, MSG_ALLOCATION_TIMEOUT);
LOG_J(LS_INFO, this) << "Refreshed allocation, lifetime=" << lifetime_secs;
}
void TurnServer::Allocation::OnMessage(rtc::Message* msg) {
- ASSERT(msg->message_id == MSG_TIMEOUT);
+ ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT);
SignalDestroyed(this);
delete this;
}
}
TurnServer::Permission::~Permission() {
- thread_->Clear(this, MSG_TIMEOUT);
+ thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
}
void TurnServer::Permission::Refresh() {
- thread_->Clear(this, MSG_TIMEOUT);
- thread_->PostDelayed(kPermissionTimeout, this, MSG_TIMEOUT);
+ thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
+ thread_->PostDelayed(kPermissionTimeout, this, MSG_ALLOCATION_TIMEOUT);
}
void TurnServer::Permission::OnMessage(rtc::Message* msg) {
- ASSERT(msg->message_id == MSG_TIMEOUT);
+ ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT);
SignalDestroyed(this);
delete this;
}
}
TurnServer::Channel::~Channel() {
- thread_->Clear(this, MSG_TIMEOUT);
+ thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
}
void TurnServer::Channel::Refresh() {
- thread_->Clear(this, MSG_TIMEOUT);
- thread_->PostDelayed(kChannelTimeout, this, MSG_TIMEOUT);
+ thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
+ thread_->PostDelayed(kChannelTimeout, this, MSG_ALLOCATION_TIMEOUT);
}
void TurnServer::Channel::OnMessage(rtc::Message* msg) {
- ASSERT(msg->message_id == MSG_TIMEOUT);
+ ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT);
SignalDestroyed(this);
delete this;
}