UNPKG

@jsprismarine/raknet

Version:
107 lines (104 loc) 16.9 kB
import BinaryStream from '@jsprismarine/jsbinaryutils'; import InetAddress from '../utils/InetAddress.es.js'; import { MessageIdentifiers } from './MessageIdentifiers.es.js'; import 'assert'; import IncompatibleProtocolVersion from './connection/IncompatibleProtocolVersion.es.js'; import OpenConnectionReply1 from './connection/OpenConnectionReply1.es.js'; import OpenConnectionReply2 from './connection/OpenConnectionReply2.es.js'; import OpenConnectionRequest2 from './connection/OpenConnectionRequest2.es.js'; import UnconnectedPing from './offline/UnconnectedPing.es.js'; import UnconnectedPong from './offline/UnconnectedPong.es.js'; import 'node:assert'; import { OFFLINE_MESSAGE_DATA_ID, MINECRAFT_PROTOCOL_VERSION, UDP_HEADER_SIZE, MAX_MTU_SIZE } from '../Constants.es.js'; import 'events'; import 'node:dgram'; class OfflineHandler { constructor(listener) { this.listener = listener; } process(msg, rinfo) { switch (msg[0]) { // https://github.com/facebookarchive/RakNet/blob/master/Source/RakPeer.cpp#L4638 case MessageIdentifiers.UNCONNECTED_PING_OPEN_CONNECTIONS: if (!this.listener.allowIncomingConnections()) { return; } case MessageIdentifiers.UNCONNECTED_PING: const ping = new UnconnectedPing(msg); ping.decode(); const pong = new UnconnectedPong(); pong.timestamp = ping.timestamp; pong.serverGuid = this.listener.getServerGuid(); pong.serverName = this.listener.serverName.toString(); this.listener.sendPacket(pong, rinfo); break; // https://github.com/facebookarchive/RakNet/blob/master/Source/RakPeer.cpp#L5127 case MessageIdentifiers.OPEN_CONNECTION_REQUEST_1: const remoteProtocol = msg[1 + OFFLINE_MESSAGE_DATA_ID.byteLength]; if (remoteProtocol !== MINECRAFT_PROTOCOL_VERSION) { const response = new IncompatibleProtocolVersion(); response.protocol = MINECRAFT_PROTOCOL_VERSION; response.serverGUID = this.listener.getServerGuid(); this.listener.sendPacket(response, rinfo); return; } const reply1 = new OpenConnectionReply1(); reply1.serverGUID = this.listener.getServerGuid(); if (msg.byteLength + UDP_HEADER_SIZE > MAX_MTU_SIZE) { reply1.mtuSize = MAX_MTU_SIZE; } else { reply1.mtuSize = msg.byteLength + UDP_HEADER_SIZE; } this.listener.sendPacket(reply1, rinfo); break; // https://github.com/facebookarchive/RakNet/blob/master/Source/RakPeer.cpp#L5198 case MessageIdentifiers.OPEN_CONNECTION_REQUEST_2: const request = new OpenConnectionRequest2(msg); request.decode(); const addrSession = this.listener.getSessionByAddress(rinfo); const addressInUse = addrSession !== null && !addrSession.isDisconnected(); const guidSession = this.listener.getSessionByGUID(request.clientGUID); const guidInUse = guidSession !== null && !guidSession.isDisconnected(); const reply2 = new OpenConnectionReply2(); reply2.serverGuid = this.listener.getServerGuid(); reply2.clientAddress = new InetAddress(rinfo.address, rinfo.port, 4); reply2.mtuSize = request.mtuSize; if (addressInUse && guidInUse) { if (addrSession === guidSession) { this.listener.sendPacket(reply2, rinfo); return; } this.sendAlreadyConnected(rinfo); return; } if (!addressInUse && guidInUse || addrSession && !guidInUse) { this.sendAlreadyConnected(rinfo); } if (!this.listener.allowIncomingConnections()) { const str = new BinaryStream(); str.writeByte(MessageIdentifiers.NO_FREE_INCOMING_CONNECTIONS); str.write(OFFLINE_MESSAGE_DATA_ID); str.writeLong(this.listener.getServerGuid()); this.listener.sendBuffer(str.getBuffer(), rinfo); return; } this.listener.addSession(rinfo, request.mtuSize, request.clientGUID); this.listener.sendPacket(reply2, rinfo); break; case MessageIdentifiers.QUERY: this.listener.emit("raw", msg, new InetAddress(rinfo.address, rinfo.port)); break; default: throw new Error(`Unknown unconnected packet with ID=${msg[0].toString(16)}`); } } sendAlreadyConnected(remote) { const str = new BinaryStream(); str.writeByte(MessageIdentifiers.ALREADY_CONNECTED); str.write(OFFLINE_MESSAGE_DATA_ID); str.writeLong(this.listener.getServerGuid()); this.listener.sendBuffer(str.getBuffer(), remote); } } export { OfflineHandler }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT2ZmbGluZUhhbmRsZXIuZXMuanMiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcm90b2NvbC9PZmZsaW5lSGFuZGxlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmV0QWRkcmVzcywgTUFYX01UVV9TSVpFLCBNSU5FQ1JBRlRfUFJPVE9DT0xfVkVSU0lPTiwgT0ZGTElORV9NRVNTQUdFX0RBVEFfSUQsIFVEUF9IRUFERVJfU0laRSB9IGZyb20gJy4uLyc7XG5cbmltcG9ydCBCaW5hcnlTdHJlYW0gZnJvbSAnQGpzcHJpc21hcmluZS9qc2JpbmFyeXV0aWxzJztcbmltcG9ydCB0eXBlIHsgUmVtb3RlSW5mbyB9IGZyb20gJ25vZGU6ZGdyYW0nO1xuaW1wb3J0IHR5cGUgU2VydmVyU29ja2V0IGZyb20gJy4uL1NlcnZlclNvY2tldCc7XG5pbXBvcnQgeyBNZXNzYWdlSWRlbnRpZmllcnMgfSBmcm9tICcuL01lc3NhZ2VJZGVudGlmaWVycyc7XG5pbXBvcnQgSW5jb21wYXRpYmxlUHJvdG9jb2xWZXJzaW9uIGZyb20gJy4vY29ubmVjdGlvbi9JbmNvbXBhdGlibGVQcm90b2NvbFZlcnNpb24nO1xuaW1wb3J0IE9wZW5Db25uZWN0aW9uUmVwbHkxIGZyb20gJy4vY29ubmVjdGlvbi9PcGVuQ29ubmVjdGlvblJlcGx5MSc7XG5pbXBvcnQgT3BlbkNvbm5lY3Rpb25SZXBseTIgZnJvbSAnLi9jb25uZWN0aW9uL09wZW5Db25uZWN0aW9uUmVwbHkyJztcbmltcG9ydCBPcGVuQ29ubmVjdGlvblJlcXVlc3QyIGZyb20gJy4vY29ubmVjdGlvbi9PcGVuQ29ubmVjdGlvblJlcXVlc3QyJztcbmltcG9ydCBVbmNvbm5lY3RlZFBpbmcgZnJvbSAnLi9vZmZsaW5lL1VuY29ubmVjdGVkUGluZyc7XG5pbXBvcnQgVW5jb25uZWN0ZWRQb25nIGZyb20gJy4vb2ZmbGluZS9VbmNvbm5lY3RlZFBvbmcnO1xuXG5leHBvcnQgY2xhc3MgT2ZmbGluZUhhbmRsZXIge1xuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGxpc3RlbmVyOiBTZXJ2ZXJTb2NrZXQpIHt9XG5cbiAgICBwdWJsaWMgcHJvY2Vzcyhtc2c6IEJ1ZmZlciwgcmluZm86IFJlbW90ZUluZm8pOiB2b2lkIHtcbiAgICAgICAgc3dpdGNoIChtc2dbMF0pIHtcbiAgICAgICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9va2FyY2hpdmUvUmFrTmV0L2Jsb2IvbWFzdGVyL1NvdXJjZS9SYWtQZWVyLmNwcCNMNDYzOFxuICAgICAgICAgICAgY2FzZSBNZXNzYWdlSWRlbnRpZmllcnMuVU5DT05ORUNURURfUElOR19PUEVOX0NPTk5FQ1RJT05TOlxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5saXN0ZW5lci5hbGxvd0luY29taW5nQ29ubmVjdGlvbnMoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBNZXNzYWdlSWRlbnRpZmllcnMuVU5DT05ORUNURURfUElORzpcbiAgICAgICAgICAgICAgICBjb25zdCBwaW5nID0gbmV3IFVuY29ubmVjdGVkUGluZyhtc2cpO1xuICAgICAgICAgICAgICAgIHBpbmcuZGVjb2RlKCk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBwb25nID0gbmV3IFVuY29ubmVjdGVkUG9uZygpO1xuICAgICAgICAgICAgICAgIHBvbmcudGltZXN0YW1wID0gcGluZy50aW1lc3RhbXA7XG4gICAgICAgICAgICAgICAgcG9uZy5zZXJ2ZXJHdWlkID0gdGhpcy5saXN0ZW5lci5nZXRTZXJ2ZXJHdWlkKCk7XG4gICAgICAgICAgICAgICAgcG9uZy5zZXJ2ZXJOYW1lID0gdGhpcy5saXN0ZW5lci5zZXJ2ZXJOYW1lLnRvU3RyaW5nKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5zZW5kUGFja2V0KHBvbmcsIHJpbmZvKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9va2FyY2hpdmUvUmFrTmV0L2Jsb2IvbWFzdGVyL1NvdXJjZS9SYWtQZWVyLmNwcCNMNTEyN1xuICAgICAgICAgICAgY2FzZSBNZXNzYWdlSWRlbnRpZmllcnMuT1BFTl9DT05ORUNUSU9OX1JFUVVFU1RfMTpcbiAgICAgICAgICAgICAgICAvLyBEb24ndCB3YXN0ZSByZXNvdXJjZXMgYnkgYWxsb2NhdGluZyBhIHBhY2tldCBpZiB3ZSBrbm93IHZlcnNpb24gbWlzbWF0Y2hlc1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlbW90ZVByb3RvY29sID0gbXNnWzEgKyBPRkZMSU5FX01FU1NBR0VfREFUQV9JRC5ieXRlTGVuZ3RoXTtcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiBzZXR0ZXIgZm9yIGN1c3RvbSBwcm90b2NvbCB2ZXJzaW9uXG4gICAgICAgICAgICAgICAgaWYgKHJlbW90ZVByb3RvY29sICE9PSBNSU5FQ1JBRlRfUFJPVE9DT0xfVkVSU0lPTikge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IG5ldyBJbmNvbXBhdGlibGVQcm90b2NvbFZlcnNpb24oKTtcbiAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UucHJvdG9jb2wgPSBNSU5FQ1JBRlRfUFJPVE9DT0xfVkVSU0lPTjtcbiAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2Uuc2VydmVyR1VJRCA9IHRoaXMubGlzdGVuZXIuZ2V0U2VydmVyR3VpZCgpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLnNlbmRQYWNrZXQocmVzcG9uc2UsIHJpbmZvKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNvbnN0IHJlcGx5MSA9IG5ldyBPcGVuQ29ubmVjdGlvblJlcGx5MSgpO1xuICAgICAgICAgICAgICAgIHJlcGx5MS5zZXJ2ZXJHVUlEID0gdGhpcy5saXN0ZW5lci5nZXRTZXJ2ZXJHdWlkKCk7XG5cbiAgICAgICAgICAgICAgICBpZiAobXNnLmJ5dGVMZW5ndGggKyBVRFBfSEVBREVSX1NJWkUgPiBNQVhfTVRVX1NJWkUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVwbHkxLm10dVNpemUgPSBNQVhfTVRVX1NJWkU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmVwbHkxLm10dVNpemUgPSBtc2cuYnl0ZUxlbmd0aCArIFVEUF9IRUFERVJfU0laRTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLnNlbmRQYWNrZXQocmVwbHkxLCByaW5mbyk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vZmFjZWJvb2thcmNoaXZlL1Jha05ldC9ibG9iL21hc3Rlci9Tb3VyY2UvUmFrUGVlci5jcHAjTDUxOThcbiAgICAgICAgICAgIGNhc2UgTWVzc2FnZUlkZW50aWZpZXJzLk9QRU5fQ09OTkVDVElPTl9SRVFVRVNUXzI6XG4gICAgICAgICAgICAgICAgY29uc3QgcmVxdWVzdCA9IG5ldyBPcGVuQ29ubmVjdGlvblJlcXVlc3QyKG1zZyk7XG4gICAgICAgICAgICAgICAgcmVxdWVzdC5kZWNvZGUoKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IGFkZHJTZXNzaW9uID0gdGhpcy5saXN0ZW5lci5nZXRTZXNzaW9uQnlBZGRyZXNzKHJpbmZvKTtcbiAgICAgICAgICAgICAgICBjb25zdCBhZGRyZXNzSW5Vc2UgPSBhZGRyU2Vzc2lvbiAhPT0gbnVsbCAmJiAhYWRkclNlc3Npb24uaXNEaXNjb25uZWN0ZWQoKTsgLy8gaXNBY3RpdmUnaXNoXG4gICAgICAgICAgICAgICAgY29uc3QgZ3VpZFNlc3Npb24gPSB0aGlzLmxpc3RlbmVyLmdldFNlc3Npb25CeUdVSUQocmVxdWVzdC5jbGllbnRHVUlEKTtcbiAgICAgICAgICAgICAgICBjb25zdCBndWlkSW5Vc2UgPSBndWlkU2Vzc2lvbiAhPT0gbnVsbCAmJiAhZ3VpZFNlc3Npb24uaXNEaXNjb25uZWN0ZWQoKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHJlcGx5MiA9IG5ldyBPcGVuQ29ubmVjdGlvblJlcGx5MigpO1xuICAgICAgICAgICAgICAgIHJlcGx5Mi5zZXJ2ZXJHdWlkID0gdGhpcy5saXN0ZW5lci5nZXRTZXJ2ZXJHdWlkKCk7XG4gICAgICAgICAgICAgICAgcmVwbHkyLmNsaWVudEFkZHJlc3MgPSBuZXcgSW5ldEFkZHJlc3MocmluZm8uYWRkcmVzcywgcmluZm8ucG9ydCwgNCk7XG4gICAgICAgICAgICAgICAgcmVwbHkyLm10dVNpemUgPSByZXF1ZXN0Lm10dVNpemU7XG5cbiAgICAgICAgICAgICAgICBpZiAoYWRkcmVzc0luVXNlICYmIGd1aWRJblVzZSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoYWRkclNlc3Npb24gPT09IGd1aWRTZXNzaW9uKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLnNlbmRQYWNrZXQocmVwbHkyLCByaW5mbyk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZW5kQWxyZWFkeUNvbm5lY3RlZChyaW5mbyk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoKCFhZGRyZXNzSW5Vc2UgJiYgZ3VpZEluVXNlKSB8fCAoYWRkclNlc3Npb24gJiYgIWd1aWRJblVzZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZW5kQWxyZWFkeUNvbm5lY3RlZChyaW5mbyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmxpc3RlbmVyLmFsbG93SW5jb21pbmdDb25uZWN0aW9ucygpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHN0ciA9IG5ldyBCaW5hcnlTdHJlYW0oKTtcbiAgICAgICAgICAgICAgICAgICAgc3RyLndyaXRlQnl0ZShNZXNzYWdlSWRlbnRpZmllcnMuTk9fRlJFRV9JTkNPTUlOR19DT05ORUNUSU9OUyk7XG4gICAgICAgICAgICAgICAgICAgIHN0ci53cml0ZShPRkZMSU5FX01FU1NBR0VfREFUQV9JRCk7XG4gICAgICAgICAgICAgICAgICAgIHN0ci53cml0ZUxvbmcodGhpcy5saXN0ZW5lci5nZXRTZXJ2ZXJHdWlkKCkpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLnNlbmRCdWZmZXIoc3RyLmdldEJ1ZmZlcigpLCByaW5mbyk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLmFkZFNlc3Npb24ocmluZm8sIHJlcXVlc3QubXR1U2l6ZSwgcmVxdWVzdC5jbGllbnRHVUlEKTtcblxuICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuc2VuZFBhY2tldChyZXBseTIsIHJpbmZvKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgTWVzc2FnZUlkZW50aWZpZXJzLlFVRVJZOlxuICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuZW1pdCgncmF3JywgbXNnLCBuZXcgSW5ldEFkZHJlc3MocmluZm8uYWRkcmVzcywgcmluZm8ucG9ydCkpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gdW5jb25uZWN0ZWQgcGFja2V0IHdpdGggSUQ9JHttc2dbMF0hLnRvU3RyaW5nKDE2KX1gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgc2VuZEFscmVhZHlDb25uZWN0ZWQocmVtb3RlOiBSZW1vdGVJbmZvKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHN0ciA9IG5ldyBCaW5hcnlTdHJlYW0oKTtcbiAgICAgICAgc3RyLndyaXRlQnl0ZShNZXNzYWdlSWRlbnRpZmllcnMuQUxSRUFEWV9DT05ORUNURUQpO1xuICAgICAgICBzdHIud3JpdGUoT0ZGTElORV9NRVNTQUdFX0RBVEFfSUQpO1xuICAgICAgICBzdHIud3JpdGVMb25nKHRoaXMubGlzdGVuZXIuZ2V0U2VydmVyR3VpZCgpKTtcbiAgICAgICAgdGhpcy5saXN0ZW5lci5zZW5kQnVmZmVyKHN0ci5nZXRCdWZmZXIoKSwgcmVtb3RlKTtcbiAgICB9XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7O0FBYU8sTUFBTSxjQUFlLENBQUE7QUFBQSxFQUNqQixZQUE2QixRQUF3QixFQUFBO0FBQXhCLElBQUEsSUFBQSxDQUFBLFFBQUEsR0FBQSxRQUFBO0FBQUE7QUFBeUIsRUFFdEQsT0FBQSxDQUFRLEtBQWEsS0FBeUIsRUFBQTtBQUNqRCxJQUFRLFFBQUEsR0FBQSxDQUFJLENBQUMsQ0FBRztBQUFBO0FBQUEsTUFFWixLQUFLLGtCQUFtQixDQUFBLGlDQUFBO0FBQ3BCLFFBQUEsSUFBSSxDQUFDLElBQUEsQ0FBSyxRQUFTLENBQUEsd0JBQUEsRUFBNEIsRUFBQTtBQUMzQyxVQUFBO0FBQUE7QUFDSixNQUNKLEtBQUssa0JBQW1CLENBQUEsZ0JBQUE7QUFDcEIsUUFBTSxNQUFBLElBQUEsR0FBTyxJQUFJLGVBQUEsQ0FBZ0IsR0FBRyxDQUFBO0FBQ3BDLFFBQUEsSUFBQSxDQUFLLE1BQU8sRUFBQTtBQUVaLFFBQU0sTUFBQSxJQUFBLEdBQU8sSUFBSSxlQUFnQixFQUFBO0FBQ2pDLFFBQUEsSUFBQSxDQUFLLFlBQVksSUFBSyxDQUFBLFNBQUE7QUFDdEIsUUFBSyxJQUFBLENBQUEsVUFBQSxHQUFhLElBQUssQ0FBQSxRQUFBLENBQVMsYUFBYyxFQUFBO0FBQzlDLFFBQUEsSUFBQSxDQUFL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