diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/client.c | 44 | ||||
-rw-r--r-- | src/conf.c | 13 | ||||
-rw-r--r-- | src/device.c | 69 | ||||
-rw-r--r-- | src/preflight.c | 60 | ||||
-rw-r--r-- | src/usb.c | 472 | ||||
-rw-r--r-- | src/usb.h | 6 | ||||
-rw-r--r-- | src/utils.c | 248 | ||||
-rw-r--r-- | src/utils.h | 43 |
9 files changed, 452 insertions, 505 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 328b700..8a96e46 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,11 +6,13 @@ AM_CFLAGS = \ $(GLOBAL_CFLAGS) \ $(libplist_CFLAGS) \ $(libusb_CFLAGS) \ + $(limd_glue_CFLAGS) \ $(libimobiledevice_CFLAGS) AM_LDFLAGS = \ $(libplist_LIBS) \ $(libusb_LIBS) \ + $(limd_glue_LIBS) \ $(libimobiledevice_LIBS) \ $(libpthread_LIBS) diff --git a/src/client.c b/src/client.c index 7395046..dbbdd5f 100644 --- a/src/client.c +++ b/src/client.c @@ -31,13 +31,15 @@ #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> +#include <netinet/in.h> #include <netinet/tcp.h> #include <sys/un.h> #include <arpa/inet.h> -#include <pthread.h> #include <fcntl.h> #include <plist/plist.h> +#include <libimobiledevice-glue/collection.h> +#include <libimobiledevice-glue/thread.h> #include "log.h" #include "usb.h" @@ -75,7 +77,7 @@ struct mux_client { }; static struct collection client_list; -pthread_mutex_t client_list_mutex; +mutex_t client_list_mutex; static uint32_t client_number = 0; #ifdef SO_PEERCRED @@ -224,10 +226,10 @@ int client_accept(int listenfd) client->events = POLLIN; client->info = NULL; - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); client->number = client_number++; collection_add(&client_list, client); - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); #ifdef SO_PEERCRED if (log_level >= LL_INFO) { @@ -252,7 +254,7 @@ int client_accept(int listenfd) void client_close(struct mux_client *client) { int found = 0; - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); FOREACH(struct mux_client *lc, &client_list) { if (client == lc) { found = 1; @@ -262,7 +264,7 @@ void client_close(struct mux_client *client) if (!found) { // in case we get called again but client was already freed usbmuxd_log(LL_DEBUG, "%s: ignoring for non-existing client %p", __func__, client); - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); return; } #ifdef SO_PEERCRED @@ -293,17 +295,17 @@ void client_close(struct mux_client *client) plist_free(client->info); collection_remove(&client_list, client); - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); free(client); } void client_get_fds(struct fdlist *list) { - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); FOREACH(struct mux_client *client, &client_list) { fdlist_add(list, FD_CLIENT, client->fd, client->events); } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); } static int output_buffer_add_message(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length) @@ -442,7 +444,7 @@ static int send_listener_list(struct mux_client *client, uint32_t tag) plist_t dict = plist_new_dict(); plist_t listeners = plist_new_array(); - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); FOREACH(struct mux_client *lc, &client_list) { if (lc->state == CLIENT_LISTEN) { plist_t n = NULL; @@ -489,7 +491,7 @@ static int send_listener_list(struct mux_client *client, uint32_t tag) plist_array_append_item(listeners, l); } } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); plist_dict_set_item(dict, "ListenerList", listeners); res = send_plist(client, tag, dict); @@ -975,14 +977,14 @@ static void input_buffer_process(struct mux_client *client) void client_process(int fd, short events) { struct mux_client *client = NULL; - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); FOREACH(struct mux_client *lc, &client_list) { if(lc->fd == fd) { client = lc; break; } } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); if(!client) { usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd); @@ -1004,45 +1006,45 @@ void client_process(int fd, short events) void client_device_add(struct device_info *dev) { - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); usbmuxd_log(LL_DEBUG, "client_device_add: id %d, location 0x%x, serial %s", dev->id, dev->location, dev->serial); device_set_visible(dev->id); FOREACH(struct mux_client *client, &client_list) { if(client->state == CLIENT_LISTEN) send_device_add(client, dev); } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); } void client_device_remove(int device_id) { - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); uint32_t id = device_id; usbmuxd_log(LL_DEBUG, "client_device_remove: id %d", device_id); FOREACH(struct mux_client *client, &client_list) { if(client->state == CLIENT_LISTEN) send_device_remove(client, id); } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); } void client_device_paired(int device_id) { - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); uint32_t id = device_id; usbmuxd_log(LL_DEBUG, "client_device_paired: id %d", device_id); FOREACH(struct mux_client *client, &client_list) { if (client->state == CLIENT_LISTEN) send_device_paired(client, id); } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); } void client_init(void) { usbmuxd_log(LL_DEBUG, "client_init"); collection_init(&client_list); - pthread_mutex_init(&client_list_mutex, NULL); + mutex_init(&client_list_mutex); } void client_shutdown(void) @@ -1051,6 +1053,6 @@ void client_shutdown(void) FOREACH(struct mux_client *client, &client_list) { client_close(client); } ENDFOREACH - pthread_mutex_destroy(&client_list_mutex); + mutex_destroy(&client_list_mutex); collection_free(&client_list); } @@ -39,6 +39,9 @@ #include <shlobj.h> #endif +#include <libimobiledevice-glue/utils.h> +#include <plist/plist.h> + #include "conf.h" #include "utils.h" #include "log.h" @@ -230,7 +233,7 @@ static int internal_set_value(const char *config_file, const char *key, plist_t /* read file into plist */ plist_t config = NULL; - plist_read_from_filename(&config, config_file); + plist_read_from_file(config_file, &config, NULL); if (!config) { config = plist_new_dict(); plist_dict_set_item(config, key, value); @@ -254,7 +257,7 @@ static int internal_set_value(const char *config_file, const char *key, plist_t usbmuxd_log(LL_DEBUG, "Setting key %s in config file %s", key, config_file); } - int res = plist_write_to_filename(config, config_file, PLIST_FORMAT_XML); + int res = (plist_write_to_file(config, config_file, PLIST_FORMAT_XML, 0) == PLIST_ERR_SUCCESS); plist_free(config); @@ -274,7 +277,7 @@ static int config_set_value(const char *key, plist_t value) int result = internal_set_value(config_file, key, value); if (!result) { - usbmuxd_log(LL_ERROR, "ERROR: Failed to write to '%s': %s", config_file, strerror(errno)); + usbmuxd_log(LL_ERROR, "ERROR: Failed to write to '%s'", config_file); } free(config_file); @@ -288,7 +291,7 @@ static int internal_get_value(const char* config_file, const char *key, plist_t /* now parse file to get the SystemBUID */ plist_t config = NULL; - if (plist_read_from_filename(&config, config_file)) { + if (plist_read_from_file(config_file, &config, NULL) == PLIST_ERR_SUCCESS) { usbmuxd_log(LL_DEBUG, "Reading key %s from config file %s", key, config_file); plist_t n = plist_dict_get_item(config, key); if (n) { @@ -428,7 +431,7 @@ int config_set_device_record(const char *udid, char* record_data, uint64_t recor remove(device_record_file); /* store file */ - if (!plist_write_to_filename(plist, device_record_file, PLIST_FORMAT_XML)) { + if (!plist_write_to_file(plist, device_record_file, PLIST_FORMAT_XML, 0)) { usbmuxd_log(LL_DEBUG, "Could not open '%s' for writing: %s", device_record_file, strerror(errno)); res = -ENOENT; } diff --git a/src/device.c b/src/device.c index aac40b1..0928021 100644 --- a/src/device.c +++ b/src/device.c @@ -32,8 +32,11 @@ #include <string.h> #include <stdint.h> #include <inttypes.h> -#include <pthread.h> #include <unistd.h> + +#include <libimobiledevice-glue/collection.h> +#include <libimobiledevice-glue/thread.h> + #include "device.h" #include "client.h" #include "preflight.h" @@ -127,19 +130,19 @@ struct mux_device }; static struct collection device_list; -pthread_mutex_t device_list_mutex; +mutex_t device_list_mutex; static struct mux_device* get_mux_device_for_id(int device_id) { struct mux_device *dev = NULL; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *cdev, &device_list) { if(cdev->id == device_id) { dev = cdev; break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); return dev; } @@ -166,7 +169,7 @@ static int get_next_device_id(void) { while(1) { int ok = 1; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == next_device_id) { next_device_id++; @@ -174,7 +177,7 @@ static int get_next_device_id(void) break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); if(ok) return next_device_id++; } @@ -464,9 +467,9 @@ static int send_tcp_ack(struct mux_connection *conn) */ void device_client_process(int device_id, struct mux_client *client, short events) { - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); struct mux_connection *conn = get_mux_connection(device_id, client); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); if(!conn) { usbmuxd_log(LL_WARNING, "Could not find connection for device %d client %p", device_id, client); return; @@ -566,9 +569,9 @@ static void device_version_input(struct mux_device *dev, struct version_header * vh->minor = ntohl(vh->minor); if(vh->major != 2 && vh->major != 1) { usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d", dev->id, vh->major, vh->minor); - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); collection_remove(&device_list, dev); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); free(dev); return; } @@ -726,14 +729,14 @@ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_t length) { struct mux_device *dev = NULL; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *tdev, &device_list) { if(tdev->usbdev == usbdev) { dev = tdev; break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); if(!dev) { usbmuxd_log(LL_WARNING, "Cannot find device entry for RX input from USB device %p on location 0x%x", usbdev, usb_get_location(usbdev)); return; @@ -850,15 +853,15 @@ int device_add(struct usb_device *usbdev) free(dev); return res; } - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); collection_add(&device_list, dev); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); return 0; } void device_remove(struct usb_device *usbdev) { - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->usbdev == usbdev) { usbmuxd_log(LL_NOTICE, "Removed device %d on location 0x%x", dev->id, usb_get_location(usbdev)); @@ -874,48 +877,48 @@ void device_remove(struct usb_device *usbdev) preflight_device_remove_cb(dev->preflight_cb_data); } collection_remove(&device_list, dev); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); free(dev->pktbuf); free(dev); return; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); usbmuxd_log(LL_WARNING, "Cannot find device entry while removing USB device %p on location 0x%x", usbdev, usb_get_location(usbdev)); } void device_set_visible(int device_id) { - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == device_id) { dev->visible = 1; break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); } void device_set_preflight_cb_data(int device_id, void* data) { - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == device_id) { dev->preflight_cb_data = data; break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); } int device_get_count(int include_hidden) { int count = 0; struct collection dev_list = {NULL, 0}; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); collection_copy(&dev_list, &device_list); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); FOREACH(struct mux_device *dev, &dev_list) { if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) @@ -930,9 +933,9 @@ int device_get_list(int include_hidden, struct device_info **devices) { int count = 0; struct collection dev_list = {NULL, 0}; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); collection_copy(&dev_list, &device_list); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); *devices = malloc(sizeof(struct device_info) * dev_list.capacity); struct device_info *p = *devices; @@ -957,7 +960,7 @@ int device_get_list(int include_hidden, struct device_info **devices) int device_get_timeout(void) { uint64_t oldest = (uint64_t)-1LL; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->state == MUXDEV_ACTIVE) { FOREACH(struct mux_connection *conn, &dev->connections) { @@ -966,7 +969,7 @@ int device_get_timeout(void) } ENDFOREACH } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); uint64_t ct = mstime64(); if((int64_t)oldest == -1LL) return 100000; //meh @@ -978,7 +981,7 @@ int device_get_timeout(void) void device_check_timeouts(void) { uint64_t ct = mstime64(); - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->state == MUXDEV_ACTIVE) { FOREACH(struct mux_connection *conn, &dev->connections) { @@ -991,14 +994,14 @@ void device_check_timeouts(void) } ENDFOREACH } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); } void device_init(void) { usbmuxd_log(LL_DEBUG, "device_init"); collection_init(&device_list); - pthread_mutex_init(&device_list_mutex, NULL); + mutex_init(&device_list_mutex); next_device_id = 1; } @@ -1019,7 +1022,7 @@ void device_kill_connections(void) void device_shutdown(void) { usbmuxd_log(LL_DEBUG, "device_shutdown"); - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { FOREACH(struct mux_connection *conn, &dev->connections) { connection_teardown(conn); @@ -1028,7 +1031,7 @@ void device_shutdown(void) collection_remove(&device_list, dev); free(dev); } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); - pthread_mutex_destroy(&device_list_mutex); + mutex_unlock(&device_list_mutex); + mutex_destroy(&device_list_mutex); collection_free(&device_list); } diff --git a/src/preflight.c b/src/preflight.c index 820f3fc..9c57e98 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -26,8 +26,6 @@ #include <unistd.h> #include <errno.h> -#include <pthread.h> - #include <sys/time.h> #ifdef HAVE_LIBIMOBILEDEVICE @@ -36,6 +34,8 @@ #include <libimobiledevice/notification_proxy.h> #endif +#include <libimobiledevice-glue/thread.h> + #include "preflight.h" #include "device.h" #include "client.h" @@ -59,6 +59,7 @@ struct idevice_private { enum idevice_connection_type conn_type; void *conn_data; int version; + int device_class; }; struct cb_data { @@ -138,6 +139,7 @@ static void* preflight_worker_handle_device_add(void* userdata) _dev->conn_type = CONNECTION_USBMUXD; _dev->conn_data = NULL; _dev->version = 0; + _dev->device_class = 0; idevice_t dev = (idevice_t)_dev; @@ -146,6 +148,7 @@ static void* preflight_worker_handle_device_add(void* userdata) plist_t value = NULL; char* version_str = NULL; + char* deviceclass_str = NULL; usbmuxd_log(LL_INFO, "%s: Starting preflight on device %s...", __func__, _dev->udid); @@ -211,23 +214,43 @@ retry: lerr = lockdownd_get_value(lockdown, NULL, "ProductVersion", &value); if (lerr != LOCKDOWN_E_SUCCESS) { - usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get ProductVersion from device %s, lockdown error %d", __func__, _dev->udid, lerr); - goto leave; + usbmuxd_log(LL_WARNING, "%s: Could not get ProductVersion from device %s, lockdown error %d", __func__, _dev->udid, lerr); + /* assume old iOS version */ + version_str = strdup("1.0"); + } else { + if (value && plist_get_node_type(value) == PLIST_STRING) { + plist_get_string_val(value, &version_str); + } + plist_free(value); + + if (!version_str) { + usbmuxd_log(LL_ERROR, "%s: Could not get ProductVersion string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data); + goto leave; + } } + lerr = lockdownd_get_value(lockdown, NULL, "DeviceClass", &value); + if (lerr != LOCKDOWN_E_SUCCESS) { + usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get DeviceClass from device %s, lockdown error %d", __func__, _dev->udid, lerr); + goto leave; + } if (value && plist_get_node_type(value) == PLIST_STRING) { - plist_get_string_val(value, &version_str); + plist_get_string_val(value, &deviceclass_str); } + plist_free(value); - if (!version_str) { - usbmuxd_log(LL_ERROR, "%s: Could not get ProductVersion string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data); + if (!deviceclass_str) { + usbmuxd_log(LL_ERROR, "%s: Could not get DeviceClass string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data); goto leave; } int version_major = strtol(version_str, NULL, 10); - if (version_major >= 7) { - /* iOS 7.0 and later */ - usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid); + if (((!strcmp(deviceclass_str, "iPhone") || !strcmp(deviceclass_str, "iPad")) && version_major >= 7) + || (!strcmp(deviceclass_str, "Watch") && version_major >= 2) + || (!strcmp(deviceclass_str, "AppleTV") && version_major >= 9) + ) { + /* iOS 7.0 / watchOS 2.0 / tvOS 9.0 and later */ + usbmuxd_log(LL_INFO, "%s: Found %s %s device %s", __func__, deviceclass_str, version_str, _dev->udid); lockdownd_set_untrusted_host_buid(lockdown); @@ -334,10 +357,8 @@ retry: } leave: - if (value) - plist_free(value); - if (version_str) - free(version_str); + free(deviceclass_str); + free(version_str); if (lockdown) lockdownd_client_free(lockdown); if (dev) @@ -369,18 +390,15 @@ void preflight_worker_device_add(struct device_info* info) infocopy->serial = strdup(info->serial); } - pthread_t th; - pthread_attr_t attr; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - int perr = pthread_create(&th, &attr, preflight_worker_handle_device_add, infocopy); + THREAD_T th; + int perr = thread_new(&th, preflight_worker_handle_device_add, infocopy); if (perr != 0) { free((char*)infocopy->serial); free(infocopy); usbmuxd_log(LL_ERROR, "ERROR: failed to start preflight worker thread for device %s: %s (%d). Invoking client_device_add() directly but things might not work as expected.", info->serial, strerror(perr), perr); client_device_add(info); + } else { + thread_detach(th); } #else client_device_add(info); @@ -31,6 +31,8 @@ #include <libusb.h> +#include <libimobiledevice-glue/collection.h> + #include "usb.h" #include "log.h" #include "device.h" @@ -63,6 +65,14 @@ struct usb_device { struct libusb_device_descriptor devdesc; }; +struct mode_context { + struct libusb_device* dev; + uint8_t bus, address; + uint8_t bRequest; + uint16_t wValue, wIndex, wLength; + unsigned int timeout; +}; + static struct collection device_list; static struct timeval next_dev_poll_time; @@ -355,181 +365,228 @@ static void get_langid_callback(struct libusb_transfer *transfer) } } -static int usb_device_add(libusb_device* dev) +static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_context *context, libusb_transfer_cb_fn callback) +{ + struct libusb_transfer* ctrl_transfer = libusb_alloc_transfer(0); + int ret = 0; + unsigned char* buffer = calloc(LIBUSB_CONTROL_SETUP_SIZE + context->wLength, 1); + uint8_t bRequestType = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE; + libusb_fill_control_setup(buffer, bRequestType, context->bRequest, context->wValue, context->wIndex, context->wLength); + + ctrl_transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER; + libusb_fill_control_transfer(ctrl_transfer, handle, buffer, callback, context, context->timeout); + + ret = libusb_submit_transfer(ctrl_transfer); + return ret; +} + +static struct usb_device* find_device(int bus, int address) { - int j, res; - // the following are non-blocking operations on the device list - uint8_t bus = libusb_get_bus_number(dev); - uint8_t address = libusb_get_device_address(dev); - struct libusb_device_descriptor devdesc; - struct libusb_transfer *transfer; - int found = 0; FOREACH(struct usb_device *usbdev, &device_list) { if(usbdev->bus == bus && usbdev->address == address) { - usbdev->alive = 1; - found = 1; - break; + return usbdev; } } ENDFOREACH - if(found) - return 0; //device already found + return NULL; +} - if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) { - usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %s", bus, address, libusb_error_name(res)); - return -1; +/// @brief guess the current mode +/// @param dev +/// @param usbdev +/// @param handle +/// @return 0 - undetermined, 1 - initial, 2 - valeria, 3 - cdc_ncm +static int guess_mode(struct libusb_device* dev, struct usb_device *usbdev) +{ + int res, j; + int has_valeria = 0, has_cdc_ncm = 0, has_usbmux = 0; + struct libusb_device_descriptor devdesc = usbdev->devdesc; + struct libusb_config_descriptor *config; + int bus = usbdev->bus; + int address = usbdev->address; + + if(devdesc.bNumConfigurations <= 4) { + // Assume this is initial mode + return 1; } - if(devdesc.idVendor != VID_APPLE) - return -1; - if((devdesc.idProduct != PID_APPLE_T2_COPROCESSOR) && - ((devdesc.idProduct < PID_RANGE_LOW) || - (devdesc.idProduct > PID_RANGE_MAX))) - return -1; - libusb_device_handle *handle; - usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address); - // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any - // blocking call - if((res = libusb_open(dev, &handle)) != 0) { - usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %s", bus, address, libusb_error_name(res)); - return -1; + + if(devdesc.bNumConfigurations != 5) { + // No known modes with more then 5 configurations + return 0; + } + + if((res = libusb_get_config_descriptor_by_value(dev, 5, &config)) != 0) { + usbmuxd_log(LL_NOTICE, "Could not get configuration 5 descriptor for device %i-%i: %s", bus, address, libusb_error_name(res)); + return 0; } - int desired_config = devdesc.bNumConfigurations; - if (desired_config > 4) { - if (desired_config > 5) { - usbmuxd_log(LL_ERROR, "Device %d-%d has more than 5 configurations, but usbmuxd doesn't support that. Choosing configuration 5 instead.", bus, address); - desired_config = 5; + // Require both usbmux and one of the other interfaces to determine this is a valid configuration + for(j = 0 ; j < config->bNumInterfaces ; j++) { + const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; + if(intf->bInterfaceClass == INTERFACE_CLASS && + intf->bInterfaceSubClass == 42 && + intf->bInterfaceProtocol == 255) { + has_valeria = 1; } - /* verify if the configuration 5 is actually usable */ - do { - struct libusb_config_descriptor *config; - const struct libusb_interface_descriptor *intf; - if (libusb_get_config_descriptor_by_value(dev, 5, &config) != 0) { - usbmuxd_log(LL_WARNING, "Device %d-%d: Failed to get config descriptor for configuration 5, choosing configuration 4 instead.", bus, address); - desired_config = 4; - break; - } - if (config->bNumInterfaces != 3) { - usbmuxd_log(LL_WARNING, "Device %d-%d: Ignoring possibly bad configuration 5, choosing configuration 4 instead.", bus, address); - desired_config = 4; - break; - } - intf = &config->interface[2].altsetting[0]; - if (intf->bInterfaceClass != 0xFF || intf->bInterfaceSubClass != 0x2A || intf->bInterfaceProtocol != 0xFF) { - usbmuxd_log(LL_WARNING, "Device %d-%d: Ignoring possibly bad configuration 5, choosing configuration 4 instead.", bus, address); - desired_config = 4; - break; - } - } while (0); + // https://github.com/torvalds/linux/blob/72a85e2b0a1e1e6fb4ee51ae902730212b2de25c/include/uapi/linux/usb/cdc.h#L22 + // 2 for Communication class, 0xd for CDC NCM subclass + if(intf->bInterfaceClass == 2 && + intf->bInterfaceSubClass == 0xd) { + has_cdc_ncm = 1; + } + if(intf->bInterfaceClass == INTERFACE_CLASS && + intf->bInterfaceSubClass == INTERFACE_SUBCLASS && + intf->bInterfaceProtocol == INTERFACE_PROTOCOL) { + has_usbmux = 1; + } + } + + libusb_free_config_descriptor(config); + + if(has_valeria && has_usbmux) { + usbmuxd_log(LL_NOTICE, "Found Valeria and Apple USB Multiplexor in device %i-%i configuration 5", bus, address); + return 2; } + + if(has_cdc_ncm && has_usbmux) { + usbmuxd_log(LL_NOTICE, "Found CDC-NCM and Apple USB Multiplexor in device %i-%i configuration 5", bus, address); + return 3; + } + + return 0; +} + +/// @brief Finds and sets the valid configuration, interface and endpoints on the usb_device +static int set_valid_configuration(struct libusb_device* dev, struct usb_device *usbdev, struct libusb_device_handle *handle) +{ + int j, k, res, found = 0; + struct libusb_config_descriptor *config; + const struct libusb_interface_descriptor *intf; + struct libusb_device_descriptor devdesc = usbdev->devdesc; + int bus = usbdev->bus; + int address = usbdev->address; int current_config = 0; + if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { - usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %s", bus, address, libusb_error_name(res)); - libusb_close(handle); + usbmuxd_log(LL_WARNING, "Could not get current configuration for device %d-%d: %s", bus, address, libusb_error_name(res)); return -1; } - if (current_config != desired_config) { - struct libusb_config_descriptor *config; + + for(j = devdesc.bNumConfigurations ; j > 0 ; j--) { + if((res = libusb_get_config_descriptor_by_value(dev, j, &config)) != 0) { + usbmuxd_log(LL_NOTICE, "Could not get configuration %i descriptor for device %i-%i: %s", j, bus, address, libusb_error_name(res)); + continue; + } + for(k = 0 ; k < config->bNumInterfaces ; k++) { + intf = &config->interface[k].altsetting[0]; + if(intf->bInterfaceClass == INTERFACE_CLASS || + intf->bInterfaceSubClass == INTERFACE_SUBCLASS || + intf->bInterfaceProtocol == INTERFACE_PROTOCOL) { + usbmuxd_log(LL_NOTICE, "Found usbmux interface for device %i-%i: %i", bus, address, intf->bInterfaceNumber); + if(intf->bNumEndpoints != 2) { + usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address); + continue; + } + if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && + (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { + usbdev->interface = intf->bInterfaceNumber; + usbdev->ep_out = intf->endpoint[0].bEndpointAddress; + usbdev->ep_in = intf->endpoint[1].bEndpointAddress; + usbmuxd_log(LL_INFO, "Found interface %i with endpoints %02x/%02x for device %i-%i", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address); + found = 1; + break; + } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && + (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { + usbdev->interface = intf->bInterfaceNumber; + usbdev->ep_out = intf->endpoint[1].bEndpointAddress; + usbdev->ep_in = intf->endpoint[0].bEndpointAddress; + usbmuxd_log(LL_INFO, "Found interface %i with swapped endpoints %02x/%02x for device %i-%i", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address); + found = 1; + break; + } else { + usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address); + } + } + } + if(!found) { + libusb_free_config_descriptor(config); + continue; + } + // If set configuration is required, try to first detach all kernel drivers if (current_config == 0) { usbmuxd_log(LL_DEBUG, "Device %d-%d is unconfigured", bus, address); - } else if ((res = libusb_get_active_config_descriptor(dev, &config)) != 0) { - usbmuxd_log(LL_NOTICE, "Could not get old configuration descriptor for device %d-%d: %s", bus, address, libusb_error_name(res)); - } else { - for(j=0; j<config->bNumInterfaces; j++) { - const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; - if((res = libusb_kernel_driver_active(handle, intf->bInterfaceNumber)) < 0) { - usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %s", intf->bInterfaceNumber, bus, address, libusb_error_name(res)); + } + if(current_config == 0 || config->bConfigurationValue != current_config) { + usbmuxd_log(LL_NOTICE, "Changing configuration of device %i-%i: %i -> %i", bus, address, current_config, config->bConfigurationValue); + for(k=0 ; k < config->bNumInterfaces ; k++) { + const struct libusb_interface_descriptor *intf1 = &config->interface[k].altsetting[0]; + if((res = libusb_kernel_driver_active(handle, intf1->bInterfaceNumber)) < 0) { + usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %s", intf1->bInterfaceNumber, bus, address, libusb_error_name(res)); continue; } if(res == 1) { - usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf->bInterfaceNumber); - if((res = libusb_detach_kernel_driver(handle, intf->bInterfaceNumber)) < 0) { + usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf1->bInterfaceNumber); + if((res = libusb_detach_kernel_driver(handle, intf1->bInterfaceNumber)) < 0) { usbmuxd_log(LL_WARNING, "Could not detach kernel driver, configuration change will probably fail! %s", libusb_error_name(res)); continue; } } } - libusb_free_config_descriptor(config); - } - - usbmuxd_log(LL_INFO, "Setting configuration for device %d-%d, from %d to %d", bus, address, current_config, desired_config); - if((res = libusb_set_configuration(handle, desired_config)) != 0) { - usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %s", desired_config, bus, address, libusb_error_name(res)); - libusb_close(handle); - return -1; + if((res = libusb_set_configuration(handle, j)) != 0) { + usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %s", j, bus, address, libusb_error_name(res)); + libusb_free_config_descriptor(config); + continue; + } } + + libusb_free_config_descriptor(config); + break; } - struct libusb_config_descriptor *config; - if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) { - usbmuxd_log(LL_WARNING, "Could not get configuration descriptor for device %d-%d: %s", bus, address, libusb_error_name(res)); - libusb_close(handle); + if(!found) { + usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %i-%i", bus, address); return -1; } - struct usb_device *usbdev; - usbdev = malloc(sizeof(struct usb_device)); - memset(usbdev, 0, sizeof(*usbdev)); + return 0; +} - for(j=0; j<config->bNumInterfaces; j++) { - const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; - if(intf->bInterfaceClass != INTERFACE_CLASS || - intf->bInterfaceSubClass != INTERFACE_SUBCLASS || - intf->bInterfaceProtocol != INTERFACE_PROTOCOL) - continue; - if(intf->bNumEndpoints != 2) { - usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address); - continue; - } - if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && - (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { - usbdev->interface = intf->bInterfaceNumber; - usbdev->ep_out = intf->endpoint[0].bEndpointAddress; - usbdev->ep_in = intf->endpoint[1].bEndpointAddress; - usbmuxd_log(LL_INFO, "Found interface %d with endpoints %02x/%02x for device %d-%d", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address); - break; - } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && - (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { - usbdev->interface = intf->bInterfaceNumber; - usbdev->ep_out = intf->endpoint[1].bEndpointAddress; - usbdev->ep_in = intf->endpoint[0].bEndpointAddress; - usbmuxd_log(LL_INFO, "Found interface %d with swapped endpoints %02x/%02x for device %d-%d", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address); - break; - } else { - usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address); - } +static void device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle) +{ + struct usb_device *usbdev = find_device(context->bus, context->address); + if(!usbdev) { + usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting initialization", context->bus, context->address); + return; } + struct libusb_device *dev = context->dev; + struct libusb_device_descriptor devdesc = usbdev->devdesc; + int bus = context->bus; + int address = context->address; + int res; + struct libusb_transfer *transfer; - if(j == config->bNumInterfaces) { - usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %d-%d", bus, address); - libusb_free_config_descriptor(config); - libusb_close(handle); - free(usbdev); - return -1; + if((res = set_valid_configuration(dev, usbdev, handle)) != 0) { + usbdev->alive = 0; + return; } - libusb_free_config_descriptor(config); - if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) { usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %s", usbdev->interface, bus, address, libusb_error_name(res)); - libusb_close(handle); - free(usbdev); - return -1; + usbdev->alive = 0; + return; } transfer = libusb_alloc_transfer(0); if(!transfer) { usbmuxd_log(LL_WARNING, "Failed to allocate transfer for device %d-%d: %s", bus, address, libusb_error_name(res)); - libusb_close(handle); - free(usbdev); - return -1; + usbdev->alive = 0; + return; } unsigned char *transfer_buffer = malloc(1024 + LIBUSB_CONTROL_SETUP_SIZE + 8); if (!transfer_buffer) { usbmuxd_log(LL_WARNING, "Failed to allocate transfer buffer for device %d-%d: %s", bus, address, libusb_error_name(res)); - libusb_close(handle); - free(usbdev); - return -1; + usbdev->alive = 0; + return; } memset(transfer_buffer, '\0', 1024 + LIBUSB_CONTROL_SETUP_SIZE + 8); @@ -579,17 +636,164 @@ static int usb_device_add(libusb_device* dev) if((res = libusb_submit_transfer(transfer)) < 0) { usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d: %s", usbdev->bus, usbdev->address, libusb_error_name(res)); libusb_free_transfer(transfer); - libusb_close(handle); free(transfer_buffer); - free(usbdev); + usbdev->alive = 0; + return; + } +} + +static void switch_mode_cb(struct libusb_transfer* transfer) +{ + // For old devices not supporting mode swtich, if anything goes wrong - continue in current mode + struct mode_context* context = transfer->user_data; + struct usb_device *dev = find_device(context->bus, context->address); + if(!dev) { + usbmuxd_log(LL_WARNING, "Device %d-%d is missing from device list", context->bus, context->address); + } + if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { + usbmuxd_log(LL_ERROR, "Failed to request mode switch for device %i-%i (%i). Completing initialization in current mode", + context->bus, context->address, transfer->status); + device_complete_initialization(context, transfer->dev_handle); + } + else { + unsigned char *data = libusb_control_transfer_get_data(transfer); + if(data[0] != 0) { + usbmuxd_log(LL_INFO, "Received unexpected response for device %i-%i mode switch (%i). Completing initialization in current mode", + context->bus, context->address, data[0]); + device_complete_initialization(context, transfer->dev_handle); + } + } + free(context); + if(transfer->buffer) + free(transfer->buffer); +} + +static void get_mode_cb(struct libusb_transfer* transfer) +{ + // For old devices not supporting mode swtich, if anything goes wrong - continue in current mode + int res; + struct mode_context* context = transfer->user_data; + struct usb_device *dev = find_device(context->bus, context->address); + if(!dev) { + usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting mode switch", context->bus, context->address); + free(context); + return; + } + + if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { + usbmuxd_log(LL_ERROR, "Failed to request get mode for device %i-%i (%i). Completing initialization in current mode", + context->bus, context->address, transfer->status); + device_complete_initialization(context, transfer->dev_handle); + free(context); + return; + } + + unsigned char *data = libusb_control_transfer_get_data(transfer); + + char* desired_mode_char = getenv(ENV_DEVICE_MODE); + int desired_mode = desired_mode_char ? atoi(desired_mode_char) : 3; + int guessed_mode = guess_mode(context->dev, dev); + + // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise. + usbmuxd_log(LL_INFO, "Received response %i:%i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], data[3], context->bus, context->address); + if(desired_mode >= 1 && desired_mode <= 3 && + guessed_mode > 0 && // do not switch mode if guess failed + guessed_mode != desired_mode) { + usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", context->bus, context->address, desired_mode); + + context->bRequest = APPLE_VEND_SPECIFIC_SET_MODE; + context->wValue = 0; + context->wIndex = desired_mode; + context->wLength = 1; + + if((res = submit_vendor_specific(transfer->dev_handle, context, switch_mode_cb)) != 0) { + usbmuxd_log(LL_WARNING, "Could not request to switch mode %i for device %i-%i (%i)", context->wIndex, context->bus, context->address, res); + dev->alive = 0; + free(context); + } + } + else { + usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode from %i to %i", context->bus, context->address, guessed_mode, desired_mode); + device_complete_initialization(context, transfer->dev_handle); + free(context); + } + if(transfer->buffer) + free(transfer->buffer); +} + +static int usb_device_add(libusb_device* dev) +{ + int res; + // the following are non-blocking operations on the device list + uint8_t bus = libusb_get_bus_number(dev); + uint8_t address = libusb_get_device_address(dev); + struct libusb_device_descriptor devdesc; + struct usb_device *usbdev = find_device(bus, address); + if(usbdev) { + usbdev->alive = 1; + return 0; //device already found + } + + if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) { + usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %s", bus, address, libusb_error_name(res)); + return -1; + } + if(devdesc.idVendor != VID_APPLE) + return -1; + if((devdesc.idProduct != PID_APPLE_T2_COPROCESSOR) && + ((devdesc.idProduct < PID_APPLE_SILICON_RESTORE_LOW) || + (devdesc.idProduct > PID_APPLE_SILICON_RESTORE_MAX)) && + ((devdesc.idProduct < PID_RANGE_LOW) || + (devdesc.idProduct > PID_RANGE_MAX))) + return -1; + libusb_device_handle *handle; + usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address); + // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any + // blocking call + if((res = libusb_open(dev, &handle)) != 0) { + usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %s", bus, address, libusb_error_name(res)); return -1; } + // Add the created handle to the device list, so we can close it in case of failure/disconnection + usbdev = malloc(sizeof(struct usb_device)); + memset(usbdev, 0, sizeof(*usbdev)); + + usbdev->serial[0] = 0; + usbdev->bus = bus; + usbdev->address = address; + usbdev->devdesc = devdesc; + usbdev->speed = 0; + usbdev->dev = handle; + usbdev->alive = 1; + collection_init(&usbdev->tx_xfers); collection_init(&usbdev->rx_xfers); collection_add(&device_list, usbdev); + // On top of configurations, Apple have multiple "modes" for devices, namely: + // 1: An "initial" mode with 4 configurations + // 2: "Valeria" mode, where configuration 5 is included with interface for H.265 video capture (activated when recording screen with QuickTime in macOS) + // 3: "CDC NCM" mode, where configuration 5 is included with interface for Ethernet/USB (activated using internet-sharing feature in macOS) + // Request current mode asynchroniously, so it can be changed in callback if needed + usbmuxd_log(LL_INFO, "Requesting current mode from device %i-%i", bus, address); + struct mode_context* context = malloc(sizeof(struct mode_context)); + context->dev = dev; + context->bus = bus; + context->address = address; + context->bRequest = APPLE_VEND_SPECIFIC_GET_MODE; + context->wValue = 0; + context->wIndex = 0; + context->wLength = 4; + context->timeout = 1000; + + if(submit_vendor_specific(handle, context, get_mode_cb) != 0) { + usbmuxd_log(LL_WARNING, "Could not request current mode from device %d-%d", bus, address); + // Schedule device for close and cleanup + usbdev->alive = 0; + return -1; + } return 0; } @@ -827,17 +1031,17 @@ int usb_init(void) device_polling = 1; res = libusb_init(NULL); + if (res != 0) { + usbmuxd_log(LL_FATAL, "libusb_init failed: %s", libusb_error_name(res)); + return -1; + } + #if LIBUSB_API_VERSION >= 0x01000106 libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, (log_level >= LL_DEBUG ? LIBUSB_LOG_LEVEL_DEBUG: (log_level >= LL_WARNING ? LIBUSB_LOG_LEVEL_WARNING: LIBUSB_LOG_LEVEL_NONE))); #else libusb_set_debug(NULL, (log_level >= LL_DEBUG ? LIBUSB_LOG_LEVEL_DEBUG: (log_level >= LL_WARNING ? LIBUSB_LOG_LEVEL_WARNING: LIBUSB_LOG_LEVEL_NONE))); #endif - if(res != 0) { - usbmuxd_log(LL_FATAL, "libusb_init failed: %s", libusb_error_name(res)); - return -1; - } - collection_init(&device_list); #ifdef HAVE_LIBUSB_HOTPLUG_API @@ -47,6 +47,12 @@ #define PID_RANGE_LOW 0x1290 #define PID_RANGE_MAX 0x12af #define PID_APPLE_T2_COPROCESSOR 0x8600 +#define PID_APPLE_SILICON_RESTORE_LOW 0x1901 +#define PID_APPLE_SILICON_RESTORE_MAX 0x1905 + +#define ENV_DEVICE_MODE "USBMUXD_DEFAULT_DEVICE_MODE" +#define APPLE_VEND_SPECIFIC_GET_MODE 0x45 +#define APPLE_VEND_SPECIFIC_SET_MODE 0x52 struct usb_device; diff --git a/src/utils.c b/src/utils.c index 206c684..2cc5675 100644 --- a/src/utils.c +++ b/src/utils.c @@ -76,254 +76,6 @@ void fdlist_reset(struct fdlist *list) list->count = 0; } -#define CAPACITY_STEP 8 - -void collection_init(struct collection *col) -{ - col->list = malloc(sizeof(void *) * CAPACITY_STEP); - memset(col->list, 0, sizeof(void *) * CAPACITY_STEP); - col->capacity = CAPACITY_STEP; -} - -void collection_free(struct collection *col) -{ - free(col->list); - col->list = NULL; - col->capacity = 0; -} - -void collection_add(struct collection *col, void *element) -{ - int i; - for(i=0; i<col->capacity; i++) { - if(!col->list[i]) { - col->list[i] = element; - return; - } - } - col->list = realloc(col->list, sizeof(void*) * (col->capacity + CAPACITY_STEP)); - memset(&col->list[col->capacity], 0, sizeof(void *) * CAPACITY_STEP); - col->list[col->capacity] = element; - col->capacity += CAPACITY_STEP; -} - -void collection_remove(struct collection *col, void *element) -{ - int i; - for(i=0; i<col->capacity; i++) { - if(col->list[i] == element) { - col->list[i] = NULL; - return; - } - } - util_error("collection_remove: element %p not present in collection %p (cap %d)", element, col, col->capacity); -} - -int collection_count(struct collection *col) -{ - int i, cnt = 0; - for(i=0; i<col->capacity; i++) { - if(col->list[i]) - cnt++; - } - return cnt; -} - -void collection_copy(struct collection *dest, struct collection *src) -{ - if (!dest || !src) return; - dest->capacity = src->capacity; - dest->list = malloc(sizeof(void*) * src->capacity); - memcpy(dest->list, src->list, sizeof(void*) * src->capacity); -} - -#ifndef HAVE_STPCPY -/** - * Copy characters from one string into another - * - * @note: The strings should not overlap, as the behavior is undefined. - * - * @s1: The source string. - * @s2: The destination string. - * - * @return a pointer to the terminating `\0' character of @s1, - * or NULL if @s1 or @s2 is NULL. - */ -char *stpcpy(char * s1, const char * s2) -{ - if (s1 == NULL || s2 == NULL) - return NULL; - - strcpy(s1, s2); - - return s1 + strlen(s2); -} -#endif - -/** - * Concatenate strings into a newly allocated string - * - * @note: Specify NULL for the last string in the varargs list - * - * @str: The first string in the list - * @...: Subsequent strings. Use NULL for the last item. - * - * @return a newly allocated string, or NULL if @str is NULL. This will also - * return NULL and set errno to ENOMEM if memory is exhausted. - */ -char *string_concat(const char *str, ...) -{ - size_t len; - va_list args; - char *s; - char *result; - char *dest; - - if (!str) - return NULL; - - /* Compute final length */ - - len = strlen(str) + 1; /* plus 1 for the null terminator */ - - va_start(args, str); - s = va_arg(args, char *); - while (s) { - len += strlen(s); - s = va_arg(args, char*); - } - va_end(args); - - /* Concat each string */ - - result = malloc(len); - if (!result) - return NULL; /* errno remains set */ - - dest = result; - - dest = stpcpy(dest, str); - - va_start(args, str); - s = va_arg(args, char *); - while (s) { - dest = stpcpy(dest, s); - s = va_arg(args, char *); - } - va_end(args); - - return result; -} - -int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length) -{ - FILE *f; - uint64_t size; - - *length = 0; - - f = fopen(filename, "rb"); - if (!f) { - return 0; - } - - fseek(f, 0, SEEK_END); - size = ftell(f); - rewind(f); - - if (size == 0) { - fclose(f); - return 0; - } - - *buffer = (char*)malloc(sizeof(char)*(size+1)); - - if (!buffer) { - return 0; - } - - int ret = 1; - if (fread(*buffer, sizeof(char), size, f) != size) { - usbmuxd_log(LL_ERROR, "%s: ERROR: couldn't read %d bytes from %s", __func__, (int)size, filename); - free(*buffer); - ret = 0; - errno = EIO; - } - fclose(f); - - *length = size; - return ret; -} - -int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length) -{ - FILE *f; - - f = fopen(filename, "wb"); - if (f) { - size_t written = fwrite(buffer, sizeof(char), length, f); - fclose(f); - - if (written == length) { - return 1; - } - else { - // Not all data could be written. - errno = EIO; - return 0; - } - } - else { - // Failed to open the file, let the caller know. - return 0; - } -} - -int plist_read_from_filename(plist_t *plist, const char *filename) -{ - char *buffer = NULL; - uint64_t length; - - if (!filename) - return 0; - - if (!buffer_read_from_filename(filename, &buffer, &length)) { - return 0; - } - - if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) { - plist_from_bin(buffer, length, plist); - } else { - plist_from_xml(buffer, length, plist); - } - - free(buffer); - - return 1; -} - -int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format) -{ - char *buffer = NULL; - uint32_t length; - - if (!plist || !filename) - return 0; - - if (format == PLIST_FORMAT_XML) - plist_to_xml(plist, &buffer, &length); - else if (format == PLIST_FORMAT_BINARY) - plist_to_bin(plist, &buffer, &length); - else - return 0; - - int res = buffer_write_to_filename(filename, buffer, length); - - free(buffer); - - return res; -} - #ifndef HAVE_CLOCK_GETTIME typedef int clockid_t; #define CLOCK_MONOTONIC 1 diff --git a/src/utils.h b/src/utils.h index b5cab3f..ce3b2e0 100644 --- a/src/utils.h +++ b/src/utils.h @@ -43,49 +43,6 @@ void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events); void fdlist_free(struct fdlist *list); void fdlist_reset(struct fdlist *list); -struct collection { - void **list; - int capacity; -}; - -void collection_init(struct collection *col); -void collection_add(struct collection *col, void *element); -void collection_remove(struct collection *col, void *element); -int collection_count(struct collection *col); -void collection_free(struct collection *col); -void collection_copy(struct collection *dest, struct collection *src); - -#define MERGE_(a,b) a ## _ ## b -#define LABEL_(a,b) MERGE_(a, b) -#define UNIQUE_VAR(a) LABEL_(a, __LINE__) - -#define FOREACH(var, col) \ - do { \ - int UNIQUE_VAR(_iter); \ - for(UNIQUE_VAR(_iter)=0; UNIQUE_VAR(_iter)<(col)->capacity; UNIQUE_VAR(_iter)++) { \ - if(!(col)->list[UNIQUE_VAR(_iter)]) continue; \ - var = (col)->list[UNIQUE_VAR(_iter)]; - -#define ENDFOREACH \ - } \ - } while(0); - -#ifndef HAVE_STPCPY -char *stpcpy(char * s1, const char * s2); -#endif -char *string_concat(const char *str, ...); - -int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length); -int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length); - -enum plist_format_t { - PLIST_FORMAT_XML, - PLIST_FORMAT_BINARY -}; - -int plist_read_from_filename(plist_t *plist, const char *filename); -int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format); - uint64_t mstime64(void); void get_tick_count(struct timeval * tv); |