Ein Projekt das es ermöglicht Beerpong über das Internet von zwei unabhängigen positionen aus zu spielen. Entstehung im Rahmen einer Praktikumsaufgabe im Fach Interaktion.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Receiver.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. /*!
  2. * ws: a node.js websocket client
  3. * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
  4. * MIT Licensed
  5. */
  6. var util = require('util')
  7. , Validation = require('./Validation').Validation
  8. , ErrorCodes = require('./ErrorCodes')
  9. , BufferPool = require('./BufferPool')
  10. , bufferUtil = require('./BufferUtil').BufferUtil
  11. , PerMessageDeflate = require('./PerMessageDeflate');
  12. /**
  13. * HyBi Receiver implementation
  14. */
  15. function Receiver (extensions) {
  16. // memory pool for fragmented messages
  17. var fragmentedPoolPrevUsed = -1;
  18. this.fragmentedBufferPool = new BufferPool(1024, function(db, length) {
  19. return db.used + length;
  20. }, function(db) {
  21. return fragmentedPoolPrevUsed = fragmentedPoolPrevUsed >= 0 ?
  22. (fragmentedPoolPrevUsed + db.used) / 2 :
  23. db.used;
  24. });
  25. // memory pool for unfragmented messages
  26. var unfragmentedPoolPrevUsed = -1;
  27. this.unfragmentedBufferPool = new BufferPool(1024, function(db, length) {
  28. return db.used + length;
  29. }, function(db) {
  30. return unfragmentedPoolPrevUsed = unfragmentedPoolPrevUsed >= 0 ?
  31. (unfragmentedPoolPrevUsed + db.used) / 2 :
  32. db.used;
  33. });
  34. this.extensions = extensions || {};
  35. this.state = {
  36. activeFragmentedOperation: null,
  37. lastFragment: false,
  38. masked: false,
  39. opcode: 0,
  40. fragmentedOperation: false
  41. };
  42. this.overflow = [];
  43. this.headerBuffer = new Buffer(10);
  44. this.expectOffset = 0;
  45. this.expectBuffer = null;
  46. this.expectHandler = null;
  47. this.currentMessage = [];
  48. this.messageHandlers = [];
  49. this.expectHeader(2, this.processPacket);
  50. this.dead = false;
  51. this.processing = false;
  52. this.onerror = function() {};
  53. this.ontext = function() {};
  54. this.onbinary = function() {};
  55. this.onclose = function() {};
  56. this.onping = function() {};
  57. this.onpong = function() {};
  58. }
  59. module.exports = Receiver;
  60. /**
  61. * Add new data to the parser.
  62. *
  63. * @api public
  64. */
  65. Receiver.prototype.add = function(data) {
  66. var dataLength = data.length;
  67. if (dataLength == 0) return;
  68. if (this.expectBuffer == null) {
  69. this.overflow.push(data);
  70. return;
  71. }
  72. var toRead = Math.min(dataLength, this.expectBuffer.length - this.expectOffset);
  73. fastCopy(toRead, data, this.expectBuffer, this.expectOffset);
  74. this.expectOffset += toRead;
  75. if (toRead < dataLength) {
  76. this.overflow.push(data.slice(toRead));
  77. }
  78. while (this.expectBuffer && this.expectOffset == this.expectBuffer.length) {
  79. var bufferForHandler = this.expectBuffer;
  80. this.expectBuffer = null;
  81. this.expectOffset = 0;
  82. this.expectHandler.call(this, bufferForHandler);
  83. }
  84. };
  85. /**
  86. * Releases all resources used by the receiver.
  87. *
  88. * @api public
  89. */
  90. Receiver.prototype.cleanup = function() {
  91. this.dead = true;
  92. this.overflow = null;
  93. this.headerBuffer = null;
  94. this.expectBuffer = null;
  95. this.expectHandler = null;
  96. this.unfragmentedBufferPool = null;
  97. this.fragmentedBufferPool = null;
  98. this.state = null;
  99. this.currentMessage = null;
  100. this.onerror = null;
  101. this.ontext = null;
  102. this.onbinary = null;
  103. this.onclose = null;
  104. this.onping = null;
  105. this.onpong = null;
  106. };
  107. /**
  108. * Waits for a certain amount of header bytes to be available, then fires a callback.
  109. *
  110. * @api private
  111. */
  112. Receiver.prototype.expectHeader = function(length, handler) {
  113. if (length == 0) {
  114. handler(null);
  115. return;
  116. }
  117. this.expectBuffer = this.headerBuffer.slice(this.expectOffset, this.expectOffset + length);
  118. this.expectHandler = handler;
  119. var toRead = length;
  120. while (toRead > 0 && this.overflow.length > 0) {
  121. var fromOverflow = this.overflow.pop();
  122. if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead));
  123. var read = Math.min(fromOverflow.length, toRead);
  124. fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset);
  125. this.expectOffset += read;
  126. toRead -= read;
  127. }
  128. };
  129. /**
  130. * Waits for a certain amount of data bytes to be available, then fires a callback.
  131. *
  132. * @api private
  133. */
  134. Receiver.prototype.expectData = function(length, handler) {
  135. if (length == 0) {
  136. handler(null);
  137. return;
  138. }
  139. this.expectBuffer = this.allocateFromPool(length, this.state.fragmentedOperation);
  140. this.expectHandler = handler;
  141. var toRead = length;
  142. while (toRead > 0 && this.overflow.length > 0) {
  143. var fromOverflow = this.overflow.pop();
  144. if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead));
  145. var read = Math.min(fromOverflow.length, toRead);
  146. fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset);
  147. this.expectOffset += read;
  148. toRead -= read;
  149. }
  150. };
  151. /**
  152. * Allocates memory from the buffer pool.
  153. *
  154. * @api private
  155. */
  156. Receiver.prototype.allocateFromPool = function(length, isFragmented) {
  157. return (isFragmented ? this.fragmentedBufferPool : this.unfragmentedBufferPool).get(length);
  158. };
  159. /**
  160. * Start processing a new packet.
  161. *
  162. * @api private
  163. */
  164. Receiver.prototype.processPacket = function (data) {
  165. if (this.extensions[PerMessageDeflate.extensionName]) {
  166. if ((data[0] & 0x30) != 0) {
  167. this.error('reserved fields (2, 3) must be empty', 1002);
  168. return;
  169. }
  170. } else {
  171. if ((data[0] & 0x70) != 0) {
  172. this.error('reserved fields must be empty', 1002);
  173. return;
  174. }
  175. }
  176. this.state.lastFragment = (data[0] & 0x80) == 0x80;
  177. this.state.masked = (data[1] & 0x80) == 0x80;
  178. var compressed = (data[0] & 0x40) == 0x40;
  179. var opcode = data[0] & 0xf;
  180. if (opcode === 0) {
  181. if (compressed) {
  182. this.error('continuation frame cannot have the Per-message Compressed bits', 1002);
  183. return;
  184. }
  185. // continuation frame
  186. this.state.fragmentedOperation = true;
  187. this.state.opcode = this.state.activeFragmentedOperation;
  188. if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
  189. this.error('continuation frame cannot follow current opcode', 1002);
  190. return;
  191. }
  192. }
  193. else {
  194. if (opcode < 3 && this.state.activeFragmentedOperation != null) {
  195. this.error('data frames after the initial data frame must have opcode 0', 1002);
  196. return;
  197. }
  198. if (opcode >= 8 && compressed) {
  199. this.error('control frames cannot have the Per-message Compressed bits', 1002);
  200. return;
  201. }
  202. this.state.compressed = compressed;
  203. this.state.opcode = opcode;
  204. if (this.state.lastFragment === false) {
  205. this.state.fragmentedOperation = true;
  206. this.state.activeFragmentedOperation = opcode;
  207. }
  208. else this.state.fragmentedOperation = false;
  209. }
  210. var handler = opcodes[this.state.opcode];
  211. if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode, 1002);
  212. else {
  213. handler.start.call(this, data);
  214. }
  215. };
  216. /**
  217. * Endprocessing a packet.
  218. *
  219. * @api private
  220. */
  221. Receiver.prototype.endPacket = function() {
  222. if (!this.state.fragmentedOperation) this.unfragmentedBufferPool.reset(true);
  223. else if (this.state.lastFragment) this.fragmentedBufferPool.reset(false);
  224. this.expectOffset = 0;
  225. this.expectBuffer = null;
  226. this.expectHandler = null;
  227. if (this.state.lastFragment && this.state.opcode === this.state.activeFragmentedOperation) {
  228. // end current fragmented operation
  229. this.state.activeFragmentedOperation = null;
  230. }
  231. this.state.lastFragment = false;
  232. this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
  233. this.state.masked = false;
  234. this.expectHeader(2, this.processPacket);
  235. };
  236. /**
  237. * Reset the parser state.
  238. *
  239. * @api private
  240. */
  241. Receiver.prototype.reset = function() {
  242. if (this.dead) return;
  243. this.state = {
  244. activeFragmentedOperation: null,
  245. lastFragment: false,
  246. masked: false,
  247. opcode: 0,
  248. fragmentedOperation: false
  249. };
  250. this.fragmentedBufferPool.reset(true);
  251. this.unfragmentedBufferPool.reset(true);
  252. this.expectOffset = 0;
  253. this.expectBuffer = null;
  254. this.expectHandler = null;
  255. this.overflow = [];
  256. this.currentMessage = [];
  257. this.messageHandlers = [];
  258. };
  259. /**
  260. * Unmask received data.
  261. *
  262. * @api private
  263. */
  264. Receiver.prototype.unmask = function (mask, buf, binary) {
  265. if (mask != null && buf != null) bufferUtil.unmask(buf, mask);
  266. if (binary) return buf;
  267. return buf != null ? buf.toString('utf8') : '';
  268. };
  269. /**
  270. * Concatenates a list of buffers.
  271. *
  272. * @api private
  273. */
  274. Receiver.prototype.concatBuffers = function(buffers) {
  275. var length = 0;
  276. for (var i = 0, l = buffers.length; i < l; ++i) length += buffers[i].length;
  277. var mergedBuffer = new Buffer(length);
  278. bufferUtil.merge(mergedBuffer, buffers);
  279. return mergedBuffer;
  280. };
  281. /**
  282. * Handles an error
  283. *
  284. * @api private
  285. */
  286. Receiver.prototype.error = function (reason, protocolErrorCode) {
  287. this.reset();
  288. this.onerror(reason, protocolErrorCode);
  289. return this;
  290. };
  291. /**
  292. * Execute message handler buffers
  293. *
  294. * @api private
  295. */
  296. Receiver.prototype.flush = function() {
  297. if (this.processing || this.dead) return;
  298. var handler = this.messageHandlers.shift();
  299. if (!handler) return;
  300. this.processing = true;
  301. var self = this;
  302. handler(function() {
  303. self.processing = false;
  304. self.flush();
  305. });
  306. };
  307. /**
  308. * Apply extensions to message
  309. *
  310. * @api private
  311. */
  312. Receiver.prototype.applyExtensions = function(messageBuffer, fin, compressed, callback) {
  313. var self = this;
  314. if (compressed) {
  315. this.extensions[PerMessageDeflate.extensionName].decompress(messageBuffer, fin, function(err, buffer) {
  316. if (self.dead) return;
  317. if (err) {
  318. callback(new Error('invalid compressed data'));
  319. return;
  320. }
  321. callback(null, buffer);
  322. });
  323. } else {
  324. callback(null, messageBuffer);
  325. }
  326. };
  327. /**
  328. * Buffer utilities
  329. */
  330. function readUInt16BE(start) {
  331. return (this[start]<<8) +
  332. this[start+1];
  333. }
  334. function readUInt32BE(start) {
  335. return (this[start]<<24) +
  336. (this[start+1]<<16) +
  337. (this[start+2]<<8) +
  338. this[start+3];
  339. }
  340. function fastCopy(length, srcBuffer, dstBuffer, dstOffset) {
  341. switch (length) {
  342. default: srcBuffer.copy(dstBuffer, dstOffset, 0, length); break;
  343. case 16: dstBuffer[dstOffset+15] = srcBuffer[15];
  344. case 15: dstBuffer[dstOffset+14] = srcBuffer[14];
  345. case 14: dstBuffer[dstOffset+13] = srcBuffer[13];
  346. case 13: dstBuffer[dstOffset+12] = srcBuffer[12];
  347. case 12: dstBuffer[dstOffset+11] = srcBuffer[11];
  348. case 11: dstBuffer[dstOffset+10] = srcBuffer[10];
  349. case 10: dstBuffer[dstOffset+9] = srcBuffer[9];
  350. case 9: dstBuffer[dstOffset+8] = srcBuffer[8];
  351. case 8: dstBuffer[dstOffset+7] = srcBuffer[7];
  352. case 7: dstBuffer[dstOffset+6] = srcBuffer[6];
  353. case 6: dstBuffer[dstOffset+5] = srcBuffer[5];
  354. case 5: dstBuffer[dstOffset+4] = srcBuffer[4];
  355. case 4: dstBuffer[dstOffset+3] = srcBuffer[3];
  356. case 3: dstBuffer[dstOffset+2] = srcBuffer[2];
  357. case 2: dstBuffer[dstOffset+1] = srcBuffer[1];
  358. case 1: dstBuffer[dstOffset] = srcBuffer[0];
  359. }
  360. }
  361. function clone(obj) {
  362. var cloned = {};
  363. for (var k in obj) {
  364. if (obj.hasOwnProperty(k)) {
  365. cloned[k] = obj[k];
  366. }
  367. }
  368. return cloned;
  369. }
  370. /**
  371. * Opcode handlers
  372. */
  373. var opcodes = {
  374. // text
  375. '1': {
  376. start: function(data) {
  377. var self = this;
  378. // decode length
  379. var firstLength = data[1] & 0x7f;
  380. if (firstLength < 126) {
  381. opcodes['1'].getData.call(self, firstLength);
  382. }
  383. else if (firstLength == 126) {
  384. self.expectHeader(2, function(data) {
  385. opcodes['1'].getData.call(self, readUInt16BE.call(data, 0));
  386. });
  387. }
  388. else if (firstLength == 127) {
  389. self.expectHeader(8, function(data) {
  390. if (readUInt32BE.call(data, 0) != 0) {
  391. self.error('packets with length spanning more than 32 bit is currently not supported', 1008);
  392. return;
  393. }
  394. opcodes['1'].getData.call(self, readUInt32BE.call(data, 4));
  395. });
  396. }
  397. },
  398. getData: function(length) {
  399. var self = this;
  400. if (self.state.masked) {
  401. self.expectHeader(4, function(data) {
  402. var mask = data;
  403. self.expectData(length, function(data) {
  404. opcodes['1'].finish.call(self, mask, data);
  405. });
  406. });
  407. }
  408. else {
  409. self.expectData(length, function(data) {
  410. opcodes['1'].finish.call(self, null, data);
  411. });
  412. }
  413. },
  414. finish: function(mask, data) {
  415. var self = this;
  416. var packet = this.unmask(mask, data, true) || new Buffer(0);
  417. var state = clone(this.state);
  418. this.messageHandlers.push(function(callback) {
  419. self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) {
  420. if (err) return self.error(err.message, 1007);
  421. if (buffer != null) self.currentMessage.push(buffer);
  422. if (state.lastFragment) {
  423. var messageBuffer = self.concatBuffers(self.currentMessage);
  424. self.currentMessage = [];
  425. if (!Validation.isValidUTF8(messageBuffer)) {
  426. self.error('invalid utf8 sequence', 1007);
  427. return;
  428. }
  429. self.ontext(messageBuffer.toString('utf8'), {masked: state.masked, buffer: messageBuffer});
  430. }
  431. callback();
  432. });
  433. });
  434. this.flush();
  435. this.endPacket();
  436. }
  437. },
  438. // binary
  439. '2': {
  440. start: function(data) {
  441. var self = this;
  442. // decode length
  443. var firstLength = data[1] & 0x7f;
  444. if (firstLength < 126) {
  445. opcodes['2'].getData.call(self, firstLength);
  446. }
  447. else if (firstLength == 126) {
  448. self.expectHeader(2, function(data) {
  449. opcodes['2'].getData.call(self, readUInt16BE.call(data, 0));
  450. });
  451. }
  452. else if (firstLength == 127) {
  453. self.expectHeader(8, function(data) {
  454. if (readUInt32BE.call(data, 0) != 0) {
  455. self.error('packets with length spanning more than 32 bit is currently not supported', 1008);
  456. return;
  457. }
  458. opcodes['2'].getData.call(self, readUInt32BE.call(data, 4, true));
  459. });
  460. }
  461. },
  462. getData: function(length) {
  463. var self = this;
  464. if (self.state.masked) {
  465. self.expectHeader(4, function(data) {
  466. var mask = data;
  467. self.expectData(length, function(data) {
  468. opcodes['2'].finish.call(self, mask, data);
  469. });
  470. });
  471. }
  472. else {
  473. self.expectData(length, function(data) {
  474. opcodes['2'].finish.call(self, null, data);
  475. });
  476. }
  477. },
  478. finish: function(mask, data) {
  479. var self = this;
  480. var packet = this.unmask(mask, data, true) || new Buffer(0);
  481. var state = clone(this.state);
  482. this.messageHandlers.push(function(callback) {
  483. self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) {
  484. if (err) return self.error(err.message, 1007);
  485. if (buffer != null) self.currentMessage.push(buffer);
  486. if (state.lastFragment) {
  487. var messageBuffer = self.concatBuffers(self.currentMessage);
  488. self.currentMessage = [];
  489. self.onbinary(messageBuffer, {masked: state.masked, buffer: messageBuffer});
  490. }
  491. callback();
  492. });
  493. });
  494. this.flush();
  495. this.endPacket();
  496. }
  497. },
  498. // close
  499. '8': {
  500. start: function(data) {
  501. var self = this;
  502. if (self.state.lastFragment == false) {
  503. self.error('fragmented close is not supported', 1002);
  504. return;
  505. }
  506. // decode length
  507. var firstLength = data[1] & 0x7f;
  508. if (firstLength < 126) {
  509. opcodes['8'].getData.call(self, firstLength);
  510. }
  511. else {
  512. self.error('control frames cannot have more than 125 bytes of data', 1002);
  513. }
  514. },
  515. getData: function(length) {
  516. var self = this;
  517. if (self.state.masked) {
  518. self.expectHeader(4, function(data) {
  519. var mask = data;
  520. self.expectData(length, function(data) {
  521. opcodes['8'].finish.call(self, mask, data);
  522. });
  523. });
  524. }
  525. else {
  526. self.expectData(length, function(data) {
  527. opcodes['8'].finish.call(self, null, data);
  528. });
  529. }
  530. },
  531. finish: function(mask, data) {
  532. var self = this;
  533. data = self.unmask(mask, data, true);
  534. var state = clone(this.state);
  535. this.messageHandlers.push(function() {
  536. if (data && data.length == 1) {
  537. self.error('close packets with data must be at least two bytes long', 1002);
  538. return;
  539. }
  540. var code = data && data.length > 1 ? readUInt16BE.call(data, 0) : 1000;
  541. if (!ErrorCodes.isValidErrorCode(code)) {
  542. self.error('invalid error code', 1002);
  543. return;
  544. }
  545. var message = '';
  546. if (data && data.length > 2) {
  547. var messageBuffer = data.slice(2);
  548. if (!Validation.isValidUTF8(messageBuffer)) {
  549. self.error('invalid utf8 sequence', 1007);
  550. return;
  551. }
  552. message = messageBuffer.toString('utf8');
  553. }
  554. self.onclose(code, message, {masked: state.masked});
  555. self.reset();
  556. });
  557. this.flush();
  558. },
  559. },
  560. // ping
  561. '9': {
  562. start: function(data) {
  563. var self = this;
  564. if (self.state.lastFragment == false) {
  565. self.error('fragmented ping is not supported', 1002);
  566. return;
  567. }
  568. // decode length
  569. var firstLength = data[1] & 0x7f;
  570. if (firstLength < 126) {
  571. opcodes['9'].getData.call(self, firstLength);
  572. }
  573. else {
  574. self.error('control frames cannot have more than 125 bytes of data', 1002);
  575. }
  576. },
  577. getData: function(length) {
  578. var self = this;
  579. if (self.state.masked) {
  580. self.expectHeader(4, function(data) {
  581. var mask = data;
  582. self.expectData(length, function(data) {
  583. opcodes['9'].finish.call(self, mask, data);
  584. });
  585. });
  586. }
  587. else {
  588. self.expectData(length, function(data) {
  589. opcodes['9'].finish.call(self, null, data);
  590. });
  591. }
  592. },
  593. finish: function(mask, data) {
  594. var self = this;
  595. data = this.unmask(mask, data, true);
  596. var state = clone(this.state);
  597. this.messageHandlers.push(function(callback) {
  598. self.onping(data, {masked: state.masked, binary: true});
  599. callback();
  600. });
  601. this.flush();
  602. this.endPacket();
  603. }
  604. },
  605. // pong
  606. '10': {
  607. start: function(data) {
  608. var self = this;
  609. if (self.state.lastFragment == false) {
  610. self.error('fragmented pong is not supported', 1002);
  611. return;
  612. }
  613. // decode length
  614. var firstLength = data[1] & 0x7f;
  615. if (firstLength < 126) {
  616. opcodes['10'].getData.call(self, firstLength);
  617. }
  618. else {
  619. self.error('control frames cannot have more than 125 bytes of data', 1002);
  620. }
  621. },
  622. getData: function(length) {
  623. var self = this;
  624. if (this.state.masked) {
  625. this.expectHeader(4, function(data) {
  626. var mask = data;
  627. self.expectData(length, function(data) {
  628. opcodes['10'].finish.call(self, mask, data);
  629. });
  630. });
  631. }
  632. else {
  633. this.expectData(length, function(data) {
  634. opcodes['10'].finish.call(self, null, data);
  635. });
  636. }
  637. },
  638. finish: function(mask, data) {
  639. var self = this;
  640. data = self.unmask(mask, data, true);
  641. var state = clone(this.state);
  642. this.messageHandlers.push(function(callback) {
  643. self.onpong(data, {masked: state.masked, binary: true});
  644. callback();
  645. });
  646. this.flush();
  647. this.endPacket();
  648. }
  649. }
  650. }