Skip to content

Honour USBMUXD_SOCKET_ADDRESS in the device listener - #441

Open
Folkman wants to merge 1 commit into
google:masterfrom
Folkman:usbmuxd-socket-address
Open

Folkman wants to merge 1 commit into
google:masterfrom
Folkman:usbmuxd-socket-address

Conversation

@Folkman

@Folkman Folkman commented Sep 20, 2026 •

Copy link
Copy Markdown

The problem

libusbmuxd reads USBMUXD_SOCKET_ADDRESS so the idevice_* tools can drive a device attached to a different machine. dl_connect() doesn't go through libusbmuxd — the comment above it explains that usbmuxd_subscribe() is threaded and does blocking reads while this listener wants a select()-able fd — so it opens the usbmuxd socket itself, and always used the local Unix socket.

On a host configured for a remote usbmuxd, that produces a confusing split:

$ export USBMUXD_SOCKET_ADDRESS=10.0.0.2:27015
$ idevice_id -l
<udid>
$ ios_webkit_debug_proxy
No device found, is it plugged in?

Same machine, same library, same phone. This comes up whenever the device is attached to a Windows or macOS box and the proxy runs on a Linux host (or in a VM/container) reaching usbmuxd over TCP.

The change

dl_connect() now reads the variable, mirroring libusbmuxd's connect_usbmuxd_socket() so the two agree on what an address means:

USBMUXD_SOCKET_ADDRESS Behaviour
unset / empty local Unix socket (unchanged)
UNIX:/path that Unix socket — exact case, as upstream
host:port TCP; port must be an entire, valid number in 1..65535
[::1]:27015 brackets stripped before getaddrinfo()
no port, host:, host:abc, host:99999 falls back to the local socket, as upstream

Deliberately matching libusbmuxd rather than being more permissive: a bare host with no port does not default to 27015, and a malformed address falls back rather than failing, because that is what every other libimobiledevice tool does with the same string. UNIX: is matched case-sensitively for the same reason.

On provenance: the behaviour is matched to libusbmuxd's connect_usbmuxd_socket() (LGPL-2.1) so the two agree on what an address means, but the implementation here was written independently against this BSD-licensed file — no code was copied from it. The differences are visible in the approach: this version parses in place without allocating, and calls getaddrinfo() directly rather than going through a socket_connect() helper.

Addresses resolve through getaddrinfo() with AF_UNSPEC, so IPv6 remotes work. A resolver failure now reports gai_strerror() instead of a bare message.

Testing

Built with the project's own -Wall -Werror, no new warnings.

Verified against a real device (iPhone SE, iOS 15.8.8) attached to a Windows host running usbmuxd, with the proxy on Linux:

  • <host>:27015 — device found, proxy serves tabs on 9222.
  • [::1]:27015 — before this change, cannot resolve "[::1]:27015"; after, it reaches connect() (Connection refused, nothing listening there), confirming the brackets are stripped.
  • <host> / <host>: / <host>:abc / <host>:99999 / UNIX:/var/run/usbmuxd / lowercase unix:... / unset — all fall back to the local socket.
  • With the variable unset the Unix-socket path is byte-for-byte the original code.

Written with Claude Code.

@google-cla

google-cla Bot commented Sep 20, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

libusbmuxd reads USBMUXD_SOCKET_ADDRESS so the idevice_* tools can drive a
device attached to another machine. dl_connect() does not go through
libusbmuxd -- the comment above it explains that usbmuxd_subscribe() is
threaded and does blocking reads, while this listener wants a select()-able
fd -- so it opens the usbmuxd socket itself, and in doing so it always used
the local Unix socket.

The result is a confusing split: on a host configured for a remote usbmuxd,
idevice_id -l lists the device while ios_webkit_debug_proxy reports
"No device found, is it plugged in?".

Read the variable in dl_connect(), mirroring libusbmuxd's
connect_usbmuxd_socket() so the two agree on what an address means:

  - "UNIX:/path" connects to that Unix socket (exact case, as upstream).
  - "host:port" connects over TCP; the port must be an entire, valid
    number in 1..65535.
  - A bracketed IPv6 literal such as "[::1]:27015" has its brackets
    stripped before it reaches getaddrinfo(), which does not accept them.
  - Anything unusable -- no port, a trailing colon, a non-numeric or
    out-of-range port -- falls back to the local socket rather than
    failing, again as upstream does.

Addresses are resolved with getaddrinfo()/AF_UNSPEC, so IPv6 remotes work.
A resolver failure now reports gai_strerror(); the Unix-socket path is
unchanged when the variable is unset.
@Folkman
Folkman force-pushed the usbmuxd-socket-address branch from cbbdf87 to c24327e Compare September 20, 2026 02:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant