From c46062aca98f2f077b3bab5c5f72ff2cb57b9dc2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 20 Aug 2009 01:19:09 +0200 Subject: Updated usbmuxd protocol definition and public header. [Hector] Merged by putting utils.c into a common dir, avoiding log.c dependency for libusbmuxd, adding CMake magic to tie things up. --- common/utils.c | 117 ++++++++++++++++ common/utils.h | 65 +++++++++ libusbmuxd/CMakeLists.txt | 4 +- libusbmuxd/libusbmuxd.c | 333 +++++++++++++++++++++++++++++++++++++++------ libusbmuxd/usbmuxd-proto.h | 58 ++++---- libusbmuxd/usbmuxd.h | 61 +++++++-- tools/iproxy.c | 4 +- usbmuxd/CMakeLists.txt | 8 +- usbmuxd/client.c | 36 ++--- usbmuxd/client.h | 50 +------ usbmuxd/utils.c | 110 --------------- usbmuxd/utils.h | 65 --------- 12 files changed, 582 insertions(+), 329 deletions(-) create mode 100644 common/utils.c create mode 100644 common/utils.h delete mode 100644 usbmuxd/utils.c delete mode 100644 usbmuxd/utils.h diff --git a/common/utils.c b/common/utils.c new file mode 100644 index 0000000..6803941 --- /dev/null +++ b/common/utils.c @@ -0,0 +1,117 @@ +/* + usbmuxd - iPhone/iPod Touch USB multiplex server daemon + +Copyright (C) 2009 Hector Martin "marcan" + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 or version 3. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include "utils.h" + +#ifdef USBMUXD_DAEMON +# include "log.h" +# define util_error(...) usbmuxd_log(LL_ERROR, __VA_ARGS__) +#else +# define util_error(...) fprintf(stderr, __VA_ARGS__) +#endif + +void fdlist_create(struct fdlist *list) +{ + list->count = 0; + list->capacity = 4; + list->owners = malloc(sizeof(*list->owners) * list->capacity); + list->fds = malloc(sizeof(*list->fds) * list->capacity); +} +void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events) +{ + if(list->count == list->capacity) { + list->capacity *= 2; + list->owners = realloc(list->owners, sizeof(*list->owners) * list->capacity); + list->fds = realloc(list->fds, sizeof(*list->fds) * list->capacity); + } + list->owners[list->count] = owner; + list->fds[list->count].fd = fd; + list->fds[list->count].events = events; + list->fds[list->count].revents = 0; + list->count++; +} + +void fdlist_free(struct fdlist *list) +{ + list->count = 0; + list->capacity = 0; + free(list->owners); + list->owners = NULL; + free(list->fds); + list->fds = NULL; +} + +void collection_init(struct collection *col) +{ + col->list = malloc(sizeof(void *)); + memset(col->list, 0, sizeof(void *)); + col->capacity = 1; +} + +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; icapacity; i++) { + if(!col->list[i]) { + col->list[i] = element; + return; + } + } + col->list = realloc(col->list, sizeof(void*) * col->capacity * 2); + memset(&col->list[col->capacity], 0, sizeof(void *) * col->capacity); + col->list[col->capacity] = element; + col->capacity *= 2; +} + +void collection_remove(struct collection *col, void *element) +{ + int i; + for(i=0; icapacity; 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; icapacity; i++) { + if(col->list[i]) + cnt++; + } + return cnt; +} diff --git a/common/utils.h b/common/utils.h new file mode 100644 index 0000000..ad4ac9d --- /dev/null +++ b/common/utils.h @@ -0,0 +1,65 @@ +/* + usbmuxd - iPhone/iPod Touch USB multiplex server daemon + +Copyright (C) 2009 Hector Martin "marcan" + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 or version 3. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef __UTILS_H__ +#define __UTILS_H__ + +#include + +enum fdowner { + FD_LISTEN, + FD_CLIENT, + FD_USB +}; + +struct fdlist { + int count; + int capacity; + enum fdowner *owners; + struct pollfd *fds; +}; + +void fdlist_create(struct fdlist *list); +void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events); +void fdlist_free(struct fdlist *list); + +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); + +#define FOREACH(var, col) \ + do { \ + int _iter; \ + for(_iter=0; _iter<(col)->capacity; _iter++) { \ + if(!(col)->list[_iter]) continue; \ + var = (col)->list[_iter]; + +#define ENDFOREACH \ + } \ + } while(0); + +#endif diff --git a/libusbmuxd/CMakeLists.txt b/libusbmuxd/CMakeLists.txt index 61de1a8..7f7b35f 100644 --- a/libusbmuxd/CMakeLists.txt +++ b/libusbmuxd/CMakeLists.txt @@ -1,4 +1,6 @@ -add_library (libusbmuxd libusbmuxd.c sock_stuff.c) +include_directories (${CMAKE_SOURCE_DIR}/common) + +add_library (libusbmuxd libusbmuxd.c sock_stuff.c ../common/utils.c) # 'lib' is a UNIXism, the proper CMake target is usbmuxd # But we can't use that due to the conflict with the usbmuxd daemon, diff --git a/libusbmuxd/libusbmuxd.c b/libusbmuxd/libusbmuxd.c index 090695f..6a54765 100644 --- a/libusbmuxd/libusbmuxd.c +++ b/libusbmuxd/libusbmuxd.c @@ -6,6 +6,7 @@ #include #include #include +#include // usbmuxd public interface #include "usbmuxd.h" @@ -13,10 +14,48 @@ #include "usbmuxd-proto.h" // socket utility functions #include "sock_stuff.h" +// misc utility functions +#include "utils.h" +static struct collection devices; +static usbmuxd_event_cb_t event_cb = NULL; +pthread_t devmon; +static int listenfd = -1; + +/** + * Finds a device info record by its handle. + * if the record is not found, NULL is returned. + */ +static usbmuxd_device_info_t *devices_find(int handle) +{ + FOREACH(usbmuxd_device_info_t *dev, &devices) { + if (dev && dev->handle == handle) { + return dev; + } + } ENDFOREACH + return NULL; +} + +/** + * Creates a socket connection to usbmuxd. + * For Mac/Linux it is a unix domain socket, + * for Windows it is a tcp socket. + */ +static int connect_usbmuxd_socket() +{ +#ifdef WINDOWS + return connect_socket("127.0.0.1", 27015); +#else + return connect_unix_socket(USBMUXD_SOCKET_FILE); +#endif +} + +/** + * Retrieves the result code to a previously sent request. + */ static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result) { - struct usbmuxd_result res; + struct usbmuxd_result_msg res; int recv_len; if (!result) { @@ -29,8 +68,8 @@ static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result) } else { if ((recv_len == sizeof(res)) && (res.header.length == (uint32_t) recv_len) - && (res.header.reserved == 0) - && (res.header.type == USBMUXD_RESULT) + && (res.header.version == USBMUXD_PROTOCOL_VERSION) + && (res.header.message == MESSAGE_RESULT) ) { *result = res.result; if (res.header.tag == tag) { @@ -44,16 +83,229 @@ static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result) return -1; } -int usbmuxd_scan(usbmuxd_scan_result ** available_devices) +/** + * Generates an event, i.e. calls the callback function. + * A reference to a populated usbmuxd_event_t with information about the event + * and the corresponding device will be passed to the callback function. + */ +static void generate_event(usbmuxd_event_cb_t callback, const usbmuxd_device_info_t *dev, enum usbmuxd_device_event event) +{ + usbmuxd_event_t ev; + + if (!callback || !dev) { + return; + } + + ev.event = event; + memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t)); + + printf("%s: event=%d, handle=%d\n", __func__, ev.event, ev.device.handle); + + callback(&ev); +} + +/** + * Tries to connect to usbmuxd and wait if it is not running. + * + * TODO inotify support should come here + */ +static int usbmuxd_listen() { - struct usbmuxd_scan_request s_req; int sfd; - int scan_success = 0; + uint32_t res = -1; + struct usbmuxd_listen_request req; + struct usbmuxd_header hdr; + + req.header.length = sizeof(struct usbmuxd_listen_request); + req.header.version = USBMUXD_PROTOCOL_VERSION; + req.header.message = MESSAGE_LISTEN; + req.header.tag = 2; + + sfd = connect_usbmuxd_socket(); + if (sfd < 0) { + fprintf(stderr, "DEBUG: waiting for usbmuxd to come up.\n"); + + while (event_cb) { + if ((sfd = connect_usbmuxd_socket()) > 0) { + fprintf(stderr, "DEBUG: usbmuxd started\n"); + break; + } + sleep(1); + } + } + + if (sfd < 0) { + fprintf(stderr, "ERROR: usbmuxd was supposed to be running here...\n"); + return sfd; + } + + if (send_buf(sfd, &req, req.header.length) != (int)req.header.length) { + fprintf(stderr, "ERROR: could not send listen packet\n"); + close(sfd); + return -1; + } + if (usbmuxd_get_result(sfd, req.header.tag, &res) && (res != 0)) { + fprintf(stderr, "ERROR: did not get OK\n"); + close(sfd); + return -1; + } + + return sfd; +} + +/** + * Waits for an event to occur, i.e. a packet coming from usbmuxd. + * Calls generate_event to pass the event via callback to the client program. + */ +int get_next_event(int sfd, usbmuxd_event_cb_t callback) +{ + int recv_len; + struct usbmuxd_listen_request req; + struct usbmuxd_header hdr; + + /* block until we receive something */ + recv_len = recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, 0); + if (recv_len < 0) { + int i; + fprintf(stderr, "DEBUG: connection closed.\n"); + // when then usbmuxd connection fails, + // generate remove events for every device that + // is still present so applications know about it + // TODO: is this behaviour correct? + FOREACH(usbmuxd_device_info_t *dev, &devices) { + generate_event(callback, dev, UE_DEVICE_REMOVE); + } ENDFOREACH + collection_free(&devices); + return recv_len; + } else if (recv_len == sizeof(hdr)) { + if (hdr.message == MESSAGE_DEVICE_ADD) { + struct usbmuxd_device_record dev; + usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t)); + if (!devinfo) { + fprintf(stderr, "Out of memory!\n"); + return -1; + } + + if (hdr.length != sizeof(struct usbmuxd_header)+sizeof(struct usbmuxd_device_record)) { + fprintf(stderr, "WARNING: unexpected packet size%d for MESSAGE_DEVICE_ADD (expected %d)!\n", hdr.length, sizeof(struct usbmuxd_header)+sizeof(struct usbmuxd_device_record)); + } + recv_len = recv_buf_timeout(sfd, &dev, hdr.length - sizeof(struct usbmuxd_header), 0, 5000); + if (recv_len != (hdr.length - sizeof(struct usbmuxd_header))) { + fprintf(stderr, "Could not receive packet\n"); + return recv_len; + } + + devinfo->handle = dev.device_id; + devinfo->product_id = dev.product_id; + memset(devinfo->uuid, '\0', sizeof(devinfo->uuid)); + memcpy(devinfo->uuid, dev.serial_number, sizeof(devinfo->uuid)); + + collection_add(&devices, devinfo); + generate_event(callback, devinfo, UE_DEVICE_ADD); + } else if (hdr.message == MESSAGE_DEVICE_REMOVE) { + uint32_t handle; + usbmuxd_device_info_t *dev; + + if (hdr.length != sizeof(struct usbmuxd_header)+sizeof(uint32_t)) { + fprintf(stderr, "WARNING: unexpected packet size%d for MESSAGE_DEVICE_REMOVE (expected %d)!\n", hdr.length, sizeof(struct usbmuxd_header)+sizeof(uint32_t)); + } + recv_len = recv_buf_timeout(sfd, &handle, sizeof(uint32_t), 0, 5000); + if (recv_len != sizeof(uint32_t)) { + fprintf(stderr, "Could not receive packet\n"); + return recv_len; + } + + dev = devices_find(handle); + if (!dev) { + fprintf(stderr, "WARNING: got device remove message for handle %d, but couldn't find the corresponding handle in the device list. This event will be ignored.\n", handle); + } else { + generate_event(callback, dev, UE_DEVICE_REMOVE); + collection_remove(&devices, dev); + } + } else { + fprintf(stderr, "%s: Unknown message type %d length %d\n", __func__, hdr.message, hdr.length); + } + } else { + fprintf(stderr, "%s: ERROR: incomplete packet received!\n", __func__); + } + return 0; +} + +/** + * Device Monitor thread function. + * + * This function sets up a connection to usbmuxd + */ +static void *device_monitor(void *data) +{ + collection_init(&devices); + + while (event_cb) { + + listenfd = usbmuxd_listen(); + if (listenfd < 0) { + fprintf(stderr, "DEBUG: listenfd=%d\n", listenfd); + continue; + } + + while (event_cb) { + printf("waiting for events\n"); + int res = get_next_event(listenfd, event_cb); + if (res < 0) { + fprintf(stderr, "%s: closing connection (code %d)\n", __func__, res); + break; + } + } + } + + collection_free(&devices); + printf("%s: terminated\n", __func__); + + return NULL; +} + +int usbmuxd_subscribe(usbmuxd_event_cb_t callback) +{ + int res; + + if (!callback) { + return -EINVAL; + } + event_cb = callback; + + res = pthread_create(&devmon, NULL, device_monitor, NULL); + if (res != 0) { + fprintf(stderr, "ERROR: Could not start device watcher thread!\n"); + return res; + } + return 0; +} + +int usbmuxd_unsubscribe() +{ + event_cb = NULL; + + if (pthread_kill(devmon, 0) == 0) { + printf("%s: unsubscribing callback\n", __func__); + close(listenfd); + listenfd = -1; + pthread_kill(devmon, SIGINT); + pthread_join(devmon, NULL); + } + + return 0; +} + +int usbmuxd_scan(usbmuxd_device_info_t ** available_devices) +{ + struct usbmuxd_listen_request s_req; + int sfd; + int listen_success = 0; uint32_t res; - uint32_t pktlen; int recv_len; - usbmuxd_scan_result *newlist = NULL; - struct usbmuxd_device_info_record dev_info_pkt; + usbmuxd_device_info_t *newlist = NULL; + struct usbmuxd_header hdr; + struct usbmuxd_device_record dev_info; int dev_cnt = 0; sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); @@ -62,9 +314,9 @@ int usbmuxd_scan(usbmuxd_scan_result ** available_devices) return sfd; } - s_req.header.length = sizeof(struct usbmuxd_scan_request); - s_req.header.reserved = 0; - s_req.header.type = USBMUXD_SCAN; + s_req.header.length = sizeof(struct usbmuxd_listen_request); + s_req.header.version = USBMUXD_PROTOCOL_VERSION; + s_req.header.message = MESSAGE_LISTEN; s_req.header.tag = 2; // send scan request packet @@ -73,7 +325,7 @@ int usbmuxd_scan(usbmuxd_scan_result ** available_devices) res = -1; // get response if (usbmuxd_get_result(sfd, s_req.header.tag, &res) && (res == 0)) { - scan_success = 1; + listen_success = 1; } else { fprintf(stderr, "%s: Did not get response to scan request (with result=0)...\n", @@ -83,50 +335,44 @@ int usbmuxd_scan(usbmuxd_scan_result ** available_devices) } } - if (!scan_success) { - fprintf(stderr, "%s: Could not send scan request!\n", __func__); + if (!listen_success) { + fprintf(stderr, "%s: Could not send listen request!\n", __func__); return -1; } *available_devices = NULL; // receive device list while (1) { - if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) { - if (pktlen != sizeof(dev_info_pkt)) { + if (recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, 1000) == sizeof(hdr)) { + if (hdr.length != sizeof(hdr)+sizeof(dev_info)) { // invalid packet size received! fprintf(stderr, "%s: Invalid packet size (%d) received when expecting a device info record.\n", - __func__, pktlen); + __func__, hdr.length); break; } - recv_len = recv_buf(sfd, &dev_info_pkt, pktlen); + recv_len = recv_buf(sfd, &dev_info, hdr.length - sizeof(hdr)); if (recv_len <= 0) { fprintf(stderr, "%s: Error when receiving device info record\n", __func__); break; - } else if ((uint32_t) recv_len < pktlen) { + } else if ((uint32_t) recv_len < hdr.length - sizeof(hdr)) { fprintf(stderr, - "%s: received less data than specified in header!\n", - __func__); + "%s: received less data than specified in header!\n", __func__); } else { - //fprintf(stderr, "%s: got device record with id %d, UUID=%s\n", __func__, dev_info_pkt.device_info.device_id, dev_info_pkt.device_info.serial_number); - newlist = - (usbmuxd_scan_result *) realloc(*available_devices, - sizeof - (usbmuxd_scan_result) * - (dev_cnt + 1)); + newlist = (usbmuxd_device_info_t *) realloc(*available_devices, sizeof(usbmuxd_device_info_t) * (dev_cnt + 1)); if (newlist) { newlist[dev_cnt].handle = - (int) dev_info_pkt.device.device_id; + (int) dev_info.device_id; newlist[dev_cnt].product_id = - dev_info_pkt.device.product_id; - memset(newlist[dev_cnt].serial_number, '\0', - sizeof(newlist[dev_cnt].serial_number)); - memcpy(newlist[dev_cnt].serial_number, - dev_info_pkt.device.serial_number, - sizeof(dev_info_pkt.device.serial_number)); + dev_info.product_id; + memset(newlist[dev_cnt].uuid, '\0', + sizeof(newlist[dev_cnt].uuid)); + memcpy(newlist[dev_cnt].uuid, + dev_info.serial_number, + sizeof(newlist[dev_cnt].uuid)); *available_devices = newlist; dev_cnt++; } else { @@ -144,24 +390,21 @@ int usbmuxd_scan(usbmuxd_scan_result ** available_devices) } // terminating zero record - newlist = - (usbmuxd_scan_result *) realloc(*available_devices, - sizeof(usbmuxd_scan_result) * - (dev_cnt + 1)); - memset(newlist + dev_cnt, 0, sizeof(usbmuxd_scan_result)); + newlist = (usbmuxd_device_info_t*) realloc(*available_devices, sizeof(usbmuxd_device_info_t) * (dev_cnt + 1)); + memset(newlist + dev_cnt, 0, sizeof(usbmuxd_device_info_t)); *available_devices = newlist; return dev_cnt; } -int usbmuxd_connect(const int handle, const unsigned short tcp_port) +int usbmuxd_connect(const int handle, const unsigned short port) { int sfd; struct usbmuxd_connect_request c_req; int connected = 0; uint32_t res = -1; - sfd = connect_unix_socket(USBMUXD_SOCKET_FILE); + sfd = connect_usbmuxd_socket(); if (sfd < 0) { fprintf(stderr, "%s: Error: Connection to usbmuxd failed: %s\n", __func__, strerror(errno)); @@ -169,11 +412,11 @@ int usbmuxd_connect(const int handle, const unsigned short tcp_port) } c_req.header.length = sizeof(c_req); - c_req.header.reserved = 0; - c_req.header.type = USBMUXD_CONNECT; + c_req.header.version = USBMUXD_PROTOCOL_VERSION; + c_req.header.message = MESSAGE_CONNECT; c_req.header.tag = 3; c_req.device_id = (uint32_t) handle; - c_req.tcp_dport = htons(tcp_port); + c_req.port = htons(port); c_req.reserved = 0; if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) { diff --git a/libusbmuxd/usbmuxd-proto.h b/libusbmuxd/usbmuxd-proto.h index 7f8c2d6..1ecb7bc 100644 --- a/libusbmuxd/usbmuxd-proto.h +++ b/libusbmuxd/usbmuxd-proto.h @@ -1,52 +1,62 @@ /* Protocol defintion for usbmuxd proxy protocol */ - #ifndef __USBMUXD_PROTO_H #define __USBMUXD_PROTO_H #include +#define USBMUXD_PROTOCOL_VERSION 0 #define USBMUXD_SOCKET_FILE "/var/run/usbmuxd" +enum usbmuxd_result { + RESULT_OK = 0, + RESULT_BADCOMMAND = 1, + RESULT_BADDEV = 2, + RESULT_CONNREFUSED = 3, + // ??? + // ??? + RESULT_BADVERSION = 6, +}; + +enum usbmuxd_msgtype { + MESSAGE_RESULT = 1, + MESSAGE_CONNECT = 2, + MESSAGE_LISTEN = 3, + MESSAGE_DEVICE_ADD = 4, + MESSAGE_DEVICE_REMOVE = 5, + //??? + //??? + //MESSAGE_PLIST = 8, +}; + struct usbmuxd_header { uint32_t length; // length of message, including header - uint32_t reserved; // always zero - uint32_t type; // message type + uint32_t version; // protocol version + uint32_t message; // message type uint32_t tag; // responses to this query will echo back this tag } __attribute__((__packed__)); -struct usbmuxd_result { +struct usbmuxd_result_msg { struct usbmuxd_header header; uint32_t result; } __attribute__((__packed__)); -struct usbmuxd_connect_request { +struct usbmuxd_connect_request { struct usbmuxd_header header; uint32_t device_id; - uint16_t tcp_dport; // TCP port number + uint16_t port; // TCP port number uint16_t reserved; // set to zero } __attribute__((__packed__)); -struct usbmuxd_device { - uint32_t device_id; - uint16_t product_id; - char serial_number[40]; -} __attribute__((__packed__)); - -struct usbmuxd_device_info_record { +struct usbmuxd_listen_request { struct usbmuxd_header header; - struct usbmuxd_device device; - char padding[222]; } __attribute__((__packed__)); -struct usbmuxd_scan_request { - struct usbmuxd_header header; +struct usbmuxd_device_record { + uint32_t device_id; + uint16_t product_id; + char serial_number[256]; + uint16_t padding; + uint32_t location; } __attribute__((__packed__)); -enum { - USBMUXD_RESULT = 1, - USBMUXD_CONNECT = 2, - USBMUXD_SCAN = 3, - USBMUXD_DEVICE_INFO = 4, -}; - #endif /* __USBMUXD_PROTO_H */ diff --git a/libusbmuxd/usbmuxd.h b/libusbmuxd/usbmuxd.h index ba45ec3..f12ae39 100644 --- a/libusbmuxd/usbmuxd.h +++ b/libusbmuxd/usbmuxd.h @@ -2,10 +2,7 @@ #define __USBMUXD_H /** - * Array entry returned by 'usbmuxd_scan()' scanning. - * - * If more than one device is available, 'product_id' and - * 'serial_number' and be analysed to help make a selection. + * Device information structure holding data to identify the device. * The relevant 'handle' should be passed to 'usbmuxd_connect()', to * start a proxy connection. The value 'handle' should be considered * opaque and no presumption made about the meaning of its value. @@ -13,22 +10,58 @@ typedef struct { int handle; int product_id; - char serial_number[41]; -} usbmuxd_scan_result; + char uuid[41]; +} usbmuxd_device_info_t; + +/** + * event types for event callback function + */ +enum usbmuxd_device_event { + UE_DEVICE_ADD = 1, + UE_DEVICE_REMOVE +}; + +/** + * Event structure that will be passed to the callback function. + * 'event' will contains the type of the event, and 'device' will contains + * information about the device. + */ +typedef struct { + int event; + usbmuxd_device_info_t device; +} usbmuxd_event_t; + +/** + * Callback function prototype. + */ +typedef void (*usbmuxd_event_cb_t) (const usbmuxd_event_t *event); + +/** + * Subscribe a callback function so that applications get to know about + * device add/remove events. + * + * @param callback A callback function that is executed when an event occurs. + * + * @return 0 on success or negative on error. + */ +int usbmuxd_subscribe(usbmuxd_event_cb_t callback); + +/** + * Unsubscribe callback. + * + * @return only 0 for now. + */ +int usbmuxd_unsubscribe(); /** - * Contacts usbmuxd and performs a scan for connected devices. + * Contacts usbmuxd and retrieves a list of connected devices. * - * @param available_devices pointer to array of usbmuxd_scan_result. - * Array of available devices. The required 'handle' - * should be passed to 'usbmuxd_connect()'. The returned array - * is zero-terminated for convenience; the final (unused) - * entry containing handle == 0. The returned array pointer - * should be freed by passing to 'free()' after use. + * @param available_devices pointer to an array of usbmuxd_device_info_t + * that will hold records of the connected devices. * * @return number of available devices, zero on no devices, or negative on error */ -int usbmuxd_scan(usbmuxd_scan_result **available_devices); +int usbmuxd_scan(usbmuxd_device_info_t **available_devices); /** * Request proxy connect to diff --git a/tools/iproxy.c b/tools/iproxy.c index 3cb2894..657ac89 100644 --- a/tools/iproxy.c +++ b/tools/iproxy.c @@ -141,7 +141,7 @@ void *run_ctos_loop(void *arg) void *acceptor_thread(void *arg) { struct client_data *cdata; - usbmuxd_scan_result *dev_list = NULL; + usbmuxd_device_info_t *dev_list = NULL; pthread_t ctos; int count; @@ -166,7 +166,7 @@ void *acceptor_thread(void *arg) return NULL; } - fprintf(stdout, "Requesting connecion to device handle == %d (serial: %s), port %d\n", dev_list[0].handle, dev_list[0].serial_number, device_port); + fprintf(stdout, "Requesting connecion to device handle == %d (serial: %s), port %d\n", dev_list[0].handle, dev_list[0].uuid, device_port); cdata->sfd = usbmuxd_connect(dev_list[0].handle, device_port); free(dev_list); diff --git a/usbmuxd/CMakeLists.txt b/usbmuxd/CMakeLists.txt index b982dc0..7d0d3d8 100644 --- a/usbmuxd/CMakeLists.txt +++ b/usbmuxd/CMakeLists.txt @@ -2,8 +2,12 @@ find_package(USB REQUIRED) include_directories(${USB_INCLUDE_DIRS}) set(LIBS ${LIBS} ${USB_LIBRARIES}) -add_definitions(-Wall -O2 -g) -add_executable(usbmuxd main.c usb-linux.c log.c utils.c device.c client.c) +include_directories (${CMAKE_SOURCE_DIR}/common) +include_directories (${CMAKE_SOURCE_DIR}/usbmuxd) +include_directories (${CMAKE_SOURCE_DIR}/libusbmuxd) + +add_definitions(-Wall -O2 -g -DUSBMUXD_DAEMON) +add_executable(usbmuxd main.c usb-linux.c log.c ../common/utils.c device.c client.c) target_link_libraries(usbmuxd ${LIBS}) install(TARGETS usbmuxd RUNTIME DESTINATION sbin) \ No newline at end of file diff --git a/usbmuxd/client.c b/usbmuxd/client.c index 7a3160f..0e47e84 100644 --- a/usbmuxd/client.c +++ b/usbmuxd/client.c @@ -150,10 +150,10 @@ void client_get_fds(struct fdlist *list) } ENDFOREACH } -static int send_pkt(struct mux_client *client, uint32_t tag, enum client_msgtype msg, void *payload, int payload_length) +static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length) { - struct client_header hdr; - hdr.version = CLIENT_PROTOCOL_VERSION; + struct usbmuxd_header hdr; + hdr.version = USBMUXD_PROTOCOL_VERSION; hdr.length = sizeof(hdr) + payload_length; hdr.message = msg; hdr.tag = tag; @@ -176,7 +176,7 @@ static int send_result(struct mux_client *client, uint32_t tag, uint32_t result) return send_pkt(client, tag, MESSAGE_RESULT, &result, sizeof(uint32_t)); } -int client_notify_connect(struct mux_client *client, enum client_result result) +int client_notify_connect(struct mux_client *client, enum usbmuxd_result result) { usbmuxd_log(LL_SPEW, "client_notify_connect fd %d result %d", client->fd, result); if(client->state == CLIENT_DEAD) @@ -201,13 +201,13 @@ int client_notify_connect(struct mux_client *client, enum client_result result) static int notify_device(struct mux_client *client, struct device_info *dev) { - struct client_msg_dev dmsg; + struct usbmuxd_device_record dmsg; memset(&dmsg, 0, sizeof(dmsg)); dmsg.device_id = dev->id; - strncpy(dmsg.device_serial, dev->serial, 256); - dmsg.device_serial[255] = 0; + strncpy(dmsg.serial_number, dev->serial, 256); + dmsg.serial_number[255] = 0; dmsg.location = dev->location; - dmsg.device_pid = dev->pid; + dmsg.product_id = dev->pid; return send_pkt(client, 0, MESSAGE_DEVICE_ADD, &dmsg, sizeof(dmsg)); } @@ -225,7 +225,7 @@ static int start_listen(struct mux_client *client) count = device_get_list(devs); // going to need a larger buffer for many devices - int needed_buffer = count * (sizeof(struct client_msg_dev) + sizeof(struct client_header)) + REPLY_BUF_SIZE; + int needed_buffer = count * (sizeof(struct usbmuxd_device_record) + sizeof(struct usbmuxd_header)) + REPLY_BUF_SIZE; if(client->ob_capacity < needed_buffer) { usbmuxd_log(LL_DEBUG, "Enlarging client %d reply buffer %d -> %d to make space for device notifications", client->fd, client->ob_capacity, needed_buffer); client->ob_buf = realloc(client->ob_buf, needed_buffer); @@ -242,7 +242,7 @@ static int start_listen(struct mux_client *client) return count; } -static int client_command(struct mux_client *client, struct client_header *hdr, const char *payload) +static int client_command(struct mux_client *client, struct usbmuxd_header *hdr, const char *payload) { int res; usbmuxd_log(LL_DEBUG, "Client command in fd %d len %d ver %d msg %d tag %d", client->fd, hdr->length, hdr->version, hdr->message, hdr->tag); @@ -255,7 +255,7 @@ static int client_command(struct mux_client *client, struct client_header *hdr, return -1; } - struct client_msg_connect *ch; + struct usbmuxd_connect_request *ch; switch(hdr->message) { case MESSAGE_LISTEN: if(send_result(client, hdr->tag, 0) < 0) @@ -318,8 +318,8 @@ static void process_recv(struct mux_client *client) { int res; int did_read = 0; - if(client->ib_size < sizeof(struct client_header)) { - res = recv(client->fd, client->ib_buf + client->ib_size, sizeof(struct client_header) - client->ib_size, 0); + if(client->ib_size < sizeof(struct usbmuxd_header)) { + res = recv(client->fd, client->ib_buf + client->ib_size, sizeof(struct usbmuxd_header) - client->ib_size, 0); if(res <= 0) { if(res < 0) usbmuxd_log(LL_ERROR, "Receive from client fd %d failed: %s", client->fd, strerror(errno)); @@ -329,20 +329,20 @@ static void process_recv(struct mux_client *client) return; } client->ib_size += res; - if(client->ib_size < sizeof(struct client_header)) + if(client->ib_size < sizeof(struct usbmuxd_header)) return; did_read = 1; } - struct client_header *hdr = (void*)client->ib_buf; - if(hdr->version != CLIENT_PROTOCOL_VERSION) { - usbmuxd_log(LL_INFO, "Client %d version mismatch: expected %d, got %d", client->fd, CLIENT_PROTOCOL_VERSION, hdr->version); + struct usbmuxd_header *hdr = (void*)client->ib_buf; + if(hdr->version != USBMUXD_PROTOCOL_VERSION) { + usbmuxd_log(LL_INFO, "Client %d version mismatch: expected %d, got %d", client->fd, USBMUXD_PROTOCOL_VERSION, hdr->version); client_close(client); } if(hdr->length > client->ib_capacity) { usbmuxd_log(LL_INFO, "Client %d message is too long (%d bytes)", client->fd, hdr->length); client_close(client); } - if(hdr->length < sizeof(struct client_header)) { + if(hdr->length < sizeof(struct usbmuxd_header)) { usbmuxd_log(LL_ERROR, "Client %d message is too short (%d bytes)", client->fd, hdr->length); client_close(client); } diff --git a/usbmuxd/client.h b/usbmuxd/client.h index 0cda676..4fc1ab4 100644 --- a/usbmuxd/client.h +++ b/usbmuxd/client.h @@ -22,62 +22,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define __CLIENT_H__ #include +#include "usbmuxd-proto.h" struct device_info; struct mux_client; -enum client_result { - RESULT_OK = 0, - RESULT_BADCOMMAND = 1, - RESULT_BADDEV = 2, - RESULT_CONNREFUSED = 3, - // ??? - // ??? - RESULT_BADVERSION = 6, -}; - -enum client_msgtype { - MESSAGE_RESULT = 1, - MESSAGE_CONNECT = 2, - MESSAGE_LISTEN = 3, - MESSAGE_DEVICE_ADD = 4, - MESSAGE_DEVICE_REMOVE = 5, - //??? - //??? - //MESSAGE_PLIST = 8, -}; - -#define CLIENT_PROTOCOL_VERSION 0 - -struct client_header { - uint32_t length; - uint32_t version; - uint32_t message; - uint32_t tag; -}; - -struct client_msg_result { - uint32_t result; -}; - -struct client_msg_connect { - uint32_t device_id; - uint16_t port; -}; - -struct client_msg_dev { - uint32_t device_id; - uint16_t device_pid; - char device_serial[256]; - uint16_t padding; - uint32_t location; -}; - int client_read(struct mux_client *client, void *buffer, int len); int client_write(struct mux_client *client, void *buffer, int len); int client_set_events(struct mux_client *client, short events); void client_close(struct mux_client *client); -int client_notify_connect(struct mux_client *client, enum client_result result); +int client_notify_connect(struct mux_client *client, enum usbmuxd_result result); void client_device_add(struct device_info *dev); void client_device_remove(int device_id); diff --git a/usbmuxd/utils.c b/usbmuxd/utils.c deleted file mode 100644 index 1ffa04a..0000000 --- a/usbmuxd/utils.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - usbmuxd - iPhone/iPod Touch USB multiplex server daemon - -Copyright (C) 2009 Hector Martin "marcan" - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 or version 3. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include "utils.h" -#include "log.h" - -void fdlist_create(struct fdlist *list) -{ - list->count = 0; - list->capacity = 4; - list->owners = malloc(sizeof(*list->owners) * list->capacity); - list->fds = malloc(sizeof(*list->fds) * list->capacity); -} -void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events) -{ - if(list->count == list->capacity) { - list->capacity *= 2; - list->owners = realloc(list->owners, sizeof(*list->owners) * list->capacity); - list->fds = realloc(list->fds, sizeof(*list->fds) * list->capacity); - } - list->owners[list->count] = owner; - list->fds[list->count].fd = fd; - list->fds[list->count].events = events; - list->fds[list->count].revents = 0; - list->count++; -} - -void fdlist_free(struct fdlist *list) -{ - list->count = 0; - list->capacity = 0; - free(list->owners); - list->owners = NULL; - free(list->fds); - list->fds = NULL; -} - -void collection_init(struct collection *col) -{ - col->list = malloc(sizeof(void *)); - memset(col->list, 0, sizeof(void *)); - col->capacity = 1; -} - -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; icapacity; i++) { - if(!col->list[i]) { - col->list[i] = element; - return; - } - } - col->list = realloc(col->list, sizeof(void*) * col->capacity * 2); - memset(&col->list[col->capacity], 0, sizeof(void *) * col->capacity); - col->list[col->capacity] = element; - col->capacity *= 2; -} - -void collection_remove(struct collection *col, void *element) -{ - int i; - for(i=0; icapacity; i++) { - if(col->list[i] == element) { - col->list[i] = NULL; - return; - } - } - usbmuxd_log(LL_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; icapacity; i++) { - if(col->list[i]) - cnt++; - } - return cnt; -} diff --git a/usbmuxd/utils.h b/usbmuxd/utils.h deleted file mode 100644 index ad4ac9d..0000000 --- a/usbmuxd/utils.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - usbmuxd - iPhone/iPod Touch USB multiplex server daemon - -Copyright (C) 2009 Hector Martin "marcan" - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 or version 3. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef __UTILS_H__ -#define __UTILS_H__ - -#include - -enum fdowner { - FD_LISTEN, - FD_CLIENT, - FD_USB -}; - -struct fdlist { - int count; - int capacity; - enum fdowner *owners; - struct pollfd *fds; -}; - -void fdlist_create(struct fdlist *list); -void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events); -void fdlist_free(struct fdlist *list); - -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); - -#define FOREACH(var, col) \ - do { \ - int _iter; \ - for(_iter=0; _iter<(col)->capacity; _iter++) { \ - if(!(col)->list[_iter]) continue; \ - var = (col)->list[_iter]; - -#define ENDFOREACH \ - } \ - } while(0); - -#endif -- cgit v1.1-32-gdbae