doronz88 / pymobiledevice3

Pure python3 implementation for working with iDevices (iPhone, etc...).
https://discord.gg/52mZGC3JXJ
GNU General Public License v3.0
1.09k stars 149 forks source link

RSD connect timeout #979

Closed marvin-kolja closed 3 weeks ago

marvin-kolja commented 3 weeks ago

Test environment

Describe the bug I'm able to use the cli commands to e.g. get the applist on device:

  1. sudo pymobiledevice3 lockdown start-tunnel
  2. pymobiledevice3 developer dvt applist --rsd <host> <port>

However this doesn't seem to work in python code:

import asyncio

from pymobiledevice3 import lockdown
from pymobiledevice3.remote import tunnel_service
from pymobiledevice3.services.dvt import dvt_secure_socket_proxy
from pymobiledevice3.remote import remote_service_discovery
from pymobiledevice3.services.dvt.instruments import application_listing

async def main():
    device = lockdown.create_using_usbmux()
    service = tunnel_service.CoreDeviceTunnelProxy(device)

    async with service.start_tcp_tunnel() as tunnel:
        rsd = remote_service_discovery.RemoteServiceDiscoveryService((tunnel.address, tunnel.port))
        print('Connecting to RSD service...')
        await rsd.connect()
        print('Connected to RSD service.')
        dvt = dvt_secure_socket_proxy.DvtSecureSocketProxyService(lockdown=rsd)
        dvt.perform_handshake()
        applist = application_listing.ApplicationListing(dvt).applist()
        print(applist)

asyncio.run(main())

To Reproduce Steps to reproduce the behavior:

Expected behavior Connect to the rsd service thus I can use it in the DvtSecureSocketProxyService

Logs

Connecting to RSD service...
Traceback (most recent call last):
  File "<path-to-project>/meassure.py", line 87, in <module>
    asyncio.run(main())
  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "<path-to-project>meassure.py", line 74, in main
    await rsd.connect()
  File "<path-to-project>/venv/lib/python3.12/site-packages/pymobiledevice3/remote/remote_service_discovery.py", line 51, in connect
    await self.service.connect()
  File "<path-to-project>/venv/lib/python3.12/site-packages/pymobiledevice3/remote/remotexpc.py", line 49, in connect
    self.service_connection = ServiceConnection.create_using_tcp(self.address[0], self.address[1],
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<path-to-project>/venv/lib/python3.12/site-packages/pymobiledevice3/service_connection.py", line 81, in create_using_tcp
    sock = socket.create_connection((hostname, port))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/socket.py", line 852, in create_connection
    raise exceptions[0]
  File "/opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/socket.py", line 837, in create_connection
    sock.connect(sa)
TimeoutError: [Errno 60] Operation timed out

Additional context I've seen that you wrote that when using iOS >= 17.4 we can use usbmux https://github.com/doronz88/pymobiledevice3/issues/975#issuecomment-2094887843. This doesn't work in my case. If I pass the device directly to the DvtSecureSocketProxyService without creating a tunnel first it throws the same error as in #975.

For community

⬇️ Please click the 👍 reaction instead of leaving a +1 or 👍 comment

doronz88 commented 3 weeks ago

You code does a lot of stuff and probably at least half of it is redundant Please edit the issue to contain only your issue

marvin-kolja commented 3 weeks ago

Sorry! I just copy pasted what I had in the moment. I removed all the unnecessary code :)

doronz88 commented 3 weeks ago

You are using it wrong. The CoreDeviceTunnelProxy is used to establish VPN connection to the device - nothing more. That is why that's a seperate process. Only from the retrieved connection detials you can connect to the device.

Read further in the project's documentation: https://github.com/doronz88/pymobiledevice3/blob/master/misc/understanding_idevice_protocol_layers.md#remotexpc

marvin-kolja commented 3 weeks ago

~I'm a little bit confused. I don't understand why this needs to be in a separate process as async with service.start_tcp_tunnel() as tunnel: would give me the connection details.~

I never worked with asyncio. But I assume that the reason for this is that the VPN connection is a blocking operation, thus it prevents the event loop to process other tasks?

doronz88 commented 3 weeks ago

Only RemoteXPC has been refactored in pymobiledevice3 v4.0 to be pure asyncio. All usbmux-lockdown remains sync - meaning you'll probably have a deadlock while trying to connect to RSD since you're blocked on connect (sync) while the server cannot accept your connection (async).

Probably only a future major version bump will need to refactor all usbmux-lockdown to be asyncio also. Till then, you'll have to use threads/processes.

I advise on processes since the tunnel creation requires the root user.