Skip to content

Commit 3382318

Browse files
committed
Bug 939318 - Have websockets act on network interface changes. r=mcmanus
If there's no outstanding PING, send a new to make sure the connection is still alive and fine.
1 parent 4e2f285 commit 3382318

File tree

4 files changed

+79
-7
lines changed

4 files changed

+79
-7
lines changed

netwerk/protocol/websocket/BaseWebSocketChannel.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ BaseWebSocketChannel::BaseWebSocketChannel()
2424
, mWasOpened(0)
2525
, mClientSetPingInterval(0)
2626
, mClientSetPingTimeout(0)
27+
, mPingForced(0)
2728
, mPingInterval(0)
2829
, mPingResponseTimeout(10000)
2930
{

netwerk/protocol/websocket/BaseWebSocketChannel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class BaseWebSocketChannel : public nsIWebSocketChannel,
7272
uint32_t mWasOpened : 1;
7373
uint32_t mClientSetPingInterval : 1;
7474
uint32_t mClientSetPingTimeout : 1;
75+
uint32_t mPingForced : 1;
7576

7677
uint32_t mPingInterval; /* milliseconds */
7778
uint32_t mPingResponseTimeout; /* milliseconds */

netwerk/protocol/websocket/WebSocketChannel.cpp

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#include "nsIRandomGenerator.h"
3636
#include "nsISocketTransport.h"
3737
#include "nsThreadUtils.h"
38+
#include "nsINetworkLinkService.h"
39+
#include "nsIObserverService.h"
3840

3941
#include "nsAutoPtr.h"
4042
#include "nsNetCID.h"
@@ -85,7 +87,8 @@ NS_IMPL_ISUPPORTS(WebSocketChannel,
8587
nsIProtocolProxyCallback,
8688
nsIInterfaceRequestor,
8789
nsIChannelEventSink,
88-
nsIThreadRetargetableRequest)
90+
nsIThreadRetargetableRequest,
91+
nsIObserver)
8992

9093
// We implement RFC 6455, which uses Sec-WebSocket-Version: 13 on the wire.
9194
#define SEC_WEBSOCKET_VERSION "13"
@@ -1046,6 +1049,16 @@ WebSocketChannel::WebSocketChannel() :
10461049
LOG(("Failed to initiate dashboard service."));
10471050

10481051
mSerial = sSerialSeed++;
1052+
1053+
// Register for prefs change notifications
1054+
nsCOMPtr<nsIObserverService> observerService =
1055+
mozilla::services::GetObserverService();
1056+
if (observerService) {
1057+
observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
1058+
} else {
1059+
NS_WARNING("failed to get observer service");
1060+
}
1061+
10491062
}
10501063

10511064
WebSocketChannel::~WebSocketChannel()
@@ -1104,6 +1117,55 @@ WebSocketChannel::~WebSocketChannel()
11041117
}
11051118
}
11061119

