|
35 | 35 | #include "nsIRandomGenerator.h"
|
36 | 36 | #include "nsISocketTransport.h"
|
37 | 37 | #include "nsThreadUtils.h"
|
| 38 | +#include "nsINetworkLinkService.h" |
| 39 | +#include "nsIObserverService.h" |
38 | 40 |
|
39 | 41 | #include "nsAutoPtr.h"
|
40 | 42 | #include "nsNetCID.h"
|
@@ -85,7 +87,8 @@ NS_IMPL_ISUPPORTS(WebSocketChannel,
|
85 | 87 | nsIProtocolProxyCallback,
|
86 | 88 | nsIInterfaceRequestor,
|
87 | 89 | nsIChannelEventSink,
|
88 |
| - nsIThreadRetargetableRequest) |
| 90 | + nsIThreadRetargetableRequest, |
| 91 | + nsIObserver) |
89 | 92 |
|
90 | 93 | // We implement RFC 6455, which uses Sec-WebSocket-Version: 13 on the wire.
|
91 | 94 | #define SEC_WEBSOCKET_VERSION "13"
|
@@ -1046,6 +1049,16 @@ WebSocketChannel::WebSocketChannel() :
|
1046 | 1049 | LOG(("Failed to initiate dashboard service."));
|
1047 | 1050 |
|
1048 | 1051 | 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 | + |
1049 | 1062 | }
|
1050 | 1063 |
|
1051 | 1064 | WebSocketChannel::~WebSocketChannel()
|
@@ -1104,6 +1117,55 @@ WebSocketChannel::~WebSocketChannel()
|
1104 | 1117 | }
|
1105 | 1118 | }
|
1106 | 1119 |
|
| 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 | + |
1107 | 1169 | void
|
1108 | 1170 | WebSocketChannel::Shutdown()
|
1109 | 1171 | {
|
@@ -2623,11 +2685,16 @@ WebSocketChannel::Notify(nsITimer *timer)
|
2623 | 2685 | }
|
2624 | 2686 |
|
2625 | 2687 | 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 | + } |
2631 | 2698 | } else {
|
2632 | 2699 | LOG(("nsWebSocketChannel:: Timed out Ping\n"));
|
2633 | 2700 | mPingTimer = nullptr;
|
|
0 commit comments