From 5745de43d0435a6024e2f79f5559b56dbed3d100 Mon Sep 17 00:00:00 2001 From: lunzii Date: Fri, 25 Oct 2013 12:03:35 +0800 Subject: [PATCH 01/70] Port to android, build succeed with android-ndk-r8e on mac osx 10.9. --- daemon/device.c | 112 +++++++++++++++++++++++++++---------- daemon/device.h | 41 ++++++++++++++ daemon/main.c | 11 +++- libusbmuxd/libusbmuxd.c | 5 +- libusbmuxd/usbmuxd-proto.h | 4 ++ 5 files changed, 139 insertions(+), 34 deletions(-) diff --git a/daemon/device.c b/daemon/device.c index 8c786a72..399bb0c8 100644 --- a/daemon/device.c +++ b/daemon/device.c @@ -148,7 +148,11 @@ static int send_packet(struct mux_device *dev, enum mux_protocol proto, void *he hdrlen = sizeof(struct version_header); break; case MUX_PROTO_TCP: - hdrlen = sizeof(struct tcphdr); +#ifdef ANDROID + hdrlen = sizeof(struct tcphdr_bsd); +#else + hdrlen = sizeof(struct tcphdr); +#endif break; default: usbmuxd_log(LL_ERROR, "Invalid protocol %d for outgoing packet (dev %d hdr %p data %p len %d)", proto, dev->id, header, data, length); @@ -200,7 +204,11 @@ static uint16_t find_sport(struct mux_device *dev) static int send_anon_rst(struct mux_device *dev, uint16_t sport, uint16_t dport, uint32_t ack) { - struct tcphdr th; +#ifdef ANDROID + struct tcphdr_bsd th; +#else + struct tcphdr th; +#endif memset(&th, 0, sizeof(th)); th.th_sport = htons(sport); th.th_dport = htons(dport); @@ -216,7 +224,11 @@ static int send_anon_rst(struct mux_device *dev, uint16_t sport, uint16_t dport, static int send_tcp(struct mux_connection *conn, uint8_t flags, const unsigned char *data, int length) { - struct tcphdr th; +#ifdef ANDROID + struct tcphdr_bsd th; +#else + struct tcphdr th; +#endif memset(&th, 0, sizeof(th)); th.th_sport = htons(conn->sport); th.th_dport = htons(conn->dport); @@ -300,7 +312,12 @@ int device_start_connect(int device_id, uint16_t dport, struct mux_client *clien conn->tx_win = 131072; conn->rx_recvd = 0; conn->flags = 0; - conn->max_payload = USB_MTU - sizeof(struct mux_header) - sizeof(struct tcphdr); + +#ifdef ANDROID + conn->max_payload = USB_MTU - sizeof(struct mux_header) - sizeof(struct tcphdr_bsd); +#else + conn->max_payload = USB_MTU - sizeof(struct mux_header) - sizeof(struct tcphdr); +#endif conn->ob_buf = malloc(CONN_OUTBUF_SIZE); conn->ob_capacity = CONN_OUTBUF_SIZE; @@ -464,7 +481,12 @@ static void device_version_input(struct mux_device *dev, struct version_header * client_device_add(&info); } -static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) + +#ifdef ANDROID + static void device_tcp_input(struct mux_device *dev, struct tcphdr_bsd *th, unsigned char *payload, uint32_t payload_length) +#else + static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) +#endif { uint16_t sport = ntohs(th->th_dport); uint16_t dport = ntohs(th->th_sport); @@ -603,32 +625,62 @@ void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_ return; } - struct tcphdr *th; - unsigned char *payload; - uint32_t payload_length; +#ifdef ANDROID + struct tcphdr_bsd *th; + unsigned char *payload; + uint32_t payload_length; - switch(ntohl(mhdr->protocol)) { - case MUX_PROTO_VERSION: - if(length < (sizeof(struct mux_header) + sizeof(struct version_header))) { - usbmuxd_log(LL_ERROR, "Incoming version packet is too small (%d)", length); - return; - } - device_version_input(dev, (struct version_header *)(mhdr+1)); - break; - case MUX_PROTO_TCP: - if(length < (sizeof(struct mux_header) + sizeof(struct tcphdr))) { - usbmuxd_log(LL_ERROR, "Incoming TCP packet is too small (%d)", length); - return; - } - th = (struct tcphdr *)(mhdr+1); - payload = (unsigned char *)(th+1); - payload_length = length - sizeof(struct tcphdr) - sizeof(struct mux_header); - device_tcp_input(dev, (struct tcphdr *)(mhdr+1), payload, payload_length); - break; - default: - usbmuxd_log(LL_ERROR, "Incoming packet for device %d has unknown protocol 0x%x)", dev->id, ntohl(mhdr->protocol)); - break; - } + switch(ntohl(mhdr->protocol)) { + case MUX_PROTO_VERSION: + if(length < (sizeof(struct mux_header) + sizeof(struct version_header))) { + usbmuxd_log(LL_ERROR, "Incoming version packet is too small (%d)", length); + return; + } + device_version_input(dev, (struct version_header *)(mhdr+1)); + break; + case MUX_PROTO_TCP: + if(length < (sizeof(struct mux_header) + sizeof(struct tcphdr))) { + usbmuxd_log(LL_ERROR, "Incoming TCP packet is too small (%d)", length); + return; + } + th = (struct tcphdr_bsd *)(mhdr+1); + payload = (unsigned char *)(th+1); + payload_length = length - sizeof(struct tcphdr_bsd) - sizeof(struct mux_header); + device_tcp_input(dev, (struct tcphdr_bsd *)(mhdr+1), payload, payload_length); + break; + default: + usbmuxd_log(LL_ERROR, "Incoming packet for device %d has unknown protocol 0x%x)", dev->id, ntohl(mhdr->protocol)); + break; + } +#else + struct tcphdr *th; + unsigned char *payload; + uint32_t payload_length; + + switch(ntohl(mhdr->protocol)) { + case MUX_PROTO_VERSION: + if(length < (sizeof(struct mux_header) + sizeof(struct version_header))) { + usbmuxd_log(LL_ERROR, "Incoming version packet is too small (%d)", length); + return; + } + device_version_input(dev, (struct version_header *)(mhdr+1)); + break; + case MUX_PROTO_TCP: + if(length < (sizeof(struct mux_header) + sizeof(struct tcphdr))) { + usbmuxd_log(LL_ERROR, "Incoming TCP packet is too small (%d)", length); + return; + } + th = (struct tcphdr *)(mhdr+1); + payload = (unsigned char *)(th+1); + payload_length = length - sizeof(struct tcphdr) - sizeof(struct mux_header); + device_tcp_input(dev, (struct tcphdr *)(mhdr+1), payload, payload_length); + break; + default: + usbmuxd_log(LL_ERROR, "Incoming packet for device %d has unknown protocol 0x%x)", dev->id, ntohl(mhdr->protocol)); + break; + } +#endif + } diff --git a/daemon/device.h b/daemon/device.h index ea770697..a06cd071 100644 --- a/daemon/device.h +++ b/daemon/device.h @@ -49,4 +49,45 @@ void device_check_timeouts(void); void device_init(void); void device_kill_connections(void); void device_shutdown(void); + +#ifdef ANDROID +#include + +typedef u_int32_t tcp_seq; + +/* + * TCP header. + * Per RFC 793, September, 1981. + */ +struct tcphdr_bsd { + u_short th_sport; /* source port */ + u_short th_dport; /* destination port */ + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ + #if __BYTE_ORDER == __LITTLE_ENDIAN + u_int th_x2:4, /* (unused) */ + th_off:4; /* data offset */ + #endif + #if __BYTE_ORDER == __BIG_ENDIAN + u_int th_off:4, /* data offset */ + th_x2:4; /* (unused) */ + #endif + u_char th_flags; + #define TH_FIN 0x01 + #define TH_SYN 0x02 + #define TH_RST 0x04 + #define TH_PUSH 0x08 + #define TH_ACK 0x10 + #define TH_URG 0x20 + #define TH_ECE 0x40 + #define TH_CWR 0x80 + #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) + + u_short th_win; /* window */ + u_short th_sum; /* checksum */ + u_short th_urp; /* urgent pointer */ +}; + +#endif + #endif diff --git a/daemon/main.c b/daemon/main.c index 140bee15..0eaae8bf 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -47,8 +47,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "device.h" #include "client.h" -static const char *socket_path = "/var/run/usbmuxd"; -static const char *lockfile = "/var/run/usbmuxd.pid"; +#ifdef ANDROID + static const char *socket_path = "/data/local/tmp/usbmuxd"; + static const char *lockfile = "/data/local/tmp/usbmuxd.pid"; +#else + static const char *socket_path = "/var/run/usbmuxd"; + static const char *lockfile = "/var/run/usbmuxd.pid"; +#endif int should_exit; int should_discover; @@ -147,7 +152,7 @@ void set_signal_handlers(void) sigaction(SIGUSR2, &sa, NULL); } -#if defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) static int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask) { int ready; diff --git a/libusbmuxd/libusbmuxd.c b/libusbmuxd/libusbmuxd.c index 20ac8ab2..64d1a489 100644 --- a/libusbmuxd/libusbmuxd.c +++ b/libusbmuxd/libusbmuxd.c @@ -690,7 +690,10 @@ int usbmuxd_unsubscribe() } #else if (pthread_kill(devmon, 0) == 0) { - pthread_cancel(devmon); +#ifdef ANDROID +#else + pthread_cancel(devmon); +#endif pthread_join(devmon, NULL); } #endif diff --git a/libusbmuxd/usbmuxd-proto.h b/libusbmuxd/usbmuxd-proto.h index be9e7092..33e58df6 100644 --- a/libusbmuxd/usbmuxd-proto.h +++ b/libusbmuxd/usbmuxd-proto.h @@ -31,8 +31,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #if defined(WIN32) || defined(__CYGWIN__) #define USBMUXD_SOCKET_PORT 27015 #else +#ifdef ANDROID +#define USBMUXD_SOCKET_FILE "/data/local/tmp/usbmuxd" +#else #define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" #endif +#endif #ifdef __cplusplus extern "C" { From f646afc045ce51b2c5e7f2e761084d708137641a Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 17 Sep 2013 11:30:01 +0200 Subject: [PATCH 02/70] remove libusbmuxd sources and adapt source tree to use autotools libusbmuxd has been split off and is now managed in a separate repository. By the time of this commit, the repository is: git clone http://git.sukimashita.com/libusbmuxd.git --- .gitignore | 38 ++- CMakeLists.txt | 83 ----- COPYING.LGPLv2.1 | 502 ------------------------------ Makefile.am | 3 + Modules/CheckConstantExists.cmake | 38 --- Modules/FindInotify.cmake | 11 - Modules/FindPLIST.cmake | 31 -- Modules/FindUSB.cmake | 40 --- Modules/LibFindMacros.cmake | 99 ------ Modules/VersionTag.cmake | 13 - Modules/cmake_uninstall.cmake.in | 21 -- Modules/describe.sh | 17 - README | 12 +- README.devel | 50 --- autogen.sh | 15 + configure.ac | 96 ++++++ daemon/CMakeLists.txt | 23 -- libusbmuxd.pc.in | 11 - libusbmuxd/CMakeLists.txt | 45 --- libusbmuxd/sock_stuff.c | 375 ---------------------- libusbmuxd/sock_stuff.h | 65 ---- libusbmuxd/usbmuxd.h | 191 ------------ m4/as-compiler-flag.m4 | 62 ++++ python-client/.gitignore | 3 - python-client/tcprelay.py | 148 --------- python-client/usbmux.py | 246 --------------- src/Makefile.am | 14 + {daemon => src}/client.c | 0 {daemon => src}/client.h | 0 {daemon => src}/device.c | 0 {daemon => src}/device.h | 0 {daemon => src}/log.c | 0 {daemon => src}/log.h | 0 {daemon => src}/main.c | 2 +- {daemon => src}/usb-linux.c | 0 {daemon => src}/usb.h | 0 {common => src}/utils.c | 10 +- {common => src}/utils.h | 2 - stuff/README | 25 -- stuff/com.openssh.sftp.plist | 41 --- tools/CMakeLists.txt | 11 - tools/iproxy.c | 281 ----------------- udev/85-usbmuxd.rules.in | 4 +- udev/CMakeLists.txt | 2 - 44 files changed, 232 insertions(+), 2398 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 COPYING.LGPLv2.1 create mode 100644 Makefile.am delete mode 100644 Modules/CheckConstantExists.cmake delete mode 100644 Modules/FindInotify.cmake delete mode 100644 Modules/FindPLIST.cmake delete mode 100644 Modules/FindUSB.cmake delete mode 100644 Modules/LibFindMacros.cmake delete mode 100644 Modules/VersionTag.cmake delete mode 100644 Modules/cmake_uninstall.cmake.in delete mode 100755 Modules/describe.sh delete mode 100644 README.devel create mode 100755 autogen.sh create mode 100644 configure.ac delete mode 100644 daemon/CMakeLists.txt delete mode 100644 libusbmuxd.pc.in delete mode 100644 libusbmuxd/CMakeLists.txt delete mode 100644 libusbmuxd/sock_stuff.c delete mode 100644 libusbmuxd/sock_stuff.h delete mode 100644 libusbmuxd/usbmuxd.h create mode 100644 m4/as-compiler-flag.m4 delete mode 100644 python-client/.gitignore delete mode 100644 python-client/tcprelay.py delete mode 100644 python-client/usbmux.py create mode 100644 src/Makefile.am rename {daemon => src}/client.c (100%) rename {daemon => src}/client.h (100%) rename {daemon => src}/device.c (100%) rename {daemon => src}/device.h (100%) rename {daemon => src}/log.c (100%) rename {daemon => src}/log.h (100%) rename {daemon => src}/main.c (99%) rename {daemon => src}/usb-linux.c (100%) rename {daemon => src}/usb.h (100%) rename {common => src}/utils.c (93%) rename {common => src}/utils.h (98%) delete mode 100644 stuff/README delete mode 100644 stuff/com.openssh.sftp.plist delete mode 100644 tools/CMakeLists.txt delete mode 100644 tools/iproxy.c delete mode 100644 udev/CMakeLists.txt diff --git a/.gitignore b/.gitignore index 0784410b..9a9e6e6a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,37 @@ +# git-ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +*.[oa] *~ -build - +*.po +*.lo +*.la +autom4te.cache/* +*.in +*/.deps/* +m4/* +swig/* +*.swp +*.patch +aclocal.m4 +config.h +config.log +config.sub +config.guess +config.status +configure +depcomp +install-sh +compile +main +ltmain.sh +missing +mkinstalldirs +libtool +*Makefile +py-compile +stamp-h1 +src/.libs +src/usbmuxd +udev/85-usbmuxd.rules diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 7a46282a..00000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,83 +0,0 @@ -PROJECT(usbmuxd) - -cmake_minimum_required(VERSION 2.6) - -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/Modules/") - -include(VersionTag) - -set(USBMUXD_VERSION "${VERSION_TAG}") -set(LIBUSBMUXD_VERSION "${VERSION_TAG}") -set(LIBUSBMUXD_SOVERSION "2") - -message("-- Configuring usbmuxd v${VERSION_TAG}") - -if(NOT DEFINED LIB_SUFFIX) - if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(LIB_SUFFIX "64" CACHE STRING "Define suffix of library directory name (32/64)" ) - else() - set(LIB_SUFFIX "" CACHE STRING "Define suffix of library directory name (32/64)" ) - endif() -endif() - -# let CFLAGS env override this -if(CMAKE_C_FLAGS STREQUAL "") - set(CMAKE_C_FLAGS "-O2") -endif() - -option(WANT_PLIST "Build with protocol version 1 support using libplist" ON) - -set(OPT_INCLUDES "") -set(OPT_LIBS "") -if(WANT_PLIST) - find_package(PLIST) - if(PLIST_FOUND) - set(HAVE_PLIST ON) - set(OPT_INCLUDES ${OPT_INCLUDES} ${PLIST_INCLUDE_DIRS}) - set(OPT_LIBS ${OPT_LIBS} ${PLIST_LIBRARIES}) - else() - message("* NOTE: libplist was not found!") - message("* libusbmuxd/usbmuxd will be build WITHOUT support for version 1") - message("* of the usbmux protocol (plist based).") - endif() -endif() - -option(WITH_USBMUXD "Build usbmux daemon (usbmuxd)" ON) -if(WIN32 AND WITH_USBMUXD) - message("** NOTE: usbmuxd cannot be built on WIN32 due to missing libusb-1.0 support!") - message(" If you need your own usbmuxd you have to use usbmuxd-legacy which works") - message(" with libusb-0.1; otherwise just use the one that ships with iTunes.") - message(" Building of usbmuxd has been disabled.") - set(WITH_USBMUXD OFF) -endif() -if(WITH_USBMUXD) - message("-- Will build usbmuxd: YES") -else() - message("-- Will build usbmuxd: NO") - message("** NOTE: will NOT build usbmuxd **") - if(WIN32 OR APPLE) - message("** Make sure iTunes is installed, otherwise this software will not work! **") - else() - message("** You'll need a working usbmuxd implementation for this software to work! **") - endif() -endif() - -add_definitions(-Wall) - -add_subdirectory (libusbmuxd) -if (WITH_USBMUXD) - add_subdirectory (daemon) - if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - add_subdirectory (udev) - endif() -endif() -add_subdirectory (tools) - -# pkg-config -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libusbmuxd.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libusbmuxd.pc") -# install pkg-config file -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libusbmuxd.pc" DESTINATION lib${LIB_SUFFIX}/pkgconfig/) - -# add uninstall target -configure_file("${CMAKE_SOURCE_DIR}/Modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) -add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") diff --git a/COPYING.LGPLv2.1 b/COPYING.LGPLv2.1 deleted file mode 100644 index 732811e4..00000000 --- a/COPYING.LGPLv2.1 +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..2cb1ca06 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,3 @@ +AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = src diff --git a/Modules/CheckConstantExists.cmake b/Modules/CheckConstantExists.cmake deleted file mode 100644 index 3d6d97e7..00000000 --- a/Modules/CheckConstantExists.cmake +++ /dev/null @@ -1,38 +0,0 @@ -# - Check if the given constant exists (as an enum, define, or whatever) -# CHECK_CONSTANT_EXISTS (CONSTANT HEADER VARIABLE) -# -# CONSTANT - the name of the constant you are interested in -# HEADER - the header(s) where the prototype should be declared -# VARIABLE - variable to store the result -# -# The following variables may be set before calling this macro to -# modify the way the check is run: -# -# CMAKE_REQUIRED_FLAGS = string of compile command line flags -# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) -# CMAKE_REQUIRED_INCLUDES = list of include directories -# -# Example: CHECK_CONSTANT_EXISTS(O_NOFOLLOW fcntl.h HAVE_O_NOFOLLOW) - - -INCLUDE(CheckCSourceCompiles) - -MACRO (CHECK_CONSTANT_EXISTS _CONSTANT _HEADER _RESULT) - SET(_INCLUDE_FILES) - FOREACH (it ${_HEADER}) - SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n") - ENDFOREACH (it) - - SET(_CHECK_CONSTANT_SOURCE_CODE " -${_INCLUDE_FILES} -void cmakeRequireConstant(int dummy,...){(void)dummy;} -int main() -{ - cmakeRequireConstant(0,${_CONSTANT}); - return 0; -} -") - CHECK_C_SOURCE_COMPILES("${_CHECK_CONSTANT_SOURCE_CODE}" ${_RESULT}) - -ENDMACRO (CHECK_CONSTANT_EXISTS) - diff --git a/Modules/FindInotify.cmake b/Modules/FindInotify.cmake deleted file mode 100644 index 90496d48..00000000 --- a/Modules/FindInotify.cmake +++ /dev/null @@ -1,11 +0,0 @@ -set(INOTIFY_H "NOTFOUND") -find_file(INOTIFY_H - "sys/inotify.h" - PATHS ENV INCLUDE -) - -if (INOTIFY_H) - set(INOTIFY_FOUND TRUE) -else() - set(INOTIFY_FOUND FALSE) -endif() diff --git a/Modules/FindPLIST.cmake b/Modules/FindPLIST.cmake deleted file mode 100644 index d51aa743..00000000 --- a/Modules/FindPLIST.cmake +++ /dev/null @@ -1,31 +0,0 @@ -# - Try to find libplist -# Once done, this will define -# -# PLIST_FOUND - system has libplist -# PLIST_INCLUDE_DIRS - the libplist include directories -# PLIST_LIBRARIES - link these to use libplist - -include(LibFindMacros) - -# Dependencies - -# Use pkg-config to get hints about paths -libfind_pkg_check_modules(PLIST_PKGCONF libplist >= 0.15) - -# Include dir -find_path(PLIST_INCLUDE_DIR - NAMES plist/plist.h - PATHS ${PLIST_PKGCONF_INCLUDE_DIRS} -) - -# Finally the library itself -find_library(PLIST_LIBRARY - NAMES plist - PATHS ${PLIST_PKGCONF_LIBRARY_DIRS} -) - -# Set the include dir variables and the libraries and let libfind_process do the rest. -# NOTE: Singular variables for this library, plural for libraries that this lib depends on. -set(PLIST_PROCESS_INCLUDES PLIST_INCLUDE_DIR) -set(PLIST_PROCESS_LIBS PLIST_LIBRARY) -libfind_process(PLIST) diff --git a/Modules/FindUSB.cmake b/Modules/FindUSB.cmake deleted file mode 100644 index 486864f9..00000000 --- a/Modules/FindUSB.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# - Try to find libusb-1.0 -# Once done, this will define -# -# USB_FOUND - system has libusb-1.0 -# USB_INCLUDE_DIRS - the libusb-1.0 include directories -# USB_LIBRARIES - link these to use libusb-1.0 - -include(LibFindMacros) - -# Dependencies - -# pkg-config + libusb fails on FreeBSD, though libusb is in base -if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")) - # Use pkg-config to get hints about paths - libfind_pkg_check_modules(USB_PKGCONF libusb-1.0>=1.0.3) - # We want to look for libusb-1.0 - set(USB_LIBRARY_NAME usb-1.0) -else() - set(USB_PKGCONF_INCLUDE_DIRS /usr/include) - set(USB_PKGCONF_LIBRARY_DIRS /usr/lib) - set(USB_LIBRARY_NAME usb) -endif() - -# Include dir -find_path(USB_INCLUDE_DIR - NAMES libusb.h - PATHS ${USB_PKGCONF_INCLUDE_DIRS} -) - -# Finally the library itself -find_library(USB_LIBRARY - NAMES ${USB_LIBRARY_NAME} - PATHS ${USB_PKGCONF_LIBRARY_DIRS} -) - -# Set the include dir variables and the libraries and let libfind_process do the rest. -# NOTE: Singular variables for this library, plural for libraries this this lib depends on. -set(USB_PROCESS_INCLUDES USB_INCLUDE_DIR) -set(USB_PROCESS_LIBS USB_LIBRARY) -libfind_process(USB) diff --git a/Modules/LibFindMacros.cmake b/Modules/LibFindMacros.cmake deleted file mode 100644 index 795d6b71..00000000 --- a/Modules/LibFindMacros.cmake +++ /dev/null @@ -1,99 +0,0 @@ -# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments -# used for the current package. For this to work, the first parameter must be the -# prefix of the current package, then the prefix of the new package etc, which are -# passed to find_package. -macro (libfind_package PREFIX) - set (LIBFIND_PACKAGE_ARGS ${ARGN}) - if (${PREFIX}_FIND_QUIETLY) - set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET) - endif (${PREFIX}_FIND_QUIETLY) - if (${PREFIX}_FIND_REQUIRED) - set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED) - endif (${PREFIX}_FIND_REQUIRED) - find_package(${LIBFIND_PACKAGE_ARGS}) -endmacro (libfind_package) - -# Damn CMake developers made the UsePkgConfig system deprecated in the same release (2.6) -# where they added pkg_check_modules. Consequently I need to support both in my scripts -# to avoid those deprecated warnings. Here's a helper that does just that. -# Works identically to pkg_check_modules, except that no checks are needed prior to use. -macro (libfind_pkg_check_modules PREFIX PKGNAME) - if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) - include(UsePkgConfig) - pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) - else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(${PREFIX} ${PKGNAME}) - endif (PKG_CONFIG_FOUND) - endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) -endmacro (libfind_pkg_check_modules) - -# Do the final processing once the paths have been detected. -# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain -# all the variables, each of which contain one include directory. -# Ditto for ${PREFIX}_PROCESS_LIBS and library files. -# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. -# Also handles errors in case library detection was required, etc. -macro (libfind_process PREFIX) - # Skip processing if already processed during this run - if (NOT ${PREFIX}_FOUND) - # Start with the assumption that the library was found - set (${PREFIX}_FOUND TRUE) - - # Process all includes and set _FOUND to false if any are missing - foreach (i ${${PREFIX}_PROCESS_INCLUDES}) - if (${i}) - set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) - mark_as_advanced(${i}) - else (${i}) - set (${PREFIX}_FOUND FALSE) - endif (${i}) - endforeach (i) - - # Process all libraries and set _FOUND to false if any are missing - foreach (i ${${PREFIX}_PROCESS_LIBS}) - if (${i}) - set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) - mark_as_advanced(${i}) - else (${i}) - set (${PREFIX}_FOUND FALSE) - endif (${i}) - endforeach (i) - - # Print message and/or exit on fatal error - if (${PREFIX}_FOUND) - if (NOT ${PREFIX}_FIND_QUIETLY) - message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") - endif (NOT ${PREFIX}_FIND_QUIETLY) - else (${PREFIX}_FOUND) - if (${PREFIX}_FIND_REQUIRED) - foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) - message("${i}=${${i}}") - endforeach (i) - message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") - endif (${PREFIX}_FIND_REQUIRED) - endif (${PREFIX}_FOUND) - endif (NOT ${PREFIX}_FOUND) -endmacro (libfind_process) - -macro(libfind_library PREFIX basename) - set(TMP "") - if(MSVC80) - set(TMP -vc80) - endif(MSVC80) - if(MSVC90) - set(TMP -vc90) - endif(MSVC90) - set(${PREFIX}_LIBNAMES ${basename}${TMP}) - if(${ARGC} GREATER 2) - set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2}) - string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES}) - set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP}) - endif(${ARGC} GREATER 2) - find_library(${PREFIX}_LIBRARY - NAMES ${${PREFIX}_LIBNAMES} - PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS} - ) -endmacro(libfind_library) - diff --git a/Modules/VersionTag.cmake b/Modules/VersionTag.cmake deleted file mode 100644 index 682ab3ed..00000000 --- a/Modules/VersionTag.cmake +++ /dev/null @@ -1,13 +0,0 @@ -execute_process( - COMMAND "sh" "${CMAKE_SOURCE_DIR}/Modules/describe.sh" - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - OUTPUT_VARIABLE DESCRIBE - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -if(DESCRIBE STREQUAL "") - set (VERSION_TAG "UNKNOWN") -else() - string(REGEX REPLACE "^v" "" VERSION_TAG "${DESCRIBE}") -endif() - diff --git a/Modules/cmake_uninstall.cmake.in b/Modules/cmake_uninstall.cmake.in deleted file mode 100644 index 4bfb0bfb..00000000 --- a/Modules/cmake_uninstall.cmake.in +++ /dev/null @@ -1,21 +0,0 @@ -IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") -ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - -FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) -STRING(REGEX REPLACE "\n" ";" files "${files}") -FOREACH(file ${files}) - MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") - IF(EXISTS "$ENV{DESTDIR}${file}") - EXEC_PROGRAM( - "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" - OUTPUT_VARIABLE rm_out - RETURN_VALUE rm_retval - ) - IF(NOT "${rm_retval}" STREQUAL 0) - MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") - ENDIF(NOT "${rm_retval}" STREQUAL 0) - ELSE(EXISTS "$ENV{DESTDIR}${file}") - MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") - ENDIF(EXISTS "$ENV{DESTDIR}${file}") -ENDFOREACH(file) diff --git a/Modules/describe.sh b/Modules/describe.sh deleted file mode 100755 index 6425ed52..00000000 --- a/Modules/describe.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# Check for git and a git repo. -if head=`git rev-parse --verify HEAD 2>/dev/null`; then - /bin/echo -n `git describe` - - # Are there uncommitted changes? - git update-index --refresh --unmerged > /dev/null - git diff-index --quiet HEAD || /bin/echo -n -dirty -else -# Check for version tag - if [ -e version.tag ]; then - /bin/echo -n `cat version.tag` - fi -fi - -echo diff --git a/README b/README index bad75310..2f09d212 100644 --- a/README +++ b/README @@ -17,21 +17,11 @@ notification and backup services running on the device). The higher-level layers are handled by libimobiledevice. 'ifuse' is then able to sit on top of this and mount your device's AFC filesystem share. -There is also a Python implementation of the client library in the python-client -library, and an example tcprelay.py which performs a similar function to iproxy. -This implementation supports OSX and Windows and the new iTunes plist-based -usbmuxd protocol, so it is portable and will run on those operating systems with -no modification, using Apple's native usbmuxd. This is useful if you need to -tunnel to your device from another OS in a pinch. Run python tcpclient.py --help -for usage information. - License ======= The contents of this package are licensed under the GNU General Public License, -versions 2 or 3 (see COPYING.GPLv2 and COPYING.GPLv3), except for libuxbmuxd -which is licensed under the GNU Lesser General Public License, version 2.1 or, -at your option, any later version (see COPYING.LGPLv2.1). If a more permissive +versions 2 or 3 (see COPYING.GPLv2 and COPYING.GPLv3). If a more permissive license is specified at the top of a source file, it takes precedence over this. Legal diff --git a/README.devel b/README.devel deleted file mode 100644 index 727e095f..00000000 --- a/README.devel +++ /dev/null @@ -1,50 +0,0 @@ -Background -========== - -'libusbmuxd' makes it really simple to talk to a running 'usbmuxd' and -hides all the details for you. There are two function calls: - -usbmuxd_scan() --------------- - -This returns a list of all available iPhone-like devices that are -available for talking to. The returned array contains the USB -product_id, hex formatted serial_number of any iPhones/iTouches and a -non-descript 'handle' for all those devices that are within range (as -of March 2009, that means a device directly plugged into the -computer's USB port). - -Once you have found the device you want to communicate with, take its -'handle' and pass this to usbmuxd_connect(). - -usbmuxd_connect() ------------------ - -This takes a handle, a destination port number and tries to setup -a proxy a connection. It returns a file-descriptor which you should -be able to read(), write() and select() on like any other active network -socket connection. - - -Technical details -================= - -When usbmuxd is running (normally started, or stopped as a result of -'udev' auto-insertion messages), it provides a socket interface in -'/var/run/usbmuxd' that is designed to be compatible with the socket -interface that is provided on MacOSX. - -The structures for communicating over this device are documented -in the 'usbmuxd-proto.h', but you shouldn't need to view them -directly if you are using the libusbmuxd.so library for easy access. - - -Example -======= - -#include - -... - -gcc -o leetphone leetphone.c -lusbmuxd - diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 00000000..32929736 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,15 @@ +#!/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 + +if [ -z "$NOCONFIGURE" ]; then + ./configure "$@" +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..a874692d --- /dev/null +++ b/configure.ac @@ -0,0 +1,96 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.61) +AC_INIT(usbmuxd, 1.0.8, nospam@nowhere.com) +AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) +AC_CONFIG_SRCDIR([src/]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_CXX +AM_PROG_CC_C_O +AC_PROG_LIBTOOL + +# Checks for libraries. +PKG_CHECK_MODULES(libusb, libusb-1.0 >= 1.0.3) +PKG_CHECK_MODULES(libplist, libplist >= 1.9, have_plist=yes, have_plist=no) + +AC_ARG_WITH([protov1], + [AS_HELP_STRING([--without-protov1], + [do not build with protocol v1 support (default is yes)])], + [with_protov1=no], + [with_protov1=yes]) + +if test "x$have_plist" = "xyes"; then + if test "x$with_protov1" != "xyes"; then + have_plist=no + echo "*** Note: Protocol V1 support has been disabled ***" + else + AC_DEFINE(HAVE_PLIST, 1, [Define if you have libplist support]) + AC_SUBST(libplist_CFLAGS) + AC_SUBST(libplist_LIBS) + fi +else + if test "x$with_protov1" == "xyes"; then + AC_MSG_ERROR([protocol V1 support requested but libplist could not be found]) + fi +fi + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([stdint.h stdlib.h string.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_CHECK_FUNCS([strcasecmp strdup strerror strndup]) + +# Check for operating system +AC_MSG_CHECKING([whether to enable WIN32 build settings]) +case ${host_os} in + *mingw32*|*cygwin*) + win32=true + AC_MSG_RESULT([yes]) + AC_CHECK_TOOL([WINDRES], [windres], AC_MSG_ERROR([windres not found])) + AC_SUBST(WINDRES) + ;; + *) + win32=false + AC_MSG_RESULT([no]) + ;; +esac +AM_CONDITIONAL(WIN32, test x$win32 = xtrue) + +AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter") +AC_SUBST(GLOBAL_CFLAGS) + +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +AC_OUTPUT([ +Makefile +src/Makefile +udev/85-usbmuxd.rules +]) + +echo " +Configuration for $PACKAGE $VERSION: +------------------------------------------- + + Install prefix: .........: $prefix + Protocol v1 support: ....: $have_plist + + Now type 'make' to build $PACKAGE $VERSION, + and then 'make install' for installation. +" diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt deleted file mode 100644 index c323f7bc..00000000 --- a/daemon/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -find_package(USB REQUIRED) -include_directories(${USB_INCLUDE_DIRS}) -include_directories(${OPT_INCLUDES}) -set(LIBS ${LIBS} ${USB_LIBRARIES} ${OPT_LIBS}) -if(HAVE_PLIST) - add_definitions("-DHAVE_PLIST") - message("-- usbmuxd will be built with protocol version 1 support") -endif() -include_directories (${CMAKE_SOURCE_DIR}/common) -include_directories (${CMAKE_SOURCE_DIR}/daemon) -include_directories (${CMAKE_SOURCE_DIR}/libusbmuxd) - -add_definitions(-DUSBMUXD_DAEMON -DUSBMUXD_VERSION="${USBMUXD_VERSION}") -add_executable(usbmuxd main.c usb-linux.c log.c ${CMAKE_SOURCE_DIR}/common/utils.c device.c client.c) -target_link_libraries(usbmuxd ${LIBS}) - -install(TARGETS usbmuxd RUNTIME DESTINATION sbin) - -message(" -* REMINDER -* Remember to add a user named 'usbmux' with USB access permissions -* for the udev hotplugging feature to work out of the box. -") diff --git a/libusbmuxd.pc.in b/libusbmuxd.pc.in deleted file mode 100644 index 1ecd8edd..00000000 --- a/libusbmuxd.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=${CMAKE_INSTALL_PREFIX} -exec_prefix=${CMAKE_INSTALL_PREFIX} -libdir=${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} -includedir=${CMAKE_INSTALL_PREFIX}/include - -Name: libusbmuxd -Description: A library to communicate with the usbmux daemon -Version: ${USBMUXD_VERSION} -Libs: -L${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} -lusbmuxd -Cflags: -I${CMAKE_INSTALL_PREFIX}/include - diff --git a/libusbmuxd/CMakeLists.txt b/libusbmuxd/CMakeLists.txt deleted file mode 100644 index 737eb02c..00000000 --- a/libusbmuxd/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -include_directories (${CMAKE_SOURCE_DIR}/common) -find_package(Threads) - -option(WANT_INOTIFY "Build with inotify support" ON) -if (WANT_INOTIFY) -find_package(Inotify) -if (INOTIFY_FOUND) - add_definitions("-DHAVE_INOTIFY") - message("-- libusbmuxd will be built with inotify support") -endif() -endif(WANT_INOTIFY) - -add_library (libusbmuxd SHARED libusbmuxd.c sock_stuff.c ${CMAKE_SOURCE_DIR}/common/utils.c) -find_library (PTHREAD pthread) - -if (HAVE_PLIST) - add_definitions("-DHAVE_PLIST") - message("-- libusbmuxd will be built with protocol version 1 support") -endif() -if(WIN32) - set(OPT_LIBS ${OPT_LIBS} ws2_32) -endif() -include_directories(${OPT_INCLUDES}) -target_link_libraries (libusbmuxd ${CMAKE_THREAD_LIBS_INIT} ${OPT_LIBS}) - -# 'lib' is a UNIXism, the proper CMake target is usbmuxd -# But we can't use that due to the conflict with the usbmuxd daemon, -# so instead change the library output base name to usbmuxd here -set_target_properties(libusbmuxd PROPERTIES OUTPUT_NAME usbmuxd) -set_target_properties(libusbmuxd PROPERTIES VERSION ${LIBUSBMUXD_VERSION}) -set_target_properties(libusbmuxd PROPERTIES SOVERSION ${LIBUSBMUXD_SOVERSION}) - -if(APPLE) - set_target_properties(libusbmuxd PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") -endif() -if(WIN32) - set_target_properties(libusbmuxd PROPERTIES PREFIX "lib" IMPORT_PREFIX "lib") -endif() - -install(TARGETS libusbmuxd - RUNTIME DESTINATION bin - ARCHIVE DESTINATION lib${LIB_SUFFIX} - LIBRARY DESTINATION lib${LIB_SUFFIX} -) -install(FILES usbmuxd.h usbmuxd-proto.h DESTINATION include) diff --git a/libusbmuxd/sock_stuff.c b/libusbmuxd/sock_stuff.c deleted file mode 100644 index 609c8add..00000000 --- a/libusbmuxd/sock_stuff.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - libusbmuxd - client library to talk to usbmuxd - -Copyright (C) 2009 Nikias Bassen -Copyright (C) 2009 Paul Sladen -Copyright (C) 2009 Martin Szulecki - -This library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 2.1 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef WIN32 -#include -#include -static int wsa_init = 0; -#else -#include -#include -#include -#include -#include -#endif -#include "sock_stuff.h" - -#define RECV_TIMEOUT 20000 - -static int verbose = 0; - -void sock_stuff_set_verbose(int level) -{ - verbose = level; -} - -#ifndef WIN32 -int create_unix_socket(const char *filename) -{ - struct sockaddr_un name; - int sock; - size_t size; - - // remove if still present - unlink(filename); - - /* Create the socket. */ - sock = socket(PF_LOCAL, SOCK_STREAM, 0); - if (sock < 0) { - perror("socket"); - return -1; - } - - /* Bind a name to the socket. */ - name.sun_family = AF_LOCAL; - strncpy(name.sun_path, filename, sizeof(name.sun_path)); - name.sun_path[sizeof(name.sun_path) - 1] = '\0'; - - /* The size of the address is - the offset of the start of the filename, - plus its length, - plus one for the terminating null byte. - Alternatively you can just do: - size = SUN_LEN (&name); - */ - size = (offsetof(struct sockaddr_un, sun_path) - + strlen(name.sun_path) + 1); - - if (bind(sock, (struct sockaddr *) &name, size) < 0) { - perror("bind"); - close_socket(sock); - return -1; - } - - if (listen(sock, 10) < 0) { - perror("listen"); - close_socket(sock); - return -1; - } - - return sock; -} - -int connect_unix_socket(const char *filename) -{ - struct sockaddr_un name; - int sfd = -1; - size_t size; - struct stat fst; - - // check if socket file exists... - if (stat(filename, &fst) != 0) { - if (verbose >= 2) - fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename, - strerror(errno)); - return -1; - } - // ... and if it is a unix domain socket - if (!S_ISSOCK(fst.st_mode)) { - if (verbose >= 2) - fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__, - filename); - return -1; - } - // make a new socket - if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - if (verbose >= 2) - fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno)); - return -1; - } - // and connect to 'filename' - name.sun_family = AF_LOCAL; - strncpy(name.sun_path, filename, sizeof(name.sun_path)); - name.sun_path[sizeof(name.sun_path) - 1] = 0; - - size = (offsetof(struct sockaddr_un, sun_path) - + strlen(name.sun_path) + 1); - - if (connect(sfd, (struct sockaddr *) &name, size) < 0) { - close_socket(sfd); - if (verbose >= 2) - fprintf(stderr, "%s: connect: %s\n", __func__, - strerror(errno)); - return -1; - } - - return sfd; -} -#endif - -int create_socket(uint16_t port) -{ - int sfd = -1; - int yes = 1; -#ifdef WIN32 - WSADATA wsa_data; - if (!wsa_init) { - if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { - fprintf(stderr, "WSAStartup failed!\n"); - ExitProcess(-1); - } - wsa_init = 1; - } -#endif - struct sockaddr_in saddr; - - if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) { - perror("socket()"); - return -1; - } - - if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { - perror("setsockopt()"); - close_socket(sfd); - return -1; - } - - memset((void *) &saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = htonl(INADDR_ANY); - saddr.sin_port = htons(port); - - if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) { - perror("bind()"); - close_socket(sfd); - return -1; - } - - if (listen(sfd, 1) == -1) { - perror("listen()"); - close_socket(sfd); - return -1; - } - - return sfd; -} - -#if defined(WIN32) || defined(__CYGWIN__) -int connect_socket(const char *addr, uint16_t port) -{ - int sfd = -1; - int yes = 1; - struct hostent *hp; - struct sockaddr_in saddr; -#ifdef WIN32 - WSADATA wsa_data; - if (!wsa_init) { - if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { - fprintf(stderr, "WSAStartup failed!\n"); - ExitProcess(-1); - } - wsa_init = 1; - } -#endif - - if (!addr) { - errno = EINVAL; - return -1; - } - - if ((hp = gethostbyname(addr)) == NULL) { - if (verbose >= 2) - fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr); - return -1; - } - - if (!hp->h_addr) { - if (verbose >= 2) - fprintf(stderr, "%s: gethostbyname returned NULL address!\n", - __func__); - return -1; - } - - if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) { - perror("socket()"); - return -1; - } - - if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { - perror("setsockopt()"); - close_socket(sfd); - return -1; - } - - memset((void *) &saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr; - saddr.sin_port = htons(port); - - if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { - perror("connect"); - close_socket(sfd); - return -2; - } - - return sfd; -} -#endif /* WIN32 || __CYGWIN__ */ - -int check_fd(int fd, fd_mode fdm, unsigned int timeout) -{ - fd_set fds; - int sret; - int eagain; - struct timeval to; - struct timeval *pto; - - if (fd <= 0) { - if (verbose >= 2) - fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd); - return -1; - } - - FD_ZERO(&fds); - FD_SET(fd, &fds); - - if (timeout > 0) { - to.tv_sec = (time_t) (timeout / 1000); - to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000); - pto = &to; - } else { - pto = NULL; - } - - sret = -1; - - do { - eagain = 0; - switch (fdm) { - case FDM_READ: - sret = select(fd + 1, &fds, NULL, NULL, pto); - break; - case FDM_WRITE: - sret = select(fd + 1, NULL, &fds, NULL, pto); - break; - case FDM_EXCEPT: - sret = select(fd + 1, NULL, NULL, &fds, pto); - break; - default: - return -1; - } - - if (sret < 0) { - switch (errno) { - case EINTR: - // interrupt signal in select - if (verbose >= 2) - fprintf(stderr, "%s: EINTR\n", __func__); - eagain = 1; - break; - case EAGAIN: - if (verbose >= 2) - fprintf(stderr, "%s: EAGAIN\n", __func__); - break; - default: - if (verbose >= 2) - fprintf(stderr, "%s: select failed: %s\n", __func__, - strerror(errno)); - return -1; - } - } - } while (eagain); - - return sret; -} - -int shutdown_socket(int fd, int how) -{ - return shutdown(fd, how); -} - -int close_socket(int fd) { -#ifdef WIN32 - return closesocket(fd); -#else - return close(fd); -#endif -} - -int recv_buf(int fd, void *data, size_t length) -{ - return recv_buf_timeout(fd, data, length, 0, RECV_TIMEOUT); -} - -int peek_buf(int fd, void *data, size_t length) -{ - return recv_buf_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT); -} - -int recv_buf_timeout(int fd, void *data, size_t length, int flags, - unsigned int timeout) -{ - int res; - int result; - - // check if data is available - res = check_fd(fd, FDM_READ, timeout); - if (res <= 0) { - return res; - } - // if we get here, there _is_ data available - result = recv(fd, data, length, flags); - if (res > 0 && result == 0) { - // but this is an error condition - if (verbose >= 3) - fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd); - return -EAGAIN; - } - if (result < 0) { - return -errno; - } - return result; -} - -int send_buf(int fd, void *data, size_t length) -{ - return send(fd, data, length, 0); -} diff --git a/libusbmuxd/sock_stuff.h b/libusbmuxd/sock_stuff.h deleted file mode 100644 index 5efcd277..00000000 --- a/libusbmuxd/sock_stuff.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - libusbmuxd - client library to talk to usbmuxd - -Copyright (C) 2009 Nikias Bassen -Copyright (C) 2009 Paul Sladen -Copyright (C) 2009 Martin Szulecki - -This library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 2.1 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#ifndef __SOCK_STUFF_H -#define __SOCK_STUFF_H - -#include - -enum fd_mode { - FDM_READ, - FDM_WRITE, - FDM_EXCEPT -}; -typedef enum fd_mode fd_mode; - -#ifdef WIN32 -#include -#define SHUT_RD SD_READ -#define SHUT_WR SD_WRITE -#define SHUT_RDWR SD_BOTH -#endif - -#ifndef WIN32 -int create_unix_socket(const char *filename); -int connect_unix_socket(const char *filename); -#endif -int create_socket(uint16_t port); -#if defined(WIN32) || defined(__CYGWIN__) -int connect_socket(const char *addr, uint16_t port); -#endif -int check_fd(int fd, fd_mode fdm, unsigned int timeout); - -int shutdown_socket(int fd, int how); -int close_socket(int fd); - -int recv_buf(int fd, void *data, size_t size); -int peek_buf(int fd, void *data, size_t size); -int recv_buf_timeout(int fd, void *data, size_t size, int flags, - unsigned int timeout); - -int send_buf(int fd, void *data, size_t size); - -void sock_stuff_set_verbose(int level); - -#endif /* __SOCK_STUFF_H */ diff --git a/libusbmuxd/usbmuxd.h b/libusbmuxd/usbmuxd.h deleted file mode 100644 index 0f7b862d..00000000 --- a/libusbmuxd/usbmuxd.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - libusbmuxd - client library to talk to usbmuxd - -Copyright (C) 2009 Nikias Bassen -Copyright (C) 2009 Paul Sladen -Copyright (C) 2009 Martin Szulecki - -This library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 2.1 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#ifndef __USBMUXD_H -#define __USBMUXD_H -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Device information structure holding data to identify the device. - * The relevant 'handle' should be passed to 'usbmuxd_connect()', to - * start a proxy connection. The value 'handle' should be considered - * opaque and no presumption made about the meaning of its value. - */ -typedef struct { - int handle; - int product_id; - char udid[41]; -} usbmuxd_device_info_t; - -/** - * event types for event callback function - */ -enum usbmuxd_event_type { - UE_DEVICE_ADD = 1, - UE_DEVICE_REMOVE -}; - -/** - * Event structure that will be passed to the callback function. - * 'event' will contains the type of the event, and 'device' will contains - * information about the device. - */ -typedef struct { - int event; - usbmuxd_device_info_t device; -} usbmuxd_event_t; - -/** - * Callback function prototype. - */ -typedef void (*usbmuxd_event_cb_t) (const usbmuxd_event_t *event, void *user_data); - -/** - * Subscribe a callback function so that applications get to know about - * device add/remove events. - * - * @param callback A callback function that is executed when an event occurs. - * - * @return 0 on success or negative on error. - */ -int usbmuxd_subscribe(usbmuxd_event_cb_t callback, void *user_data); - -/** - * Unsubscribe callback. - * - * @return only 0 for now. - */ -int usbmuxd_unsubscribe(); - -/** - * Contacts usbmuxd and retrieves a list of connected devices. - * - * @param device_list A pointer to an array of usbmuxd_device_info_t - * that will hold records of the connected devices. The last record - * is a null-terminated record with all fields set to 0/NULL. - * @note The user has to free the list returned. - * - * @return number of attached devices, zero on no devices, or negative - * if an error occured. - */ -int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list); - -/** - * Frees the device list returned by an usbmuxd_get_device_list call - * - * @param device_list A pointer to an array of usbmuxd_device_info_t to free. - * - * @return 0 on success, -1 on error. - */ -int usbmuxd_device_list_free(usbmuxd_device_info_t **device_list); - -/** - * Gets device information for the device specified by udid. - * - * @param udid A device UDID of the device to look for. If udid is NULL, - * This function will return the first device found. - * @param device Pointer to a previously allocated (or static) - * usbmuxd_device_info_t that will be filled with the device info. - * - * @return 0 if no matching device is connected, 1 if the device was found, - * or a negative value on error. - */ -int usbmuxd_get_device_by_udid(const char *udid, usbmuxd_device_info_t *device); - -/** - * Request proxy connect to - * - * @param handle returned by 'usbmuxd_scan()' - * - * @param tcp_port TCP port number on device, in range 0-65535. - * common values are 62078 for lockdown, and 22 for SSH. - * - * @return file descriptor socket of the connection, or -1 on error - */ -int usbmuxd_connect(const int handle, const unsigned short tcp_port); - -/** - * Disconnect. For now, this just closes the socket file descriptor. - * - * @param sfd socker file descriptor returned by usbmuxd_connect() - * - * @return 0 on success, -1 on error. - */ -int usbmuxd_disconnect(int sfd); - -/** - * Send data to the specified socket. - * - * @param sfd socket file descriptor returned by usbmuxd_connect() - * @param data buffer to send - * @param len size of buffer to send - * @param sent_bytes how many bytes sent - * - * @return 0 on success, a negative errno value otherwise. - */ -int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes); - -/** - * Receive data from the specified socket. - * - * @param sfd socket file descriptor returned by usbmuxd_connect() - * @param data buffer to put the data to - * @param len number of bytes to receive - * @param recv_bytes number of bytes received - * @param timeout how many milliseconds to wait for data - * - * @return 0 on success, a negative errno value otherwise. - */ -int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout); - -/** - * Receive data from the specified socket with a default timeout. - * - * @param sfd socket file descriptor returned by usbmuxd_connect() - * @param data buffer to put the data to - * @param len number of bytes to receive - * @param recv_bytes number of bytes received - * - * @return 0 on success, a negative errno value otherwise. - */ -int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes); - -/** - * Enable or disable the use of inotify extension. Enabled by default. - * Use 0 to disable and 1 to enable inotify support. - * This only has an effect on linux systems if inotify support has been built - * in. Otherwise and on all other platforms this function has no effect. - */ -void libusbmuxd_set_use_inotify(int set); - -void libusbmuxd_set_debug_level(int level); - -#ifdef __cplusplus -} -#endif - -#endif /* __USBMUXD_H */ diff --git a/m4/as-compiler-flag.m4 b/m4/as-compiler-flag.m4 new file mode 100644 index 00000000..0f660cf0 --- /dev/null +++ b/m4/as-compiler-flag.m4 @@ -0,0 +1,62 @@ +dnl as-compiler-flag.m4 0.1.0 + +dnl autostars m4 macro for detection of compiler flags + +dnl David Schleef + +dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $ + +dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_COMPILER_FLAG], +[ + AC_MSG_CHECKING([to see if compiler understands $1]) + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + m4_ifvaln([$2],[$2]) + true + else + m4_ifvaln([$3],[$3]) + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + +dnl AS_COMPILER_FLAGS(VAR, FLAGS) +dnl Tries to compile with the given CFLAGS. + +AC_DEFUN([AS_COMPILER_FLAGS], +[ + list=$2 + flags_supported="" + flags_unsupported="" + AC_MSG_CHECKING([for supported compiler flags]) + for each in $list + do + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $each" + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + flags_supported="$flags_supported $each" + else + flags_unsupported="$flags_unsupported $each" + fi + done + AC_MSG_RESULT([$flags_supported]) + if test "X$flags_unsupported" != X ; then + AC_MSG_WARN([unsupported compiler flags: $flags_unsupported]) + fi + $1="$$1 $flags_supported" +]) + diff --git a/python-client/.gitignore b/python-client/.gitignore deleted file mode 100644 index 5da7ef51..00000000 --- a/python-client/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.pyc -*.pyo - diff --git a/python-client/tcprelay.py b/python-client/tcprelay.py deleted file mode 100644 index add200c9..00000000 --- a/python-client/tcprelay.py +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# tcprelay.py - TCP connection relay for usbmuxd -# -# Copyright (C) 2009 Hector Martin "marcan" -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 or version 3. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import usbmux -import SocketServer -import select -from optparse import OptionParser -import sys -import threading - -class SocketRelay(object): - def __init__(self, a, b, maxbuf=65535): - self.a = a - self.b = b - self.atob = "" - self.btoa = "" - self.maxbuf = maxbuf - def handle(self): - while True: - rlist = [] - wlist = [] - xlist = [self.a, self.b] - if self.atob: - wlist.append(self.b) - if self.btoa: - wlist.append(self.a) - if len(self.atob) < self.maxbuf: - rlist.append(self.a) - if len(self.btoa) < self.maxbuf: - rlist.append(self.b) - rlo, wlo, xlo = select.select(rlist, wlist, xlist) - if xlo: - return - if self.a in wlo: - n = self.a.send(self.btoa) - self.btoa = self.btoa[n:] - if self.b in wlo: - n = self.b.send(self.atob) - self.atob = self.atob[n:] - if self.a in rlo: - s = self.a.recv(self.maxbuf - len(self.atob)) - if not s: - return - self.atob += s - if self.b in rlo: - s = self.b.recv(self.maxbuf - len(self.btoa)) - if not s: - return - self.btoa += s - #print "Relay iter: %8d atob, %8d btoa, lists: %r %r %r"%(len(self.atob), len(self.btoa), rlo, wlo, xlo) - -class TCPRelay(SocketServer.BaseRequestHandler): - def handle(self): - print "Incoming connection to %d"%self.server.server_address[1] - mux = usbmux.USBMux(options.sockpath) - print "Waiting for devices..." - if not mux.devices: - mux.process(1.0) - if not mux.devices: - print "No device found" - self.request.close() - return - dev = mux.devices[0] - print "Connecting to device %s"%str(dev) - dsock = mux.connect(dev, self.server.rport) - lsock = self.request - print "Connection established, relaying data" - try: - fwd = SocketRelay(dsock, lsock, self.server.bufsize * 1024) - fwd.handle() - finally: - dsock.close() - lsock.close() - print "Connection closed" - -class TCPServer(SocketServer.TCPServer): - allow_reuse_address = True - -class ThreadedTCPServer(SocketServer.ThreadingMixIn, TCPServer): - pass - -HOST = "localhost" - -parser = OptionParser(usage="usage: %prog [OPTIONS] RemotePort[:LocalPort] [RemotePort[:LocalPort]]...") -parser.add_option("-t", "--threaded", dest='threaded', action='store_true', default=False, help="use threading to handle multiple connections at once") -parser.add_option("-b", "--bufsize", dest='bufsize', action='store', metavar='KILOBYTES', type='int', default=128, help="specify buffer size for socket forwarding") -parser.add_option("-s", "--socket", dest='sockpath', action='store', metavar='PATH', type='str', default=None, help="specify the path of the usbmuxd socket") - -options, args = parser.parse_args() - -serverclass = TCPServer -if options.threaded: - serverclass = ThreadedTCPServer - -if len(args) == 0: - parser.print_help() - sys.exit(1) - -ports = [] - -for arg in args: - try: - if ':' in arg: - rport, lport = arg.split(":") - rport = int(rport) - lport = int(lport) - ports.append((rport, lport)) - else: - ports.append((int(arg), int(arg))) - except: - parser.print_help() - sys.exit(1) - -servers=[] - -for rport, lport in ports: - print "Forwarding local port %d to remote port %d"%(lport, rport) - server = serverclass((HOST, lport), TCPRelay) - server.rport = rport - server.bufsize = options.bufsize - servers.append(server) - -alive = True - -while alive: - try: - rl, wl, xl = select.select(servers, [], []) - for server in rl: - server.handle_request() - except: - alive = False diff --git a/python-client/usbmux.py b/python-client/usbmux.py deleted file mode 100644 index 79ec26ae..00000000 --- a/python-client/usbmux.py +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# usbmux.py - usbmux client library for Python -# -# Copyright (C) 2009 Hector Martin "marcan" -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 or version 3. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import socket, struct, select, sys - -try: - import plistlib - haveplist = True -except: - haveplist = False - -class MuxError(Exception): - pass - -class MuxVersionError(MuxError): - pass - -class SafeStreamSocket: - def __init__(self, address, family): - self.sock = socket.socket(family, socket.SOCK_STREAM) - self.sock.connect(address) - def send(self, msg): - totalsent = 0 - while totalsent < len(msg): - sent = self.sock.send(msg[totalsent:]) - if sent == 0: - raise MuxError("socket connection broken") - totalsent = totalsent + sent - def recv(self, size): - msg = '' - while len(msg) < size: - chunk = self.sock.recv(size-len(msg)) - if chunk == '': - raise MuxError("socket connection broken") - msg = msg + chunk - return msg - -class MuxDevice(object): - def __init__(self, devid, usbprod, serial, location): - self.devid = devid - self.usbprod = usbprod - self.serial = serial - self.location = location - def __str__(self): - return ""%(self.devid, self.usbprod, self.serial, self.location) - -class BinaryProtocol(object): - TYPE_RESULT = 1 - TYPE_CONNECT = 2 - TYPE_LISTEN = 3 - TYPE_DEVICE_ADD = 4 - TYPE_DEVICE_REMOVE = 5 - VERSION = 0 - def __init__(self, socket): - self.socket = socket - self.connected = False - - def _pack(self, req, payload): - if req == self.TYPE_CONNECT: - return struct.pack("IH", payload['DeviceID'], payload['PortNumber']) + "\x00\x00" - elif req == self.TYPE_LISTEN: - return "" - else: - raise ValueError("Invalid outgoing request type %d"%req) - - def _unpack(self, resp, payload): - if resp == self.TYPE_RESULT: - return {'Number':struct.unpack("I", payload)[0]} - elif resp == self.TYPE_DEVICE_ADD: - devid, usbpid, serial, pad, location = struct.unpack("IH256sHI", payload) - serial = serial.split("\0")[0] - return {'DeviceID': devid, 'Properties': {'LocationID': location, 'SerialNumber': serial, 'ProductID': usbpid}} - elif resp == self.TYPE_DEVICE_REMOVE: - devid = struct.unpack("I", payload)[0] - return {'DeviceID': devid} - else: - raise MuxError("Invalid incoming request type %d"%req) - - def sendpacket(self, req, tag, payload={}): - payload = self._pack(req, payload) - if self.connected: - raise MuxError("Mux is connected, cannot issue control packets") - length = 16 + len(payload) - data = struct.pack("IIII", length, self.VERSION, req, tag) + payload - self.socket.send(data) - def getpacket(self): - if self.connected: - raise MuxError("Mux is connected, cannot issue control packets") - dlen = self.socket.recv(4) - dlen = struct.unpack("I", dlen)[0] - body = self.socket.recv(dlen - 4) - version, resp, tag = struct.unpack("III",body[:0xc]) - if version != self.VERSION: - raise MuxVersionError("Version mismatch: expected %d, got %d"%(self.VERSION,version)) - payload = self._unpack(resp, body[0xc:]) - return (resp, tag, payload) - -class PlistProtocol(BinaryProtocol): - TYPE_RESULT = "Result" - TYPE_CONNECT = "Connect" - TYPE_LISTEN = "Listen" - TYPE_DEVICE_ADD = "Attached" - TYPE_DEVICE_REMOVE = "Detached" #??? - TYPE_PLIST = 8 - VERSION = 1 - def __init__(self, socket): - if not haveplist: - raise Exception("You need the plistlib module") - BinaryProtocol.__init__(self, socket) - - def _pack(self, req, payload): - return payload - - def _unpack(self, resp, payload): - return payload - - def sendpacket(self, req, tag, payload={}): - payload['ClientVersionString'] = 'usbmux.py by marcan' - if isinstance(req, int): - req = [self.TYPE_CONNECT, self.TYPE_LISTEN][req-2] - payload['MessageType'] = req - payload['ProgName'] = 'tcprelay' - BinaryProtocol.sendpacket(self, self.TYPE_PLIST, tag, plistlib.writePlistToString(payload)) - def getpacket(self): - resp, tag, payload = BinaryProtocol.getpacket(self) - if resp != self.TYPE_PLIST: - raise MuxError("Received non-plist type %d"%resp) - payload = plistlib.readPlistFromString(payload) - return payload['MessageType'], tag, payload - -class MuxConnection(object): - def __init__(self, socketpath, protoclass): - self.socketpath = socketpath - if sys.platform in ['win32', 'cygwin']: - family = socket.AF_INET - address = ('127.0.0.1', 27015) - else: - family = socket.AF_UNIX - address = self.socketpath - self.socket = SafeStreamSocket(address, family) - self.proto = protoclass(self.socket) - self.pkttag = 1 - self.devices = [] - - def _getreply(self): - while True: - resp, tag, data = self.proto.getpacket() - if resp == self.proto.TYPE_RESULT: - return tag, data - else: - raise MuxError("Invalid packet type received: %d"%resp) - def _processpacket(self): - resp, tag, data = self.proto.getpacket() - if resp == self.proto.TYPE_DEVICE_ADD: - self.devices.append(MuxDevice(data['DeviceID'], data['Properties']['ProductID'], data['Properties']['SerialNumber'], data['Properties']['LocationID'])) - elif resp == self.proto.TYPE_DEVICE_REMOVE: - for dev in self.devices: - if dev.devid == data['DeviceID']: - self.devices.remove(dev) - elif resp == self.proto.TYPE_RESULT: - raise MuxError("Unexpected result: %d"%resp) - else: - raise MuxError("Invalid packet type received: %d"%resp) - def _exchange(self, req, payload={}): - mytag = self.pkttag - self.pkttag += 1 - self.proto.sendpacket(req, mytag, payload) - recvtag, data = self._getreply() - if recvtag != mytag: - raise MuxError("Reply tag mismatch: expected %d, got %d"%(mytag, recvtag)) - return data['Number'] - - def listen(self): - ret = self._exchange(self.proto.TYPE_LISTEN) - if ret != 0: - raise MuxError("Listen failed: error %d"%ret) - def process(self, timeout=None): - if self.proto.connected: - raise MuxError("Socket is connected, cannot process listener events") - rlo, wlo, xlo = select.select([self.socket.sock], [], [self.socket.sock], timeout) - if xlo: - self.socket.sock.close() - raise MuxError("Exception in listener socket") - if rlo: - self._processpacket() - def connect(self, device, port): - ret = self._exchange(self.proto.TYPE_CONNECT, {'DeviceID':device.devid, 'PortNumber':((port<<8) & 0xFF00) | (port>>8)}) - if ret != 0: - raise MuxError("Connect failed: error %d"%ret) - self.proto.connected = True - return self.socket.sock - def close(self): - self.socket.sock.close() - -class USBMux(object): - def __init__(self, socketpath=None): - if socketpath is None: - if sys.platform == 'darwin': - socketpath = "/var/run/usbmuxd" - else: - socketpath = "/var/run/usbmuxd" - self.socketpath = socketpath - self.listener = MuxConnection(socketpath, BinaryProtocol) - try: - self.listener.listen() - self.version = 0 - self.protoclass = BinaryProtocol - except MuxVersionError: - self.listener = MuxConnection(socketpath, PlistProtocol) - self.listener.listen() - self.protoclass = PlistProtocol - self.version = 1 - self.devices = self.listener.devices - def process(self, timeout=None): - self.listener.process(timeout) - def connect(self, device, port): - connector = MuxConnection(self.socketpath, self.protoclass) - return connector.connect(device, port) - -if __name__ == "__main__": - mux = USBMux() - print "Waiting for devices..." - if not mux.devices: - mux.process(0.1) - while True: - print "Devices:" - for dev in mux.devices: - print dev - mux.process() diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..d2fcfefb --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,14 @@ +AM_CFLAGS = $(GLOBAL_CFLAGS) -I$(top_srcdir)/src $(libplist_CFLAGS) $(libusb_CFLAGS) +AM_LDFLAGS = $(libplist_LIBS) $(libusb_LIBS) + +bin_PROGRAMS = usbmuxd + +usbmuxd_SOURCES = client.c client.h \ + device.c device.h \ + log.c log.h \ + usb-linux.c usb.h \ + utils.c utils.h \ + main.c +usbmuxd_CFLAGS = $(AM_CFLAGS) +usbmuxd_LDFLAGS = $(AM_LDFLAGS) + diff --git a/daemon/client.c b/src/client.c similarity index 100% rename from daemon/client.c rename to src/client.c diff --git a/daemon/client.h b/src/client.h similarity index 100% rename from daemon/client.h rename to src/client.h diff --git a/daemon/device.c b/src/device.c similarity index 100% rename from daemon/device.c rename to src/device.c diff --git a/daemon/device.h b/src/device.h similarity index 100% rename from daemon/device.h rename to src/device.h diff --git a/daemon/log.c b/src/log.c similarity index 100% rename from daemon/log.c rename to src/log.c diff --git a/daemon/log.h b/src/log.h similarity index 100% rename from daemon/log.h rename to src/log.h diff --git a/daemon/main.c b/src/main.c similarity index 99% rename from daemon/main.c rename to src/main.c index 0eaae8bf..0997ee82 100644 --- a/daemon/main.c +++ b/src/main.c @@ -440,7 +440,7 @@ int main(int argc, char *argv[]) /* set log level to specified verbosity */ log_level = verbose; - usbmuxd_log(LL_NOTICE, "usbmuxd v%s starting up", USBMUXD_VERSION); + usbmuxd_log(LL_NOTICE, "usbmuxd v%s starting up", PACKAGE_VERSION); should_exit = 0; should_discover = 0; diff --git a/daemon/usb-linux.c b/src/usb-linux.c similarity index 100% rename from daemon/usb-linux.c rename to src/usb-linux.c diff --git a/daemon/usb.h b/src/usb.h similarity index 100% rename from daemon/usb.h rename to src/usb.h diff --git a/common/utils.c b/src/utils.c similarity index 93% rename from common/utils.c rename to src/utils.c index 0096907a..ceef5357 100644 --- a/common/utils.c +++ b/src/utils.c @@ -29,14 +29,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include "utils.h" -#ifdef USBMUXD_DAEMON -# include "log.h" -# define util_error(...) usbmuxd_log(LL_ERROR, __VA_ARGS__) -#else -# define util_error(...) fprintf(stderr, __VA_ARGS__) -#endif +#include "log.h" +#define util_error(...) usbmuxd_log(LL_ERROR, __VA_ARGS__) -#ifdef USBMUXD_DAEMON void fdlist_create(struct fdlist *list) { list->count = 0; @@ -72,7 +67,6 @@ void fdlist_reset(struct fdlist *list) { list->count = 0; } -#endif void collection_init(struct collection *col) { diff --git a/common/utils.h b/src/utils.h similarity index 98% rename from common/utils.h rename to src/utils.h index 0addb469..5aa2915b 100644 --- a/common/utils.h +++ b/src/utils.h @@ -23,7 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __UTILS_H__ #define __UTILS_H__ -#ifdef USBMUXD_DAEMON #include enum fdowner { @@ -43,7 +42,6 @@ void fdlist_create(struct fdlist *list); 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); -#endif struct collection { void **list; diff --git a/stuff/README b/stuff/README deleted file mode 100644 index 290285d9..00000000 --- a/stuff/README +++ /dev/null @@ -1,25 +0,0 @@ -*** NOTE: -*** Doing this is mostly obsolete. The preferred method to sync music to an -*** iPhone now is to use ifuse or some other afc-based client, which does not -*** require jailbreaking or adding this service. Please take a look at the -*** libiphone, ifuse, and libgpod projects. - -com.openssh.sft.plist is a launchd configuration to set up a bare SFTP server -on TCP port 2299 localhost-only for USB use. It's nice for relatively fast music -syncing and file transfer under Linux (and it avoids encryption). Con: it gives -anyone with usb access root FS access on the phone, as well as anything running -on the phone itself. - -Use it with a command like this: - -IPATH=/var/mobile/Media -MOUNTPOINT=$HOME/media/iphone -$ sshfs localhost:$IPATH $MOUNTPOINT -o workaround=rename -o directport=2299 \ - -o kernel_cache -o entry_timeout=30 -o attr_timeout=30 - -Make sure you run tcprelay.py: -$ python tcprelay.py -t 2299 - -Remember that to bypass the stupid new iTunesDB hash you need to edit -/System/Library/Lockdown/Checkpoint.xml and change DBVersion to 2. - diff --git a/stuff/com.openssh.sftp.plist b/stuff/com.openssh.sftp.plist deleted file mode 100644 index 569fabc0..00000000 --- a/stuff/com.openssh.sftp.plist +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - Label - com.openssh.sftpd - - Program - /usr/libexec/sftp-server - - ProgramArguments - - /usr/libexec/sftp-server - - - SessionCreate - - - Sockets - - Listeners - - SockServiceName - 2299 - SockNodeName - 127.0.0.1 - - - - StandardErrorPath - /dev/null - - inetdCompatibility - - Wait - - - - - diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt deleted file mode 100644 index 64d0d0e2..00000000 --- a/tools/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -include_directories (${CMAKE_SOURCE_DIR}/libusbmuxd) -link_directories (${CMAKE_BINARY_DIR}/libusbmuxd) - -add_executable(iproxy iproxy.c) -if(WIN32) - target_link_libraries(iproxy libusbmuxd pthread ws2_32) -else() - target_link_libraries(iproxy libusbmuxd pthread) -endif() - -install(TARGETS iproxy RUNTIME DESTINATION bin) diff --git a/tools/iproxy.c b/tools/iproxy.c deleted file mode 100644 index e4e39f6d..00000000 --- a/tools/iproxy.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - iproxy -- proxy that enables tcp service access to iPhone/iPod - -Copyright (C) 2009 Nikias Bassen -Copyright (C) 2009 Paul Sladen - -Based upon iTunnel source code, Copyright (c) 2008 Jing Su. -http://www.cs.toronto.edu/~jingsu/itunnel/ - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -TODO: improve code... - -*/ - -#include -#include -#include -#include -#include -#include -#include -#ifdef WIN32 -#include -#include -typedef unsigned int socklen_t; -#else -#include -#include -#include -#include -#include -#endif -#include "sock_stuff.h" -#include "usbmuxd.h" - -static uint16_t listen_port = 0; -static uint16_t device_port = 0; - -struct client_data { - int fd; - int sfd; - volatile int stop_ctos; - volatile int stop_stoc; -}; - -void *run_stoc_loop(void *arg) -{ - struct client_data *cdata = (struct client_data*)arg; - int recv_len; - int sent; - char buffer[131072]; - - printf("%s: fd = %d\n", __func__, cdata->fd); - - while (!cdata->stop_stoc && cdata->fd>0 && cdata->sfd>0) { - recv_len = recv_buf_timeout(cdata->sfd, buffer, sizeof(buffer), 0, 5000); - if (recv_len <= 0) { - if (recv_len == 0) { - // try again - continue; - } else { - fprintf(stderr, "recv failed: %s\n", strerror(errno)); - break; - } - } else { -// printf("received %d bytes from server\n", recv_len); - // send to socket - sent = send_buf(cdata->fd, buffer, recv_len); - if (sent < recv_len) { - if (sent <= 0) { - fprintf(stderr, "send failed: %s\n", strerror(errno)); - break; - } else { - fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); - } - } else { - // sending succeeded, receive from device -// printf("pushed %d bytes to client\n", sent); - } - } - } - close(cdata->fd); - cdata->fd = -1; - cdata->stop_ctos = 1; - - return NULL; -} - -void *run_ctos_loop(void *arg) -{ - struct client_data *cdata = (struct client_data*)arg; - int recv_len; - int sent; - char buffer[131072]; -#ifdef WIN32 - HANDLE stoc = NULL; -#else - pthread_t stoc; -#endif - - printf("%s: fd = %d\n", __func__, cdata->fd); - - cdata->stop_stoc = 0; -#ifdef WIN32 - stoc = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)run_stoc_loop, cdata, 0, NULL); -#else - pthread_create(&stoc, NULL, run_stoc_loop, cdata); -#endif - - while (!cdata->stop_ctos && cdata->fd>0 && cdata->sfd>0) { - recv_len = recv_buf_timeout(cdata->fd, buffer, sizeof(buffer), 0, 5000); - if (recv_len <= 0) { - if (recv_len == 0) { - // try again - continue; - } else { - fprintf(stderr, "recv failed: %s\n", strerror(errno)); - break; - } - } else { -// printf("pulled %d bytes from client\n", recv_len); - // send to local socket - sent = send_buf(cdata->sfd, buffer, recv_len); - if (sent < recv_len) { - if (sent <= 0) { - fprintf(stderr, "send failed: %s\n", strerror(errno)); - break; - } else { - fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); - } - } else { - // sending succeeded, receive from device -// printf("sent %d bytes to server\n", sent); - } - } - } - close(cdata->fd); - cdata->fd = -1; - cdata->stop_stoc = 1; - -#ifdef WIN32 - WaitForSingleObject(stoc, INFINITE); -#else - pthread_join(stoc, NULL); -#endif - - return NULL; -} - -void *acceptor_thread(void *arg) -{ - struct client_data *cdata; - usbmuxd_device_info_t *dev_list = NULL; -#ifdef WIN32 - HANDLE ctos = NULL; -#else - pthread_t ctos; -#endif - int count; - - if (!arg) { - fprintf(stderr, "invalid client_data provided!\n"); - return NULL; - } - - cdata = (struct client_data*)arg; - - if ((count = usbmuxd_get_device_list(&dev_list)) < 0) { - printf("Connecting to usbmuxd failed, terminating.\n"); - free(dev_list); - return NULL; - } - - fprintf(stdout, "Number of available devices == %d\n", count); - - if (dev_list == NULL || dev_list[0].handle == 0) { - printf("No connected device found, terminating.\n"); - free(dev_list); - return NULL; - } - - fprintf(stdout, "Requesting connecion to device handle == %d (serial: %s), port %d\n", dev_list[0].handle, dev_list[0].udid, device_port); - - cdata->sfd = usbmuxd_connect(dev_list[0].handle, device_port); - free(dev_list); - if (cdata->sfd < 0) { - fprintf(stderr, "Error connecting to device!\n"); - } else { - cdata->stop_ctos = 0; -#ifdef WIN32 - ctos = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)run_ctos_loop, cdata, 0, NULL); - WaitForSingleObject(ctos, INFINITE); -#else - pthread_create(&ctos, NULL, run_ctos_loop, cdata); - pthread_join(ctos, NULL); -#endif - } - - if (cdata->fd > 0) { - close(cdata->fd); - } - if (cdata->sfd > 0) { - close(cdata->sfd); - } - - return NULL; -} - -int main(int argc, char **argv) -{ - int mysock = -1; - - if (argc != 3) { - printf("usage: %s LOCAL_TCP_PORT DEVICE_TCP_PORT\n", argv[0]); - return 0; - } - - listen_port = atoi(argv[1]); - device_port = atoi(argv[2]); - - if (!listen_port) { - fprintf(stderr, "Invalid listen_port specified!\n"); - return -EINVAL; - } - - if (!device_port) { - fprintf(stderr, "Invalid device_port specified!\n"); - return -EINVAL; - } - - // first create the listening socket endpoint waiting for connections. - mysock = create_socket(listen_port); - if (mysock < 0) { - fprintf(stderr, "Error creating socket: %s\n", strerror(errno)); - return -errno; - } else { -#ifdef WIN32 - HANDLE acceptor = NULL; -#else - pthread_t acceptor; -#endif - struct sockaddr_in c_addr; - socklen_t len = sizeof(struct sockaddr_in); - struct client_data cdata; - int c_sock; - while (1) { - printf("waiting for connection\n"); - c_sock = accept(mysock, (struct sockaddr*)&c_addr, &len); - if (c_sock) { - printf("accepted connection, fd = %d\n", c_sock); - cdata.fd = c_sock; -#ifdef WIN32 - acceptor = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)acceptor_thread, &cdata, 0, NULL); - WaitForSingleObject(acceptor, INFINITE); -#else - pthread_create(&acceptor, NULL, acceptor_thread, &cdata); - pthread_join(acceptor, NULL); -#endif - } else { - break; - } - } - close(c_sock); - close(mysock); - } - - return 0; -} diff --git a/udev/85-usbmuxd.rules.in b/udev/85-usbmuxd.rules.in index 6f2186b9..da8042da 100644 --- a/udev/85-usbmuxd.rules.in +++ b/udev/85-usbmuxd.rules.in @@ -1,7 +1,7 @@ # usbmuxd ("Apple Mobile Device" muxer listening on /var/run/usbmuxd) # Forces iDevices to the last USB configuration and runs usbmuxd -ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="12[9a][0-9a-f]", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}!="$attr{bNumConfigurations}", ATTR{bConfigurationValue}="$attr{bNumConfigurations}", OWNER="usbmux", RUN+="@CMAKE_INSTALL_PREFIX@/sbin/usbmuxd -u -U usbmux" +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="12[9a][0-9a-f]", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}!="$attr{bNumConfigurations}", ATTR{bConfigurationValue}="$attr{bNumConfigurations}", OWNER="usbmux", RUN+="@prefix@/sbin/usbmuxd -u -U usbmux" # Exit usbmuxd when the last device is removed -ACTION=="remove", SUBSYSTEM=="usb", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ENV{INTERFACE}=="255/*", RUN+="@CMAKE_INSTALL_PREFIX@/sbin/usbmuxd -x" +ACTION=="remove", SUBSYSTEM=="usb", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ENV{INTERFACE}=="255/*", RUN+="@prefix@/sbin/usbmuxd -x" diff --git a/udev/CMakeLists.txt b/udev/CMakeLists.txt deleted file mode 100644 index 0f7042db..00000000 --- a/udev/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/85-usbmuxd.rules.in ${CMAKE_CURRENT_BINARY_DIR}/85-usbmuxd.rules @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/85-usbmuxd.rules DESTINATION /lib/udev/rules.d/) From 5e0119ba49106b449d983e3e71222e0a53936953 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 17 Sep 2013 11:56:34 +0200 Subject: [PATCH 03/70] silence several compiler warnings --- src/client.c | 4 ++-- src/device.c | 2 +- src/log.c | 2 +- src/log.h | 2 +- src/main.c | 10 +++++----- src/usb-linux.c | 6 ++++++ 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/client.c b/src/client.c index ac1045a2..d4a4a103 100644 --- a/src/client.c +++ b/src/client.c @@ -318,7 +318,7 @@ static int start_listen(struct mux_client *client) count = device_get_list(devs); // going to need a larger buffer for many devices - int needed_buffer = count * (sizeof(struct usbmuxd_device_record) + sizeof(struct usbmuxd_header)) + REPLY_BUF_SIZE; + uint32_t needed_buffer = count * (sizeof(struct usbmuxd_device_record) + sizeof(struct usbmuxd_header)) + REPLY_BUF_SIZE; if(client->ob_capacity < needed_buffer) { usbmuxd_log(LL_DEBUG, "Enlarging client %d reply buffer %d -> %d to make space for device notifications", client->fd, client->ob_capacity, needed_buffer); client->ob_buf = realloc(client->ob_buf, needed_buffer); @@ -464,7 +464,7 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) static void process_send(struct mux_client *client) { - int res; + uint32_t res; if(!client->ob_size) { usbmuxd_log(LL_WARNING, "Client %d OUT process but nothing to send?", client->fd); client->events &= ~POLLOUT; diff --git a/src/device.c b/src/device.c index 399bb0c8..5adf3217 100644 --- a/src/device.c +++ b/src/device.c @@ -114,7 +114,7 @@ struct mux_device static struct collection device_list; -uint64_t mstime64(void) +static uint64_t mstime64(void) { struct timeval tv; gettimeofday(&tv, NULL); diff --git a/src/log.c b/src/log.c index 1973257b..2d22e945 100644 --- a/src/log.c +++ b/src/log.c @@ -33,7 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "log.h" -int log_level = LL_WARNING; +unsigned int log_level = LL_WARNING; int log_syslog = 0; diff --git a/src/log.h b/src/log.h index eeefa41d..1fb77ee6 100644 --- a/src/log.h +++ b/src/log.h @@ -33,7 +33,7 @@ enum loglevel { LL_FLOOD, }; -extern int log_level; +extern unsigned int log_level; void log_enable_syslog(); void log_disable_syslog(); diff --git a/src/main.c b/src/main.c index 0997ee82..a9afdf69 100644 --- a/src/main.c +++ b/src/main.c @@ -69,7 +69,7 @@ static int daemon_pipe; static int report_to_parent = 0; -int create_socket(void) { +static int create_socket(void) { struct sockaddr_un bind_addr; int listenfd; @@ -103,7 +103,7 @@ int create_socket(void) { return listenfd; } -void handle_signal(int sig) +static void handle_signal(int sig) { if (sig != SIGUSR1 && sig != SIGUSR2) { usbmuxd_log(LL_NOTICE,"Caught signal %d, exiting", sig); @@ -129,7 +129,7 @@ void handle_signal(int sig) } } -void set_signal_handlers(void) +static void set_signal_handlers(void) { struct sigaction sa; sigset_t set; @@ -167,7 +167,7 @@ static int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout } #endif -int main_loop(int listenfd) +static int main_loop(int listenfd) { int to, cnt, i, dto; struct fdlist pollfds; @@ -524,7 +524,7 @@ int main(int argc, char *argv[]) goto terminate; } sprintf(pids, "%d", getpid()); - if ((res = write(lfd, pids, strlen(pids))) != strlen(pids)) { + if ((size_t)(res = write(lfd, pids, strlen(pids))) != strlen(pids)) { usbmuxd_log(LL_FATAL, "Could not write pidfile!"); if(res >= 0) res = -2; diff --git a/src/usb-linux.c b/src/usb-linux.c index 334d9670..f937de0e 100644 --- a/src/usb-linux.c +++ b/src/usb-linux.c @@ -121,6 +121,9 @@ static void tx_callback(struct libusb_transfer *xfer) usbmuxd_log(LL_ERROR, "TX transfer overflow for device %d-%d", dev->bus, dev->address); break; // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad) + default: + // this should never be reached. + break; } // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events // we'll do device_remove there too @@ -190,6 +193,9 @@ static void rx_callback(struct libusb_transfer *xfer) usbmuxd_log(LL_ERROR, "RX transfer overflow for device %d-%d", dev->bus, dev->address); break; // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad) + default: + // this should never be reached. + break; } free(xfer->buffer); dev->rx_xfer = NULL; From a98ed839e2cbc582439cd8aa1d539392bf43fe66 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 17 Sep 2013 12:14:51 +0200 Subject: [PATCH 04/70] added missing usbmuxd-proto.h --- src/usbmuxd-proto.h | 96 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/usbmuxd-proto.h diff --git a/src/usbmuxd-proto.h b/src/usbmuxd-proto.h new file mode 100644 index 00000000..7842975d --- /dev/null +++ b/src/usbmuxd-proto.h @@ -0,0 +1,96 @@ +/* + usbmuxd - iPhone/iPod Touch USB multiplex server daemon + +Copyright (C) 2009 Paul Sladen +Copyright (C) 2009 Nikias Bassen +Copyright (C) 2009 Hector Martin "marcan" + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 or version 3. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/* Protocol defintion for usbmuxd proxy protocol */ +#ifndef __USBMUXD_PROTO_H +#define __USBMUXD_PROTO_H + +#include +#define USBMUXD_PROTOCOL_VERSION 0 + +#if defined(WIN32) || defined(__CYGWIN__) +#define USBMUXD_SOCKET_PORT 27015 +#else +#define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +enum usbmuxd_result { + RESULT_OK = 0, + RESULT_BADCOMMAND = 1, + RESULT_BADDEV = 2, + RESULT_CONNREFUSED = 3, + // ??? + // ??? + RESULT_BADVERSION = 6, +}; + +enum usbmuxd_msgtype { + MESSAGE_RESULT = 1, + MESSAGE_CONNECT = 2, + MESSAGE_LISTEN = 3, + MESSAGE_DEVICE_ADD = 4, + MESSAGE_DEVICE_REMOVE = 5, + //??? + //??? + MESSAGE_PLIST = 8, +}; + +struct usbmuxd_header { + uint32_t length; // length of message, including header + uint32_t version; // protocol version + uint32_t message; // message type + uint32_t tag; // responses to this query will echo back this tag +} __attribute__((__packed__)); + +struct usbmuxd_result_msg { + struct usbmuxd_header header; + uint32_t result; +} __attribute__((__packed__)); + +struct usbmuxd_connect_request { + struct usbmuxd_header header; + uint32_t device_id; + uint16_t port; // TCP port number + uint16_t reserved; // set to zero +} __attribute__((__packed__)); + +struct usbmuxd_listen_request { + struct usbmuxd_header header; +} __attribute__((__packed__)); + +struct usbmuxd_device_record { + uint32_t device_id; + uint16_t product_id; + char serial_number[256]; + uint16_t padding; + uint32_t location; +} __attribute__((__packed__)); + +#ifdef __cplusplus +} +#endif + +#endif /* __USBMUXD_PROTO_H */ From a18d2c0ad8b192b01c145b1677574b3de12eccad Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2013 23:41:51 +0200 Subject: [PATCH 05/70] install usbmuxd to $prefix/sbin, not $prefix/bin --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index d2fcfefb..ae8fee7b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ AM_CFLAGS = $(GLOBAL_CFLAGS) -I$(top_srcdir)/src $(libplist_CFLAGS) $(libusb_CFLAGS) AM_LDFLAGS = $(libplist_LIBS) $(libusb_LIBS) -bin_PROGRAMS = usbmuxd +sbin_PROGRAMS = usbmuxd usbmuxd_SOURCES = client.c client.h \ device.c device.h \ From 8e4762fa3e4f860d014afb9f66750ffbb9d46763 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 19 Sep 2013 07:45:02 +0200 Subject: [PATCH 06/70] added preflight worker implementation to handle initial device pairing --- configure.ac | 30 +++++- src/Makefile.am | 5 +- src/client.c | 1 + src/device.c | 19 +++- src/device.h | 2 + src/main.c | 21 +++- src/preflight.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++ src/preflight.h | 28 +++++ 8 files changed, 366 insertions(+), 11 deletions(-) create mode 100644 src/preflight.c create mode 100644 src/preflight.h diff --git a/configure.ac b/configure.ac index a874692d..b7aa54be 100644 --- a/configure.ac +++ b/configure.ac @@ -18,6 +18,8 @@ AC_PROG_LIBTOOL # Checks for libraries. PKG_CHECK_MODULES(libusb, libusb-1.0 >= 1.0.3) PKG_CHECK_MODULES(libplist, libplist >= 1.9, have_plist=yes, have_plist=no) +PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.1.6, 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])]) AC_ARG_WITH([protov1], [AS_HELP_STRING([--without-protov1], @@ -40,6 +42,27 @@ else fi fi +AC_ARG_WITH([preflight], + [AS_HELP_STRING([--without-preflight], + [do not build with preflight worker support (default is yes)])], + [with_preflight=no], + [with_preflight=yes]) + +if test "x$have_limd" = "xyes"; then + if test "x$with_preflight" != "xyes"; then + have_limd=no + echo "*** Note: preflight worker support has been disabled ***" + else + AC_DEFINE(HAVE_LIBIMOBILEDEVICE, 1, [Define if you have libimobiledevice support]) + AC_SUBST(libimobiledevice_CFLAGS) + AC_SUBST(libimobiledevice_LIBS) + fi +else + if test "x$with_preflight" == "xyes"; then + AC_MSG_ERROR([preflight worker support requested but libimobiledevice could not befound]) + fi +fi + # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([stdint.h stdlib.h string.h]) @@ -73,7 +96,7 @@ case ${host_os} in esac AM_CONDITIONAL(WIN32, test x$win32 = xtrue) -AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter") +AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-g -Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter") AC_SUBST(GLOBAL_CFLAGS) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) @@ -88,8 +111,9 @@ echo " Configuration for $PACKAGE $VERSION: ------------------------------------------- - Install prefix: .........: $prefix - Protocol v1 support: ....: $have_plist + Install prefix: ...........: $prefix + Protocol v1 support: ......: $have_plist + Preflight worker support ..: $have_limd Now type 'make' to build $PACKAGE $VERSION, and then 'make install' for installation. diff --git a/src/Makefile.am b/src/Makefile.am index ae8fee7b..883f1d84 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,10 +1,11 @@ -AM_CFLAGS = $(GLOBAL_CFLAGS) -I$(top_srcdir)/src $(libplist_CFLAGS) $(libusb_CFLAGS) -AM_LDFLAGS = $(libplist_LIBS) $(libusb_LIBS) +AM_CFLAGS = $(GLOBAL_CFLAGS) -I$(top_srcdir)/src $(libplist_CFLAGS) $(libusb_CFLAGS) $(libimobildevice_CFLAGS) +AM_LDFLAGS = $(libplist_LIBS) $(libusb_LIBS) $(libimobiledevice_LIBS) $(libpthread_LIBS) sbin_PROGRAMS = usbmuxd usbmuxd_SOURCES = client.c client.h \ device.c device.h \ + preflight.c preflight.h \ log.c log.h \ usb-linux.c usb.h \ utils.c utils.h \ diff --git a/src/client.c b/src/client.c index d4a4a103..b2e3644b 100644 --- a/src/client.c +++ b/src/client.c @@ -584,6 +584,7 @@ void client_process(int fd, short events) void client_device_add(struct device_info *dev) { 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); diff --git a/src/device.c b/src/device.c index 5adf3217..69f623a3 100644 --- a/src/device.c +++ b/src/device.c @@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include "device.h" #include "client.h" +#include "preflight.h" #include "usb.h" #include "log.h" @@ -106,6 +107,7 @@ struct mux_device struct usb_device *usbdev; int id; enum mux_dev_state state; + int visible; struct collection connections; uint16_t next_sport; unsigned char *pktbuf; @@ -478,7 +480,7 @@ static void device_version_input(struct mux_device *dev, struct version_header * info.location = usb_get_location(dev->usbdev); info.serial = usb_get_serial(dev->usbdev); info.pid = usb_get_pid(dev->usbdev); - client_device_add(&info); + preflight_worker_device_add(&info); } @@ -694,6 +696,7 @@ int device_add(struct usb_device *usbdev) dev->id = id; dev->usbdev = usbdev; dev->state = MUXDEV_INIT; + dev->visible = 0; dev->next_sport = 1; dev->pktbuf = malloc(DEV_MRU); dev->pktlen = 0; @@ -732,11 +735,21 @@ void device_remove(struct usb_device *usbdev) 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) +{ + FOREACH(struct mux_device *dev, &device_list) { + if(dev->id == device_id) { + dev->visible = 1; + break; + } + } ENDFOREACH +} + int device_get_count(void) { int count = 0; FOREACH(struct mux_device *dev, &device_list) { - if(dev->state == MUXDEV_ACTIVE) + if((dev->state == MUXDEV_ACTIVE) && dev->visible) count++; } ENDFOREACH return count; @@ -746,7 +759,7 @@ int device_get_list(struct device_info *p) { int count = 0; FOREACH(struct mux_device *dev, &device_list) { - if(dev->state == MUXDEV_ACTIVE) { + if((dev->state == MUXDEV_ACTIVE) && dev->visible) { p->id = dev->id; p->serial = usb_get_serial(dev->usbdev); p->location = usb_get_location(dev->usbdev); diff --git a/src/device.h b/src/device.h index a06cd071..8e51b3ad 100644 --- a/src/device.h +++ b/src/device.h @@ -40,6 +40,8 @@ int device_start_connect(int device_id, uint16_t port, struct mux_client *client void device_client_process(int device_id, struct mux_client *client, short events); void device_abort_connect(int device_id, struct mux_client *client); +void device_set_visible(int device_id); + int device_get_count(void); int device_get_list(struct device_info *p); diff --git a/src/main.c b/src/main.c index a9afdf69..66592cca 100644 --- a/src/main.c +++ b/src/main.c @@ -50,9 +50,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #ifdef ANDROID static const char *socket_path = "/data/local/tmp/usbmuxd"; static const char *lockfile = "/data/local/tmp/usbmuxd.pid"; + static const char *userprefdir = "/data/local/tmp/lockdown"; #else static const char *socket_path = "/var/run/usbmuxd"; static const char *lockfile = "/var/run/usbmuxd.pid"; + static const char *userprefdir = "/var/lib/lockdown"; #endif int should_exit; @@ -290,9 +292,6 @@ static int daemonize(void) close(pfd[0]); report_to_parent = 1; - // Change the file mode mask - umask(0); - // Create a new SID for the child process sid = setsid(); if (sid < 0) { @@ -536,6 +535,13 @@ int main(int argc, char *argv[]) if(listenfd < 0) goto terminate; + struct stat fst; + int userprefdir_created = 0; + if (stat(userprefdir, &fst) < 0) { + mkdir(userprefdir, 0775); + userprefdir_created = 1; + } + // drop elevated privileges if (drop_privileges && (getuid() == 0 || geteuid() == 0)) { struct passwd *pw; @@ -553,6 +559,15 @@ int main(int argc, char *argv[]) if (pw->pw_uid == 0) { usbmuxd_log(LL_INFO, "Not dropping privileges to root"); } else { + if (userprefdir_created) { + if (chown(userprefdir, pw->pw_uid, pw->pw_gid) < 0) { + usbmuxd_log(LL_WARNING, "chown(%s, %d, %d) failed", userprefdir, pw->pw_uid, pw->pw_gid); + } + if (chmod(userprefdir, 02775) < 0) { + usbmuxd_log(LL_WARNING, "chmod %s failed", userprefdir); + } + } + if ((res = initgroups(drop_user, pw->pw_gid)) < 0) { usbmuxd_log(LL_FATAL, "Failed to drop privileges (cannot set supplementary groups)"); goto terminate; diff --git a/src/preflight.c b/src/preflight.c new file mode 100644 index 00000000..0041b21a --- /dev/null +++ b/src/preflight.c @@ -0,0 +1,271 @@ +/* + usbmuxd - iPhone/iPod Touch USB multiplex server daemon + +Copyright (C) 2013 Nikias Bassen + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 or version 3. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include "preflight.h" +#include "client.h" +#include "log.h" + +#ifdef HAVE_LIBIMOBILEDEVICE +enum connection_type { + CONNECTION_USBMUXD = 1 +}; + +struct idevice_private { + char *udid; + enum connection_type conn_type; + void *conn_data; +}; + +extern void userpref_get_system_buid(char **systembuid); + +struct np_cb_data { + idevice_t dev; + np_client_t np; +}; + +static void set_untrusted_host_buid(lockdownd_client_t lockdown) +{ + char* system_buid = NULL; + userpref_get_system_buid(&system_buid); + usbmuxd_log(LL_DEBUG, "%s: Setting UntrustedHostBUID to %s", __func__, system_buid); + lockdownd_set_value(lockdown, NULL, "UntrustedHostBUID", plist_new_string(system_buid)); + free(system_buid); +} + +static void np_callback(const char* notification, void* userdata) +{ + struct np_cb_data *cbdata = (struct np_cb_data*)userdata; + idevice_t dev = cbdata->dev; + struct idevice_private *_dev = (struct idevice_private*)dev; + + lockdownd_client_t lockdown = NULL; + lockdownd_error_t lerr; + + if (strlen(notification) == 0) { + cbdata->np = NULL; + return; + } + + if (strcmp(notification, "com.apple.mobile.lockdown.request_pair") == 0) { + usbmuxd_log(LL_INFO, "%s: user trusted this computer on device %s, pairing now", __func__, _dev->udid); + lerr = lockdownd_client_new(dev, &lockdown, "usbmuxd"); + if (lerr != LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr); + return; + } + + lerr = lockdownd_pair(lockdown, NULL); + if (lerr != LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr); + lockdownd_client_free(lockdown); + return; + } + lockdownd_client_free(lockdown); + // device will reconnect by itself at this point. + + } else if (strcmp(notification, "com.apple.mobile.lockdown.request_host_buid") == 0) { + lerr = lockdownd_client_new(cbdata->dev, &lockdown, "usbmuxd"); + if (lerr != LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr); + } else { + set_untrusted_host_buid(lockdown); + lockdownd_client_free(lockdown); + } + } +} + +static void* preflight_worker_handle_device_add(void* userdata) +{ + struct device_info *info = (struct device_info*)userdata; + struct idevice_private *_dev = (struct idevice_private*)malloc(sizeof(struct idevice_private)); + _dev->udid = strdup(info->serial); + _dev->conn_type = CONNECTION_USBMUXD; + _dev->conn_data = (void*)(long)info->id; + + idevice_t dev = (idevice_t)_dev; + + lockdownd_client_t lockdown; + lockdownd_error_t lerr; + + lerr = lockdownd_client_new(dev, &lockdown, "usbmuxd"); + if (lerr != LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr); + goto leave; + } + + char *type = NULL; + lerr = lockdownd_query_type(lockdown, &type); + if (!type) { + usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get lockdownd type from device %s, lockdown error %d", __func__, _dev->udid, lerr); + goto leave; + } + + if (strcmp(type, "com.apple.mobile.lockdown") != 0) { + // make restore mode devices visible + client_device_add(info); + goto leave; + } + + char *host_id = NULL; + userpref_device_record_get_host_id(dev->udid, &host_id); + lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); + free(host_id); + if (lerr == LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_INFO, "%s: StartSession success for device %s", __func__, _dev->udid); + client_device_add(info); + goto leave; + } + + usbmuxd_log(LL_INFO, "%s: StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr); + if (lerr == LOCKDOWN_E_INVALID_HOST_ID) { + usbmuxd_log(LL_INFO, "%s: Device %s is not paired with this host.", __func__, _dev->udid); + } + + plist_t value = NULL; + 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; + } + + char* version_str = NULL; + plist_get_string_val(value, &version_str); + 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; + } + + int version_major = strtol(version_str, NULL, 10); + if (version_major >= 7) { + // ============== iOS 7.0 and beyond ============= + usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid); + + set_untrusted_host_buid(lockdown); + + lockdownd_service_descriptor_t service = NULL; + lerr = lockdownd_start_service(lockdown, "com.apple.mobile.insecure_notification_proxy", &service); + if (lerr != LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_ERROR, "%s: ERROR: Could not start insecure_notification_proxy on %s, lockdown error %d", __func__, _dev->udid, lerr); + goto leave; + } + + np_client_t np = NULL; + np_client_new(dev, service, &np); + + lockdownd_service_descriptor_free(service); + service = NULL; + + lockdownd_client_free(lockdown); + lockdown = NULL; + + struct np_cb_data cbdata; + cbdata.dev = dev; + cbdata.np = np; + + np_set_notify_callback(np, np_callback, (void*)&cbdata); + + const char* spec[] = { + "com.apple.mobile.lockdown.request_pair", + "com.apple.mobile.lockdown.request_host_buid", + NULL + }; + np_observe_notifications(np, spec); + + usbmuxd_log(LL_INFO, "%s: Waiting for user to trust this computer on device %s", __func__, _dev->udid); + // TODO send notification to user's desktop + while (cbdata.np) { + sleep(1); + } + + if (cbdata.np) { + np_client_free(cbdata.np); + } + } else { + // ============== iOS 6.x and below ============== + lerr = lockdownd_pair(lockdown, NULL); + if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { + usbmuxd_log(LL_INFO, "%s: Device %s is locked with a passcode. Cannot pair.", __func__, _dev->udid); + // TODO send notification to user's desktop + goto leave; + } else if (lerr != LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr); + goto leave; + } + + host_id = NULL; + userpref_device_record_get_host_id(dev->udid, &host_id); + lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); + free(host_id); + if (lerr != LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_ERROR, "%s: ERROR StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr); + goto leave; + } + + lerr = lockdownd_validate_pair(lockdown, NULL); + if (lerr != LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_ERROR, "%s: ERROR: ValidatePair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr); + goto leave; + } + + // make device visible + client_device_add(info); + } + +leave: + if (lockdown) + lockdownd_client_free(lockdown); + if (dev) + idevice_free(dev); + + free(info); + + return NULL; +} +#endif + +void preflight_worker_device_add(struct device_info* info) +{ +#ifdef HAVE_LIBIMOBILEDEVICE + struct device_info *infocopy = (struct device_info*)malloc(sizeof(struct device_info)); + + memcpy(infocopy, info, sizeof(struct device_info)); + + pthread_t th; + pthread_create(&th, NULL, preflight_worker_handle_device_add, infocopy); +#else + client_device_add(info); +#endif +} diff --git a/src/preflight.h b/src/preflight.h new file mode 100644 index 00000000..dce33567 --- /dev/null +++ b/src/preflight.h @@ -0,0 +1,28 @@ +/* + usbmuxd - iPhone/iPod Touch USB multiplex server daemon + +Copyright (C) 2013 Nikias Bassen + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 or version 3. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef __PREFLIGHT_H__ +#define __PREFLIGHT_H__ + +#include "device.h" + +void preflight_worker_device_add(struct device_info* info); + +#endif From 71943d1152828daf672e2b5a991fc75c41be72ab Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 19 Sep 2013 08:08:38 +0200 Subject: [PATCH 07/70] make sure usbmuxd -x does not terminate when unpaired devices are still present --- src/client.c | 4 ++-- src/device.c | 8 ++++---- src/device.h | 4 ++-- src/main.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/client.c b/src/client.c index b2e3644b..8f7d9451 100644 --- a/src/client.c +++ b/src/client.c @@ -311,11 +311,11 @@ static int start_listen(struct mux_client *client) int count, i; client->state = CLIENT_LISTEN; - count = device_get_count(); + count = device_get_count(0); if(!count) return 0; devs = malloc(sizeof(struct device_info) * count); - count = device_get_list(devs); + count = device_get_list(0, devs); // going to need a larger buffer for many devices uint32_t needed_buffer = count * (sizeof(struct usbmuxd_device_record) + sizeof(struct usbmuxd_header)) + REPLY_BUF_SIZE; diff --git a/src/device.c b/src/device.c index 69f623a3..e3006db7 100644 --- a/src/device.c +++ b/src/device.c @@ -745,21 +745,21 @@ void device_set_visible(int device_id) } ENDFOREACH } -int device_get_count(void) +int device_get_count(int include_hidden) { int count = 0; FOREACH(struct mux_device *dev, &device_list) { - if((dev->state == MUXDEV_ACTIVE) && dev->visible) + if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) count++; } ENDFOREACH return count; } -int device_get_list(struct device_info *p) +int device_get_list(int include_hidden, struct device_info *p) { int count = 0; FOREACH(struct mux_device *dev, &device_list) { - if((dev->state == MUXDEV_ACTIVE) && dev->visible) { + if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) { p->id = dev->id; p->serial = usb_get_serial(dev->usbdev); p->location = usb_get_location(dev->usbdev); diff --git a/src/device.h b/src/device.h index 8e51b3ad..f8ff590d 100644 --- a/src/device.h +++ b/src/device.h @@ -42,8 +42,8 @@ void device_abort_connect(int device_id, struct mux_client *client); void device_set_visible(int device_id); -int device_get_count(void); -int device_get_list(struct device_info *p); +int device_get_count(int include_hidden); +int device_get_list(int include_hidden, struct device_info *p); int device_get_timeout(void); void device_check_timeouts(void); diff --git a/src/main.c b/src/main.c index 66592cca..bd3a352a 100644 --- a/src/main.c +++ b/src/main.c @@ -114,7 +114,7 @@ static void handle_signal(int sig) if(opt_udev) { if (sig == SIGUSR1) { usbmuxd_log(LL_INFO, "Caught SIGUSR1, checking if we can terminate (no more devices attached)..."); - if (device_get_count() > 0) { + if (device_get_count(1) > 0) { // we can't quit, there are still devices attached. usbmuxd_log(LL_NOTICE, "Refusing to terminate, there are still devices attached. Kill me with signal 15 (TERM) to force quit."); } else { From b9eb89e942dce258978a0ad1e5347ea88d6c1f6d Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 19 Sep 2013 20:46:30 +0200 Subject: [PATCH 08/70] Bump version to 1.0.9 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b7aa54be..c41d806a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT(usbmuxd, 1.0.8, nospam@nowhere.com) +AC_INIT(usbmuxd, 1.0.9, nospam@nowhere.com) AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) AC_CONFIG_SRCDIR([src/]) From 04c4f392aeff333e3610e72a5ce5439bd3b53dc1 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 19 Sep 2013 20:53:58 +0200 Subject: [PATCH 09/70] preflight: Fix some comments to comply to C89 --- src/preflight.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/preflight.c b/src/preflight.c index 0041b21a..0582dd1b 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -170,7 +170,7 @@ static void* preflight_worker_handle_device_add(void* userdata) int version_major = strtol(version_str, NULL, 10); if (version_major >= 7) { - // ============== iOS 7.0 and beyond ============= + /* iOS 7.0 and later */ usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid); set_untrusted_host_buid(lockdown); @@ -205,7 +205,7 @@ static void* preflight_worker_handle_device_add(void* userdata) np_observe_notifications(np, spec); usbmuxd_log(LL_INFO, "%s: Waiting for user to trust this computer on device %s", __func__, _dev->udid); - // TODO send notification to user's desktop + /* TODO send notification to user's desktop */ while (cbdata.np) { sleep(1); } @@ -214,7 +214,7 @@ static void* preflight_worker_handle_device_add(void* userdata) np_client_free(cbdata.np); } } else { - // ============== iOS 6.x and below ============== + /* iOS 6.x and earlier */ lerr = lockdownd_pair(lockdown, NULL); if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { usbmuxd_log(LL_INFO, "%s: Device %s is locked with a passcode. Cannot pair.", __func__, _dev->udid); @@ -240,7 +240,7 @@ static void* preflight_worker_handle_device_add(void* userdata) goto leave; } - // make device visible + /* emit device added event and thus make device visible to clients */ client_device_add(info); } From 6c793a8857cf2239472193b66a909e5275a747aa Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 19 Sep 2013 21:02:19 +0200 Subject: [PATCH 10/70] preflight: Allow pre iOS 6 devices to become visible if pairing fails This allows any client to react and handle pairing errors which includes password protected devices and alike. --- src/preflight.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/preflight.c b/src/preflight.c index 0582dd1b..ec510ecb 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -216,12 +216,17 @@ static void* preflight_worker_handle_device_add(void* userdata) } else { /* iOS 6.x and earlier */ lerr = lockdownd_pair(lockdown, NULL); - if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { - usbmuxd_log(LL_INFO, "%s: Device %s is locked with a passcode. Cannot pair.", __func__, _dev->udid); - // TODO send notification to user's desktop - goto leave; - } else if (lerr != LOCKDOWN_E_SUCCESS) { - usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr); + if (lerr != LOCKDOWN_E_SUCCESS) { + if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { + usbmuxd_log(LL_INFO, "%s: Device %s is locked with a passcode. Cannot pair.", __func__, _dev->udid); + /* TODO send notification to user's desktop */ + } else { + usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr); + } + + /* make device visible anyways */ + client_device_add(info); + goto leave; } From 1e6c6011435f4e30e0f4c52eac44b43bbb8e9190 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 19 Sep 2013 21:46:51 +0200 Subject: [PATCH 11/70] preflight: Add missing definition for userpref_device_record_get_host_id() --- src/preflight.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/preflight.h b/src/preflight.h index dce33567..045a5e9a 100644 --- a/src/preflight.h +++ b/src/preflight.h @@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "device.h" +extern void userpref_device_record_get_host_id(const char *udid, char **host_id); + void preflight_worker_device_add(struct device_info* info); #endif From dfe7c690968927901fba4374551d03ff981310c1 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 19 Sep 2013 21:47:44 +0200 Subject: [PATCH 12/70] preflight: Use userpref_get_system_buid() instead of hardcoded path --- src/main.c | 3 +++ src/preflight.c | 6 ++---- src/preflight.h | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index bd3a352a..983a4f57 100644 --- a/src/main.c +++ b/src/main.c @@ -57,6 +57,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA static const char *userprefdir = "/var/lib/lockdown"; #endif +extern const char* userpref_get_config_dir(); int should_exit; int should_discover; @@ -535,6 +536,8 @@ int main(int argc, char *argv[]) if(listenfd < 0) goto terminate; + const char* userprefdir = userpref_get_config_dir(); + struct stat fst; int userprefdir_created = 0; if (stat(userprefdir, &fst) < 0) { diff --git a/src/preflight.c b/src/preflight.c index ec510ecb..17748c63 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -49,8 +49,6 @@ struct idevice_private { void *conn_data; }; -extern void userpref_get_system_buid(char **systembuid); - struct np_cb_data { idevice_t dev; np_client_t np; @@ -194,9 +192,9 @@ static void* preflight_worker_handle_device_add(void* userdata) struct np_cb_data cbdata; cbdata.dev = dev; cbdata.np = np; - + np_set_notify_callback(np, np_callback, (void*)&cbdata); - + const char* spec[] = { "com.apple.mobile.lockdown.request_pair", "com.apple.mobile.lockdown.request_host_buid", diff --git a/src/preflight.h b/src/preflight.h index 045a5e9a..62349d19 100644 --- a/src/preflight.h +++ b/src/preflight.h @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "device.h" +extern void userpref_get_system_buid(char **systembuid); extern void userpref_device_record_get_host_id(const char *udid, char **host_id); void preflight_worker_device_add(struct device_info* info); From 15d74f7c7a21786086b9c5379ab4e2dd8d712761 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 19 Sep 2013 21:48:05 +0200 Subject: [PATCH 13/70] preflight: Trigger new trust dialog if user denied pairing before This changes allows to replug a device to trigger a new trust dialog if the user did deny the pairing before. --- src/preflight.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/preflight.c b/src/preflight.c index 17748c63..30a2217b 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -137,6 +137,7 @@ static void* preflight_worker_handle_device_add(void* userdata) goto leave; } + int is_device_paired = 0; char *host_id = NULL; userpref_device_record_get_host_id(dev->udid, &host_id); lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); @@ -150,6 +151,8 @@ static void* preflight_worker_handle_device_add(void* userdata) usbmuxd_log(LL_INFO, "%s: StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr); if (lerr == LOCKDOWN_E_INVALID_HOST_ID) { usbmuxd_log(LL_INFO, "%s: Device %s is not paired with this host.", __func__, _dev->udid); + } else { + is_device_paired = 1; } plist_t value = NULL; @@ -173,6 +176,11 @@ static void* preflight_worker_handle_device_add(void* userdata) set_untrusted_host_buid(lockdown); + /* if not paired, trigger the trust dialog to make sure it appears */ + if (!is_device_paired) { + lockdownd_pair(lockdown, NULL); + } + lockdownd_service_descriptor_t service = NULL; lerr = lockdownd_start_service(lockdown, "com.apple.mobile.insecure_notification_proxy", &service); if (lerr != LOCKDOWN_E_SUCCESS) { From 1afac1e9b2492ab145968f9c1c739a6837fce689 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 22 Sep 2013 03:58:59 +0200 Subject: [PATCH 14/70] main: enclose libimobiledevice related code in #ifdefs --- src/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.c b/src/main.c index 983a4f57..f784f838 100644 --- a/src/main.c +++ b/src/main.c @@ -57,7 +57,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA static const char *userprefdir = "/var/lib/lockdown"; #endif +#ifdef HAVE_LIBIMOBILEDEVICE extern const char* userpref_get_config_dir(); +#endif + int should_exit; int should_discover; @@ -536,6 +539,7 @@ int main(int argc, char *argv[]) if(listenfd < 0) goto terminate; +#ifdef HAVE_LIBIMOBILEDEVICE const char* userprefdir = userpref_get_config_dir(); struct stat fst; @@ -544,6 +548,7 @@ int main(int argc, char *argv[]) mkdir(userprefdir, 0775); userprefdir_created = 1; } +#endif // drop elevated privileges if (drop_privileges && (getuid() == 0 || geteuid() == 0)) { @@ -562,6 +567,7 @@ int main(int argc, char *argv[]) if (pw->pw_uid == 0) { usbmuxd_log(LL_INFO, "Not dropping privileges to root"); } else { +#ifdef HAVE_LIBIMOBILEDEVICE if (userprefdir_created) { if (chown(userprefdir, pw->pw_uid, pw->pw_gid) < 0) { usbmuxd_log(LL_WARNING, "chown(%s, %d, %d) failed", userprefdir, pw->pw_uid, pw->pw_gid); @@ -570,6 +576,7 @@ int main(int argc, char *argv[]) usbmuxd_log(LL_WARNING, "chmod %s failed", userprefdir); } } +#endif if ((res = initgroups(drop_user, pw->pw_gid)) < 0) { usbmuxd_log(LL_FATAL, "Failed to drop privileges (cannot set supplementary groups)"); From 7ec44915aeee940afa93280f1b1cc233049add07 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 24 Sep 2013 03:46:22 +0200 Subject: [PATCH 15/70] preflight: handle invalid pair records properly --- src/preflight.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/preflight.c b/src/preflight.c index 30a2217b..97fdb8b9 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -115,9 +115,10 @@ static void* preflight_worker_handle_device_add(void* userdata) idevice_t dev = (idevice_t)_dev; - lockdownd_client_t lockdown; + lockdownd_client_t lockdown = NULL; lockdownd_error_t lerr; +retry: lerr = lockdownd_client_new(dev, &lockdown, "usbmuxd"); if (lerr != LOCKDOWN_E_SUCCESS) { usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr); @@ -149,10 +150,23 @@ static void* preflight_worker_handle_device_add(void* userdata) } usbmuxd_log(LL_INFO, "%s: StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr); - if (lerr == LOCKDOWN_E_INVALID_HOST_ID) { + switch (lerr) { + case LOCKDOWN_E_INVALID_HOST_ID: usbmuxd_log(LL_INFO, "%s: Device %s is not paired with this host.", __func__, _dev->udid); - } else { + break; + case LOCKDOWN_E_SSL_ERROR: + usbmuxd_log(LL_ERROR, "%s: The stored pair record for device %s is invalid. Removing.", __func__, _dev->udid); + if (userpref_remove_device_record(_dev->udid) == 0) { + lockdownd_client_free(lockdown); + lockdown = NULL; + goto retry; + } else { + usbmuxd_log(LL_ERROR, "%s: Could not remove pair record for device %s\n", __func__, _dev->udid); + } + break; + default: is_device_paired = 1; + break; } plist_t value = NULL; From f078c3d89024b36f6f94ed1b374384d7ab7a817b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 24 Sep 2013 20:25:37 +0200 Subject: [PATCH 16/70] preflight: don't wait for trust if device is at setup screen --- src/preflight.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/preflight.c b/src/preflight.c index 97fdb8b9..c40311c9 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -192,7 +192,12 @@ static void* preflight_worker_handle_device_add(void* userdata) /* if not paired, trigger the trust dialog to make sure it appears */ if (!is_device_paired) { - lockdownd_pair(lockdown, NULL); + if (lockdownd_pair(lockdown, NULL) == LOCKDOWN_E_SUCCESS) { + /* if device is still showing the setup screen it will pair even without trust dialog */ + usbmuxd_log(LL_INFO, "%s: Pair success for device %s", __func__, _dev->udid); + client_device_add(info); + goto leave; + } } lockdownd_service_descriptor_t service = NULL; From cbdc6affe26a6177a1eb1c88d95a710cfd71a2f2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 26 Sep 2013 22:39:11 +0200 Subject: [PATCH 17/70] udev: lower rules numbering to make sure we start as early as possible To prevent the trust dialog from appearing on iOS7 devices we need to make sure that no PTP access is happening before usbmuxd starts. So we start as early as possible so the device will be in trusted host state. --- configure.ac | 2 +- udev/{85-usbmuxd.rules.in => 39-usbmuxd.rules.in} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename udev/{85-usbmuxd.rules.in => 39-usbmuxd.rules.in} (100%) diff --git a/configure.ac b/configure.ac index c41d806a..30673041 100644 --- a/configure.ac +++ b/configure.ac @@ -104,7 +104,7 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) AC_OUTPUT([ Makefile src/Makefile -udev/85-usbmuxd.rules +udev/39-usbmuxd.rules ]) echo " diff --git a/udev/85-usbmuxd.rules.in b/udev/39-usbmuxd.rules.in similarity index 100% rename from udev/85-usbmuxd.rules.in rename to udev/39-usbmuxd.rules.in From 002bf2398e57ec8512d3953529f6dca2ca81b5dc Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 26 Sep 2013 22:42:27 +0200 Subject: [PATCH 18/70] actually install udev rules file --- Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.am b/Makefile.am index 2cb1ca06..4ee9db62 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,6 @@ AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 SUBDIRS = src + +udevrulesdir = /lib/udev/rules.d +udevrules_DATA = udev/39-usbmuxd.rules From c9ff0cb5fc27ef0ca93481e764c9fc8e34e4426c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 30 Sep 2013 15:25:17 +0200 Subject: [PATCH 19/70] utils: make FOREACH macro _iter variable unique --- src/utils.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/utils.h b/src/utils.h index 5aa2915b..69a4259e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -54,12 +54,16 @@ void collection_remove(struct collection *col, void *element); int collection_count(struct collection *col); void collection_free(struct collection *col); +#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 _iter; \ - for(_iter=0; _iter<(col)->capacity; _iter++) { \ - if(!(col)->list[_iter]) continue; \ - var = (col)->list[_iter]; + 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 \ } \ From 11735d261049f475c13352191f11356b07c27a06 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 30 Sep 2013 15:58:24 +0200 Subject: [PATCH 20/70] device: suppress two compiler warnings with appropriate casts --- src/device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/device.c b/src/device.c index e3006db7..2d10e1d1 100644 --- a/src/device.c +++ b/src/device.c @@ -403,7 +403,7 @@ void device_client_process(int device_id, struct mux_client *client, short event return; } conn->tx_ack += size; - if(size == conn->ib_size) { + if(size == (int)conn->ib_size) { conn->ib_size = 0; } else { conn->ib_size -= size; @@ -773,7 +773,7 @@ int device_get_list(int include_hidden, struct device_info *p) int device_get_timeout(void) { - uint64_t oldest = (uint64_t)-1; + uint64_t oldest = (uint64_t)-1LL; FOREACH(struct mux_device *dev, &device_list) { if(dev->state == MUXDEV_ACTIVE) { FOREACH(struct mux_connection *conn, &dev->connections) { @@ -783,7 +783,7 @@ int device_get_timeout(void) } } ENDFOREACH uint64_t ct = mstime64(); - if(oldest == -1) + if((int64_t)oldest == -1LL) return 100000; //meh if((ct - oldest) > ACK_TIMEOUT) return 0; From eef049511747b1b66e9dc41a6890f4ebfe2933b4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 30 Sep 2013 16:54:18 +0200 Subject: [PATCH 21/70] client: added mutex around client_list access --- src/client.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/client.c b/src/client.c index 8f7d9451..65dc4ce5 100644 --- a/src/client.c +++ b/src/client.c @@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include #ifdef HAVE_PLIST #include @@ -73,6 +74,7 @@ struct mux_client { }; static struct collection client_list; +pthread_mutex_t client_list_mutex; int client_read(struct mux_client *client, void *buffer, uint32_t len) { @@ -131,7 +133,9 @@ int client_accept(int listenfd) client->state = CLIENT_COMMAND; client->events = POLLIN; + pthread_mutex_lock(&client_list_mutex); collection_add(&client_list, client); + pthread_mutex_unlock(&client_list_mutex); usbmuxd_log(LL_INFO, "New client on fd %d", client->fd); return client->fd; @@ -150,15 +154,19 @@ void client_close(struct mux_client *client) free(client->ob_buf); if(client->ib_buf) free(client->ib_buf); + pthread_mutex_lock(&client_list_mutex); collection_remove(&client_list, client); + pthread_mutex_unlock(&client_list_mutex); free(client); } void client_get_fds(struct fdlist *list) { + pthread_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); } static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length) @@ -556,12 +564,14 @@ static void process_recv(struct mux_client *client) void client_process(int fd, short events) { struct mux_client *client = NULL; + pthread_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); if(!client) { usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd); @@ -583,28 +593,33 @@ void client_process(int fd, short events) void client_device_add(struct device_info *dev) { + pthread_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); } ENDFOREACH + pthread_mutex_unlock(&client_list_mutex); } + void client_device_remove(int device_id) { + pthread_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); } ENDFOREACH + pthread_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); } void client_shutdown(void) @@ -613,5 +628,6 @@ void client_shutdown(void) FOREACH(struct mux_client *client, &client_list) { client_close(client); } ENDFOREACH + pthread_mutex_destroy(&client_list_mutex); collection_free(&client_list); } From 110b5f3aabf2af45da9bf8aec4292b4c00014a14 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 8 Oct 2013 22:24:39 +0200 Subject: [PATCH 22/70] main: prevent uninitialized value when using struct flock --- src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.c b/src/main.c index f784f838..e252b105 100644 --- a/src/main.c +++ b/src/main.c @@ -459,6 +459,7 @@ int main(int argc, char *argv[]) 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) { From 113be3790b0d3df44f4f48970fd5702785c9dcb1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 8 Oct 2013 23:18:18 +0200 Subject: [PATCH 23/70] preflight: plug small memory leak --- src/preflight.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/preflight.c b/src/preflight.c index c40311c9..b616e5f9 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -134,9 +134,11 @@ static void* preflight_worker_handle_device_add(void* userdata) if (strcmp(type, "com.apple.mobile.lockdown") != 0) { // make restore mode devices visible + free(type); client_device_add(info); goto leave; } + free(type); int is_device_paired = 0; char *host_id = NULL; From 6dcd0704ca47628f1c4c4e16ab9a563523e8b6e8 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Wed, 9 Oct 2013 17:14:58 +0200 Subject: [PATCH 24/70] preflight: Free version string in all cases to prevent memory leak --- src/preflight.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/preflight.c b/src/preflight.c index b616e5f9..44a59ff1 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -118,6 +118,9 @@ static void* preflight_worker_handle_device_add(void* userdata) lockdownd_client_t lockdown = NULL; lockdownd_error_t lerr; + plist_t value = NULL; + char* version_str = NULL; + retry: lerr = lockdownd_client_new(dev, &lockdown, "usbmuxd"); if (lerr != LOCKDOWN_E_SUCCESS) { @@ -171,15 +174,16 @@ static void* preflight_worker_handle_device_add(void* userdata) break; } - plist_t value = NULL; 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; } - char* version_str = NULL; - plist_get_string_val(value, &version_str); + if (value && plist_get_node_type(value) == PLIST_STRING) { + plist_get_string_val(value, &version_str); + } + 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; @@ -277,6 +281,10 @@ static void* preflight_worker_handle_device_add(void* userdata) } leave: + if (value) + plist_free(value); + if (version_str) + free(version_str); if (lockdown) lockdownd_client_free(lockdown); if (dev) From 71928df3351dfbd6f308dbb87107925e0388a902 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 9 Oct 2013 17:45:56 +0200 Subject: [PATCH 25/70] preflight: define extern userpref_remove_device_record --- src/preflight.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/preflight.c b/src/preflight.c index 44a59ff1..832996bb 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -54,6 +54,8 @@ struct np_cb_data { np_client_t np; }; +extern uint16_t userpref_remove_device_record(const char* udid); + static void set_untrusted_host_buid(lockdownd_client_t lockdown) { char* system_buid = NULL; From e017748c0a9d6d4cf5d1de644695fb52114f39c0 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Mon, 4 Nov 2013 22:39:21 +0100 Subject: [PATCH 26/70] udev: Set "deactivated" USB configuration on iOS devices by default With the introduction of iOS 7, devices should start of in the "deactivated" USB configuration "0" by default to not trigger a trust dialog. Once the devices are identified, usbmuxd will set the correct USB configuration itself and immediately run the preflight worker code to ensure a trust relationship with the host is established. This change fixes the trust dialog from appearing during hotplug of paired devices. The last remaining issue is that current kernel code still sets the USB configuration to "1" by default before the udev rules and thus causes multiple connection beeps. --- udev/39-usbmuxd.rules.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/udev/39-usbmuxd.rules.in b/udev/39-usbmuxd.rules.in index da8042da..f4eb66f9 100644 --- a/udev/39-usbmuxd.rules.in +++ b/udev/39-usbmuxd.rules.in @@ -1,7 +1,7 @@ # usbmuxd ("Apple Mobile Device" muxer listening on /var/run/usbmuxd) -# Forces iDevices to the last USB configuration and runs usbmuxd -ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="12[9a][0-9a-f]", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}!="$attr{bNumConfigurations}", ATTR{bConfigurationValue}="$attr{bNumConfigurations}", OWNER="usbmux", RUN+="@prefix@/sbin/usbmuxd -u -U usbmux" +# Initialize iOS devices into "deactivated" USB configuration state and run usbmuxd +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="12[9a][0-9a-f]", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux", RUN+="@prefix@/sbin/usbmuxd -u -U usbmux" # Exit usbmuxd when the last device is removed ACTION=="remove", SUBSYSTEM=="usb", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ENV{INTERFACE}=="255/*", RUN+="@prefix@/sbin/usbmuxd -x" From f9aa386d06292bcdcd6aef3a7268151b13e25472 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Mon, 4 Nov 2013 22:53:43 +0100 Subject: [PATCH 27/70] preflight: Add lockdownd prefix to name of set_untrusted_host_buid() --- src/preflight.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/preflight.c b/src/preflight.c index 832996bb..28485db4 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -56,7 +56,7 @@ struct np_cb_data { extern uint16_t userpref_remove_device_record(const char* udid); -static void set_untrusted_host_buid(lockdownd_client_t lockdown) +static void lockdownd_set_untrusted_host_buid(lockdownd_client_t lockdown) { char* system_buid = NULL; userpref_get_system_buid(&system_buid); @@ -101,7 +101,7 @@ static void np_callback(const char* notification, void* userdata) if (lerr != LOCKDOWN_E_SUCCESS) { usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr); } else { - set_untrusted_host_buid(lockdown); + lockdownd_set_untrusted_host_buid(lockdown); lockdownd_client_free(lockdown); } } @@ -196,7 +196,7 @@ static void* preflight_worker_handle_device_add(void* userdata) /* iOS 7.0 and later */ usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid); - set_untrusted_host_buid(lockdown); + lockdownd_set_untrusted_host_buid(lockdown); /* if not paired, trigger the trust dialog to make sure it appears */ if (!is_device_paired) { From 8b3648c00648c9ab7018680cebbf08bd4064c237 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Mon, 4 Nov 2013 22:56:48 +0100 Subject: [PATCH 28/70] preflight: Make device visible during trust dialog pairing and handle unplug The usbmuxd implementation on Win/OS X does allow enumerating and accessing the device during the "trust dialog" pairing process. We now also exit the waiting loop during unplugging of a device while waiting for the trust dialog to be dismissed. --- src/preflight.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/preflight.c b/src/preflight.c index 28485db4..dc4b3dcd 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -49,9 +49,10 @@ struct idevice_private { void *conn_data; }; -struct np_cb_data { +struct cb_data { idevice_t dev; np_client_t np; + int is_device_connected; }; extern uint16_t userpref_remove_device_record(const char* udid); @@ -65,9 +66,20 @@ static void lockdownd_set_untrusted_host_buid(lockdownd_client_t lockdown) free(system_buid); } +static void idevice_callback(const idevice_event_t* event, void* userdata) +{ + struct cb_data *cbdata = (struct cb_data*)userdata; + idevice_t dev = cbdata->dev; + struct idevice_private *_dev = (struct idevice_private*)dev; + + if (event->event == IDEVICE_DEVICE_REMOVE && !strcmp(_dev->udid, event->udid)) { + cbdata->is_device_connected = 0; + } +} + static void np_callback(const char* notification, void* userdata) { - struct np_cb_data *cbdata = (struct np_cb_data*)userdata; + struct cb_data *cbdata = (struct cb_data*)userdata; idevice_t dev = cbdata->dev; struct idevice_private *_dev = (struct idevice_private*)dev; @@ -224,11 +236,13 @@ static void* preflight_worker_handle_device_add(void* userdata) lockdownd_client_free(lockdown); lockdown = NULL; - struct np_cb_data cbdata; + struct cb_data cbdata; cbdata.dev = dev; cbdata.np = np; + cbdata.is_device_connected = 1; np_set_notify_callback(np, np_callback, (void*)&cbdata); + idevice_event_subscribe(idevice_callback, (void*)&cbdata); const char* spec[] = { "com.apple.mobile.lockdown.request_pair", @@ -237,11 +251,19 @@ static void* preflight_worker_handle_device_add(void* userdata) }; np_observe_notifications(np, spec); - usbmuxd_log(LL_INFO, "%s: Waiting for user to trust this computer on device %s", __func__, _dev->udid); /* TODO send notification to user's desktop */ - while (cbdata.np) { + + usbmuxd_log(LL_INFO, "%s: Waiting for user to trust this computer on device %s", __func__, _dev->udid); + + /* make device visible anyways */ + client_device_add(info); + + while (cbdata.np && cbdata.is_device_connected == 1) { sleep(1); } + usbmuxd_log(LL_INFO, "%s: Finished waiting for notification from device %s, is_device_connected %d", __func__, _dev->udid, cbdata.is_device_connected); + + idevice_event_unsubscribe(); if (cbdata.np) { np_client_free(cbdata.np); From 4bfc979d425768be94fa35605869aa188edba0b6 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Mon, 4 Nov 2013 23:06:35 +0100 Subject: [PATCH 29/70] preflight: Add messages to indicate start and finish of preflight process --- src/preflight.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/preflight.c b/src/preflight.c index dc4b3dcd..def6a827 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -135,6 +135,8 @@ static void* preflight_worker_handle_device_add(void* userdata) plist_t value = NULL; char* version_str = NULL; + usbmuxd_log(LL_INFO, "%s: Starting preflight on device %s...", __func__, _dev->udid); + retry: lerr = lockdownd_client_new(dev, &lockdown, "usbmuxd"); if (lerr != LOCKDOWN_E_SUCCESS) { @@ -152,6 +154,7 @@ static void* preflight_worker_handle_device_add(void* userdata) if (strcmp(type, "com.apple.mobile.lockdown") != 0) { // make restore mode devices visible free(type); + usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); client_device_add(info); goto leave; } @@ -164,6 +167,7 @@ static void* preflight_worker_handle_device_add(void* userdata) free(host_id); if (lerr == LOCKDOWN_E_SUCCESS) { usbmuxd_log(LL_INFO, "%s: StartSession success for device %s", __func__, _dev->udid); + usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); client_device_add(info); goto leave; } @@ -215,6 +219,7 @@ static void* preflight_worker_handle_device_add(void* userdata) if (lockdownd_pair(lockdown, NULL) == LOCKDOWN_E_SUCCESS) { /* if device is still showing the setup screen it will pair even without trust dialog */ usbmuxd_log(LL_INFO, "%s: Pair success for device %s", __func__, _dev->udid); + usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); client_device_add(info); goto leave; } @@ -279,6 +284,8 @@ static void* preflight_worker_handle_device_add(void* userdata) usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr); } + usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); + /* make device visible anyways */ client_device_add(info); @@ -300,6 +307,8 @@ static void* preflight_worker_handle_device_add(void* userdata) goto leave; } + usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); + /* emit device added event and thus make device visible to clients */ client_device_add(info); } From dc5cc04c89460f6c47e5b932179b72097bf4d70b Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Mon, 4 Nov 2013 23:07:34 +0100 Subject: [PATCH 30/70] usb: Output message to show USB configuration change --- src/usb-linux.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/usb-linux.c b/src/usb-linux.c index f937de0e..9d463c61 100644 --- a/src/usb-linux.c +++ b/src/usb-linux.c @@ -285,6 +285,7 @@ int usb_discover(void) usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res); continue; } + int current_config = 0; if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %d", bus, address, res); @@ -312,6 +313,8 @@ int usb_discover(void) } libusb_free_config_descriptor(config); } + + usbmuxd_log(LL_INFO, "Setting configuration for device %d-%d, from %d to %d", bus, address, current_config, devdesc.bNumConfigurations); if((res = libusb_set_configuration(handle, devdesc.bNumConfigurations)) != 0) { usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %d", devdesc.bNumConfigurations, bus, address, res); libusb_close(handle); From 7674066d1cbe4334878deb3c736fa92483420960 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 9 Dec 2013 05:17:38 +0100 Subject: [PATCH 31/70] client: also add DeviceID to main dictionary for Attached message --- src/client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client.c b/src/client.c index 65dc4ce5..d9025919 100644 --- a/src/client.c +++ b/src/client.c @@ -251,6 +251,7 @@ static int notify_device_add(struct mux_client *client, struct device_info *dev) uint32_t xmlsize = 0; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("Attached")); + plist_dict_insert_item(dict, "DeviceID", plist_new_uint(dev->id)); plist_t props = plist_new_dict(); // TODO: get current usb speed plist_dict_insert_item(props, "ConnectionSpeed", plist_new_uint(480000000)); From f1409240242789d8e98f5995500880e2f00bdc38 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 10 Dec 2013 19:13:49 +0100 Subject: [PATCH 32/70] main: make sure the non-privileged user has proper access to the config dir --- src/main.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main.c b/src/main.c index e252b105..033c8e47 100644 --- a/src/main.c +++ b/src/main.c @@ -542,12 +542,26 @@ int main(int argc, char *argv[]) #ifdef HAVE_LIBIMOBILEDEVICE const char* userprefdir = userpref_get_config_dir(); - struct stat fst; - int userprefdir_created = 0; + memset(&fst, '\0', sizeof(struct stat)); if (stat(userprefdir, &fst) < 0) { - mkdir(userprefdir, 0775); - userprefdir_created = 1; + if (mkdir(userprefdir, 0775) < 0) { + usbmuxd_log(LL_FATAL, "Failed to create required directory '%s': %s\n", userprefdir, strerror(errno)); + res = -1; + goto terminate; + } + if (stat(userprefdir, &fst) < 0) { + usbmuxd_log(LL_FATAL, "stat() failed after creating directory '%s': %s\n", userprefdir, strerror(errno)); + res = -1; + goto terminate; + } + } + + // make sure permission bits are set correctly + if (fst.st_mode != 02775) { + if (chmod(userprefdir, 02775) < 0) { + usbmuxd_log(LL_WARNING, "chmod(%s, 02775) failed: %s", userprefdir, strerror(errno)); + } } #endif @@ -569,12 +583,10 @@ int main(int argc, char *argv[]) usbmuxd_log(LL_INFO, "Not dropping privileges to root"); } else { #ifdef HAVE_LIBIMOBILEDEVICE - if (userprefdir_created) { + /* make sure the non-privileged user has proper access to the config directory */ + if ((fst.st_uid != pw->pw_uid) || (fst.st_gid != pw->pw_gid)) { if (chown(userprefdir, pw->pw_uid, pw->pw_gid) < 0) { - usbmuxd_log(LL_WARNING, "chown(%s, %d, %d) failed", userprefdir, pw->pw_uid, pw->pw_gid); - } - if (chmod(userprefdir, 02775) < 0) { - usbmuxd_log(LL_WARNING, "chmod %s failed", userprefdir); + usbmuxd_log(LL_WARNING, "chown(%s, %d, %d) failed: %s", userprefdir, pw->pw_uid, pw->pw_gid, strerror(errno)); } } #endif From 9bbdf5ce88df0fe805554e68cd59a8a32d639e1f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 10 Dec 2013 20:14:41 +0100 Subject: [PATCH 33/70] client: add send_plist_pkt helper to remove code duplication --- src/client.c | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/client.c b/src/client.c index d9025919..e77e07ed 100644 --- a/src/client.c +++ b/src/client.c @@ -190,25 +190,32 @@ 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) +{ + 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); + free(xml); + } else { + usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__); + } + return res; +} + static int send_result(struct mux_client *client, uint32_t tag, uint32_t result) { int res = -1; #ifdef HAVE_PLIST if (client->proto_version == 1) { /* XML plist packet */ - char *xml = NULL; - uint32_t xmlsize = 0; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("Result")); plist_dict_insert_item(dict, "Number", plist_new_uint(result)); - plist_to_xml(dict, &xml, &xmlsize); - plist_free(dict); - if (xml) { - res = send_pkt(client, tag, MESSAGE_PLIST, xml, xmlsize); - free(xml); - } else { - usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__); - } + res = send_plist_pkt(client, tag, dict); + free(dict); } else #endif { @@ -247,8 +254,6 @@ static int notify_device_add(struct mux_client *client, struct device_info *dev) #ifdef HAVE_PLIST if (client->proto_version == 1) { /* XML plist packet */ - char *xml = NULL; - uint32_t xmlsize = 0; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("Attached")); plist_dict_insert_item(dict, "DeviceID", plist_new_uint(dev->id)); @@ -261,14 +266,8 @@ static int notify_device_add(struct mux_client *client, struct device_info *dev) plist_dict_insert_item(props, "ProductID", plist_new_uint(dev->pid)); plist_dict_insert_item(props, "SerialNumber", plist_new_string(dev->serial)); plist_dict_insert_item(dict, "Properties", props); - plist_to_xml(dict, &xml, &xmlsize); + res = send_plist_pkt(client, 0, dict); plist_free(dict); - if (xml) { - res = send_pkt(client, 0, MESSAGE_PLIST, xml, xmlsize); - free(xml); - } else { - usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__); - } } else #endif { @@ -291,19 +290,11 @@ static int notify_device_remove(struct mux_client *client, uint32_t device_id) #ifdef HAVE_PLIST if (client->proto_version == 1) { /* XML plist packet */ - char *xml = NULL; - uint32_t xmlsize = 0; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("Detached")); plist_dict_insert_item(dict, "DeviceID", plist_new_uint(device_id)); - plist_to_xml(dict, &xml, &xmlsize); + res = send_plist_pkt(client, 0, dict); plist_free(dict); - if (xml) { - res = send_pkt(client, 0, MESSAGE_PLIST, xml, xmlsize); - free(xml); - } else { - usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__); - } } else #endif { From 9fb10d3072d4a1ee4ff8b6d7b9cbcbfd8cbe8efb Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 10 Dec 2013 20:17:43 +0100 Subject: [PATCH 34/70] client: implemented "ListDevices" command --- src/client.c | 67 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/src/client.c b/src/client.c index e77e07ed..aa276cd4 100644 --- a/src/client.c +++ b/src/client.c @@ -248,24 +248,61 @@ int client_notify_connect(struct mux_client *client, enum usbmuxd_result result) return 0; } +#ifdef HAVE_PLIST +static plist_t create_device_attached_plist(struct device_info *dev) +{ + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "MessageType", plist_new_string("Attached")); + plist_dict_insert_item(dict, "DeviceID", plist_new_uint(dev->id)); + plist_t props = plist_new_dict(); + // TODO: get current usb speed + plist_dict_insert_item(props, "ConnectionSpeed", plist_new_uint(480000000)); + plist_dict_insert_item(props, "ConnectionType", plist_new_string("USB")); + plist_dict_insert_item(props, "DeviceID", plist_new_uint(dev->id)); + plist_dict_insert_item(props, "LocationID", plist_new_uint(dev->location)); + plist_dict_insert_item(props, "ProductID", plist_new_uint(dev->pid)); + plist_dict_insert_item(props, "SerialNumber", plist_new_string(dev->serial)); + plist_dict_insert_item(dict, "Properties", props); + return dict; +} + +static int send_device_list(struct mux_client *client, uint32_t tag) +{ + int res = -1; + plist_t dict = plist_new_dict(); + plist_t devices = plist_new_array(); + + int count = device_get_count(0); + if (count > 0) { + struct device_info *devs; + struct device_info *dev; + int i; + + devs = malloc(sizeof(struct device_info) * count); + count = device_get_list(0, devs); + dev = devs; + for (i = 0; i < count; i++) { + plist_t device = create_device_attached_plist(dev++); + if (device) { + plist_array_append_item(devices, device); + } + } + free(devs); + } + plist_dict_insert_item(dict, "DeviceList", devices); + res = send_plist_pkt(client, tag, dict); + plist_free(dict); + return res; +} +#endif + static int notify_device_add(struct mux_client *client, struct device_info *dev) { int res = -1; #ifdef HAVE_PLIST if (client->proto_version == 1) { /* XML plist packet */ - plist_t dict = plist_new_dict(); - plist_dict_insert_item(dict, "MessageType", plist_new_string("Attached")); - plist_dict_insert_item(dict, "DeviceID", plist_new_uint(dev->id)); - plist_t props = plist_new_dict(); - // TODO: get current usb speed - plist_dict_insert_item(props, "ConnectionSpeed", plist_new_uint(480000000)); - plist_dict_insert_item(props, "ConnectionType", plist_new_string("USB")); - plist_dict_insert_item(props, "DeviceID", plist_new_uint(dev->id)); - plist_dict_insert_item(props, "LocationID", plist_new_uint(dev->location)); - plist_dict_insert_item(props, "ProductID", plist_new_uint(dev->pid)); - plist_dict_insert_item(props, "SerialNumber", plist_new_string(dev->serial)); - plist_dict_insert_item(dict, "Properties", props); + plist_t dict = create_device_attached_plist(dev); res = send_plist_pkt(client, 0, dict); plist_free(dict); } else @@ -423,6 +460,12 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) client->state = CLIENT_CONNECTING1; } return 0; +#ifdef HAVE_PLIST + } else if (!strcmp(message, "ListDevices")) { + if (send_device_list(client, hdr->tag) < 0) + return -1; + return 0; +#endif } else { usbmuxd_log(LL_ERROR, "Unexpected command '%s' received!", message); free(message); From e12c28a1c0f8c9c9653a227a4874276bdc4a0f30 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 11 Dec 2013 00:35:02 +0100 Subject: [PATCH 35/70] fix compilation when compiling without plist support --- src/client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client.c b/src/client.c index aa276cd4..c8fb470a 100644 --- a/src/client.c +++ b/src/client.c @@ -190,6 +190,7 @@ static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtyp return hdr.length; } +#ifdef HAVE_PLIST static int send_plist_pkt(struct mux_client *client, uint32_t tag, plist_t plist) { int res = -1; @@ -204,6 +205,7 @@ static int send_plist_pkt(struct mux_client *client, uint32_t tag, plist_t plist } return res; } +#endif static int send_result(struct mux_client *client, uint32_t tag, uint32_t result) { From f9140eb3a421a8c7d031b70732166abdf570b2ac Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 11 Dec 2013 03:05:19 +0100 Subject: [PATCH 36/70] client: return proper error packet on client version mismatch --- src/client.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/client.c b/src/client.c index c8fb470a..ac5d08e9 100644 --- a/src/client.c +++ b/src/client.c @@ -42,11 +42,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "client.h" #include "device.h" -#ifdef HAVE_PLIST #define CMD_BUF_SIZE 1024 -#else -#define CMD_BUF_SIZE 256 -#endif #define REPLY_BUF_SIZE 1024 enum client_state { @@ -387,6 +383,17 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) return -1; } +#ifdef HAVE_PLIST + if((hdr->version != 0) && (hdr->version != 1)) { + usbmuxd_log(LL_INFO, "Client %d version mismatch: expected 0 or 1, got %d", client->fd, hdr->version); +#else + if(hdr->version != USBMUXD_PROTOCOL_VERSION) { + usbmuxd_log(LL_INFO, "Client %d version mismatch: expected %d, got %d", client->fd, USBMUXD_PROTOCOL_VERSION, hdr->version); +#endif + send_result(client, hdr->tag, RESULT_BADVERSION); + return 0; + } + struct usbmuxd_connect_request *ch; #ifdef HAVE_PLIST char *payload; @@ -557,16 +564,6 @@ static void process_recv(struct mux_client *client) did_read = 1; } struct usbmuxd_header *hdr = (void*)client->ib_buf; -#ifdef HAVE_PLIST - if((hdr->version != 0) && (hdr->version != 1)) { - usbmuxd_log(LL_INFO, "Client %d version mismatch: expected 0 or 1, got %d", client->fd, hdr->version); -#else - if(hdr->version != USBMUXD_PROTOCOL_VERSION) { - usbmuxd_log(LL_INFO, "Client %d version mismatch: expected %d, got %d", client->fd, USBMUXD_PROTOCOL_VERSION, hdr->version); -#endif - client_close(client); - return; - } if(hdr->length > client->ib_capacity) { usbmuxd_log(LL_INFO, "Client %d message is too long (%d bytes)", client->fd, hdr->length); client_close(client); From 61c30e8fa029a78375fb49db14875fd13379437a Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 13 Dec 2013 04:14:53 +0100 Subject: [PATCH 37/70] make libplist/protov1 support mandatory --- configure.ac | 24 +----------------------- src/client.c | 32 +++----------------------------- 2 files changed, 4 insertions(+), 52 deletions(-) diff --git a/configure.ac b/configure.ac index 30673041..9e113d71 100644 --- a/configure.ac +++ b/configure.ac @@ -17,31 +17,10 @@ AC_PROG_LIBTOOL # Checks for libraries. PKG_CHECK_MODULES(libusb, libusb-1.0 >= 1.0.3) -PKG_CHECK_MODULES(libplist, libplist >= 1.9, have_plist=yes, have_plist=no) +PKG_CHECK_MODULES(libplist, libplist >= 1.11) PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.1.6, 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])]) -AC_ARG_WITH([protov1], - [AS_HELP_STRING([--without-protov1], - [do not build with protocol v1 support (default is yes)])], - [with_protov1=no], - [with_protov1=yes]) - -if test "x$have_plist" = "xyes"; then - if test "x$with_protov1" != "xyes"; then - have_plist=no - echo "*** Note: Protocol V1 support has been disabled ***" - else - AC_DEFINE(HAVE_PLIST, 1, [Define if you have libplist support]) - AC_SUBST(libplist_CFLAGS) - AC_SUBST(libplist_LIBS) - fi -else - if test "x$with_protov1" == "xyes"; then - AC_MSG_ERROR([protocol V1 support requested but libplist could not be found]) - fi -fi - AC_ARG_WITH([preflight], [AS_HELP_STRING([--without-preflight], [do not build with preflight worker support (default is yes)])], @@ -112,7 +91,6 @@ Configuration for $PACKAGE $VERSION: ------------------------------------------- Install prefix: ...........: $prefix - Protocol v1 support: ......: $have_plist Preflight worker support ..: $have_limd Now type 'make' to build $PACKAGE $VERSION, diff --git a/src/client.c b/src/client.c index ac5d08e9..b81c11c3 100644 --- a/src/client.c +++ b/src/client.c @@ -33,9 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include -#ifdef HAVE_PLIST #include -#endif #include "log.h" #include "usb.h" @@ -186,7 +184,6 @@ static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtyp return hdr.length; } -#ifdef HAVE_PLIST static int send_plist_pkt(struct mux_client *client, uint32_t tag, plist_t plist) { int res = -1; @@ -201,12 +198,10 @@ static int send_plist_pkt(struct mux_client *client, uint32_t tag, plist_t plist } return res; } -#endif static int send_result(struct mux_client *client, uint32_t tag, uint32_t result) { int res = -1; -#ifdef HAVE_PLIST if (client->proto_version == 1) { /* XML plist packet */ plist_t dict = plist_new_dict(); @@ -214,9 +209,7 @@ static int send_result(struct mux_client *client, uint32_t tag, uint32_t result) plist_dict_insert_item(dict, "Number", plist_new_uint(result)); res = send_plist_pkt(client, tag, dict); free(dict); - } else -#endif - { + } else { /* binary packet */ res = send_pkt(client, tag, MESSAGE_RESULT, &result, sizeof(uint32_t)); } @@ -246,7 +239,6 @@ int client_notify_connect(struct mux_client *client, enum usbmuxd_result result) return 0; } -#ifdef HAVE_PLIST static plist_t create_device_attached_plist(struct device_info *dev) { plist_t dict = plist_new_dict(); @@ -292,20 +284,16 @@ static int send_device_list(struct mux_client *client, uint32_t tag) plist_free(dict); return res; } -#endif static int notify_device_add(struct mux_client *client, struct device_info *dev) { int res = -1; -#ifdef HAVE_PLIST if (client->proto_version == 1) { /* XML plist packet */ plist_t dict = create_device_attached_plist(dev); res = send_plist_pkt(client, 0, dict); plist_free(dict); - } else -#endif - { + } else { /* binary packet */ struct usbmuxd_device_record dmsg; memset(&dmsg, 0, sizeof(dmsg)); @@ -322,7 +310,6 @@ static int notify_device_add(struct mux_client *client, struct device_info *dev) static int notify_device_remove(struct mux_client *client, uint32_t device_id) { int res = -1; -#ifdef HAVE_PLIST if (client->proto_version == 1) { /* XML plist packet */ plist_t dict = plist_new_dict(); @@ -330,9 +317,7 @@ static int notify_device_remove(struct mux_client *client, uint32_t device_id) plist_dict_insert_item(dict, "DeviceID", plist_new_uint(device_id)); res = send_plist_pkt(client, 0, dict); plist_free(dict); - } else -#endif - { + } else { /* binary packet */ res = send_pkt(client, 0, MESSAGE_DEVICE_REMOVE, &device_id, sizeof(uint32_t)); } @@ -383,25 +368,17 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) return -1; } -#ifdef HAVE_PLIST if((hdr->version != 0) && (hdr->version != 1)) { usbmuxd_log(LL_INFO, "Client %d version mismatch: expected 0 or 1, got %d", client->fd, hdr->version); -#else - if(hdr->version != USBMUXD_PROTOCOL_VERSION) { - usbmuxd_log(LL_INFO, "Client %d version mismatch: expected %d, got %d", client->fd, USBMUXD_PROTOCOL_VERSION, hdr->version); -#endif send_result(client, hdr->tag, RESULT_BADVERSION); return 0; } struct usbmuxd_connect_request *ch; -#ifdef HAVE_PLIST char *payload; uint32_t payload_size; -#endif switch(hdr->message) { -#ifdef HAVE_PLIST case MESSAGE_PLIST: client->proto_version = 1; payload = (char*)(hdr) + sizeof(struct usbmuxd_header); @@ -469,12 +446,10 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) client->state = CLIENT_CONNECTING1; } return 0; -#ifdef HAVE_PLIST } else if (!strcmp(message, "ListDevices")) { if (send_device_list(client, hdr->tag) < 0) return -1; return 0; -#endif } else { usbmuxd_log(LL_ERROR, "Unexpected command '%s' received!", message); free(message); @@ -486,7 +461,6 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) } // should not be reached?! return -1; -#endif case MESSAGE_LISTEN: if(send_result(client, hdr->tag, 0) < 0) return -1; From 641bc48b8f7a65ab82899b4aa16c13c4b7259999 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 13 Dec 2013 04:35:44 +0100 Subject: [PATCH 38/70] add support for reading and writing config and pair record files --- configure.ac | 2 +- src/Makefile.am | 1 + src/conf.c | 499 ++++++++++++++++++++++++++++++++++++++++++++++++ src/conf.h | 40 ++++ src/main.c | 3 +- src/preflight.c | 11 +- src/utils.c | 144 ++++++++++++++ src/utils.h | 17 ++ 8 files changed, 709 insertions(+), 8 deletions(-) create mode 100644 src/conf.c create mode 100644 src/conf.h diff --git a/configure.ac b/configure.ac index 9e113d71..6737f6fd 100644 --- a/configure.ac +++ b/configure.ac @@ -57,7 +57,7 @@ AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_REALLOC -AC_CHECK_FUNCS([strcasecmp strdup strerror strndup]) +AC_CHECK_FUNCS([strcasecmp strdup strerror strndup stpcpy]) # Check for operating system AC_MSG_CHECKING([whether to enable WIN32 build settings]) diff --git a/src/Makefile.am b/src/Makefile.am index 883f1d84..38858c4f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,7 @@ usbmuxd_SOURCES = client.c client.h \ log.c log.h \ usb-linux.c usb.h \ utils.c utils.h \ + conf.c conf.h \ main.c usbmuxd_CFLAGS = $(AM_CFLAGS) usbmuxd_LDFLAGS = $(AM_LDFLAGS) diff --git a/src/conf.c b/src/conf.c new file mode 100644 index 00000000..780a7c49 --- /dev/null +++ b/src/conf.c @@ -0,0 +1,499 @@ +/* + usbmuxd - iPhone/iPod Touch USB multiplex server daemon + +Copyright (C) 2013 Nikias Bassen + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 or version 3. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include +#include +#include +#include + +#ifdef WIN32 +#include +#endif + +#include "conf.h" +#include "utils.h" +#include "log.h" + +#ifdef WIN32 +#define DIR_SEP '\\' +#define DIR_SEP_S "\\" +#else +#define DIR_SEP '/' +#define DIR_SEP_S "/" +#endif + +#define CONFIG_SYSTEM_BUID_KEY "SystemBUID" +#define CONFIG_HOST_ID_KEY "HostID" + +#define CONFIG_EXT ".plist" + +#ifdef WIN32 +#define CONFIG_DIR "Apple"DIR_SEP_S"Lockdown" +#else +#define CONFIG_DIR "lockdown" +#endif + +#define CONFIG_FILE "SystemConfiguration"CONFIG_EXT + +static char *__config_dir = NULL; + +#ifdef WIN32 +static char *config_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written) +{ + if (!unistr || (len <= 0)) return NULL; + char *outbuf = (char*)malloc(3*(len+1)); + int p = 0; + int i = 0; + + wchar_t wc; + + while (i < len) { + wc = unistr[i++]; + if (wc >= 0x800) { + outbuf[p++] = (char)(0xE0 + ((wc >> 12) & 0xF)); + outbuf[p++] = (char)(0x80 + ((wc >> 6) & 0x3F)); + outbuf[p++] = (char)(0x80 + (wc & 0x3F)); + } else if (wc >= 0x80) { + outbuf[p++] = (char)(0xC0 + ((wc >> 6) & 0x1F)); + outbuf[p++] = (char)(0x80 + (wc & 0x3F)); + } else { + outbuf[p++] = (char)(wc & 0x7F); + } + } + if (items_read) { + *items_read = i; + } + if (items_written) { + *items_written = p; + } + outbuf[p] = 0; + + return outbuf; +} +#endif + +const char *config_get_config_dir() +{ + char *base_config_dir = NULL; + + if (__config_dir) + return __config_dir; + +#ifdef WIN32 + wchar_t path[MAX_PATH+1]; + HRESULT hr; + LPITEMIDLIST pidl = NULL; + BOOL b = FALSE; + + hr = SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_APPDATA, &pidl); + if (hr == S_OK) { + b = SHGetPathFromIDListW (pidl, path); + if (b) { + base_config_dir = config_utf16_to_utf8 (path, wcslen(path), NULL, NULL); + CoTaskMemFree (pidl); + } + } +#else +#ifdef __APPLE__ + base_config_dir = strdup("/var/db"); +#else + base_config_dir = strdup("/var/lib"); +#endif +#endif + __config_dir = string_concat(base_config_dir, DIR_SEP_S, CONFIG_DIR, NULL); + + if (__config_dir) { + int i = strlen(__config_dir)-1; + while ((i > 0) && (__config_dir[i] == DIR_SEP)) { + __config_dir[i--] = '\0'; + } + } + + free(base_config_dir); + + usbmuxd_log(LL_DEBUG, "initialized config_dir to %s", __config_dir); + + return __config_dir; +} + +static int __mkdir(const char *dir, int mode) +{ +#ifdef WIN32 + return mkdir(dir); +#else + return mkdir(dir, mode); +#endif +} + +static int mkdir_with_parents(const char *dir, int mode) +{ + if (!dir) return -1; + if (__mkdir(dir, mode) == 0) { + return 0; + } else { + if (errno == EEXIST) return 0; + } + int res; + char *parent = strdup(dir); + char* parentdir = dirname(parent); + if (parentdir) { + res = mkdir_with_parents(parentdir, mode); + } else { + res = -1; + } + free(parent); + return res; +} + +/** + * Creates a freedesktop compatible configuration directory. + */ +static void config_create_config_dir(void) +{ + const char *config_path = config_get_config_dir(); + struct stat st; + if (stat(config_path, &st) != 0) { + mkdir_with_parents(config_path, 0755); + } +} + +static int get_rand(int min, int max) +{ + int retval = (rand() % (max - min)) + min; + return retval; +} + +static char *config_generate_uuid(int idx) +{ + char *uuid = (char *) malloc(sizeof(char) * 37); + const char *chars = "ABCDEF0123456789"; + srand(time(NULL) - idx); + int i = 0; + + for (i = 0; i < 36; i++) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + uuid[i] = '-'; + continue; + } else { + uuid[i] = chars[get_rand(0, 16)]; + } + } + /* make it a real string */ + uuid[36] = '\0'; + return uuid; +} + +/** + * Generates a valid BUID for this system (which is actually a UUID). + * + * @return A null terminated string containing a valid BUID. + */ +static char *config_generate_system_buid() +{ + return config_generate_uuid(1); +} + +static int internal_set_value(const char *config_file, const char *key, plist_t value) +{ + if (!config_file) + return 0; + + /* read file into plist */ + plist_t config = NULL; + + plist_read_from_filename(&config, config_file); + if (!config) { + config = plist_new_dict(); + plist_dict_insert_item(config, key, value); + } else { + plist_t n = plist_dict_get_item(config, key); + if (n) { + plist_dict_remove_item(config, key); + } + plist_dict_insert_item(config, key, value); + remove(config_file); + } + + /* store in config file */ + 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); + if (value_string) + free(value_string); + } else { + usbmuxd_log(LL_DEBUG, "setting key %s in config_file %s", key, config_file); + } + + plist_write_to_filename(config, config_file, PLIST_FORMAT_XML); + + plist_free(config); + + return 1; +} + +static int config_set_value(const char *key, plist_t value) +{ + const char *config_path = NULL; + char *config_file = NULL; + + /* Make sure config directory exists */ + config_create_config_dir(); + + config_path = config_get_config_dir(); + config_file = string_concat(config_path, DIR_SEP_S, CONFIG_FILE, NULL); + + int result = internal_set_value(config_file, key, value); + + free(config_file); + + return result; +} + +static int internal_get_value(const char* config_file, const char *key, plist_t *value) +{ + *value = NULL; + + /* 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); + plist_t n = plist_dict_get_item(config, key); + if (n) { + *value = plist_copy(n); + plist_free(n); + n = NULL; + } + } + plist_free(config); + + return 1; +} + +static int config_get_value(const char *key, plist_t *value) +{ + const char *config_path = NULL; + char *config_file = NULL; + + config_path = config_get_config_dir(); + config_file = string_concat(config_path, DIR_SEP_S, CONFIG_FILE, NULL); + + int result = internal_get_value(config_file, key, value); + + free(config_file); + + return result; +} + +/** + * Store SystemBUID in config file. + * + * @param system_buid A null terminated string containing a valid SystemBUID. + */ +static int config_set_system_buid(const char *system_buid) +{ + return config_set_value(CONFIG_SYSTEM_BUID_KEY, plist_new_string(system_buid)); +} + +/** + * Reads the BUID from a previously generated configuration file. + * + * @param system_buid pointer to a variable that will be set to point to a + * newly allocated string containing the BUID. + * + * @note It is the responsibility of the calling function to free the returned system_buid + */ +void config_get_system_buid(char **system_buid) +{ + plist_t value = NULL; + + config_get_value(CONFIG_SYSTEM_BUID_KEY, &value); + + 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); + } + + if (value) + plist_free(value); + + if (!*system_buid) { + /* no config, generate system_buid */ + usbmuxd_log(LL_DEBUG, "no previous %s found", CONFIG_SYSTEM_BUID_KEY); + *system_buid = config_generate_system_buid(); + config_set_system_buid(*system_buid); + } + + usbmuxd_log(LL_DEBUG, "using %s as %s", *system_buid, CONFIG_SYSTEM_BUID_KEY); +} + +/** + * Store a pairing record for the given device identifier. + * + * @param udid device identifier + * @param record_data buffer containing a pairing record + * @param record_size size of buffer passed in record_data + * + * @return 0 on success or a negative errno otherwise. + */ +int config_set_device_record(const char *udid, char* record_data, uint64_t record_size) +{ + int res = 0; + + if (!udid || record_data || record_size < 8) + return -EINVAL; + + plist_t plist = NULL; + if (memcmp(record_data, "bplist00", 8) == 0) { + plist_from_bin(record_data, record_size, &plist); + } else { + plist_from_xml(record_data, record_size, &plist); + } + + if (!plist || plist_get_node_type(plist) != PLIST_DICT) { + if (plist) + plist_free(plist); + return -EINVAL; + } + + /* ensure config directory exists */ + config_create_config_dir(); + + /* build file path */ + const char *config_path = config_get_config_dir(); + char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL); + + 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)); + res = -ENOENT; + } + free(device_record_file); + if (plist) + plist_free(plist); + + return res; +} + +/** + * Retrieve a pairing record for the given device identifier + * + * @param udid device identifier + * @param record_data pointer to a variable that will be set to point to a + * newly allocated buffer holding the pairing record + * @param record_size pointer to a variable that will be set to the size + * of the buffer given in record_data. + * + * @return 0 on success or a negative errno otherwise. + */ +int config_get_device_record(const char *udid, char **record_data, uint64_t *record_size) +{ + int res = 0; + + /* ensure config directory exists */ + config_create_config_dir(); + + /* build file path */ + const char *config_path = config_get_config_dir(); + char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL); + + /* 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)); + res = -ENOENT; + } + free(device_record_file); + + return res; +} + +/** + * Remove the pairing record stored for a device from this host. + * + * @param udid The udid of the device + * + * @return 0 on success or a negative errno otherwise. + */ +int config_remove_device_record(const char *udid) +{ + int res = 0; + + /* build file path */ + const char *config_path = config_get_config_dir(); + char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL); + + /* remove file */ + if (remove(device_record_file) != 0) { + res = -errno; + usbmuxd_log(LL_DEBUG, "could not remove %s: %s", device_record_file, strerror(errno)); + } + + free(device_record_file); + + return res; +} + +static int config_device_record_get_value(const char *udid, const char *key, plist_t *value) +{ + const char *config_path = NULL; + char *config_file = NULL; + + config_path = config_get_config_dir(); + config_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL); + + int result = internal_get_value(config_file, key, value); + + free(config_file); + + return result; +} + +void config_device_record_get_host_id(const char *udid, char **host_id) +{ + plist_t value = NULL; + + config_device_record_get_value(udid, CONFIG_HOST_ID_KEY, &value); + + if (value && (plist_get_node_type(value) == PLIST_STRING)) { + plist_get_string_val(value, host_id); + } + + if (value) + plist_free(value); + + if (!*host_id) { + usbmuxd_log(LL_ERROR, "%s: ERROR couldn't get HostID from pairing record for udid %s\n", __func__, udid); + } +} diff --git a/src/conf.h b/src/conf.h new file mode 100644 index 00000000..a1041854 --- /dev/null +++ b/src/conf.h @@ -0,0 +1,40 @@ +/* + usbmuxd - iPhone/iPod Touch USB multiplex server daemon + +Copyright (C) 2013 Nikias Bassen + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 or version 3. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef __CONF_H__ +#define __CONF_H__ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +const char *config_get_config_dir(); + +void config_get_system_buid(char **system_buid); + +int config_get_device_record(const char *udid, char **record_data, uint64_t *record_size); +int config_set_device_record(const char *udid, char* record_data, uint64_t record_size); +int config_remove_device_record(const char *udid); + +void config_device_record_get_host_id(const char *udid, char **host_id); + +#endif diff --git a/src/main.c b/src/main.c index 033c8e47..d0e60225 100644 --- a/src/main.c +++ b/src/main.c @@ -46,6 +46,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "usb.h" #include "device.h" #include "client.h" +#include "conf.h" #ifdef ANDROID static const char *socket_path = "/data/local/tmp/usbmuxd"; @@ -541,7 +542,7 @@ int main(int argc, char *argv[]) goto terminate; #ifdef HAVE_LIBIMOBILEDEVICE - const char* userprefdir = userpref_get_config_dir(); + const char* userprefdir = config_get_config_dir(); struct stat fst; memset(&fst, '\0', sizeof(struct stat)); if (stat(userprefdir, &fst) < 0) { diff --git a/src/preflight.c b/src/preflight.c index def6a827..283c6d9c 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "preflight.h" #include "client.h" +#include "conf.h" #include "log.h" #ifdef HAVE_LIBIMOBILEDEVICE @@ -55,12 +56,10 @@ struct cb_data { int is_device_connected; }; -extern uint16_t userpref_remove_device_record(const char* udid); - static void lockdownd_set_untrusted_host_buid(lockdownd_client_t lockdown) { char* system_buid = NULL; - userpref_get_system_buid(&system_buid); + config_get_system_buid(&system_buid); usbmuxd_log(LL_DEBUG, "%s: Setting UntrustedHostBUID to %s", __func__, system_buid); lockdownd_set_value(lockdown, NULL, "UntrustedHostBUID", plist_new_string(system_buid)); free(system_buid); @@ -162,7 +161,7 @@ static void* preflight_worker_handle_device_add(void* userdata) int is_device_paired = 0; char *host_id = NULL; - userpref_device_record_get_host_id(dev->udid, &host_id); + config_device_record_get_host_id(dev->udid, &host_id); lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); free(host_id); if (lerr == LOCKDOWN_E_SUCCESS) { @@ -179,7 +178,7 @@ static void* preflight_worker_handle_device_add(void* userdata) break; case LOCKDOWN_E_SSL_ERROR: usbmuxd_log(LL_ERROR, "%s: The stored pair record for device %s is invalid. Removing.", __func__, _dev->udid); - if (userpref_remove_device_record(_dev->udid) == 0) { + if (config_remove_device_record(_dev->udid) == 0) { lockdownd_client_free(lockdown); lockdown = NULL; goto retry; @@ -293,7 +292,7 @@ static void* preflight_worker_handle_device_add(void* userdata) } host_id = NULL; - userpref_device_record_get_host_id(dev->udid, &host_id); + config_device_record_get_host_id(dev->udid, &host_id); lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); free(host_id); if (lerr != LOCKDOWN_E_SUCCESS) { diff --git a/src/utils.c b/src/utils.c index ceef5357..475a9219 100644 --- a/src/utils.c +++ b/src/utils.c @@ -3,6 +3,7 @@ Copyright (C) 2009 Hector Martin "marcan" Copyright (C) 2009 Nikias Bassen +Copyright (c) 2013 Federico Mena Quintero This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -27,6 +28,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include + #include "utils.h" #include "log.h" @@ -118,3 +121,144 @@ int collection_count(struct collection *col) } return cnt; } + +#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; +} + +void 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; + } + + fseek(f, 0, SEEK_END); + size = ftell(f); + rewind(f); + + if (size == 0) { + fclose(f); + return; + } + + *buffer = (char*)malloc(sizeof(char)*(size+1)); + if (fread(*buffer, sizeof(char), size, f) != size) { + usbmuxd_log(LL_ERROR, "%s: ERROR: couldn't read %d bytes from %s\n", __func__, (int)size, filename); + } + fclose(f); + + *length = size; +} + +void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length) +{ + FILE *f; + + f = fopen(filename, "wb"); + if (f) { + fwrite(buffer, sizeof(char), length, f); + fclose(f); + } +} + +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; + + buffer_write_to_filename(filename, buffer, length); + + free(buffer); + + return 1; +} diff --git a/src/utils.h b/src/utils.h index 69a4259e..730fbad0 100644 --- a/src/utils.h +++ b/src/utils.h @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #define __UTILS_H__ #include +#include enum fdowner { FD_LISTEN, @@ -69,4 +70,20 @@ void collection_free(struct collection *col); } \ } while(0); +#ifndef HAVE_STPCPY +char *stpcpy(char * s1, const char * s2); +#endif +char *string_concat(const char *str, ...); + +void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length); +void 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); + #endif From 007e2d249f8887eaf39b0dcb949aea9fe86d8fd5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 13 Dec 2013 04:36:35 +0100 Subject: [PATCH 39/70] client: implemented ReadBUID, ReadPairRecord, SavePairRecord, and DeletePairRecord commonds --- src/client.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/client.c b/src/client.c index b81c11c3..fdbea25c 100644 --- a/src/client.c +++ b/src/client.c @@ -39,6 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "usb.h" #include "client.h" #include "device.h" +#include "conf.h" #define CMD_BUF_SIZE 1024 #define REPLY_BUF_SIZE 1024 @@ -285,6 +286,44 @@ static int send_device_list(struct mux_client *client, uint32_t tag) return res; } +static int send_system_buid(struct mux_client *client, uint32_t tag) +{ + int res = -1; + char* buid = NULL; + + config_get_system_buid(&buid); + + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "BUID", plist_new_string(buid)); + res = send_plist_pkt(client, tag, dict); + plist_free(dict); + return res; +} + +static int send_pair_record(struct mux_client *client, uint32_t tag, const char* record_id) +{ + int res = -1; + char* record_data = NULL; + uint64_t record_size = 0; + + if (!record_id) { + return send_result(client, tag, EINVAL); + } + + config_get_device_record(record_id, &record_data, &record_size); + + if (record_data) { + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "PairRecordData", plist_new_data(record_data, record_size)); + free(record_data); + res = send_plist_pkt(client, tag, dict); + plist_free(dict); + } else { + res = send_result(client, tag, ENOENT); + } + return res; +} + static int notify_device_add(struct mux_client *client, struct device_info *dev) { int res = -1; @@ -355,6 +394,18 @@ static int start_listen(struct mux_client *client) return count; } +static char* plist_dict_get_string_val(plist_t dict, const char* key) +{ + if (!dict || plist_get_node_type(dict) != PLIST_DICT) + return NULL; + plist_t item = plist_dict_get_item(dict, key); + if (!item || plist_get_node_type(item) != PLIST_STRING) + return NULL; + char *str = NULL; + plist_get_string_val(item, &str); + return str; +} + static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) { int res; @@ -450,6 +501,62 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) if (send_device_list(client, hdr->tag) < 0) return -1; return 0; + } else if (!strcmp(message, "ReadBUID")) { + if (send_system_buid(client, hdr->tag) < 0) + return -1; + return 0; + } else if (!strcmp(message, "ReadPairRecord")) { + free(message); + char* record_id = plist_dict_get_string_val(dict, "PairRecordID"); + plist_free(dict); + + res = send_pair_record(client, hdr->tag, record_id); + if (record_id) + free(record_id); + if (res < 0) + return -1; + return 0; + } else if (!strcmp(message, "SavePairRecord")) { + uint32_t rval = RESULT_OK; + free(message); + char* record_id = plist_dict_get_string_val(dict, "PairRecordID"); + char* record_data = NULL; + uint64_t record_size = 0; + plist_t rdata = plist_dict_get_item(dict, "PairRecordData"); + if (rdata && plist_get_node_type(rdata) == PLIST_DATA) { + plist_get_data_val(rdata, &record_data, &record_size); + } + plist_free(dict); + + if (record_id && record_data) { + res = config_set_device_record(record_id, record_data, record_size); + if (res < 0) { + rval = -res; + } + free(record_id); + } else { + rval = EINVAL; + } + if (send_result(client, hdr->tag, rval) < 0) + return -1; + return 0; + } else if (!strcmp(message, "DeletePairRecord")) { + uint32_t rval = RESULT_OK; + free(message); + char* record_id = plist_dict_get_string_val(dict, "PairRecordID"); + plist_free(dict); + if (record_id) { + res = config_remove_device_record(record_id); + if (res < 0) { + rval = -res; + } + free(record_id); + } else { + rval = EINVAL; + } + if (send_result(client, hdr->tag, rval) < 0) + return -1; + return 0; } else { usbmuxd_log(LL_ERROR, "Unexpected command '%s' received!", message); free(message); From d6c96a387ded46872745412d8829ecede3a65677 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 23 Dec 2013 21:46:20 +0100 Subject: [PATCH 40/70] enlarge input+output buffer sizes. --- src/client.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/client.c b/src/client.c index fdbea25c..ba6a3028 100644 --- a/src/client.c +++ b/src/client.c @@ -41,8 +41,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "device.h" #include "conf.h" -#define CMD_BUF_SIZE 1024 -#define REPLY_BUF_SIZE 1024 +#define CMD_BUF_SIZE 0x10000 +#define REPLY_BUF_SIZE 0x10000 enum client_state { CLIENT_COMMAND, // waiting for command @@ -172,10 +172,14 @@ static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtyp 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); - if((client->ob_capacity - client->ob_size) < hdr.length) { - usbmuxd_log(LL_ERROR, "Client %d output buffer full (%d bytes) while sending message %d (%d bytes)", client->fd, client->ob_capacity, hdr.message, hdr.length); - client_close(client); - return -1; + + uint32_t available = client->ob_capacity - client->ob_size; + /* the output buffer _should_ be large enough, but just in case */ + if(available < hdr.length) { + uint32_t needed_buffer = hdr.length; + usbmuxd_log(LL_DEBUG, "Enlarging client %d output buffer %d -> %d", client->fd, client->ob_capacity, needed_buffer); + client->ob_buf = realloc(client->ob_buf, needed_buffer); + client->ob_capacity = needed_buffer; } memcpy(client->ob_buf + client->ob_size, &hdr, sizeof(hdr)); if(payload && payload_length) @@ -376,13 +380,6 @@ static int start_listen(struct mux_client *client) devs = malloc(sizeof(struct device_info) * count); count = device_get_list(0, devs); - // going to need a larger buffer for many devices - uint32_t needed_buffer = count * (sizeof(struct usbmuxd_device_record) + sizeof(struct usbmuxd_header)) + REPLY_BUF_SIZE; - if(client->ob_capacity < needed_buffer) { - usbmuxd_log(LL_DEBUG, "Enlarging client %d reply buffer %d -> %d to make space for device notifications", client->fd, client->ob_capacity, needed_buffer); - client->ob_buf = realloc(client->ob_buf, needed_buffer); - client->ob_capacity = needed_buffer; - } dev = devs; for(i=0; i Date: Mon, 23 Dec 2013 22:01:53 +0100 Subject: [PATCH 41/70] increase number of open file descriptors When a large number of devices are used, the number of open file descriptors can reach the default system limit. Upon startup we now raise it to a much higher value to give more 'space'. --- src/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.c b/src/main.c index d0e60225..9b58e68f 100644 --- a/src/main.c +++ b/src/main.c @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include #include #include #include @@ -536,6 +537,12 @@ int main(int argc, char *argv[]) goto terminate; } + // set number of file descriptors to higher value + struct rlimit rlim; + getrlimit(RLIMIT_NOFILE, &rlim); + rlim.rlim_max = 65536; + setrlimit(RLIMIT_NOFILE, (const struct rlimit*)&rlim); + usbmuxd_log(LL_INFO, "Creating socket"); res = listenfd = create_socket(); if(listenfd < 0) From 6bbb49731e45969bb05d43258b66aa4620f0722d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Dec 2013 01:55:08 +0100 Subject: [PATCH 42/70] preflight: replace idevice_event_* with thread safe implementation idevice_event_subscribe() calls usbmuxd_subscribe() which will start a thread waiting for device add/remove events. But this implementation is not able to handle more than one "subscription". However the preflight worker will start a thread for _each_ device resulting in a really messed up situation if more than one device is attached at the same time. This fix will use usbmuxd's internal device_remove function calling a preflight callback to make this implementation thread safe. --- src/device.c | 17 ++++++++++++++++- src/device.h | 1 + src/preflight.c | 24 +++++++++++++----------- src/preflight.h | 1 + 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/device.c b/src/device.c index 2d10e1d1..8bf5df5d 100644 --- a/src/device.c +++ b/src/device.c @@ -112,6 +112,7 @@ struct mux_device uint16_t next_sport; unsigned char *pktbuf; uint32_t pktlen; + void *preflight_cb_data; }; static struct collection device_list; @@ -700,6 +701,7 @@ int device_add(struct usb_device *usbdev) dev->next_sport = 1; dev->pktbuf = malloc(DEV_MRU); dev->pktlen = 0; + dev->preflight_cb_data = NULL; struct version_header vh; vh.major = htonl(1); vh.minor = htonl(0); @@ -726,6 +728,9 @@ void device_remove(struct usb_device *usbdev) client_device_remove(dev->id); collection_free(&dev->connections); } + if (dev->preflight_cb_data) { + preflight_device_remove_cb(dev->preflight_cb_data); + } collection_remove(&device_list, dev); free(dev->pktbuf); free(dev); @@ -742,7 +747,17 @@ void device_set_visible(int device_id) dev->visible = 1; break; } - } ENDFOREACH + } ENDFOREACH +} + +void device_set_preflight_cb_data(int device_id, void* data) +{ + FOREACH(struct mux_device *dev, &device_list) { + if(dev->id == device_id) { + dev->preflight_cb_data = data; + break; + } + } ENDFOREACH } int device_get_count(int include_hidden) diff --git a/src/device.h b/src/device.h index f8ff590d..bd81699e 100644 --- a/src/device.h +++ b/src/device.h @@ -41,6 +41,7 @@ void device_client_process(int device_id, struct mux_client *client, short event void device_abort_connect(int device_id, struct mux_client *client); void device_set_visible(int device_id); +void device_set_preflight_cb_data(int device_id, void* data); int device_get_count(int include_hidden); int device_get_list(int include_hidden, struct device_info *p); diff --git a/src/preflight.c b/src/preflight.c index 283c6d9c..b011344f 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -30,11 +30,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include +#ifdef HAVE_LIBIMOBILEDEVICE #include #include #include +#endif #include "preflight.h" +#include "device.h" #include "client.h" #include "conf.h" #include "log.h" @@ -65,15 +68,12 @@ static void lockdownd_set_untrusted_host_buid(lockdownd_client_t lockdown) free(system_buid); } -static void idevice_callback(const idevice_event_t* event, void* userdata) +void preflight_device_remove_cb(void *data) { - struct cb_data *cbdata = (struct cb_data*)userdata; - idevice_t dev = cbdata->dev; - struct idevice_private *_dev = (struct idevice_private*)dev; - - if (event->event == IDEVICE_DEVICE_REMOVE && !strcmp(_dev->udid, event->udid)) { - cbdata->is_device_connected = 0; - } + if (!data) + return; + struct cb_data *cbdata = (struct cb_data*)data; + cbdata->is_device_connected = 0; } static void np_callback(const char* notification, void* userdata) @@ -246,7 +246,7 @@ static void* preflight_worker_handle_device_add(void* userdata) cbdata.is_device_connected = 1; np_set_notify_callback(np, np_callback, (void*)&cbdata); - idevice_event_subscribe(idevice_callback, (void*)&cbdata); + device_set_preflight_cb_data(info->id, (void*)&cbdata); const char* spec[] = { "com.apple.mobile.lockdown.request_pair", @@ -267,8 +267,6 @@ static void* preflight_worker_handle_device_add(void* userdata) } usbmuxd_log(LL_INFO, "%s: Finished waiting for notification from device %s, is_device_connected %d", __func__, _dev->udid, cbdata.is_device_connected); - idevice_event_unsubscribe(); - if (cbdata.np) { np_client_free(cbdata.np); } @@ -326,6 +324,10 @@ static void* preflight_worker_handle_device_add(void* userdata) return NULL; } +#else +void preflight_device_remove_cb(void *data) +{ +} #endif void preflight_worker_device_add(struct device_info* info) diff --git a/src/preflight.h b/src/preflight.h index 62349d19..4c8aa60e 100644 --- a/src/preflight.h +++ b/src/preflight.h @@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA extern void userpref_get_system_buid(char **systembuid); extern void userpref_device_record_get_host_id(const char *udid, char **host_id); +void preflight_device_remove_cb(void *data); void preflight_worker_device_add(struct device_info* info); #endif From 4c5fdcde0e4f1d6c01a8922dab3ab767a881d96b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Dec 2013 02:32:35 +0100 Subject: [PATCH 43/70] client: plug several memory leaks --- src/client.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/client.c b/src/client.c index ba6a3028..ed383b7e 100644 --- a/src/client.c +++ b/src/client.c @@ -213,7 +213,7 @@ static int send_result(struct mux_client *client, uint32_t tag, uint32_t result) plist_dict_insert_item(dict, "MessageType", plist_new_string("Result")); plist_dict_insert_item(dict, "Number", plist_new_uint(result)); res = send_plist_pkt(client, tag, dict); - free(dict); + plist_free(dict); } else { /* binary packet */ res = send_pkt(client, tag, MESSAGE_RESULT, &result, sizeof(uint32_t)); @@ -482,6 +482,7 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) val = 0; plist_get_uint_val(node, &val); 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)); res = device_start_connect(device_id, ntohs(portnum), client); @@ -495,10 +496,14 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) } return 0; } else if (!strcmp(message, "ListDevices")) { + free(message); + plist_free(dict); if (send_device_list(client, hdr->tag) < 0) return -1; return 0; } else if (!strcmp(message, "ReadBUID")) { + free(message); + plist_free(dict); if (send_system_buid(client, hdr->tag) < 0) return -1; return 0; From 94e6bd0424f950f48f2c9b18a5365c088126a1c2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Dec 2013 12:47:26 +0100 Subject: [PATCH 44/70] preflight: check for device record before trying to read host id --- src/conf.c | 32 +++++++++++++++++++++++++++++++- src/conf.h | 1 + src/preflight.c | 25 +++++++++++++++---------- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/conf.c b/src/conf.c index 780a7c49..2291671b 100644 --- a/src/conf.c +++ b/src/conf.c @@ -325,6 +325,35 @@ static int config_set_system_buid(const char *system_buid) return config_set_value(CONFIG_SYSTEM_BUID_KEY, plist_new_string(system_buid)); } +/** + * Determines whether a pairing record is present for the given device. + * + * @param udid The device UDID as given by the device. + * + * @return 1 if there's a pairing record for the given udid or 0 otherwise. + */ +int config_has_device_record(const char *udid) +{ + int res = 0; + if (!udid) return 0; + + /* ensure config directory exists */ + config_create_config_dir(); + + /* build file path */ + const char *config_path = config_get_config_dir(); + char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL); + + struct stat st; + + if ((stat(device_record_file, &st) == 0) && S_ISREG(st.st_mode)) + res = 1; + + free(device_record_file); + + return res; +} + /** * Reads the BUID from a previously generated configuration file. * @@ -430,7 +459,8 @@ int config_get_device_record(const char *udid, char **record_data, uint64_t *rec char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL); /* read file */ - buffer_read_from_filename(device_record_file, record_data, record_size); if (!*record_data) { + 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)); res = -ENOENT; } diff --git a/src/conf.h b/src/conf.h index a1041854..fd746072 100644 --- a/src/conf.h +++ b/src/conf.h @@ -31,6 +31,7 @@ const char *config_get_config_dir(); void config_get_system_buid(char **system_buid); +int config_has_device_record(const char *udid); int config_get_device_record(const char *udid, char **record_data, uint64_t *record_size); int config_set_device_record(const char *udid, char* record_data, uint64_t record_size); int config_remove_device_record(const char *udid); diff --git a/src/preflight.c b/src/preflight.c index b011344f..5198d8c5 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -161,17 +161,22 @@ static void* preflight_worker_handle_device_add(void* userdata) int is_device_paired = 0; char *host_id = NULL; - config_device_record_get_host_id(dev->udid, &host_id); - lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); - free(host_id); - if (lerr == LOCKDOWN_E_SUCCESS) { - usbmuxd_log(LL_INFO, "%s: StartSession success for device %s", __func__, _dev->udid); - usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); - client_device_add(info); - goto leave; - } + if (config_has_device_record(dev->udid)) { + config_device_record_get_host_id(dev->udid, &host_id); + lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); + if (host_id) + free(host_id); + if (lerr == LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_INFO, "%s: StartSession success for device %s", __func__, _dev->udid); + usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid); + client_device_add(info); + goto leave; + } - usbmuxd_log(LL_INFO, "%s: StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr); + usbmuxd_log(LL_INFO, "%s: StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr); + } else { + lerr = LOCKDOWN_E_INVALID_HOST_ID; + } switch (lerr) { case LOCKDOWN_E_INVALID_HOST_ID: usbmuxd_log(LL_INFO, "%s: Device %s is not paired with this host.", __func__, _dev->udid); From 5c27fcc7e52ed914181c1935c3af914ea353e265 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 7 Jan 2014 15:32:43 +0100 Subject: [PATCH 45/70] conf: fix wrong check for parameter that made SavePairRecord always fail --- src/conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conf.c b/src/conf.c index 2291671b..ef371a37 100644 --- a/src/conf.c +++ b/src/conf.c @@ -399,7 +399,7 @@ int config_set_device_record(const char *udid, char* record_data, uint64_t recor { int res = 0; - if (!udid || record_data || record_size < 8) + if (!udid || !record_data || record_size < 8) return -EINVAL; plist_t plist = NULL; From 312af2af60299e7ff2d4c8804b718597f1b0b279 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Jan 2014 09:38:19 +0100 Subject: [PATCH 46/70] client: fix 64-bit crash in process_send due to signed/unsigned foo --- src/client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client.c b/src/client.c index ed383b7e..d4719c3b 100644 --- a/src/client.c +++ b/src/client.c @@ -599,7 +599,7 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) static void process_send(struct mux_client *client) { - uint32_t res; + int res; if(!client->ob_size) { usbmuxd_log(LL_WARNING, "Client %d OUT process but nothing to send?", client->fd); client->events &= ~POLLOUT; @@ -611,7 +611,7 @@ static void process_send(struct mux_client *client) client_close(client); return; } - if(res == client->ob_size) { + if((uint32_t)res == client->ob_size) { client->ob_size = 0; client->events &= ~POLLOUT; if(client->state == CLIENT_CONNECTING2) { From f8d68fd91ef29651a50fa44127dd070ad0a4ef02 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Jan 2014 11:21:16 +0100 Subject: [PATCH 47/70] utils: collection_add don't double capacity but instead increase by a fixed amount --- src/utils.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/utils.c b/src/utils.c index 475a9219..245894e6 100644 --- a/src/utils.c +++ b/src/utils.c @@ -71,11 +71,13 @@ void fdlist_reset(struct fdlist *list) list->count = 0; } +#define CAPACITY_STEP 8 + void collection_init(struct collection *col) { - col->list = malloc(sizeof(void *)); - memset(col->list, 0, sizeof(void *)); - col->capacity = 1; + 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) @@ -94,10 +96,10 @@ void collection_add(struct collection *col, void *element) return; } } - col->list = realloc(col->list, sizeof(void*) * col->capacity * 2); - memset(&col->list[col->capacity], 0, sizeof(void *) * col->capacity); + 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 *= 2; + col->capacity += CAPACITY_STEP; } void collection_remove(struct collection *col, void *element) From 2f0d8b6d04bd0840e5983d0af07087dcdd540ced Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Jan 2014 11:31:08 +0100 Subject: [PATCH 48/70] device: make device_list access thread safe --- src/device.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/device.c b/src/device.c index 8bf5df5d..605d6131 100644 --- a/src/device.c +++ b/src/device.c @@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include #include "device.h" #include "client.h" #include "preflight.h" @@ -116,6 +117,7 @@ struct mux_device }; static struct collection device_list; +pthread_mutex_t device_list_mutex; static uint64_t mstime64(void) { @@ -128,6 +130,7 @@ static int get_next_device_id(void) { while(1) { int ok = 1; + pthread_mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == next_device_id) { next_device_id++; @@ -135,6 +138,7 @@ static int get_next_device_id(void) break; } } ENDFOREACH + pthread_mutex_unlock(&device_list_mutex); if(ok) return next_device_id++; } @@ -283,12 +287,14 @@ static void connection_teardown(struct mux_connection *conn) int device_start_connect(int device_id, uint16_t dport, struct mux_client *client) { struct mux_device *dev = NULL; + pthread_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); if(!dev) { usbmuxd_log(LL_WARNING, "Attempted to connect to nonexistent device %d", device_id); return -RESULT_BADDEV; @@ -376,6 +382,7 @@ static void update_connection(struct mux_connection *conn) void device_client_process(int device_id, struct mux_client *client, short events) { struct mux_connection *conn = NULL; + pthread_mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == device_id) { FOREACH(struct mux_connection *lconn, &dev->connections) { @@ -387,6 +394,7 @@ void device_client_process(int device_id, struct mux_client *client, short event break; } } ENDFOREACH + pthread_mutex_unlock(&device_list_mutex); if(!conn) { usbmuxd_log(LL_WARNING, "Could not find connection for device %d client %p", device_id, client); @@ -444,18 +452,22 @@ static void connection_device_input(struct mux_connection *conn, unsigned char * void device_abort_connect(int device_id, struct mux_client *client) { + pthread_mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == device_id) { FOREACH(struct mux_connection *conn, &dev->connections) { if(conn->client == client) { connection_teardown(conn); + pthread_mutex_unlock(&device_list_mutex); return; } } ENDFOREACH + pthread_mutex_unlock(&device_list_mutex); usbmuxd_log(LL_WARNING, "Attempted to abort for nonexistent connection for device %d", device_id); return; } } ENDFOREACH + pthread_mutex_unlock(&device_list_mutex); usbmuxd_log(LL_WARNING, "Attempted to abort connection for nonexistent device %d", device_id); } @@ -469,7 +481,9 @@ static void device_version_input(struct mux_device *dev, struct version_header * vh->minor = ntohl(vh->minor); if(vh->major != 1 || vh->minor != 0) { usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d\n", dev->id, vh->major, vh->minor); + pthread_mutex_lock(&device_list_mutex); collection_remove(&device_list, dev); + pthread_mutex_unlock(&device_list_mutex); free(dev); return; } @@ -570,12 +584,14 @@ static void device_version_input(struct mux_device *dev, struct version_header * 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); FOREACH(struct mux_device *tdev, &device_list) { if(tdev->usbdev == usbdev) { dev = tdev; break; } } ENDFOREACH + pthread_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; @@ -711,12 +727,15 @@ int device_add(struct usb_device *usbdev) free(dev); return res; } + pthread_mutex_lock(&device_list_mutex); collection_add(&device_list, dev); + pthread_mutex_unlock(&device_list_mutex); return 0; } void device_remove(struct usb_device *usbdev) { + pthread_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)); @@ -732,47 +751,57 @@ 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); free(dev->pktbuf); free(dev); return; } } ENDFOREACH + pthread_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); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == device_id) { dev->visible = 1; break; } } ENDFOREACH + pthread_mutex_unlock(&device_list_mutex); } void device_set_preflight_cb_data(int device_id, void* data) { + pthread_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); } int device_get_count(int include_hidden) { int count = 0; + pthread_mutex_unlock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) count++; } ENDFOREACH + pthread_mutex_unlock(&device_list_mutex); return count; } int device_get_list(int include_hidden, struct device_info *p) { int count = 0; + pthread_mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) { p->id = dev->id; @@ -783,12 +812,14 @@ int device_get_list(int include_hidden, struct device_info *p) p++; } } ENDFOREACH + pthread_mutex_unlock(&device_list_mutex); return count; } int device_get_timeout(void) { uint64_t oldest = (uint64_t)-1LL; + pthread_mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->state == MUXDEV_ACTIVE) { FOREACH(struct mux_connection *conn, &dev->connections) { @@ -797,6 +828,7 @@ int device_get_timeout(void) } ENDFOREACH } } ENDFOREACH + pthread_mutex_unlock(&device_list_mutex); uint64_t ct = mstime64(); if((int64_t)oldest == -1LL) return 100000; //meh @@ -808,6 +840,7 @@ int device_get_timeout(void) void device_check_timeouts(void) { uint64_t ct = mstime64(); + pthread_mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->state == MUXDEV_ACTIVE) { FOREACH(struct mux_connection *conn, &dev->connections) { @@ -823,12 +856,14 @@ void device_check_timeouts(void) } ENDFOREACH } } ENDFOREACH + pthread_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); next_device_id = 1; } @@ -849,6 +884,7 @@ void device_kill_connections(void) void device_shutdown(void) { usbmuxd_log(LL_DEBUG, "device_shutdown"); + pthread_mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { FOREACH(struct mux_connection *conn, &dev->connections) { connection_teardown(conn); @@ -857,5 +893,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); collection_free(&device_list); } From 017cf5425571f40bbdd760ccb06089de39f7e44f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Jan 2014 11:31:49 +0100 Subject: [PATCH 49/70] device/client: make device_get_list() allocate the result buffer itself Using device_get_count() and device_get_list() separately can return different device counts in case there are devices added to the list inbetween these two function calls. To prevent this, device_get_list() will allocate the buffer by itself. --- src/client.c | 42 +++++++++++++++++++----------------------- src/device.c | 7 ++++++- src/device.h | 2 +- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/client.c b/src/client.c index d4719c3b..5a70edb9 100644 --- a/src/client.c +++ b/src/client.c @@ -267,23 +267,21 @@ static int send_device_list(struct mux_client *client, uint32_t tag) plist_t dict = plist_new_dict(); plist_t devices = plist_new_array(); - int count = device_get_count(0); - if (count > 0) { - struct device_info *devs; - struct device_info *dev; - int i; - - devs = malloc(sizeof(struct device_info) * count); - count = device_get_list(0, devs); - dev = devs; - for (i = 0; i < count; i++) { - plist_t device = create_device_attached_plist(dev++); - if (device) { - plist_array_append_item(devices, device); - } + struct device_info *devs = NULL; + struct device_info *dev; + int i; + + int count = device_get_list(0, &devs); + dev = devs; + for (i = 0; devs && i < count; i++) { + plist_t device = create_device_attached_plist(dev++); + if (device) { + plist_array_append_item(devices, device); } - free(devs); } + if (devs) + free(devs); + plist_dict_insert_item(dict, "DeviceList", devices); res = send_plist_pkt(client, tag, dict); plist_free(dict); @@ -369,25 +367,23 @@ static int notify_device_remove(struct mux_client *client, uint32_t device_id) static int start_listen(struct mux_client *client) { - struct device_info *devs; + struct device_info *devs = NULL; struct device_info *dev; int count, i; client->state = CLIENT_LISTEN; - count = device_get_count(0); - if(!count) - return 0; - devs = malloc(sizeof(struct device_info) * count); - count = device_get_list(0, devs); + count = device_get_list(0, &devs); dev = devs; - for(i=0; istate == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) { p->id = dev->id; diff --git a/src/device.h b/src/device.h index bd81699e..8e8dce87 100644 --- a/src/device.h +++ b/src/device.h @@ -44,7 +44,7 @@ void device_set_visible(int device_id); void device_set_preflight_cb_data(int device_id, void* data); int device_get_count(int include_hidden); -int device_get_list(int include_hidden, struct device_info *p); +int device_get_list(int include_hidden, struct device_info **devices); int device_get_timeout(void); void device_check_timeouts(void); From 046ee6989fa18edf18e5a47181a03ff8b149c960 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Jan 2014 15:14:35 +0100 Subject: [PATCH 50/70] device: suppress "No connection for device" if TH_RST is set --- src/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device.c b/src/device.c index d4ed47ce..5b393fe6 100644 --- a/src/device.c +++ b/src/device.c @@ -525,8 +525,8 @@ static void device_version_input(struct mux_device *dev, struct version_header * } ENDFOREACH if(!conn) { - usbmuxd_log(LL_INFO, "No connection for device %d incoming packet %d->%d", dev->id, dport, sport); if(!(th->th_flags & TH_RST)) { + usbmuxd_log(LL_INFO, "No connection for device %d incoming packet %d->%d", dev->id, dport, sport); if(send_anon_rst(dev, sport, dport, ntohl(th->th_seq)) < 0) usbmuxd_log(LL_ERROR, "Error sending TCP RST to device %d (%d->%d)", conn->dev->id, sport, dport); } From 64891030a0ff1b9575642f066c0c0a44c719f9ba Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Jan 2014 15:27:00 +0100 Subject: [PATCH 51/70] removed trailing \n from usbmuxd_log() messages --- src/conf.c | 2 +- src/device.c | 4 ++-- src/main.c | 4 ++-- src/preflight.c | 2 +- src/usb-linux.c | 2 +- src/utils.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/conf.c b/src/conf.c index ef371a37..12194bce 100644 --- a/src/conf.c +++ b/src/conf.c @@ -524,6 +524,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\n", __func__, udid); + usbmuxd_log(LL_ERROR, "%s: ERROR couldn't get HostID from pairing record for udid %s", __func__, udid); } } diff --git a/src/device.c b/src/device.c index 5b393fe6..6ac6d616 100644 --- a/src/device.c +++ b/src/device.c @@ -480,7 +480,7 @@ static void device_version_input(struct mux_device *dev, struct version_header * vh->major = ntohl(vh->major); vh->minor = ntohl(vh->minor); if(vh->major != 1 || vh->minor != 0) { - usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d\n", dev->id, vh->major, vh->minor); + usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d", dev->id, vh->major, vh->minor); pthread_mutex_lock(&device_list_mutex); collection_remove(&device_list, dev); pthread_mutex_unlock(&device_list_mutex); @@ -513,7 +513,7 @@ static void device_version_input(struct mux_device *dev, struct version_header * dev->id, dport, sport, ntohl(th->th_seq), ntohl(th->th_ack), th->th_flags, ntohs(th->th_win) << 8, ntohs(th->th_win), payload_length); if(dev->state != MUXDEV_ACTIVE) { - usbmuxd_log(LL_ERROR, "Received TCP packet from device %d but the device isn't active yet, discarding\n", dev->id); + usbmuxd_log(LL_ERROR, "Received TCP packet from device %d but the device isn't active yet, discarding", dev->id); return; } diff --git a/src/main.c b/src/main.c index 9b58e68f..4f377844 100644 --- a/src/main.c +++ b/src/main.c @@ -554,12 +554,12 @@ int main(int argc, char *argv[]) memset(&fst, '\0', sizeof(struct stat)); if (stat(userprefdir, &fst) < 0) { if (mkdir(userprefdir, 0775) < 0) { - usbmuxd_log(LL_FATAL, "Failed to create required directory '%s': %s\n", userprefdir, strerror(errno)); + usbmuxd_log(LL_FATAL, "Failed to create required directory '%s': %s", userprefdir, strerror(errno)); res = -1; goto terminate; } if (stat(userprefdir, &fst) < 0) { - usbmuxd_log(LL_FATAL, "stat() failed after creating directory '%s': %s\n", userprefdir, strerror(errno)); + usbmuxd_log(LL_FATAL, "stat() failed after creating directory '%s': %s", userprefdir, strerror(errno)); res = -1; goto terminate; } diff --git a/src/preflight.c b/src/preflight.c index 5198d8c5..5c4474a6 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -188,7 +188,7 @@ static void* preflight_worker_handle_device_add(void* userdata) lockdown = NULL; goto retry; } else { - usbmuxd_log(LL_ERROR, "%s: Could not remove pair record for device %s\n", __func__, _dev->udid); + usbmuxd_log(LL_ERROR, "%s: Could not remove pair record for device %s", __func__, _dev->udid); } break; default: diff --git a/src/usb-linux.c b/src/usb-linux.c index 9d463c61..127446a2 100644 --- a/src/usb-linux.c +++ b/src/usb-linux.c @@ -234,7 +234,7 @@ int usb_discover(void) devlist_failures++; // sometimes libusb fails getting the device list if you've just removed something if(devlist_failures > 5) { - usbmuxd_log(LL_FATAL, "Too many errors getting device list\n"); + usbmuxd_log(LL_FATAL, "Too many errors getting device list"); return cnt; } else { gettimeofday(&next_dev_poll_time, NULL); diff --git a/src/utils.c b/src/utils.c index 245894e6..52963329 100644 --- a/src/utils.c +++ b/src/utils.c @@ -225,7 +225,7 @@ void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *le *buffer = (char*)malloc(sizeof(char)*(size+1)); if (fread(*buffer, sizeof(char), size, f) != size) { - usbmuxd_log(LL_ERROR, "%s: ERROR: couldn't read %d bytes from %s\n", __func__, (int)size, filename); + usbmuxd_log(LL_ERROR, "%s: ERROR: couldn't read %d bytes from %s", __func__, (int)size, filename); } fclose(f); From d283ba1483ba70442f26912c0edc683ddc7ae4c7 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Jan 2014 18:49:36 +0100 Subject: [PATCH 52/70] utils: add new collection_copy() function --- src/utils.c | 8 ++++++++ src/utils.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/utils.c b/src/utils.c index 52963329..9fa4d802 100644 --- a/src/utils.c +++ b/src/utils.c @@ -124,6 +124,14 @@ int collection_count(struct collection *col) 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 diff --git a/src/utils.h b/src/utils.h index 730fbad0..67477b57 100644 --- a/src/utils.h +++ b/src/utils.h @@ -54,6 +54,7 @@ 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) From bdb4c19f794cbadaaa57dd206723b6c8fa8836dc Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Jan 2014 18:49:56 +0100 Subject: [PATCH 53/70] device: reduce locking time inside device_get_list() and device_get_count() --- src/device.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/device.c b/src/device.c index 6ac6d616..17ddb570 100644 --- a/src/device.c +++ b/src/device.c @@ -789,22 +789,29 @@ void device_set_preflight_cb_data(int device_id, void* data) int device_get_count(int include_hidden) { int count = 0; + struct collection dev_list = {NULL, 0}; + pthread_mutex_lock(&device_list_mutex); + collection_copy(&dev_list, &device_list); pthread_mutex_unlock(&device_list_mutex); - FOREACH(struct mux_device *dev, &device_list) { + + FOREACH(struct mux_device *dev, &dev_list) { if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) count++; } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + + collection_free(&dev_list); return count; } 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); + collection_copy(&dev_list, &device_list); + pthread_mutex_unlock(&device_list_mutex); - int total_count = collection_count(&device_list); - *devices = malloc(sizeof(struct device_info) * total_count); + *devices = malloc(sizeof(struct device_info) * dev_list.capacity); struct device_info *p = *devices; FOREACH(struct mux_device *dev, &device_list) { @@ -817,7 +824,9 @@ int device_get_list(int include_hidden, struct device_info **devices) p++; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + + collection_free(&dev_list); + return count; } From 971dcd33f4b6ab5de73d77e22efd7ff049bb8b0e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 10 Jan 2014 11:12:21 +0100 Subject: [PATCH 54/70] client: fix realloc in send_pkt() that made the buffer smaller instead of larger --- src/client.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/client.c b/src/client.c index 5a70edb9..330a9020 100644 --- a/src/client.c +++ b/src/client.c @@ -176,10 +176,16 @@ static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtyp uint32_t available = client->ob_capacity - client->ob_size; /* the output buffer _should_ be large enough, but just in case */ if(available < hdr.length) { - uint32_t needed_buffer = hdr.length; - usbmuxd_log(LL_DEBUG, "Enlarging client %d output buffer %d -> %d", client->fd, client->ob_capacity, needed_buffer); - client->ob_buf = realloc(client->ob_buf, needed_buffer); - client->ob_capacity = needed_buffer; + unsigned char* new_buf; + uint32_t new_size = ((client->ob_capacity + hdr.length + 4096) / 4096) * 4096; + usbmuxd_log(LL_DEBUG, "%s: Enlarging client %d output buffer %d -> %d", __func__, client->fd, client->ob_capacity, new_size); + new_buf = realloc(client->ob_buf, new_size); + if (!new_buf) { + usbmuxd_log(LL_FATAL, "%s: Failed to realloc.\n", __func__); + return -1; + } + client->ob_buf = new_buf; + client->ob_capacity = new_size; } memcpy(client->ob_buf + client->ob_size, &hdr, sizeof(hdr)); if(payload && payload_length) From e16bb31066f8ebea706352dc16994ae0a76763f8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 25 Jan 2014 02:43:54 +0100 Subject: [PATCH 55/70] updated README --- README | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README b/README index 2f09d212..65219c10 100644 --- a/README +++ b/README @@ -33,9 +33,7 @@ U.S. and other countries. Building ======== - mkdir build - cd build - cmake .. + ./autogen.sh make sudo make install @@ -65,7 +63,7 @@ If 'udev' is _not_ automatically running on your machine and picking up the new and that there is only one copy with 'ps aux | grep usbmuxd'. - sudo usbmuxd -U -v -v & + sudo usbmuxd -U usbmux -v -v & ./iproxy 2222 22 & ssh -p 2222 root@localhost From 7eaecdedc2ce4d1d30a68713ab1e144764fb2fa8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 15 Feb 2014 19:15:58 +0100 Subject: [PATCH 56/70] preflight: create preflight worker as detached thread and handle errors --- src/preflight.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/preflight.c b/src/preflight.c index 5c4474a6..88e6700f 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include #include @@ -343,7 +344,17 @@ void preflight_worker_device_add(struct device_info* info) memcpy(infocopy, info, sizeof(struct device_info)); pthread_t th; - pthread_create(&th, NULL, preflight_worker_handle_device_add, infocopy); + 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); + if (perr != 0) { + 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 client_device_add(info); #endif From 3cad548d69b878993b2a085506369e50498cfb4b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 13 Mar 2014 02:47:18 +0100 Subject: [PATCH 57/70] device: suppress 'error reading from client (0)' which is not actually an error --- src/device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/device.c b/src/device.c index 17ddb570..49f21318 100644 --- a/src/device.c +++ b/src/device.c @@ -422,7 +422,9 @@ void device_client_process(int device_id, struct mux_client *client, short event if(events & POLLIN) { size = client_read(conn->client, conn->ob_buf, conn->sendable); if(size <= 0) { - usbmuxd_log(LL_DEBUG, "error reading from client (%d)", size); + if (size < 0) { + usbmuxd_log(LL_DEBUG, "error reading from client (%d)", size); + } connection_teardown(conn); return; } From bfdddc8ee97d0bd21e1895e19ad6117fe97d7d52 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Mon, 24 Mar 2014 16:49:33 +0100 Subject: [PATCH 58/70] Use plist_dict_set_item() instead of deprecated plist_dict_insert_item() --- src/client.c | 32 ++++++++++++++++---------------- src/conf.c | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/client.c b/src/client.c index 330a9020..1e15a1e9 100644 --- a/src/client.c +++ b/src/client.c @@ -216,8 +216,8 @@ static int send_result(struct mux_client *client, uint32_t tag, uint32_t result) if (client->proto_version == 1) { /* XML plist packet */ plist_t dict = plist_new_dict(); - plist_dict_insert_item(dict, "MessageType", plist_new_string("Result")); - plist_dict_insert_item(dict, "Number", plist_new_uint(result)); + 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); plist_free(dict); } else { @@ -253,17 +253,17 @@ int client_notify_connect(struct mux_client *client, enum usbmuxd_result result) static plist_t create_device_attached_plist(struct device_info *dev) { plist_t dict = plist_new_dict(); - plist_dict_insert_item(dict, "MessageType", plist_new_string("Attached")); - plist_dict_insert_item(dict, "DeviceID", plist_new_uint(dev->id)); + plist_dict_set_item(dict, "MessageType", plist_new_string("Attached")); + plist_dict_set_item(dict, "DeviceID", plist_new_uint(dev->id)); plist_t props = plist_new_dict(); // TODO: get current usb speed - plist_dict_insert_item(props, "ConnectionSpeed", plist_new_uint(480000000)); - plist_dict_insert_item(props, "ConnectionType", plist_new_string("USB")); - plist_dict_insert_item(props, "DeviceID", plist_new_uint(dev->id)); - plist_dict_insert_item(props, "LocationID", plist_new_uint(dev->location)); - plist_dict_insert_item(props, "ProductID", plist_new_uint(dev->pid)); - plist_dict_insert_item(props, "SerialNumber", plist_new_string(dev->serial)); - plist_dict_insert_item(dict, "Properties", props); + plist_dict_set_item(props, "ConnectionSpeed", plist_new_uint(480000000)); + plist_dict_set_item(props, "ConnectionType", plist_new_string("USB")); + plist_dict_set_item(props, "DeviceID", plist_new_uint(dev->id)); + plist_dict_set_item(props, "LocationID", plist_new_uint(dev->location)); + plist_dict_set_item(props, "ProductID", plist_new_uint(dev->pid)); + plist_dict_set_item(props, "SerialNumber", plist_new_string(dev->serial)); + plist_dict_set_item(dict, "Properties", props); return dict; } @@ -288,7 +288,7 @@ static int send_device_list(struct mux_client *client, uint32_t tag) if (devs) free(devs); - plist_dict_insert_item(dict, "DeviceList", devices); + plist_dict_set_item(dict, "DeviceList", devices); res = send_plist_pkt(client, tag, dict); plist_free(dict); return res; @@ -302,7 +302,7 @@ static int send_system_buid(struct mux_client *client, uint32_t tag) config_get_system_buid(&buid); plist_t dict = plist_new_dict(); - plist_dict_insert_item(dict, "BUID", plist_new_string(buid)); + plist_dict_set_item(dict, "BUID", plist_new_string(buid)); res = send_plist_pkt(client, tag, dict); plist_free(dict); return res; @@ -322,7 +322,7 @@ static int send_pair_record(struct mux_client *client, uint32_t tag, const char* if (record_data) { plist_t dict = plist_new_dict(); - plist_dict_insert_item(dict, "PairRecordData", plist_new_data(record_data, record_size)); + plist_dict_set_item(dict, "PairRecordData", plist_new_data(record_data, record_size)); free(record_data); res = send_plist_pkt(client, tag, dict); plist_free(dict); @@ -360,8 +360,8 @@ static int notify_device_remove(struct mux_client *client, uint32_t device_id) if (client->proto_version == 1) { /* XML plist packet */ plist_t dict = plist_new_dict(); - plist_dict_insert_item(dict, "MessageType", plist_new_string("Detached")); - plist_dict_insert_item(dict, "DeviceID", plist_new_uint(device_id)); + 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); plist_free(dict); } else { diff --git a/src/conf.c b/src/conf.c index 12194bce..2a90922b 100644 --- a/src/conf.c +++ b/src/conf.c @@ -234,13 +234,13 @@ static int internal_set_value(const char *config_file, const char *key, plist_t plist_read_from_filename(&config, config_file); if (!config) { config = plist_new_dict(); - plist_dict_insert_item(config, key, value); + plist_dict_set_item(config, key, value); } else { plist_t n = plist_dict_get_item(config, key); if (n) { plist_dict_remove_item(config, key); } - plist_dict_insert_item(config, key, value); + plist_dict_set_item(config, key, value); remove(config_file); } From 10c3ef7e334debb2805ce573696a93de18886fe5 Mon Sep 17 00:00:00 2001 From: Mikkel Kamstrup Erlandsen Date: Wed, 19 Mar 2014 13:28:25 +0100 Subject: [PATCH 59/70] client: add a bunch of comments and function docs --- src/client.c | 35 ++++++++++++++++++++++++++++++ src/device.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/client.c b/src/client.c index 1e15a1e9..c6a7ce88 100644 --- a/src/client.c +++ b/src/client.c @@ -71,6 +71,14 @@ struct mux_client { static struct collection client_list; pthread_mutex_t client_list_mutex; +/** + * Receive raw data from the client socket. + * + * @param client Client to read from. + * @param buffer Buffer to store incoming data. + * @param len Max number of bytes to read. + * @return Same as recv() system call. Number of bytes read; when < 0 errno will be set. + */ int client_read(struct mux_client *client, void *buffer, uint32_t len) { usbmuxd_log(LL_SPEW, "client_read fd %d buf %p len %d", client->fd, buffer, len); @@ -81,6 +89,14 @@ int client_read(struct mux_client *client, void *buffer, uint32_t len) return recv(client->fd, buffer, len, 0); } +/** + * Send raw data to the client socket. + * + * @param client Client to send to. + * @param buffer The data to send. + * @param len Number of bytes to write. + * @return Same as system call send(). Number of bytes written; when < 0 errno will be set. + */ int client_write(struct mux_client *client, void *buffer, uint32_t len) { usbmuxd_log(LL_SPEW, "client_write fd %d buf %p len %d", client->fd, buffer, len); @@ -91,6 +107,16 @@ int client_write(struct mux_client *client, void *buffer, uint32_t len) return send(client->fd, buffer, len, 0); } +/** + * Set event mask to use for ppoll()ing the client socket. + * Typically POLLOUT and/or POLLIN. Note that this overrides + * the current mask, that is, it is not ORing the argument + * into the current mask. + * + * @param client The client to set the event mask on. + * @param events The event mask to sert. + * @return 0 on success, -1 on error. + */ int client_set_events(struct mux_client *client, short events) { if((client->state != CLIENT_CONNECTED) && (client->state != CLIENT_CONNECTING2)) { @@ -103,6 +129,15 @@ int client_set_events(struct mux_client *client, short events) return 0; } +/** + * Wait for an inbound connection on the usbmuxd socket + * and create a new mux_client instance for it, and store + * the client in the client list. + * + * @param listenfd the socket fd to accept() on. + * @return The connection fd for the client, or < 0 for error + * in which case errno will be set. + */ int client_accept(int listenfd) { struct sockaddr_un addr; diff --git a/src/device.c b/src/device.c index 49f21318..962877b0 100644 --- a/src/device.c +++ b/src/device.c @@ -346,6 +346,13 @@ int device_start_connect(int device_id, uint16_t dport, struct mux_client *clien return 0; } +/** + * Examine the state of a connection's buffers and + * update all connection flags and masks accordingly. + * Does not do I/O. + * + * @param conn The connection to update. + */ static void update_connection(struct mux_connection *conn) { uint32_t sent = conn->tx_seq - conn->rx_ack; @@ -379,8 +386,18 @@ static void update_connection(struct mux_connection *conn) client_set_events(conn->client, conn->events); } +/** + * Flush input and output buffers for a client connection. + * + * @param device_id Numeric id for the device. + * @param client The client to flush buffers for. + * @param events event mask for the client. POLLOUT means that + * the client is ready to receive data, POLLIN that it has + * data to be read (and send along to the device). + */ void device_client_process(int device_id, struct mux_client *client, short events) { + // Find the connection for the given device_id struct mux_connection *conn = NULL; pthread_mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { @@ -405,6 +422,8 @@ void device_client_process(int device_id, struct mux_client *client, short event int res; int size; if(events & POLLOUT) { + // Client is ready to receive data, send what we have + // in the client's connection buffer size = client_write(conn->client, conn->ib_buf, conn->ib_size); if(size <= 0) { usbmuxd_log(LL_DEBUG, "error writing to client (%d)", size); @@ -420,6 +439,8 @@ void device_client_process(int device_id, struct mux_client *client, short event } } if(events & POLLIN) { + // There is inbound trafic on the client socket, + // convert it to tcp and send to the device size = client_read(conn->client, conn->ob_buf, conn->sendable); if(size <= 0) { if (size < 0) { @@ -439,6 +460,23 @@ void device_client_process(int device_id, struct mux_client *client, short event update_connection(conn); } +/** + * Copy a payload to a connection's in-buffer and + * set the POLLOUT event mask on the connection so + * the next main_loop iteration will dispatch the + * buffer if the connection socket is writable. + * + * Connection buffers are flushed in the + * device_client_process() function. + * + * @param conn The connection to add incoming data to. + * @param payload Payload to prepare for writing. + * The payload will be copied immediately so you are + * free to alter or free the payload buffer when this + * function returns. + * @param payload_length number of bytes to copy from from + * the payload. + */ static void connection_device_input(struct mux_connection *conn, unsigned char *payload, uint32_t payload_length) { if((conn->ib_size + payload_length) > conn->ib_capacity) { @@ -500,12 +538,24 @@ static void device_version_input(struct mux_device *dev, struct version_header * preflight_worker_device_add(&info); } +<<<<<<< HEAD #ifdef ANDROID static void device_tcp_input(struct mux_device *dev, struct tcphdr_bsd *th, unsigned char *payload, uint32_t payload_length) #else static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) #endif +======= +/** + * Handle an incoming TCP packet from the device. + * + * @param dev The device handle TCP input on. + * @param th Pointer to the TCP header struct. + * @param payload Payload data. + * @param payload_length Number of bytes in payload. + */ +static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) +>>>>>>> client: add a bunch of comments and function docs { uint16_t sport = ntohs(th->th_dport); uint16_t dport = ntohs(th->th_sport); @@ -583,6 +633,14 @@ static void device_version_input(struct mux_device *dev, struct version_header * } } +/** + * Take input data from the device that has been read into a buffer + * and dispatch it to the right protocol backend (eg. TCP). + * + * @param usbdev + * @param buffer + * @param length + */ void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_t length) { struct mux_device *dev = NULL; @@ -617,7 +675,7 @@ void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_ dev->pktlen = 0; return; } - memcpy(dev->pktbuf + dev->pktlen, buffer, length); + memcpy(dev->pktbuf + dev->pktlen, buffer, length); struct mux_header *mhdr = (struct mux_header *)dev->pktbuf; if((length < USB_MRU) || (ntohl(mhdr->length) == (length + dev->pktlen))) { buffer = dev->pktbuf; From 6f4c4384ef96e7efc9fc7c356d3b0437b79cde97 Mon Sep 17 00:00:00 2001 From: Mikkel Kamstrup Erlandsen Date: Wed, 19 Mar 2014 14:41:22 +0100 Subject: [PATCH 60/70] device: more aggresively send ACKs when receiving TCP data Before this it seemed that we only ever sent ACK when timing out... Looks like a perf double when reading. --- src/device.c | 115 +++++++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 49 deletions(-) diff --git a/src/device.c b/src/device.c index 962877b0..44d8edd5 100644 --- a/src/device.c +++ b/src/device.c @@ -2,6 +2,7 @@ usbmuxd - iPhone/iPod Touch USB multiplex server daemon Copyright (C) 2009 Hector Martin "marcan" +Copyright (C) 2014 Mikkel Kamstrup Erlandsen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -126,6 +127,41 @@ static uint64_t mstime64(void) return tv.tv_sec * 1000 + tv.tv_usec / 1000; } +static struct mux_device* get_mux_device_for_id(int device_id) +{ + struct mux_device *dev = NULL; + pthread_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); + + return dev; +} + +static struct mux_connection* get_mux_connection(int device_id, struct mux_client *client) +{ + struct mux_connection *conn = NULL; + pthread_mutex_lock(&device_list_mutex); + FOREACH(struct mux_device *dev, &device_list) { + if(dev->id == device_id) { + FOREACH(struct mux_connection *lconn, &dev->connections) { + if(lconn->client == client) { + conn = lconn; + break; + } + } ENDFOREACH + break; + } + } ENDFOREACH + pthread_mutex_unlock(&device_list_mutex); + + return conn; +} + static int get_next_device_id(void) { while(1) { @@ -286,15 +322,7 @@ static void connection_teardown(struct mux_connection *conn) int device_start_connect(int device_id, uint16_t dport, struct mux_client *client) { - struct mux_device *dev = NULL; - pthread_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); + struct mux_device *dev = get_mux_device_for_id(device_id); if(!dev) { usbmuxd_log(LL_WARNING, "Attempted to connect to nonexistent device %d", device_id); return -RESULT_BADDEV; @@ -386,6 +414,19 @@ static void update_connection(struct mux_connection *conn) client_set_events(conn->client, conn->events); } +static int send_tcp_ack(struct mux_connection *conn) +{ + if(send_tcp(conn, TH_ACK, NULL, 0) < 0) { + usbmuxd_log(LL_ERROR, "Error sending TCP ACK (%d->%d)", conn->sport, conn->dport); + connection_teardown(conn); + return -1; + } + + update_connection(conn); + + return 0; +} + /** * Flush input and output buffers for a client connection. * @@ -397,21 +438,7 @@ static void update_connection(struct mux_connection *conn) */ void device_client_process(int device_id, struct mux_client *client, short events) { - // Find the connection for the given device_id - struct mux_connection *conn = NULL; - pthread_mutex_lock(&device_list_mutex); - FOREACH(struct mux_device *dev, &device_list) { - if(dev->id == device_id) { - FOREACH(struct mux_connection *lconn, &dev->connections) { - if(lconn->client == client) { - conn = lconn; - break; - } - } ENDFOREACH - break; - } - } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + struct mux_connection *conn = get_mux_connection(device_id, client); if(!conn) { usbmuxd_log(LL_WARNING, "Could not find connection for device %d client %p", device_id, client); @@ -422,8 +449,8 @@ void device_client_process(int device_id, struct mux_client *client, short event int res; int size; if(events & POLLOUT) { - // Client is ready to receive data, send what we have - // in the client's connection buffer + // Client is ready to receive data, send what we have + // in the client's connection buffer size = client_write(conn->client, conn->ib_buf, conn->ib_size); if(size <= 0) { usbmuxd_log(LL_DEBUG, "error writing to client (%d)", size); @@ -439,8 +466,8 @@ void device_client_process(int device_id, struct mux_client *client, short event } } if(events & POLLIN) { - // There is inbound trafic on the client socket, - // convert it to tcp and send to the device + // There is inbound trafic on the client socket, + // convert it to tcp and send to the device size = client_read(conn->client, conn->ob_buf, conn->sendable); if(size <= 0) { if (size < 0) { @@ -492,23 +519,12 @@ static void connection_device_input(struct mux_connection *conn, unsigned char * void device_abort_connect(int device_id, struct mux_client *client) { - pthread_mutex_lock(&device_list_mutex); - FOREACH(struct mux_device *dev, &device_list) { - if(dev->id == device_id) { - FOREACH(struct mux_connection *conn, &dev->connections) { - if(conn->client == client) { - connection_teardown(conn); - pthread_mutex_unlock(&device_list_mutex); - return; - } - } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); - usbmuxd_log(LL_WARNING, "Attempted to abort for nonexistent connection for device %d", device_id); - return; - } - } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); - usbmuxd_log(LL_WARNING, "Attempted to abort connection for nonexistent device %d", device_id); + struct mux_connection *conn = get_mux_connection(device_id, client); + if (conn) { + connection_teardown(conn); + } else { + usbmuxd_log(LL_WARNING, "Attempted to abort for nonexistent connection for device %d", device_id); + } } static void device_version_input(struct mux_device *dev, struct version_header *vh) @@ -569,6 +585,7 @@ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned return; } + // Find the connection on this device that has the right sport and dport FOREACH(struct mux_connection *lconn, &dev->connections) { if(lconn->sport == sport && lconn->dport == dport) { conn = lconn; @@ -629,6 +646,9 @@ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned connection_teardown(conn); } else { connection_device_input(conn, payload, payload_length); + + // Device likes it best when we are prompty ACKing data + send_tcp_ack(conn); } } } @@ -922,10 +942,7 @@ void device_check_timeouts(void) (conn->flags & CONN_ACK_PENDING) && (ct - conn->last_ack_time) > ACK_TIMEOUT) { usbmuxd_log(LL_DEBUG, "Sending ACK due to expired timeout (%" PRIu64 " -> %" PRIu64 ")", conn->last_ack_time, ct); - if(send_tcp(conn, TH_ACK, NULL, 0) < 0) { - usbmuxd_log(LL_ERROR, "Error sending TCP ACK to device %d (%d->%d)", dev->id, conn->sport, conn->dport); - connection_teardown(conn); - } + send_tcp_ack(conn); } } ENDFOREACH } From 8ddbaed2a404e917fdaba01792602610a37e6b1d Mon Sep 17 00:00:00 2001 From: Mikkel Kamstrup Erlandsen Date: Wed, 19 Mar 2014 13:32:45 +0100 Subject: [PATCH 61/70] device: fix potential integer overflow in mstime64() on 32 bit systems --- src/device.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/device.c b/src/device.c index 44d8edd5..19c37414 100644 --- a/src/device.c +++ b/src/device.c @@ -124,7 +124,10 @@ static uint64_t mstime64(void) { struct timeval tv; gettimeofday(&tv, NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; + + // Careful, avoid overflow on 32 bit systems + // time_t could be 4 bytes + return ((long long)tv.tv_sec) * 1000LL + ((long long)tv.tv_usec) / 1000LL; } static struct mux_device* get_mux_device_for_id(int device_id) From e4fec5784e514943a17791505794d01f2ed85efc Mon Sep 17 00:00:00 2001 From: Mikkel Kamstrup Erlandsen Date: Wed, 19 Mar 2014 21:29:13 +0100 Subject: [PATCH 62/70] device/utils: move mstime64() into utils since it is generally useful --- src/device.c | 10 ---------- src/utils.c | 14 ++++++++++++++ src/utils.h | 2 ++ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/device.c b/src/device.c index 19c37414..6f2299cc 100644 --- a/src/device.c +++ b/src/device.c @@ -120,16 +120,6 @@ struct mux_device static struct collection device_list; pthread_mutex_t device_list_mutex; -static uint64_t mstime64(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - - // Careful, avoid overflow on 32 bit systems - // time_t could be 4 bytes - return ((long long)tv.tv_sec) * 1000LL + ((long long)tv.tv_usec) / 1000LL; -} - static struct mux_device* get_mux_device_for_id(int device_id) { struct mux_device *dev = NULL; diff --git a/src/utils.c b/src/utils.c index 9fa4d802..42187588 100644 --- a/src/utils.c +++ b/src/utils.c @@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include #include "utils.h" @@ -272,3 +273,16 @@ int plist_write_to_filename(plist_t plist, const char *filename, enum plist_form return 1; } + +/** + * Get number of milliseconds since the epoch. + */ +uint64_t mstime64(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + + // Careful, avoid overflow on 32 bit systems + // time_t could be 4 bytes + return ((long long)tv.tv_sec) * 1000LL + ((long long)tv.tv_usec) / 1000LL; +} diff --git a/src/utils.h b/src/utils.h index 67477b57..92a7d68c 100644 --- a/src/utils.h +++ b/src/utils.h @@ -87,4 +87,6 @@ enum plist_format_t { 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); + #endif From 19f42b0533fe20cdb3caf165fb2e6bce2c3ac1a2 Mon Sep 17 00:00:00 2001 From: Mikkel Kamstrup Erlandsen Date: Wed, 19 Mar 2014 21:28:29 +0100 Subject: [PATCH 63/70] usb-linux: add some explanatory comments to usb-linux.c --- src/usb-linux.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/usb-linux.c b/src/usb-linux.c index 127446a2..94db8f29 100644 --- a/src/usb-linux.c +++ b/src/usb-linux.c @@ -93,6 +93,7 @@ static void usb_disconnect(struct usb_device *dev) free(dev); } +// Callback from write operation static void tx_callback(struct libusb_transfer *xfer) { struct usb_device *dev = xfer->user_data; @@ -162,6 +163,9 @@ int usb_send(struct usb_device *dev, const unsigned char *buf, int length) return 0; } +// Callback from read operation +// Under normal operation this issues a new read transfer request immediately, +// doing a kind of read-callback loop static void rx_callback(struct libusb_transfer *xfer) { struct usb_device *dev = xfer->user_data; @@ -206,6 +210,7 @@ static void rx_callback(struct libusb_transfer *xfer) } } +// Start a read-callback loop for this device static int start_rx(struct usb_device *dev) { int res; From e43875d5ea966edbaf5acdd9f61f735a155707c6 Mon Sep 17 00:00:00 2001 From: Mikkel Kamstrup Erlandsen Date: Thu, 20 Mar 2014 10:01:53 +0100 Subject: [PATCH 64/70] usb-linux: massive read perf improvement with 3 parallel transfers By maintaining 3 parallel usb trasfers when reading we get 2-3x more throughput when reading. Without this the usb port is mostly just idling. I get 23mb/s on my system compared to a clean Apple stack that gives me 17mb/s. 3 was chosen because it is simple to hard code, gives very good performance, and have very little impact on out resource consumption. --- src/usb-linux.c | 107 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/src/usb-linux.c b/src/usb-linux.c index 94db8f29..40bf5026 100644 --- a/src/usb-linux.c +++ b/src/usb-linux.c @@ -4,6 +4,7 @@ Copyright (C) 2009 Hector Martin "marcan" Copyright (C) 2009 Nikias Bassen Copyright (C) 2009 Martin Szulecki +Copyright (C) 2014 Mikkel Kamstrup Erlandsen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -39,6 +40,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // we need this because there is currently no asynchronous device discovery mechanism in libusb #define DEVICE_POLL_TIME 1000 +// Number of parallel bulk transfers we have running for reading data from the device. +// Older versions of usbmuxd kept only 1, which leads to a mostly dormant USB port. +// 3 seems to be an all round sensible number - giving better read perf than +// Apples usbmuxd, at least. +#define NUM_RX_LOOPS 3 + struct usb_device { libusb_device_handle *dev; uint8_t bus, address; @@ -46,7 +53,7 @@ struct usb_device { char serial[256]; int alive; uint8_t interface, ep_in, ep_out; - struct libusb_transfer *rx_xfer; + struct collection rx_xfers; struct collection tx_xfers; int wMaxPacketSize; }; @@ -64,17 +71,20 @@ static void usb_disconnect(struct usb_device *dev) return; } - // kill the rx xfer and tx xfers and try to make sure the callbacks get called before we free the device - if(dev->rx_xfer) { - usbmuxd_log(LL_DEBUG, "usb_disconnect: cancelling RX xfer"); - libusb_cancel_transfer(dev->rx_xfer); - } + // kill the rx xfer and tx xfers and try to make sure the callbacks + // get called before we free the device + FOREACH(struct libusb_transfer *xfer, &dev->rx_xfers) { + usbmuxd_log(LL_DEBUG, "usb_disconnect: cancelling RX xfer %p", xfer); + libusb_cancel_transfer(xfer); + } ENDFOREACH + FOREACH(struct libusb_transfer *xfer, &dev->tx_xfers) { usbmuxd_log(LL_DEBUG, "usb_disconnect: cancelling TX xfer %p", xfer); libusb_cancel_transfer(xfer); } ENDFOREACH - while(dev->rx_xfer || collection_count(&dev->tx_xfers)) { + // Busy-wait until all xfers are closed + while(collection_count(&dev->rx_xfers) || collection_count(&dev->tx_xfers)) { struct timeval tv; int res; @@ -85,7 +95,9 @@ static void usb_disconnect(struct usb_device *dev) break; } } + collection_free(&dev->tx_xfers); + collection_free(&dev->rx_xfers); libusb_release_interface(dev->dev, dev->interface); libusb_close(dev->dev); dev->dev = NULL; @@ -93,6 +105,15 @@ static void usb_disconnect(struct usb_device *dev) free(dev); } +static void reap_dead_devices(void) { + FOREACH(struct usb_device *usbdev, &device_list) { + if(!usbdev->alive) { + device_remove(usbdev); + usb_disconnect(usbdev); + } + } ENDFOREACH +} + // Callback from write operation static void tx_callback(struct libusb_transfer *xfer) { @@ -201,9 +222,11 @@ static void rx_callback(struct libusb_transfer *xfer) // this should never be reached. break; } + free(xfer->buffer); - dev->rx_xfer = NULL; + collection_remove(&dev->rx_xfers, xfer); libusb_free_transfer(xfer); + // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events // we'll do device_remove there too dev->alive = 0; @@ -211,19 +234,21 @@ static void rx_callback(struct libusb_transfer *xfer) } // Start a read-callback loop for this device -static int start_rx(struct usb_device *dev) +static int start_rx_loop(struct usb_device *dev) { int res; void *buf; - dev->rx_xfer = libusb_alloc_transfer(0); + struct libusb_transfer *xfer = libusb_alloc_transfer(0); buf = malloc(USB_MRU); - libusb_fill_bulk_transfer(dev->rx_xfer, dev->dev, dev->ep_in, buf, USB_MRU, rx_callback, dev, 0); - if((res = libusb_submit_transfer(dev->rx_xfer)) != 0) { + 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); - libusb_free_transfer(dev->rx_xfer); - dev->rx_xfer = NULL; + libusb_free_transfer(xfer); return res; } + + collection_add(&dev->rx_xfers, xfer); + return 0; } @@ -253,10 +278,14 @@ int usb_discover(void) usbmuxd_log(LL_SPEW, "usb_discover: scanning %d devices", cnt); + // Mark all devices as dead, and do a mark-sweep like + // collection of dead devices FOREACH(struct usb_device *usbdev, &device_list) { usbdev->alive = 0; } ENDFOREACH + // Enumerate all USB devices and mark the ones we already know + // about as live, again for(i=0; itx_xfers); + collection_init(&usbdev->rx_xfers); collection_add(&device_list, usbdev); @@ -414,19 +444,37 @@ int usb_discover(void) usb_disconnect(usbdev); continue; } - if(start_rx(usbdev) < 0) { + + // Spin up NUM_RX_LOOPS parallel usb data retrieval loops + // Old usbmuxds used only 1 rx loop, but that leaves the + // USB port sleeping most of the time + int rx_loops = NUM_RX_LOOPS; + for (rx_loops = NUM_RX_LOOPS; rx_loops > 0; rx_loops--) { + if(start_rx_loop(usbdev) < 0) { + usbmuxd_log(LL_WARNING, "Failed to start RX loop number %d", NUM_RX_LOOPS - rx_loops); + } + } + + // Ensure we have at least 1 RX loop going + if (rx_loops == NUM_RX_LOOPS) { + usbmuxd_log(LL_FATAL, "Failed to start any RX loop for device %d-%d", + usbdev->bus, usbdev->address); device_remove(usbdev); usb_disconnect(usbdev); continue; + } else if (rx_loops > 0) { + usbmuxd_log(LL_WARNING, "Failed to start all %d RX loops. Going on with %d loops. " + "This may have negative impact on device read speed.", + NUM_RX_LOOPS, NUM_RX_LOOPS - rx_loops); + } else { + usbmuxd_log(LL_DEBUG, "All %d RX loops started successfully", NUM_RX_LOOPS); } + valid_count++; } - FOREACH(struct usb_device *usbdev, &device_list) { - if(!usbdev->alive) { - device_remove(usbdev); - usb_disconnect(usbdev); - } - } ENDFOREACH + + // Clean out any device we didn't mark back as live + reap_dead_devices(); libusb_free_device_list(devs, 1); @@ -530,13 +578,9 @@ int usb_process(void) usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res); return res; } + // reap devices marked dead due to an RX error - FOREACH(struct usb_device *usbdev, &device_list) { - if(!usbdev->alive) { - device_remove(usbdev); - usb_disconnect(usbdev); - } - } ENDFOREACH + reap_dead_devices(); if(dev_poll_remain_ms() <= 0) { res = usb_discover(); @@ -570,13 +614,8 @@ int usb_process_timeout(int msec) return res; } // reap devices marked dead due to an RX error - FOREACH(struct usb_device *usbdev, &device_list) { - if(!usbdev->alive) { - device_remove(usbdev); - usb_disconnect(usbdev); - } - } ENDFOREACH - gettimeofday(&tcur, NULL); + reap_dead_devices(); + gettimeofday(&tcur, NULL); } return 0; } From 3650357e0203cbb186beef220daee0e48379b3fe Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 27 Mar 2014 10:22:46 +0100 Subject: [PATCH 65/70] Update command usage output to match best practice and other tools --- src/main.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main.c b/src/main.c index 4f377844..9a0f98fa 100644 --- a/src/main.c +++ b/src/main.c @@ -357,16 +357,17 @@ static int notify_parent(int status) static void usage() { - printf("usage: usbmuxd [options]\n"); - printf("\t-h|--help Print this message.\n"); - printf("\t-v|--verbose Be verbose (use twice or more to increase).\n"); - printf("\t-f|--foreground Do not daemonize (implies one -v).\n"); - printf("\t-U|--user USER Change to this user after startup (needs usb privileges).\n"); - printf("\t-u|--udev Run in udev operation mode.\n"); - printf("\t-x|--exit Tell a running instance to exit if there are no devices\n"); - printf("\t connected (must be in udev mode).\n"); - printf("\t-X|--force-exit Tell a running instance to exit, even if there are still\n"); - printf("\t devices connected (always works).\n"); + printf("Usage: %s [OPTIONS]\n", PACKAGE_NAME); + printf("Expose a socket to multiplex connections from and to iOS devices.\n\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"); + printf(" -U, --user USER\tChange to this user after startup (needs USB privileges).\n"); + printf(" -u, --udev\t\tRun in udev operation mode.\n"); + printf(" -x, --exit\t\tTell a running instance to exit if there are no devices\n"); + printf(" \t\tconnected (must be in udev mode).\n"); + printf(" -X, --force-exit\tTell a running instance to exit, even if there are still\n"); + printf(" \tdevices connected (always works).\n"); printf("\n"); } From 9b8f755505b2064c1b5c14045b1b83a0a65f7b1a Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 27 Mar 2014 10:23:22 +0100 Subject: [PATCH 66/70] Add "--version" option to print version number and exit, useful for bug reports --- src/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.c b/src/main.c index 9a0f98fa..48fedec9 100644 --- a/src/main.c +++ b/src/main.c @@ -368,6 +368,7 @@ static void usage() printf(" \t\tconnected (must be in udev mode).\n"); printf(" -X, --force-exit\tTell a running instance to exit, even if there are still\n"); printf(" \tdevices connected (always works).\n"); + printf(" -V, --version\t\tPrint version information and exit.\n"); printf("\n"); } @@ -381,6 +382,7 @@ static void parse_opts(int argc, char **argv) {"udev", 0, NULL, 'u'}, {"exit", 0, NULL, 'x'}, {"force-exit", 0, NULL, 'X'}, + {"version", 0, NULL, 'V'}, {NULL, 0, NULL, 0} }; int c; @@ -401,6 +403,9 @@ static void parse_opts(int argc, char **argv) case 'v': ++verbose; break; + case 'V': + printf("%s\n", PACKAGE_STRING); + exit(0); case 'U': drop_privileges = 1; drop_user = optarg; From 2aef3cf462740bedd9c78ce18e9e857e6a7d4e27 Mon Sep 17 00:00:00 2001 From: lunzii Date: Fri, 25 Oct 2013 12:03:35 +0800 Subject: [PATCH 67/70] Port to android, build succeed with android-ndk-r8e on mac osx 10.9. --- src/device.c | 15 +++++++++++++++ src/main.c | 6 ++++++ src/usbmuxd-proto.h | 4 ++++ 3 files changed, 25 insertions(+) diff --git a/src/device.c b/src/device.c index 6f2299cc..36b3adcf 100644 --- a/src/device.c +++ b/src/device.c @@ -547,6 +547,7 @@ static void device_version_input(struct mux_device *dev, struct version_header * preflight_worker_device_add(&info); } +<<<<<<< HEAD <<<<<<< HEAD #ifdef ANDROID @@ -555,6 +556,9 @@ static void device_version_input(struct mux_device *dev, struct version_header * static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) #endif ======= +======= +<<<<<<< HEAD:src/device.c +>>>>>>> Port to android, build succeed with android-ndk-r8e on mac osx 10.9. /** * Handle an incoming TCP packet from the device. * @@ -564,7 +568,18 @@ static void device_version_input(struct mux_device *dev, struct version_header * * @param payload_length Number of bytes in payload. */ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) +<<<<<<< HEAD >>>>>>> client: add a bunch of comments and function docs +======= +======= + +#ifdef ANDROID + static void device_tcp_input(struct mux_device *dev, struct tcphdr_bsd *th, unsigned char *payload, uint32_t payload_length) +#else + static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) +#endif +>>>>>>> Port to android, build succeed with android-ndk-r8e on mac osx 10.9.:daemon/device.c +>>>>>>> Port to android, build succeed with android-ndk-r8e on mac osx 10.9. { uint16_t sport = ntohs(th->th_dport); uint16_t dport = ntohs(th->th_sport); diff --git a/src/main.c b/src/main.c index 48fedec9..e7f77365 100644 --- a/src/main.c +++ b/src/main.c @@ -52,6 +52,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #ifdef ANDROID static const char *socket_path = "/data/local/tmp/usbmuxd"; static const char *lockfile = "/data/local/tmp/usbmuxd.pid"; +<<<<<<< HEAD static const char *userprefdir = "/data/local/tmp/lockdown"; #else static const char *socket_path = "/var/run/usbmuxd"; @@ -61,6 +62,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #ifdef HAVE_LIBIMOBILEDEVICE extern const char* userpref_get_config_dir(); +======= +#else + static const char *socket_path = "/var/run/usbmuxd"; + static const char *lockfile = "/var/run/usbmuxd.pid"; +>>>>>>> Port to android, build succeed with android-ndk-r8e on mac osx 10.9. #endif int should_exit; diff --git a/src/usbmuxd-proto.h b/src/usbmuxd-proto.h index 7842975d..f8131e46 100644 --- a/src/usbmuxd-proto.h +++ b/src/usbmuxd-proto.h @@ -30,8 +30,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #if defined(WIN32) || defined(__CYGWIN__) #define USBMUXD_SOCKET_PORT 27015 #else +#ifdef ANDROID +#define USBMUXD_SOCKET_FILE "/data/local/tmp/usbmuxd" +#else #define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" #endif +#endif #ifdef __cplusplus extern "C" { From b4fa7b2e09f8cf12db5f2ced1ab6fd6597c93090 Mon Sep 17 00:00:00 2001 From: lunzic Date: Fri, 4 Apr 2014 20:29:46 +0800 Subject: [PATCH 68/70] port to android --- libusbmuxd/libusbmuxd.c | 978 ------------------------------------- libusbmuxd/usbmuxd-proto.h | 101 ---- src/device.c | 20 - src/main.c | 12 - src/usbmuxd-proto.h | 10 +- 5 files changed, 5 insertions(+), 1116 deletions(-) delete mode 100644 libusbmuxd/libusbmuxd.c delete mode 100644 libusbmuxd/usbmuxd-proto.h diff --git a/libusbmuxd/libusbmuxd.c b/libusbmuxd/libusbmuxd.c deleted file mode 100644 index 64d1a489..00000000 --- a/libusbmuxd/libusbmuxd.c +++ /dev/null @@ -1,978 +0,0 @@ -/* - libusbmuxd - client library to talk to usbmuxd - -Copyright (C) 2009-2010 Nikias Bassen -Copyright (C) 2009 Paul Sladen -Copyright (C) 2009 Martin Szulecki - -This library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 2.1 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include -#include -#include -#include -#include -#ifdef WIN32 -#include -#include -#define sleep(x) Sleep(x*1000) -#ifndef EPROTO -#define EPROTO 134 -#endif -#ifndef EBADMSG -#define EBADMSG 104 -#endif -#else -#include -#include -#include -#endif - -#ifdef HAVE_INOTIFY -#include -#define EVENT_SIZE (sizeof (struct inotify_event)) -#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16)) -#define USBMUXD_DIRNAME "/var/run" -#define USBMUXD_SOCKET_NAME "usbmuxd" -#endif /* HAVE_INOTIFY */ - -#include -#include - -#ifdef HAVE_PLIST -#include -#define PLIST_BUNDLE_ID "com.marcansoft.usbmuxd" -#define PLIST_CLIENT_VERSION_STRING "usbmuxd built for freedom" -#define PLIST_PROGNAME "libusbmuxd" -#endif - -// usbmuxd public interface -#include "usbmuxd.h" -// usbmuxd protocol -#include "usbmuxd-proto.h" -// socket utility functions -#include "sock_stuff.h" -// misc utility functions -#include "utils.h" - -static int libusbmuxd_debug = 0; -#define DEBUG(x, y, ...) if (x <= libusbmuxd_debug) fprintf(stderr, (y), __VA_ARGS__); - -static struct collection devices; -static usbmuxd_event_cb_t event_cb = NULL; -#ifdef WIN32 -HANDLE devmon = NULL; -CRITICAL_SECTION mutex; -static int mutex_initialized = 0; -#define LOCK if (!mutex_initialized) { InitializeCriticalSection(&mutex); mutex_initialized = 1; } EnterCriticalSection(&mutex); -#define UNLOCK LeaveCriticalSection(&mutex); -#else -pthread_t devmon; -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -#define LOCK pthread_mutex_lock(&mutex) -#define UNLOCK pthread_mutex_unlock(&mutex) -#endif -static int listenfd = -1; - -static int use_tag = 0; -static int proto_version = 0; - -/** - * Finds a device info record by its handle. - * if the record is not found, NULL is returned. - */ -static usbmuxd_device_info_t *devices_find(int handle) -{ - FOREACH(usbmuxd_device_info_t *dev, &devices) { - if (dev && dev->handle == handle) { - return dev; - } - } ENDFOREACH - return NULL; -} - -/** - * Creates a socket connection to usbmuxd. - * For Mac/Linux it is a unix domain socket, - * for Windows it is a tcp socket. - */ -static int connect_usbmuxd_socket() -{ -#if defined(WIN32) || defined(__CYGWIN__) - return connect_socket("127.0.0.1", USBMUXD_SOCKET_PORT); -#else - return connect_unix_socket(USBMUXD_SOCKET_FILE); -#endif -} - -static int receive_packet(int sfd, struct usbmuxd_header *header, void **payload, int timeout) -{ - int recv_len; - struct usbmuxd_header hdr; - char *payload_loc = NULL; - - header->length = 0; - header->version = 0; - header->message = 0; - header->tag = 0; - - recv_len = recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, timeout); - if (recv_len < 0) { - return recv_len; - } else if (recv_len < sizeof(hdr)) { - return recv_len; - } - - uint32_t payload_size = hdr.length - sizeof(hdr); - if (payload_size > 0) { - payload_loc = (char*)malloc(payload_size); - if (recv_buf_timeout(sfd, payload_loc, payload_size, 0, 5000) != payload_size) { - DEBUG(1, "%s: Error receiving payload of size %d\n", __func__, payload_size); - free(payload_loc); - return -EBADMSG; - } - } - -#ifdef HAVE_PLIST - if (hdr.message == MESSAGE_PLIST) { - char *message = NULL; - plist_t plist = NULL; - plist_from_xml(payload_loc, payload_size, &plist); - free(payload_loc); - - if (!plist) { - DEBUG(1, "%s: Error getting plist from payload!\n", __func__); - return -EBADMSG; - } - - plist_t node = plist_dict_get_item(plist, "MessageType"); - if (plist_get_node_type(node) != PLIST_STRING) { - DEBUG(1, "%s: Error getting message type from plist!\n", __func__); - free(plist); - return -EBADMSG; - } - - plist_get_string_val(node, &message); - if (message) { - uint64_t val = 0; - if (strcmp(message, "Result") == 0) { - /* result message */ - uint32_t dwval = 0; - plist_t n = plist_dict_get_item(plist, "Number"); - plist_get_uint_val(n, &val); - *payload = malloc(sizeof(uint32_t)); - dwval = val; - memcpy(*payload, &dwval, sizeof(dwval)); - hdr.length = sizeof(hdr) + sizeof(dwval); - hdr.message = MESSAGE_RESULT; - } else if (strcmp(message, "Attached") == 0) { - /* device add message */ - struct usbmuxd_device_record *dev = NULL; - plist_t props = plist_dict_get_item(plist, "Properties"); - if (!props) { - DEBUG(1, "%s: Could not get properties for message '%s' from plist!\n", __func__, message); - free(message); - plist_free(plist); - return -EBADMSG; - } - dev = (struct usbmuxd_device_record*)malloc(sizeof(struct usbmuxd_device_record)); - memset(dev, 0, sizeof(struct usbmuxd_device_record)); - - plist_t n = plist_dict_get_item(props, "DeviceID"); - plist_get_uint_val(n, &val); - dev->device_id = (uint32_t)val; - - n = plist_dict_get_item(props, "ProductID"); - plist_get_uint_val(n, &val); - dev->product_id = (uint32_t)val; - - n = plist_dict_get_item(props, "SerialNumber"); - char *strval = NULL; - plist_get_string_val(n, &strval); - if (strval) { - strncpy(dev->serial_number, strval, 255); - free(strval); - } - n = plist_dict_get_item(props, "LocationID"); - plist_get_uint_val(n, &val); - dev->location = (uint32_t)val; - *payload = (void*)dev; - hdr.length = sizeof(hdr) + sizeof(struct usbmuxd_device_record); - hdr.message = MESSAGE_DEVICE_ADD; - } else if (strcmp(message, "Detached") == 0) { - /* device remove message */ - uint32_t dwval = 0; - plist_t n = plist_dict_get_item(plist, "DeviceID"); - if (n) { - plist_get_uint_val(n, &val); - *payload = malloc(sizeof(uint32_t)); - dwval = val; - memcpy(*payload, &dwval, sizeof(dwval)); - hdr.length = sizeof(hdr) + sizeof(dwval); - hdr.message = MESSAGE_DEVICE_REMOVE; - } - } else { - DEBUG(1, "%s: Unexpected message '%s' in plist!\n", __func__, message); - free(message); - plist_free(plist); - return -EBADMSG; - } - free(message); - } - plist_free(plist); - } else -#endif - { - *payload = payload_loc; - } - - memcpy(header, &hdr, sizeof(hdr)); - - return hdr.length; -} - -/** - * Retrieves the result code to a previously sent request. - */ -static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result) -{ - struct usbmuxd_header hdr; - int recv_len; - uint32_t *res = NULL; - - if (!result) { - return -EINVAL; - } - *result = -1; - - if ((recv_len = receive_packet(sfd, &hdr, (void**)&res, 5000)) < 0) { - DEBUG(1, "%s: Error receiving packet: %d\n", __func__, errno); - if (res) - free(res); - return -errno; - } - if (recv_len < sizeof(hdr)) { - DEBUG(1, "%s: Received packet is too small!\n", __func__); - if (res) - free(res); - return -EPROTO; - } - - if (hdr.message == MESSAGE_RESULT) { - int ret = 0; - if (res && (hdr.tag == tag)) { - memcpy(result, res, sizeof(uint32_t)); - ret = 1; - } - if (res) - free(res); - return ret; - } - DEBUG(1, "%s: Unexpected message of type %d received!\n", __func__, hdr.message); - if (res) - free(res); - return -EPROTO; -} - -static int send_packet(int sfd, uint32_t message, uint32_t tag, void *payload, uint32_t payload_size) -{ - struct usbmuxd_header header; - - header.length = sizeof(struct usbmuxd_header); - header.version = proto_version; - header.message = message; - header.tag = tag; - if (payload && (payload_size > 0)) { - header.length += payload_size; - } - int sent = send_buf(sfd, &header, sizeof(header)); - if (sent != sizeof(header)) { - DEBUG(1, "%s: ERROR: could not send packet header\n", __func__); - return -1; - } - if (payload && (payload_size > 0)) { - sent += send_buf(sfd, payload, payload_size); - } - if (sent != (int)header.length) { - DEBUG(1, "%s: ERROR: could not send whole packet\n", __func__); - close_socket(sfd); - return -1; - } - return sent; -} - -static int send_listen_packet(int sfd, uint32_t tag) -{ - int res = 0; -#ifdef HAVE_PLIST - if (proto_version == 1) { - /* plist packet */ - char *payload = NULL; - uint32_t payload_size = 0; - plist_t plist; - - /* construct message plist */ - plist = plist_new_dict(); - plist_dict_insert_item(plist, "BundleID", plist_new_string(PLIST_BUNDLE_ID)); - plist_dict_insert_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING)); - plist_dict_insert_item(plist, "MessageType", plist_new_string("Listen")); - plist_dict_insert_item(plist, "ProgName", plist_new_string(PLIST_PROGNAME)); - plist_to_xml(plist, &payload, &payload_size); - plist_free(plist); - - res = send_packet(sfd, MESSAGE_PLIST, tag, payload, payload_size); - free(payload); - } else -#endif - { - /* binary packet */ - res = send_packet(sfd, MESSAGE_LISTEN, tag, NULL, 0); - } - return res; -} - -static int send_connect_packet(int sfd, uint32_t tag, uint32_t device_id, uint16_t port) -{ - int res = 0; -#ifdef HAVE_PLIST - if (proto_version == 1) { - /* plist packet */ - char *payload = NULL; - uint32_t payload_size = 0; - plist_t plist; - - /* construct message plist */ - plist = plist_new_dict(); - plist_dict_insert_item(plist, "BundleID", plist_new_string(PLIST_BUNDLE_ID)); - plist_dict_insert_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING)); - plist_dict_insert_item(plist, "MessageType", plist_new_string("Connect")); - plist_dict_insert_item(plist, "DeviceID", plist_new_uint(device_id)); - plist_dict_insert_item(plist, "PortNumber", plist_new_uint(htons(port))); - plist_dict_insert_item(plist, "ProgName", plist_new_string(PLIST_PROGNAME)); - plist_to_xml(plist, &payload, &payload_size); - plist_free(plist); - - res = send_packet(sfd, MESSAGE_PLIST, tag, (void*)payload, payload_size); - free(payload); - } else -#endif - { - /* binary packet */ - struct { - uint32_t device_id; - uint16_t port; - uint16_t reserved; - } conninfo; - - conninfo.device_id = device_id; - conninfo.port = htons(port); - conninfo.reserved = 0; - - res = send_packet(sfd, MESSAGE_CONNECT, tag, &conninfo, sizeof(conninfo)); - } - return res; -} - -/** - * Generates an event, i.e. calls the callback function. - * A reference to a populated usbmuxd_event_t with information about the event - * and the corresponding device will be passed to the callback function. - */ -static void generate_event(usbmuxd_event_cb_t callback, const usbmuxd_device_info_t *dev, enum usbmuxd_event_type event, void *user_data) -{ - usbmuxd_event_t ev; - - if (!callback || !dev) { - return; - } - - ev.event = event; - memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t)); - - callback(&ev, user_data); -} - -static int usbmuxd_listen_poll() -{ - int sfd; - - sfd = connect_usbmuxd_socket(); - if (sfd < 0) { - while (event_cb) { - if ((sfd = connect_usbmuxd_socket()) > 0) { - break; - } - sleep(1); - } - } - - return sfd; -} - -#ifdef HAVE_INOTIFY -static int use_inotify = 1; - -static int usbmuxd_listen_inotify() -{ - int inot_fd; - int watch_d; - int sfd; - - if (!use_inotify) { - return -2; - } - - sfd = connect_usbmuxd_socket(); - if (sfd >= 0) - return sfd; - - sfd = -1; - inot_fd = inotify_init (); - if (inot_fd < 0) { - DEBUG(1, "%s: Failed to setup inotify\n", __func__); - return -2; - } - - /* inotify is setup, listen for events that concern us */ - watch_d = inotify_add_watch (inot_fd, USBMUXD_DIRNAME, IN_CREATE); - if (watch_d < 0) { - DEBUG(1, "%s: Failed to setup watch descriptor for socket dir\n", __func__); - close (inot_fd); - return -2; - } - - while (1) { - ssize_t len, i; - char buff[EVENT_BUF_LEN] = {0}; - - i = 0; - len = read (inot_fd, buff, EVENT_BUF_LEN -1); - if (len < 0) - goto end; - while (i < len) { - struct inotify_event *pevent = (struct inotify_event *) & buff[i]; - - /* check that it's ours */ - if (pevent->mask & IN_CREATE && - pevent->len && - pevent->name != NULL && - strcmp(pevent->name, USBMUXD_SOCKET_NAME) == 0) { - sfd = connect_usbmuxd_socket (); - goto end; - } - i += EVENT_SIZE + pevent->len; - } - } - -end: - inotify_rm_watch(inot_fd, watch_d); - close(inot_fd); - - return sfd; -} -#endif /* HAVE_INOTIFY */ - -/** - * Tries to connect to usbmuxd and wait if it is not running. - */ -static int usbmuxd_listen() -{ - int sfd; - uint32_t res = -1; - -#ifdef HAVE_PLIST -retry: -#endif - -#ifdef HAVE_INOTIFY - sfd = usbmuxd_listen_inotify(); - if (sfd == -2) - sfd = usbmuxd_listen_poll(); -#else - sfd = usbmuxd_listen_poll(); -#endif - - if (sfd < 0) { - DEBUG(1, "%s: ERROR: usbmuxd was supposed to be running here...\n", __func__); - return sfd; - } - - use_tag++; - LOCK; - if (send_listen_packet(sfd, use_tag) <= 0) { - UNLOCK; - DEBUG(1, "%s: ERROR: could not send listen packet\n", __func__); - close_socket(sfd); - return -1; - } - if (usbmuxd_get_result(sfd, use_tag, &res) && (res != 0)) { - UNLOCK; - close_socket(sfd); -#ifdef HAVE_PLIST - if ((res == RESULT_BADVERSION) && (proto_version != 1)) { - proto_version = 1; - goto retry; - } -#endif - DEBUG(1, "%s: ERROR: did not get OK but %d\n", __func__, res); - return -1; - } - UNLOCK; - - return sfd; -} - -/** - * Waits for an event to occur, i.e. a packet coming from usbmuxd. - * Calls generate_event to pass the event via callback to the client program. - */ -int get_next_event(int sfd, usbmuxd_event_cb_t callback, void *user_data) -{ - struct usbmuxd_header hdr; - void *payload = NULL; - - /* block until we receive something */ - if (receive_packet(sfd, &hdr, &payload, 0) < 0) { - // when then usbmuxd connection fails, - // generate remove events for every device that - // is still present so applications know about it - FOREACH(usbmuxd_device_info_t *dev, &devices) { - generate_event(callback, dev, UE_DEVICE_REMOVE, user_data); - collection_remove(&devices, dev); - free(dev); - } ENDFOREACH - return -EIO; - } - - if ((hdr.length > sizeof(hdr)) && !payload) { - DEBUG(1, "%s: Invalid packet received, payload is missing!\n", __func__); - return -EBADMSG; - } - - if (hdr.message == MESSAGE_DEVICE_ADD) { - struct usbmuxd_device_record *dev = payload; - usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t)); - if (!devinfo) { - DEBUG(1, "%s: Out of memory!\n", __func__); - free(payload); - return -1; - } - - devinfo->handle = dev->device_id; - devinfo->product_id = dev->product_id; - memset(devinfo->udid, '\0', sizeof(devinfo->udid)); - memcpy(devinfo->udid, dev->serial_number, sizeof(devinfo->udid)); - - if (strcasecmp(devinfo->udid, "ffffffffffffffffffffffffffffffffffffffff") == 0) { - sprintf(devinfo->udid + 32, "%08x", devinfo->handle); - } - - collection_add(&devices, devinfo); - generate_event(callback, devinfo, UE_DEVICE_ADD, user_data); - } else if (hdr.message == MESSAGE_DEVICE_REMOVE) { - uint32_t handle; - usbmuxd_device_info_t *devinfo; - - memcpy(&handle, payload, sizeof(uint32_t)); - - devinfo = devices_find(handle); - if (!devinfo) { - DEBUG(1, "%s: WARNING: got device remove message for handle %d, but couldn't find the corresponding handle in the device list. This event will be ignored.\n", __func__, handle); - } else { - generate_event(callback, devinfo, UE_DEVICE_REMOVE, user_data); - collection_remove(&devices, devinfo); - free(devinfo); - } - } else if (hdr.length > 0) { - DEBUG(1, "%s: Unexpected message type %d length %d received!\n", __func__, hdr.message, hdr.length); - } - if (payload) { - free(payload); - } - return 0; -} - -static void device_monitor_cleanup(void* data) -{ - FOREACH(usbmuxd_device_info_t *dev, &devices) { - collection_remove(&devices, dev); - free(dev); - } ENDFOREACH - collection_free(&devices); - - close_socket(listenfd); - listenfd = -1; -} - -/** - * Device Monitor thread function. - * - * This function sets up a connection to usbmuxd - */ -static void *device_monitor(void *data) -{ - collection_init(&devices); - -#ifndef WIN32 - pthread_cleanup_push(device_monitor_cleanup, NULL); -#endif - while (event_cb) { - - listenfd = usbmuxd_listen(); - if (listenfd < 0) { - continue; - } - - while (event_cb) { - int res = get_next_event(listenfd, event_cb, data); - if (res < 0) { - break; - } - } - } - -#ifndef WIN32 - pthread_cleanup_pop(1); -#else - device_monitor_cleanup(NULL); -#endif - return NULL; -} - -int usbmuxd_subscribe(usbmuxd_event_cb_t callback, void *user_data) -{ - int res; - - if (!callback) { - return -EINVAL; - } - event_cb = callback; - -#ifdef WIN32 - res = 0; - devmon = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)device_monitor, user_data, 0, NULL); - if (devmon == NULL) { - res = GetLastError(); - } -#else - res = pthread_create(&devmon, NULL, device_monitor, user_data); -#endif - if (res != 0) { - DEBUG(1, "%s: ERROR: Could not start device watcher thread!\n", __func__); - return res; - } - return 0; -} - -int usbmuxd_unsubscribe() -{ - event_cb = NULL; - - shutdown_socket(listenfd, SHUT_RDWR); - -#ifdef WIN32 - if (devmon != NULL) { - WaitForSingleObject(devmon, INFINITE); - } -#else - if (pthread_kill(devmon, 0) == 0) { -#ifdef ANDROID -#else - pthread_cancel(devmon); -#endif - pthread_join(devmon, NULL); - } -#endif - - return 0; -} - -int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) -{ - int sfd; - int listen_success = 0; - uint32_t res; - struct collection tmpdevs; - usbmuxd_device_info_t *newlist = NULL; - struct usbmuxd_header hdr; - struct usbmuxd_device_record *dev; - int dev_cnt = 0; - void *payload = NULL; - - *device_list = NULL; - -#ifdef HAVE_PLIST -retry: -#endif - sfd = connect_usbmuxd_socket(); - if (sfd < 0) { - DEBUG(1, "%s: error opening socket!\n", __func__); - return sfd; - } - - use_tag++; - LOCK; - if (send_listen_packet(sfd, use_tag) > 0) { - res = -1; - // get response - if (usbmuxd_get_result(sfd, use_tag, &res) && (res == 0)) { - listen_success = 1; - } else { - UNLOCK; - close_socket(sfd); -#ifdef HAVE_PLIST - if ((res == RESULT_BADVERSION) && (proto_version != 1)) { - proto_version = 1; - goto retry; - } -#endif - DEBUG(1, "%s: Did not get response to scan request (with result=0)...\n", __func__); - return res; - } - } - - if (!listen_success) { - UNLOCK; - DEBUG(1, "%s: Could not send listen request!\n", __func__); - return -1; - } - - collection_init(&tmpdevs); - - // receive device list - while (1) { - if (receive_packet(sfd, &hdr, &payload, 1000) > 0) { - if (hdr.message == MESSAGE_DEVICE_ADD) { - dev = payload; - usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t)); - if (!devinfo) { - UNLOCK; - DEBUG(1, "%s: Out of memory!\n", __func__); - free(payload); - return -1; - } - - devinfo->handle = dev->device_id; - devinfo->product_id = dev->product_id; - memset(devinfo->udid, '\0', sizeof(devinfo->udid)); - memcpy(devinfo->udid, dev->serial_number, sizeof(devinfo->udid)); - - if (strcasecmp(devinfo->udid, "ffffffffffffffffffffffffffffffffffffffff") == 0) { - sprintf(devinfo->udid + 32, "%08x", devinfo->handle); - } - - collection_add(&tmpdevs, devinfo); - - } else if (hdr.message == MESSAGE_DEVICE_REMOVE) { - uint32_t handle; - usbmuxd_device_info_t *devinfo = NULL; - - memcpy(&handle, payload, sizeof(uint32_t)); - - FOREACH(usbmuxd_device_info_t *di, &tmpdevs) { - if (di && di->handle == handle) { - devinfo = di; - break; - } - } ENDFOREACH - if (devinfo) { - collection_remove(&tmpdevs, devinfo); - free(devinfo); - } - } else { - DEBUG(1, "%s: Unexpected message %d\n", __func__, hdr.message); - } - if (payload) - free(payload); - } else { - // we _should_ have all of them now. - // or perhaps an error occured. - break; - } - } - UNLOCK; - - // explicitly close connection - close_socket(sfd); - - // create copy of device info entries from collection - newlist = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t) * (collection_count(&tmpdevs) + 1)); - dev_cnt = 0; - FOREACH(usbmuxd_device_info_t *di, &tmpdevs) { - if (di) { - memcpy(&newlist[dev_cnt], di, sizeof(usbmuxd_device_info_t)); - free(di); - dev_cnt++; - } - } ENDFOREACH - collection_free(&tmpdevs); - - memset(&newlist[dev_cnt], 0, sizeof(usbmuxd_device_info_t)); - *device_list = newlist; - - return dev_cnt; -} - -int usbmuxd_device_list_free(usbmuxd_device_info_t **device_list) -{ - if (device_list) { - free(*device_list); - } - return 0; -} - -int usbmuxd_get_device_by_udid(const char *udid, usbmuxd_device_info_t *device) -{ - usbmuxd_device_info_t *dev_list = NULL; - - if (!device) { - return -EINVAL; - } - if (usbmuxd_get_device_list(&dev_list) < 0) { - return -ENODEV; - } - - int i; - int result = 0; - for (i = 0; dev_list[i].handle > 0; i++) { - if (!udid) { - device->handle = dev_list[i].handle; - device->product_id = dev_list[i].product_id; - strcpy(device->udid, dev_list[i].udid); - result = 1; - break; - } - if (!strcmp(udid, dev_list[i].udid)) { - device->handle = dev_list[i].handle; - device->product_id = dev_list[i].product_id; - strcpy(device->udid, dev_list[i].udid); - result = 1; - break; - } - } - - free(dev_list); - - return result; -} - -int usbmuxd_connect(const int handle, const unsigned short port) -{ - int sfd; - int connected = 0; - uint32_t res = -1; - -#ifdef HAVE_PLIST -retry: -#endif - sfd = connect_usbmuxd_socket(); - if (sfd < 0) { - DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n", - __func__, strerror(errno)); - return sfd; - } - - use_tag++; - if (send_connect_packet(sfd, use_tag, (uint32_t)handle, (uint16_t)port) <= 0) { - DEBUG(1, "%s: Error sending connect message!\n", __func__); - } else { - // read ACK - DEBUG(2, "%s: Reading connect result...\n", __func__); - if (usbmuxd_get_result(sfd, use_tag, &res)) { - if (res == 0) { - DEBUG(2, "%s: Connect success!\n", __func__); - connected = 1; - } else { -#ifdef HAVE_PLIST - if ((res == RESULT_BADVERSION) && (proto_version == 0)) { - proto_version = 1; - close_socket(sfd); - goto retry; - } -#endif - DEBUG(1, "%s: Connect failed, Error code=%d\n", __func__, res); - } - } - } - - if (connected) { - return sfd; - } - - close_socket(sfd); - - return -1; -} - -int usbmuxd_disconnect(int sfd) -{ - return close_socket(sfd); -} - -int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes) -{ - int num_sent; - - if (sfd < 0) { - return -EINVAL; - } - - num_sent = send(sfd, (void*)data, len, 0); - if (num_sent < 0) { - *sent_bytes = 0; - DEBUG(1, "%s: Error %d when sending: %s\n", __func__, num_sent, strerror(errno)); - return num_sent; - } else if ((uint32_t)num_sent < len) { - DEBUG(1, "%s: Warning: Did not send enough (only %d of %d)\n", __func__, num_sent, len); - } - - *sent_bytes = num_sent; - - return 0; -} - -int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) -{ - int num_recv = recv_buf_timeout(sfd, (void*)data, len, 0, timeout); - if (num_recv < 0) { - *recv_bytes = 0; - return num_recv; - } - - *recv_bytes = num_recv; - - return 0; -} - -int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes) -{ - return usbmuxd_recv_timeout(sfd, data, len, recv_bytes, 5000); -} - -void libusbmuxd_set_use_inotify(int set) -{ -#ifdef HAVE_INOTIFY - use_inotify = set; -#endif - return; -} - -void libusbmuxd_set_debug_level(int level) -{ - libusbmuxd_debug = level; - sock_stuff_set_verbose(level); -} diff --git a/libusbmuxd/usbmuxd-proto.h b/libusbmuxd/usbmuxd-proto.h deleted file mode 100644 index 33e58df6..00000000 --- a/libusbmuxd/usbmuxd-proto.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - libusbmuxd - client library to talk to usbmuxd - -Copyright (C) 2009 Paul Sladen -Copyright (C) 2009 Nikias Bassen -Copyright (C) 2009 Hector Martin "marcan" - -This library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 2.1 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -/* Protocol defintion for usbmuxd proxy protocol */ -#ifndef __USBMUXD_PROTO_H -#define __USBMUXD_PROTO_H - -#include -#define USBMUXD_PROTOCOL_VERSION 0 - -#if defined(WIN32) || defined(__CYGWIN__) -#define USBMUXD_SOCKET_PORT 27015 -#else -#ifdef ANDROID -#define USBMUXD_SOCKET_FILE "/data/local/tmp/usbmuxd" -#else -#define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -enum usbmuxd_result { - RESULT_OK = 0, - RESULT_BADCOMMAND = 1, - RESULT_BADDEV = 2, - RESULT_CONNREFUSED = 3, - // ??? - // ??? - RESULT_BADVERSION = 6, -}; - -enum usbmuxd_msgtype { - MESSAGE_RESULT = 1, - MESSAGE_CONNECT = 2, - MESSAGE_LISTEN = 3, - MESSAGE_DEVICE_ADD = 4, - MESSAGE_DEVICE_REMOVE = 5, - //??? - //??? - MESSAGE_PLIST = 8, -}; - -struct usbmuxd_header { - uint32_t length; // length of message, including header - uint32_t version; // protocol version - uint32_t message; // message type - uint32_t tag; // responses to this query will echo back this tag -} __attribute__((__packed__)); - -struct usbmuxd_result_msg { - struct usbmuxd_header header; - uint32_t result; -} __attribute__((__packed__)); - -struct usbmuxd_connect_request { - struct usbmuxd_header header; - uint32_t device_id; - uint16_t port; // TCP port number - uint16_t reserved; // set to zero -} __attribute__((__packed__)); - -struct usbmuxd_listen_request { - struct usbmuxd_header header; -} __attribute__((__packed__)); - -struct usbmuxd_device_record { - uint32_t device_id; - uint16_t product_id; - char serial_number[256]; - uint16_t padding; - uint32_t location; -} __attribute__((__packed__)); - -#ifdef __cplusplus -} -#endif - -#endif /* __USBMUXD_PROTO_H */ diff --git a/src/device.c b/src/device.c index 36b3adcf..5366a15b 100644 --- a/src/device.c +++ b/src/device.c @@ -547,18 +547,6 @@ static void device_version_input(struct mux_device *dev, struct version_header * preflight_worker_device_add(&info); } -<<<<<<< HEAD -<<<<<<< HEAD - -#ifdef ANDROID - static void device_tcp_input(struct mux_device *dev, struct tcphdr_bsd *th, unsigned char *payload, uint32_t payload_length) -#else - static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) -#endif -======= -======= -<<<<<<< HEAD:src/device.c ->>>>>>> Port to android, build succeed with android-ndk-r8e on mac osx 10.9. /** * Handle an incoming TCP packet from the device. * @@ -567,19 +555,11 @@ static void device_version_input(struct mux_device *dev, struct version_header * * @param payload Payload data. * @param payload_length Number of bytes in payload. */ -static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) -<<<<<<< HEAD ->>>>>>> client: add a bunch of comments and function docs -======= -======= - #ifdef ANDROID static void device_tcp_input(struct mux_device *dev, struct tcphdr_bsd *th, unsigned char *payload, uint32_t payload_length) #else static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, uint32_t payload_length) #endif ->>>>>>> Port to android, build succeed with android-ndk-r8e on mac osx 10.9.:daemon/device.c ->>>>>>> Port to android, build succeed with android-ndk-r8e on mac osx 10.9. { uint16_t sport = ntohs(th->th_dport); uint16_t dport = ntohs(th->th_sport); diff --git a/src/main.c b/src/main.c index e7f77365..06ef279d 100644 --- a/src/main.c +++ b/src/main.c @@ -52,21 +52,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #ifdef ANDROID static const char *socket_path = "/data/local/tmp/usbmuxd"; static const char *lockfile = "/data/local/tmp/usbmuxd.pid"; -<<<<<<< HEAD - static const char *userprefdir = "/data/local/tmp/lockdown"; #else static const char *socket_path = "/var/run/usbmuxd"; static const char *lockfile = "/var/run/usbmuxd.pid"; - static const char *userprefdir = "/var/lib/lockdown"; -#endif - -#ifdef HAVE_LIBIMOBILEDEVICE -extern const char* userpref_get_config_dir(); -======= -#else - static const char *socket_path = "/var/run/usbmuxd"; - static const char *lockfile = "/var/run/usbmuxd.pid"; ->>>>>>> Port to android, build succeed with android-ndk-r8e on mac osx 10.9. #endif int should_exit; diff --git a/src/usbmuxd-proto.h b/src/usbmuxd-proto.h index f8131e46..957c1f2c 100644 --- a/src/usbmuxd-proto.h +++ b/src/usbmuxd-proto.h @@ -30,11 +30,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #if defined(WIN32) || defined(__CYGWIN__) #define USBMUXD_SOCKET_PORT 27015 #else -#ifdef ANDROID -#define USBMUXD_SOCKET_FILE "/data/local/tmp/usbmuxd" -#else -#define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" -#endif + #ifdef ANDROID + #define USBMUXD_SOCKET_FILE "/data/local/tmp/usbmuxd" + #else + #define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" + #endif #endif #ifdef __cplusplus From 9238535e6d9a4645d8605c7114baf1ded46548e1 Mon Sep 17 00:00:00 2001 From: lunzic Date: Tue, 8 Apr 2014 10:21:47 +0800 Subject: [PATCH 69/70] fixed on android --- src/conf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/conf.c b/src/conf.c index 2a90922b..cc02a711 100644 --- a/src/conf.c +++ b/src/conf.c @@ -127,7 +127,11 @@ const char *config_get_config_dir() #ifdef __APPLE__ base_config_dir = strdup("/var/db"); #else - base_config_dir = strdup("/var/lib"); + #ifdef ANDROID + base_config_dir = strdup("/data/local/tmp"); + #else + base_config_dir = strdup("/var/lib"); + #endif #endif #endif __config_dir = string_concat(base_config_dir, DIR_SEP_S, CONFIG_DIR, NULL); From d43f7c05c21def4bb2d1ed07d4e02a193a7f0667 Mon Sep 17 00:00:00 2001 From: lunzii Date: Wed, 9 Apr 2014 15:12:01 +0800 Subject: [PATCH 70/70] add android debug info --- src/conf.c | 6 +----- src/log.c | 7 +++++++ src/main.c | 9 ++------- src/usbmuxd-proto.h | 6 +----- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/conf.c b/src/conf.c index cc02a711..2a90922b 100644 --- a/src/conf.c +++ b/src/conf.c @@ -127,11 +127,7 @@ const char *config_get_config_dir() #ifdef __APPLE__ base_config_dir = strdup("/var/db"); #else - #ifdef ANDROID - base_config_dir = strdup("/data/local/tmp"); - #else - base_config_dir = strdup("/var/lib"); - #endif + base_config_dir = strdup("/var/lib"); #endif #endif __config_dir = string_concat(base_config_dir, DIR_SEP_S, CONFIG_DIR, NULL); diff --git a/src/log.c b/src/log.c index 2d22e945..ec308b8c 100644 --- a/src/log.c +++ b/src/log.c @@ -31,6 +31,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include +#ifdef ANDROID +#include +#define DEBUG(...) __android_log_print(ANDROID_LOG_DEBUG, "usbmuxd", __VA_ARGS__) +#endif + #include "log.h" unsigned int log_level = LL_WARNING; @@ -63,6 +68,7 @@ static int level_to_syslog_level(int level) void usbmuxd_log(enum loglevel level, const char *fmt, ...) { + va_list ap; char *fs; struct timeval ts; @@ -89,6 +95,7 @@ void usbmuxd_log(enum loglevel level, const char *fmt, ...) } else { vfprintf(stderr, fs, ap); } + DEBUG(fs, ap); va_end(ap); free(fs); diff --git a/src/main.c b/src/main.c index 06ef279d..60faa338 100644 --- a/src/main.c +++ b/src/main.c @@ -49,13 +49,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "client.h" #include "conf.h" -#ifdef ANDROID - static const char *socket_path = "/data/local/tmp/usbmuxd"; - static const char *lockfile = "/data/local/tmp/usbmuxd.pid"; -#else - static const char *socket_path = "/var/run/usbmuxd"; - static const char *lockfile = "/var/run/usbmuxd.pid"; -#endif +static const char *socket_path = "/var/run/usbmuxd"; +static const char *lockfile = "/var/run/usbmuxd.pid"; int should_exit; int should_discover; diff --git a/src/usbmuxd-proto.h b/src/usbmuxd-proto.h index 957c1f2c..7842975d 100644 --- a/src/usbmuxd-proto.h +++ b/src/usbmuxd-proto.h @@ -30,11 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #if defined(WIN32) || defined(__CYGWIN__) #define USBMUXD_SOCKET_PORT 27015 #else - #ifdef ANDROID - #define USBMUXD_SOCKET_FILE "/data/local/tmp/usbmuxd" - #else - #define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" - #endif +#define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" #endif #ifdef __cplusplus