1120+
NS_IMETHODIMP
1121+
WebSocketChannel::Observe(nsISupports *subject,
1122+
const char *topic,
1123+
const char16_t *data)
1124+
{
1125+
LOG(("WebSocketChannel::Observe [topic=\"%s\"]\n", topic));
1126+
1127+
if (strcmp(topic, NS_NETWORK_LINK_TOPIC) == 0) {
1128+
nsCString converted = NS_ConvertUTF16toUTF8(data);
1129+
const char *state = converted.get();
1130+
1131+
if (strcmp(state, NS_NETWORK_LINK_DATA_CHANGED) == 0) {
1132+
LOG(("WebSocket: received network CHANGED event"));
1133+
if (mPingOutstanding) {
1134+
// If there's an outstanding ping that's expected to get a pong back
1135+
// we let that do its thing.
1136+
LOG(("WebSocket: pong already pending"));
1137+
} else if (!mSocketThread) {
1138+
// there has not been an asyncopen yet on the object and then we need
1139+
// no ping.
1140+
LOG(("WebSocket: early object, no ping needed"));
1141+
} else {
1142+
LOG(("nsWebSocketChannel:: Generating Ping as network changed\n"));
1143+
1144+
if (mPingForced) {
1145+
// avoid more than one
1146+
return NS_OK;
1147+
}
1148+
if (!mPingTimer) {
1149+
// The ping timer is only conditionally running already. If it
1150+
// wasn't already created do it here.
1151+
nsresult rv;
1152+
mPingTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
1153+
if (NS_FAILED(rv)) {
1154+
NS_WARNING("unable to create ping timer. Carrying on.");
1155+
} else {
1156+
mPingTimer->SetTarget(mSocketThread);
1157+
}
1158+
}
1159+
// Trigger the ping timeout asap to fire off a new ping. Wait just
1160+
// a little bit to better avoid multi-triggers.
1161+
mPingForced = 1;
1162+
mPingTimer->InitWithCallback(this, 200, nsITimer::TYPE_ONE_SHOT);
1163+
}
1164+
}
1165+
}
1166+
return NS_OK;
1167+
}
1168+
11071169
void
11081170
WebSocketChannel::Shutdown()
11091171
{
@@ -2623,11 +2685,16 @@ WebSocketChannel::Notify(nsITimer *timer)
26232685
}
26242686

26252687
if (!mPingOutstanding) {
2626-
LOG(("nsWebSocketChannel:: Generating Ping\n"));
2627-
mPingOutstanding = 1;
2628-
GeneratePing();
2629-
mPingTimer->InitWithCallback(this, mPingResponseTimeout,
2630-
nsITimer::TYPE_ONE_SHOT);
2688+
// Allow for the case where a PING was force-sent even though ping
2689+
// interval isn't enabled. Only issue a new PING if it truly is enabled.
2690+
if (mPingInterval || mPingForced) {
2691+
LOG(("nsWebSocketChannel:: Generating Ping\n"));
2692+
mPingOutstanding = 1;
2693+
mPingForced = 0;
2694+
GeneratePing();
2695+
mPingTimer->InitWithCallback(this, mPingResponseTimeout,
2696+
nsITimer::TYPE_ONE_SHOT);
2697+
}
26312698
} else {
26322699
LOG(("nsWebSocketChannel:: Timed out Ping\n"));
26332700
mPingTimer = nullptr;

netwerk/protocol/websocket/WebSocketChannel.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "nsIAsyncOutputStream.h"
1515
#include "nsITimer.h"
1616
#include "nsIDNSListener.h"
17+
#include "nsIObserver.h"
1718
#include "nsIProtocolProxyCallback.h"
1819
#include "nsIChannelEventSink.h"
1920
#include "nsIHttpChannelInternal.h"
@@ -62,6 +63,7 @@ class WebSocketChannel : public BaseWebSocketChannel,
6263
public nsIOutputStreamCallback,
6364
public nsITimerCallback,
6465
public nsIDNSListener,
66+
public nsIObserver,
6567
public nsIProtocolProxyCallback,
6668
public nsIInterfaceRequestor,
6769
public nsIChannelEventSink
@@ -78,6 +80,7 @@ class WebSocketChannel : public BaseWebSocketChannel,
7880
NS_DECL_NSIPROTOCOLPROXYCALLBACK
7981
NS_DECL_NSIINTERFACEREQUESTOR
8082
NS_DECL_NSICHANNELEVENTSINK
83+
NS_DECL_NSIOBSERVER
8184

8285
// nsIWebSocketChannel methods BaseWebSocketChannel didn't implement for us
8386
//
@@ -160,8 +163,8 @@ class WebSocketChannel : public BaseWebSocketChannel,
160163

161164
inline void ResetPingTimer()
162165
{
166+
mPingOutstanding = 0;
163167
if (mPingTimer) {
164-
mPingOutstanding = 0;
165168
mPingTimer->SetDelay(mPingInterval);
166169
}
167170
}

0 commit comments

Comments
 (0)