Files
utun2/tests/tcp_proxy_full/tcp_client.py
T
evgeny 38c9f229bc stcp: ed25519 pubkey exchange in handshake, fix instance destroy segfault, fix chat_tcp_test
- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll
- stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close
- utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP),
  add deferred drain in both Phase J and L
- stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39,
  exchange ed25519_pubkey in both handshake directions
- etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in
  etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb
- chat_sync.c: fix lk->conn NULL dereference for TCP links
- test_stcp.c: update stcp_server_create/stcp_client_connect callsites
- tools/chat_tcp_test: change transport udp→tcp
2026-08-07 00:48:27 +03:00

98 lines
2.9 KiB
Python
Executable File

#!/usr/bin/env python3
"""TCP test client for tcp_proxy integration test.
Connects to host:port with SO_MARK=1, sends N bytes, receives echo, verifies.
"""
import os
import socket
import sys
import time
SO_MARK = 36
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--host", required=True)
parser.add_argument("--port", type=int, required=True)
parser.add_argument("--size", type=int, required=True)
parser.add_argument("--verify", action="store_true")
parser.add_argument("--half-close", action="store_true")
parser.add_argument("--sleep-before", type=float, default=0)
parser.add_argument("--timeout", type=float, default=30.0)
parser.add_argument("--mark", type=int, default=1, help="SO_MARK (0=off)")
parser.add_argument("--name", default="test")
args = parser.parse_args()
payload = os.urandom(args.size)
t0 = time.monotonic()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if args.mark != 0:
s.setsockopt(socket.SOL_SOCKET, SO_MARK, args.mark)
s.settimeout(args.timeout)
try:
s.connect((args.host, args.port))
except OSError as e:
print(f"[FAIL] {args.name}: connect failed: {e}", flush=True)
s.close()
sys.exit(1)
if args.sleep_before > 0:
time.sleep(args.sleep_before)
try:
s.sendall(payload)
except OSError as e:
print(f"[FAIL] {args.name}: sendall failed: {e}", flush=True)
s.close()
sys.exit(1)
if args.half_close:
s.shutdown(socket.SHUT_WR)
if not args.verify and not args.half_close:
elapsed = time.monotonic() - t0
print(f"[PASS] {args.name}: {args.size} bytes sent in {elapsed:.3f}s "
f"({args.size / 1e6 / elapsed:.2f} MB/s)", flush=True)
s.close()
sys.exit(0)
received = bytearray()
expected = args.size
try:
while len(received) < expected:
chunk = s.recv(min(65536, expected - len(received)))
if not chunk:
break
received += chunk
except OSError as e:
print(f"[FAIL] {args.name}: recv error after {len(received)} bytes: {e}", flush=True)
s.close()
sys.exit(1)
s.close()
elapsed = time.monotonic() - t0
if len(received) != expected:
print(f"[FAIL] {args.name}: {len(received)}/{expected} bytes in {elapsed:.3f}s", flush=True)
sys.exit(1)
if payload != received:
for i in range(min(len(payload), len(received))):
if payload[i] != received[i]:
print(f"[FAIL] {args.name}: data mismatch at byte {i}: "
f"sent={payload[i]:02x} recv={received[i]:02x}", flush=True)
sys.exit(1)
throughput = (expected * 2) / 1e6 / elapsed
print(f"[PASS] {args.name}: {expected} bytes echoed in {elapsed:.3f}s ({throughput:.2f} MB/s)", flush=True)
if __name__ == "__main__":
main()