1111from pathlib import Path
1212import asyncio
1313
14- from threading import Thread
1514from time import sleep
1615from typing import Union
1716
2322from pymobiledevice3 .remote .common import TunnelProtocol
2423from pymobiledevice3 .services .installation_proxy import InstallationProxyService
2524from 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
2726from pymobiledevice3 .tunneld .api import get_tunneld_device_by_udid , TUNNELD_DEFAULT_ADDRESS
2827from pymobiledevice3 .tunneld .server import TunneldRunner
2928from pymobiledevice3 .usbmux import *
3231
3332VERSION : 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+
3552class 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+
4881class 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 ]] = {}
139169write_dispatcher = WriteDispatcher ()
140170read_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
329360def 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
366392def 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