Skip to content

Commit ef027b2

Browse files
committed
feat: Bind tcp forwarders to IPC connection
*If the connection dies, the forwarding should stop too
1 parent 114cc0a commit ef027b2

File tree

1 file changed

+42
-23
lines changed

1 file changed

+42
-23
lines changed

src/main/resources/handler.py

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from pathlib import Path
1212
import asyncio
1313

14-
from threading import Thread
1514
from time import sleep
1615
from typing import Union
1716

@@ -23,7 +22,7 @@
2322
from pymobiledevice3.remote.common import TunnelProtocol
2423
from pymobiledevice3.services.installation_proxy import InstallationProxyService
2524
from pymobiledevice3.services.mobile_image_mounter import auto_mount
26-
from pymobiledevice3.tcp_forwarder import LockdownTcpForwarder, UsbmuxTcpForwarder
25+
from pymobiledevice3.tcp_forwarder import LockdownTcpForwarder, UsbmuxTcpForwarder, TcpForwarderBase
2726
from pymobiledevice3.tunneld.api import get_tunneld_device_by_udid, TUNNELD_DEFAULT_ADDRESS
2827
from pymobiledevice3.tunneld.server import TunneldRunner
2928
from pymobiledevice3.usbmux import *
@@ -32,19 +31,53 @@
3231

3332
VERSION: int
3433

34+
class ConnectionResource:
35+
def close(self):
36+
raise NotImplementedError()
37+
38+
class TcpForwarderResource(ConnectionResource):
39+
40+
def __init__(self, forwarder: TcpForwarderBase, thread):
41+
self.forwarder = forwarder
42+
self.thread = thread
43+
44+
def close(self):
45+
self.forwarder.stop()
46+
self.thread.join(5)
47+
48+
if self.thread.is_alive():
49+
print(f"Joining forwarder thread {self.forwarder.src_port} timed out")
50+
51+
3552
class IPCClient:
3653
def __init__(self, sock, address, version):
3754
self.sock = sock
3855
self.read_file = sock.makefile('r')
3956
self.write_file = sock.makefile('w')
4057
self.address = address
4158
self.version = version
59+
self.active_forwarder: dict[int, TcpForwarderResource] = {}
4260

4361
def close(self):
62+
for resource in self.active_forwarder.values():
63+
resource.close()
64+
self.active_forwarder.clear()
65+
4466
self.sock.close()
4567
self.read_file.close()
4668
self.write_file.close()
4769

70+
def add_forwarder(self, local_port: int, forwarder: TcpForwarderResource):
71+
if local_port in self.active_forwarder:
72+
raise ValueError(f"{local_port} already has an open connection: {self.active_forwarder[local_port]}")
73+
self.active_forwarder[local_port] = forwarder
74+
75+
def close_forwarder(self, local_port: int):
76+
if local_port not in self.active_forwarder:
77+
raise ValueError(f"Port {local_port} is not open")
78+
forwarder = self.active_forwarder.pop(local_port)
79+
forwarder.close()
80+
4881
class WriteDispatcher:
4982
def __init__(self):
5083
self.write_queue = queue.Queue()
@@ -133,9 +166,6 @@ def add_client(self, ipc_client):
133166
def shutdown(self):
134167
self.shutdown_event.set()
135168

136-
137-
active_debug_server: dict[int, tuple[LockdownTcpForwarder, Thread]] = {}
138-
active_usbmux_forwarder: dict[int, tuple[UsbmuxTcpForwarder, Thread]] = {}
139169
write_dispatcher = WriteDispatcher()
140170
read_dispatcher = ReadDispatcher()
141171

@@ -317,7 +347,8 @@ def forwarder_thread():
317347
listen_event.wait()
318348
selected_port = forwarder.server_socket.getsockname()[1]
319349

320-
active_debug_server[selected_port] = (forwarder, thread)
350+
resource = TcpForwarderResource(forwarder, thread)
351+
ipc_client.add_forwarder(selected_port, resource)
321352

322353
reply = {"id": id, "state": "completed", "result": {
323354
"host": "127.0.0.1",
@@ -327,13 +358,7 @@ def forwarder_thread():
327358

328359

329360
def debugserver_close(id, port, ipc_client):
330-
forwarder, thread = active_debug_server.pop(port)
331-
forwarder.stop()
332-
333-
thread.join(5)
334-
335-
if thread.is_alive():
336-
print(f"Joining debugserver thread {port} timed out")
361+
ipc_client.close_forwarder(port)
337362

338363
reply = {"id": id, "state": "completed"}
339364
write_dispatcher.write_reply(ipc_client, reply)
@@ -353,7 +378,8 @@ def forwarder_thread():
353378
listen_event.wait()
354379
selected_port = forwarder.server_socket.getsockname()[1]
355380

356-
active_usbmux_forwarder[selected_port] = (forwarder, thread)
381+
resource = TcpForwarderResource(forwarder, thread)
382+
ipc_client.add_forwarder(selected_port, resource)
357383

358384
reply = {"id": id, "state": "completed", "result": {
359385
"host": "127.0.0.1",
@@ -364,13 +390,7 @@ def forwarder_thread():
364390

365391

366392
def usbmux_forward_close(id, local_port, ipc_client):
367-
forwarder, thread = active_usbmux_forwarder.pop(local_port)
368-
forwarder.stop()
369-
370-
thread.join(5)
371-
372-
if thread.is_alive():
373-
print(f"Joining usbmux thread {local_port} timed out")
393+
ipc_client.close_forwarder(local_port)
374394

375395
reply = {"id": id, "state": "completed"}
376396
write_dispatcher.write_reply(ipc_client, reply)
@@ -438,8 +458,7 @@ def handle_command(command, ipc_client):
438458
auto_mount_image(id, lockdown, ipc_client)
439459
return
440460
elif command_type == "debugserver_connect":
441-
port = res['port'] if 'port' in res else 0
442-
debugserver_connect(id, lockdown, port, ipc_client)
461+
debugserver_connect(id, lockdown, res['port'], ipc_client)
443462
return
444463
elif command_type == "get_installed_path":
445464
get_installed_path(id, lockdown, res["bundle_identifier"], ipc_client)

0 commit comments

Comments
 (0)