@jsprismarine/raknet
Version:
Basic RakNet implementation written in TypeScript
115 lines (108 loc) • 18.2 kB
JavaScript
'use strict';
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const BinaryStream = require('@jsprismarine/jsbinaryutils');
const utils_InetAddress = require('../utils/InetAddress.cjs.cjs');
const protocol_MessageIdentifiers = require('./MessageIdentifiers.cjs.cjs');
require('assert');
const protocol_connection_IncompatibleProtocolVersion = require('./connection/IncompatibleProtocolVersion.cjs.cjs');
const protocol_connection_OpenConnectionReply1 = require('./connection/OpenConnectionReply1.cjs.cjs');
const protocol_connection_OpenConnectionReply2 = require('./connection/OpenConnectionReply2.cjs.cjs');
const protocol_connection_OpenConnectionRequest2 = require('./connection/OpenConnectionRequest2.cjs.cjs');
const protocol_offline_UnconnectedPing = require('./offline/UnconnectedPing.cjs.cjs');
const protocol_offline_UnconnectedPong = require('./offline/UnconnectedPong.cjs.cjs');
require('node:assert');
const Constants = require('../Constants.cjs.cjs');
require('events');
require('node:dgram');
const _interopDefault = e => e && e.__esModule ? e : { default: e };
const BinaryStream__default = /*#__PURE__*/_interopDefault(BinaryStream);
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 protocol_MessageIdentifiers.MessageIdentifiers.UNCONNECTED_PING_OPEN_CONNECTIONS:
if (!this.listener.allowIncomingConnections()) {
return;
}
case protocol_MessageIdentifiers.MessageIdentifiers.UNCONNECTED_PING:
const ping = new protocol_offline_UnconnectedPing.default(msg);
ping.decode();
const pong = new protocol_offline_UnconnectedPong.default();
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 protocol_MessageIdentifiers.MessageIdentifiers.OPEN_CONNECTION_REQUEST_1:
const remoteProtocol = msg[1 + Constants.OFFLINE_MESSAGE_DATA_ID.byteLength];
if (remoteProtocol !== Constants.MINECRAFT_PROTOCOL_VERSION) {
const response = new protocol_connection_IncompatibleProtocolVersion.default();
response.protocol = Constants.MINECRAFT_PROTOCOL_VERSION;
response.serverGUID = this.listener.getServerGuid();
this.listener.sendPacket(response, rinfo);
return;
}
const reply1 = new protocol_connection_OpenConnectionReply1.default();
reply1.serverGUID = this.listener.getServerGuid();
if (msg.byteLength + Constants.UDP_HEADER_SIZE > Constants.MAX_MTU_SIZE) {
reply1.mtuSize = Constants.MAX_MTU_SIZE;
} else {
reply1.mtuSize = msg.byteLength + Constants.UDP_HEADER_SIZE;
}
this.listener.sendPacket(reply1, rinfo);
break;
// https://github.com/facebookarchive/RakNet/blob/master/Source/RakPeer.cpp#L5198
case protocol_MessageIdentifiers.MessageIdentifiers.OPEN_CONNECTION_REQUEST_2:
const request = new protocol_connection_OpenConnectionRequest2.default(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 protocol_connection_OpenConnectionReply2.default();
reply2.serverGuid = this.listener.getServerGuid();
reply2.clientAddress = new utils_InetAddress.default(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__default.default();
str.writeByte(protocol_MessageIdentifiers.MessageIdentifiers.NO_FREE_INCOMING_CONNECTIONS);
str.write(Constants.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 protocol_MessageIdentifiers.MessageIdentifiers.QUERY:
this.listener.emit("raw", msg, new utils_InetAddress.default(rinfo.address, rinfo.port));
break;
default:
throw new Error(`Unknown unconnected packet with ID=${msg[0].toString(16)}`);
}
}
sendAlreadyConnected(remote) {
const str = new BinaryStream__default.default();
str.writeByte(protocol_MessageIdentifiers.MessageIdentifiers.ALREADY_CONNECTED);
str.write(Constants.OFFLINE_MESSAGE_DATA_ID);
str.writeLong(this.listener.getServerGuid());
this.listener.sendBuffer(str.getBuffer(), remote);
}
}
exports.OfflineHandler = OfflineHandler;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT2ZmbGluZUhhbmRsZXIuY2pzLmNqcyIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Byb3RvY29sL09mZmxpbmVIYW5kbGVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluZXRBZGRyZXNzLCBNQVhfTVRVX1NJWkUsIE1JTkVDUkFGVF9QUk9UT0NPTF9WRVJTSU9OLCBPRkZMSU5FX01FU1NBR0VfREFUQV9JRCwgVURQX0hFQURFUl9TSVpFIH0gZnJvbSAnLi4vJztcblxuaW1wb3J0IEJpbmFyeVN0cmVhbSBmcm9tICdAanNwcmlzbWFyaW5lL2pzYmluYXJ5dXRpbHMnO1xuaW1wb3J0IHR5cGUgeyBSZW1vdGVJbmZvIH0gZnJvbSAnbm9kZTpkZ3JhbSc7XG5pbXBvcnQgdHlwZSBTZXJ2ZXJTb2NrZXQgZnJvbSAnLi4vU2VydmVyU29ja2V0JztcbmltcG9ydCB7IE1lc3NhZ2VJZGVudGlmaWVycyB9IGZyb20gJy4vTWVzc2FnZUlkZW50aWZpZXJzJztcbmltcG9ydCBJbmNvbXBhdGlibGVQcm90b2NvbFZlcnNpb24gZnJvbSAnLi9jb25uZWN0aW9uL0luY29tcGF0aWJsZVByb3RvY29sVmVyc2lvbic7XG5pbXBvcnQgT3BlbkNvbm5lY3Rpb25SZXBseTEgZnJvbSAnLi9jb25uZWN0aW9uL09wZW5Db25uZWN0aW9uUmVwbHkxJztcbmltcG9ydCBPcGVuQ29ubmVjdGlvblJlcGx5MiBmcm9tICcuL2Nvbm5lY3Rpb24vT3BlbkNvbm5lY3Rpb25SZXBseTInO1xuaW1wb3J0IE9wZW5Db25uZWN0aW9uUmVxdWVzdDIgZnJvbSAnLi9jb25uZWN0aW9uL09wZW5Db25uZWN0aW9uUmVxdWVzdDInO1xuaW1wb3J0IFVuY29ubmVjdGVkUGluZyBmcm9tICcuL29mZmxpbmUvVW5jb25uZWN0ZWRQaW5nJztcbmltcG9ydCBVbmNvbm5lY3RlZFBvbmcgZnJvbSAnLi9vZmZsaW5lL1VuY29ubmVjdGVkUG9uZyc7XG5cbmV4cG9ydCBjbGFzcyBPZmZsaW5lSGFuZGxlciB7XG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgbGlzdGVuZXI6IFNlcnZlclNvY2tldCkge31cblxuICAgIHB1YmxpYyBwcm9jZXNzKG1zZzogQnVmZmVyLCByaW5mbzogUmVtb3RlSW5mbyk6IHZvaWQge1xuICAgICAgICBzd2l0Y2ggKG1zZ1swXSkge1xuICAgICAgICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2ZhY2Vib29rYXJjaGl2ZS9SYWtOZXQvYmxvYi9tYXN0ZXIvU291cmNlL1Jha1BlZXIuY3BwI0w0NjM4XG4gICAgICAgICAgICBjYXNlIE1lc3NhZ2VJZGVudGlmaWVycy5VTkNPTk5FQ1RFRF9QSU5HX09QRU5fQ09OTkVDVElPTlM6XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmxpc3RlbmVyLmFsbG93SW5jb21pbmdDb25uZWN0aW9ucygpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIE1lc3NhZ2VJZGVudGlmaWVycy5VTkNPTk5FQ1RFRF9QSU5HOlxuICAgICAgICAgICAgICAgIGNvbnN0IHBpbmcgPSBuZXcgVW5jb25uZWN0ZWRQaW5nKG1zZyk7XG4gICAgICAgICAgICAgICAgcGluZy5kZWNvZGUoKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHBvbmcgPSBuZXcgVW5jb25uZWN0ZWRQb25nKCk7XG4gICAgICAgICAgICAgICAgcG9uZy50aW1lc3RhbXAgPSBwaW5nLnRpbWVzdGFtcDtcbiAgICAgICAgICAgICAgICBwb25nLnNlcnZlckd1aWQgPSB0aGlzLmxpc3RlbmVyLmdldFNlcnZlckd1aWQoKTtcbiAgICAgICAgICAgICAgICBwb25nLnNlcnZlck5hbWUgPSB0aGlzLmxpc3RlbmVyLnNlcnZlck5hbWUudG9TdHJpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLnNlbmRQYWNrZXQocG9uZywgcmluZm8pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2ZhY2Vib29rYXJjaGl2ZS9SYWtOZXQvYmxvYi9tYXN0ZXIvU291cmNlL1Jha1BlZXIuY3BwI0w1MTI3XG4gICAgICAgICAgICBjYXNlIE1lc3NhZ2VJZGVudGlmaWVycy5PUEVOX0NPTk5FQ1RJT05fUkVRVUVTVF8xOlxuICAgICAgICAgICAgICAgIC8vIERvbid0IHdhc3RlIHJlc291cmNlcyBieSBhbGxvY2F0aW5nIGEgcGFja2V0IGlmIHdlIGtub3cgdmVyc2lvbiBtaXNtYXRjaGVzXG4gICAgICAgICAgICAgICAgY29uc3QgcmVtb3RlUHJvdG9jb2wgPSBtc2dbMSArIE9GRkxJTkVfTUVTU0FHRV9EQVRBX0lELmJ5dGVMZW5ndGhdO1xuICAgICAgICAgICAgICAgIC8vIFRPRE86IHNldHRlciBmb3IgY3VzdG9tIHByb3RvY29sIHZlcnNpb25cbiAgICAgICAgICAgICAgICBpZiAocmVtb3RlUHJvdG9jb2wgIT09IE1JTkVDUkFGVF9QUk9UT0NPTF9WRVJTSU9OKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlc3BvbnNlID0gbmV3IEluY29tcGF0aWJsZVByb3RvY29sVmVyc2lvbigpO1xuICAgICAgICAgICAgICAgICAgICByZXNwb25zZS5wcm90b2NvbCA9IE1JTkVDUkFGVF9QUk9UT0NPTF9WRVJTSU9OO1xuICAgICAgICAgICAgICAgICAgICByZXNwb25zZS5zZXJ2ZXJHVUlEID0gdGhpcy5saXN0ZW5lci5nZXRTZXJ2ZXJHdWlkKCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuc2VuZFBhY2tldChyZXNwb25zZSwgcmluZm8pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29uc3QgcmVwbHkxID0gbmV3IE9wZW5Db25uZWN0aW9uUmVwbHkxKCk7XG4gICAgICAgICAgICAgICAgcmVwbHkxLnNlcnZlckdVSUQgPSB0aGlzLmxpc3RlbmVyLmdldFNlcnZlckd1aWQoKTtcblxuICAgICAgICAgICAgICAgIGlmIChtc2cuYnl0ZUxlbmd0aCArIFVEUF9IRUFERVJfU0laRSA+IE1BWF9NVFVfU0laRSkge1xuICAgICAgICAgICAgICAgICAgICByZXBseTEubXR1U2l6ZSA9IE1BWF9NVFVfU0laRTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXBseTEubXR1U2l6ZSA9IG1zZy5ieXRlTGVuZ3RoICsgVURQX0hFQURFUl9TSVpFO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuc2VuZFBhY2tldChyZXBseTEsIHJpbmZvKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9va2FyY2hpdmUvUmFrTmV0L2Jsb2IvbWFzdGVyL1NvdXJjZS9SYWtQZWVyLmNwcCNMNTE5OFxuICAgICAgICAgICAgY2FzZSBNZXNzYWdlSWRlbnRpZmllcnMuT1BFTl9DT05ORUNUSU9OX1JFUVVFU1RfMjpcbiAgICAgICAgICAgICAgICBjb25zdCByZXF1ZXN0ID0gbmV3IE9wZW5Db25uZWN0aW9uUmVxdWVzdDIobXNnKTtcbiAgICAgICAgICAgICAgICByZXF1ZXN0LmRlY29kZSgpO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgYWRkclNlc3Npb24gPSB0aGlzLmxpc3RlbmVyLmdldFNlc3Npb25CeUFkZHJlc3MocmluZm8pO1xuICAgICAgICAgICAgICAgIGNvbnN0IGFkZHJlc3NJblVzZSA9IGFkZHJTZXNzaW9uICE9PSBudWxsICYmICFhZGRyU2Vzc2lvbi5pc0Rpc2Nvbm5lY3RlZCgpOyAvLyBpc0FjdGl2ZSdpc2hcbiAgICAgICAgICAgICAgICBjb25zdCBndWlkU2Vzc2lvbiA9IHRoaXMubGlzdGVuZXIuZ2V0U2Vzc2lvbkJ5R1VJRChyZXF1ZXN0LmNsaWVudEdVSUQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGd1aWRJblVzZSA9IGd1aWRTZXNzaW9uICE9PSBudWxsICYmICFndWlkU2Vzc2lvbi5pc0Rpc2Nvbm5lY3RlZCgpO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgcmVwbHkyID0gbmV3IE9wZW5Db25uZWN0aW9uUmVwbHkyKCk7XG4gICAgICAgICAgICAgICAgcmVwbHkyLnNlcnZlckd1aWQgPSB0aGlzLmxpc3RlbmVyLmdldFNlcnZlckd1aWQoKTtcbiAgICAgICAgICAgICAgICByZXBseTIuY2xpZW50QWRkcmVzcyA9IG5ldyBJbmV0QWRkcmVzcyhyaW5mby5hZGRyZXNzLCByaW5mby5wb3J0LCA0KTtcbiAgICAgICAgICAgICAgICByZXBseTIubXR1U2l6ZSA9IHJlcXVlc3QubXR1U2l6ZTtcblxuICAgICAgICAgICAgICAgIGlmIChhZGRyZXNzSW5Vc2UgJiYgZ3VpZEluVXNlKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChhZGRyU2Vzc2lvbiA9PT0gZ3VpZFNlc3Npb24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuc2VuZFBhY2tldChyZXBseTIsIHJpbmZvKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNlbmRBbHJlYWR5Q29ubmVjdGVkKHJpbmZvKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICgoIWFkZHJlc3NJblVzZSAmJiBndWlkSW5Vc2UpIHx8IChhZGRyU2Vzc2lvbiAmJiAhZ3VpZEluVXNlKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNlbmRBbHJlYWR5Q29ubmVjdGVkKHJpbmZvKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMubGlzdGVuZXIuYWxsb3dJbmNvbWluZ0Nvbm5lY3Rpb25zKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3RyID0gbmV3IEJpbmFyeVN0cmVhbSgpO1xuICAgICAgICAgICAgICAgICAgICBzdHIud3JpdGVCeXRlKE1lc3NhZ2VJZGVudGlmaWVycy5OT19GUkVFX0lOQ09NSU5HX0NPTk5FQ1RJT05TKTtcbiAgICAgICAgICAgICAgICAgICAgc3RyLndyaXRlKE9GRkxJTkVfTUVTU0FHRV9EQVRBX0lEKTtcbiAgICAgICAgICAgICAgICAgICAgc3RyLndyaXRlTG9uZyh0aGlzLmxpc3RlbmVyLmdldFNlcnZlckd1aWQoKSk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuc2VuZEJ1ZmZlcihzdHIuZ2V0QnVmZmVyKCksIHJpbmZvKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuYWRkU2Vzc2lvbihyaW5mbywgcmVxdWVzdC5tdHVTaXplLCByZXF1ZXN0LmNsaWVudEdVSUQpO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5zZW5kUGFja2V0KHJlcGx5MiwgcmluZm8pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBNZXNzYWdlSWRlbnRpZmllcnMuUVVFUlk6XG4gICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5lbWl0KCdyYXcnLCBtc2csIG5ldyBJbmV0QWRkcmVzcyhyaW5mby5hZGRyZXNzLCByaW5mby5wb3J0KSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biB1bmNvbm5lY3RlZCBwYWNrZXQgd2l0aCBJRD0ke21zZ1swXSEudG9TdHJpbmcoMTYpfWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzZW5kQWxyZWFkeUNvbm5lY3RlZChyZW1vdGU6IFJlbW90ZUluZm8pOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgc3RyID0gbmV3IEJpbmFyeVN0cmVhbSgpO1xuICAgICAgICBzdHIud3JpdGVCeXRlKE1lc3NhZ2VJZGVudGlmaWVycy5BTFJFQURZX0NPTk5FQ1RFRCk7XG4gICAgICAgIHN0ci53cml0ZShPRkZMSU5FX01FU1NBR0VfREFUQV9JRCk7XG4gICAgICAgIHN0ci53cml0ZUxvbmcodGhpcy5saXN0ZW5lci5nZXRTZXJ2ZXJHdWlkKCkpO1xuICAgICAgICB0aGlzLmxpc3RlbmVyLnNlbmRCdWZmZXIoc3RyLmdldEJ1ZmZlcigpLCByZW1vdGUpO1xuICAgIH1cbn1cbiJdLCJuYW1lcyI6WyJNZXNzYWdlSWRlbnRpZmllcnMiLCJVbmNvbm5lY3RlZFBpbmciLCJVbmNvbm5lY3RlZFBvbmciLCJPRkZMSU5FX01FU1NBR0VfREFUQV9JRCIsIk1JTkVDUkFGVF9QUk9UT0NPTF9WRVJTSU9OIiwiSW5jb21wYXRpYmxlUHJvdG9jb2xWZXJzaW9uIiwiT3BlbkNvbm5lY3Rpb25SZXBseTEiLCJVRFBfSEVBREVSX1NJWkUiLCJNQVhfTVRVX1NJWkUiLCJPcGVuQ29ubmVjdGlvblJlcXVlc3QyIiwiT3BlbkNvbm5lY3Rpb25SZXBseTIiLCJJbmV0QWRkcmVzcyIsIkJpbmFyeVN0cmVhbSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFhTyxNQUFNLGNBQWUsQ0FBQTtBQUFBLEVBQ2pCLFlBQTZCLFFBQXdCLEVBQUE7QUFBeEIsSUFBQSxJQUFBLENBQUEsUUFBQSxHQUFBLFFBQUE7QUFBQTtBQUF5QixFQUV0RCxPQUFBLENBQVEsS0FBYSxLQUF5QixFQUFBO0FBQ2pELElBQVEsUUFBQSxHQUFBLENBQUksQ0FBQyxDQUFHO0FBQUE7QUFBQSxNQUVaLEtBQUtBLDhDQUFtQixDQUFBLGlDQUFBO0FBQ3BCLFFBQUEsSUFBSSxDQUFDLElBQUEsQ0FBSyxRQUFTLENBQUEsd0JBQUEsRUFBNEIsRUFBQTtBQUMzQyxVQUFB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