Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions discovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -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();
});
});

Expand Down
4 changes: 2 additions & 2 deletions handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 => {
Expand Down
18 changes: 13 additions & 5 deletions impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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 };
};
17 changes: 13 additions & 4 deletions session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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;
});

Expand Down Expand Up @@ -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");
Expand Down
8 changes: 5 additions & 3 deletions tests/fn.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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);

Expand Down