From 5390060ec90bed0f565698a389cebc57c09c3ac8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 7 Nov 2019 23:25:55 +0100 Subject: Add propert support for network (WiFi) devices via new idevice_new_with_options() --- include/libimobiledevice/libimobiledevice.h | 56 ++++++++++++++++-- src/idevice.c | 92 ++++++++++++++++++++++------- src/idevice.h | 8 +-- 3 files changed, 124 insertions(+), 32 deletions(-) diff --git a/include/libimobiledevice/libimobiledevice.h b/include/libimobiledevice/libimobiledevice.h index 8f8589d..c1d5460 100644 --- a/include/libimobiledevice/libimobiledevice.h +++ b/include/libimobiledevice/libimobiledevice.h @@ -3,6 +3,7 @@ * @brief Device/Connection handling and communication * \internal * + * Copyright (c) 2010-2019 Nikias Bassen All Rights Reserved. * Copyright (c) 2010-2014 Martin Szulecki All Rights Reserved. * Copyright (c) 2014 Christophe Fergeau All Rights Reserved. * Copyright (c) 2008 Jonathan Beck All Rights Reserved. @@ -51,6 +52,26 @@ typedef idevice_private *idevice_t; /**< The device handle. */ typedef struct idevice_connection_private idevice_connection_private; typedef idevice_connection_private *idevice_connection_t; /**< The connection handle. */ +/** Options for idevice_new_with_options() */ +enum idevice_options { + IDEVICE_LOOKUP_USBMUX = 1 << 1, /**< include USBMUX devices during lookup */ + IDEVICE_LOOKUP_NETWORK = 1 << 2, /**< include network devices during lookup */ + IDEVICE_LOOKUP_PREFER_NETWORK = 1 << 3 /**< prefer network connection if device is available via USBMUX *and* network */ +}; + +/** Type of connection a device is available on */ +enum idevice_connection_type { + CONNECTION_USBMUXD = 1, + CONNECTION_NETWORK +}; + +struct idevice_info { + char *udid; + enum idevice_connection_type conn_type; + void* conn_data; +}; +typedef struct idevice_info* idevice_info_t; + /* discovery (events/asynchronous) */ /** The event type for device add or removal */ enum idevice_event_type { @@ -64,7 +85,7 @@ enum idevice_event_type { typedef struct { enum idevice_event_type event; /**< The event type. */ const char *udid; /**< The device unique id. */ - int conn_type; /**< The connection type. Currently only 1 for usbmuxd. */ + enum idevice_connection_type conn_type; /**< The connection type. */ } idevice_event_t; /* event callback function prototype */ @@ -125,11 +146,15 @@ idevice_error_t idevice_device_list_free(char **devices); /* device structure creation and destruction */ /** - * Creates an idevice_t structure for the device specified by udid, - * if the device is available. + * Creates an idevice_t structure for the device specified by UDID, + * if the device is available (USBMUX devices only). * * @note The resulting idevice_t structure has to be freed with * idevice_free() if it is no longer used. + * If you need to connect to a device available via network, use + * idevice_new_with_options() and include IDEVICE_LOOKUP_NETWORK in options. + * + * @see idevice_new_with_options * * @param device Upon calling this function, a pointer to a location of type * idevice_t. On successful return, this location will be populated. @@ -139,10 +164,31 @@ idevice_error_t idevice_device_list_free(char **devices); */ idevice_error_t idevice_new(idevice_t *device, const char *udid); +/** + * Creates an idevice_t structure for the device specified by UDID, + * if the device is available, with the given lookup options. + * + * @note The resulting idevice_t structure has to be freed with + * idevice_free() if it is no longer used. + * + * @param device Upon calling this function, a pointer to a location of type + * idevice_t. On successful return, this location will be populated. + * @param udid The UDID to match. + * @param options Specifies what connection types should be considered + * when looking up devices. Accepts bitwise or'ed values of idevice_options. + * If 0 (no option) is specified it will default to IDEVICE_LOOKUP_USBMUX. + * To lookup both USB and network-connected devices, pass + * IDEVICE_LOOKUP_USBMUX | IDEVICE_LOOKUP_NETWORK. If a device is available + * both via USBMUX *and* network, it will select the USB connection. + * This behavior can be changed by adding IDEVICE_LOOKUP_PREFER_NETWORK + * to the options in which case it will select the network connection. + * + * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. + */ +idevice_error_t idevice_new_with_options(idevice_t *device, const char *udid, enum idevice_options options); + /** * Cleans up an idevice structure, then frees the structure itself. - * This is a library-level function; deals directly with the device to tear - * down relations, but otherwise is mostly internal. * * @param device idevice_t to free. */ diff --git a/src/idevice.c b/src/idevice.c index 06991c5..d23c5b5 100644 --- a/src/idevice.c +++ b/src/idevice.c @@ -190,7 +190,14 @@ static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data) ev.event = event->event; ev.udid = event->device.udid; - ev.conn_type = CONNECTION_USBMUXD; + ev.conn_type = 0; + if (event->device.conn_type == CONNECTION_TYPE_USB) { + ev.conn_type = CONNECTION_USBMUXD; + } else if (event->device.conn_type == CONNECTION_TYPE_NETWORK) { + ev.conn_type = CONNECTION_NETWORK; + } else { + debug_info("Unknown connection type %d", event->device.conn_type); + } if (event_cb) { event_cb(&ev, user_data); @@ -236,9 +243,11 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_device_list(char ***devices, in int i, newcount = 0; for (i = 0; dev_list[i].handle > 0; i++) { - newlist = realloc(*devices, sizeof(char*) * (newcount+1)); - newlist[newcount++] = strdup(dev_list[i].udid); - *devices = newlist; + if (dev_list[i].conn_type == CONNECTION_TYPE_USB) { + newlist = realloc(*devices, sizeof(char*) * (newcount+1)); + newlist[newcount++] = strdup(dev_list[i].udid); + *devices = newlist; + } } usbmuxd_device_list_free(&dev_list); @@ -268,25 +277,66 @@ LIBIMOBILEDEVICE_API void idevice_set_debug_level(int level) internal_set_debug_level(level); } -LIBIMOBILEDEVICE_API idevice_error_t idevice_new(idevice_t * device, const char *udid) +static idevice_t idevice_from_mux_device(usbmuxd_device_info_t *muxdev) +{ + if (!muxdev) + return NULL; + + idevice_t device = (idevice_t)malloc(sizeof(struct idevice_private)); + if (!device) + return NULL; + + device->udid = strdup(muxdev->udid); + device->mux_id = muxdev->handle; + device->version = 0; + switch (muxdev->conn_type) { + case CONNECTION_TYPE_USB: + device->conn_type = CONNECTION_USBMUXD; + device->conn_data = NULL; + break; + case CONNECTION_TYPE_NETWORK: + device->conn_type = CONNECTION_NETWORK; + size_t len = ((uint8_t*)muxdev->conn_data)[0]; + device->conn_data = malloc(len); + memcpy(device->conn_data, muxdev->conn_data, len); + break; + default: + device->conn_type = 0; + device->conn_data = NULL; + break; + } + return device; +} + +LIBIMOBILEDEVICE_API idevice_error_t idevice_new_with_options(idevice_t * device, const char *udid, enum idevice_options options) { usbmuxd_device_info_t muxdev; - int res = usbmuxd_get_device_by_udid(udid, &muxdev); + int usbmux_options = 0; + if (options & IDEVICE_LOOKUP_USBMUX) { + usbmux_options |= DEVICE_LOOKUP_USBMUX; + } + if (options & IDEVICE_LOOKUP_NETWORK) { + usbmux_options |= DEVICE_LOOKUP_NETWORK; + } + if (options & IDEVICE_LOOKUP_PREFER_NETWORK) { + usbmux_options |= DEVICE_LOOKUP_PREFER_NETWORK; + } + int res = usbmuxd_get_device(udid, &muxdev, usbmux_options); if (res > 0) { - idevice_t dev = (idevice_t) malloc(sizeof(struct idevice_private)); - dev->udid = strdup(muxdev.udid); - dev->mux_id = muxdev.handle; - dev->conn_type = CONNECTION_USBMUXD; - dev->conn_data = NULL; - dev->version = 0; - *device = dev; + *device = idevice_from_mux_device(&muxdev); + if (!*device) { + return IDEVICE_E_UNKNOWN_ERROR; + } return IDEVICE_E_SUCCESS; } - /* other connection types could follow here */ - return IDEVICE_E_NO_DEVICE; } +LIBIMOBILEDEVICE_API idevice_error_t idevice_new(idevice_t * device, const char *udid) +{ + return idevice_new_with_options(device, udid, 0); +} + LIBIMOBILEDEVICE_API idevice_error_t idevice_free(idevice_t device) { if (!device) @@ -310,7 +360,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t return IDEVICE_E_INVALID_ARG; } - if (device->conn_type == CONNECTION_USBMUXD) { + if (device->conn_type == CONNECTION_USBMUXD || device->conn_type == CONNECTION_NETWORK) { int sfd = usbmuxd_connect(device->mux_id, port); if (sfd < 0) { debug_info("ERROR: Connecting to usbmuxd failed: %d (%s)", sfd, strerror(-sfd)); @@ -340,7 +390,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_disconnect(idevice_connection_t con idevice_connection_disable_ssl(connection); } idevice_error_t result = IDEVICE_E_UNKNOWN_ERROR; - if (connection->type == CONNECTION_USBMUXD) { + if (connection->type == CONNECTION_USBMUXD || connection->type == CONNECTION_NETWORK) { usbmuxd_disconnect((int)(long)connection->data); connection->data = NULL; result = IDEVICE_E_SUCCESS; @@ -363,7 +413,7 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection, return IDEVICE_E_INVALID_ARG; } - if (connection->type == CONNECTION_USBMUXD) { + if (connection->type == CONNECTION_USBMUXD || connection->type == CONNECTION_NETWORK) { int res = usbmuxd_send((int)(long)connection->data, data, len, sent_bytes); if (res < 0) { debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res)); @@ -434,7 +484,7 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t return IDEVICE_E_INVALID_ARG; } - if (connection->type == CONNECTION_USBMUXD) { + if (connection->type == CONNECTION_USBMUXD || connection->type == CONNECTION_NETWORK) { int conn_error = usbmuxd_recv_timeout((int)(long)connection->data, data, len, recv_bytes, timeout); idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, *recv_bytes); @@ -510,7 +560,7 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti return IDEVICE_E_INVALID_ARG; } - if (connection->type == CONNECTION_USBMUXD) { + if (connection->type == CONNECTION_USBMUXD || connection->type == CONNECTION_NETWORK) { int res = usbmuxd_recv((int)(long)connection->data, data, len, recv_bytes); if (res < 0) { debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res)); @@ -554,7 +604,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_get_fd(idevice_connectio } idevice_error_t result = IDEVICE_E_UNKNOWN_ERROR; - if (connection->type == CONNECTION_USBMUXD) { + if (connection->type == CONNECTION_USBMUXD || connection->type == CONNECTION_NETWORK) { *fd = (int)(long)connection->data; result = IDEVICE_E_SUCCESS; } else { diff --git a/src/idevice.h b/src/idevice.h index f403c55..8709c9a 100644 --- a/src/idevice.h +++ b/src/idevice.h @@ -48,10 +48,6 @@ #define DEVICE_VERSION(maj, min, patch) (((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (patch & 0xFF)) -enum connection_type { - CONNECTION_USBMUXD = 1 -}; - struct ssl_data_private { #ifdef HAVE_OPENSSL SSL *session; @@ -69,7 +65,7 @@ typedef struct ssl_data_private *ssl_data_t; struct idevice_connection_private { idevice_t device; - enum connection_type type; + enum idevice_connection_type type; void *data; ssl_data_t ssl_data; }; @@ -77,7 +73,7 @@ struct idevice_connection_private { struct idevice_private { char *udid; uint32_t mux_id; - enum connection_type conn_type; + enum idevice_connection_type conn_type; void *conn_data; int version; }; -- cgit v1.1-32-gdbae