"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/sntp/lib/index.js" (7 Feb 2017, 9758 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Load modules
    2 
    3 var Dgram = require('dgram');
    4 var Dns = require('dns');
    5 var Hoek = require('hoek');
    6 
    7 
    8 // Declare internals
    9 
   10 var internals = {};
   11 
   12 
   13 exports.time = function (options, callback) {
   14 
   15     if (arguments.length !== 2) {
   16         callback = arguments[0];
   17         options = {};
   18     }
   19 
   20     var settings = Hoek.clone(options);
   21     settings.host = settings.host || 'pool.ntp.org';
   22     settings.port = settings.port || 123;
   23     settings.resolveReference = settings.resolveReference || false;
   24 
   25     // Declare variables used by callback
   26 
   27     var timeoutId = 0;
   28     var sent = 0;
   29 
   30     // Ensure callback is only called once
   31 
   32     var finish = function (err, result) {
   33 
   34         if (timeoutId) {
   35             clearTimeout(timeoutId);
   36             timeoutId = 0;
   37         }
   38 
   39         socket.removeAllListeners();
   40         socket.once('error', internals.ignore);
   41         socket.close();
   42         return callback(err, result);
   43     };
   44 
   45     finish = Hoek.once(finish);
   46 
   47     // Create UDP socket
   48 
   49     var socket = Dgram.createSocket('udp4');
   50 
   51     socket.once('error', function (err) {
   52 
   53         return finish(err);
   54     });
   55 
   56     // Listen to incoming messages
   57 
   58     socket.on('message', function (buffer, rinfo) {
   59 
   60         var received = Date.now();
   61 
   62         var message = new internals.NtpMessage(buffer);
   63         if (!message.isValid) {
   64             return finish(new Error('Invalid server response'), message);
   65         }
   66 
   67         if (message.originateTimestamp !== sent) {
   68             return finish(new Error('Wrong originate timestamp'), message);
   69         }
   70 
   71         // Timestamp Name          ID   When Generated
   72         // ------------------------------------------------------------
   73         // Originate Timestamp     T1   time request sent by client
   74         // Receive Timestamp       T2   time request received by server
   75         // Transmit Timestamp      T3   time reply sent by server
   76         // Destination Timestamp   T4   time reply received by client
   77         //
   78         // The roundtrip delay d and system clock offset t are defined as:
   79         //
   80         // d = (T4 - T1) - (T3 - T2)     t = ((T2 - T1) + (T3 - T4)) / 2
   81 
   82         var T1 = message.originateTimestamp;
   83         var T2 = message.receiveTimestamp;
   84         var T3 = message.transmitTimestamp;
   85         var T4 = received;
   86 
   87         message.d = (T4 - T1) - (T3 - T2);
   88         message.t = ((T2 - T1) + (T3 - T4)) / 2;
   89         message.receivedLocally = received;
   90 
   91         if (!settings.resolveReference ||
   92             message.stratum !== 'secondary') {
   93 
   94             return finish(null, message);
   95         }
   96 
   97         // Resolve reference IP address
   98 
   99         Dns.reverse(message.referenceId, function (err, domains) {
  100 
  101             if (/* $lab:coverage:off$ */ !err /* $lab:coverage:on$ */) {
  102                 message.referenceHost = domains[0];
  103             }
  104 
  105             return finish(null, message);
  106         });
  107     });
  108 
  109     // Set timeout
  110 
  111     if (settings.timeout) {
  112         timeoutId = setTimeout(function () {
  113 
  114             timeoutId = 0;
  115             return finish(new Error('Timeout'));
  116         }, settings.timeout);
  117     }
  118 
  119     // Construct NTP message
  120 
  121     var message = new Buffer(48);
  122     for (var i = 0; i < 48; i++) {                      // Zero message
  123         message[i] = 0;
  124     }
  125 
  126     message[0] = (0 << 6) + (4 << 3) + (3 << 0)         // Set version number to 4 and Mode to 3 (client)
  127     sent = Date.now();
  128     internals.fromMsecs(sent, message, 40);               // Set transmit timestamp (returns as originate)
  129 
  130     // Send NTP request
  131 
  132     socket.send(message, 0, message.length, settings.port, settings.host, function (err, bytes) {
  133 
  134         if (err ||
  135             bytes !== 48) {
  136 
  137             return finish(err || new Error('Could not send entire message'));
  138         }
  139     });
  140 };
  141 
  142 
  143 internals.NtpMessage = function (buffer) {
  144 
  145     this.isValid = false;
  146 
  147     // Validate
  148 
  149     if (buffer.length !== 48) {
  150         return;
  151     }
  152 
  153     // Leap indicator
  154 
  155     var li = (buffer[0] >> 6);
  156     switch (li) {
  157         case 0: this.leapIndicator = 'no-warning'; break;
  158         case 1: this.leapIndicator = 'last-minute-61'; break;
  159         case 2: this.leapIndicator = 'last-minute-59'; break;
  160         case 3: this.leapIndicator = 'alarm'; break;
  161     }
  162 
  163     // Version
  164 
  165     var vn = ((buffer[0] & 0x38) >> 3);
  166     this.version = vn;
  167 
  168     // Mode
  169 
  170     var mode = (buffer[0] & 0x7);
  171     switch (mode) {
  172         case 1: this.mode = 'symmetric-active'; break;
  173         case 2: this.mode = 'symmetric-passive'; break;
  174         case 3: this.mode = 'client'; break;
  175         case 4: this.mode = 'server'; break;
  176         case 5: this.mode = 'broadcast'; break;
  177         case 0:
  178         case 6:
  179         case 7: this.mode = 'reserved'; break;
  180     }
  181 
  182     // Stratum
  183 
  184     var stratum = buffer[1];
  185     if (stratum === 0) {
  186         this.stratum = 'death';
  187     }
  188     else if (stratum === 1) {
  189         this.stratum = 'primary';
  190     }
  191     else if (stratum <= 15) {
  192         this.stratum = 'secondary';
  193     }
  194     else {
  195         this.stratum = 'reserved';
  196     }
  197 
  198     // Poll interval (msec)
  199 
  200     this.pollInterval = Math.round(Math.pow(2, buffer[2])) * 1000;
  201 
  202     // Precision (msecs)
  203 
  204     this.precision = Math.pow(2, buffer[3]) * 1000;
  205 
  206     // Root delay (msecs)
  207 
  208     var rootDelay = 256 * (256 * (256 * buffer[4] + buffer[5]) + buffer[6]) + buffer[7];
  209     this.rootDelay = 1000 * (rootDelay / 0x10000);
  210 
  211     // Root dispersion (msecs)
  212 
  213     this.rootDispersion = ((buffer[8] << 8) + buffer[9] + ((buffer[10] << 8) + buffer[11]) / Math.pow(2, 16)) * 1000;
  214 
  215     // Reference identifier
  216 
  217     this.referenceId = '';
  218     switch (this.stratum) {
  219         case 'death':
  220         case 'primary':
  221             this.referenceId = String.fromCharCode(buffer[12]) + String.fromCharCode(buffer[13]) + String.fromCharCode(buffer[14]) + String.fromCharCode(buffer[15]);
  222             break;
  223         case 'secondary':
  224             this.referenceId = '' + buffer[12] + '.' + buffer[13] + '.' + buffer[14] + '.' + buffer[15];
  225             break;
  226     }
  227 
  228     // Reference timestamp
  229 
  230     this.referenceTimestamp = internals.toMsecs(buffer, 16);
  231 
  232     // Originate timestamp
  233 
  234     this.originateTimestamp = internals.toMsecs(buffer, 24);
  235 
  236     // Receive timestamp
  237 
  238     this.receiveTimestamp = internals.toMsecs(buffer, 32);
  239 
  240     // Transmit timestamp
  241 
  242     this.transmitTimestamp = internals.toMsecs(buffer, 40);
  243 
  244     // Validate
  245 
  246     if (this.version === 4 &&
  247         this.stratum !== 'reserved' &&
  248         this.mode === 'server' &&
  249         this.originateTimestamp &&
  250         this.receiveTimestamp &&
  251         this.transmitTimestamp) {
  252 
  253         this.isValid = true;
  254     }
  255 
  256     return this;
  257 };
  258 
  259 
  260 internals.toMsecs = function (buffer, offset) {
  261 
  262     var seconds = 0;
  263     var fraction = 0;
  264 
  265     for (var i = 0; i < 4; ++i) {
  266         seconds = (seconds * 256) + buffer[offset + i];
  267     }
  268 
  269     for (i = 4; i < 8; ++i) {
  270         fraction = (fraction * 256) + buffer[offset + i];
  271     }
  272 
  273     return ((seconds - 2208988800 + (fraction / Math.pow(2, 32))) * 1000);
  274 };
  275 
  276 
  277 internals.fromMsecs = function (ts, buffer, offset) {
  278 
  279     var seconds = Math.floor(ts / 1000) + 2208988800;
  280     var fraction = Math.round((ts % 1000) / 1000 * Math.pow(2, 32));
  281 
  282     buffer[offset + 0] = (seconds & 0xFF000000) >> 24;
  283     buffer[offset + 1] = (seconds & 0x00FF0000) >> 16;
  284     buffer[offset + 2] = (seconds & 0x0000FF00) >> 8;
  285     buffer[offset + 3] = (seconds & 0x000000FF);
  286 
  287     buffer[offset + 4] = (fraction & 0xFF000000) >> 24;
  288     buffer[offset + 5] = (fraction & 0x00FF0000) >> 16;
  289     buffer[offset + 6] = (fraction & 0x0000FF00) >> 8;
  290     buffer[offset + 7] = (fraction & 0x000000FF);
  291 };
  292 
  293 
  294 // Offset singleton
  295 
  296 internals.last = {
  297     offset: 0,
  298     expires: 0,
  299     host: '',
  300     port: 0
  301 };
  302 
  303 
  304 exports.offset = function (options, callback) {
  305 
  306     if (arguments.length !== 2) {
  307         callback = arguments[0];
  308         options = {};
  309     }
  310 
  311     var now = Date.now();
  312     var clockSyncRefresh = options.clockSyncRefresh || 24 * 60 * 60 * 1000;                    // Daily
  313 
  314     if (internals.last.offset &&
  315         internals.last.host === options.host &&
  316         internals.last.port === options.port &&
  317         now < internals.last.expires) {
  318 
  319         process.nextTick(function () {
  320 
  321             callback(null, internals.last.offset);
  322         });
  323 
  324         return;
  325     }
  326 
  327     exports.time(options, function (err, time) {
  328 
  329         if (err) {
  330             return callback(err, 0);
  331         }
  332 
  333         internals.last = {
  334             offset: Math.round(time.t),
  335             expires: now + clockSyncRefresh,
  336             host: options.host,
  337             port: options.port
  338         };
  339 
  340         return callback(null, internals.last.offset);
  341     });
  342 };
  343 
  344 
  345 // Now singleton
  346 
  347 internals.now = {
  348     intervalId: 0
  349 };
  350 
  351 
  352 exports.start = function (options, callback) {
  353 
  354     if (arguments.length !== 2) {
  355         callback = arguments[0];
  356         options = {};
  357     }
  358 
  359     if (internals.now.intervalId) {
  360         process.nextTick(function () {
  361 
  362             callback();
  363         });
  364 
  365         return;
  366     }
  367 
  368     exports.offset(options, function (err, offset) {
  369 
  370         internals.now.intervalId = setInterval(function () {
  371 
  372             exports.offset(options, function () { });
  373         }, options.clockSyncRefresh || 24 * 60 * 60 * 1000);                                // Daily
  374 
  375         return callback();
  376     });
  377 };
  378 
  379 
  380 exports.stop = function () {
  381 
  382     if (!internals.now.intervalId) {
  383         return;
  384     }
  385 
  386     clearInterval(internals.now.intervalId);
  387     internals.now.intervalId = 0;
  388 };
  389 
  390 
  391 exports.isLive = function () {
  392 
  393     return !!internals.now.intervalId;
  394 };
  395 
  396 
  397 exports.now = function () {
  398 
  399     var now = Date.now();
  400     if (!exports.isLive() ||
  401         now >= internals.last.expires) {
  402 
  403         return now;
  404     }
  405 
  406     return now + internals.last.offset;
  407 };
  408 
  409 
  410 internals.ignore = function () {
  411 
  412 };