From c24327eb283b9018d1eb546ac908cf6d1cda3252 Mon Sep 17 00:00:00 2001 From: Lee Folkman Date: Sat, 19 Sep 2026 21:46:18 -0400 Subject: [PATCH] Honour USBMUXD_SOCKET_ADDRESS in the device listener 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. --- src/device_listener.c | 111 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 13 deletions(-) diff --git a/src/device_listener.c b/src/device_listener.c index cd3ae4fb..51b2cdc7 100644 --- a/src/device_listener.c +++ b/src/device_listener.c @@ -18,6 +18,7 @@ #ifdef WIN32 #include #else +#include #include #include #include @@ -89,22 +90,106 @@ int dl_connect(int recv_timeout) { } } #else + // libusbmuxd lets USBMUXD_SOCKET_ADDRESS point the idevice_* tools at a + // usbmuxd on another machine. This listener opens the socket itself rather + // than going through libusbmuxd (see above), so it has to read the variable + // too; otherwise the proxy reports "No device found" on a host where + // idevice_id lists the device. The parsing mirrors libusbmuxd's + // connect_usbmuxd_socket(), including its fallback to the local socket when + // the address is not usable. const char *filename = USBMUXD_FILE_PATH; - struct stat fst; - if (stat(filename, &fst) || - !S_ISSOCK(fst.st_mode) || - (fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - return -1; + const char *socket_addr = getenv("USBMUXD_SOCKET_ADDRESS"); + + fd = -1; + if (socket_addr && !strncmp(socket_addr, "UNIX:", 5)) { + if (socket_addr[5]) { + filename = socket_addr + 5; + } + } else if (socket_addr) { + const char *colon = strrchr(socket_addr, ':'); + const char *host_start = socket_addr; + const char *host_end = colon; + long port = 0; + size_t host_len = 0; + + if (colon) { + char *endp = NULL; + port = strtol(colon + 1, &endp, 10); + if (!endp || *endp || port <= 0 || port > 65535) { + port = 0; + } + if (*socket_addr == '[') { + host_start = socket_addr + 1; + while (host_end > host_start && host_end[-1] != ']') { + host_end--; + } + if (host_end > host_start) { + host_end--; + } + } + if (port > 0) { + host_len = (size_t)(host_end - host_start); + } + } + + if (host_len > 0 && host_len < NI_MAXHOST) { + char host[NI_MAXHOST]; + char service[6]; + struct addrinfo hints; + struct addrinfo *results = NULL; + struct addrinfo *it = NULL; + int err; + + memcpy(host, host_start, host_len); + host[host_len] = '\0'; + snprintf(service, sizeof(service), "%ld", port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + err = getaddrinfo(host, service, &hints, &results); + if (err) { + fprintf(stderr, "device_listener: could not resolve \"%s\": %s\n", + socket_addr, gai_strerror(err)); + return -1; + } + for (it = results; it; it = it->ai_next) { + fd = socket(it->ai_family, it->ai_socktype, it->ai_protocol); + if (fd < 0) { + continue; + } + if (!connect(fd, it->ai_addr, it->ai_addrlen)) { + break; + } + close(fd); + fd = -1; + } + freeaddrinfo(results); + if (fd < 0) { + perror("Could not connect to remote usbmuxd"); + return -1; + } + } } - struct sockaddr_un name; - name.sun_family = AF_LOCAL; - strncpy(name.sun_path, filename, sizeof(name.sun_path)); - name.sun_path[sizeof(name.sun_path) - 1] = 0; - size_t size = SUN_LEN(&name); - if (connect(fd, (struct sockaddr *)&name, size) < 0) { - close(fd); - return -1; + if (fd < 0) { + struct stat fst; + if (stat(filename, &fst) || + !S_ISSOCK(fst.st_mode) || + (fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + return -1; + } + + struct sockaddr_un name; + name.sun_family = AF_LOCAL; + strncpy(name.sun_path, filename, sizeof(name.sun_path)); + name.sun_path[sizeof(name.sun_path) - 1] = 0; + size_t size = SUN_LEN(&name); + if (connect(fd, (struct sockaddr *)&name, size) < 0) { + close(fd); + return -1; + } } if (recv_timeout < 0) {