summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml73
-rw-r--r--Makefile.am8
-rw-r--r--NEWS26
-rw-r--r--README.md183
-rwxr-xr-xautogen.sh42
-rw-r--r--configure.ac39
-rw-r--r--docs/usbmuxd.88
-rwxr-xr-xgit-version-gen19
-rw-r--r--m4/as-compiler-flag.m44
-rw-r--r--src/Makefile.am37
-rw-r--r--src/client.c172
-rw-r--r--src/conf.c39
-rw-r--r--src/device.c98
-rw-r--r--src/main.c304
-rw-r--r--src/preflight.c70
-rw-r--r--src/usb.c489
-rw-r--r--src/usb.h6
-rw-r--r--src/usbmuxd-proto.h2
-rw-r--r--src/utils.c248
-rw-r--r--src/utils.h43
-rw-r--r--systemd/Makefile.am2
-rw-r--r--systemd/usbmuxd.service.in2
-rw-r--r--udev/39-usbmuxd.rules.in11
23 files changed, 1191 insertions, 734 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..f8c3f94
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,73 @@
+name: build
+
+on: [push]
+
+jobs:
+ build-linux-ubuntu:
+ runs-on: ubuntu-latest
+ steps:
+ - name: install dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install libusb-1.0-0-dev
+ - name: prepare environment
+ run: |
+ echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV
+ - name: fetch libplist
+ uses: dawidd6/action-download-artifact@v2
+ with:
+ github_token: ${{secrets.GITHUB_TOKEN}}
+ workflow: build.yml
+ name: libplist-latest_${{env.target_triplet}}
+ repo: libimobiledevice/libplist
+ - name: fetch libusbmuxd
+ uses: dawidd6/action-download-artifact@v2
+ with:
+ github_token: ${{secrets.GITHUB_TOKEN}}
+ workflow: build.yml
+ name: libusbmuxd-latest_${{env.target_triplet}}
+ repo: libimobiledevice/libusbmuxd
+ - name: fetch libimobiledevice-glue
+ uses: dawidd6/action-download-artifact@v2
+ with:
+ github_token: ${{secrets.GITHUB_TOKEN}}
+ workflow: build.yml
+ name: libimobiledevice-glue-latest_${{env.target_triplet}}
+ repo: libimobiledevice/libimobiledevice-glue
+ - name: fetch libimobiledevice
+ uses: dawidd6/action-download-artifact@v2
+ with:
+ github_token: ${{secrets.GITHUB_TOKEN}}
+ workflow: build.yml
+ name: libimobiledevice-latest_${{env.target_triplet}}
+ repo: libimobiledevice/libimobiledevice
+ - name: install external dependencies
+ run: |
+ mkdir extract
+ for I in *.tar; do
+ tar -C extract -xvf $I
+ done
+ sudo cp -r extract/* /
+ sudo ldconfig
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ - name: autogen
+ run: ./autogen.sh PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
+ - name: print config.log
+ if: ${{ failure() }}
+ run: cat config.log
+ - name: make
+ run: make
+ - name: make install
+ run: sudo make install
+ - name: prepare artifact
+ run: |
+ mkdir -p dest
+ DESTDIR=`pwd`/dest make install
+ tar -C dest -cf usbmuxd.tar usr lib
+ - name: publish artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: usbmuxd-latest_${{env.target_triplet}}
+ path: usbmuxd.tar
diff --git a/Makefile.am b/Makefile.am
index a4d86c0..6da23b6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,8 +2,12 @@ AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src $(UDEV_SUB) $(SYSTEMD_SUB) docs
-EXTRA_DIST = docs COPYING.GPLv2 COPYING.GPLv3
+EXTRA_DIST = \
+ docs \
+ COPYING.GPLv2 \
+ COPYING.GPLv3 \
+ README.md
-DISTCHECK_CONFIGURE_FLAGS = \
+DISTCHECK_CONFIGURE_FLAGS = \
--with-udevrulesdir=$$dc_install_base/$(udevrulesdir) \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) \ No newline at end of file
diff --git a/NEWS b/NEWS
index 7430c27..b2ba013 100644
--- a/NEWS
+++ b/NEWS
@@ -6,8 +6,34 @@ Version 1.1.1
- Use clock_gettime() instead of gettimeofday() to avoid timing issues
when calculating packet timeouts
- Get correct USB device speed instead of hardcoded value
+ - Bump libusb dependency to 1.0.9
- Use non-blocking sockets for client communication to avoid hanging
- Use correct manual section (8) for manpage
+ - Log pid of connecting clients if supported
+ - Implement device discovery using libusb hotplug events
+ - Fix wrong timeout value in debug messages
+ - Log error message if writing a config file fails
+ - Fix blocking by using libusb asynchronous I/O for getting initial device
+ information
+ - Tag all udev events with systemd tag
+ - Fix occasional USB reconfiguration due to udev rules being run again
+ - Fix wrong timestamps when running in foreground
+ - Set socket options for client connections to improve performance
+ - Implement "ListListeners" usbmux command handling
+ - Bump libimobiledevice dependency to 1.3.0
+ - Bump libplist dependency to 2.2.0
+ - Add support for iPhone XS/XR UDID format
+ - Add option to allow logging to dedicated logfile
+ - Convert README file to markdown format
+ - Fix USB reconnection issues on virtual machines with iOS 11+ devices
+ - Add support for connecting with T2 chip
+ - Various memory leak, deadlock and invalid free fixes
+ - Show actual libusb version in debug message on startup
+ - Enable libusb debugging output
+ - Log client process name alongside pid if possible on Linux
+ - Unify and improve log message output
+ - Improve README.md with project description, installation, contributing and
+ usage sections
Version 1.1.0
~~~~~~~~~~~~~
diff --git a/README.md b/README.md
index 9a2d869..8249358 100644
--- a/README.md
+++ b/README.md
@@ -1,84 +1,159 @@
# usbmuxd
-## About
+*A socket daemon to multiplex connections from and to iOS devices.*
-A socket daemon to multiplex connections from and to iOS devices.
+![build](https://github.com/libimobiledevice/usbmuxd/actions/workflows/build.yml/badge.svg)
-## Background
+## Features
usbmuxd stands for "USB multiplexing daemon". This daemon is in charge of
-multiplexing connections over USB to an iOS device. To users, it means
-you can sync your music, contacts, photos, etc. over USB. To developers, it
-means you can connect to any listening localhost socket on the device. usbmuxd
-is not used for tethering data transfer which uses a dedicated USB interface as
-a virtual network device. Multiple connections to different TCP ports can happen
-in parallel. The higher-level layers are handled by libimobiledevice.
-
-When usbmuxd is running (normally started or stopped as a result of _udev_
-auto-insertion messages, or by _systemd_) it provides a socket interface in
-`/var/run/usbmuxd` that is designed to be compatible with the socket interface
-that is provided on macOS.
-
-You should also create a `usbmux` user that has access to USB devices on your
-system. Alternatively, you can pass a different username using the `-U` argument.
-
-The daemon also manages pairing records with iOS devices and the host in
-`/var/lib/lockdown` (Linux) or `/var/db/lockdown` (macOS).
-Ensure proper permissions are setup for the daemon to access the directory.
-
-## Requirements
-
-Development Packages of:
-* libimobiledevice
-* libplist
-* libusb
-
-Software:
-* make
-* autoheader
-* automake
-* autoconf
-* libtool
-* pkg-config
-* gcc or clang
-* udev (Linux only)
+multiplexing connections over USB to an iOS device.
+
+To users, it means you can use various applications to interact with your
+device.
+
+To developers, it means you can connect to any listening localhost socket on
+the device.
+
+Some key features are:
+
+- **Implementation**: Open-Source implementation of proprietary usbmuxd daemon
+- **Cross-Platform:** Tested on Linux, macOS, Windows and Android platforms
+- **Linux**: Supports udev and systemd for automatic activation
+- **Compatibility**: Supports latest device firmware releases
+- **Scalability**: Supports multiple connections to different ports in parallel
+
+usbmuxd is not used for tethering data transfers which uses a dedicated USB
+interface to act as a virtual network device.
+
+The higher-level layers, especially if you want to write an application to
+interact with the device, are handled by [libimobiledevice](https://github.com/libimobiledevice/libimobiledevice.git).
+
+The low-level layer is handled by [libusbmuxd](https://github.com/libimobiledevice/libusbmuxd.git).
+
+## Installation / Getting started
+
+### Debian / Ubuntu Linux
+
+First install all required dependencies and build tools:
+```shell
+sudo apt-get install \
+ build-essential \
+ pkg-config \
+ checkinstall \
+ git \
+ autoconf \
+ automake \
+ libtool-bin \
+ libplist-dev \
+ libusbmuxd-dev \
+ libimobiledevice-dev \
+ libimobiledevice-glue-dev \
+ libusb-1.0-0-dev \
+ udev
+```
-Optional:
-* systemd (Linux only)
+If systemd is not installed and should control spawning the daemon use:
+```shell
+sudo apt-get install \
+ systemd
+```
-## Installation
+Then clone the actual project repository:
+```shell
+git clone https://github.com/libimobiledevice/usbmuxd.git
+cd usbmuxd
+```
-To compile run:
+Now you can build and install it:
+```shell
+./autogen.sh
+make
+sudo make install
+```
+If you require a custom prefix or other option being passed to `./configure`
+you can pass them directly to `./autogen.sh` like this:
```bash
-./autogen.sh
+./autogen.sh --prefix=/opt/local --without-preflight --without-systemd
make
sudo make install
```
+To output a list of available configure options use:
+```bash
+./autogen.sh --help
+```
+
+## Usage
+
The daemon is automatically started by udev or systemd depending on what you
-have configured it on hotplug of an iOS device and exits if the last device
+have configured upon hotplug of an iOS device and exits if the last device
was unplugged.
+When usbmuxd is running it provides a socket interface at `/var/run/usbmuxd`
+that is designed to be compatible with the socket interface that is provided
+on macOS.
+
+You should also create an `usbmux` user that has access to USB devices on your
+system. Alternatively, just pass a different username using the `-U` argument.
+
+The daemon also manages pairing records with iOS devices and the host in
+`/var/lib/lockdown` (Linux) or `/var/db/lockdown` (macOS).
+
+Ensure proper permissions are setup for the daemon to access the directory.
+
For debugging purposes it is helpful to start usbmuxd using the foreground `-f`
argument and enable verbose mode `-v` to get suitable logs.
-## Who/What/Where?
+Please consult the usage information or manual page for a full documentation of
+available command line options:
+```shell
+usbmuxd --help
+man usbmuxd
+```
+
+## Contributing
-* Home: https://www.libimobiledevice.org/
-* Code: `git clone https://git.libimobiledevice.org/usbmuxd.git`
-* Code (Mirror): `git clone https://github.com/libimobiledevice/usbmuxd.git`
-* Tickets: https://github.com/libimobiledevice/usbmuxd/issues
+We welcome contributions from anyone and are grateful for every pull request!
+
+If you'd like to contribute, please fork the `master` branch, change, commit and
+send a pull request for review. Once approved it can be merged into the main
+code base.
+
+If you plan to contribute larger changes or a major refactoring, please create a
+ticket first to discuss the idea upfront to ensure less effort for everyone.
+
+Please make sure your contribution adheres to:
+* Try to follow the code style of the project
+* Commit messages should describe the change well without being too short
+* Try to split larger changes into individual commits of a common domain
+* Use your real name and a valid email address for your commits
+
+We are still working on the guidelines so bear with us!
+
+## Links
+
+* Homepage: https://libimobiledevice.org/
+* Repository: https://git.libimobiledevice.org/usbmuxd.git
+* Repository (Mirror): https://github.com/libimobiledevice/usbmuxd.git
+* Issue Tracker: https://github.com/libimobiledevice/usbmuxd/issues
* Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel
-* IRC: irc://irc.freenode.net#libimobiledevice
* Twitter: https://twitter.com/libimobiledev
+## License
+
+This library and utilities are licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html),
+also included in the repository in the `COPYING.GPLv3` file.
+
## Credits
-The first usbmuxd daemon implementation was authored by Hector Martin.
+The initial usbmuxd daemon implementation was authored by Hector Martin.
+
+Apple, iPhone, iPad, iPod, iPod Touch, Apple TV, Apple Watch, Mac, iOS,
+iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc.
-Apple, iPhone, iPod, and iPod Touch are trademarks of Apple Inc.
-libimobiledevice is an independent software library and has not been
+usbmuxd is an independent software application and has not been
authorized, sponsored, or otherwise approved by Apple Inc.
-README Updated on: 2019-05-16
+README Updated on: 2022-04-04
diff --git a/autogen.sh b/autogen.sh
index 858fca3..5936e8a 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,19 +1,31 @@
#!/bin/sh
-gprefix=`which glibtoolize 2>&1 >/dev/null`
-if [ $? -eq 0 ]; then
- glibtoolize --force
-else
- libtoolize --force
-fi
-aclocal -I m4
-autoheader
-automake --add-missing
-autoconf
-requires_pkgconfig=`which pkg-config 2>&1 >/dev/null`
-if [ $? -ne 0 ]; then
- echo "Missing required pkg-config. Please install it on your system and run again."
-fi
+
+olddir=`pwd`
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+(
+ cd "$srcdir"
+
+ gprefix=`which glibtoolize 2>&1 >/dev/null`
+ if [ $? -eq 0 ]; then
+ glibtoolize --force
+ else
+ libtoolize --force
+ fi
+ aclocal -I m4
+ autoheader
+ automake --add-missing
+ autoconf
+
+ requires_pkgconfig=`which pkg-config 2>&1 >/dev/null`
+ if [ $? -ne 0 ]; then
+ echo "Missing required pkg-config. Please install it on your system and run again."
+ fi
+
+ cd "$olddir"
+)
if [ -z "$NOCONFIGURE" ]; then
- ./configure "$@"
+ $srcdir/configure "$@"
fi
diff --git a/configure.ac b/configure.ac
index 3b2dec0..c51d53a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,30 +1,34 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
-AC_PREREQ(2.64)
-AC_INIT([usbmuxd], [1.1.1], [https://github.com/libimobiledevice/usbmuxd/issues],, [http://libimobiledevice.org])
+AC_PREREQ([2.68])
+AC_INIT([usbmuxd], [m4_esyscmd(./git-version-gen $RELEASE_VERSION)], [https://github.com/libimobiledevice/usbmuxd/issues], [], [https://libimobiledevice.org])
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip check-news])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
AC_CONFIG_SRCDIR([src/])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
+# Check if we have a version defined
+if test -z $PACKAGE_VERSION; then
+ AC_MSG_ERROR([PACKAGE_VERSION is not defined. Make sure to configure a source tree checked out from git or that .tarball-version is present.])
+fi
+
# Checks for programs.
AC_PROG_CC
-AC_PROG_CXX
AM_PROG_CC_C_O
-AC_PROG_LIBTOOL
+LT_INIT
# Checks for libraries.
PKG_CHECK_MODULES(libusb, libusb-1.0 >= 1.0.9)
-PKG_CHECK_MODULES(libplist, libplist >= 1.11)
-PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.2.1, have_limd=yes, have_limd=no)
-AC_CHECK_LIB(pthread, [pthread_create, pthread_mutex_lock], [AC_SUBST(libpthread_LIBS,[-lpthread])], [AC_MSG_ERROR([libpthread is required to build usbmuxd])])
+PKG_CHECK_MODULES(libplist, libplist-2.0 >= 2.3.0)
+PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.3.0, have_limd=yes, have_limd=no)
+PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= 1.0.0)
AC_ARG_WITH([preflight],
[AS_HELP_STRING([--without-preflight],
[do not build with preflight worker support @<:@default=yes@:>@])],
- [with_preflight=no],
+ [with_preflight=$withval],
[with_preflight=yes])
if test "x$have_limd" = "xyes"; then
@@ -38,11 +42,11 @@ if test "x$have_limd" = "xyes"; then
CACHED_CFLAGS="$CFLAGS"
CFLAGS+=" $libimobiledevice_CFLAGS"
AC_CACHE_CHECK(for enum idevice_connection_type, ac_cv_enum_idevice_connection_type,
- AC_TRY_COMPILE([
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
#include <libimobiledevice/libimobiledevice.h>
], [
enum idevice_connection_type conn_type = CONNECTION_USBMUXD;
- ], ac_cv_enum_idevice_connection_type=yes, ac_cv_enum_idevice_connection_type=no))
+ ])], ac_cv_enum_idevice_connection_type=yes, ac_cv_enum_idevice_connection_type=no))
CFLAGS="$CACHED_CFLAGS"
if (test "$ac_cv_enum_idevice_connection_type" = "yes"); then
AC_DEFINE(HAVE_ENUM_IDEVICE_CONNECTION_TYPE, 1, [Define if enum idevice_connection_type is available])
@@ -71,7 +75,7 @@ fi
AC_ARG_WITH([systemd],
[AS_HELP_STRING([--without-systemd],
[do not build with systemd support @<:@default=yes@:>@])],
- [],
+ [with_systemd=$withval],
[with_systemd=yes])
AC_ARG_WITH([systemdsystemunitdir],
@@ -93,7 +97,6 @@ fi
AC_SUBST(udev_activation_rule)
# Checks for header files.
-AC_HEADER_STDC
AC_CHECK_HEADERS([stdint.h stdlib.h string.h])
# Checks for typedefs, structures, and compiler characteristics.
@@ -108,9 +111,7 @@ AC_TYPE_UINT8_T
AC_SEARCH_LIBS([clock_gettime],[rt posix4])
# Checks for library functions.
-AC_FUNC_MALLOC
-AC_FUNC_REALLOC
-AC_CHECK_FUNCS([strcasecmp strdup strerror strndup stpcpy])
+AC_CHECK_FUNCS([strcasecmp strdup strerror strndup malloc realloc])
AC_CHECK_FUNCS([ppoll clock_gettime localtime_r])
# Check for operating system
@@ -157,13 +158,19 @@ AC_SUBST(GLOBAL_CFLAGS)
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
-AC_OUTPUT([
+# workaround for older autoconf versions
+if test "x$runstatedir" == "x"; then
+ runstatedir=$localstatedir/run
+fi
+
+AC_CONFIG_FILES([
Makefile
src/Makefile
udev/Makefile
systemd/Makefile
docs/Makefile
])
+AC_OUTPUT
echo "
Configuration for $PACKAGE $VERSION:
diff --git a/docs/usbmuxd.8 b/docs/usbmuxd.8
index 0a05f12..590afdc 100644
--- a/docs/usbmuxd.8
+++ b/docs/usbmuxd.8
@@ -72,9 +72,9 @@ The first usbmuxd daemon implementation was authored by Hector Martin.
Now mainly developed by Nikias Bassen, Martin Szulecki and contributors (see AUTHORS file).
.SH SEE ALSO
+idevice_id(1), iproxy(1).
-http://www.libimobiledevice.org
-
-http://github.com/libimobiledevice/usbmuxd/
+.SH ON THE WEB
+https://libimobiledevice.org
-idevice_id(1), iproxy(1).
+https://github.com/libimobiledevice/usbmuxd
diff --git a/git-version-gen b/git-version-gen
new file mode 100755
index 0000000..3eb6a42
--- /dev/null
+++ b/git-version-gen
@@ -0,0 +1,19 @@
+#!/bin/sh
+SRCDIR=`dirname $0`
+if test -n "$1"; then
+ VER=$1
+else
+ if test -d "${SRCDIR}/.git" && test -x "`which git`" ; then
+ git update-index -q --refresh
+ if ! VER=`git describe --tags --dirty 2>/dev/null`; then
+ COMMIT=`git rev-parse --short HEAD`
+ DIRTY=`git diff --quiet HEAD || echo "-dirty"`
+ VER=`sed -n '1,/RE/s/Version \(.*\)/\1/p' ${SRCDIR}/NEWS`-git-${COMMIT}${DIRTY}
+ fi
+ else
+ if test -f "${SRCDIR}/.tarball-version"; then
+ VER=`cat "${SRCDIR}/.tarball-version"`
+ fi
+ fi
+fi
+printf %s "$VER"
diff --git a/m4/as-compiler-flag.m4 b/m4/as-compiler-flag.m4
index 0f660cf..baab5d9 100644
--- a/m4/as-compiler-flag.m4
+++ b/m4/as-compiler-flag.m4
@@ -18,7 +18,7 @@ AC_DEFUN([AS_COMPILER_FLAG],
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $1"
- AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])], [flag_ok=yes], [flag_ok=no])
CFLAGS="$save_CFLAGS"
if test "X$flag_ok" = Xyes ; then
@@ -44,7 +44,7 @@ AC_DEFUN([AS_COMPILER_FLAGS],
do
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $each"
- AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])], [flag_ok=yes], [flag_ok=no])
CFLAGS="$save_CFLAGS"
if test "X$flag_ok" = Xyes ; then
diff --git a/src/Makefile.am b/src/Makefile.am
index 9faf204..8a96e46 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,17 +1,32 @@
-AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)
-AM_CFLAGS = $(GLOBAL_CFLAGS) $(libplist_CFLAGS) $(libusb_CFLAGS) $(libimobiledevice_CFLAGS)
-AM_LDFLAGS = $(libplist_LIBS) $(libusb_LIBS) $(libimobiledevice_LIBS) $(libpthread_LIBS)
+AM_CFLAGS = \
+ $(GLOBAL_CFLAGS) \
+ $(libplist_CFLAGS) \
+ $(libusb_CFLAGS) \
+ $(limd_glue_CFLAGS) \
+ $(libimobiledevice_CFLAGS)
+
+AM_LDFLAGS = \
+ $(libplist_LIBS) \
+ $(libusb_LIBS) \
+ $(limd_glue_LIBS) \
+ $(libimobiledevice_LIBS) \
+ $(libpthread_LIBS)
sbin_PROGRAMS = usbmuxd
usbmuxd_CFLAGS = $(AM_CFLAGS)
usbmuxd_LDFLAGS = $(AM_LDFLAGS) -no-undefined
-usbmuxd_SOURCES = client.c client.h \
- device.c device.h \
- preflight.c preflight.h \
- log.c log.h \
- usbmuxd-proto.h usb.c usb.h \
- utils.c utils.h \
- conf.c conf.h \
- main.c
+usbmuxd_SOURCES = \
+ client.c client.h \
+ device.c device.h \
+ preflight.c preflight.h \
+ log.c log.h \
+ usbmuxd-proto.h \
+ usb.c usb.h \
+ utils.c utils.h \
+ conf.c conf.h \
+ main.c
diff --git a/src/client.c b/src/client.c
index 85d0c8b..dbbdd5f 100644
--- a/src/client.c
+++ b/src/client.c
@@ -31,13 +31,15 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include <arpa/inet.h>
-#include <pthread.h>
#include <fcntl.h>
#include <plist/plist.h>
+#include <libimobiledevice-glue/collection.h>
+#include <libimobiledevice-glue/thread.h>
#include "log.h"
#include "usb.h"
@@ -75,9 +77,30 @@ struct mux_client {
};
static struct collection client_list;
-pthread_mutex_t client_list_mutex;
+mutex_t client_list_mutex;
static uint32_t client_number = 0;
+#ifdef SO_PEERCRED
+static char* _get_process_name_by_pid(const int pid)
+{
+ char* name = (char*)calloc(1024, sizeof(char));
+ if(name) {
+ sprintf(name, "/proc/%d/cmdline", pid);
+ FILE* f = fopen(name, "r");
+ if(f) {
+ size_t size;
+ size = fread(name, sizeof(char), 1024, f);
+ if(size > 0) {
+ if('\n' == name[size-1])
+ name[size-1]='\0';
+ }
+ fclose(f);
+ }
+ }
+ return name;
+}
+#endif
+
/**
* Receive raw data from the client socket.
*
@@ -203,32 +226,64 @@ int client_accept(int listenfd)
client->events = POLLIN;
client->info = NULL;
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
client->number = client_number++;
collection_add(&client_list, client);
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
#ifdef SO_PEERCRED
if (log_level >= LL_INFO) {
struct ucred cr;
len = sizeof(struct ucred);
- getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
+ getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
if (getpid() == cr.pid) {
- usbmuxd_log(LL_INFO, "New client on fd %d (self)", client->fd);
+ usbmuxd_log(LL_INFO, "Client %d accepted: %s[%d]", client->fd, PACKAGE_NAME, cr.pid);
} else {
- usbmuxd_log(LL_INFO, "New client on fd %d (pid %d)", client->fd, cr.pid);
+ char* process_name = _get_process_name_by_pid(cr.pid);
+ usbmuxd_log(LL_INFO, "Client %d accepted: %s[%d]", client->fd, process_name, cr.pid);
+ free(process_name);
}
}
#else
- usbmuxd_log(LL_INFO, "New client on fd %d", client->fd);
+ usbmuxd_log(LL_INFO, "Client %d accepted", client->fd);
#endif
return client->fd;
}
void client_close(struct mux_client *client)
{
- usbmuxd_log(LL_INFO, "Disconnecting client fd %d", client->fd);
+ int found = 0;
+ mutex_lock(&client_list_mutex);
+ FOREACH(struct mux_client *lc, &client_list) {
+ if (client == lc) {
+ found = 1;
+ break;
+ }
+ } ENDFOREACH
+ if (!found) {
+ // in case we get called again but client was already freed
+ usbmuxd_log(LL_DEBUG, "%s: ignoring for non-existing client %p", __func__, client);
+ mutex_unlock(&client_list_mutex);
+ return;
+ }
+#ifdef SO_PEERCRED
+ if (log_level >= LL_INFO) {
+ struct ucred cr;
+ socklen_t len = sizeof(struct ucred);
+ getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
+
+ if (getpid() == cr.pid) {
+ usbmuxd_log(LL_INFO, "Client %d is going to be disconnected: %s[%d]", client->fd, PACKAGE_NAME, cr.pid);
+ } else {
+ char* process_name = _get_process_name_by_pid(cr.pid);
+ usbmuxd_log(LL_INFO, "Client %d is going to be disconnected: %s[%d]", client->fd, process_name, cr.pid);
+ free(process_name);
+ }
+ }
+#else
+ usbmuxd_log(LL_INFO, "Client %d is going to be disconnected", client->fd);
+#endif
if(client->state == CLIENT_CONNECTING1 || client->state == CLIENT_CONNECTING2) {
usbmuxd_log(LL_INFO, "Client died mid-connect, aborting device %d connection", client->connect_device);
client->state = CLIENT_DEAD;
@@ -239,29 +294,28 @@ void client_close(struct mux_client *client)
free(client->ib_buf);
plist_free(client->info);
- pthread_mutex_lock(&client_list_mutex);
collection_remove(&client_list, client);
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
free(client);
}
void client_get_fds(struct fdlist *list)
{
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
FOREACH(struct mux_client *client, &client_list) {
fdlist_add(list, FD_CLIENT, client->fd, client->events);
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
}
-static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length)
+static int output_buffer_add_message(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length)
{
struct usbmuxd_header hdr;
hdr.version = client->proto_version;
hdr.length = sizeof(hdr) + payload_length;
hdr.message = msg;
hdr.tag = tag;
- usbmuxd_log(LL_DEBUG, "send_pkt fd %d tag %d msg %d payload_length %d", client->fd, tag, msg, payload_length);
+ usbmuxd_log(LL_DEBUG, "Client %d output buffer got tag %d msg %d payload_length %d", client->fd, tag, msg, payload_length);
uint32_t available = client->ob_capacity - client->ob_size;
/* the output buffer _should_ be large enough, but just in case */
@@ -285,14 +339,14 @@ static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtyp
return hdr.length;
}
-static int send_plist_pkt(struct mux_client *client, uint32_t tag, plist_t plist)
+static int send_plist(struct mux_client *client, uint32_t tag, plist_t plist)
{
int res = -1;
char *xml = NULL;
uint32_t xmlsize = 0;
plist_to_xml(plist, &xml, &xmlsize);
if (xml) {
- res = send_pkt(client, tag, MESSAGE_PLIST, xml, xmlsize);
+ res = output_buffer_add_message(client, tag, MESSAGE_PLIST, xml, xmlsize);
free(xml);
} else {
usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__);
@@ -308,11 +362,11 @@ static int send_result(struct mux_client *client, uint32_t tag, uint32_t result)
plist_t dict = plist_new_dict();
plist_dict_set_item(dict, "MessageType", plist_new_string("Result"));
plist_dict_set_item(dict, "Number", plist_new_uint(result));
- res = send_plist_pkt(client, tag, dict);
+ res = send_plist(client, tag, dict);
plist_free(dict);
} else {
/* binary packet */
- res = send_pkt(client, tag, MESSAGE_RESULT, &result, sizeof(uint32_t));
+ res = output_buffer_add_message(client, tag, MESSAGE_RESULT, &result, sizeof(uint32_t));
}
return res;
}
@@ -378,7 +432,7 @@ static int send_device_list(struct mux_client *client, uint32_t tag)
free(devs);
plist_dict_set_item(dict, "DeviceList", devices);
- res = send_plist_pkt(client, tag, dict);
+ res = send_plist(client, tag, dict);
plist_free(dict);
return res;
}
@@ -390,7 +444,7 @@ static int send_listener_list(struct mux_client *client, uint32_t tag)
plist_t dict = plist_new_dict();
plist_t listeners = plist_new_array();
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
FOREACH(struct mux_client *lc, &client_list) {
if (lc->state == CLIENT_LISTEN) {
plist_t n = NULL;
@@ -437,10 +491,10 @@ static int send_listener_list(struct mux_client *client, uint32_t tag)
plist_array_append_item(listeners, l);
}
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
plist_dict_set_item(dict, "ListenerList", listeners);
- res = send_plist_pkt(client, tag, dict);
+ res = send_plist(client, tag, dict);
plist_free(dict);
return res;
@@ -456,7 +510,7 @@ static int send_system_buid(struct mux_client *client, uint32_t tag)
plist_t dict = plist_new_dict();
plist_dict_set_item(dict, "BUID", plist_new_string(buid));
free(buid);
- res = send_plist_pkt(client, tag, dict);
+ res = send_plist(client, tag, dict);
plist_free(dict);
return res;
}
@@ -472,12 +526,12 @@ static int send_pair_record(struct mux_client *client, uint32_t tag, const char*
}
config_get_device_record(record_id, &record_data, &record_size);
-
+
if (record_data) {
plist_t dict = plist_new_dict();
plist_dict_set_item(dict, "PairRecordData", plist_new_data(record_data, record_size));
free(record_data);
- res = send_plist_pkt(client, tag, dict);
+ res = send_plist(client, tag, dict);
plist_free(dict);
} else {
res = send_result(client, tag, ENOENT);
@@ -485,13 +539,13 @@ static int send_pair_record(struct mux_client *client, uint32_t tag, const char*
return res;
}
-static int notify_device_add(struct mux_client *client, struct device_info *dev)
+static int send_device_add(struct mux_client *client, struct device_info *dev)
{
int res = -1;
if (client->proto_version == 1) {
/* XML plist packet */
plist_t dict = create_device_attached_plist(dev);
- res = send_plist_pkt(client, 0, dict);
+ res = send_plist(client, 0, dict);
plist_free(dict);
} else {
/* binary packet */
@@ -502,12 +556,12 @@ static int notify_device_add(struct mux_client *client, struct device_info *dev)
dmsg.serial_number[255] = 0;
dmsg.location = dev->location;
dmsg.product_id = dev->pid;
- res = send_pkt(client, 0, MESSAGE_DEVICE_ADD, &dmsg, sizeof(dmsg));
+ res = output_buffer_add_message(client, 0, MESSAGE_DEVICE_ADD, &dmsg, sizeof(dmsg));
}
return res;
}
-static int notify_device_remove(struct mux_client *client, uint32_t device_id)
+static int send_device_remove(struct mux_client *client, uint32_t device_id)
{
int res = -1;
if (client->proto_version == 1) {
@@ -515,16 +569,16 @@ static int notify_device_remove(struct mux_client *client, uint32_t device_id)
plist_t dict = plist_new_dict();
plist_dict_set_item(dict, "MessageType", plist_new_string("Detached"));
plist_dict_set_item(dict, "DeviceID", plist_new_uint(device_id));
- res = send_plist_pkt(client, 0, dict);
+ res = send_plist(client, 0, dict);
plist_free(dict);
} else {
/* binary packet */
- res = send_pkt(client, 0, MESSAGE_DEVICE_REMOVE, &device_id, sizeof(uint32_t));
+ res = output_buffer_add_message(client, 0, MESSAGE_DEVICE_REMOVE, &device_id, sizeof(uint32_t));
}
return res;
}
-static int notify_device_paired(struct mux_client *client, uint32_t device_id)
+static int send_device_paired(struct mux_client *client, uint32_t device_id)
{
int res = -1;
if (client->proto_version == 1) {
@@ -532,12 +586,12 @@ static int notify_device_paired(struct mux_client *client, uint32_t device_id)
plist_t dict = plist_new_dict();
plist_dict_set_item(dict, "MessageType", plist_new_string("Paired"));
plist_dict_set_item(dict, "DeviceID", plist_new_uint(device_id));
- res = send_plist_pkt(client, 0, dict);
+ res = send_plist(client, 0, dict);
plist_free(dict);
}
else {
/* binary packet */
- res = send_pkt(client, 0, MESSAGE_DEVICE_PAIRED, &device_id, sizeof(uint32_t));
+ res = output_buffer_add_message(client, 0, MESSAGE_DEVICE_PAIRED, &device_id, sizeof(uint32_t));
}
return res;
}
@@ -553,7 +607,7 @@ static int start_listen(struct mux_client *client)
count = device_get_list(0, &devs);
dev = devs;
for(i=0; devs && i < count; i++) {
- if(notify_device_add(client, dev++) < 0) {
+ if(send_device_add(client, dev++) < 0) {
free(devs);
return -1;
}
@@ -604,13 +658,13 @@ static void update_client_info(struct mux_client *client, plist_t dict)
client->info = info;
}
-static int client_command(struct mux_client *client, struct usbmuxd_header *hdr)
+static int handle_command(struct mux_client *client, struct usbmuxd_header *hdr)
{
int res;
- usbmuxd_log(LL_DEBUG, "Client command in fd %d len %d ver %d msg %d tag %d", client->fd, hdr->length, hdr->version, hdr->message, hdr->tag);
+ usbmuxd_log(LL_DEBUG, "Client %d command len %d ver %d msg %d tag %d", client->fd, hdr->length, hdr->version, hdr->message, hdr->tag);
if(client->state != CLIENT_COMMAND) {
- usbmuxd_log(LL_ERROR, "Client %d command received in the wrong state", client->fd);
+ usbmuxd_log(LL_ERROR, "Client %d command received in the wrong state, got %d but want %d", client->fd, client->state, CLIENT_COMMAND);
if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
return -1;
client_close(client);
@@ -691,7 +745,7 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr)
portnum = (uint16_t)val;
plist_free(dict);
- usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, device_id, ntohs(portnum));
+ usbmuxd_log(LL_DEBUG, "Client %d requesting connection to device %d port %d", client->fd, device_id, ntohs(portnum));
res = device_start_connect(device_id, ntohs(portnum), client);
if(res < 0) {
if (send_result(client, hdr->tag, -res) < 0)
@@ -839,7 +893,7 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr)
return -1;
}
-static void process_send(struct mux_client *client)
+static void output_buffer_process(struct mux_client *client)
{
int res;
if(!client->ob_size) {
@@ -849,7 +903,7 @@ static void process_send(struct mux_client *client)
}
res = send(client->fd, client->ob_buf, client->ob_size, 0);
if(res <= 0) {
- usbmuxd_log(LL_ERROR, "Send to client fd %d failed: %d %s", client->fd, res, strerror(errno));
+ usbmuxd_log(LL_ERROR, "Sending to client fd %d failed: %d %s", client->fd, res, strerror(errno));
client_close(client);
return;
}
@@ -869,7 +923,7 @@ static void process_send(struct mux_client *client)
memmove(client->ob_buf, client->ob_buf + res, client->ob_size);
}
}
-static void process_recv(struct mux_client *client)
+static void input_buffer_process(struct mux_client *client)
{
int res;
int did_read = 0;
@@ -916,21 +970,21 @@ static void process_recv(struct mux_client *client)
if(client->ib_size < hdr->length)
return;
}
- client_command(client, hdr);
+ handle_command(client, hdr);
client->ib_size = 0;
}
void client_process(int fd, short events)
{
struct mux_client *client = NULL;
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
FOREACH(struct mux_client *lc, &client_list) {
if(lc->fd == fd) {
client = lc;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
if(!client) {
usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd);
@@ -942,9 +996,9 @@ void client_process(int fd, short events)
device_client_process(client->connect_device, client, events);
} else {
if(events & POLLIN) {
- process_recv(client);
+ input_buffer_process(client);
} else if(events & POLLOUT) { //not both in case client died as part of process_recv
- process_send(client);
+ output_buffer_process(client);
}
}
@@ -952,45 +1006,45 @@ void client_process(int fd, short events)
void client_device_add(struct device_info *dev)
{
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
usbmuxd_log(LL_DEBUG, "client_device_add: id %d, location 0x%x, serial %s", dev->id, dev->location, dev->serial);
device_set_visible(dev->id);
FOREACH(struct mux_client *client, &client_list) {
if(client->state == CLIENT_LISTEN)
- notify_device_add(client, dev);
+ send_device_add(client, dev);
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
}
void client_device_remove(int device_id)
{
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
uint32_t id = device_id;
usbmuxd_log(LL_DEBUG, "client_device_remove: id %d", device_id);
FOREACH(struct mux_client *client, &client_list) {
if(client->state == CLIENT_LISTEN)
- notify_device_remove(client, id);
+ send_device_remove(client, id);
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
}
void client_device_paired(int device_id)
{
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
uint32_t id = device_id;
usbmuxd_log(LL_DEBUG, "client_device_paired: id %d", device_id);
FOREACH(struct mux_client *client, &client_list) {
if (client->state == CLIENT_LISTEN)
- notify_device_paired(client, id);
+ send_device_paired(client, id);
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
}
void client_init(void)
{
usbmuxd_log(LL_DEBUG, "client_init");
collection_init(&client_list);
- pthread_mutex_init(&client_list_mutex, NULL);
+ mutex_init(&client_list_mutex);
}
void client_shutdown(void)
@@ -999,6 +1053,6 @@ void client_shutdown(void)
FOREACH(struct mux_client *client, &client_list) {
client_close(client);
} ENDFOREACH
- pthread_mutex_destroy(&client_list_mutex);
+ mutex_destroy(&client_list_mutex);
collection_free(&client_list);
}
diff --git a/src/conf.c b/src/conf.c
index f211d99..2e6c97f 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -39,6 +39,9 @@
#include <shlobj.h>
#endif
+#include <libimobiledevice-glue/utils.h>
+#include <plist/plist.h>
+
#include "conf.h"
#include "utils.h"
#include "log.h"
@@ -132,7 +135,7 @@ const char *config_get_config_dir()
__config_dir = string_concat(base_config_dir, DIR_SEP_S, CONFIG_DIR, NULL);
if (__config_dir) {
- int i = strlen(__config_dir)-1;
+ int i = strlen(__config_dir)-1;
while ((i > 0) && (__config_dir[i] == DIR_SEP)) {
__config_dir[i--] = '\0';
}
@@ -140,7 +143,7 @@ const char *config_get_config_dir()
free(base_config_dir);
- usbmuxd_log(LL_DEBUG, "initialized config_dir to %s", __config_dir);
+ usbmuxd_log(LL_DEBUG, "Initialized config_dir to %s", __config_dir);
return __config_dir;
}
@@ -160,7 +163,7 @@ static int mkdir_with_parents(const char *dir, int mode)
if (__mkdir(dir, mode) == 0) {
return 0;
} else {
- if (errno == EEXIST) return 0;
+ if (errno == EEXIST) return 0;
}
int res;
char *parent = strdup(dir);
@@ -230,7 +233,7 @@ static int internal_set_value(const char *config_file, const char *key, plist_t
/* read file into plist */
plist_t config = NULL;
- plist_read_from_filename(&config, config_file);
+ plist_read_from_file(config_file, &config, NULL);
if (!config) {
config = plist_new_dict();
plist_dict_set_item(config, key, value);
@@ -247,14 +250,14 @@ static int internal_set_value(const char *config_file, const char *key, plist_t
char *value_string = NULL;
if (plist_get_node_type(value) == PLIST_STRING) {
plist_get_string_val(value, &value_string);
- usbmuxd_log(LL_DEBUG, "setting key %s to %s in config_file %s", key, value_string, config_file);
+ usbmuxd_log(LL_DEBUG, "Setting key %s to %s in config file %s", key, value_string, config_file);
if (value_string)
free(value_string);
} else {
- usbmuxd_log(LL_DEBUG, "setting key %s in config_file %s", key, config_file);
+ usbmuxd_log(LL_DEBUG, "Setting key %s in config file %s", key, config_file);
}
- int res = plist_write_to_filename(config, config_file, PLIST_FORMAT_XML);
+ int res = (plist_write_to_file(config, config_file, PLIST_FORMAT_XML, 0) == PLIST_ERR_SUCCESS);
plist_free(config);
@@ -274,7 +277,7 @@ static int config_set_value(const char *key, plist_t value)
int result = internal_set_value(config_file, key, value);
if (!result) {
- usbmuxd_log(LL_ERROR, "ERROR: Failed to write to '%s': %s", config_file, strerror(errno));
+ usbmuxd_log(LL_ERROR, "ERROR: Failed to write to '%s'", config_file);
}
free(config_file);
@@ -288,8 +291,8 @@ static int internal_get_value(const char* config_file, const char *key, plist_t
/* now parse file to get the SystemBUID */
plist_t config = NULL;
- if (plist_read_from_filename(&config, config_file)) {
- usbmuxd_log(LL_DEBUG, "reading key %s from config_file %s", key, config_file);
+ if (plist_read_from_file(config_file, &config, NULL) == PLIST_ERR_SUCCESS) {
+ usbmuxd_log(LL_DEBUG, "Reading key %s from config file %s", key, config_file);
plist_t n = plist_dict_get_item(config, key);
if (n) {
*value = plist_copy(n);
@@ -371,7 +374,7 @@ void config_get_system_buid(char **system_buid)
if (value && (plist_get_node_type(value) == PLIST_STRING)) {
plist_get_string_val(value, system_buid);
- usbmuxd_log(LL_DEBUG, "got %s %s", CONFIG_SYSTEM_BUID_KEY, *system_buid);
+ usbmuxd_log(LL_DEBUG, "Got %s %s", CONFIG_SYSTEM_BUID_KEY, *system_buid);
}
if (value)
@@ -379,14 +382,14 @@ void config_get_system_buid(char **system_buid)
if (!*system_buid) {
/* no config, generate system_buid */
- usbmuxd_log(LL_DEBUG, "no previous %s found", CONFIG_SYSTEM_BUID_KEY);
+ usbmuxd_log(LL_DEBUG, "No previous %s found", CONFIG_SYSTEM_BUID_KEY);
*system_buid = config_generate_system_buid();
if (!config_set_system_buid(*system_buid)) {
usbmuxd_log(LL_WARNING, "WARNING: Failed to store SystemBUID, this might be a problem");
}
}
- usbmuxd_log(LL_DEBUG, "using %s as %s", *system_buid, CONFIG_SYSTEM_BUID_KEY);
+ usbmuxd_log(LL_DEBUG, "Using %s as %s", *system_buid, CONFIG_SYSTEM_BUID_KEY);
}
/**
@@ -428,8 +431,8 @@ int config_set_device_record(const char *udid, char* record_data, uint64_t recor
remove(device_record_file);
/* store file */
- if (!plist_write_to_filename(plist, device_record_file, PLIST_FORMAT_XML)) {
- usbmuxd_log(LL_DEBUG, "could not open '%s' for writing: %s", device_record_file, strerror(errno));
+ if (!plist_write_to_file(plist, device_record_file, PLIST_FORMAT_XML, 0)) {
+ usbmuxd_log(LL_DEBUG, "Could not open '%s' for writing: %s", device_record_file, strerror(errno));
res = -ENOENT;
}
free(device_record_file);
@@ -464,7 +467,7 @@ int config_get_device_record(const char *udid, char **record_data, uint64_t *rec
/* read file */
buffer_read_from_filename(device_record_file, record_data, record_size);
if (!*record_data) {
- usbmuxd_log(LL_ERROR, "%s: failed to read '%s': %s", __func__, device_record_file, strerror(errno));
+ usbmuxd_log(LL_ERROR, "ERROR: Failed to read '%s': %s", device_record_file, strerror(errno));
res = -ENOENT;
}
free(device_record_file);
@@ -490,7 +493,7 @@ int config_remove_device_record(const char *udid)
/* remove file */
if (remove(device_record_file) != 0) {
res = -errno;
- usbmuxd_log(LL_DEBUG, "could not remove %s: %s", device_record_file, strerror(errno));
+ usbmuxd_log(LL_DEBUG, "Could not remove %s: %s", device_record_file, strerror(errno));
}
free(device_record_file);
@@ -527,6 +530,6 @@ void config_device_record_get_host_id(const char *udid, char **host_id)
plist_free(value);
if (!*host_id) {
- usbmuxd_log(LL_ERROR, "%s: ERROR couldn't get HostID from pairing record for udid %s", __func__, udid);
+ usbmuxd_log(LL_ERROR, "ERROR: Could not get HostID from pairing record for udid %s", udid);
}
}
diff --git a/src/device.c b/src/device.c
index 6858cf5..0928021 100644
--- a/src/device.c
+++ b/src/device.c
@@ -32,8 +32,11 @@
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
-#include <pthread.h>
#include <unistd.h>
+
+#include <libimobiledevice-glue/collection.h>
+#include <libimobiledevice-glue/thread.h>
+
#include "device.h"
#include "client.h"
#include "preflight.h"
@@ -127,19 +130,19 @@ struct mux_device
};
static struct collection device_list;
-pthread_mutex_t device_list_mutex;
+mutex_t device_list_mutex;
static struct mux_device* get_mux_device_for_id(int device_id)
{
struct mux_device *dev = NULL;
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *cdev, &device_list) {
if(cdev->id == device_id) {
dev = cdev;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
return dev;
}
@@ -166,7 +169,7 @@ static int get_next_device_id(void)
{
while(1) {
int ok = 1;
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->id == next_device_id) {
next_device_id++;
@@ -174,7 +177,7 @@ static int get_next_device_id(void)
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
if(ok)
return next_device_id++;
}
@@ -464,9 +467,9 @@ static int send_tcp_ack(struct mux_connection *conn)
*/
void device_client_process(int device_id, struct mux_client *client, short events)
{
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
struct mux_connection *conn = get_mux_connection(device_id, client);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
if(!conn) {
usbmuxd_log(LL_WARNING, "Could not find connection for device %d client %p", device_id, client);
return;
@@ -549,6 +552,7 @@ void device_abort_connect(int device_id, struct mux_client *client)
{
struct mux_connection *conn = get_mux_connection(device_id, client);
if (conn) {
+ conn->client = NULL;
connection_teardown(conn);
} else {
usbmuxd_log(LL_WARNING, "Attempted to abort for nonexistent connection for device %d", device_id);
@@ -565,9 +569,9 @@ static void device_version_input(struct mux_device *dev, struct version_header *
vh->minor = ntohl(vh->minor);
if(vh->major != 2 && vh->major != 1) {
usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d", dev->id, vh->major, vh->minor);
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
collection_remove(&device_list, dev);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
free(dev);
return;
}
@@ -595,29 +599,31 @@ static void device_control_input(struct mux_device *dev, unsigned char *payload,
switch (payload[0]) {
case 3:
if (payload_length > 1) {
- char* buf = malloc(payload_length);
- strncpy(buf, (char*)payload+1, payload_length-1);
- buf[payload_length-1] = '\0';
- usbmuxd_log(LL_ERROR, "%s: ERROR: %s", __func__, buf);
- free(buf);
+ usbmuxd_log(LL_ERROR, "Device %d: ERROR: %.*s", dev->id, payload_length-1, payload+1);
} else {
- usbmuxd_log(LL_ERROR, "%s: Error occurred, but empty error message", __func__);
+ usbmuxd_log(LL_ERROR, "%s: Device %d: Got device error payload with empty message", __func__, dev->id);
+ }
+ break;
+ case 5:
+ if (payload_length > 1) {
+ usbmuxd_log(LL_WARNING, "Device %d: WARNING: %.*s", dev->id, payload_length-1, payload+1);
+ } else {
+ usbmuxd_log(LL_WARNING, "%s: Device %d: Got payload type %d with empty message", __func__, dev->id, payload[0]);
}
break;
case 7:
if (payload_length > 1) {
- char* buf = malloc(payload_length);
- strncpy(buf, (char*)payload+1, payload_length-1);
- buf[payload_length-1] = '\0';
- usbmuxd_log(LL_INFO, "%s: %s", __func__, buf);
- free(buf);
+ usbmuxd_log(LL_INFO, "Device %d: %.*s", dev->id, payload_length-1, payload+1);
+ } else {
+ usbmuxd_log(LL_WARNING, "%s: Device %d: Got payload type %d with empty message", __func__, dev->id, payload[0]);
}
break;
default:
+ usbmuxd_log(LL_WARNING, "%s: Device %d: Got unhandled payload type %d: %.*s", __func__, dev->id, payload[0], payload_length-1, payload+1);
break;
}
} else {
- usbmuxd_log(LL_WARNING, "%s: got a type 1 packet without payload", __func__);
+ usbmuxd_log(LL_WARNING, "%s: Got a type 1 packet without payload for device %d", __func__, dev->id);
}
}
@@ -690,7 +696,7 @@ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned
return;
}
conn->state = CONN_CONNECTED;
- usbmuxd_log(LL_DEBUG, "Client connected to device %d (%d->%d)", dev->id, sport, dport);
+ usbmuxd_log(LL_INFO, "Client connected to device %d (%d->%d)", dev->id, sport, dport);
if(client_notify_connect(conn->client, RESULT_OK) < 0) {
conn->client = NULL;
connection_teardown(conn);
@@ -723,14 +729,14 @@ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned
void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_t length)
{
struct mux_device *dev = NULL;
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *tdev, &device_list) {
if(tdev->usbdev == usbdev) {
dev = tdev;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
if(!dev) {
usbmuxd_log(LL_WARNING, "Cannot find device entry for RX input from USB device %p on location 0x%x", usbdev, usb_get_location(usbdev));
return;
@@ -847,15 +853,15 @@ int device_add(struct usb_device *usbdev)
free(dev);
return res;
}
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
collection_add(&device_list, dev);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
return 0;
}
void device_remove(struct usb_device *usbdev)
{
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->usbdev == usbdev) {
usbmuxd_log(LL_NOTICE, "Removed device %d on location 0x%x", dev->id, usb_get_location(usbdev));
@@ -871,48 +877,48 @@ void device_remove(struct usb_device *usbdev)
preflight_device_remove_cb(dev->preflight_cb_data);
}
collection_remove(&device_list, dev);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
free(dev->pktbuf);
free(dev);
return;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
usbmuxd_log(LL_WARNING, "Cannot find device entry while removing USB device %p on location 0x%x", usbdev, usb_get_location(usbdev));
}
void device_set_visible(int device_id)
{
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->id == device_id) {
dev->visible = 1;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
}
void device_set_preflight_cb_data(int device_id, void* data)
{
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->id == device_id) {
dev->preflight_cb_data = data;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
}
int device_get_count(int include_hidden)
{
int count = 0;
struct collection dev_list = {NULL, 0};
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
collection_copy(&dev_list, &device_list);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
FOREACH(struct mux_device *dev, &dev_list) {
if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible))
@@ -927,9 +933,9 @@ int device_get_list(int include_hidden, struct device_info **devices)
{
int count = 0;
struct collection dev_list = {NULL, 0};
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
collection_copy(&dev_list, &device_list);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
*devices = malloc(sizeof(struct device_info) * dev_list.capacity);
struct device_info *p = *devices;
@@ -954,7 +960,7 @@ int device_get_list(int include_hidden, struct device_info **devices)
int device_get_timeout(void)
{
uint64_t oldest = (uint64_t)-1LL;
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->state == MUXDEV_ACTIVE) {
FOREACH(struct mux_connection *conn, &dev->connections) {
@@ -963,7 +969,7 @@ int device_get_timeout(void)
} ENDFOREACH
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
uint64_t ct = mstime64();
if((int64_t)oldest == -1LL)
return 100000; //meh
@@ -975,7 +981,7 @@ int device_get_timeout(void)
void device_check_timeouts(void)
{
uint64_t ct = mstime64();
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->state == MUXDEV_ACTIVE) {
FOREACH(struct mux_connection *conn, &dev->connections) {
@@ -988,14 +994,14 @@ void device_check_timeouts(void)
} ENDFOREACH
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
}
void device_init(void)
{
usbmuxd_log(LL_DEBUG, "device_init");
collection_init(&device_list);
- pthread_mutex_init(&device_list_mutex, NULL);
+ mutex_init(&device_list_mutex);
next_device_id = 1;
}
@@ -1016,7 +1022,7 @@ void device_kill_connections(void)
void device_shutdown(void)
{
usbmuxd_log(LL_DEBUG, "device_shutdown");
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
FOREACH(struct mux_connection *conn, &dev->connections) {
connection_teardown(conn);
@@ -1025,7 +1031,7 @@ void device_shutdown(void)
collection_remove(&device_list, dev);
free(dev);
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
- pthread_mutex_destroy(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
+ mutex_destroy(&device_list_mutex);
collection_free(&device_list);
}
diff --git a/src/main.c b/src/main.c
index aede710..8702a4b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,7 +1,7 @@
/*
* main.c
*
- * Copyright (C) 2009-2019 Nikias Bassen <nikias@gmx.li>
+ * Copyright (C) 2009-2021 Nikias Bassen <nikias@gmx.li>
* Copyright (C) 2013-2014 Martin Szulecki <m.szulecki@libimobiledevice.org>
* Copyright (C) 2009 Hector Martin <hector@marcansoft.com>
* Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org>
@@ -36,6 +36,9 @@
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/resource.h>
@@ -51,12 +54,16 @@
#include "conf.h"
static const char *socket_path = "/var/run/usbmuxd";
-static const char *lockfile = "/var/run/usbmuxd.pid";
+#define DEFAULT_LOCKFILE "/var/run/usbmuxd.pid"
+static const char *lockfile = DEFAULT_LOCKFILE;
+// Global state used in other files
int should_exit;
int should_discover;
int use_logfile = 0;
+int no_preflight = 0;
+// Global state for main.c
static int verbose = 0;
static int foreground = 0;
static int drop_privileges = 0;
@@ -66,22 +73,162 @@ static int opt_enable_exit = 0;
static int opt_exit = 0;
static int exit_signal = 0;
static int daemon_pipe;
+static const char *listen_addr = NULL;
static int report_to_parent = 0;
-static int create_socket(void) {
- struct sockaddr_un bind_addr;
+static int create_socket(void)
+{
int listenfd;
+ const char* socket_addr = socket_path;
+ const char* tcp_port;
+ char listen_addr_str[256];
+
+ if (listen_addr) {
+ socket_addr = listen_addr;
+ }
+ tcp_port = strrchr(socket_addr, ':');
+ if (tcp_port) {
+ tcp_port++;
+ size_t nlen = tcp_port - socket_addr;
+ char* hostname = malloc(nlen);
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ int yes = 1;
+ int res;
+
+ strncpy(hostname, socket_addr, nlen-1);
+ hostname[nlen-1] = '\0';
+
+ memset(&hints, '\0', sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ res = getaddrinfo(hostname, tcp_port, &hints, &result);
+ free(hostname);
+ if (res != 0) {
+ usbmuxd_log(LL_FATAL, "%s: getaddrinfo() failed: %s\n", __func__, gai_strerror(res));
+ return -1;
+ }
- if(unlink(socket_path) == -1 && errno != ENOENT) {
- usbmuxd_log(LL_FATAL, "unlink(%s) failed: %s", socket_path, strerror(errno));
- return -1;
- }
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ listenfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (listenfd == -1) {
+ listenfd = -1;
+ continue;
+ }
- listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (listenfd == -1) {
- usbmuxd_log(LL_FATAL, "socket() failed: %s", strerror(errno));
- return -1;
+ if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
+ usbmuxd_log(LL_ERROR, "%s: setsockopt(): %s", __func__, strerror(errno));
+ close(listenfd);
+ listenfd = -1;
+ continue;
+ }
+
+#ifdef SO_NOSIGPIPE
+ if (setsockopt(listenfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
+ usbmuxd_log(LL_ERROR, "%s: setsockopt(): %s", __func__, strerror(errno));
+ close(listenfd);
+ listenfd = -1;
+ continue;
+ }
+#endif
+
+#if defined(AF_INET6) && defined(IPV6_V6ONLY)
+ if (rp->ai_family == AF_INET6) {
+ if (setsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(int)) == -1) {
+ usbmuxd_log(LL_ERROR, "%s: setsockopt() IPV6_V6ONLY: %s", __func__, strerror(errno));
+ }
+ }
+#endif
+
+ if (bind(listenfd, rp->ai_addr, rp->ai_addrlen) < 0) {
+ usbmuxd_log(LL_FATAL, "%s: bind() failed: %s", __func__, strerror(errno));
+ close(listenfd);
+ listenfd = -1;
+ continue;
+ }
+
+ const void *addrdata = NULL;
+ if (rp->ai_family == AF_INET) {
+ addrdata = &((struct sockaddr_in*)rp->ai_addr)->sin_addr;
+ }
+#ifdef AF_INET6
+ else if (rp->ai_family == AF_INET6) {
+ addrdata = &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr;
+ }
+#endif
+ if (addrdata) {
+ char* endp = NULL;
+ uint16_t listen_port = 0;
+ if (rp->ai_family == AF_INET) {
+ listen_port = ntohs(((struct sockaddr_in*)rp->ai_addr)->sin_port);
+ if (inet_ntop(AF_INET, addrdata, listen_addr_str, sizeof(listen_addr_str)-6)) {
+ endp = &listen_addr_str[0] + strlen(listen_addr_str);
+ }
+ }
+#ifdef AF_INET6
+ else if (rp->ai_family == AF_INET6) {
+ listen_port = ntohs(((struct sockaddr_in6*)rp->ai_addr)->sin6_port);
+ listen_addr_str[0] = '[';
+ if (inet_ntop(AF_INET6, addrdata, listen_addr_str+1, sizeof(listen_addr_str)-8)) {
+ endp = &listen_addr_str[0] + strlen(listen_addr_str);
+ }
+ if (endp) {
+ *endp = ']';
+ endp++;
+ }
+ }
+#endif
+ if (endp) {
+ sprintf(endp, ":%u", listen_port);
+ }
+ }
+ break;
+ }
+ freeaddrinfo(result);
+ if (listenfd == -1) {
+ usbmuxd_log(LL_FATAL, "%s: Failed to create listening socket", __func__);
+ return -1;
+ }
+ } else {
+ struct sockaddr_un bind_addr;
+
+ if (strcmp(socket_addr, socket_path) != 0) {
+ struct stat fst;
+ if (stat(socket_addr, &fst) == 0) {
+ if (!S_ISSOCK(fst.st_mode)) {
+ usbmuxd_log(LL_FATAL, "FATAL: File '%s' already exists and is not a socket file. Refusing to continue.", socket_addr);
+ return -1;
+ }
+ }
+ }
+
+ if (unlink(socket_addr) == -1 && errno != ENOENT) {
+ usbmuxd_log(LL_FATAL, "%s: unlink(%s) failed: %s", __func__, socket_addr, strerror(errno));
+ return -1;
+ }
+
+ listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (listenfd == -1) {
+ usbmuxd_log(LL_FATAL, "socket() failed: %s", strerror(errno));
+ return -1;
+ }
+
+ bzero(&bind_addr, sizeof(bind_addr));
+ bind_addr.sun_family = AF_UNIX;
+ strncpy(bind_addr.sun_path, socket_addr, sizeof(bind_addr.sun_path));
+ bind_addr.sun_path[sizeof(bind_addr.sun_path) - 1] = '\0';
+
+ if (bind(listenfd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) != 0) {
+ usbmuxd_log(LL_FATAL, "bind() failed: %s", strerror(errno));
+ return -1;
+ }
+ chmod(socket_addr, 0666);
+
+ snprintf(listen_addr_str, sizeof(listen_addr_str), "%s", socket_addr);
}
int flags = fcntl(listenfd, F_GETFL, 0);
@@ -93,21 +240,13 @@ static int create_socket(void) {
}
}
- bzero(&bind_addr, sizeof(bind_addr));
- bind_addr.sun_family = AF_UNIX;
- strcpy(bind_addr.sun_path, socket_path);
- if (bind(listenfd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) != 0) {
- usbmuxd_log(LL_FATAL, "bind() failed: %s", strerror(errno));
- return -1;
- }
-
// Start listening
- if (listen(listenfd, 5) != 0) {
+ if (listen(listenfd, 256) != 0) {
usbmuxd_log(LL_FATAL, "listen() failed: %s", strerror(errno));
return -1;
}
- chmod(socket_path, 0666);
+ usbmuxd_log(LL_INFO, "Listening on %s", listen_addr_str);
return listenfd;
}
@@ -151,7 +290,7 @@ static void set_signal_handlers(void)
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
sigprocmask(SIG_SETMASK, &set, NULL);
-
+
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handle_signal;
sigaction(SIGINT, &sa, NULL);
@@ -359,7 +498,10 @@ static int notify_parent(int status)
static void usage()
{
printf("Usage: %s [OPTIONS]\n", PACKAGE_NAME);
- printf("Expose a socket to multiplex connections from and to iOS devices.\n\n");
+ printf("\n");
+ printf("Expose a socket to multiplex connections from and to iOS devices.\n");
+ printf("\n");
+ printf("OPTIONS:\n");
printf(" -h, --help\t\tPrint this message.\n");
printf(" -v, --verbose\t\tBe verbose (use twice or more to increase).\n");
printf(" -f, --foreground\tDo not daemonize (implies one -v).\n");
@@ -368,12 +510,18 @@ static void usage()
printf(" \tStarting another instance will trigger discovery instead.\n");
printf(" -z, --enable-exit\tEnable \"--exit\" request from other instances and exit\n");
printf(" \tautomatically if no device is attached.\n");
+ printf(" -p, --no-preflight\tDisable lockdownd preflight on new device.\n");
#ifdef HAVE_UDEV
printf(" -u, --udev\t\tRun in udev operation mode (implies -n and -z).\n");
#endif
#ifdef HAVE_SYSTEMD
printf(" -s, --systemd\t\tRun in systemd operation mode (implies -z and -f).\n");
#endif
+ printf(" -S, --socket ADDR:PORT | PATH Specify source ADDR and PORT or a UNIX\n");
+ printf(" \t\tsocket PATH to use for the listening socket.\n");
+ printf(" \t\tDefault: %s\n", socket_path);
+ printf(" -P, --pidfile PATH\tSpecify a different location for the pid file, or pass\n");
+ printf(" \t\tNONE to disable. Default: %s\n", DEFAULT_LOCKFILE);
printf(" -x, --exit\t\tNotify a running instance to exit if there are no devices\n");
printf(" \t\tconnected (sends SIGUSR1 to running instance) and exit.\n");
printf(" -X, --force-exit\tNotify a running instance to exit even if there are still\n");
@@ -381,6 +529,8 @@ static void usage()
printf(" -l, --logfile=LOGFILE\tLog (append) to LOGFILE instead of stderr or syslog.\n");
printf(" -V, --version\t\tPrint version information and exit.\n");
printf("\n");
+ printf("Homepage: <" PACKAGE_URL ">\n");
+ printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n");
}
static void parse_opts(int argc, char **argv)
@@ -392,12 +542,15 @@ static void parse_opts(int argc, char **argv)
{"user", required_argument, NULL, 'U'},
{"disable-hotplug", no_argument, NULL, 'n'},
{"enable-exit", no_argument, NULL, 'z'},
+ {"no-preflight", no_argument, NULL, 'p'},
#ifdef HAVE_UDEV
{"udev", no_argument, NULL, 'u'},
#endif
#ifdef HAVE_SYSTEMD
{"systemd", no_argument, NULL, 's'},
#endif
+ {"socket", required_argument, NULL, 'S'},
+ {"pidfile", required_argument, NULL, 'P'},
{"exit", no_argument, NULL, 'x'},
{"force-exit", no_argument, NULL, 'X'},
{"logfile", required_argument, NULL, 'l'},
@@ -407,11 +560,11 @@ static void parse_opts(int argc, char **argv)
int c;
#ifdef HAVE_SYSTEMD
- const char* opts_spec = "hfvVuU:xXsnzl:";
+ const char* opts_spec = "hfvVuU:xXsnzl:pS:P:";
#elif HAVE_UDEV
- const char* opts_spec = "hfvVuU:xXnzl:";
+ const char* opts_spec = "hfvVuU:xXnzl:pS:P:";
#else
- const char* opts_spec = "hfvVU:xXnzl:";
+ const char* opts_spec = "hfvVU:xXnzl:pS:P:";
#endif
while (1) {
@@ -437,6 +590,9 @@ static void parse_opts(int argc, char **argv)
drop_privileges = 1;
drop_user = optarg;
break;
+ case 'p':
+ no_preflight = 1;
+ break;
#ifdef HAVE_UDEV
case 'u':
opt_disable_hotplug = 1;
@@ -455,6 +611,26 @@ static void parse_opts(int argc, char **argv)
case 'z':
opt_enable_exit = 1;
break;
+ case 'S':
+ if (!*optarg || *optarg == '-') {
+ usbmuxd_log(LL_FATAL, "ERROR: --socket requires an argument");
+ usage();
+ exit(2);
+ }
+ listen_addr = optarg;
+ break;
+ case 'P':
+ if (!*optarg || *optarg == '-') {
+ usbmuxd_log(LL_FATAL, "ERROR: --pidfile requires an argument");
+ usage();
+ exit(2);
+ }
+ if (!strcmp(optarg, "NONE")) {
+ lockfile = NULL;
+ } else {
+ lockfile = optarg;
+ }
+ break;
case 'x':
opt_exit = 1;
exit_signal = SIGUSR1;
@@ -516,19 +692,21 @@ int main(int argc, char *argv[])
set_signal_handlers();
signal(SIGPIPE, SIG_IGN);
- res = lfd = open(lockfile, O_WRONLY|O_CREAT, 0644);
- if(res == -1) {
- usbmuxd_log(LL_FATAL, "Could not open lockfile");
- goto terminate;
- }
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- lock.l_pid = 0;
- fcntl(lfd, F_GETLK, &lock);
- close(lfd);
- if (lock.l_type != F_UNLCK) {
+ if (lockfile) {
+ res = lfd = open(lockfile, O_WRONLY|O_CREAT, 0644);
+ if(res == -1) {
+ usbmuxd_log(LL_FATAL, "Could not open lockfile");
+ goto terminate;
+ }
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_pid = 0;
+ fcntl(lfd, F_GETLK, &lock);
+ close(lfd);
+ }
+ if (lockfile && lock.l_type != F_UNLCK) {
if (opt_exit) {
if (lock.l_pid && !kill(lock.l_pid, 0)) {
usbmuxd_log(LL_NOTICE, "Sending signal %d to instance with pid %d", exit_signal, lock.l_pid);
@@ -564,7 +742,9 @@ int main(int argc, char *argv[])
goto terminate;
}
}
- unlink(lockfile);
+ if (lockfile) {
+ unlink(lockfile);
+ }
if (opt_exit) {
usbmuxd_log(LL_NOTICE, "No running instance found, none killed. Exiting.");
@@ -579,26 +759,28 @@ int main(int argc, char *argv[])
}
}
- // now open the lockfile and place the lock
- res = lfd = open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
- if(res < 0) {
- usbmuxd_log(LL_FATAL, "Could not open lockfile");
- goto terminate;
- }
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- if ((res = fcntl(lfd, F_SETLK, &lock)) < 0) {
- usbmuxd_log(LL_FATAL, "Lockfile locking failed!");
- goto terminate;
- }
- sprintf(pids, "%d", getpid());
- if ((size_t)(res = write(lfd, pids, strlen(pids))) != strlen(pids)) {
- usbmuxd_log(LL_FATAL, "Could not write pidfile!");
- if(res >= 0)
- res = -2;
- goto terminate;
+ if (lockfile) {
+ // now open the lockfile and place the lock
+ res = lfd = open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
+ if(res < 0) {
+ usbmuxd_log(LL_FATAL, "Could not open pidfile '%s'", lockfile);
+ goto terminate;
+ }
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ if ((res = fcntl(lfd, F_SETLK, &lock)) < 0) {
+ usbmuxd_log(LL_FATAL, "Locking pidfile '%s' failed!", lockfile);
+ goto terminate;
+ }
+ sprintf(pids, "%d", getpid());
+ if ((size_t)(res = write(lfd, pids, strlen(pids))) != strlen(pids)) {
+ usbmuxd_log(LL_FATAL, "Could not write pidfile!");
+ if(res >= 0)
+ res = -2;
+ goto terminate;
+ }
}
// set number of file descriptors to higher value
diff --git a/src/preflight.c b/src/preflight.c
index c7cfa50..9c57e98 100644
--- a/src/preflight.c
+++ b/src/preflight.c
@@ -26,8 +26,6 @@
#include <unistd.h>
#include <errno.h>
-#include <pthread.h>
-
#include <sys/time.h>
#ifdef HAVE_LIBIMOBILEDEVICE
@@ -36,11 +34,16 @@
#include <libimobiledevice/notification_proxy.h>
#endif
+#include <libimobiledevice-glue/thread.h>
+
#include "preflight.h"
#include "device.h"
#include "client.h"
#include "conf.h"
#include "log.h"
+#include "usb.h"
+
+extern int no_preflight;
#ifdef HAVE_LIBIMOBILEDEVICE
#ifndef HAVE_ENUM_IDEVICE_CONNECTION_TYPE
@@ -56,6 +59,7 @@ struct idevice_private {
enum idevice_connection_type conn_type;
void *conn_data;
int version;
+ int device_class;
};
struct cb_data {
@@ -135,6 +139,7 @@ static void* preflight_worker_handle_device_add(void* userdata)
_dev->conn_type = CONNECTION_USBMUXD;
_dev->conn_data = NULL;
_dev->version = 0;
+ _dev->device_class = 0;
idevice_t dev = (idevice_t)_dev;
@@ -143,6 +148,7 @@ static void* preflight_worker_handle_device_add(void* userdata)
plist_t value = NULL;
char* version_str = NULL;
+ char* deviceclass_str = NULL;
usbmuxd_log(LL_INFO, "%s: Starting preflight on device %s...", __func__, _dev->udid);
@@ -208,23 +214,43 @@ retry:
lerr = lockdownd_get_value(lockdown, NULL, "ProductVersion", &value);
if (lerr != LOCKDOWN_E_SUCCESS) {
- usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get ProductVersion from device %s, lockdown error %d", __func__, _dev->udid, lerr);
- goto leave;
+ usbmuxd_log(LL_WARNING, "%s: Could not get ProductVersion from device %s, lockdown error %d", __func__, _dev->udid, lerr);
+ /* assume old iOS version */
+ version_str = strdup("1.0");
+ } else {
+ if (value && plist_get_node_type(value) == PLIST_STRING) {
+ plist_get_string_val(value, &version_str);
+ }
+ plist_free(value);
+
+ if (!version_str) {
+ usbmuxd_log(LL_ERROR, "%s: Could not get ProductVersion string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data);
+ goto leave;
+ }
}
+ lerr = lockdownd_get_value(lockdown, NULL, "DeviceClass", &value);
+ if (lerr != LOCKDOWN_E_SUCCESS) {
+ usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get DeviceClass from device %s, lockdown error %d", __func__, _dev->udid, lerr);
+ goto leave;
+ }
if (value && plist_get_node_type(value) == PLIST_STRING) {
- plist_get_string_val(value, &version_str);
+ plist_get_string_val(value, &deviceclass_str);
}
+ plist_free(value);
- if (!version_str) {
- usbmuxd_log(LL_ERROR, "%s: Could not get ProductVersion string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data);
+ if (!deviceclass_str) {
+ usbmuxd_log(LL_ERROR, "%s: Could not get DeviceClass string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data);
goto leave;
}
int version_major = strtol(version_str, NULL, 10);
- if (version_major >= 7) {
- /* iOS 7.0 and later */
- usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid);
+ if (((!strcmp(deviceclass_str, "iPhone") || !strcmp(deviceclass_str, "iPad")) && version_major >= 7)
+ || (!strcmp(deviceclass_str, "Watch") && version_major >= 2)
+ || (!strcmp(deviceclass_str, "AppleTV") && version_major >= 9)
+ ) {
+ /* iOS 7.0 / watchOS 2.0 / tvOS 9.0 and later */
+ usbmuxd_log(LL_INFO, "%s: Found %s %s device %s", __func__, deviceclass_str, version_str, _dev->udid);
lockdownd_set_untrusted_host_buid(lockdown);
@@ -270,7 +296,7 @@ retry:
"com.apple.mobile.lockdown.request_pair",
"com.apple.mobile.lockdown.request_host_buid",
NULL
- };
+ };
np_observe_notifications(np, spec);
/* TODO send notification to user's desktop */
@@ -331,10 +357,8 @@ retry:
}
leave:
- if (value)
- plist_free(value);
- if (version_str)
- free(version_str);
+ free(deviceclass_str);
+ free(version_str);
if (lockdown)
lockdownd_client_free(lockdown);
if (dev)
@@ -353,6 +377,11 @@ void preflight_device_remove_cb(void *data)
void preflight_worker_device_add(struct device_info* info)
{
+ if (info->pid == PID_APPLE_T2_COPROCESSOR || no_preflight == 1) {
+ client_device_add(info);
+ return;
+ }
+
#ifdef HAVE_LIBIMOBILEDEVICE
struct device_info *infocopy = (struct device_info*)malloc(sizeof(struct device_info));
@@ -361,18 +390,15 @@ void preflight_worker_device_add(struct device_info* info)
infocopy->serial = strdup(info->serial);
}
- pthread_t th;
- pthread_attr_t attr;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- int perr = pthread_create(&th, &attr, preflight_worker_handle_device_add, infocopy);
+ THREAD_T th;
+ int perr = thread_new(&th, preflight_worker_handle_device_add, infocopy);
if (perr != 0) {
free((char*)infocopy->serial);
free(infocopy);
usbmuxd_log(LL_ERROR, "ERROR: failed to start preflight worker thread for device %s: %s (%d). Invoking client_device_add() directly but things might not work as expected.", info->serial, strerror(perr), perr);
client_device_add(info);
+ } else {
+ thread_detach(th);
}
#else
client_device_add(info);
diff --git a/src/usb.c b/src/usb.c
index 9baf933..63d0208 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2009 Hector Martin <hector@marcansoft.com>
* Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
- * Copyright (C) 2009 Martin Szulecki <opensuse@sukimashita.com>
+ * Copyright (C) 2009-2020 Martin Szulecki <martin.szulecki@libimobiledevice.org>
* Copyright (C) 2014 Mikkel Kamstrup Erlandsen <mikkel.kamstrup@xamarin.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -31,6 +31,8 @@
#include <libusb.h>
+#include <libimobiledevice-glue/collection.h>
+
#include "usb.h"
#include "log.h"
#include "device.h"
@@ -63,6 +65,14 @@ struct usb_device {
struct libusb_device_descriptor devdesc;
};
+struct mode_context {
+ struct libusb_device* dev;
+ uint8_t bus, address;
+ uint8_t bRequest;
+ uint16_t wValue, wIndex, wLength;
+ unsigned int timeout;
+};
+
static struct collection device_list;
static struct timeval next_dev_poll_time;
@@ -97,7 +107,7 @@ static void usb_disconnect(struct usb_device *dev)
tv.tv_sec = 0;
tv.tv_usec = 1000;
if((res = libusb_handle_events_timeout(NULL, &tv)) < 0) {
- usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout for usb_disconnect failed: %d", res);
+ usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout for usb_disconnect failed: %s", libusb_error_name(res));
break;
}
}
@@ -169,7 +179,7 @@ int usb_send(struct usb_device *dev, const unsigned char *buf, int length)
struct libusb_transfer *xfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_out, (void*)buf, length, tx_callback, dev, 0);
if((res = libusb_submit_transfer(xfer)) < 0) {
- usbmuxd_log(LL_ERROR, "Failed to submit TX transfer %p len %d to device %d-%d: %d", buf, length, dev->bus, dev->address, res);
+ usbmuxd_log(LL_ERROR, "Failed to submit TX transfer %p len %d to device %d-%d: %s", buf, length, dev->bus, dev->address, libusb_error_name(res));
libusb_free_transfer(xfer);
return res;
}
@@ -181,7 +191,7 @@ int usb_send(struct usb_device *dev, const unsigned char *buf, int length)
void *buffer = malloc(1);
libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_out, buffer, 0, tx_callback, dev, 0);
if((res = libusb_submit_transfer(xfer)) < 0) {
- usbmuxd_log(LL_ERROR, "Failed to submit TX ZLP transfer to device %d-%d: %d", dev->bus, dev->address, res);
+ usbmuxd_log(LL_ERROR, "Failed to submit TX ZLP transfer to device %d-%d: %s", dev->bus, dev->address, libusb_error_name(res));
libusb_free_transfer(xfer);
return res;
}
@@ -248,7 +258,7 @@ static int start_rx_loop(struct usb_device *dev)
buf = malloc(USB_MRU);
libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_in, buf, USB_MRU, rx_callback, dev, 0);
if((res = libusb_submit_transfer(xfer)) != 0) {
- usbmuxd_log(LL_ERROR, "Failed to submit RX transfer to device %d-%d: %d", dev->bus, dev->address, res);
+ usbmuxd_log(LL_ERROR, "Failed to submit RX transfer to device %d-%d: %s", dev->bus, dev->address, libusb_error_name(res));
libusb_free_transfer(xfer);
return res;
}
@@ -350,160 +360,233 @@ static void get_langid_callback(struct libusb_transfer *transfer)
libusb_fill_control_transfer(transfer, usbdev->dev, transfer->buffer, get_serial_callback, usbdev, 1000);
if((res = libusb_submit_transfer(transfer)) < 0) {
- usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d (%d)", usbdev->bus, usbdev->address, res);
+ usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d: %s", usbdev->bus, usbdev->address, libusb_error_name(res));
libusb_free_transfer(transfer);
}
}
-static int usb_device_add(libusb_device* dev)
+static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_context *context, libusb_transfer_cb_fn callback)
+{
+ struct libusb_transfer* ctrl_transfer = libusb_alloc_transfer(0);
+ int ret = 0;
+ unsigned char* buffer = calloc(LIBUSB_CONTROL_SETUP_SIZE + context->wLength, 1);
+ uint8_t bRequestType = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE;
+ libusb_fill_control_setup(buffer, bRequestType, context->bRequest, context->wValue, context->wIndex, context->wLength);
+
+ ctrl_transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER;
+ libusb_fill_control_transfer(ctrl_transfer, handle, buffer, callback, context, context->timeout);
+
+ ret = libusb_submit_transfer(ctrl_transfer);
+ return ret;
+}
+
+static struct usb_device* find_device(int bus, int address)
{
- int j, res;
- // the following are non-blocking operations on the device list
- uint8_t bus = libusb_get_bus_number(dev);
- uint8_t address = libusb_get_device_address(dev);
- struct libusb_device_descriptor devdesc;
- struct libusb_transfer *transfer;
- int found = 0;
FOREACH(struct usb_device *usbdev, &device_list) {
if(usbdev->bus == bus && usbdev->address == address) {
- usbdev->alive = 1;
- found = 1;
- break;
+ return usbdev;
}
} ENDFOREACH
- if(found)
- return 0; //device already found
+ return NULL;
+}
- if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %d", bus, address, res);
- return -1;
+/// @brief guess the current mode
+/// @param dev
+/// @param usbdev
+/// @param handle
+/// @return 0 - undetermined, 1 - initial, 2 - valeria, 3 - cdc_ncm
+static int guess_mode(struct libusb_device* dev, struct usb_device *usbdev)
+{
+ int res, j;
+ int has_valeria = 0, has_cdc_ncm = 0, has_usbmux = 0;
+ struct libusb_device_descriptor devdesc = usbdev->devdesc;
+ struct libusb_config_descriptor *config;
+ int bus = usbdev->bus;
+ int address = usbdev->address;
+
+ if(devdesc.bNumConfigurations <= 4) {
+ // Assume this is initial mode
+ return 1;
}
- if(devdesc.idVendor != VID_APPLE)
- return -1;
- if((devdesc.idProduct != PID_APPLE_T2_COPROCESSOR) &&
- ((devdesc.idProduct < PID_RANGE_LOW) ||
- (devdesc.idProduct > PID_RANGE_MAX)))
- return -1;
- libusb_device_handle *handle;
- usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
- // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any
- // blocking call
- if((res = libusb_open(dev, &handle)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res);
- return -1;
+
+ if(devdesc.bNumConfigurations != 5) {
+ // No known modes with more then 5 configurations
+ return 0;
}
- int desired_config = devdesc.bNumConfigurations;
- if (desired_config > 4) {
- desired_config = 4;
+ if((res = libusb_get_config_descriptor_by_value(dev, 5, &config)) != 0) {
+ usbmuxd_log(LL_NOTICE, "Could not get configuration 5 descriptor for device %i-%i: %s", bus, address, libusb_error_name(res));
+ return 0;
+ }
+
+ // Require both usbmux and one of the other interfaces to determine this is a valid configuration
+ for(j = 0 ; j < config->bNumInterfaces ; j++) {
+ const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
+ if(intf->bInterfaceClass == INTERFACE_CLASS &&
+ intf->bInterfaceSubClass == 42 &&
+ intf->bInterfaceProtocol == 255) {
+ has_valeria = 1;
+ }
+ // https://github.com/torvalds/linux/blob/72a85e2b0a1e1e6fb4ee51ae902730212b2de25c/include/uapi/linux/usb/cdc.h#L22
+ // 2 for Communication class, 0xd for CDC NCM subclass
+ if(intf->bInterfaceClass == 2 &&
+ intf->bInterfaceSubClass == 0xd) {
+ has_cdc_ncm = 1;
+ }
+ if(intf->bInterfaceClass == INTERFACE_CLASS &&
+ intf->bInterfaceSubClass == INTERFACE_SUBCLASS &&
+ intf->bInterfaceProtocol == INTERFACE_PROTOCOL) {
+ has_usbmux = 1;
+ }
}
+
+ libusb_free_config_descriptor(config);
+
+ if(has_valeria && has_usbmux) {
+ usbmuxd_log(LL_NOTICE, "Found Valeria and Apple USB Multiplexor in device %i-%i configuration 5", bus, address);
+ return 2;
+ }
+
+ if(has_cdc_ncm && has_usbmux) {
+ usbmuxd_log(LL_NOTICE, "Found CDC-NCM and Apple USB Multiplexor in device %i-%i configuration 5", bus, address);
+ return 3;
+ }
+
+ return 0;
+}
+
+/// @brief Finds and sets the valid configuration, interface and endpoints on the usb_device
+static int set_valid_configuration(struct libusb_device* dev, struct usb_device *usbdev, struct libusb_device_handle *handle)
+{
+ int j, k, res, found = 0;
+ struct libusb_config_descriptor *config;
+ const struct libusb_interface_descriptor *intf;
+ struct libusb_device_descriptor devdesc = usbdev->devdesc;
+ int bus = usbdev->bus;
+ int address = usbdev->address;
int current_config = 0;
+
if((res = libusb_get_configuration(handle, &current_config)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %d", bus, address, res);
- libusb_close(handle);
+ usbmuxd_log(LL_WARNING, "Could not get current configuration for device %d-%d: %s", bus, address, libusb_error_name(res));
return -1;
}
- if (current_config != desired_config) {
- struct libusb_config_descriptor *config;
- if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) {
- usbmuxd_log(LL_NOTICE, "Could not get old configuration descriptor for device %d-%d: %d", bus, address, res);
- } else {
- for(j=0; j<config->bNumInterfaces; j++) {
- const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
- if((res = libusb_kernel_driver_active(handle, intf->bInterfaceNumber)) < 0) {
- usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %d", intf->bInterfaceNumber, bus, address, res);
+
+ for(j = devdesc.bNumConfigurations ; j > 0 ; j--) {
+ if((res = libusb_get_config_descriptor_by_value(dev, j, &config)) != 0) {
+ usbmuxd_log(LL_NOTICE, "Could not get configuration %i descriptor for device %i-%i: %s", j, bus, address, libusb_error_name(res));
+ continue;
+ }
+ for(k = 0 ; k < config->bNumInterfaces ; k++) {
+ intf = &config->interface[k].altsetting[0];
+ if(intf->bInterfaceClass == INTERFACE_CLASS ||
+ intf->bInterfaceSubClass == INTERFACE_SUBCLASS ||
+ intf->bInterfaceProtocol == INTERFACE_PROTOCOL) {
+ usbmuxd_log(LL_NOTICE, "Found usbmux interface for device %i-%i: %i", bus, address, intf->bInterfaceNumber);
+ if(intf->bNumEndpoints != 2) {
+ usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address);
+ continue;
+ }
+ if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT &&
+ (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) {
+ usbdev->interface = intf->bInterfaceNumber;
+ usbdev->ep_out = intf->endpoint[0].bEndpointAddress;
+ usbdev->ep_in = intf->endpoint[1].bEndpointAddress;
+ usbmuxd_log(LL_INFO, "Found interface %i with endpoints %02x/%02x for device %i-%i", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address);
+ found = 1;
+ break;
+ } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT &&
+ (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) {
+ usbdev->interface = intf->bInterfaceNumber;
+ usbdev->ep_out = intf->endpoint[1].bEndpointAddress;
+ usbdev->ep_in = intf->endpoint[0].bEndpointAddress;
+ usbmuxd_log(LL_INFO, "Found interface %i with swapped endpoints %02x/%02x for device %i-%i", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address);
+ found = 1;
+ break;
+ } else {
+ usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address);
+ }
+ }
+ }
+ if(!found) {
+ libusb_free_config_descriptor(config);
+ continue;
+ }
+ // If set configuration is required, try to first detach all kernel drivers
+ if (current_config == 0) {
+ usbmuxd_log(LL_DEBUG, "Device %d-%d is unconfigured", bus, address);
+ }
+ if(current_config == 0 || config->bConfigurationValue != current_config) {
+ usbmuxd_log(LL_NOTICE, "Changing configuration of device %i-%i: %i -> %i", bus, address, current_config, config->bConfigurationValue);
+ for(k=0 ; k < config->bNumInterfaces ; k++) {
+ const struct libusb_interface_descriptor *intf1 = &config->interface[k].altsetting[0];
+ if((res = libusb_kernel_driver_active(handle, intf1->bInterfaceNumber)) < 0) {
+ usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %s", intf1->bInterfaceNumber, bus, address, libusb_error_name(res));
continue;
}
if(res == 1) {
- usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf->bInterfaceNumber);
- if((res = libusb_detach_kernel_driver(handle, intf->bInterfaceNumber)) < 0) {
- usbmuxd_log(LL_WARNING, "Could not detach kernel driver (%d), configuration change will probably fail!", res);
+ usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf1->bInterfaceNumber);
+ if((res = libusb_detach_kernel_driver(handle, intf1->bInterfaceNumber)) < 0) {
+ usbmuxd_log(LL_WARNING, "Could not detach kernel driver, configuration change will probably fail! %s", libusb_error_name(res));
continue;
}
}
}
- libusb_free_config_descriptor(config);
- }
-
- usbmuxd_log(LL_INFO, "Setting configuration for device %d-%d, from %d to %d", bus, address, current_config, desired_config);
- if((res = libusb_set_configuration(handle, desired_config)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %d", desired_config, bus, address, res);
- libusb_close(handle);
- return -1;
+ if((res = libusb_set_configuration(handle, j)) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %s", j, bus, address, libusb_error_name(res));
+ libusb_free_config_descriptor(config);
+ continue;
+ }
}
+
+ libusb_free_config_descriptor(config);
+ break;
}
- struct libusb_config_descriptor *config;
- if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not get configuration descriptor for device %d-%d: %d", bus, address, res);
- libusb_close(handle);
+ if(!found) {
+ usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %i-%i", bus, address);
return -1;
}
- struct usb_device *usbdev;
- usbdev = malloc(sizeof(struct usb_device));
- memset(usbdev, 0, sizeof(*usbdev));
+ return 0;
+}
- for(j=0; j<config->bNumInterfaces; j++) {
- const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
- if(intf->bInterfaceClass != INTERFACE_CLASS ||
- intf->bInterfaceSubClass != INTERFACE_SUBCLASS ||
- intf->bInterfaceProtocol != INTERFACE_PROTOCOL)
- continue;
- if(intf->bNumEndpoints != 2) {
- usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address);
- continue;
- }
- if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT &&
- (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) {
- usbdev->interface = intf->bInterfaceNumber;
- usbdev->ep_out = intf->endpoint[0].bEndpointAddress;
- usbdev->ep_in = intf->endpoint[1].bEndpointAddress;
- usbmuxd_log(LL_INFO, "Found interface %d with endpoints %02x/%02x for device %d-%d", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address);
- break;
- } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT &&
- (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) {
- usbdev->interface = intf->bInterfaceNumber;
- usbdev->ep_out = intf->endpoint[1].bEndpointAddress;
- usbdev->ep_in = intf->endpoint[0].bEndpointAddress;
- usbmuxd_log(LL_INFO, "Found interface %d with swapped endpoints %02x/%02x for device %d-%d", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address);
- break;
- } else {
- usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address);
- }
+static void device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle)
+{
+ struct usb_device *usbdev = find_device(context->bus, context->address);
+ if(!usbdev) {
+ usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting initialization", context->bus, context->address);
+ return;
}
+ struct libusb_device *dev = context->dev;
+ struct libusb_device_descriptor devdesc = usbdev->devdesc;
+ int bus = context->bus;
+ int address = context->address;
+ int res;
+ struct libusb_transfer *transfer;
- if(j == config->bNumInterfaces) {
- usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %d-%d", bus, address);
- libusb_free_config_descriptor(config);
- libusb_close(handle);
- free(usbdev);
- return -1;
+ if((res = set_valid_configuration(dev, usbdev, handle)) != 0) {
+ usbdev->alive = 0;
+ return;
}
- libusb_free_config_descriptor(config);
-
if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %d", usbdev->interface, bus, address, res);
- libusb_close(handle);
- free(usbdev);
- return -1;
+ usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %s", usbdev->interface, bus, address, libusb_error_name(res));
+ usbdev->alive = 0;
+ return;
}
transfer = libusb_alloc_transfer(0);
if(!transfer) {
- usbmuxd_log(LL_WARNING, "Failed to allocate transfer for device %d-%d: %d", bus, address, res);
- libusb_close(handle);
- free(usbdev);
- return -1;
+ usbmuxd_log(LL_WARNING, "Failed to allocate transfer for device %d-%d: %s", bus, address, libusb_error_name(res));
+ usbdev->alive = 0;
+ return;
}
unsigned char *transfer_buffer = malloc(1024 + LIBUSB_CONTROL_SETUP_SIZE + 8);
if (!transfer_buffer) {
- usbmuxd_log(LL_WARNING, "Failed to allocate transfer buffer for device %d-%d: %d", bus, address, res);
- libusb_close(handle);
- free(usbdev);
- return -1;
+ usbmuxd_log(LL_WARNING, "Failed to allocate transfer buffer for device %d-%d: %s", bus, address, libusb_error_name(res));
+ usbdev->alive = 0;
+ return;
}
memset(transfer_buffer, '\0', 1024 + LIBUSB_CONTROL_SETUP_SIZE + 8);
@@ -551,19 +634,166 @@ static int usb_device_add(libusb_device* dev)
libusb_fill_control_transfer(transfer, handle, transfer_buffer, get_langid_callback, usbdev, 1000);
if((res = libusb_submit_transfer(transfer)) < 0) {
- usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d (%d)", usbdev->bus, usbdev->address, res);
+ usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d: %s", usbdev->bus, usbdev->address, libusb_error_name(res));
libusb_free_transfer(transfer);
- libusb_close(handle);
free(transfer_buffer);
- free(usbdev);
+ usbdev->alive = 0;
+ return;
+ }
+}
+
+static void switch_mode_cb(struct libusb_transfer* transfer)
+{
+ // For old devices not supporting mode swtich, if anything goes wrong - continue in current mode
+ struct mode_context* context = transfer->user_data;
+ struct usb_device *dev = find_device(context->bus, context->address);
+ if(!dev) {
+ usbmuxd_log(LL_WARNING, "Device %d-%d is missing from device list", context->bus, context->address);
+ }
+ if(transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+ usbmuxd_log(LL_ERROR, "Failed to request mode switch for device %i-%i (%i). Completing initialization in current mode",
+ context->bus, context->address, transfer->status);
+ device_complete_initialization(context, transfer->dev_handle);
+ }
+ else {
+ unsigned char *data = libusb_control_transfer_get_data(transfer);
+ if(data[0] != 0) {
+ usbmuxd_log(LL_INFO, "Received unexpected response for device %i-%i mode switch (%i). Completing initialization in current mode",
+ context->bus, context->address, data[0]);
+ device_complete_initialization(context, transfer->dev_handle);
+ }
+ }
+ free(context);
+ if(transfer->buffer)
+ free(transfer->buffer);
+}
+
+static void get_mode_cb(struct libusb_transfer* transfer)
+{
+ // For old devices not supporting mode swtich, if anything goes wrong - continue in current mode
+ int res;
+ struct mode_context* context = transfer->user_data;
+ struct usb_device *dev = find_device(context->bus, context->address);
+ if(!dev) {
+ usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting mode switch", context->bus, context->address);
+ free(context);
+ return;
+ }
+
+ if(transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+ usbmuxd_log(LL_ERROR, "Failed to request get mode for device %i-%i (%i). Completing initialization in current mode",
+ context->bus, context->address, transfer->status);
+ device_complete_initialization(context, transfer->dev_handle);
+ free(context);
+ return;
+ }
+
+ unsigned char *data = libusb_control_transfer_get_data(transfer);
+
+ char* desired_mode_char = getenv(ENV_DEVICE_MODE);
+ int desired_mode = desired_mode_char ? atoi(desired_mode_char) : 3;
+ int guessed_mode = guess_mode(context->dev, dev);
+
+ // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise.
+ usbmuxd_log(LL_INFO, "Received response %i:%i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], data[3], context->bus, context->address);
+ if(desired_mode >= 1 && desired_mode <= 3 &&
+ guessed_mode > 0 && // do not switch mode if guess failed
+ guessed_mode != desired_mode) {
+ usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", context->bus, context->address, desired_mode);
+
+ context->bRequest = APPLE_VEND_SPECIFIC_SET_MODE;
+ context->wValue = 0;
+ context->wIndex = desired_mode;
+ context->wLength = 1;
+
+ if((res = submit_vendor_specific(transfer->dev_handle, context, switch_mode_cb)) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not request to switch mode %i for device %i-%i (%i)", context->wIndex, context->bus, context->address, res);
+ dev->alive = 0;
+ free(context);
+ }
+ }
+ else {
+ usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode from %i to %i", context->bus, context->address, guessed_mode, desired_mode);
+ device_complete_initialization(context, transfer->dev_handle);
+ free(context);
+ }
+ if(transfer->buffer)
+ free(transfer->buffer);
+}
+
+static int usb_device_add(libusb_device* dev)
+{
+ int res;
+ // the following are non-blocking operations on the device list
+ uint8_t bus = libusb_get_bus_number(dev);
+ uint8_t address = libusb_get_device_address(dev);
+ struct libusb_device_descriptor devdesc;
+ struct usb_device *usbdev = find_device(bus, address);
+ if(usbdev) {
+ usbdev->alive = 1;
+ return 0; //device already found
+ }
+
+ if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %s", bus, address, libusb_error_name(res));
+ return -1;
+ }
+ if(devdesc.idVendor != VID_APPLE)
+ return -1;
+ if((devdesc.idProduct != PID_APPLE_T2_COPROCESSOR) &&
+ ((devdesc.idProduct < PID_APPLE_SILICON_RESTORE_LOW) ||
+ (devdesc.idProduct > PID_APPLE_SILICON_RESTORE_MAX)) &&
+ ((devdesc.idProduct < PID_RANGE_LOW) ||
+ (devdesc.idProduct > PID_RANGE_MAX)))
+ return -1;
+ libusb_device_handle *handle;
+ usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
+ // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any
+ // blocking call
+ if((res = libusb_open(dev, &handle)) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %s", bus, address, libusb_error_name(res));
return -1;
}
+ // Add the created handle to the device list, so we can close it in case of failure/disconnection
+ usbdev = malloc(sizeof(struct usb_device));
+ memset(usbdev, 0, sizeof(*usbdev));
+
+ usbdev->serial[0] = 0;
+ usbdev->bus = bus;
+ usbdev->address = address;
+ usbdev->devdesc = devdesc;
+ usbdev->speed = 0;
+ usbdev->dev = handle;
+ usbdev->alive = 1;
+
collection_init(&usbdev->tx_xfers);
collection_init(&usbdev->rx_xfers);
collection_add(&device_list, usbdev);
+ // On top of configurations, Apple have multiple "modes" for devices, namely:
+ // 1: An "initial" mode with 4 configurations
+ // 2: "Valeria" mode, where configuration 5 is included with interface for H.265 video capture (activated when recording screen with QuickTime in macOS)
+ // 3: "CDC NCM" mode, where configuration 5 is included with interface for Ethernet/USB (activated using internet-sharing feature in macOS)
+ // Request current mode asynchroniously, so it can be changed in callback if needed
+ usbmuxd_log(LL_INFO, "Requesting current mode from device %i-%i", bus, address);
+ struct mode_context* context = malloc(sizeof(struct mode_context));
+ context->dev = dev;
+ context->bus = bus;
+ context->address = address;
+ context->bRequest = APPLE_VEND_SPECIFIC_GET_MODE;
+ context->wValue = 0;
+ context->wIndex = 0;
+ context->wLength = 4;
+ context->timeout = 1000;
+
+ if(submit_vendor_specific(handle, context, get_mode_cb) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not request current mode from device %d-%d", bus, address);
+ // Schedule device for close and cleanup
+ usbdev->alive = 0;
+ return -1;
+ }
return 0;
}
@@ -703,7 +933,7 @@ int usb_get_timeout(void)
if(res == 0)
return pollrem;
if(res < 0) {
- usbmuxd_log(LL_ERROR, "libusb_get_next_timeout failed: %d", res);
+ usbmuxd_log(LL_ERROR, "libusb_get_next_timeout failed: %s", libusb_error_name(res));
return pollrem;
}
msec = tv.tv_sec * 1000;
@@ -720,7 +950,7 @@ int usb_process(void)
tv.tv_sec = tv.tv_usec = 0;
res = libusb_handle_events_timeout(NULL, &tv);
if(res < 0) {
- usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res);
+ usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %s", libusb_error_name(res));
return res;
}
@@ -730,7 +960,7 @@ int usb_process(void)
if(dev_poll_remain_ms() <= 0) {
res = usb_discover();
if(res < 0) {
- usbmuxd_log(LL_ERROR, "usb_discover failed: %d", res);
+ usbmuxd_log(LL_ERROR, "usb_discover failed: %s", libusb_error_name(res));
return res;
}
}
@@ -755,7 +985,7 @@ int usb_process_timeout(int msec)
}
res = libusb_handle_events_timeout(NULL, &tleft);
if(res < 0) {
- usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res);
+ usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %s", libusb_error_name(res));
return res;
}
// reap devices marked dead due to an RX error
@@ -794,17 +1024,24 @@ static int usb_hotplug_cb(libusb_context *ctx, libusb_device *device, libusb_hot
int usb_init(void)
{
int res;
- usbmuxd_log(LL_DEBUG, "usb_init for linux / libusb 1.0");
+ const struct libusb_version* libusb_version_info = libusb_get_version();
+ usbmuxd_log(LL_NOTICE, "Using libusb %d.%d.%d", libusb_version_info->major, libusb_version_info->minor, libusb_version_info->micro);
devlist_failures = 0;
device_polling = 1;
res = libusb_init(NULL);
- //libusb_set_debug(NULL, 3);
- if(res != 0) {
- usbmuxd_log(LL_FATAL, "libusb_init failed: %d", res);
+
+ if (res != 0) {
+ usbmuxd_log(LL_FATAL, "libusb_init failed: %s", libusb_error_name(res));
return -1;
}
+#if LIBUSB_API_VERSION >= 0x01000106
+ libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, (log_level >= LL_DEBUG ? LIBUSB_LOG_LEVEL_DEBUG: (log_level >= LL_WARNING ? LIBUSB_LOG_LEVEL_WARNING: LIBUSB_LOG_LEVEL_NONE)));
+#else
+ libusb_set_debug(NULL, (log_level >= LL_DEBUG ? LIBUSB_LOG_LEVEL_DEBUG: (log_level >= LL_WARNING ? LIBUSB_LOG_LEVEL_WARNING: LIBUSB_LOG_LEVEL_NONE)));
+#endif
+
collection_init(&device_list);
#ifdef HAVE_LIBUSB_HOTPLUG_API
@@ -814,7 +1051,7 @@ int usb_init(void)
if (res == LIBUSB_SUCCESS) {
device_polling = 0;
} else {
- usbmuxd_log(LL_ERROR, "ERROR: Could not register for libusb hotplug events (%d)", res);
+ usbmuxd_log(LL_ERROR, "ERROR: Could not register for libusb hotplug events. %s", libusb_error_name(res));
}
} else {
usbmuxd_log(LL_ERROR, "libusb does not support hotplug events");
diff --git a/src/usb.h b/src/usb.h
index 18f2a72..4e44cce 100644
--- a/src/usb.h
+++ b/src/usb.h
@@ -47,6 +47,12 @@
#define PID_RANGE_LOW 0x1290
#define PID_RANGE_MAX 0x12af
#define PID_APPLE_T2_COPROCESSOR 0x8600
+#define PID_APPLE_SILICON_RESTORE_LOW 0x1901
+#define PID_APPLE_SILICON_RESTORE_MAX 0x1905
+
+#define ENV_DEVICE_MODE "USBMUXD_DEFAULT_DEVICE_MODE"
+#define APPLE_VEND_SPECIFIC_GET_MODE 0x45
+#define APPLE_VEND_SPECIFIC_SET_MODE 0x52
struct usb_device;
diff --git a/src/usbmuxd-proto.h b/src/usbmuxd-proto.h
index 9416416..93df00e 100644
--- a/src/usbmuxd-proto.h
+++ b/src/usbmuxd-proto.h
@@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/* Protocol defintion for usbmuxd proxy protocol */
+/* Protocol definition for usbmuxd proxy protocol */
#ifndef USBMUXD_PROTO_H
#define USBMUXD_PROTO_H
diff --git a/src/utils.c b/src/utils.c
index 206c684..2cc5675 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -76,254 +76,6 @@ void fdlist_reset(struct fdlist *list)
list->count = 0;
}
-#define CAPACITY_STEP 8
-
-void collection_init(struct collection *col)
-{
- col->list = malloc(sizeof(void *) * CAPACITY_STEP);
- memset(col->list, 0, sizeof(void *) * CAPACITY_STEP);
- col->capacity = CAPACITY_STEP;
-}
-
-void collection_free(struct collection *col)
-{
- free(col->list);
- col->list = NULL;
- col->capacity = 0;
-}
-
-void collection_add(struct collection *col, void *element)
-{
- int i;
- for(i=0; i<col->capacity; i++) {
- if(!col->list[i]) {
- col->list[i] = element;
- return;
- }
- }
- col->list = realloc(col->list, sizeof(void*) * (col->capacity + CAPACITY_STEP));
- memset(&col->list[col->capacity], 0, sizeof(void *) * CAPACITY_STEP);
- col->list[col->capacity] = element;
- col->capacity += CAPACITY_STEP;
-}
-
-void collection_remove(struct collection *col, void *element)
-{
- int i;
- for(i=0; i<col->capacity; i++) {
- if(col->list[i] == element) {
- col->list[i] = NULL;
- return;
- }
- }
- util_error("collection_remove: element %p not present in collection %p (cap %d)", element, col, col->capacity);
-}
-
-int collection_count(struct collection *col)
-{
- int i, cnt = 0;
- for(i=0; i<col->capacity; i++) {
- if(col->list[i])
- cnt++;
- }
- return cnt;
-}
-
-void collection_copy(struct collection *dest, struct collection *src)
-{
- if (!dest || !src) return;
- dest->capacity = src->capacity;
- dest->list = malloc(sizeof(void*) * src->capacity);
- memcpy(dest->list, src->list, sizeof(void*) * src->capacity);
-}
-
-#ifndef HAVE_STPCPY
-/**
- * Copy characters from one string into another
- *
- * @note: The strings should not overlap, as the behavior is undefined.
- *
- * @s1: The source string.
- * @s2: The destination string.
- *
- * @return a pointer to the terminating `\0' character of @s1,
- * or NULL if @s1 or @s2 is NULL.
- */
-char *stpcpy(char * s1, const char * s2)
-{
- if (s1 == NULL || s2 == NULL)
- return NULL;
-
- strcpy(s1, s2);
-
- return s1 + strlen(s2);
-}
-#endif
-
-/**
- * Concatenate strings into a newly allocated string
- *
- * @note: Specify NULL for the last string in the varargs list
- *
- * @str: The first string in the list
- * @...: Subsequent strings. Use NULL for the last item.
- *
- * @return a newly allocated string, or NULL if @str is NULL. This will also
- * return NULL and set errno to ENOMEM if memory is exhausted.
- */
-char *string_concat(const char *str, ...)
-{
- size_t len;
- va_list args;
- char *s;
- char *result;
- char *dest;
-
- if (!str)
- return NULL;
-
- /* Compute final length */
-
- len = strlen(str) + 1; /* plus 1 for the null terminator */
-
- va_start(args, str);
- s = va_arg(args, char *);
- while (s) {
- len += strlen(s);
- s = va_arg(args, char*);
- }
- va_end(args);
-
- /* Concat each string */
-
- result = malloc(len);
- if (!result)
- return NULL; /* errno remains set */
-
- dest = result;
-
- dest = stpcpy(dest, str);
-
- va_start(args, str);
- s = va_arg(args, char *);
- while (s) {
- dest = stpcpy(dest, s);
- s = va_arg(args, char *);
- }
- va_end(args);
-
- return result;
-}
-
-int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
-{
- FILE *f;
- uint64_t size;
-
- *length = 0;
-
- f = fopen(filename, "rb");
- if (!f) {
- return 0;
- }
-
- fseek(f, 0, SEEK_END);
- size = ftell(f);
- rewind(f);
-
- if (size == 0) {
- fclose(f);
- return 0;
- }
-
- *buffer = (char*)malloc(sizeof(char)*(size+1));
-
- if (!buffer) {
- return 0;
- }
-
- int ret = 1;
- if (fread(*buffer, sizeof(char), size, f) != size) {
- usbmuxd_log(LL_ERROR, "%s: ERROR: couldn't read %d bytes from %s", __func__, (int)size, filename);
- free(*buffer);
- ret = 0;
- errno = EIO;
- }
- fclose(f);
-
- *length = size;
- return ret;
-}
-
-int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
-{
- FILE *f;
-
- f = fopen(filename, "wb");
- if (f) {
- size_t written = fwrite(buffer, sizeof(char), length, f);
- fclose(f);
-
- if (written == length) {
- return 1;
- }
- else {
- // Not all data could be written.
- errno = EIO;
- return 0;
- }
- }
- else {
- // Failed to open the file, let the caller know.
- return 0;
- }
-}
-
-int plist_read_from_filename(plist_t *plist, const char *filename)
-{
- char *buffer = NULL;
- uint64_t length;
-
- if (!filename)
- return 0;
-
- if (!buffer_read_from_filename(filename, &buffer, &length)) {
- return 0;
- }
-
- if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) {
- plist_from_bin(buffer, length, plist);
- } else {
- plist_from_xml(buffer, length, plist);
- }
-
- free(buffer);
-
- return 1;
-}
-
-int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
-{
- char *buffer = NULL;
- uint32_t length;
-
- if (!plist || !filename)
- return 0;
-
- if (format == PLIST_FORMAT_XML)
- plist_to_xml(plist, &buffer, &length);
- else if (format == PLIST_FORMAT_BINARY)
- plist_to_bin(plist, &buffer, &length);
- else
- return 0;
-
- int res = buffer_write_to_filename(filename, buffer, length);
-
- free(buffer);
-
- return res;
-}
-
#ifndef HAVE_CLOCK_GETTIME
typedef int clockid_t;
#define CLOCK_MONOTONIC 1
diff --git a/src/utils.h b/src/utils.h
index b5cab3f..ce3b2e0 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -43,49 +43,6 @@ void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events);
void fdlist_free(struct fdlist *list);
void fdlist_reset(struct fdlist *list);
-struct collection {
- void **list;
- int capacity;
-};
-
-void collection_init(struct collection *col);
-void collection_add(struct collection *col, void *element);
-void collection_remove(struct collection *col, void *element);
-int collection_count(struct collection *col);
-void collection_free(struct collection *col);
-void collection_copy(struct collection *dest, struct collection *src);
-
-#define MERGE_(a,b) a ## _ ## b
-#define LABEL_(a,b) MERGE_(a, b)
-#define UNIQUE_VAR(a) LABEL_(a, __LINE__)
-
-#define FOREACH(var, col) \
- do { \
- int UNIQUE_VAR(_iter); \
- for(UNIQUE_VAR(_iter)=0; UNIQUE_VAR(_iter)<(col)->capacity; UNIQUE_VAR(_iter)++) { \
- if(!(col)->list[UNIQUE_VAR(_iter)]) continue; \
- var = (col)->list[UNIQUE_VAR(_iter)];
-
-#define ENDFOREACH \
- } \
- } while(0);
-
-#ifndef HAVE_STPCPY
-char *stpcpy(char * s1, const char * s2);
-#endif
-char *string_concat(const char *str, ...);
-
-int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length);
-int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length);
-
-enum plist_format_t {
- PLIST_FORMAT_XML,
- PLIST_FORMAT_BINARY
-};
-
-int plist_read_from_filename(plist_t *plist, const char *filename);
-int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format);
-
uint64_t mstime64(void);
void get_tick_count(struct timeval * tv);
diff --git a/systemd/Makefile.am b/systemd/Makefile.am
index a23f1d1..1d40c25 100644
--- a/systemd/Makefile.am
+++ b/systemd/Makefile.am
@@ -1,7 +1,7 @@
edit = \
$(SED) -r \
-e 's|@sbindir[@]|$(sbindir)|g' \
- -e 's|@localstatedir[@]|$(localstatedir)|g' \
+ -e 's|@runstatedir[@]|$(runstatedir)|g' \
< $< > $@ || rm $@
if WANT_SYSTEMD
diff --git a/systemd/usbmuxd.service.in b/systemd/usbmuxd.service.in
index bee2476..3a27aee 100644
--- a/systemd/usbmuxd.service.in
+++ b/systemd/usbmuxd.service.in
@@ -4,4 +4,4 @@ Documentation=man:usbmuxd(8)
[Service]
ExecStart=@sbindir@/usbmuxd --user usbmux --systemd
-PIDFile=@localstatedir@/run/usbmuxd.pid
+PIDFile=@runstatedir@/usbmuxd.pid
diff --git a/udev/39-usbmuxd.rules.in b/udev/39-usbmuxd.rules.in
index 11d33c6..ac15593 100644
--- a/udev/39-usbmuxd.rules.in
+++ b/udev/39-usbmuxd.rules.in
@@ -1,13 +1,16 @@
# usbmuxd (Apple Mobile Device Muxer listening on /var/run/usbmuxd)
# systemd should receive all events relating to device
-SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/8600/*", TAG+="systemd"
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", TAG+="systemd"
# Initialize iOS devices into "deactivated" USB configuration state and activate usbmuxd
-SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/8600/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux", @udev_activation_rule@
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux", @udev_activation_rule@
+# but make sure iBridge (T1) doesn't end up in an unconfigured state
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/8600/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="1", OWNER="usbmux", @udev_activation_rule@
+
# Make sure properties don't get lost when bind action is called
-SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/8600/*", ACTION=="bind", ENV{USBMUX_SUPPORTED}="1", OWNER="usbmux", @udev_activation_rule@
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", ACTION=="bind", ENV{USBMUX_SUPPORTED}="1", OWNER="usbmux"
# Exit usbmuxd when the last device is removed
-SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/8600/*", ACTION=="remove", RUN+="@sbindir@/usbmuxd -x"
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", ACTION=="remove", RUN+="@sbindir@/usbmuxd -x"