pymobiledevice3 4.27.7__py3-none-any.whl → 5.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pymobiledevice3 might be problematic. Click here for more details.

@@ -190,7 +190,7 @@ class RemotePairingTunnel(ABC):
190
190
  self._tun_read_task = asyncio.create_task(self.tun_read_task(), name=f'tun-read-{address}')
191
191
 
192
192
  async def stop_tunnel(self) -> None:
193
- self._logger.debug('stopping tunnel')
193
+ self._logger.debug(f'[{asyncio.current_task().get_name()}] stopping tunnel')
194
194
  self._tun_read_task.cancel()
195
195
  with suppress(CancelledError):
196
196
  await self._tun_read_task
@@ -223,6 +223,9 @@ class RemotePairingQuicTunnel(RemotePairingTunnel, QuicConnectionProtocol):
223
223
  self._quic.send_datagram_frame(packet)
224
224
  self.transmit()
225
225
 
226
+ # Allow other tasks to run
227
+ await asyncio.sleep(0)
228
+
226
229
  async def request_tunnel_establish(self) -> dict:
227
230
  stream_id = self._quic.get_next_available_stream_id()
228
231
  # pad the data with random data to force the MTU size correctly
@@ -939,17 +942,21 @@ class RemotePairingManualPairingService(RemotePairingTunnelService):
939
942
  class CoreDeviceTunnelProxy(StartTcpTunnel):
940
943
  SERVICE_NAME = 'com.apple.internal.devicecompute.CoreDeviceProxy'
941
944
 
942
- def __init__(self, lockdown: LockdownServiceProvider) -> None:
943
- self._lockdown = lockdown
944
- self._service: Optional[ServiceConnection] = None
945
+ @classmethod
946
+ async def create(cls, lockdown: LockdownServiceProvider) -> 'CoreDeviceTunnelProxy':
947
+ return cls(await lockdown.aio_start_lockdown_service(cls.SERVICE_NAME), lockdown.udid)
948
+
949
+ def __init__(self, service: ServiceConnection, remote_identifier: str) -> None:
950
+ self._service: ServiceConnection = service
951
+ self._remote_identifier: str = remote_identifier
945
952
 
946
953
  @property
947
954
  def remote_identifier(self) -> str:
948
- return self._lockdown.udid
955
+ return self._remote_identifier
949
956
 
950
957
  @asynccontextmanager
951
958
  async def start_tcp_tunnel(self) -> AsyncGenerator['TunnelResult', None]:
952
- self._service = await self._lockdown.aio_start_lockdown_service(self.SERVICE_NAME)
959
+ assert self._service is not None, 'service must be connected first'
953
960
  tunnel = RemotePairingTcpTunnel(self._service.reader, self._service.writer)
954
961
  handshake_response = await tunnel.request_tunnel_establish()
