From 1f6282ffddec7012df82fa929dfe72cfc74b063a Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 10 Sep 2009 13:28:13 +0200 Subject: Public API rework, extension and adaption to latest libusbmuxd-1.0 API. --- include/libiphone/libiphone.h | 44 ++++- src/AFC.c | 40 ++--- src/AFC.h | 2 +- src/MobileSync.c | 14 +- src/MobileSync.h | 2 +- src/NotificationProxy.c | 28 ++-- src/NotificationProxy.h | 2 +- src/iphone.c | 371 ++++++++++++++++++++++++++++++++++-------- src/iphone.h | 22 ++- src/lockdown.c | 26 +-- src/lockdown.h | 2 +- src/userpref.c | 6 +- src/userpref.h | 4 +- tools/iphone_id.c | 9 +- tools/iphoneinfo.c | 4 +- tools/iphonesyslog.c | 16 +- 16 files changed, 437 insertions(+), 155 deletions(-) diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h index 1451f15..77860f8 100644 --- a/include/libiphone/libiphone.h +++ b/include/libiphone/libiphone.h @@ -31,7 +31,6 @@ extern "C" { #include #include #include -#include /* Error Codes */ #define IPHONE_E_SUCCESS 0 @@ -46,19 +45,56 @@ typedef int16_t iphone_error_t; struct iphone_device_int; typedef struct iphone_device_int *iphone_device_t; +struct iphone_connection_int; +typedef struct iphone_connection_int *iphone_connection_t; + /* Debugging */ #define DBGMASK_ALL 0xFFFF #define DBGMASK_NONE 0x0000 #define DBGMASK_LOCKDOWND (1 << 1) #define DBGMASK_MOBILESYNC (1 << 2) +/* generic */ void iphone_set_debug_mask(uint16_t mask); void iphone_set_debug_level(int level); -/* Interface */ -iphone_error_t iphone_get_device(iphone_device_t *device); -iphone_error_t iphone_get_device_by_uuid(iphone_device_t *device, const char *uuid); +/* discovery (events/asynchronous) */ +// event type +enum iphone_event_type { + IPHONE_DEVICE_ADD = 1, + IPHONE_DEVICE_REMOVE +}; + +// event data structure +typedef struct { + enum iphone_event_type event; + const char *uuid; + int conn_type; +} iphone_event_t; + +// event callback function prototype +typedef void (*iphone_event_cb_t) (const iphone_event_t *event, void *user_data); + +// functions +iphone_error_t iphone_event_subscribe(iphone_event_cb_t callback, void *user_data); +iphone_error_t iphone_event_unsubscribe(); + +/* discovery (synchronous) */ +iphone_error_t iphone_get_device_list(char ***devices, int *count); +iphone_error_t iphone_free_device_list(char **devices); + +/* device structure creation and destruction */ +iphone_error_t iphone_device_new(iphone_device_t *device, const char *uuid); iphone_error_t iphone_device_free(iphone_device_t device); + +/* connection/disconnection and communication */ +iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t dst_port, iphone_connection_t *connection); +iphone_error_t iphone_device_disconnect(iphone_connection_t connection); +iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes); +iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout); +iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes); + +/* misc */ iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle); iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid); diff --git a/src/AFC.c b/src/AFC.c index b27080a..ba436e7 100644 --- a/src/AFC.c +++ b/src/AFC.c @@ -68,18 +68,18 @@ afc_error_t afc_client_new(iphone_device_t device, int dst_port, afc_client_t * return AFC_E_INVALID_ARGUMENT; /* attempt connection */ - int sfd = usbmuxd_connect(device->handle, dst_port); - if (sfd < 0) { + iphone_connection_t connection = NULL; + if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { return AFC_E_MUX_ERROR; } afc_client_t client_loc = (afc_client_t) malloc(sizeof(struct afc_client_int)); - client_loc->sfd = sfd; + client_loc->connection = connection; /* allocate a packet */ client_loc->afc_packet = (AFCPacket *) malloc(sizeof(AFCPacket)); if (!client_loc->afc_packet) { - usbmuxd_disconnect(client_loc->sfd); + iphone_device_disconnect(client_loc->connection); free(client_loc); return AFC_E_NO_MEM; } @@ -102,10 +102,10 @@ afc_error_t afc_client_new(iphone_device_t device, int dst_port, afc_client_t * */ afc_error_t afc_client_free(afc_client_t client) { - if (!client || client->sfd < 0 || !client->afc_packet) + if (!client || !client->connection || !client->afc_packet) return AFC_E_INVALID_ARGUMENT; - usbmuxd_disconnect(client->sfd); + iphone_device_disconnect(client->connection); free(client->afc_packet); if (client->mutex) { g_mutex_free(client->mutex); @@ -132,7 +132,7 @@ static int afc_dispatch_packet(afc_client_t client, const char *data, uint64_t l int bytes = 0, offset = 0; char *buffer; - if (!client || client->sfd < 0 || !client->afc_packet) + if (!client || !client->connection || !client->afc_packet) return 0; if (!data || !length) @@ -164,7 +164,7 @@ static int afc_dispatch_packet(afc_client_t client, const char *data, uint64_t l return -1; } memcpy(buffer + sizeof(AFCPacket), data, offset); - usbmuxd_send(client->sfd, buffer, client->afc_packet->this_length, (uint32_t*)&bytes); + iphone_device_send(client->connection, buffer, client->afc_packet->this_length, (uint32_t*)&bytes); free(buffer); if (bytes <= 0) { return bytes; @@ -175,7 +175,7 @@ static int afc_dispatch_packet(afc_client_t client, const char *data, uint64_t l log_debug_msg("%s: Buffer: \n", __func__); log_debug_buffer(data + offset, length - offset); - usbmuxd_send(client->sfd, data + offset, length - offset, (uint32_t*)&bytes); + iphone_device_send(client->connection, data + offset, length - offset, (uint32_t*)&bytes); return bytes; } else { log_debug_msg("%s: doin things the old way\n", __func__); @@ -188,7 +188,7 @@ static int afc_dispatch_packet(afc_client_t client, const char *data, uint64_t l } log_debug_buffer(buffer, client->afc_packet->this_length); log_debug_msg("\n"); - usbmuxd_send(client->sfd, buffer, client->afc_packet->this_length, (uint32_t*)&bytes); + iphone_device_send(client->connection, buffer, client->afc_packet->this_length, (uint32_t*)&bytes); if (buffer) { free(buffer); @@ -220,7 +220,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, int * *bytes = 0; /* first, read the AFC header */ - usbmuxd_recv(client->sfd, (char*)&header, sizeof(AFCPacket), (uint32_t*)bytes); + iphone_device_recv(client->connection, (char*)&header, sizeof(AFCPacket), (uint32_t*)bytes); if (*bytes <= 0) { log_debug_msg("%s: Just didn't get enough.\n", __func__); *dump_here = NULL; @@ -273,7 +273,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, int * *dump_here = (char*)malloc(entire_len); if (this_len > 0) { - usbmuxd_recv(client->sfd, *dump_here, this_len, (uint32_t*)bytes); + iphone_device_recv(client->connection, *dump_here, this_len, (uint32_t*)bytes); if (*bytes <= 0) { free(*dump_here); *dump_here = NULL; @@ -291,7 +291,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, int * if (entire_len > this_len) { while (current_count < entire_len) { - usbmuxd_recv(client->sfd, (*dump_here)+current_count, entire_len - current_count, (uint32_t*)bytes); + iphone_device_recv(client->connection, (*dump_here)+current_count, entire_len - current_count, (uint32_t*)bytes); if (*bytes <= 0) { log_debug_msg("%s: Error receiving data (recv returned %d)\n", __func__, *bytes); break; @@ -517,7 +517,7 @@ afc_error_t afc_remove_path(afc_client_t client, const char *path) int bytes; afc_error_t ret = AFC_E_UNKNOWN_ERROR; - if (!client || !path || !client->afc_packet || client->sfd < 0) + if (!client || !path || !client->afc_packet || !client->connection) return AFC_E_INVALID_ARGUMENT; afc_lock(client); @@ -560,7 +560,7 @@ afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *t int bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; - if (!client || !from || !to || !client->afc_packet || client->sfd < 0) + if (!client || !from || !to || !client->afc_packet || !client->connection) return AFC_E_INVALID_ARGUMENT; afc_lock(client); @@ -687,7 +687,7 @@ afc_file_open(afc_client_t client, const char *filename, // set handle to 0 so in case an error occurs, the handle is invalid *handle = 0; - if (!client || client->sfd < 0|| !client->afc_packet) + if (!client || !client->connection || !client->afc_packet) return AFC_E_INVALID_ARGUMENT; afc_lock(client); @@ -742,7 +742,7 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, int length, uint const int MAXIMUM_READ_SIZE = 1 << 16; afc_error_t ret = AFC_E_SUCCESS; - if (!client || !client->afc_packet || client->sfd < 0 || handle == 0) + if (!client || !client->afc_packet || !client->connection || handle == 0) return AFC_E_INVALID_ARGUMENT; log_debug_msg("%s: called for length %i\n", __func__, length); @@ -819,7 +819,7 @@ afc_file_write(afc_client_t client, uint64_t handle, char *out_buffer = NULL; afc_error_t ret = AFC_E_SUCCESS; - if (!client || !client->afc_packet || client->sfd < 0 || !bytes || (handle == 0)) + if (!client || !client->afc_packet || !client->connection || !bytes || (handle == 0)) return AFC_E_INVALID_ARGUMENT; afc_lock(client); @@ -1139,7 +1139,7 @@ afc_error_t afc_truncate(afc_client_t client, const char *path, off_t newsize) uint64_t size_requested = newsize; afc_error_t ret = AFC_E_UNKNOWN_ERROR; - if (!client || !path || !client->afc_packet || client->sfd < 0) + if (!client || !path || !client->afc_packet || !client->connection) return AFC_E_INVALID_ARGUMENT; afc_lock(client); @@ -1183,7 +1183,7 @@ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const c uint64_t type = linktype; afc_error_t ret = AFC_E_UNKNOWN_ERROR; - if (!client || !target || !linkname || !client->afc_packet || client->sfd < 0) + if (!client || !target || !linkname || !client->afc_packet || !client->connection) return AFC_E_INVALID_ARGUMENT; afc_lock(client); diff --git a/src/AFC.h b/src/AFC.h index 7ed6bd8..685d7b5 100644 --- a/src/AFC.h +++ b/src/AFC.h @@ -46,7 +46,7 @@ typedef struct __AFCToken { } AFCToken; struct afc_client_int { - int sfd; + iphone_connection_t connection; AFCPacket *afc_packet; int file_handle; int lock; diff --git a/src/MobileSync.c b/src/MobileSync.c index 4463251..8a7d724 100644 --- a/src/MobileSync.c +++ b/src/MobileSync.c @@ -40,13 +40,13 @@ mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port, mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR; /* Attempt connection */ - int sfd = usbmuxd_connect(device->handle, dst_port); - if (sfd < 0) { + iphone_connection_t connection = NULL; + if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { return ret; } mobilesync_client_t client_loc = (mobilesync_client_t) malloc(sizeof(struct mobilesync_client_int)); - client_loc->sfd = sfd; + client_loc->connection = connection; /* perform handshake */ plist_t array = NULL; @@ -126,7 +126,7 @@ mobilesync_error_t mobilesync_client_free(mobilesync_client_t client) return IPHONE_E_INVALID_ARG; mobilesync_disconnect(client); - return (usbmuxd_disconnect(client->sfd) == 0 ? MOBILESYNC_E_SUCCESS: MOBILESYNC_E_MUX_ERROR); + return (iphone_device_disconnect(client->connection) == 0 ? MOBILESYNC_E_SUCCESS: MOBILESYNC_E_MUX_ERROR); } /** Polls the iPhone for MobileSync data. @@ -144,14 +144,14 @@ mobilesync_error_t mobilesync_recv(mobilesync_client_t client, plist_t * plist) char *receive = NULL; uint32_t datalen = 0, bytes = 0, received_bytes = 0; - ret = usbmuxd_recv(client->sfd, (char *) &datalen, sizeof(datalen), &bytes); + ret = iphone_device_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes); datalen = ntohl(datalen); receive = (char *) malloc(sizeof(char) * datalen); /* fill buffer and request more packets if needed */ while ((received_bytes < datalen) && (ret == MOBILESYNC_E_SUCCESS)) { - ret = usbmuxd_recv(client->sfd, receive + received_bytes, datalen - received_bytes, &bytes); + ret = iphone_device_recv(client->connection, receive + received_bytes, datalen - received_bytes, &bytes); received_bytes += bytes; } @@ -207,7 +207,7 @@ mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist) memcpy(real_query, &length, sizeof(length)); memcpy(real_query + 4, content, ntohl(length)); - ret = usbmuxd_send(client->sfd, real_query, ntohl(length) + sizeof(length), (uint32_t*)&bytes); + ret = iphone_device_send(client->connection, real_query, ntohl(length) + sizeof(length), (uint32_t*)&bytes); free(real_query); return (ret == 0 ? MOBILESYNC_E_SUCCESS: MOBILESYNC_E_MUX_ERROR); } diff --git a/src/MobileSync.h b/src/MobileSync.h index 6347399..605145f 100644 --- a/src/MobileSync.h +++ b/src/MobileSync.h @@ -24,7 +24,7 @@ #include "libiphone/mobilesync.h" struct mobilesync_client_int { - int sfd; + iphone_connection_t connection; }; #endif diff --git a/src/NotificationProxy.c b/src/NotificationProxy.c index e4735cc..da636ab 100644 --- a/src/NotificationProxy.c +++ b/src/NotificationProxy.c @@ -83,9 +83,9 @@ static np_error_t np_plist_send(np_client_t client, plist_t dict) } nlen = htonl(length); - usbmuxd_send(client->sfd, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); + iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); if (bytes == sizeof(nlen)) { - usbmuxd_send(client->sfd, XML_content, length, (uint32_t*)&bytes); + iphone_device_send(client->connection, XML_content, length, (uint32_t*)&bytes); if (bytes > 0) { if ((uint32_t)bytes == length) { res = NP_E_SUCCESS; @@ -121,13 +121,13 @@ np_error_t np_client_new(iphone_device_t device, int dst_port, np_client_t *clie return NP_E_INVALID_ARG; /* Attempt connection */ - int sfd = usbmuxd_connect(device->handle, dst_port); - if (sfd < 0) { + iphone_connection_t connection = NULL; + if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { return NP_E_UNKNOWN_ERROR; } np_client_t client_loc = (np_client_t) malloc(sizeof(struct np_client_int)); - client_loc->sfd = sfd; + client_loc->connection = connection; client_loc->mutex = g_mutex_new(); @@ -146,8 +146,8 @@ np_error_t np_client_free(np_client_t client) if (!client) return NP_E_INVALID_ARG; - usbmuxd_disconnect(client->sfd); - client->sfd = -1; + iphone_device_disconnect(client->connection); + client->connection = NULL; if (client->notifier) { log_debug_msg("joining np callback\n"); g_thread_join(client->notifier); @@ -293,12 +293,12 @@ static int np_get_notification(np_client_t client, char **notification) char *XML_content = NULL; plist_t dict = NULL; - if (!client || client->sfd < 0 || *notification) + if (!client || !client->connection || *notification) return -1; np_lock(client); - usbmuxd_recv_timeout(client->sfd, (char*)&pktlen, sizeof(pktlen), &bytes, 500); + iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 500); log_debug_msg("NotificationProxy: initial read=%i\n", bytes); if (bytes < 4) { log_debug_msg("NotificationProxy: no notification received!\n"); @@ -310,7 +310,7 @@ static int np_get_notification(np_client_t client, char **notification) XML_content = (char*)malloc(pktlen); log_debug_msg("pointer %p\n", XML_content); - usbmuxd_recv_timeout(client->sfd, XML_content, pktlen, &bytes, 1000); + iphone_device_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000); if (bytes <= 0) { res = -1; } else { @@ -390,7 +390,7 @@ gpointer np_notifier( gpointer arg ) if (!npt) return NULL; log_debug_msg("%s: starting callback.\n", __func__); - while (npt->client->sfd >= 0) { + while (npt->client->connection) { np_get_notification(npt->client, ¬ification); if (notification) { npt->cbfunc(notification); @@ -429,11 +429,11 @@ np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb np_lock(client); if (client->notifier) { log_debug_msg("%s: callback already set, removing\n"); - int conn = client->sfd; - client->sfd = -1; + iphone_connection_t conn = client->connection; + client->connection = NULL; g_thread_join(client->notifier); client->notifier = NULL; - client->sfd = conn; + client->connection = conn; } if (notify_cb) { diff --git a/src/NotificationProxy.h b/src/NotificationProxy.h index bc5be43..84f1f89 100644 --- a/src/NotificationProxy.h +++ b/src/NotificationProxy.h @@ -26,7 +26,7 @@ #include "libiphone/notification_proxy.h" struct np_client_int { - int sfd; + iphone_connection_t connection; GMutex *mutex; GThread *notifier; }; diff --git a/src/iphone.c b/src/iphone.c index e694373..80e796b 100644 --- a/src/iphone.c +++ b/src/iphone.c @@ -1,8 +1,9 @@ /* * iphone.c - * Functions for creating and initializing iPhone structures. + * Device discovery and communication interface. * * Copyright (c) 2008 Zach C. All Rights Reserved. + * Copyright (c) 2009 Nikias Bassen. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,104 +20,161 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include #include +#include +#include #include "iphone.h" #include "utils.h" +static iphone_event_cb_t event_cb = NULL; + +static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data) +{ + iphone_event_t ev; + + ev.event = event->event; + ev.uuid = event->device.uuid; + ev.conn_type = CONNECTION_USBMUXD; + + if (event_cb) { + event_cb(&ev, user_data); + } +} + /** - * Retrieves a list of connected devices from usbmuxd and matches their - * UUID with the given UUID. If the given UUID is NULL then the first - * device reported by usbmuxd is used. + * Register a callback function that will be called when device add/remove + * events occur. * - * @param device Upon calling this function, a pointer to a location of type - * iphone_device_t, which must have the value NULL. On return, this location - * will be filled with a handle to the device. - * @param uuid The UUID to match. + * @param callback Callback function to call. + * @param user_data Application-specific data passed as parameter + * to the registered callback function. * - * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + * @return IPHONE_E_SUCCESS on success or an error value when an error occured. */ -iphone_error_t iphone_get_device_by_uuid(iphone_device_t * device, const char *uuid) +iphone_error_t iphone_event_subscribe(iphone_event_cb_t callback, void *user_data) { - iphone_device_t phone; - uint32_t handle = 0; - char *serial_number = malloc(41); - usbmuxd_scan_result *dev_list = NULL; - int i; - - if (usbmuxd_scan(&dev_list) < 0) { - log_debug_msg("%s: usbmuxd_scan returned an error, is usbmuxd running?\n", __func__); - } - if (dev_list && dev_list[0].handle > 0) { - if (!uuid) { - /* select first device found if no UUID specified */ - handle = dev_list[0].handle; - strcpy(serial_number, dev_list[0].serial_number); - } else { - /* otherwise walk through the list */ - for (i = 0; dev_list[i].handle > 0; i++) { - log_debug_msg("%s: device handle=%d, uuid=%s\n", __func__, dev_list[i].handle, dev_list[i].serial_number); - if (strcasecmp(uuid, dev_list[i].serial_number) == 0) { - handle = dev_list[i].handle; - strcpy(serial_number, dev_list[i].serial_number); - break; - } - } - } - free(dev_list); - - if (handle > 0) { - phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int)); - phone->handle = handle; - phone->serial_number = serial_number; - *device = phone; - return IPHONE_E_SUCCESS; - } + event_cb = callback; + int res = usbmuxd_subscribe(usbmux_event_cb, user_data); + if (res != 0) { + event_cb = NULL; + log_debug_msg("%s: Error %d when subscribing usbmux event callback!\n", __func__, res); + return IPHONE_E_UNKNOWN_ERROR; } + return IPHONE_E_SUCCESS; +} - return IPHONE_E_NO_DEVICE; +/** + * Release the event callback function that has been registered with + * iphone_event_subscribe(). + * + * @return IPHONE_E_SUCCESS on success or an error value when an error occured. + */ +iphone_error_t iphone_event_unsubscribe() +{ + event_cb = NULL; + int res = usbmuxd_unsubscribe(); + if (res != 0) { + log_debug_msg("%s: Error %d when unsubscribing usbmux event callback!\n", __func__, res); + return IPHONE_E_UNKNOWN_ERROR; + } + return IPHONE_E_SUCCESS; } /** - * This function has the purpose to retrieve a handle to the first - * attached iPhone/iPod reported by usbmuxd. + * Get a list of currently available devices. * - * @param Upon calling this function, a pointer to a location of type - * iphone_device_t, which must have the value NULL. On return, this location - * will be filled with a handle to the device. + * @param devices List of uuids of devices that are currently available. + * This list is terminated by a NULL pointer. + * @param count Number of devices found. * - * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + * @return IPHONE_E_SUCCESS on success or an error value when an error occured. */ -iphone_error_t iphone_get_device(iphone_device_t * device) +iphone_error_t iphone_get_device_list(char ***devices, int *count) { - return iphone_get_device_by_uuid(device, NULL); + usbmuxd_device_info_t *dev_list; + + *devices = NULL; + *count = 0; + + if (usbmuxd_get_device_list(&dev_list) < 0) { + log_debug_msg("%s: ERROR: usbmuxd is not running!\n", __func__); + return IPHONE_E_NO_DEVICE; + } + + char **newlist = NULL; + 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].uuid); + *devices = newlist; + } + usbmuxd_free_device_list(dev_list); + + *count = newcount; + newlist = realloc(*devices, sizeof(char*) * (newcount+1)); + newlist[newcount] = NULL; + *devices = newlist; + + return IPHONE_E_SUCCESS; } -iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle) +/** + * Free a list of device uuids. + * + * @param devices List of uuids to free. + * + * @return Always returnes IPHONE_E_SUCCESS. + */ +iphone_error_t iphone_free_device_list(char **devices) { - if (!device) - return IPHONE_E_INVALID_ARG; - - *handle = device->handle; + if (devices) { + int i = 0; + while (devices[i++]) { + free(devices[i]); + } + free(devices); + } return IPHONE_E_SUCCESS; } -iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid) +/** + * Creates an iphone_device_t structure for the device specified by uuid, + * if the device is available. + * + * @note The resulting iphone_device_t structure has to be freed with + * iphone_device_free() if it is no longer used. + * + * @param device Upon calling this function, a pointer to a location of type + * iphone_device_t. On successful return, this location will be populated. + * @param uuid The UUID to match. + * + * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + */ +iphone_error_t iphone_device_new(iphone_device_t * device, const char *uuid) { - if (!device) - return IPHONE_E_INVALID_ARG; + usbmuxd_device_info_t muxdev; + int res = usbmuxd_get_device_by_uuid(uuid, &muxdev); + if (res > 0) { + iphone_device_t phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int)); + phone->uuid = strdup(muxdev.uuid); + phone->conn_type = CONNECTION_USBMUXD; + phone->conn_data = (void*)muxdev.handle; + *device = phone; + return IPHONE_E_SUCCESS; + } + /* other connection types could follow here */ - *uuid = strdup(device->serial_number); - return IPHONE_E_SUCCESS; + return IPHONE_E_NO_DEVICE; } /** Cleans up an iPhone structure, then frees the structure itself. * This is a library-level function; deals directly with the iPhone to tear * down relations, but otherwise is mostly internal. * - * @param phone A pointer to an iPhone structure. + * @param device A pointer to an iPhone structure. */ iphone_error_t iphone_device_free(iphone_device_t device) { @@ -126,8 +184,189 @@ iphone_error_t iphone_device_free(iphone_device_t device) ret = IPHONE_E_SUCCESS; - free(device->serial_number); + free(device->uuid); + + if (device->conn_type == CONNECTION_USBMUXD) { + device->conn_data = 0; + } + if (device->conn_data) { + free(device->conn_data); + } free(device); return ret; } +/** + * Set up a connection to the given device. + * + * @param device The device to connect to. + * @param dst_port The destination port to connect to. + * @param connection Pointer to an iphone_connection_t that will be filled + * with the necessary data of the connection. + * + * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + */ +iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t dst_port, iphone_connection_t *connection) +{ + if (!device) { + return IPHONE_E_INVALID_ARG; + } + + if (device->conn_type == CONNECTION_USBMUXD) { + int sfd = usbmuxd_connect((uint32_t)(device->conn_data), dst_port); + if (sfd < 0) { + log_debug_msg("%s: ERROR: Connecting to usbmuxd failed: %d (%s)\n", __func__, sfd, strerror(-sfd)); + return IPHONE_E_UNKNOWN_ERROR; + } + iphone_connection_t new_connection = (iphone_connection_t)malloc(sizeof(struct iphone_connection_int)); + new_connection->type = CONNECTION_USBMUXD; + new_connection->data = (void*)sfd; + *connection = new_connection; + return IPHONE_E_SUCCESS; + } else { + log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type); + } + + return IPHONE_E_UNKNOWN_ERROR; +} + +/** + * Disconnect from the device and clean up the connection structure. + * + * @param connection The connection to close. + * + * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + */ +iphone_error_t iphone_device_disconnect(iphone_connection_t connection) +{ + if (!connection) { + return IPHONE_E_INVALID_ARG; + } + iphone_error_t result = IPHONE_E_UNKNOWN_ERROR; + if (connection->type == CONNECTION_USBMUXD) { + usbmuxd_disconnect((int)(connection->data)); + result = IPHONE_E_SUCCESS; + } else { + log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); + } + free(connection); + return result; +} + +/** + * Send data to a device via the given connection. + * + * @param connection The connection to send data over. + * @param data Buffer with data to send. + * @param len Size of the buffer to send. + * @param sent_bytes Pointer to an uint32_t that will be filled + * with the number of bytes actually sent. + * + * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + */ +iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes) +{ + if (!connection || !data) { + return IPHONE_E_INVALID_ARG; + } + + if (connection->type == CONNECTION_USBMUXD) { + int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes); + if (res < 0) { + log_debug_msg("%s: ERROR: usbmuxd_send returned %d (%s)\n", __func__, res, strerror(-res)); + return IPHONE_E_UNKNOWN_ERROR; + } + return IPHONE_E_SUCCESS; + } else { + log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); + } + return IPHONE_E_UNKNOWN_ERROR; +} + +/** + * Receive data from a device via the given connection. + * This function will return after the given timeout even if no data has been + * received. + * + * @param connection The connection to receive data from. + * @param data Buffer that will be filled with the received data. + * This buffer has to be large enough to hold len bytes. + * @param len Buffer size or number of bytes to receive. + * @param recv_bytes Number of bytes actually received. + * @param timeout Timeout in milliseconds after which this function should + * return even if no data has been received. + * + * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + */ +iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) +{ + if (!connection) { + return IPHONE_E_INVALID_ARG; + } + + if (connection->type == CONNECTION_USBMUXD) { + int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout); + if (res < 0) { + log_debug_msg("%s: ERROR: usbmuxd_recv_timeout returned %d (%s)\n", __func__, res, strerror(-res)); + return IPHONE_E_UNKNOWN_ERROR; + } + } else { + log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); + } + return IPHONE_E_UNKNOWN_ERROR; +} + +/** + * Receive data from a device via the given connection. + * This function is like iphone_device_recv_timeout, but with a predefined + * reasonable timeout. + * + * @param connection The connection to receive data from. + * @param data Buffer that will be filled with the received data. + * This buffer has to be large enough to hold len bytes. + * @param len Buffer size or number of bytes to receive. + * @param recv_bytes Number of bytes actually received. + * + * @return IPHONE_E_SUCCESS if ok, otherwise an error code. + */ +iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) +{ + if (!connection) { + return -EINVAL; + } + + if (connection->type == CONNECTION_USBMUXD) { + int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes); + if (res < 0) { + log_debug_msg("%s: ERROR: usbmuxd_recv returned %d (%s)\n", __func__, res, strerror(-res)); + return IPHONE_E_UNKNOWN_ERROR; + } + } else { + log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type); + } + return IPHONE_E_UNKNOWN_ERROR; +} + +iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle) +{ + if (!device) + return IPHONE_E_INVALID_ARG; + + if (device->conn_type == CONNECTION_USBMUXD) { + *handle = (uint32_t)device->conn_data; + return IPHONE_E_SUCCESS; + } else { + log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type); + } + return IPHONE_E_UNKNOWN_ERROR; +} + +iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid) +{ + if (!device) + return IPHONE_E_INVALID_ARG; + + *uuid = strdup(device->uuid); + return IPHONE_E_SUCCESS; +} + diff --git a/src/iphone.h b/src/iphone.h index 6e14280..98b0ed8 100644 --- a/src/iphone.h +++ b/src/iphone.h @@ -1,7 +1,7 @@ /* * iphone.h - * iPhone struct - * + * Device discovery and communication interface -- header file. + * * Copyright (c) 2008 Zach C. All Rights Reserved. * * This library is free software; you can redistribute it and/or @@ -18,18 +18,24 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - #ifndef IPHONE_H #define IPHONE_H -#include - #include "libiphone/libiphone.h" +enum connection_type { + CONNECTION_USBMUXD = 1 +}; + +struct iphone_connection_int { + enum connection_type type; + void *data; +}; + struct iphone_device_int { - char *buffer; - uint32_t handle; - char *serial_number; + char *uuid; + enum connection_type conn_type; + void *conn_data; }; #endif diff --git a/src/lockdown.c b/src/lockdown.c index 7a2aa7d..a05b5db 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -213,12 +213,14 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) lockdownd_stop_ssl_session(client); - if (client->sfd > 0) { + if (client->connection) { lockdownd_goodbye(client); // IMO, read of final "sessionUpcall connection closed" packet // should come here instead of in iphone_free_device - ret = usbmuxd_disconnect(client->sfd); + if ((ret = iphone_device_disconnect(client->connection)) != IPHONE_E_SUCCESS) { + ret = LOCKDOWN_E_UNKNOWN_ERROR; + } } free(client); @@ -241,7 +243,7 @@ lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist) uint32_t datalen = 0, bytes = 0, received_bytes = 0; if (!client->in_SSL) - ret = usbmuxd_recv(client->sfd, (char *) &datalen, sizeof(datalen), &bytes); + ret = iphone_device_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes); else { ssize_t res = gnutls_record_recv(*client->ssl_session, &datalen, sizeof(datalen)); if (res < 0) { @@ -260,7 +262,7 @@ lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist) /* fill buffer and request more packets if needed */ if (!client->in_SSL) { while ((received_bytes < datalen) && (ret == LOCKDOWN_E_SUCCESS)) { - ret = usbmuxd_recv(client->sfd, receive + received_bytes, datalen - received_bytes, &bytes); + ret = iphone_device_recv(client->connection, receive + received_bytes, datalen - received_bytes, &bytes); received_bytes += bytes; } } else { @@ -328,7 +330,7 @@ lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist) log_dbg_msg(DBGMASK_LOCKDOWND, "%s: made the query, sending it along\n", __func__); if (!client->in_SSL) - ret = usbmuxd_send(client->sfd, real_query, ntohl(length) + sizeof(length), (uint32_t*)&bytes); + ret = iphone_device_send(client->connection, real_query, ntohl(length) + sizeof(length), (uint32_t*)&bytes); else { ssize_t res = gnutls_record_send(*client->ssl_session, real_query, ntohl(length) + sizeof(length)); if (res < 0) { @@ -659,19 +661,19 @@ lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **de */ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client) { - if (!device || !client) + if (!client) return LOCKDOWN_E_INVALID_ARG; lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; char *host_id = NULL; - int sfd = usbmuxd_connect(device->handle, 0xf27e); - if (sfd < 0) { - log_debug_msg("%s: could not connect to lockdownd (device handle %d)\n", __func__, device->handle); + iphone_connection_t connection; + if (iphone_device_connect(device, 0xf27e, &connection) != IPHONE_E_SUCCESS) { + log_debug_msg("%s: could not connect to lockdownd (device %s)\n", __func__, device->uuid); return LOCKDOWN_E_MUX_ERROR; } lockdownd_client_t client_loc = (lockdownd_client_t) malloc(sizeof(struct lockdownd_client_int)); - client_loc->sfd = sfd; + client_loc->connection = connection; client_loc->ssl_session = (gnutls_session_t *) malloc(sizeof(gnutls_session_t)); client_loc->in_SSL = 0; @@ -1176,7 +1178,7 @@ ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size client = (lockdownd_client_t) transport; log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pre-send length = %zi\n", __func__, length); - usbmuxd_send(client->sfd, buffer, length, &bytes); + iphone_device_send(client->connection, buffer, length, &bytes); log_dbg_msg(DBGMASK_LOCKDOWND, "%s: post-send sent %i bytes\n", __func__, bytes); return bytes; } @@ -1205,7 +1207,7 @@ ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_ // repeat until we have the full data or an error occurs. do { - if ((res = usbmuxd_recv(client->sfd, recv_buffer, this_len, (uint32_t*)&bytes)) != LOCKDOWN_E_SUCCESS) { + if ((res = iphone_device_recv(client->connection, recv_buffer, this_len, (uint32_t*)&bytes)) != LOCKDOWN_E_SUCCESS) { log_debug_msg("%s: ERROR: usbmux_recv returned %d\n", __func__, res); return res; } diff --git a/src/lockdown.h b/src/lockdown.h index 1e193f6..19cf9f2 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -28,7 +28,7 @@ #include "libiphone/lockdown.h" struct lockdownd_client_int { - int sfd; + iphone_connection_t connection; gnutls_session_t *ssl_session; int in_SSL; char session_id[40]; diff --git a/src/userpref.c b/src/userpref.c index 9dd1a01..10c14a0 100644 --- a/src/userpref.c +++ b/src/userpref.c @@ -88,7 +88,7 @@ static char *userpref_generate_host_id() * * @param host_id A null terminated string containing a valid HostID. */ -static int userpref_set_host_id(char *host_id) +static int userpref_set_host_id(const char *host_id) { GKeyFile *key_file; gsize length; @@ -164,7 +164,7 @@ void userpref_get_host_id(char **host_id) * @return 1 if the iPhone has been connected previously to this configuration * or 0 otherwise. */ -int userpref_has_device_public_key(char *uuid) +int userpref_has_device_public_key(const char *uuid) { int ret = 0; gchar *config_file; @@ -187,7 +187,7 @@ int userpref_has_device_public_key(char *uuid) * @return 1 on success and 0 if no public key is given or if it has already * been marked as connected previously. */ -userpref_error_t userpref_set_device_public_key(char *uuid, gnutls_datum_t public_key) +userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t public_key) { if (NULL == public_key.data) return USERPREF_E_INVALID_ARG; diff --git a/src/userpref.h b/src/userpref.h index 414c093..fcb8b62 100644 --- a/src/userpref.h +++ b/src/userpref.h @@ -36,8 +36,8 @@ typedef int16_t userpref_error_t; userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt); userpref_error_t userpref_set_keys_and_certs(gnutls_datum_t * root_key, gnutls_datum_t * root_cert, gnutls_datum_t * host_key, gnutls_datum_t * host_cert); userpref_error_t userpref_get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert); -userpref_error_t userpref_set_device_public_key(char *uuid, gnutls_datum_t public_key); -int userpref_has_device_public_key(char *uuid); +userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t public_key); +int userpref_has_device_public_key(const char *uuid); void userpref_get_host_id(char **host_id); #endif diff --git a/tools/iphone_id.c b/tools/iphone_id.c index 835e214..ab36e7c 100644 --- a/tools/iphone_id.c +++ b/tools/iphone_id.c @@ -28,7 +28,7 @@ int main(int argc, char **argv) { iphone_device_t phone = NULL; lockdownd_client_t client = NULL; - usbmuxd_scan_result *dev_list; + usbmuxd_device_info_t *dev_list; char *devname = NULL; int ret = 0; int i; @@ -65,7 +65,7 @@ int main(int argc, char **argv) switch (mode) { case MODE_SHOW_ID: - iphone_get_device_by_uuid(&phone, uuid); + iphone_device_new(&phone, uuid); if (!phone) { fprintf(stderr, "ERROR: No device with UUID=%s attached.\n", uuid); return -2; @@ -96,13 +96,14 @@ int main(int argc, char **argv) return ret; case MODE_LIST_DEVICES: default: - if (usbmuxd_scan(&dev_list) < 0) { + if (usbmuxd_get_device_list(&dev_list) < 0) { fprintf(stderr, "ERROR: usbmuxd is not running!\n"); return -1; } for (i = 0; dev_list[i].handle > 0; i++) { - printf("handle=%d product_id=%04x uuid=%s\n", dev_list[i].handle, dev_list[i].product_id, dev_list[i].serial_number); + printf("handle=%d product_id=%04x uuid=%s\n", dev_list[i].handle, dev_list[i].product_id, dev_list[i].uuid); } + usbmuxd_free_device_list(dev_list); return 0; } } diff --git a/tools/iphoneinfo.c b/tools/iphoneinfo.c index 7e275b2..16a1069 100644 --- a/tools/iphoneinfo.c +++ b/tools/iphoneinfo.c @@ -121,7 +121,7 @@ int main(int argc, char *argv[]) } if (uuid[0] != 0) { - ret = iphone_get_device_by_uuid(&phone, uuid); + ret = iphone_device_new(&phone, uuid); if (ret != IPHONE_E_SUCCESS) { printf("No device found with uuid %s, is it plugged in?\n", uuid); return -1; @@ -129,7 +129,7 @@ int main(int argc, char *argv[]) } else { - ret = iphone_get_device(&phone); + ret = iphone_device_new(&phone, NULL); if (ret != IPHONE_E_SUCCESS) { printf("No device found, is it plugged in?\n"); return -1; diff --git a/tools/iphonesyslog.c b/tools/iphonesyslog.c index a096101..10b3fb6 100644 --- a/tools/iphonesyslog.c +++ b/tools/iphonesyslog.c @@ -28,7 +28,6 @@ #include #include -#include static int quit_flag = 0; @@ -86,7 +85,7 @@ int main(int argc, char *argv[]) } if (uuid[0] != 0) { - ret = iphone_get_device_by_uuid(&phone, uuid); + ret = iphone_device_new(&phone, uuid); if (ret != IPHONE_E_SUCCESS) { printf("No device found with uuid %s, is it plugged in?\n", uuid); return -1; @@ -94,7 +93,7 @@ int main(int argc, char *argv[]) } else { - ret = iphone_get_device(&phone); + ret = iphone_device_new(&phone, NULL); if (ret != IPHONE_E_SUCCESS) { printf("No device found, is it plugged in?\n"); return -1; @@ -112,16 +111,15 @@ int main(int argc, char *argv[]) lockdownd_client_free(client); /* connect to socket relay messages */ - iphone_device_get_handle(phone, &handle); - int sfd = usbmuxd_connect(handle, port); - if (sfd < 0) { + iphone_connection_t conn = NULL; + if ((iphone_device_connect(phone, port, &conn) != IPHONE_E_SUCCESS) || !conn) { printf("ERROR: Could not open usbmux connection.\n"); } else { while (!quit_flag) { char *receive = NULL; uint32_t datalen = 0, bytes = 0, recv_bytes = 0; - ret = usbmuxd_recv(sfd, (char *) &datalen, sizeof(datalen), &bytes); + ret = iphone_device_recv(conn, (char *) &datalen, sizeof(datalen), &bytes); datalen = ntohl(datalen); if (datalen == 0) @@ -131,7 +129,7 @@ int main(int argc, char *argv[]) receive = (char *) malloc(sizeof(char) * datalen); while (!quit_flag && (recv_bytes <= datalen)) { - ret = usbmuxd_recv(sfd, receive, datalen, &bytes); + ret = iphone_device_recv(conn, receive, datalen, &bytes); if (bytes == 0) break; @@ -144,7 +142,7 @@ int main(int argc, char *argv[]) free(receive); } } - usbmuxd_disconnect(sfd); + iphone_device_disconnect(conn); } else { printf("ERROR: Could not start service com.apple.syslog_relay.\n"); } -- cgit v1.1-32-gdbae