mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 874771 - Implement SNTP support (Gecko end). r=gene
This commit is contained in:
parent
242a797ff7
commit
e39458f3a8
@ -747,6 +747,14 @@ pref("ping.manifestURL", "https://marketplace.firefox.com/packaged.webapp");
|
||||
// Enable the disk space watcher
|
||||
pref("disk_space_watcher.enabled", true);
|
||||
|
||||
// SNTP preferences.
|
||||
pref("network.sntp.maxRetryCount", 10);
|
||||
pref("network.sntp.refreshPeriod", 86400); // In seconds.
|
||||
pref("network.sntp.pools", // Servers separated by ';'.
|
||||
"0.pool.ntp.org;1.pool.ntp.org;2.pool.ntp.org;3.pool.ntp.org");
|
||||
pref("network.sntp.port", 123);
|
||||
pref("network.sntp.timeout", 30); // In seconds.
|
||||
|
||||
// Enable promise
|
||||
pref("dom.promise.enabled", false);
|
||||
|
||||
|
@ -19,6 +19,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Sntp.jsm");
|
||||
|
||||
var RIL = {};
|
||||
Cu.import("resource://gre/modules/ril_consts.js", RIL);
|
||||
@ -58,8 +59,10 @@ const kMozSettingsChangedObserverTopic = "mozsettings-changed";
|
||||
const kSysMsgListenerReadyObserverTopic = "system-message-listener-ready";
|
||||
const kSysClockChangeObserverTopic = "system-clock-change";
|
||||
const kScreenStateChangedTopic = "screen-state-changed";
|
||||
const kTimeNitzAutomaticUpdateEnabled = "time.nitz.automatic-update.enabled";
|
||||
const kTimeNitzAvailable = "time.nitz.available";
|
||||
const kClockAutoUpdateEnabled = "time.clock.automatic-update.enabled";
|
||||
const kClockAutoUpdateAvailable = "time.clock.automatic-update.available";
|
||||
const kTimezoneAutoUpdateEnabled = "time.timezone.automatic-update.enabled";
|
||||
const kTimezoneAutoUpdateAvailable = "time.timezone.automatic-update.available";
|
||||
const kCellBroadcastSearchList = "ril.cellbroadcast.searchlist";
|
||||
const kCellBroadcastDisabled = "ril.cellbroadcast.disabled";
|
||||
const kPrefenceChangedObserverTopic = "nsPref:changed";
|
||||
@ -709,12 +712,19 @@ function RadioInterface(options) {
|
||||
lock.get("ril.data.enabled", this);
|
||||
lock.get("ril.data.apnSettings", this);
|
||||
|
||||
// Read the 'time.nitz.automatic-update.enabled' setting to see if
|
||||
// we need to adjust the system clock time and time zone by NITZ.
|
||||
lock.get(kTimeNitzAutomaticUpdateEnabled, this);
|
||||
// Read the 'time.clock.automatic-update.enabled' setting to see if
|
||||
// we need to adjust the system clock time by NITZ or SNTP.
|
||||
lock.get(kClockAutoUpdateEnabled, this);
|
||||
|
||||
// Set "time.nitz.available" to false when starting up.
|
||||
this.setNitzAvailable(false);
|
||||
// Read the 'time.timezone.automatic-update.enabled' setting to see if
|
||||
// we need to adjust the system timezone by NITZ.
|
||||
lock.get(kTimezoneAutoUpdateEnabled, this);
|
||||
|
||||
// Set "time.clock.automatic-update.available" to false when starting up.
|
||||
this.setClockAutoUpdateAvailable(false);
|
||||
|
||||
// Set "time.timezone.automatic-update.available" to false when starting up.
|
||||
this.setTimezoneAutoUpdateAvailable(false);
|
||||
|
||||
// Read the Cell Broadcast Search List setting, string of integers or integer
|
||||
// ranges separated by comma, to set listening channels.
|
||||
@ -726,11 +736,20 @@ function RadioInterface(options) {
|
||||
Services.obs.addObserver(this, kSysClockChangeObserverTopic, false);
|
||||
Services.obs.addObserver(this, kScreenStateChangedTopic, false);
|
||||
|
||||
Services.obs.addObserver(this, kNetworkInterfaceStateChangedTopic, false);
|
||||
Services.prefs.addObserver(kCellBroadcastDisabled, this, false);
|
||||
|
||||
this.portAddressedSmsApps = {};
|
||||
this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
|
||||
|
||||
this._sntp = new Sntp(this.setClockBySntp.bind(this),
|
||||
Services.prefs.getIntPref('network.sntp.maxRetryCount'),
|
||||
Services.prefs.getIntPref('network.sntp.refreshPeriod'),
|
||||
Services.prefs.getIntPref('network.sntp.timeout'),
|
||||
Services.prefs.getCharPref('network.sntp.pools').split(';'),
|
||||
Services.prefs.getIntPref('network.sntp.port'));
|
||||
}
|
||||
|
||||
RadioInterface.prototype = {
|
||||
|
||||
classID: RADIOINTERFACE_CID,
|
||||
@ -1860,22 +1879,35 @@ RadioInterface.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the setting value of "time.nitz.available".
|
||||
* Set the setting value of "time.clock.automatic-update.available".
|
||||
*/
|
||||
setNitzAvailable: function setNitzAvailable(value) {
|
||||
gSettingsService.createLock().set(kTimeNitzAvailable, value, null,
|
||||
setClockAutoUpdateAvailable: function setClockAutoUpdateAvailable(value) {
|
||||
gSettingsService.createLock().set(kClockAutoUpdateAvailable, value, null,
|
||||
"fromInternalSetting");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the NITZ message in our system time.
|
||||
* Set the setting value of "time.timezone.automatic-update.available".
|
||||
*/
|
||||
setNitzTime: function setNitzTime(message) {
|
||||
setTimezoneAutoUpdateAvailable: function setTimezoneAutoUpdateAvailable(value) {
|
||||
gSettingsService.createLock().set(kTimezoneAutoUpdateAvailable, value, null,
|
||||
"fromInternalSetting");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the system clock by NITZ.
|
||||
*/
|
||||
setClockByNitz: function setClockByNitz(message) {
|
||||
// To set the system clock time. Note that there could be a time diff
|
||||
// between when the NITZ was received and when the time is actually set.
|
||||
gTimeService.set(
|
||||
message.networkTimeInMS + (Date.now() - message.receiveTimeInMS));
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the system time zone by NITZ.
|
||||
*/
|
||||
setTimezoneByNitz: function setTimezoneByNitz(message) {
|
||||
// To set the sytem timezone. Note that we need to convert the time zone
|
||||
// value to a UTC repesentation string in the format of "UTC(+/-)hh:mm".
|
||||
// Ex, time zone -480 is "UTC-08:00"; time zone 630 is "UTC+10:30".
|
||||
@ -1898,15 +1930,36 @@ RadioInterface.prototype = {
|
||||
*/
|
||||
handleNitzTime: function handleNitzTime(message) {
|
||||
// Got the NITZ info received from the ril_worker.
|
||||
this.setNitzAvailable(true);
|
||||
this.setClockAutoUpdateAvailable(true);
|
||||
this.setTimezoneAutoUpdateAvailable(true);
|
||||
|
||||
// Cache the latest NITZ message whenever receiving it.
|
||||
this._lastNitzMessage = message;
|
||||
|
||||
// Set the received NITZ time if the setting is enabled.
|
||||
if (this._nitzAutomaticUpdateEnabled) {
|
||||
this.setNitzTime(message);
|
||||
// Set the received NITZ clock if the setting is enabled.
|
||||
if (this._clockAutoUpdateEnabled) {
|
||||
this.setClockByNitz(message);
|
||||
}
|
||||
// Set the received NITZ timezone if the setting is enabled.
|
||||
if (this._timezoneAutoUpdateEnabled) {
|
||||
this.setTimezoneByNitz(message);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the system clock by SNTP.
|
||||
*/
|
||||
setClockBySntp: function setClockBySntp(offset) {
|
||||
// Got the SNTP info.
|
||||
this.setClockAutoUpdateAvailable(true);
|
||||
if (!this._clockAutoUpdateEnabled) {
|
||||
return;
|
||||
}
|
||||
if (this._lastNitzMessage) {
|
||||
debug("SNTP: NITZ available, discard SNTP");
|
||||
return;
|
||||
}
|
||||
gTimeService.set(Date.now() + offset);
|
||||
},
|
||||
|
||||
handleIccMbdn: function handleIccMbdn(message) {
|
||||
@ -2023,11 +2076,24 @@ RadioInterface.prototype = {
|
||||
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
|
||||
Services.obs.removeObserver(this, kSysClockChangeObserverTopic);
|
||||
Services.obs.removeObserver(this, kScreenStateChangedTopic);
|
||||
Services.obs.removeObserver(this, kNetworkInterfaceStateChangedTopic);
|
||||
Services.prefs.removeObserver(kCellBroadcastDisabled, this);
|
||||
break;
|
||||
case kSysClockChangeObserverTopic:
|
||||
let offset = parseInt(data, 10);
|
||||
if (this._lastNitzMessage) {
|
||||
this._lastNitzMessage.receiveTimeInMS += parseInt(data, 10);
|
||||
this._lastNitzMessage.receiveTimeInMS += offset;
|
||||
}
|
||||
this._sntp.updateOffset(offset);
|
||||
break;
|
||||
case kNetworkInterfaceStateChangedTopic:
|
||||
let network = subject.QueryInterface(Ci.nsINetworkInterface);
|
||||
if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
|
||||
// Check SNTP when we have data connection, this may not take
|
||||
// effect immediately before the setting get enabled.
|
||||
if (this._sntp.isExpired()) {
|
||||
this._sntp.request();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kScreenStateChangedTopic:
|
||||
@ -2053,28 +2119,51 @@ RadioInterface.prototype = {
|
||||
|
||||
apnSettings: null,
|
||||
|
||||
// Flag to determine whether to use NITZ. It corresponds to the
|
||||
// 'time.nitz.automatic-update.enabled' setting from the UI.
|
||||
_nitzAutomaticUpdateEnabled: null,
|
||||
// Flag to determine whether to update system clock automatically. It
|
||||
// corresponds to the 'time.clock.automatic-update.enabled' setting.
|
||||
_clockAutoUpdateEnabled: null,
|
||||
|
||||
// Flag to determine whether to update system timezone automatically. It
|
||||
// corresponds to the 'time.clock.automatic-update.enabled' setting.
|
||||
_timezoneAutoUpdateEnabled: null,
|
||||
|
||||
// Remember the last NITZ message so that we can set the time based on
|
||||
// the network immediately when users enable network-based time.
|
||||
_lastNitzMessage: null,
|
||||
|
||||
// Object that handles SNTP.
|
||||
_sntp: null,
|
||||
|
||||
// Cell Broadcast settings values.
|
||||
_cellBroadcastSearchListStr: null,
|
||||
|
||||
handleSettingsChange: function handleSettingsChange(aName, aResult, aMessage) {
|
||||
// Don't allow any content processes to modify the setting
|
||||
// "time.nitz.available" except for the chrome process.
|
||||
let isNitzAvailable = (this._lastNitzMessage !== null);
|
||||
if (aName === kTimeNitzAvailable && aMessage !== "fromInternalSetting" &&
|
||||
aResult !== isNitzAvailable) {
|
||||
if (DEBUG) {
|
||||
this.debug("Content processes cannot modify 'time.nitz.available'. Restore!");
|
||||
// "time.clock.automatic-update.available" except for the chrome process.
|
||||
if (aName === kClockAutoUpdateAvailable &&
|
||||
aMessage !== "fromInternalSetting") {
|
||||
let isClockAutoUpdateAvailable = this._lastNitzMessage !== null ||
|
||||
this._sntp.isAvailable();
|
||||
if (aResult !== isClockAutoUpdateAvailable) {
|
||||
debug("Content processes cannot modify 'time.clock.automatic-update.available'. Restore!");
|
||||
// Restore the setting to the current value.
|
||||
this.setClockAutoUpdateAvailable(isClockAutoUpdateAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't allow any content processes to modify the setting
|
||||
// "time.timezone.automatic-update.available" except for the chrome
|
||||
// process.
|
||||
if (aName === kTimezoneAutoUpdateAvailable &&
|
||||
aMessage !== "fromInternalSetting") {
|
||||
let isTimezoneAutoUpdateAvailable = this._lastNitzMessage !== null;
|
||||
if (aResult !== isTimezoneAutoUpdateAvailable) {
|
||||
if (DEBUG) {
|
||||
this.debug("Content processes cannot modify 'time.timezone.automatic-update.available'. Restore!");
|
||||
}
|
||||
// Restore the setting to the current value.
|
||||
this.setTimezoneAutoUpdateAvailable(isTimezoneAutoUpdateAvailable);
|
||||
}
|
||||
// Restore the setting to the current value.
|
||||
this.setNitzAvailable(isNitzAvailable);
|
||||
}
|
||||
|
||||
this.handle(aName, aResult);
|
||||
@ -2117,12 +2206,34 @@ RadioInterface.prototype = {
|
||||
this.updateRILNetworkInterface();
|
||||
}
|
||||
break;
|
||||
case kTimeNitzAutomaticUpdateEnabled:
|
||||
this._nitzAutomaticUpdateEnabled = aResult;
|
||||
case kClockAutoUpdateEnabled:
|
||||
this._clockAutoUpdateEnabled = aResult;
|
||||
if (!this._clockAutoUpdateEnabled) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the latest cached NITZ time if the setting is enabled.
|
||||
if (this._nitzAutomaticUpdateEnabled && this._lastNitzMessage) {
|
||||
this.setNitzTime(this._lastNitzMessage);
|
||||
// Set the latest cached NITZ time if it's available.
|
||||
if (this._lastNitzMessage) {
|
||||
this.setClockByNitz(this._lastNitzMessage);
|
||||
} else if (gNetworkManager.active && gNetworkManager.active.state ==
|
||||
Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
|
||||
// Set the latest cached SNTP time if it's available.
|
||||
if (!this._sntp.isExpired()) {
|
||||
this.setClockBySntp(this._sntp.getOffset());
|
||||
} else {
|
||||
// Or refresh the SNTP.
|
||||
this._sntp.request();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kTimezoneAutoUpdateEnabled:
|
||||
this._timezoneAutoUpdateEnabled = aResult;
|
||||
|
||||
if (this._timezoneAutoUpdateEnabled) {
|
||||
// Apply the latest cached NITZ for timezone if it's available.
|
||||
if (this._timezoneAutoUpdateEnabled && this._lastNitzMessage) {
|
||||
this.setTimezoneByNitz(this._lastNitzMessage);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kCellBroadcastSearchList:
|
||||
|
334
toolkit/modules/Sntp.jsm
Normal file
334
toolkit/modules/Sntp.jsm
Normal file
@ -0,0 +1,334 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"Sntp",
|
||||
];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
// Set to true to see debug messages.
|
||||
let DEBUG = false;
|
||||
|
||||
/**
|
||||
* Constructor of Sntp.
|
||||
*
|
||||
* @param dataAvailableCb
|
||||
* Callback function gets called when SNTP offset available. Signature
|
||||
* is function dataAvailableCb(offsetInMS).
|
||||
* @param maxRetryCount
|
||||
* Maximum retry count when SNTP failed to connect to server; set to
|
||||
* zero to disable the retry.
|
||||
* @param refreshPeriodInSecs
|
||||
* Refresh period; set to zero to disable refresh.
|
||||
* @param timeoutInSecs
|
||||
* Timeout value used for connection.
|
||||
* @param pools
|
||||
* SNTP server lists separated by ';'.
|
||||
* @param port
|
||||
* SNTP port.
|
||||
*/
|
||||
this.Sntp = function Sntp(dataAvailableCb, maxRetryCount, refreshPeriodInSecs,
|
||||
timeoutInSecs, pools, port) {
|
||||
if (dataAvailableCb != null) {
|
||||
this._dataAvailableCb = dataAvailableCb;
|
||||
}
|
||||
if (maxRetryCount != null) {
|
||||
this._maxRetryCount = maxRetryCount;
|
||||
}
|
||||
if (refreshPeriodInSecs != null) {
|
||||
this._refreshPeriodInMS = refreshPeriodInSecs * 1000;
|
||||
}
|
||||
if (timeoutInSecs != null) {
|
||||
this._timeoutInMS = timeoutInSecs * 1000;
|
||||
}
|
||||
if (pools != null && Array.isArray(pools) && pools.length > 0) {
|
||||
this._pools = pools;
|
||||
}
|
||||
if (port != null) {
|
||||
this._port = port;
|
||||
}
|
||||
}
|
||||
|
||||
Sntp.prototype = {
|
||||
isAvailable: function isAvailable() {
|
||||
return this._cachedOffset != null;
|
||||
},
|
||||
|
||||
isExpired: function isExpired() {
|
||||
let valid = this._cachedOffset != null && this._cachedTimeInMS != null;
|
||||
if (this._refreshPeriodInMS > 0) {
|
||||
valid = valid && Date.now() < this._cachedTimeInMS +
|
||||
this._refreshPeriodInMS;
|
||||
}
|
||||
return !valid;
|
||||
},
|
||||
|
||||
request: function request() {
|
||||
this._request();
|
||||
},
|
||||
|
||||
getOffset: function getOffset() {
|
||||
return this._cachedOffset;
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates the system clock has been changed by [offset]ms so we need to
|
||||
* adjust the stored value.
|
||||
*/
|
||||
updateOffset: function updateOffset(offset) {
|
||||
if (this._cachedOffset != null) {
|
||||
this._cachedOffset -= offset;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Used to schedule a retry or periodic updates.
|
||||
*/
|
||||
_schedule: function _schedule(timeInMS) {
|
||||
if (this._updateTimer == null) {
|
||||
this._updateTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
}
|
||||
|
||||
this._updateTimer.initWithCallback(this._request.bind(this),
|
||||
timeInMS,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
debug("Scheduled SNTP request in " + timeInMS + "ms");
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the SNTP response.
|
||||
*/
|
||||
_handleSntp: function _handleSntp(originateTimeInMS, receiveTimeInMS,
|
||||
transmitTimeInMS, respondTimeInMS) {
|
||||
let clockOffset = Math.floor(((receiveTimeInMS - originateTimeInMS) +
|
||||
(transmitTimeInMS - respondTimeInMS)) / 2);
|
||||
debug("Clock offset: " + clockOffset);
|
||||
|
||||
// We've succeeded so clear the retry status.
|
||||
this._retryCount = 0;
|
||||
this._retryPeriodInMS = 0;
|
||||
|
||||
// Cache the latest SNTP offset whenever receiving it.
|
||||
this._cachedOffset = clockOffset;
|
||||
this._cachedTimeInMS = respondTimeInMS;
|
||||
|
||||
if (this._dataAvailableCb != null) {
|
||||
this._dataAvailableCb(clockOffset);
|
||||
}
|
||||
|
||||
this._schedule(this._refreshPeriodInMS);
|
||||
},
|
||||
|
||||
/**
|
||||
* Used for retry SNTP requests.
|
||||
*/
|
||||
_retry: function _retry() {
|
||||
this._retryCount++;
|
||||
if (this._retryCount > this._maxRetryCount) {
|
||||
debug ("stop retrying SNTP");
|
||||
// Clear so we can start with clean status next time we have network.
|
||||
this._retryCount = 0;
|
||||
this._retryPeriodInMS = 0;
|
||||
return;
|
||||
}
|
||||
this._retryPeriodInMS = Math.max(1000, this._retryPeriodInMS * 2);
|
||||
|
||||
this._schedule(this._retryPeriodInMS);
|
||||
},
|
||||
|
||||
/**
|
||||
* Request SNTP.
|
||||
*/
|
||||
_request: function _request() {
|
||||
function GetRequest() {
|
||||
let NTP_PACKET_SIZE = 48;
|
||||
let NTP_MODE_CLIENT = 3;
|
||||
let NTP_VERSION = 3;
|
||||
let TRANSMIT_TIME_OFFSET = 40;
|
||||
|
||||
// Send the NTP request.
|
||||
let requestTimeInMS = Date.now();
|
||||
let s = requestTimeInMS / 1000;
|
||||
let ms = requestTimeInMS % 1000;
|
||||
// NTP time is relative to 1900.
|
||||
s += OFFSET_1900_TO_1970;
|
||||
let f = ms * 0x100000000 / 1000;
|
||||
s = Math.floor(s);
|
||||
f = Math.floor(f);
|
||||
|
||||
let buffer = new ArrayBuffer(NTP_PACKET_SIZE);
|
||||
let data = new DataView(buffer);
|
||||
data.setUint8(0, NTP_MODE_CLIENT | (NTP_VERSION << 3));
|
||||
data.setUint32(TRANSMIT_TIME_OFFSET, s, false);
|
||||
data.setUint32(TRANSMIT_TIME_OFFSET + 4, f, false);
|
||||
|
||||
return String.fromCharCode.apply(null, new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
function SNTPListener() {};
|
||||
SNTPListener.prototype = {
|
||||
onStartRequest: function onStartRequest(request, context) {
|
||||
},
|
||||
|
||||
onStopRequest: function onStopRequest(request, context, status) {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
debug ("Connection failed");
|
||||
this._requesting = false;
|
||||
this._retry();
|
||||
}
|
||||
}.bind(this),
|
||||
|
||||
onDataAvailable: function onDataAvailable(request, context, inputStream,
|
||||
offset, count) {
|
||||
function GetTimeStamp(binaryInputStream) {
|
||||
let s = binaryInputStream.read32();
|
||||
let f = binaryInputStream.read32();
|
||||
return Math.floor(
|
||||
((s - OFFSET_1900_TO_1970) * 1000) + ((f * 1000) / 0x100000000)
|
||||
);
|
||||
}
|
||||
debug ("Data available: " + count + " bytes");
|
||||
|
||||
try {
|
||||
let binaryInputStream = Cc["@mozilla.org/binaryinputstream;1"]
|
||||
.createInstance(Ci.nsIBinaryInputStream);
|
||||
binaryInputStream.setInputStream(inputStream);
|
||||
// We don't need first 24 bytes.
|
||||
for (let i = 0; i < 6; i++) {
|
||||
binaryInputStream.read32();
|
||||
}
|
||||
// Offset 24: originate time.
|
||||
let originateTimeInMS = GetTimeStamp(binaryInputStream);
|
||||
// Offset 32: receive time.
|
||||
let receiveTimeInMS = GetTimeStamp(binaryInputStream);
|
||||
// Offset 40: transmit time.
|
||||
let transmitTimeInMS = GetTimeStamp(binaryInputStream);
|
||||
let respondTimeInMS = Date.now();
|
||||
|
||||
this._handleSntp(originateTimeInMS, receiveTimeInMS,
|
||||
transmitTimeInMS, respondTimeInMS);
|
||||
this._requesting = false;
|
||||
} catch (e) {
|
||||
debug ("SNTPListener Error: " + e.message);
|
||||
this._requesting = false;
|
||||
this._retry();
|
||||
}
|
||||
inputStream.close();
|
||||
}.bind(this)
|
||||
};
|
||||
|
||||
function SNTPRequester() {}
|
||||
SNTPRequester.prototype = {
|
||||
onOutputStreamReady: function(stream) {
|
||||
try {
|
||||
let data = GetRequest();
|
||||
let bytes_write = stream.write(data, data.length);
|
||||
debug ("SNTP: sent " + bytes_write + " bytes");
|
||||
stream.close();
|
||||
} catch (e) {
|
||||
debug ("SNTPRequester Error: " + e.message);
|
||||
this._requesting = false;
|
||||
this._retry();
|
||||
}
|
||||
}.bind(this)
|
||||
};
|
||||
|
||||
// Number of seconds between Jan 1, 1900 and Jan 1, 1970.
|
||||
// 70 years plus 17 leap days.
|
||||
let OFFSET_1900_TO_1970 = ((365 * 70) + 17) * 24 * 60 * 60;
|
||||
|
||||
if (this._requesting) {
|
||||
return;
|
||||
}
|
||||
if (this._pools.length < 1) {
|
||||
debug("No server defined");
|
||||
return;
|
||||
}
|
||||
if (this._updateTimer) {
|
||||
this._updateTimer.cancel();
|
||||
}
|
||||
|
||||
debug ("Making request");
|
||||
this._requesting = true;
|
||||
|
||||
let currentThread = Cc["@mozilla.org/thread-manager;1"]
|
||||
.getService().currentThread;
|
||||
let socketTransportService =
|
||||
Cc["@mozilla.org/network/socket-transport-service;1"]
|
||||
.getService(Ci.nsISocketTransportService);
|
||||
let pump = Cc["@mozilla.org/network/input-stream-pump;1"]
|
||||
.createInstance(Ci.nsIInputStreamPump);
|
||||
let transport = socketTransportService
|
||||
.createTransport(["udp"],
|
||||
1,
|
||||
this._pools[Math.floor(this._pools.length * Math.random())],
|
||||
this._port,
|
||||
null);
|
||||
|
||||
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, this._timeoutInMS);
|
||||
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, this._timeoutInMS);
|
||||
|
||||
let outStream = transport.openOutputStream(0, 0, 0)
|
||||
.QueryInterface(Ci.nsIAsyncOutputStream);
|
||||
let inStream = transport.openInputStream(0, 0, 0);
|
||||
|
||||
pump.init(inStream, -1, -1, 0, 0, false);
|
||||
pump.asyncRead(new SNTPListener(), null);
|
||||
|
||||
outStream.asyncWait(new SNTPRequester(), 0, 0, currentThread);
|
||||
},
|
||||
|
||||
// Callback function.
|
||||
_dataAvailableCb: null,
|
||||
|
||||
// Sntp servers.
|
||||
_pools: [
|
||||
"0.pool.ntp.org",
|
||||
"1.pool.ntp.org",
|
||||
"2.pool.ntp.org",
|
||||
"3.pool.ntp.org"
|
||||
],
|
||||
|
||||
// The SNTP port.
|
||||
_port: 123,
|
||||
|
||||
// Maximum retry count allowed when request failed.
|
||||
_maxRetryCount: 0,
|
||||
|
||||
// Refresh period.
|
||||
_refreshPeriodInMS: 0,
|
||||
|
||||
// Timeout value used for connecting.
|
||||
_timeoutInMS: 30 * 1000,
|
||||
|
||||
// Cached SNTP offset.
|
||||
_cachedOffset: null,
|
||||
|
||||
// The time point when we cache the offset.
|
||||
_cachedTimeInMS: null,
|
||||
|
||||
// Flag to avoid redundant requests.
|
||||
_requesting: false,
|
||||
|
||||
// Retry counter.
|
||||
_retryCount: 0,
|
||||
|
||||
// Retry time offset (in seconds).
|
||||
_retryPeriodInMS: 0,
|
||||
|
||||
// Timer used for retries & daily updates.
|
||||
_updateTimer: null
|
||||
};
|
||||
|
||||
let debug;
|
||||
if (DEBUG) {
|
||||
debug = function (s) {
|
||||
dump("-*- Sntp: " + s + "\n");
|
||||
};
|
||||
} else {
|
||||
debug = function (s) {};
|
||||
}
|
@ -29,6 +29,7 @@ EXTRA_JS_MODULES += [
|
||||
'RemoteWebProgress.jsm',
|
||||
'SelectContentHelper.jsm',
|
||||
'SelectParentHelper.jsm',
|
||||
'Sntp.jsm',
|
||||
'Sqlite.jsm',
|
||||
'Task.jsm',
|
||||
'TelemetryTimestamps.jsm',
|
||||
|
Loading…
Reference in New Issue
Block a user