955
962
  tunnel.start_tunnel(handshake_response['clientParameters']['address'],
@@ -1078,13 +1085,14 @@ async def get_remote_pairing_tunnel_services(
1078
1085
  udid: Optional[str] = None) -> list[RemotePairingTunnelService]:
1079
1086
  result = []
1080
1087
  for answer in await browse_remotepairing(timeout=bonjour_timeout):
1081
- for ip in answer.ips:
1088
+ for address in answer.addresses:
1082
1089
  for identifier in iter_remote_paired_identifiers():
1083
1090
  if udid is not None and identifier != udid:
1084
1091
  continue
1085
1092
  conn = None
1086
1093
  try:
1087
- conn = await create_core_device_tunnel_service_using_remotepairing(identifier, ip, answer.port)
1094
+ conn = await create_core_device_tunnel_service_using_remotepairing(
1095
+ identifier, address.full_ip, answer.port)
1088
1096
  result.append(conn)
1089
1097
  break
1090
1098
  except ConnectionAbortedError:
@@ -17,8 +17,8 @@ async def get_rsds(bonjour_timeout: float = DEFAULT_BONJOUR_TIMEOUT, udid: Optio
17
17
  result = []
18
18
  with stop_remoted():
19
19
  for answer in await browse_remoted(timeout=bonjour_timeout):
20
- for ip in answer.ips:
21
- rsd = RemoteServiceDiscoveryService((ip, RSD_PORT))
20
+ for address in answer.addresses:
21
+ rsd = RemoteServiceDiscoveryService((address.full_ip, RSD_PORT))
22
22
  try:
23
23
  await rsd.connect()
24
24
  except ConnectionRefusedError:
@@ -100,10 +100,24 @@ kcdata_types = {
100
100
  'STACKSHOT_KCTYPE_LATENCY_INFO_THREAD': 0x92d,
101
101
  'STACKSHOT_KCTYPE_LOADINFO64_TEXT_EXEC': 0x92e,
102
102
 
103
+ 'STACKSHOT_KCTYPE_USER_ASYNC_START_INDEX': 0x932,
104
+ 'STACKSHOT_KCTYPE_USER_ASYNC_STACKLR64': 0x933,
105
+
103
106
  'STACKSHOT_KCTYPE_TASK_DELTA_SNAPSHOT': 0x940,
104
107
  'STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT': 0x941,
105
- 'STACKSHOT_KCTYPE_UNKNOWN_0x942': 0x942,
108
+ 'STACKSHOT_KCCONTAINER_SHAREDCACHE': 0x942,
106
109
  'STACKSHOT_KCTYPE_UNKNOWN_0x943': 0x943,
110
+ 'STACKSHOT_KCCONTAINER_EXCLAVES': 0x949,
111
+ 'STACKSHOT_KCCONTAINER_EXCLAVE_SCRESULT': 0x94a,
112
+
113
+ 'STACKSHOT_KCCONTAINER_EXCLAVE_IPCSTACKENTRY': 0x94c,
114
+ 'STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_INFO': 0x94d,
115
+ 'STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_ECSTACK': 0x94e,
116
+ 'STACKSHOT_KCCONTAINER_EXCLAVE_ADDRESSSPACE': 0x94f,
117
+
118
+ 'STACKSHOT_KCCONTAINER_EXCLAVE_TEXTLAYOUT': 0x952,
119
+ 'STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_INFO': 0x953,
120
+ 'STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_SEGMENTS': 0x954,
107
121
 
108
122
  'KCDATA_TYPE_BUFFER_END': 0xF19158ED,
109
123
 
@@ -185,6 +199,16 @@ predefined_names = {
185
199
  kcdata_types_enum.STACKSHOT_KCTYPE_STACKSHOT_FAULT_STATS: 'stackshot_fault_stats',
186
200
  kcdata_types_enum.STACKSHOT_KCTYPE_STACKSHOT_DURATION: 'stackshot_duration',
187
201
  kcdata_types_enum.STACKSHOT_KCTYPE_LOADINFO64_TEXT_EXEC: 'dyld_load_info_text_exec',
202
+ kcdata_types_enum.STACKSHOT_KCTYPE_USER_ASYNC_STACKLR64: 'user_async_stack_lr',
203
+ kcdata_types_enum.STACKSHOT_KCCONTAINER_SHAREDCACHE: 'container_sharedcache',
204
+ kcdata_types_enum.STACKSHOT_KCCONTAINER_EXCLAVES: 'container_exclaves',
205
+ kcdata_types_enum.STACKSHOT_KCCONTAINER_EXCLAVE_SCRESULT: 'exclave_scresult',
206
+ kcdata_types_enum.STACKSHOT_KCCONTAINER_EXCLAVE_IPCSTACKENTRY: 'exclave_ipc_stack_entry',
207
+ kcdata_types_enum.STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_ECSTACK: 'exclave_ipc_stack_entry_ecstack',
208
+ kcdata_types_enum.STACKSHOT_KCCONTAINER_EXCLAVE_ADDRESSSPACE: 'exclave_address_space',
209
+ kcdata_types_enum.STACKSHOT_KCCONTAINER_EXCLAVE_TEXTLAYOUT: 'exclave_text_layout',
210
+ kcdata_types_enum.STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_INFO: 'exclave_text_layout_info',
211
+ kcdata_types_enum.STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_SEGMENTS: 'exclave_text_layout_segments',
188
212
  }
189
213
 
190
214
  predefined_name_substruct = 'name' / Computed(lambda ctx: predefined_names[ctx._.type])
@@ -443,6 +467,39 @@ loadinfo64_text_exec = Struct(
443
467
  ),
444
468
  )
445
469
 
470
+ user_async_stacklr64 = Struct(
471
+ predefined_name_substruct,
472
+ 'obj' / Struct(
473
+ 'lr' / Int64ul,
474
+ ),
475
+ )
476
+
477
+ exclave_ipcstackentry_ecstack = Struct(
478
+ predefined_name_substruct,
479
+ 'obj' / Struct(
480
+ 'addr' / Int64ul,
481
+ ),
482
+ )
483
+
484
+ exclave_textlayout_info = Struct(
485
+ predefined_name_substruct,
486
+ 'obj' / Struct(
487
+ 'layout_id' / Int64ul,
488
+ 'etl_flags' / Int64ul,
489
+ 'sharedcache_index' / Int32ul,
490
+ ),
491
+ )
492
+
493
+ exclave_textlayout_segments = Struct(
494
+ predefined_name_substruct,
495
+ 'obj' / Struct(
496
+ '_imageUUID' / Bytes(16),
497
+ 'imageUUID' / Computed(lambda ctx: uuid.UUID(bytes=ctx._imageUUID)),
498
+ 'layoutSegment_loadAddress' / Int64ul,
499
+ 'layoutSegment_rawLoadAddress' / Int64ul,
500
+ ),
501
+ )
502
+
446
503
  kcdata_types_structures = {
447
504
  kcdata_types_enum.KCDATA_TYPE_UINT32_DESC: uint32_desc,
448
505
  kcdata_types_enum.KCDATA_TYPE_UINT64_DESC: uint64_desc,
@@ -482,6 +539,10 @@ kcdata_types_structures = {
482
539
  kcdata_types_enum.KCDATA_TYPE_BUFFER_END: Pass,
483
540
  kcdata_types_enum.STACKSHOT_KCTYPE_STACKSHOT_DURATION: stackshot_duration,
484
541
  kcdata_types_enum.STACKSHOT_KCTYPE_LOADINFO64_TEXT_EXEC: loadinfo64_text_exec,
542
+ kcdata_types_enum.STACKSHOT_KCTYPE_USER_ASYNC_STACKLR64: user_async_stacklr64,
543
+ kcdata_types_enum.STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_ECSTACK: exclave_ipcstackentry_ecstack,
544
+ kcdata_types_enum.STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_INFO: exclave_textlayout_info,
545
+ kcdata_types_enum.STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_SEGMENTS: exclave_textlayout_segments,
485
546
  }
486
547
 
487
548
  kcdata_item = Struct(
@@ -7,10 +7,13 @@ import signal
7
7
  import traceback
8
8
  import warnings
9
9
  from contextlib import asynccontextmanager, suppress
10
+ from ssl import SSLEOFError
10
11
  from typing import Optional, Union
11
12
 
12
13
  import construct
13
14
 
15
+ from pymobiledevice3.bonjour import browse_remoted
16
+
14
17
  with warnings.catch_warnings():
15
18
  # Ignore: "Core Pydantic V1 functionality isn't compatible with Python 3.14 or greater."
16
19
  warnings.simplefilter('ignore', category=UserWarning)
@@ -22,9 +25,9 @@ from fastapi import FastAPI
22
25
  from packaging.version import Version
23
26
 
24
27
  from pymobiledevice3 import usbmux
25
- from pymobiledevice3.bonjour import REMOTED_SERVICE_NAMES, browse
26
28
  from pymobiledevice3.exceptions import ConnectionFailedError, ConnectionFailedToUsbmuxdError, DeviceNotFoundError, \
27
- GetProhibitedError, IncorrectModeError, InvalidServiceError, LockdownError, MuxException, PairingError
29
+ GetProhibitedError, IncorrectModeError, InvalidServiceError, LockdownError, MuxException, PairingError, \
30
+ StreamClosedError
28
31
  from pymobiledevice3.lockdown import create_using_usbmux, get_mobdev2_lockdowns
29
32
  from pymobiledevice3.osu.os_utils import get_os_utils
30
33
  from pymobiledevice3.remote.common import TunnelProtocol
@@ -42,7 +45,7 @@ REATTEMPT_INTERVAL = 5
42
45
  REATTEMPT_COUNT = 5
43
46
 
44
47
  REMOTEPAIRING_INTERVAL = 5
45
- MOVDEV2_INTERVAL = 5
48
+ MOBDEV2_INTERVAL = 5
46
49
 
47
50
  USBMUX_INTERVAL = 2
48
51
  OSUTILS = get_os_utils()
@@ -91,50 +94,75 @@ class TunneldCore:
91
94
 
92
95
  @asyncio_print_traceback
93
96
  async def monitor_usb_task(self) -> None:
94
- previous_ips = []
95
- while True:
96
- current_ips = OSUTILS.get_ipv6_ips()
97
- added = [ip for ip in current_ips if ip not in previous_ips]
98
- removed = [ip for ip in previous_ips if ip not in current_ips]
99
-
100
- previous_ips = current_ips
101
-
102
- logger.debug(f'added interfaces: {added}')
103
- logger.debug(f'removed interfaces: {removed}')
104
-
105
- for ip in removed:
106
- if ip in self.tunnel_tasks:
107
- self.tunnel_tasks[ip].task.cancel()
108
- await self.tunnel_tasks[ip].task
109
-
110
- for ip in added:
111
- self.tunnel_tasks[ip] = TunnelTask(
112
- task=asyncio.create_task(self.handle_new_potential_usb_cdc_ncm_interface_task(ip),
113
- name=f'handle-new-potential-usb-cdc-ncm-interface-task-{ip}'))
114
-
115
- # wait before re-iterating
116
- await asyncio.sleep(1)
97
+ try:
98
+ previous_ips = []
99
+ while True:
100
+ current_ips = OSUTILS.get_ipv6_ips()
101
+ added = [ip for ip in current_ips if ip not in previous_ips]
102
+ removed = [ip for ip in previous_ips if ip not in current_ips]
103
+
104
+ previous_ips = current_ips
105
+
106
+ # logger.debug(f'added interfaces: {added}')
107
+ # logger.debug(f'removed interfaces: {removed}')
108
+
109
+ for ip in removed:
110
+ if ip in self.tunnel_tasks:
111
+ self.tunnel_tasks[ip].task.cancel()
112
+ with suppress(asyncio.CancelledError):
113
+ await self.tunnel_tasks[ip].task
114
+
115
+ if added:
116
+ # A new interface was attached
117
+ for answer in await browse_remoted():
118
+ for address in answer.addresses:
119
+ if address.iface.startswith('utun'):
120
+ # Skip already established tunnels
121
+ continue
122
+ if address.full_ip in self.tunnel_tasks.keys():
123
+ # Skip already established tunnels
124
+ continue
125
+ self.tunnel_tasks[address.full_ip] = TunnelTask(
126
+ task=asyncio.create_task(
127
+ self.handle_new_potential_usb_cdc_ncm_interface_task(address.full_ip),
128
+ name=f'handle-new-potential-usb-cdc-ncm-interface-task-{address.full_ip}'))
129
+
130
+ # wait before re-iterating
131
+ await asyncio.sleep(1)
132
+ except asyncio.CancelledError:
133
+ pass
117
134
 
118
135
  @asyncio_print_traceback
119
136
  async def monitor_wifi_task(self) -> None:
120
137
  try:
121
138
  while True:
122
- for service in await get_remote_pairing_tunnel_services():
123
- if service.hostname in self.tunnel_tasks:
124
- # skip tunnel if already exists for this ip
125
- await service.close()
126
- continue
127
- if self.tunnel_exists_for_udid(service.remote_identifier):
128
- # skip tunnel if already exists for this udid
129
- await service.close()
130
- continue
131
- self.tunnel_tasks[service.hostname] = TunnelTask(
132
- task=asyncio.create_task(self.start_tunnel_task(service.hostname, service),
133
- name=f'start-tunnel-task-wifi-{service.hostname}'),
134
- udid=service.remote_identifier
135
- )
139
+ try:
140
+ remote_pairing_tunnel_services = await get_remote_pairing_tunnel_services()
141
+ for service in remote_pairing_tunnel_services:
142
+ if service.hostname in self.tunnel_tasks:
143
+ # skip tunnel if already exists for this ip
144
+ await service.close()
145
+ continue
146
+ if self.tunnel_exists_for_udid(service.remote_identifier):
147
+ # skip tunnel if already exists for this udid
148
+ await service.close()
149
+ continue
150
+ self.tunnel_tasks[service.hostname] = TunnelTask(
151
+ task=asyncio.create_task(self.start_tunnel_task(service.hostname, service),
152
+ name=f'start-tunnel-task-wifi-{service.hostname}'),
153
+ udid=service.remote_identifier
154
+ )
155
+ except asyncio.exceptions.IncompleteReadError:
156
+ continue
157
+ except asyncio.CancelledError:
158
+ # Raise and cancel gracefully
159
+ raise
160
+ except Exception:
161
+ logger.error(f'Got exception from {asyncio.current_task().get_name()}: {traceback.format_exc()}')
162
+ continue
136
163
  await asyncio.sleep(REMOTEPAIRING_INTERVAL)
137
164
  except asyncio.CancelledError:
165
+ # Cancel gracefully
138
166
  pass
139
167
 
140
168
  @asyncio_print_traceback
@@ -145,11 +173,20 @@ class TunneldCore:
145
173
  for mux_device in usbmux.list_devices():
146
174
  task_identifier = f'usbmux-{mux_device.serial}-{mux_device.connection_type}'
147
175
  if self.tunnel_exists_for_udid(mux_device.serial):
176
+ # Skip if already established a tunnel for this udid
148
177
  continue
178
+ if task_identifier in self.tunnel_tasks:
179
+ # Skip if already trying to establish a tunnel for this device
180
+ continue
181
+ service = None
149
182
  try:
150
- service = CoreDeviceTunnelProxy(create_using_usbmux(mux_device.serial))
183
+ with create_using_usbmux(mux_device.serial) as lockdown:
184
+ service = await CoreDeviceTunnelProxy.create(lockdown)
151
185
  except (MuxException, InvalidServiceError, GetProhibitedError, construct.core.StreamError,
152
- ConnectionAbortedError, DeviceNotFoundError, LockdownError, IncorrectModeError):
186
+ ConnectionAbortedError, DeviceNotFoundError, LockdownError, IncorrectModeError,
187
+ SSLEOFError):
188
+ if service is not None:
189
+ await service.close()
153
190
  continue
154
191
  self.tunnel_tasks[task_identifier] = TunnelTask(
155
192
  udid=mux_device.serial,
@@ -172,22 +209,26 @@ class TunneldCore:
172
209
  try:
173
210
  while True:
174
211
  async for ip, lockdown in get_mobdev2_lockdowns(only_paired=True):
175
- if self.tunnel_exists_for_udid(lockdown.udid):
176
- # skip tunnel if already exists for this udid
177
- continue
178
- task_identifier = f'mobdev2-{lockdown.udid}-{ip}'
179
- try:
180
- tunnel_service = CoreDeviceTunnelProxy(lockdown)
181
- except InvalidServiceError:
182
- logger.warning(f'[{task_identifier}] failed to start CoreDeviceTunnelProxy - skipping')
183
- lockdown.close()
184
- continue
212
+ with lockdown:
213
+ udid = lockdown.udid
214
+ task_identifier = f'mobdev2-{udid}-{ip}'
215
+ if self.tunnel_exists_for_udid(udid):
216
+ # Skip tunnel if already exists for this udid
217
+ continue
218
+ if task_identifier in self.tunnel_tasks:
219
+ # Skip if already trying to establish a tunnel for this device
220
+ continue
221
+ try:
222
+ tunnel_service = await CoreDeviceTunnelProxy.create(lockdown)
223
+ except InvalidServiceError:
224
+ logger.warning(f'[{task_identifier}] failed to start CoreDeviceTunnelProxy - skipping')
225
+ continue
185
226
  self.tunnel_tasks[task_identifier] = TunnelTask(
186
227
  task=asyncio.create_task(self.start_tunnel_task(task_identifier, tunnel_service),
187
228
  name=f'start-tunnel-task-{task_identifier}'),
188
- udid=lockdown.udid
229
+ udid=udid
189
230
  )
190
- await asyncio.sleep(MOVDEV2_INTERVAL)
231
+ await asyncio.sleep(MOBDEV2_INTERVAL)
191
232
  except asyncio.CancelledError:
192
233
  pass
193
234
 
@@ -219,8 +260,8 @@ class TunneldCore:
219
260
  else:
220
261
  bailed_out = True
221
262
  logger.debug(
222
- f'not establishing tunnel from {asyncio.current_task().get_name()} '
223
- f'since there is already an active one for same udid')
263
+ f'[{asyncio.current_task().get_name()}] Not establishing tunnel since there is already an '
264
+ f'active one for same udid')
224
265
  except asyncio.CancelledError:
225
266
  pass
226
267
  except (asyncio.exceptions.IncompleteReadError, TimeoutError, OSError, ConnectionResetError, StreamError,
@@ -254,30 +295,28 @@ class TunneldCore:
254
295
  async def handle_new_potential_usb_cdc_ncm_interface_task(self, ip: str) -> None:
255
296
  rsd = None
256
297
  try:
257
- answers = None
258
- for i in range(REATTEMPT_COUNT):
259
- answers = await browse(REMOTED_SERVICE_NAMES, [ip])
260
- if answers:
261
- break
262
- logger.debug(f'No addresses found for: {ip}')
263
- await asyncio.sleep(REATTEMPT_INTERVAL)
264
-
265
- if not answers:
266
- raise asyncio.CancelledError()
267
-
268
- peer_address = answers[0].ips[0]
269
-
270
298
  # establish an untrusted RSD handshake
271
- rsd = RemoteServiceDiscoveryService((peer_address, RSD_PORT))
299
+ rsd = RemoteServiceDiscoveryService((ip, RSD_PORT))
272
300
 
273
301
  with stop_remoted():
274
- try:
275
- await rsd.connect()
276
- except (ConnectionRefusedError, TimeoutError):
277
- raise asyncio.CancelledError()
302
+ first_time = True
303
+ retry = False
304
+ while retry or first_time:
305
+ retry = False
306
+ try:
307
+ await rsd.connect()
308
+ except StreamClosedError:
309
+ # Could be on first try because of remoted race
310
+ if first_time:
311
+ retry = True
312
+ except (ConnectionRefusedError, TimeoutError, OSError):
313
+ raise asyncio.CancelledError()
314
+ finally:
315
+ first_time = False
278
316
 
279
317
  if (self.protocol == TunnelProtocol.QUIC) and (Version(rsd.product_version) < Version('17.0.0')):
280
318
  await rsd.close()
319
+ rsd = None
281
320
  raise asyncio.CancelledError()
282
321
 
283
322
  await asyncio.create_task(
@@ -299,7 +338,7 @@ class TunneldCore:
299
338
  pass
300
339
 
301
340
  if ip in self.tunnel_tasks:
302
- # in case the tunnel was removed just now
341
+ # In case the tunnel was removed just now
303
342
  self.tunnel_tasks.pop(ip)
304
343
 
305
344
  async def close(self) -> None:
@@ -325,7 +364,7 @@ class TunneldCore:
325
364
  """ Cancel active tunnels """
326
365
  for tunnel_ip in self.get_tunnels_ips().get(udid, []):
327
366
  self.tunnel_tasks.pop(tunnel_ip).task.cancel()
328
- logger.info(f'canceling tunnel {tunnel_ip}')
367
+ logger.info(f'Canceling tunnel {tunnel_ip}')
329
368
 
330
369
  def clear(self) -> None:
331
370
  """ Clear active tunnels """
@@ -348,7 +387,6 @@ class TunneldRunner:
348
387
  wifi_monitor: bool = True, usbmux_monitor: bool = True, mobdev2_monitor: bool = True):
349
388
  @asynccontextmanager
350
389
  async def lifespan(app: FastAPI):
351
- logging.getLogger('zeroconf').disabled = True
352
390
  self._tunneld_core.start()
353
391
  yield
354
392
  logger.info('Closing tunneld tasks...')
@@ -427,7 +465,8 @@ class TunneldRunner:
427
465
  if not created_task and connection_type in ('usbmux', None):
428
466
  task_identifier = f'usbmux-{udid}'
429
467
  try:
430
- service = CoreDeviceTunnelProxy(create_using_usbmux(udid))
468
+ with create_using_usbmux(udid) as lockdown:
469
+ service = await CoreDeviceTunnelProxy.create(lockdown)
431
470
  task = asyncio.create_task(
432
471
  self._tunneld_core.start_tunnel_task(task_identifier, service, protocol=TunnelProtocol.TCP,
433
472
  queue=queue),
@@ -469,7 +508,7 @@ class TunneldRunner:
469
508
  }}))
470
509
 
471
510
  if not created_task:
472
- return fastapi.Response(status_code=501, content=json.dumps({'error': 'task not not created'}))
511
+ return fastapi.Response(status_code=501, content=json.dumps({'error': 'task not created'}))
473
512
 
474
513
  tunnel: Optional[TunnelResult] = await queue.get()
475
514
  if tunnel is not None:
pymobiledevice3/usbmux.py CHANGED
@@ -174,15 +174,17 @@ class MuxConnection:
174
174
  # first attempt to connect with possibly the wrong version header (plist protocol)
175
175
  sock = MuxConnection.create_usbmux_socket(usbmux_address=usbmux_address)
176
176
 
177
- message = usbmuxd_request.build({
178
- 'header': {'version': usbmuxd_version.PLIST, 'message': usbmuxd_msgtype.PLIST, 'tag': 1},
179
- 'data': plistlib.dumps({'MessageType': 'ReadBUID'})
180
- })
181
- sock.send(message)
182
- response = usbmuxd_response.parse_stream(sock)
183
-
184
- # if we sent a bad request, we should re-create the socket in the correct version this time
185
- sock.close()
177
+ try:
178
+ message = usbmuxd_request.build({
179
+ 'header': {'version': usbmuxd_version.PLIST, 'message': usbmuxd_msgtype.PLIST, 'tag': 1},
180
+ 'data': plistlib.dumps({'MessageType': 'ReadBUID'})
181
+ })
182
+ sock.send(message)
183
+ response = usbmuxd_response.parse_stream(sock)
184
+
185
+ finally:
186
+ # If we sent a bad request, we should re-create the socket in the correct version this time
187
+ sock.close()
186
188
  sock = MuxConnection.create_usbmux_socket(usbmux_address=usbmux_address)
187
189
 
188
190
  if response.header.version == usbmuxd_version.BINARY:
@@ -414,9 +416,11 @@ def create_mux(usbmux_address: Optional[str] = None) -> MuxConnection:
414
416
 
415
417
  def list_devices(usbmux_address: Optional[str] = None) -> list[MuxDevice]:
416
418
  mux = create_mux(usbmux_address=usbmux_address)
417
- mux.get_device_list(0.1)
418
- devices = mux.devices
419
- mux.close()
419
+ try:
420
+ mux.get_device_list(0.1)
421
+ devices = mux.devices
422
+ finally:
423
+ mux.close()
420
424
  return devices
421
425
 
422
426
 
pymobiledevice3/utils.py CHANGED
@@ -45,7 +45,7 @@ def asyncio_print_traceback(f: Callable):
45
45
  async def wrapper(*args, **kwargs):
46
46
  try:
47
47
  return await f(*args, **kwargs)
48
- except Exception as e: # noqa: E72
48
+ except (Exception, RuntimeError) as e: # noqa: E72
49
49
  if not isinstance(e, asyncio.CancelledError):
50
50
  traceback.print_exc()
51
51
  raise
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymobiledevice3
3
- Version: 4.27.7
3
+ Version: 5.0.1
4
4
  Summary: Pure python3 implementation for working with iDevices (iPhone, etc...)
5
5
  Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
6
6
  Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
@@ -47,7 +47,6 @@ Requires-Dist: nest_asyncio>=1.5.5
47
47
  Requires-Dist: Pillow
48
48
  Requires-Dist: inquirer3>=0.6.0
49
49
  Requires-Dist: ipsw_parser>=1.3.4
50
- Requires-Dist: zeroconf>=0.132.2
51
50
  Requires-Dist: ifaddr
52
51
  Requires-Dist: hyperframe
53
52
  Requires-Dist: srptools
@@ -7,35 +7,35 @@ misc/remotexpc_sniffer.py,sha256=EThsKN0Vbs-mnLKCDXeooqg0MdpSkjwhAZHZwvhI458,797
7
7
  misc/understanding_idevice_protocol_layers.md,sha256=8tEqRXWOUPoxOJLZVh7C7H9JGCh2sQ3B5UH8_AymaQc,18805
8
8
  misc/usbmux_sniff.sh,sha256=iWtbucOEQ9_UEFXk9x-2VNt48Jg5zrPsnUbZ_LfZxwA,212
9
9
  pymobiledevice3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- pymobiledevice3/__main__.py,sha256=1nv18QRgR_FDq5rE95uhdZGOQ6xkPzNDrcMzQQs8ZZ4,11697
11
- pymobiledevice3/_version.py,sha256=o71ypd5ta4I52mZXxyMHxfYh6TBRnN5IHKzT1nOt2gI,706
12
- pymobiledevice3/bonjour.py,sha256=-Q_TLBGJ6qW3CX_DgBcz-CXfWSwxWVQ2L64hk6PxnDY,5631
10
+ pymobiledevice3/__main__.py,sha256=viUbhGzaoDi18zu5crX33PMws4qNBjBTwnaK5rAaObY,11651
11
+ pymobiledevice3/_version.py,sha256=MpPN0ZsEisc17aqn7bpe-bL3iBKNBaREenP6NUe6-4s,704
12
+ pymobiledevice3/bonjour.py,sha256=_f5RQs9uLDjDFsXMvykQs8vFoGJXiw6xfth86qewEGA,13719
13
13
  pymobiledevice3/ca.py,sha256=mTvWdSjTZw6Eb-22-IZ323GyA1G6CXYmdPedImTjm3A,10542
14
14
  pymobiledevice3/common.py,sha256=-PG6oaUkNFlB3jb7E0finMrX8wqhkS-cuTAfmLvZUmc,329
15
15
  pymobiledevice3/exceptions.py,sha256=VqWB6WWoMrXt8GDdKqRHeJ1otP-eZIThoHERswXWqpw,10347
16
16
  pymobiledevice3/irecv.py,sha256=FoEln1_zHkAiNcEctB5bStfhKNgniOSg7lg9xcX1U2Q,10596
17
17
  pymobiledevice3/irecv_devices.py,sha256=BG30ecXSChxdyYCCGIrIO0sVWT31hbKymB78nZWVfWc,38506
18
- pymobiledevice3/lockdown.py,sha256=xejqmSLhJsvM-F4rs4InxtVVtSYYSN3VJXnxd-ijspI,38814
18
+ pymobiledevice3/lockdown.py,sha256=jVrw--ifD8ewGwp5fZVYdoQDuaUiSckZ7fnB8dDtc58,38615
19
19
  pymobiledevice3/lockdown_service_provider.py,sha256=l5N72tiuI-2uowk8wu6B7qkjY2UmqQsnhdJqvJy3I8A,1744
20
20
  pymobiledevice3/pair_records.py,sha256=Tr28mlBWPXvOF7vdKBDOuw1rCRwm6RViDTGbikfP77I,6034
21
21
  pymobiledevice3/service_connection.py,sha256=_-PTLFr3krtwEBNHEKXCd_2eOGwMpbsfPbB8AX2uN-g,14861
22
22
  pymobiledevice3/tcp_forwarder.py,sha256=TVtIHn4hFlNIMEYXW9nwdSEhLfHaEHf4jkMsfJXLrTA,8906
23
- pymobiledevice3/usbmux.py,sha256=CvJ_NgH77wcfF7ZAQuLGHTIYkuWvhXPYZNQNR7-Jf8A,16820
24
- pymobiledevice3/utils.py,sha256=ybli_l8JIG2usFiToAsVYe0Ymg3q0bcpKqmYUF_wpi8,2179
23
+ pymobiledevice3/usbmux.py,sha256=NSgcgEbaFxGqyyYuZm4SgLx1DPdkP1oeGRLZ8bEkXes,16916
24
+ pymobiledevice3/utils.py,sha256=X3hU3wf_REUPRS-XtLgGgI2pxIwDGZP0RpZvZf7hOBY,2195
25
25
  pymobiledevice3/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  pymobiledevice3/cli/activation.py,sha256=mF64abX7d0bbyALVC-f_9rjc1DuB6mukP3Zwg9Hoj1Y,1321
27
27
  pymobiledevice3/cli/afc.py,sha256=z-qnBVUPA4uOnXADkYVyRJxeibRDFF3j5LejHt_6UW4,2129
28
28
  pymobiledevice3/cli/amfi.py,sha256=6hlqKrKOFj0secUnLQ8grDDnnh3fRsO6x_vo40oy22w,963
29
29
  pymobiledevice3/cli/apps.py,sha256=LH75A1gDRGP0nWO4QFcOUDg0EdphkGuYnWJgIQHrIBg,3859
30
30
  pymobiledevice3/cli/backup.py,sha256=SyHojiRRguxdkAPMz_Rp_9-zJNeuOtmpa0imdPN12-4,6691
31
- pymobiledevice3/cli/bonjour.py,sha256=qWFH05BZ-FlnSilVP0PMzPUidfBs5LPdepMhPyIliFE,2806
31
+ pymobiledevice3/cli/bonjour.py,sha256=X5W-5rPLX3xAwEeQJLPB_iOhdHcOL9ePkrm3xx4-Qic,2854
32
32
  pymobiledevice3/cli/cli_common.py,sha256=lQFhkTwPfi1UYFkMiDc-jrId2s2yHwzF5lFTK0dXM_s,12945
33
33
  pymobiledevice3/cli/companion_proxy.py,sha256=ey0X3moJ49zVJoNCpRMMHmf9fBZfdqimhz2VCA35oII,581
34
34
  pymobiledevice3/cli/completions.py,sha256=t8oryezQTcWDno_E2Cch7o1f-qURVL9M1Z4o6uLA_kM,1722
35
35
  pymobiledevice3/cli/crash.py,sha256=m1vs0_KUy4cxu8vHYjn7olay8oPQGTFZqMCHspnGpVs,3181
36
36
  pymobiledevice3/cli/developer.py,sha256=qSGvUZPVCwJZQaE9jF2vk-0Fp3x_2-wIlFjy-QoM5cI,61471
37
37
  pymobiledevice3/cli/diagnostics.py,sha256=VDWr41ryIZcpuQp47nQSzCiSuIILExqGSrwFizXCIkI,3641
38
- pymobiledevice3/cli/lockdown.py,sha256=498SgKdIC_YaoEjVtQQvo8bvv8GDeUTY8yWh4isy_qc,6941
38
+ pymobiledevice3/cli/lockdown.py,sha256=AV_7snLEkc9mbwWVlWg1Ki0tWQMtPHReziun_lxjNvY,7133
39
39
  pymobiledevice3/cli/mounter.py,sha256=AnNneNF_kW7XnBMe4V5cvlbLYd_mAP4tuB3PXLQpeiA,7724
40
40
  pymobiledevice3/cli/notification.py,sha256=vqn8uPslr7A9HiZ4yrs7YKF2VLS7Nk4G7ab5ELljpVQ,1962
41
41
  pymobiledevice3/cli/pcap.py,sha256=KzFxXWFRYWNOEJE1XAuMF2cG8I4k5wFVcMRhSdY4GQg,2188
@@ -43,7 +43,7 @@ pymobiledevice3/cli/power_assertion.py,sha256=aTlesowRyrbd9JXebEZe9SomTkDkZaAXIO
43
43
  pymobiledevice3/cli/processes.py,sha256=XNJe2KaacP7c-1NtR_HF6Gd5rByyj3vpyyT_xEntIbA,1102
44
44
  pymobiledevice3/cli/profile.py,sha256=WT8hgYOmkOHUlWtEz-BoBelCerT70TpwBBzJC8wRLmY,7939
45
45
  pymobiledevice3/cli/provision.py,sha256=yWabJrieISrBfFo7vCFIAM8xXLG-8_9qRe1igkTHIA0,1967
46
- pymobiledevice3/cli/remote.py,sha256=2XFa0x1EwPoRpndizM70QrKgPPj4BELpnoN1VZZUB5Q,11969
46
+ pymobiledevice3/cli/remote.py,sha256=n_PbPnUqnQRYxVG-y8rERmWu__64OY0mDx12mX62pRg,11999
47
47
  pymobiledevice3/cli/restore.py,sha256=vg3yjKOjsONUUzPp-XHIjNGMV8qCfptJrz6eJzG2diY,8172
48
48
  pymobiledevice3/cli/springboard.py,sha256=pYMqnD0zN_ETIASPqxBohi54F2HMC9jCILW4epVaaIk,3140
49
49
  pymobiledevice3/cli/syslog.py,sha256=JfLhjyVAeRx16VC4BsAu308rABjcIQX8DB7vbVKGiic,7462
@@ -60,8 +60,8 @@ pymobiledevice3/remote/module_imports.py,sha256=DwExSL1r4kkFIWmXiQpqPo-cGl4duYd3
60
60
  pymobiledevice3/remote/remote_service.py,sha256=fCyzm4oT_WEorAXVHVLYnIOyTOuMGhX69Co3HkUdRYY,867
61
61
  pymobiledevice3/remote/remote_service_discovery.py,sha256=iqPE1PiDDB2ISK-ThuUPEiSU9ETZ-FGTcANhb6MrWmo,7156
62
62
  pymobiledevice3/remote/remotexpc.py,sha256=KbFHaH4D3RnaATve6kaIpJMHNF8H-kdhbRbEbxFmO6w,8082
63
- pymobiledevice3/remote/tunnel_service.py,sha256=zVg9t7Z_zzK4Rav8Xn_UEanIXTzBvcjEsd_-bBYs1CE,46451
64
- pymobiledevice3/remote/utils.py,sha256=BgUODRwkET5lyloZxJ-PrVZqTvyOlBuJ-MM7OCSqZ9g,2506
63
+ pymobiledevice3/remote/tunnel_service.py,sha256=LhPCduH4mNU8sACGI3aJeXpH0UjPfvsjm0FGA4QIV_4,46830
64
+ pymobiledevice3/remote/utils.py,sha256=PV9tICVY6-L7eoqRF1yNmOGxdC2kp9h0kBqeoIAo4pA,2530
65
65
  pymobiledevice3/remote/xpc_message.py,sha256=-nVbf88ZN4ZNxLg6cOq4FfeKXYAoVRKnwGdfe7s-sZE,9336
66
66
  pymobiledevice3/remote/core_device/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
67
  pymobiledevice3/remote/core_device/app_service.py,sha256=x_K-3IA4NWG-skyffKyeGrS7slAbn3MsVLhdY62FSh0,5066
@@ -138,7 +138,7 @@ pymobiledevice3/services/dvt/instruments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5
138
138
  pymobiledevice3/services/dvt/instruments/activity_trace_tap.py,sha256=SARFCaEhDxams9slRKZBBiZDCmR6WDlRdho3mxZGNLY,8769
139
139
  pymobiledevice3/services/dvt/instruments/application_listing.py,sha256=6zWnYUyaxNFudrZo0oKGMTYG3T4sTm2w2XKi-jK-59E,666
140
140
  pymobiledevice3/services/dvt/instruments/condition_inducer.py,sha256=u7CfKvS2dkL3xzbmU9e8zWY29RKRPuAqi3PT6REErpQ,1243
141
- pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py,sha256=YeV4xiI8QMc8O6Su0s6h7GiS27RhE14z9U9dlr7mV5k,27877
141
+ pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py,sha256=XYV_b-LiryH7UEoeyIlMJ7UFVmRAabp6RT7RLJQ_57o,30499
142
142
  pymobiledevice3/services/dvt/instruments/device_info.py,sha256=dP6PEW62MsRS8hUy3i000wwI2tE8jek_GvOmT1cjMUE,3085
143
143
  pymobiledevice3/services/dvt/instruments/energy_monitor.py,sha256=ZzkoC1wyK1zYskiXDtUoEa9PPWnDM9WLl4tZWxfVl-k,892
144
144
  pymobiledevice3/services/dvt/instruments/graphics.py,sha256=KjdO6o_rDsD1YfvW8rW2nOj0N7JfPblFTOlR9XIwwXY,588
@@ -164,10 +164,10 @@ pymobiledevice3/services/web_protocol/session_protocol.py,sha256=7dJkFyivu554K6I
164
164
  pymobiledevice3/services/web_protocol/switch_to.py,sha256=hDddJUEePbRN-8xlllOeGhnYvE4NEnd8JJIlosLMB9c,2880
165
165
  pymobiledevice3/tunneld/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
166
166
  pymobiledevice3/tunneld/api.py,sha256=EfGKXEWhsMSB__menPmRmL9R6dpazVJDUy7B3pn05MM,2357
167
- pymobiledevice3/tunneld/server.py,sha256=L_98QatvVuyiXexoHF5rA0V56wC84VLeKhLyiFWwHrc,22960
168
- pymobiledevice3-4.27.7.dist-info/licenses/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
169
- pymobiledevice3-4.27.7.dist-info/METADATA,sha256=SeVtOrCTF3zAP9RVUQWVMVUsbhFVazGwlJutdprYp08,17450
170
- pymobiledevice3-4.27.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
171
- pymobiledevice3-4.27.7.dist-info/entry_points.txt,sha256=jJMlOanHlVwUxcY__JwvKeWPrvBJr_wJyEq4oHIZNKE,66
172
- pymobiledevice3-4.27.7.dist-info/top_level.txt,sha256=MjZoRqcWPOh5banG-BbDOnKEfsS3kCxqV9cv-nzyg2Q,21
173
- pymobiledevice3-4.27.7.dist-info/RECORD,,
167
+ pymobiledevice3/tunneld/server.py,sha256=fbwnKrm4d84MpopWKIWoQF1_ZEUB4vONKmHih6qce_U,25206
168
+ pymobiledevice3-5.0.1.dist-info/licenses/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
169
+ pymobiledevice3-5.0.1.dist-info/METADATA,sha256=s8IX_VJnsx5y6tqtiY5JleNQhacBm6kN3eJVvur2GqY,17416
170
+ pymobiledevice3-5.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
171
+ pymobiledevice3-5.0.1.dist-info/entry_points.txt,sha256=jJMlOanHlVwUxcY__JwvKeWPrvBJr_wJyEq4oHIZNKE,66
172
+ pymobiledevice3-5.0.1.dist-info/top_level.txt,sha256=MjZoRqcWPOh5banG-BbDOnKEfsS3kCxqV9cv-nzyg2Q,21
173
+ pymobiledevice3-5.0.1.dist-info/RECORD,,