index.js 10 KB

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