Skip to content

Commit b1180c7

Browse files
author
Threepwood-7
committed
RUST-BUG-082: report SX2 answer source counts
1 parent 16938ba commit b1180c7

2 files changed

Lines changed: 53 additions & 1 deletion

File tree

scripts/rust-live-wire-hideme.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ def _multipacket_subop_counts(opcode: int, payload: bytes) -> Counter[str]:
140140
return counts
141141

142142

143+
def _answer_sources2_source_count(payload: bytes) -> int | None:
144+
if len(payload) < 19:
145+
return None
146+
return int.from_bytes(payload[17:19], "little")
147+
148+
143149
def summarize_source_exchange_packets(packet_dump_dir: Path) -> dict[str, Any]:
144150
counts: Counter[str] = Counter()
145151
for dump_file in packet_dump_dir.glob("emulebb-rust-ed2k-tcp-dump-*.jsonl"):
@@ -160,6 +166,18 @@ def summarize_source_exchange_packets(packet_dump_dir: Path) -> dict[str, Any]:
160166
counts[f"{direction}RequestSources2"] += 1
161167
elif opcode_int == OP_ANSWERSOURCES2:
162168
counts[f"{direction}AnswerSources2"] += 1
169+
payload_hex = str(record.get("payload_hex") or "")
170+
try:
171+
payload = bytes.fromhex(payload_hex)
172+
except ValueError:
173+
payload = b""
174+
source_count = _answer_sources2_source_count(payload)
175+
if source_count is None:
176+
counts[f"{direction}MalformedAnswerSources2"] += 1
177+
else:
178+
counts[f"{direction}AnswerSources2SourceCount"] += source_count
179+
if source_count == 0:
180+
counts[f"{direction}EmptyAnswerSources2"] += 1
163181
elif opcode_int in {OP_MULTIPACKET, OP_MULTIPACKET_EXT, OP_MULTIPACKET_EXT2}:
164182
payload_hex = str(record.get("payload_hex") or "")
165183
try:
@@ -172,6 +190,9 @@ def summarize_source_exchange_packets(packet_dump_dir: Path) -> dict[str, Any]:
172190
return {
173191
"requestSources2Sent": counts["sendRequestSources2"] + counts["sendEmbeddedRequestSources2"],
174192
"answerSources2Received": counts["recvAnswerSources2"],
193+
"answerSources2SourceCount": counts["recvAnswerSources2SourceCount"],
194+
"emptyAnswerSources2Received": counts["recvEmptyAnswerSources2"],
195+
"malformedAnswerSources2Received": counts["recvMalformedAnswerSources2"],
175196
"embeddedRequestSources2Sent": counts["sendEmbeddedRequestSources2"],
176197
"standaloneRequestSources2Sent": counts["sendRequestSources2"],
177198
"counts": dict(sorted(counts.items())),

tests/python/test_rust_live_wire_hideme.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ def test_source_exchange_summary_counts_embedded_sx2_requests(tmp_path: Path) ->
6262
module = load_live_wire_module()
6363
dump_path = tmp_path / "emulebb-rust-ed2k-tcp-dump-test.jsonl"
6464
request_filename_ext_info = bytes([1, 0, 0, 0, 0])
65+
answer_sources2_payload = (
66+
bytes([4])
67+
+ bytes(range(16))
68+
+ (2).to_bytes(2, "little")
69+
+ (bytes([192, 0, 2, 1]) + (4662).to_bytes(2, "little") + bytes(23))
70+
+ (bytes([192, 0, 2, 2]) + (4663).to_bytes(2, "little") + bytes(23))
71+
)
6572
multipacket_ext_payload = (
6673
bytes(range(16))
6774
+ (12345).to_bytes(8, "little")
@@ -79,7 +86,7 @@ def test_source_exchange_summary_counts_embedded_sx2_requests(tmp_path: Path) ->
7986
{
8087
"direction": "recv",
8188
"opcode": module.OP_ANSWERSOURCES2,
82-
"payload_hex": "",
89+
"payload_hex": answer_sources2_payload.hex(),
8390
},
8491
]
8592
dump_path.write_text("\n".join(json.dumps(row) for row in records), encoding="utf-8")
@@ -90,6 +97,8 @@ def test_source_exchange_summary_counts_embedded_sx2_requests(tmp_path: Path) ->
9097
assert summary["embeddedRequestSources2Sent"] == 1
9198
assert summary["standaloneRequestSources2Sent"] == 0
9299
assert summary["answerSources2Received"] == 1
100+
assert summary["answerSources2SourceCount"] == 2
101+
assert summary["emptyAnswerSources2Received"] == 0
93102

94103

95104
def test_source_exchange_summary_counts_ext2_embedded_sx2_requests(tmp_path: Path) -> None:
@@ -120,6 +129,28 @@ def test_source_exchange_summary_counts_ext2_embedded_sx2_requests(tmp_path: Pat
120129
assert summary["embeddedRequestSources2Sent"] == 1
121130

122131

132+
def test_source_exchange_summary_counts_empty_sx2_answers(tmp_path: Path) -> None:
133+
module = load_live_wire_module()
134+
dump_path = tmp_path / "emulebb-rust-ed2k-tcp-dump-test.jsonl"
135+
answer_sources2_payload = bytes([4]) + bytes(range(16)) + (0).to_bytes(2, "little")
136+
dump_path.write_text(
137+
json.dumps(
138+
{
139+
"direction": "recv",
140+
"opcode": module.OP_ANSWERSOURCES2,
141+
"payload_hex": answer_sources2_payload.hex(),
142+
}
143+
),
144+
encoding="utf-8",
145+
)
146+
147+
summary = module.summarize_source_exchange_packets(tmp_path)
148+
149+
assert summary["answerSources2Received"] == 1
150+
assert summary["answerSources2SourceCount"] == 0
151+
assert summary["emptyAnswerSources2Received"] == 1
152+
153+
123154
def test_run_downloads_returns_after_first_completion(monkeypatch) -> None:
124155
module = load_live_wire_module()
125156
transfer_hashes = [

0 commit comments

Comments
 (0)