index.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // Load modules
  2. var Dns = require('dns');
  3. var Dgram = require('dgram');
  4. var Lab = require('lab');
  5. var Sntp = require('../lib');
  6. // Declare internals
  7. var internals = {};
  8. // Test shortcuts
  9. var lab = exports.lab = Lab.script();
  10. var before = lab.before;
  11. var after = lab.after;
  12. var describe = lab.experiment;
  13. var it = lab.test;
  14. var expect = Lab.expect;
  15. describe('SNTP', function () {
  16. describe('#time', function () {
  17. it('returns consistent result over multiple tries', function (done) {
  18. Sntp.time(function (err, time) {
  19. expect(err).to.not.exist;
  20. expect(time).to.exist;
  21. var t1 = time.t;
  22. Sntp.time(function (err, time) {
  23. expect(err).to.not.exist;
  24. expect(time).to.exist;
  25. var t2 = time.t;
  26. expect(Math.abs(t1 - t2)).is.below(200);
  27. done();
  28. });
  29. });
  30. });
  31. it('resolves reference IP', function (done) {
  32. Sntp.time({ host: 'ntp.exnet.com', resolveReference: true }, function (err, time) {
  33. expect(err).to.not.exist;
  34. expect(time).to.exist;
  35. expect(time.referenceHost).to.exist;
  36. done();
  37. });
  38. });
  39. it('times out on no response', function (done) {
  40. Sntp.time({ port: 124, timeout: 100 }, function (err, time) {
  41. expect(err).to.exist;
  42. expect(time).to.not.exist;
  43. expect(err.message).to.equal('Timeout');
  44. done();
  45. });
  46. });
  47. it('errors on error event', { parallel: false }, function (done) {
  48. var orig = Dgram.createSocket;
  49. Dgram.createSocket = function (type) {
  50. Dgram.createSocket = orig;
  51. var socket = Dgram.createSocket(type);
  52. setImmediate(function () { socket.emit('error', new Error('Fake')) });
  53. return socket;
  54. };
  55. Sntp.time(function (err, time) {
  56. expect(err).to.exist;
  57. expect(time).to.not.exist;
  58. expect(err.message).to.equal('Fake');
  59. done();
  60. });
  61. });
  62. it('errors on incorrect sent size', { parallel: false }, function (done) {
  63. var orig = Dgram.Socket.prototype.send;
  64. Dgram.Socket.prototype.send = function (buf, offset, length, port, address, callback) {
  65. Dgram.Socket.prototype.send = orig;
  66. return callback(null, 40);
  67. };
  68. Sntp.time(function (err, time) {
  69. expect(err).to.exist;
  70. expect(time).to.not.exist;
  71. expect(err.message).to.equal('Could not send entire message');
  72. done();
  73. });
  74. });
  75. it('times out on invalid host', function (done) {
  76. Sntp.time({ host: 'error', timeout: 10000 }, function (err, time) {
  77. expect(err).to.exist;
  78. expect(time).to.not.exist;
  79. expect(err.message).to.contain('getaddrinfo');
  80. done();
  81. });
  82. });
  83. it('fails on bad response buffer size', function (done) {
  84. var server = Dgram.createSocket('udp4');
  85. server.on('message', function (message, remote) {
  86. var message = new Buffer(10);
  87. server.send(message, 0, message.length, remote.port, remote.address, function (err, bytes) {
  88. server.close();
  89. });
  90. });
  91. server.bind(49123);
  92. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  93. expect(err).to.exist;
  94. expect(err.message).to.equal('Invalid server response');
  95. done();
  96. });
  97. });
  98. var messup = function (bytes) {
  99. var server = Dgram.createSocket('udp4');
  100. server.on('message', function (message, remote) {
  101. var message = new Buffer([
  102. 0x24, 0x01, 0x00, 0xe3,
  103. 0x00, 0x00, 0x00, 0x00,
  104. 0x00, 0x00, 0x00, 0x00,
  105. 0x41, 0x43, 0x54, 0x53,
  106. 0xd4, 0xa8, 0x2d, 0xc7,
  107. 0x1c, 0x5d, 0x49, 0x1b,
  108. 0xd4, 0xa8, 0x2d, 0xe6,
  109. 0x67, 0xef, 0x9d, 0xb2,
  110. 0xd4, 0xa8, 0x2d, 0xe6,
  111. 0x71, 0xed, 0xb5, 0xfb,
  112. 0xd4, 0xa8, 0x2d, 0xe6,
  113. 0x71, 0xee, 0x6c, 0xc5
  114. ]);
  115. for (var i = 0, il = bytes.length; i < il; ++i) {
  116. message[bytes[i][0]] = bytes[i][1];
  117. }
  118. server.send(message, 0, message.length, remote.port, remote.address, function (err, bytes) {
  119. server.close();
  120. });
  121. });
  122. server.bind(49123);
  123. };
  124. it('fails on bad version', function (done) {
  125. messup([[0, (0 << 6) + (3 << 3) + (4 << 0)]]);
  126. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  127. expect(err).to.exist;
  128. expect(time.version).to.equal(3);
  129. expect(err.message).to.equal('Invalid server response');
  130. done();
  131. });
  132. });
  133. it('fails on bad originateTimestamp', function (done) {
  134. messup([[24, 0x83], [25, 0xaa], [26, 0x7e], [27, 0x80], [28, 0], [29, 0], [30, 0], [31, 0]]);
  135. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  136. expect(err).to.exist;
  137. expect(err.message).to.equal('Invalid server response');
  138. done();
  139. });
  140. });
  141. it('fails on bad receiveTimestamp', function (done) {
  142. messup([[32, 0x83], [33, 0xaa], [34, 0x7e], [35, 0x80], [36, 0], [37, 0], [38, 0], [39, 0]]);
  143. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  144. expect(err).to.exist;
  145. expect(err.message).to.equal('Invalid server response');
  146. done();
  147. });
  148. });
  149. it('fails on bad originate timestamp and alarm li', function (done) {
  150. messup([[0, (3 << 6) + (4 << 3) + (4 << 0)]]);
  151. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  152. expect(err).to.exist;
  153. expect(err.message).to.equal('Wrong originate timestamp');
  154. expect(time.leapIndicator).to.equal('alarm');
  155. done();
  156. });
  157. });
  158. it('returns time with death stratum and last61 li', function (done) {
  159. messup([[0, (1 << 6) + (4 << 3) + (4 << 0)], [1, 0]]);
  160. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  161. expect(time.stratum).to.equal('death');
  162. expect(time.leapIndicator).to.equal('last-minute-61');
  163. done();
  164. });
  165. });
  166. it('returns time with reserved stratum and last59 li', function (done) {
  167. messup([[0, (2 << 6) + (4 << 3) + (4 << 0)], [1, 0x1f]]);
  168. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  169. expect(time.stratum).to.equal('reserved');
  170. expect(time.leapIndicator).to.equal('last-minute-59');
  171. done();
  172. });
  173. });
  174. it('fails on bad mode (symmetric-active)', function (done) {
  175. messup([[0, (0 << 6) + (4 << 3) + (1 << 0)]]);
  176. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  177. expect(err).to.exist;
  178. expect(time.mode).to.equal('symmetric-active');
  179. done();
  180. });
  181. });
  182. it('fails on bad mode (symmetric-passive)', function (done) {
  183. messup([[0, (0 << 6) + (4 << 3) + (2 << 0)]]);
  184. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  185. expect(err).to.exist;
  186. expect(time.mode).to.equal('symmetric-passive');
  187. done();
  188. });
  189. });
  190. it('fails on bad mode (client)', function (done) {
  191. messup([[0, (0 << 6) + (4 << 3) + (3 << 0)]]);
  192. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  193. expect(err).to.exist;
  194. expect(time.mode).to.equal('client');
  195. done();
  196. });
  197. });
  198. it('fails on bad mode (broadcast)', function (done) {
  199. messup([[0, (0 << 6) + (4 << 3) + (5 << 0)]]);
  200. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  201. expect(err).to.exist;
  202. expect(time.mode).to.equal('broadcast');
  203. done();
  204. });
  205. });
  206. it('fails on bad mode (reserved)', function (done) {
  207. messup([[0, (0 << 6) + (4 << 3) + (6 << 0)]]);
  208. Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
  209. expect(err).to.exist;
  210. expect(time.mode).to.equal('reserved');
  211. done();
  212. });
  213. });
  214. });
  215. describe('#offset', function () {
  216. it('gets the current offset', function (done) {
  217. Sntp.offset(function (err, offset) {
  218. expect(err).to.not.exist;
  219. expect(offset).to.not.equal(0);
  220. done();
  221. });
  222. });
  223. it('gets the current offset from cache', function (done) {
  224. Sntp.offset(function (err, offset) {
  225. expect(err).to.not.exist;
  226. expect(offset).to.not.equal(0);
  227. var offset1 = offset;
  228. Sntp.offset({}, function (err, offset) {
  229. expect(err).to.not.exist;
  230. expect(offset).to.equal(offset1);
  231. done();
  232. });
  233. });
  234. });
  235. it('gets the new offset on different server', function (done) {
  236. Sntp.offset(function (err, offset) {
  237. expect(err).to.not.exist;
  238. expect(offset).to.not.equal(0);
  239. var offset1 = offset;
  240. Sntp.offset({ host: 'nist1-sj.ustiming.org' }, function (err, offset) {
  241. expect(err).to.not.exist;
  242. expect(offset).to.not.equal(offset1);
  243. done();
  244. });
  245. });
  246. });
  247. it('gets the new offset on different server', function (done) {
  248. Sntp.offset(function (err, offset) {
  249. expect(err).to.not.exist;
  250. expect(offset).to.not.equal(0);
  251. var offset1 = offset;
  252. Sntp.offset({ port: 123 }, function (err, offset) {
  253. expect(err).to.not.exist;
  254. expect(offset).to.not.equal(offset1);
  255. done();
  256. });
  257. });
  258. });
  259. it('fails getting the current offset on invalid server', function (done) {
  260. Sntp.offset({ host: 'error' }, function (err, offset) {
  261. expect(err).to.exist;
  262. expect(offset).to.equal(0);
  263. done();
  264. });
  265. });
  266. });
  267. describe('#now', function () {
  268. it('starts auto-sync, gets now, then stops', function (done) {
  269. Sntp.stop();
  270. var before = Sntp.now();
  271. expect(before).to.equal(Date.now());
  272. Sntp.start(function () {
  273. var now = Sntp.now();
  274. expect(now).to.not.equal(Date.now());
  275. Sntp.stop();
  276. done();
  277. });
  278. });
  279. it('starts twice', function (done) {
  280. Sntp.start(function () {
  281. Sntp.start(function () {
  282. var now = Sntp.now();
  283. expect(now).to.not.equal(Date.now());
  284. Sntp.stop();
  285. done();
  286. });
  287. });
  288. });
  289. it('starts auto-sync, gets now, waits, gets again after timeout', function (done) {
  290. Sntp.stop();
  291. var before = Sntp.now();
  292. expect(before).to.equal(Date.now());
  293. Sntp.start({ clockSyncRefresh: 100 }, function () {
  294. var now = Sntp.now();
  295. expect(now).to.not.equal(Date.now());
  296. expect(now).to.equal(Sntp.now());
  297. setTimeout(function () {
  298. expect(Sntp.now()).to.not.equal(now);
  299. Sntp.stop();
  300. done();
  301. }, 110);
  302. });
  303. });
  304. });
  305. });