diff --git a/discovery.ts b/discovery.ts index 2ec5a70..30018e3 100644 --- a/discovery.ts +++ b/discovery.ts @@ -5,11 +5,23 @@ import { Commands } from "./datatypes.js"; import { create_LanSearch, parse_PunchPkt } from "./impl.js"; import { logger } from "./logger.js"; import { config } from "./settings.js"; +import { decode, encode } from "./encode"; + +const maybeDecode = (dv: DataView): DataView => { + if (dv.readU8() === 0xf1) { + return dv; + } + return decode(dv); +} const handleIncomingPunch = (msg: Buffer, ee: EventEmitter, rinfo: RemoteInfo) => { const ab = new Uint8Array(msg).buffer; - const dv = new DataView(ab); + const receivedPkt = new DataView(ab); + const isEncoded = receivedPkt.readU8() !== 0xf1 + let dv = maybeDecode(receivedPkt); + const cmd_id = dv.readU16(); + logger.log("trace", `<- received: cmd_id: ${cmd_id} ${JSON.stringify(msg)}`); if (cmd_id != Commands.PunchPkt) { return; } @@ -18,9 +30,13 @@ const handleIncomingPunch = (msg: Buffer, ee: EventEmitter, rinfo: RemoteInfo) = return; } logger.debug("Received a PunchPkt message"); - ee.emit("discover", rinfo, parse_PunchPkt(dv)); + ee.emit("discover", rinfo, parse_PunchPkt(dv, isEncoded)); }; +const getLanSearchVariants = (buf: DataView): DataView[] => { + return [buf, encode(buf)]; +} + export const discoverDevices = (discovery_ips: string[]): EventEmitter => { const sock = createSocket("udp4"); const SEND_PORT = 32108; @@ -36,17 +52,20 @@ export const discoverDevices = (discovery_ips: string[]): EventEmitter => { let timers = []; sock.on("listening", () => { let ls_buf = create_LanSearch(); + const variants = getLanSearchVariants(ls_buf); sock.setBroadcast(true); discovery_ips.forEach((discovery_ip) => { logger.info(`Searching for devices on ${discovery_ip}`); - - let int = setInterval(() => { + const searchFn = () => { logger.log("trace", `>> LanSearch [${discovery_ip}]`); - sock.send(new Uint8Array(ls_buf.buffer), SEND_PORT, discovery_ip); - }, 3000); + variants.forEach((buf) => { + sock.send(new Uint8Array(buf.buffer), SEND_PORT, discovery_ip); + }) + }; + + let int = setInterval(searchFn, 3000); timers.push(int); - logger.log("trace", `>> LanSearch [${discovery_ip}]`); - sock.send(new Uint8Array(ls_buf.buffer), SEND_PORT, discovery_ip); + searchFn(); }); }); diff --git a/handlers.ts b/handlers.ts index 860c13e..13d914e 100644 --- a/handlers.ts +++ b/handlers.ts @@ -30,7 +30,7 @@ export const handle_P2PRdy = (session: Session, _: DataView) => { session.send(b); }; -export const makeP2pRdy = (dev: DevSerial): DataView => { +export const makeP2pRdy = (dev: DevSerial, makefn: Function = create_P2pRdy): DataView => { const outbuf = new DataView(new Uint8Array(0x14).buffer); // 8 = serial u64 // The protocol seems to expect 4 bytes -- check the regression test // `replies properly to PunchPkt with 3-letters-long prefix` for a case with a @@ -39,7 +39,7 @@ export const makeP2pRdy = (dev: DevSerial): DataView => { outbuf.add(0).writeString(dev.prefix); outbuf.add(4).writeU64(dev.serialU64); outbuf.add(8 + devPrefixLength).writeString(dev.suffix); - return create_P2pRdy(outbuf); + return makefn(outbuf); }; export const swVerToString = (swver: number): string => { diff --git a/impl.ts b/impl.ts index e5f12ab..0be1415 100644 --- a/impl.ts +++ b/impl.ts @@ -178,15 +178,23 @@ export const create_LanSearch = (): DataView => { return outbuf; }; -export const create_P2pRdy = (inbuf: DataView): DataView => { +const create_P2pRdy_Like = (command: number, inbuf: DataView): DataView => { const P2PRDY_SIZE = 0x14; const outbuf = new DataView(new Uint8Array(P2PRDY_SIZE + 4).buffer); - outbuf.writeU16(Commands.P2pRdy); + outbuf.writeU16(command); outbuf.add(2).writeU16(P2PRDY_SIZE); outbuf.add(4).writeByteArray(new Uint8Array(inbuf.readByteArray(P2PRDY_SIZE).buffer)); return outbuf; }; +export const create_P2pRdy = (inbuf: DataView): DataView => { + return create_P2pRdy_Like(Commands.P2pRdy, inbuf) +}; + +export const create_PunchPkt = (inbuf: DataView): DataView => { + return create_P2pRdy_Like(Commands.PunchPkt, inbuf) +}; + export const create_P2pAlive = (): DataView => { const outbuf = new DataView(new Uint8Array(4).buffer); outbuf.writeU16(Commands.P2PAlive); @@ -201,8 +209,8 @@ export const create_P2pClose = (): DataView => { return outbuf; }; -export type DevSerial = { prefix: string; serial: string; suffix: string; serialU64: bigint; devId: string }; -export const parse_PunchPkt = (dv: DataView): DevSerial => { +export type DevSerial = { prefix: string; serial: string; suffix: string; serialU64: bigint; devId: string, encoded: boolean }; +export const parse_PunchPkt = (dv: DataView, encoded: boolean): DevSerial => { const punchCmd = dv.readU16(); const len = dv.add(2).readU16(); const prefix = dv.add(4).readString(4); @@ -211,5 +219,5 @@ export const parse_PunchPkt = (dv: DataView): DevSerial => { const suffix = dv.add(16).readString(len - 16 + 4); // 16 = offset, +4 header const devId = prefix + serial + suffix; - return { prefix, serial, suffix, serialU64, devId }; + return { prefix, serial, suffix, serialU64, devId, encoded }; }; diff --git a/session.ts b/session.ts index 8c8c946..512e514 100644 --- a/session.ts +++ b/session.ts @@ -13,7 +13,14 @@ import { notImpl, noop, } from "./handlers.js"; -import { create_P2pAlive, DevSerial, SendStartVideo, SendVideoResolution, SendWifiDetails } from "./impl.js"; +import { + create_P2pAlive, + create_PunchPkt, + DevSerial, + SendStartVideo, + SendVideoResolution, + SendWifiDetails +} from "./impl.js"; import { logger } from "./logger.js"; export type Session = { @@ -85,8 +92,10 @@ export const makeSession = ( sock.on("message", (msg, rinfo) => handleIncoming(session, handlers, msg, rinfo)); sock.on("listening", () => { - const buf = makeP2pRdy(dev); - session.send(buf); + session.send(makeP2pRdy(dev)); + if (dev.encoded) { + session.send(makeP2pRdy(dev, create_PunchPkt)); + } session.started = true; }); @@ -153,7 +162,7 @@ export const makeSession = ( rcvSeqId: 0, frame_is_bad: false, frame_was_fixed: false, - encoded: false, + encoded: dev.encoded, unackedDrw, close: () => { session.eventEmitter.emit("disconnect"); diff --git a/tests/fn.test.js b/tests/fn.test.js index 5e9f374..30ee708 100644 --- a/tests/fn.test.js +++ b/tests/fn.test.js @@ -136,9 +136,10 @@ describe("parse packet", () => { suffix: "WONJM", serialU64: BigInt(156362), devId: "BATD156362WONJM", + encoded: false, }; - assert.deepEqual(parse_PunchPkt(pkt), expected); + assert.deepEqual(parse_PunchPkt(pkt, false), expected); }); { const in_pkt_str = "f14100145848410000000000000003e24b4d4d4542000000"; @@ -150,12 +151,13 @@ describe("parse packet", () => { suffix: "KMMEB", serialU64: BigInt(994), devId: "XHA994KMMEB", + encoded: false, }; - assert.deepEqual(parse_PunchPkt(pkt), expected); + assert.deepEqual(parse_PunchPkt(pkt, false), expected); }); // https://github.com/DavidVentura/cam-reverse/issues/17#issuecomment-2094819873 it("replies properly to PunchPkt with 3-letters-long prefix", () => { - const dev = parse_PunchPkt(pkt); + const dev = parse_PunchPkt(pkt, false); const p2prdy = makeP2pRdy(dev); let p2pstr = BATohstr(p2prdy);