3 """Test binding to ports on localhost."""
9 from testlib import check, util
10 from testlib.const import EXIT_SKIP
11 from testlib.log import log
12 from testlib.proc import Script
13 from testlib.test import Test
15 # Call to close opened port
16 Closer = T.Callable[[], None]
19 def bind_random_port() -> T.Tuple[T.Optional[int], Closer]:
20 """Bind to random port and return it, keeping the bind."""
22 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
23 sock.bind(("127.0.0.1", 0))
25 _, port = sock.getsockname()
26 return port, sock.close
31 def test_bind_port(ctx: Test, ok_ports: T.List[int], bad_ports: T.List[int]) -> None:
32 """Test binding to ports on localhost."""
34 foo = ctx.node(init="set LogLevel 1")
35 foo.add_script(Script.TINC_UP)
36 foo.add_script(Script.TINC_DOWN)
37 log_path = foo.sub("log")
40 log.info("check that tincd successfully binds to %s", ok_ports)
43 foo.cmd("add", "BindToAddress", f"127.0.0.1 {port}")
45 proc = foo.tincd("-D")
46 foo[Script.TINC_UP].wait()
48 foo[Script.TINC_DOWN].wait()
49 check.success(proc.wait())
51 foo_log = util.read_text(log_path)
54 check.is_in(f"Listening on 127.0.0.1 port {port}", foo_log)
57 log.info("check that tincd fails to bind to %s", bad_ports)
59 for port in bad_ports:
60 foo.cmd("add", "BindToAddress", f"127.0.0.1 {port}")
62 util.remove_file(log_path)
63 proc = foo.tincd("-D")
65 # Flush logs to the log file
67 foo[Script.TINC_UP].wait()
69 foo[Script.TINC_DOWN].wait()
70 check.success(proc.wait())
72 check.failure(proc.wait())
74 foo_log = util.read_text(log_path)
76 for port in bad_ports:
77 check.is_in(f"Can't bind to 127.0.0.1 port {port}", foo_log)
80 check.is_in("Unable to create any listening socket", foo_log)
83 port0, close0 = bind_random_port()
84 port1, close1 = bind_random_port()
86 if not port0 or not port1:
87 log.info("could not bind ports, skipping test")
90 with Test("test binding with both ports unavailable") as context:
91 test_bind_port(context, [], [port0, port1])
93 with Test("test binding to one free and one unavailable port") as context:
95 test_bind_port(context, [port0], [port1])
97 with Test("test binding to two free ports") as context:
99 test_bind_port(context, [port0, port1], [])