Skip to content

Commit

Permalink
Bug 1152334 - StartWebsocketData null deref mSocketIn, r=bagder
Browse files Browse the repository at this point in the history
  • Loading branch information
vonasek committed May 11, 2015
1 parent 8480427 commit 70212cb
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 35 deletions.
135 changes: 100 additions & 35 deletions netwerk/protocol/websocket/WebSocketChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1223,39 +1223,78 @@ WebSocketChannel::Observe(nsISupports *subject,

if (strcmp(state, NS_NETWORK_LINK_DATA_CHANGED) == 0) {
LOG(("WebSocket: received network CHANGED event"));
if (mPingOutstanding) {
// If there's an outstanding ping that's expected to get a pong back
// we let that do its thing.
LOG(("WebSocket: pong already pending"));
} else if (!mSocketThread) {

if (!mSocketThread) {
// there has not been an asyncopen yet on the object and then we need
// no ping.
LOG(("WebSocket: early object, no ping needed"));
} else {
LOG(("nsWebSocketChannel:: Generating Ping as network changed\n"));

if (mPingForced) {
// avoid more than one
return NS_OK;
}
if (!mPingTimer) {
// The ping timer is only conditionally running already. If it
// wasn't already created do it here.
nsresult rv;
mPingTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_FAILED(rv)) {
NS_WARNING("unable to create ping timer. Carrying on.");
} else {
mPingTimer->SetTarget(mSocketThread);
}
// Next we check mDataStarted, which we need to do on mTargetThread.
if (!IsOnTargetThread()) {
mTargetThread->Dispatch(
NS_NewRunnableMethod(this, &WebSocketChannel::OnNetworkChanged),
NS_DISPATCH_NORMAL);
} else {
OnNetworkChanged();
}
// Trigger the ping timeout asap to fire off a new ping. Wait just
// a little bit to better avoid multi-triggers.
mPingForced = 1;
mPingTimer->InitWithCallback(this, 200, nsITimer::TYPE_ONE_SHOT);
}
}
}

return NS_OK;
}

nsresult
WebSocketChannel::OnNetworkChanged()
{
if (IsOnTargetThread()) {
LOG(("WebSocketChannel::OnNetworkChanged() - on target thread %p", this));

if (!mDataStarted) {
LOG(("WebSocket: data not started yet, no ping needed"));
return NS_OK;
}

return mSocketThread->Dispatch(
NS_NewRunnableMethod(this, &WebSocketChannel::OnNetworkChanged),
NS_DISPATCH_NORMAL);
}

MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");

LOG(("WebSocketChannel::OnNetworkChanged() - on socket thread %p", this));

if (mPingOutstanding) {
// If there's an outstanding ping that's expected to get a pong back
// we let that do its thing.
LOG(("WebSocket: pong already pending"));
return NS_OK;
}

if (mPingForced) {
// avoid more than one
LOG(("WebSocket: forced ping timer already fired"));
return NS_OK;
}

LOG(("nsWebSocketChannel:: Generating Ping as network changed\n"));

if (!mPingTimer) {
// The ping timer is only conditionally running already. If it wasn't
// already created do it here.
nsresult rv;
mPingTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_FAILED(rv)) {
LOG(("WebSocket: unable to create ping timer!"));
NS_WARNING("unable to create ping timer!");
return rv;
}
}
// Trigger the ping timeout asap to fire off a new ping. Wait just
// a little bit to better avoid multi-triggers.
mPingForced = 1;
mPingTimer->InitWithCallback(this, 200, nsITimer::TYPE_ONE_SHOT);

return NS_OK;
}

Expand Down Expand Up @@ -2574,6 +2613,8 @@ WebSocketChannel::ApplyForAdmission()
nsresult
WebSocketChannel::StartWebsocketData()
{
nsresult rv;

if (!IsOnTargetThread()) {
return mTargetThread->Dispatch(
NS_NewRunnableMethod(this, &WebSocketChannel::StartWebsocketData),
Expand All @@ -2596,23 +2637,47 @@ WebSocketChannel::StartWebsocketData()
mListenerMT->mListener->OnStart(mListenerMT->mContext);
}

// Start keepalive ping timer, if we're using keepalive.
rv = mSocketIn->AsyncWait(this, 0, 0, mSocketThread);
if (NS_FAILED(rv)) {
LOG(("WebSocketChannel::StartWebsocketData mSocketIn->AsyncWait() failed "
"with error %0x%08x\n", rv));
return rv;
}

if (mPingInterval) {
nsresult rv;
mPingTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
rv = mSocketThread->Dispatch(
NS_NewRunnableMethod(this, &WebSocketChannel::StartPinging),
NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
NS_WARNING("unable to create ping timer. Carrying on.");
} else {
LOG(("WebSocketChannel will generate ping after %d ms of receive silence\n",
mPingInterval));
mPingTimer->SetTarget(mSocketThread);
mPingTimer->InitWithCallback(this, mPingInterval, nsITimer::TYPE_ONE_SHOT);
return rv;
}
}

return mSocketIn->AsyncWait(this, 0, 0, mSocketThread);
return NS_OK;
}

nsresult
WebSocketChannel::StartPinging()
{
LOG(("WebSocketChannel::StartPinging() %p", this));
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");
MOZ_ASSERT(mPingInterval);
MOZ_ASSERT(!mPingTimer);

nsresult rv;
mPingTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_FAILED(rv)) {
NS_WARNING("unable to create ping timer. Carrying on.");
} else {
LOG(("WebSocketChannel will generate ping after %d ms of receive silence\n",
mPingInterval));
mPingTimer->InitWithCallback(this, mPingInterval, nsITimer::TYPE_ONE_SHOT);
}

return NS_OK;
}


void
WebSocketChannel::ReportConnectionTelemetry()
{
Expand Down
3 changes: 3 additions & 0 deletions netwerk/protocol/websocket/WebSocketChannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ class WebSocketChannel : public BaseWebSocketChannel,
void GeneratePong(uint8_t *payload, uint32_t len);
void GeneratePing();

nsresult OnNetworkChanged();
nsresult StartPinging();

void BeginOpen();
nsresult HandleExtensions();
nsresult SetupRequest();
Expand Down

0 comments on commit 70212cb

Please sign in to comment.