зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1170645 - Intermittent crash in mozilla::net::nsWSAdmissionManager::RemoveFromQueue(mozilla::net::WebSocketChannel*), r=mcmanus
This commit is contained in:
Родитель
8afa7178e7
Коммит
c6803255b7
|
@ -267,8 +267,9 @@ public:
|
|||
rv = ws->mReconnectDelayTimer->InitWithCallback(
|
||||
ws, remainingDelay, nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG(("WebSocket: delaying websocket [this=%p] by %lu ms",
|
||||
ws, (unsigned long)remainingDelay));
|
||||
LOG(("WebSocket: delaying websocket [this=%p] by %lu ms, changing"
|
||||
" state to CONNECTING_DELAYED", ws,
|
||||
(unsigned long)remainingDelay));
|
||||
ws->mConnecting = CONNECTING_DELAYED;
|
||||
return;
|
||||
}
|
||||
|
@ -281,13 +282,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Delays disabled, or no previous failure, or we're reconnecting after
|
||||
// scheduled delay interval has passed: connect.
|
||||
// Post an event to avoid potential re-entering of nsWSAdmissionManager and
|
||||
// its lock.
|
||||
NS_DispatchToMainThread(
|
||||
NS_NewRunnableMethod(ws, &WebSocketChannel::BeginOpen),
|
||||
NS_DISPATCH_NORMAL);
|
||||
// Delays disabled, or no previous failure, or we're reconnecting after scheduled
|
||||
// delay interval has passed: connect.
|
||||
ws->BeginOpen(true);
|
||||
}
|
||||
|
||||
// Remove() also deletes all expired entries as it iterates: better for
|
||||
|
@ -342,6 +339,8 @@ public:
|
|||
// delay/queue the connection (returns false)
|
||||
static void ConditionallyConnect(WebSocketChannel *ws)
|
||||
{
|
||||
LOG(("Websocket: ConditionallyConnect: [this=%p]", ws));
|
||||
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
|
||||
MOZ_ASSERT(ws->mConnecting == NOT_CONNECTING, "opening state");
|
||||
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
|
@ -355,9 +354,12 @@ public:
|
|||
|
||||
// Always add ourselves to queue, even if we'll connect immediately
|
||||
nsOpenConn *newdata = new nsOpenConn(ws->mAddress, ws);
|
||||
LOG(("Websocket: adding conn %p to the queue", newdata));
|
||||
sManager->mQueue.AppendElement(newdata);
|
||||
|
||||
if (found) {
|
||||
LOG(("Websocket: some other channel is connecting, changing state to "
|
||||
"CONNECTING_QUEUED"));
|
||||
ws->mConnecting = CONNECTING_QUEUED;
|
||||
} else {
|
||||
sManager->mFailures.DelayOrBegin(ws);
|
||||
|
@ -366,6 +368,9 @@ public:
|
|||
|
||||
static void OnConnected(WebSocketChannel *aChannel)
|
||||
{
|
||||
LOG(("Websocket: OnConnected: [this=%p]", aChannel));
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
|
||||
MOZ_ASSERT(aChannel->mConnecting == CONNECTING_IN_PROGRESS,
|
||||
"Channel completed connect, but not connecting?");
|
||||
|
||||
|
@ -374,6 +379,7 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
LOG(("Websocket: changing state to NOT_CONNECTING"));
|
||||
aChannel->mConnecting = NOT_CONNECTING;
|
||||
|
||||
// Remove from queue
|
||||
|
@ -392,6 +398,9 @@ public:
|
|||
// w/o ever successfully creating a connection)
|
||||
static void OnStopSession(WebSocketChannel *aChannel, nsresult aReason)
|
||||
{
|
||||
LOG(("Websocket: OnStopSession: [this=%p, reason=0x%08x]", aChannel,
|
||||
aReason));
|
||||
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
if (!sManager) {
|
||||
return;
|
||||
|
@ -420,6 +429,8 @@ public:
|
|||
}
|
||||
|
||||
if (aChannel->mConnecting) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
|
||||
|
||||
// Only way a connecting channel may get here w/o failing is if it was
|
||||
// closed with GOING_AWAY (1001) because of navigation, tab close, etc.
|
||||
MOZ_ASSERT(NS_FAILED(aReason) ||
|
||||
|
@ -429,6 +440,7 @@ public:
|
|||
sManager->RemoveFromQueue(aChannel);
|
||||
|
||||
bool wasNotQueued = (aChannel->mConnecting != CONNECTING_QUEUED);
|
||||
LOG(("Websocket: changing state to NOT_CONNECTING"));
|
||||
aChannel->mConnecting = NOT_CONNECTING;
|
||||
if (wasNotQueued) {
|
||||
sManager->ConnectNext(aChannel->mAddress);
|
||||
|
@ -489,6 +501,8 @@ private:
|
|||
|
||||
void ConnectNext(nsCString &hostName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
|
||||
|
||||
int32_t index = IndexOf(hostName);
|
||||
if (index >= 0) {
|
||||
WebSocketChannel *chan = mQueue[index]->mChannel;
|
||||
|
@ -503,11 +517,13 @@ private:
|
|||
|
||||
void RemoveFromQueue(WebSocketChannel *aChannel)
|
||||
{
|
||||
LOG(("Websocket: RemoveFromQueue: [this=%p]", aChannel));
|
||||
int32_t index = IndexOf(aChannel);
|
||||
MOZ_ASSERT(index >= 0, "connection to remove not in queue");
|
||||
if (index >= 0) {
|
||||
nsOpenConn *olddata = mQueue[index];
|
||||
mQueue.RemoveElementAt(index);
|
||||
LOG(("Websocket: removing conn %p from the queue", olddata));
|
||||
delete olddata;
|
||||
}
|
||||
}
|
||||
|
@ -614,8 +630,6 @@ public:
|
|||
{
|
||||
MOZ_ASSERT(mChannel->IsOnTargetThread());
|
||||
|
||||
nsWSAdmissionManager::OnStopSession(mChannel, mReason);
|
||||
|
||||
if (mListenerMT) {
|
||||
mListenerMT->mListener->OnStop(mListenerMT->mContext, mReason);
|
||||
mChannel->mListenerMT = nullptr;
|
||||
|
@ -1311,26 +1325,38 @@ WebSocketChannel::IsEncrypted() const
|
|||
}
|
||||
|
||||
void
|
||||
WebSocketChannel::BeginOpen()
|
||||
WebSocketChannel::BeginOpen(bool aCalledFromAdmissionManager)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(
|
||||
NS_NewRunnableMethod(this, &WebSocketChannel::BeginOpen),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
|
||||
|
||||
LOG(("WebSocketChannel::BeginOpen() %p\n", this));
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// Important that we set CONNECTING_IN_PROGRESS before any call to
|
||||
// AbortSession here: ensures that any remaining queued connection(s) are
|
||||
// scheduled in OnStopSession
|
||||
LOG(("Websocket: changing state to CONNECTING_IN_PROGRESS"));
|
||||
mConnecting = CONNECTING_IN_PROGRESS;
|
||||
|
||||
if (aCalledFromAdmissionManager) {
|
||||
// When called from nsWSAdmissionManager post an event to avoid potential
|
||||
// re-entering of nsWSAdmissionManager and its lock.
|
||||
NS_DispatchToMainThread(
|
||||
NS_NewRunnableMethod(this, &WebSocketChannel::BeginOpenInternal),
|
||||
NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
BeginOpenInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketChannel::BeginOpenInternal()
|
||||
{
|
||||
LOG(("WebSocketChannel::BeginOpenInternal() %p\n", this));
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mRedirectCallback) {
|
||||
LOG(("WebSocketChannel::BeginOpen: Resuming Redirect\n"));
|
||||
LOG(("WebSocketChannel::BeginOpenInternal: Resuming Redirect\n"));
|
||||
rv = mRedirectCallback->OnRedirectVerifyCallback(NS_OK);
|
||||
mRedirectCallback = nullptr;
|
||||
return;
|
||||
|
@ -1338,7 +1364,7 @@ WebSocketChannel::BeginOpen()
|
|||
|
||||
nsCOMPtr<nsIChannel> localChannel = do_QueryInterface(mChannel, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("WebSocketChannel::BeginOpen: cannot async open\n"));
|
||||
LOG(("WebSocketChannel::BeginOpenInternal: cannot async open\n"));
|
||||
AbortSession(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
@ -1358,7 +1384,7 @@ WebSocketChannel::BeginOpen()
|
|||
|
||||
rv = localChannel->AsyncOpen(this, mHttpChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("WebSocketChannel::BeginOpen: cannot async open\n"));
|
||||
LOG(("WebSocketChannel::BeginOpenInternal: cannot async open\n"));
|
||||
AbortSession(NS_ERROR_CONNECTION_REFUSED);
|
||||
return;
|
||||
}
|
||||
|
@ -1366,7 +1392,7 @@ WebSocketChannel::BeginOpen()
|
|||
|
||||
mOpenTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("WebSocketChannel::BeginOpen: cannot create open timer\n"));
|
||||
LOG(("WebSocketChannel::BeginOpenInternal: cannot create open timer\n"));
|
||||
AbortSession(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
@ -1374,7 +1400,8 @@ WebSocketChannel::BeginOpen()
|
|||
rv = mOpenTimer->InitWithCallback(this, mOpenTimeout,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("WebSocketChannel::BeginOpen: cannot initialize open timer\n"));
|
||||
LOG(("WebSocketChannel::BeginOpenInternal: cannot initialize open "
|
||||
"timer\n"));
|
||||
AbortSession(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
@ -2609,11 +2636,6 @@ WebSocketChannel::StartWebsocketData()
|
|||
MOZ_ASSERT(!mDataStarted, "StartWebsocketData twice");
|
||||
mDataStarted = 1;
|
||||
|
||||
// We're now done CONNECTING, which means we can now open another,
|
||||
// perhaps parallel, connection to the same host if one
|
||||
// is pending
|
||||
nsWSAdmissionManager::OnConnected(this);
|
||||
|
||||
LOG(("WebSocketChannel::StartWebsocketData Notifying Listener %p\n",
|
||||
mListenerMT ? mListenerMT->mListener.get() : nullptr));
|
||||
|
||||
|
@ -2790,6 +2812,9 @@ WebSocketChannel::AsyncOnChannelRedirect(
|
|||
nsIAsyncVerifyRedirectCallback *callback)
|
||||
{
|
||||
LOG(("WebSocketChannel::AsyncOnChannelRedirect() %p\n", this));
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIURI> newuri;
|
||||
|
@ -2934,10 +2959,11 @@ WebSocketChannel::Notify(nsITimer *timer)
|
|||
} else if (timer == mReconnectDelayTimer) {
|
||||
MOZ_ASSERT(mConnecting == CONNECTING_DELAYED,
|
||||
"woke up from delay w/o being delayed?");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
|
||||
|
||||
mReconnectDelayTimer = nullptr;
|
||||
LOG(("WebSocketChannel: connecting [this=%p] after reconnect delay", this));
|
||||
BeginOpen();
|
||||
BeginOpen(false);
|
||||
} else if (timer == mPingTimer) {
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread,
|
||||
"not socket thread");
|
||||
|
@ -3321,8 +3347,15 @@ WebSocketChannel::OnTransportAvailable(nsISocketTransport *aTransport,
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mRecvdHttpUpgradeTransport = 1;
|
||||
if (mGotUpgradeOK)
|
||||
if (mGotUpgradeOK) {
|
||||
// We're now done CONNECTING, which means we can now open another,
|
||||
// perhaps parallel, connection to the same host if one
|
||||
// is pending
|
||||
nsWSAdmissionManager::OnConnected(this);
|
||||
|
||||
return StartWebsocketData();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3476,8 +3509,14 @@ WebSocketChannel::OnStartRequest(nsIRequest *aRequest,
|
|||
CopyUTF8toUTF16(spec, mEffectiveURL);
|
||||
|
||||
mGotUpgradeOK = 1;
|
||||
if (mRecvdHttpUpgradeTransport)
|
||||
if (mRecvdHttpUpgradeTransport) {
|
||||
// We're now done CONNECTING, which means we can now open another,
|
||||
// perhaps parallel, connection to the same host if one
|
||||
// is pending
|
||||
nsWSAdmissionManager::OnConnected(this);
|
||||
|
||||
return StartWebsocketData();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -148,7 +148,8 @@ private:
|
|||
nsresult OnNetworkChanged();
|
||||
nsresult StartPinging();
|
||||
|
||||
void BeginOpen();
|
||||
void BeginOpen(bool aCalledFromAdmissionManager);
|
||||
void BeginOpenInternal();
|
||||
nsresult HandleExtensions();
|
||||
nsresult SetupRequest();
|
||||
nsresult ApplyForAdmission();
|
||||
|
|
Загрузка…
Ссылка в новой задаче