Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: support start-tunnel over Wi-Fi
  • Loading branch information
huangguihua committed May 21, 2024
commit 7fcb6c0d969d95efb899d157615022c844bf273e
8 changes: 5 additions & 3 deletions tidevice3/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,16 @@ def connect_remote_service_discovery_service(udid: str, tunneld_url: str = None)
if is_port_open("localhost", 49151):
tunneld_url = "http://localhost:49151"
else:
tunneld_url = "http://localhost:5555" # for backward compatibility
tunneld_url = "http://localhost:5555" # for backward compatibility

try:
resp = requests.get(tunneld_url, timeout=DEFAULT_TIMEOUT)
tunnels: Dict[str, Any] = resp.json()
ipv6_address = tunnels.get(udid)
ipv6_address = tunnels.get("usb_" + udid)
if ipv6_address is None:
raise FatalError("tunneld not ready for device", udid)
ipv6_address = tunnels.get("wifi_" + udid)
if ipv6_address is None:
raise FatalError("tunneld not ready for device", udid)
rsd = EnterableRemoteServiceDiscoveryService(ipv6_address)
return rsd
except requests.RequestException:
Expand Down
48 changes: 32 additions & 16 deletions tidevice3/cli/tunneld.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,18 @@ class Address(NamedTuple):
port: int


def get_connected_devices() -> list[str]:
def get_connected_devices(wifi: bool) -> list[str]:
"""return list of udid"""
try:
devices = list_devices(usb=True, network=False)
usb_devices = list_devices(usb=True, network=False)
devices = ["usb_" + d.Identifier for d in usb_devices if Version(d.ProductVersion) >= Version("17")]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里感觉不太好,udid加上前缀 usb_, wifi_ 感觉不如直接定义一个新的类型,比如

get_connected_devices(usb: bool, network: bool) -> List[DeviceInfo]

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

以提交新版本

if wifi:
wifi_devices = list_devices(usb=False, network=True)
devices.extend(["wifi_" + d.Identifier for d in wifi_devices if Version(d.ProductVersion) >= Version("17")])
except MuxException as e:
logger.error("list_devices failed: %s", e)
return []
return [d.Identifier for d in devices if Version(d.ProductVersion) >= Version("17")]
return devices


def get_need_lockdown_devices() -> list[str]:
Expand Down Expand Up @@ -74,11 +78,16 @@ def start_tunnel(pmd3_path: List[str], udid: str) -> Tuple[Address, subprocess.P
TunnelError
"""
# cmd = ["bash", "-c", "echo ::1 1234; sleep 10001"]
log_prefix = f"[{udid}]"
device_type, _udid = udid.split("_")[0], udid.split("_")[1]
log_prefix = f"[{_udid}]"
start_tunnel_cmd = "remote"
if udid in get_need_lockdown_devices():
start_tunnel_cmd = "lockdown"
cmdargs = pmd3_path + f"{start_tunnel_cmd} start-tunnel --script-mode --udid {udid}".split()
lockdown_devices = get_need_lockdown_devices()
if device_type == "wifi" and _udid not in lockdown_devices:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

=17.0 < 17.4 的设备不包含这这里面?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

17.4以下,Wi-Fi模式,用remote加-t wifi;17.4以上,Wi-Fi模式和USB模式都用lockdown,没有-t wifi选项

cmdargs = pmd3_path + f"{start_tunnel_cmd} start-tunnel --script-mode --udid {_udid} -t wifi".split()
else:
if _udid in lockdown_devices:
start_tunnel_cmd = "lockdown"
cmdargs = pmd3_path + f"{start_tunnel_cmd} start-tunnel --script-mode --udid {_udid}".split()
logger.info("%s cmd: %s", log_prefix, shlex.join(cmdargs))
process = subprocess.Popen(
cmdargs, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE
Expand All @@ -100,12 +109,16 @@ def __init__(self):
self.addresses: Mapping[str, Address] = {}
self.pmd3_cmd = ["pymobiledevice3"]

def update_devices(self):
current_devices = set(get_connected_devices())
active_udids = set(self.active_monitors.keys())
def update_devices(self, wifi: bool):
current_devices = get_connected_devices(wifi)
active_udids = self.active_monitors.keys()

# Start monitors for new devices
for udid in current_devices - active_udids:
for udid in current_devices:
if udid in active_udids:
continue
if udid.replace("wifi", "usb") in active_udids: # skip if device already monitered by usb
continue
self.active_monitors[udid] = None
try:
threading.Thread(name=f"{udid} keeper",
Expand All @@ -116,7 +129,9 @@ def update_devices(self):
logger.error("udid: %s start-tunnel failed: %s", udid, e)

# Stop monitors for disconnected devices
for udid in active_udids - current_devices:
for udid in active_udids:
if udid in current_devices:
continue
logger.info("udid: %s quit, terminate related process", udid)
process = self.active_monitors[udid]
if process:
Expand Down Expand Up @@ -152,10 +167,10 @@ def shutdown(self):
process.terminate()
self.running = False

def run_forever(self):
def run_forever(self, wifi: bool):
while self.running:
try:
self.update_devices()
self.update_devices(wifi)
except Exception as e:
logger.exception("update_devices failed: %s", e)
time.sleep(1)
Expand All @@ -169,7 +184,8 @@ def run_forever(self):
default=None,
)
@click.option("--port", "port", help="listen port", default=5555)
def tunneld(pmd3_path: str, port: int):
@click.option("--wifi", is_flag=True, help="start-tunnel for network devices")
def tunneld(pmd3_path: str, port: int, wifi: bool):
"""start server for iOS >= 17 auto start-tunnel, function like pymobiledevice3 remote tunneld"""
if not os_utils.is_admin:
logger.error("Please run as root(Mac) or administrator(Windows)")
Expand All @@ -194,7 +210,7 @@ def shutdown():
manager.pmd3_cmd = [pmd3_path]

threading.Thread(
target=manager.run_forever, daemon=True, name="device_manager"
target=manager.run_forever, args=(wifi,), daemon=True, name="device_manager"
).start()
try:
uvicorn.run(app, host="0.0.0.0", port=port)
Expand Down