From 6cb505257ff848aa7ead80b60b575effc3a915fa Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 24 May 2010 18:57:10 +0200 Subject: Add protocol version 1 (plist based) support using libplist --- CMakeLists.txt | 17 ++++ daemon/CMakeLists.txt | 6 +- daemon/client.c | 198 +++++++++++++++++++++++++++++++++++++++++--- libusbmuxd/CMakeLists.txt | 6 +- libusbmuxd/libusbmuxd.c | 201 ++++++++++++++++++++++++++++++++++++++++++--- libusbmuxd/usbmuxd-proto.h | 2 +- 6 files changed, 402 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f0a6a8..93fa715 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,23 @@ if(CMAKE_C_FLAGS STREQUAL "") set(CMAKE_C_FLAGS "-O2") endif() +option(WANT_PLIST "Build with protocol version 1 support using libplist" ON) + +set(OPT_INCLUDES "") +set(OPT_LIBS "") +if(WANT_PLIST) + find_package(PLIST) + if(PLIST_FOUND) + set(HAVE_PLIST ON) + set(OPT_INCLUDES ${OPT_INCLUDES} ${PLIST_INCLUDE_DIRS}) + set(OPT_LIBS ${OPT_LIBS} ${PLIST_LIBRARIES}) + else() + message("* NOTE: libplist was not found!") + message("* libusbmuxd/usbmuxd will be build WITHOUT support for version 1") + message("* of the usbmux protocol (plist based).") + endif() +endif() + option(WITH_USBMUXD "Build usbmux daemon (usbmuxd)" ON) if(WIN32 AND WITH_USBMUXD) message("** NOTE: usbmuxd cannot be built on WIN32 due to missing libusb-1.0 support!") diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 6593deb..48ff0c6 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,7 +1,9 @@ find_package(USB REQUIRED) include_directories(${USB_INCLUDE_DIRS}) -set(LIBS ${LIBS} ${USB_LIBRARIES}) - +set(LIBS ${LIBS} ${USB_LIBRARIES} ${OPT_LIBS}) +if(HAVE_PLIST) + message("-- usbmuxd will be built with protocol version 1 support") +endif() include_directories (${CMAKE_SOURCE_DIR}/common) include_directories (${CMAKE_SOURCE_DIR}/daemon) include_directories (${CMAKE_SOURCE_DIR}/libusbmuxd) diff --git a/daemon/client.c b/daemon/client.c index 194632d..80bc0c7 100644 --- a/daemon/client.c +++ b/daemon/client.c @@ -32,12 +32,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include +#ifdef HAVE_PLIST +#include +#endif + #include "log.h" #include "usb.h" #include "client.h" #include "device.h" +#ifdef HAVE_PLIST +#define CMD_BUF_SIZE 1024 +#else #define CMD_BUF_SIZE 256 +#endif #define REPLY_BUF_SIZE 1024 enum client_state { @@ -61,6 +69,7 @@ struct mux_client { uint32_t connect_tag; int connect_device; enum client_state state; + uint32_t proto_version; }; static struct collection client_list; @@ -155,7 +164,7 @@ void client_get_fds(struct fdlist *list) static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length) { struct usbmuxd_header hdr; - hdr.version = USBMUXD_PROTOCOL_VERSION; + hdr.version = client->proto_version; hdr.length = sizeof(hdr) + payload_length; hdr.message = msg; hdr.tag = tag; @@ -175,7 +184,30 @@ static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtyp 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 res = -1; +#ifdef HAVE_PLIST + if (client->proto_version == 1) { + /* XML plist packet */ + char *xml = NULL; + uint32_t xmlsize = 0; + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "MessageType", plist_new_string("Result")); + plist_dict_insert_item(dict, "Number", plist_new_uint(result)); + plist_to_xml(dict, &xml, &xmlsize); + plist_free(dict); + if (xml) { + res = send_pkt(client, tag, MESSAGE_PLIST, xml, xmlsize); + free(xml); + } else { + usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__); + } + } else +#endif + { + /* binary packet */ + res = send_pkt(client, tag, MESSAGE_RESULT, &result, sizeof(uint32_t)); + } + return res; } int client_notify_connect(struct mux_client *client, enum usbmuxd_result result) @@ -203,19 +235,73 @@ int client_notify_connect(struct mux_client *client, enum usbmuxd_result result) static int notify_device_add(struct mux_client *client, struct device_info *dev) { - struct usbmuxd_device_record dmsg; - memset(&dmsg, 0, sizeof(dmsg)); - dmsg.device_id = dev->id; - strncpy(dmsg.serial_number, dev->serial, 256); - dmsg.serial_number[255] = 0; - dmsg.location = dev->location; - dmsg.product_id = dev->pid; - return send_pkt(client, 0, MESSAGE_DEVICE_ADD, &dmsg, sizeof(dmsg)); + int res = -1; +#ifdef HAVE_PLIST + if (client->proto_version == 1) { + /* XML plist packet */ + char *xml = NULL; + uint32_t xmlsize = 0; + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "MessageType", plist_new_string("Attached")); + plist_t props = plist_new_dict(); + // TODO: get current usb speed + plist_dict_insert_item(props, "ConnectionSpeed", plist_new_uint(480000000)); + plist_dict_insert_item(props, "ConnectionType", plist_new_string("USB")); + plist_dict_insert_item(props, "DeviceID", plist_new_uint(dev->id)); + plist_dict_insert_item(props, "LocationID", plist_new_uint(dev->location)); + plist_dict_insert_item(props, "ProductID", plist_new_uint(dev->pid)); + plist_dict_insert_item(props, "SerialNumber", plist_new_string(dev->serial)); + plist_dict_insert_item(dict, "Properties", props); + plist_to_xml(dict, &xml, &xmlsize); + plist_free(dict); + if (xml) { + res = send_pkt(client, 0, MESSAGE_PLIST, xml, xmlsize); + free(xml); + } else { + usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__); + } + } else +#endif + { + /* binary packet */ + struct usbmuxd_device_record dmsg; + memset(&dmsg, 0, sizeof(dmsg)); + dmsg.device_id = dev->id; + strncpy(dmsg.serial_number, dev->serial, 256); + dmsg.serial_number[255] = 0; + dmsg.location = dev->location; + dmsg.product_id = dev->pid; + res = send_pkt(client, 0, MESSAGE_DEVICE_ADD, &dmsg, sizeof(dmsg)); + } + return res; } static int notify_device_remove(struct mux_client *client, uint32_t device_id) { - return send_pkt(client, 0, MESSAGE_DEVICE_REMOVE, &device_id, sizeof(uint32_t)); + int res = -1; +#ifdef HAVE_PLIST + if (client->proto_version == 1) { + /* XML plist packet */ + char *xml = NULL; + uint32_t xmlsize = 0; + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "MessageType", plist_new_string("Detached")); + plist_dict_insert_item(dict, "DeviceID", plist_new_uint(device_id)); + plist_to_xml(dict, &xml, &xmlsize); + plist_free(dict); + if (xml) { + res = send_pkt(client, 0, MESSAGE_PLIST, xml, xmlsize); + free(xml); + } else { + usbmuxd_log(LL_ERROR, "%s: Could not convert plist to xml", __func__); + } + } else +#endif + { + /* binary packet */ + res = send_pkt(client, 0, MESSAGE_DEVICE_REMOVE, &device_id, sizeof(uint32_t)); + } + return res; } static int start_listen(struct mux_client *client) @@ -263,7 +349,92 @@ static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) } struct usbmuxd_connect_request *ch; +#ifdef HAVE_PLIST + char *payload; + uint32_t payload_size; +#endif + switch(hdr->message) { +#ifdef HAVE_PLIST + case MESSAGE_PLIST: + client->proto_version = 1; + payload = (char*)(hdr) + sizeof(struct usbmuxd_header); + payload_size = hdr->length - sizeof(struct usbmuxd_header); + plist_t dict = NULL; + plist_from_xml(payload, payload_size, &dict); + if (!dict) { + usbmuxd_log(LL_ERROR, "Could not parse plist from payload!"); + return -1; + } else { + char *message = NULL; + plist_t node = plist_dict_get_item(dict, "MessageType"); + plist_get_string_val(node, &message); + if (!message) { + usbmuxd_log(LL_ERROR, "Could not extract MessageType from plist!"); + plist_free(dict); + return -1; + } + if (!strcmp(message, "Listen")) { + free(message); + plist_free(dict); + if (send_result(client, hdr->tag, 0) < 0) + return -1; + usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd); + return start_listen(client); + } else if (!strcmp(message, "Connect")) { + uint64_t val; + uint16_t portnum = 0; + uint32_t device_id = 0; + free(message); + // get device id + node = plist_dict_get_item(dict, "DeviceID"); + if (!node) { + usbmuxd_log(LL_ERROR, "Received connect request without device_id!"); + plist_free(dict); + if (send_result(client, hdr->tag, RESULT_BADDEV) < 0) + return -1; + return 0; + } + val = 0; + plist_get_uint_val(node, &val); + device_id = (uint32_t)val; + + // get port number + node = plist_dict_get_item(dict, "PortNumber"); + if (!node) { + usbmuxd_log(LL_ERROR, "Received connect request without port number!"); + plist_free(dict); + if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) + return -1; + return 0; + } + val = 0; + plist_get_uint_val(node, &val); + portnum = (uint16_t)val; + + usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, device_id, ntohs(portnum)); + res = device_start_connect(device_id, ntohs(portnum), client); + if(res < 0) { + if (send_result(client, hdr->tag, -res) < 0) + return -1; + } else { + client->connect_tag = hdr->tag; + client->connect_device = device_id; + client->state = CLIENT_CONNECTING1; + } + return 0; + } else { + usbmuxd_log(LL_ERROR, "Unexpected command '%s' received!", message); + free(message); + plist_free(dict); + if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) + return -1; + return 0; + } + } + // should not be reached?! + return -1; +#endif case MESSAGE_LISTEN: if(send_result(client, hdr->tag, 0) < 0) return -1; @@ -341,8 +512,13 @@ static void process_recv(struct mux_client *client) did_read = 1; } struct usbmuxd_header *hdr = (void*)client->ib_buf; +#ifdef HAVE_PLIST + if((hdr->version != 0) && (hdr->version != 1)) { + usbmuxd_log(LL_INFO, "Client %d version mismatch: expected 0 or 1, got %d", client->fd, hdr->version); +#else if(hdr->version != USBMUXD_PROTOCOL_VERSION) { usbmuxd_log(LL_INFO, "Client %d version mismatch: expected %d, got %d", client->fd, USBMUXD_PROTOCOL_VERSION, hdr->version); +#endif client_close(client); } if(hdr->length > client->ib_capacity) { diff --git a/libusbmuxd/CMakeLists.txt b/libusbmuxd/CMakeLists.txt index d275169..236cca3 100644 --- a/libusbmuxd/CMakeLists.txt +++ b/libusbmuxd/CMakeLists.txt @@ -3,7 +3,11 @@ find_package(Threads) add_library (libusbmuxd SHARED libusbmuxd.c sock_stuff.c ${CMAKE_SOURCE_DIR}/common/utils.c) find_library (PTHREAD pthread) -target_link_libraries (libusbmuxd ${CMAKE_THREAD_LIBS_INIT}) + +if (HAVE_PLIST) + message("-- libusbmuxd will be built with protocol version 1 support") +endif() +target_link_libraries (libusbmuxd ${CMAKE_THREAD_LIBS_INIT} ${OPT_LIBS}) # 'lib' is a UNIXism, the proper CMake target is usbmuxd # But we can't use that due to the conflict with the usbmuxd daemon, diff --git a/libusbmuxd/libusbmuxd.c b/libusbmuxd/libusbmuxd.c index f5e5d1b..f465deb 100644 --- a/libusbmuxd/libusbmuxd.c +++ b/libusbmuxd/libusbmuxd.c @@ -32,6 +32,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include +#ifdef HAVE_PLIST +#include +#define PLIST_BUNDLE_ID "com.marcansoft.usbmuxd" +#define PLIST_CLIENT_VERSION_STRING "usbmuxd built for freedom" +#define PLIST_PROGNAME "libusbmuxd" +#endif + // usbmuxd public interface #include "usbmuxd.h" // usbmuxd protocol @@ -47,6 +54,7 @@ pthread_t devmon; static int listenfd = -1; static int use_tag = 0; +static int proto_version = 0; /** * Finds a device info record by its handle. @@ -104,7 +112,95 @@ static int receive_packet(int sfd, struct usbmuxd_header *header, void **payload } } - *payload = payload_loc; +#ifdef HAVE_PLIST + if (hdr.message == MESSAGE_PLIST) { + char *message = NULL; + plist_t plist = NULL; + plist_from_xml(payload_loc, payload_size, &plist); + free(payload_loc); + + if (!plist) { + fprintf(stderr, "%s: Error getting plist from payload!\n", __func__); + return -EBADMSG; + } + + plist_t node = plist_dict_get_item(plist, "MessageType"); + if (plist_get_node_type(node) != PLIST_STRING) { + fprintf(stderr, "%s: Error getting message type from plist!\n", __func__); + free(plist); + return -EBADMSG; + } + + plist_get_string_val(node, &message); + if (message) { + uint64_t val = 0; + if (strcmp(message, "Result") == 0) { + /* result message */ + uint32_t dwval = 0; + plist_t n = plist_dict_get_item(plist, "Number"); + plist_get_uint_val(n, &val); + *payload = malloc(sizeof(uint32_t)); + dwval = val; + memcpy(*payload, &dwval, sizeof(dwval)); + hdr.length = sizeof(hdr) + sizeof(dwval); + hdr.message = MESSAGE_RESULT; + } else if (strcmp(message, "Attached") == 0) { + /* device add message */ + struct usbmuxd_device_record *dev = NULL; + plist_t props = plist_dict_get_item(plist, "Properties"); + if (!props) { + fprintf(stderr, "%s: Could not get properties for message '%s' from plist!\n", __func__, message); + plist_free(plist); + return -EBADMSG; + } + dev = (struct usbmuxd_device_record*)malloc(sizeof(struct usbmuxd_device_record)); + memset(dev, 0, sizeof(struct usbmuxd_device_record)); + + plist_t n = plist_dict_get_item(props, "DeviceID"); + plist_get_uint_val(n, &val); + dev->device_id = (uint32_t)val; + + n = plist_dict_get_item(props, "ProductID"); + plist_get_uint_val(n, &val); + dev->product_id = (uint32_t)val; + + n = plist_dict_get_item(props, "SerialNumber"); + char *strval = NULL; + plist_get_string_val(n, &strval); + if (strval) { + strcpy(dev->serial_number, strval); + free(strval); + } + n = plist_dict_get_item(props, "LocationID"); + plist_get_uint_val(n, &val); + dev->location = (uint32_t)val; + *payload = (void*)dev; + hdr.length = sizeof(hdr) + sizeof(struct usbmuxd_device_record); + hdr.message = MESSAGE_DEVICE_ADD; + } else if (strcmp(message, "Detached") == 0) { + /* device remove message */ + uint32_t dwval = 0; + plist_t n = plist_dict_get_item(plist, "DeviceID"); + if (n) { + plist_get_uint_val(n, &val); + *payload = malloc(sizeof(uint32_t)); + dwval = val; + memcpy(*payload, &dwval, sizeof(dwval)); + hdr.length = sizeof(hdr) + sizeof(dwval); + hdr.message = MESSAGE_DEVICE_REMOVE; + } + } else { + fprintf(stderr, "%s: Unexpected message '%s' in plist!\n", __func__, message); + plist_free(plist); + return -EBADMSG; + } + } + plist_free(plist); + } else +#endif + { + *payload = payload_loc; + } memcpy(header, &hdr, sizeof(hdr)); @@ -159,7 +255,7 @@ static int send_packet(int sfd, uint32_t message, uint32_t tag, void *payload, u struct usbmuxd_header header; header.length = sizeof(struct usbmuxd_header); - header.version = USBMUXD_PROTOCOL_VERSION; + header.version = proto_version; header.message = message; header.tag = tag; if (payload && (payload_size > 0)) { @@ -183,23 +279,74 @@ static int send_packet(int sfd, uint32_t message, uint32_t tag, void *payload, u static int send_listen_packet(int sfd, uint32_t tag) { - return send_packet(sfd, MESSAGE_LISTEN, tag, NULL, 0); + int res = 0; +#ifdef HAVE_PLIST + if (proto_version == 1) { + /* plist packet */ + char *payload = NULL; + uint32_t payload_size = 0; + plist_t plist; + + /* construct message plist */ + plist = plist_new_dict(); + plist_dict_insert_item(plist, "BundleID", plist_new_string(PLIST_BUNDLE_ID)); + plist_dict_insert_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING)); + plist_dict_insert_item(plist, "MessageType", plist_new_string("Listen")); + plist_dict_insert_item(plist, "ProgName", plist_new_string(PLIST_PROGNAME)); + plist_to_xml(plist, &payload, &payload_size); + plist_free(plist); + + res = send_packet(sfd, MESSAGE_PLIST, tag, payload, payload_size); + free(payload); + } else +#endif + { + /* binary packet */ + res = send_packet(sfd, MESSAGE_LISTEN, tag, NULL, 0); + } + return res; } static int send_connect_packet(int sfd, uint32_t tag, uint32_t device_id, uint16_t port) { - struct { - uint32_t device_id; - uint16_t port; - uint16_t reserved; - } conninfo; - - conninfo.device_id = device_id; - conninfo.port = htons(port); - conninfo.reserved = 0; + int res = 0; +#ifdef HAVE_PLIST + if (proto_version == 1) { + /* plist packet */ + char *payload = NULL; + uint32_t payload_size = 0; + plist_t plist; + + /* construct message plist */ + plist = plist_new_dict(); + plist_dict_insert_item(plist, "BundleID", plist_new_string(PLIST_BUNDLE_ID)); + plist_dict_insert_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING)); + plist_dict_insert_item(plist, "MessageType", plist_new_string("Connect")); + plist_dict_insert_item(plist, "DeviceID", plist_new_uint(device_id)); + plist_dict_insert_item(plist, "PortNumber", plist_new_uint(port)); + plist_dict_insert_item(plist, "ProgName", plist_new_string(PLIST_PROGNAME)); + plist_to_xml(plist, &payload, &payload_size); + plist_free(plist); + + res = send_packet(sfd, MESSAGE_PLIST, tag, (void*)payload, payload_size); + free(payload); + } else +#endif + { + /* binary packet */ + struct { + uint32_t device_id; + uint16_t port; + uint16_t reserved; + } conninfo; - return send_packet(sfd, MESSAGE_CONNECT, tag, &conninfo, sizeof(conninfo)); + conninfo.device_id = device_id; + conninfo.port = htons(port); + conninfo.reserved = 0; + res = send_packet(sfd, MESSAGE_CONNECT, tag, &conninfo, sizeof(conninfo)); + } + return res; } /** @@ -231,6 +378,9 @@ static int usbmuxd_listen() int sfd; uint32_t res = -1; +#ifdef HAVE_PLIST +retry: +#endif sfd = connect_usbmuxd_socket(); if (sfd < 0) { while (event_cb) { @@ -254,6 +404,12 @@ static int usbmuxd_listen() } if (usbmuxd_get_result(sfd, use_tag, &res) && (res != 0)) { close(sfd); +#ifdef HAVE_PLIST + if ((res == RESULT_BADVERSION) && (proto_version != 1)) { + proto_version = 1; + goto retry; + } +#endif fprintf(stderr, "%s: ERROR: did not get OK but %d\n", __func__, res); return -1; } @@ -396,6 +552,9 @@ int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) int dev_cnt = 0; void *payload = NULL; +#ifdef HAVE_PLIST +retry: +#endif sfd = connect_usbmuxd_socket(); if (sfd < 0) { fprintf(stderr, "%s: error opening socket!\n", __func__); @@ -410,6 +569,12 @@ int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) listen_success = 1; } else { close(sfd); +#ifdef HAVE_PLIST + if ((res == RESULT_BADVERSION) && (proto_version != 1)) { + proto_version = 1; + goto retry; + } +#endif fprintf(stderr, "%s: Did not get response to scan request (with result=0)...\n", __func__); @@ -521,6 +686,9 @@ int usbmuxd_connect(const int handle, const unsigned short port) int connected = 0; uint32_t res = -1; +#ifdef HAVE_PLIST +retry: +#endif sfd = connect_usbmuxd_socket(); if (sfd < 0) { fprintf(stderr, "%s: Error: Connection to usbmuxd failed: %s\n", @@ -539,6 +707,13 @@ int usbmuxd_connect(const int handle, const unsigned short port) //fprintf(stderr, "%s: Connect success!\n", __func__); connected = 1; } else { +#ifdef HAVE_PLIST + if ((res == RESULT_BADVERSION) && (proto_version == 0)) { + proto_version = 1; + close(sfd); + goto retry; + } +#endif fprintf(stderr, "%s: Connect failed, Error code=%d\n", __func__, res); } diff --git a/libusbmuxd/usbmuxd-proto.h b/libusbmuxd/usbmuxd-proto.h index 0d4596c..11dd3cf 100644 --- a/libusbmuxd/usbmuxd-proto.h +++ b/libusbmuxd/usbmuxd-proto.h @@ -52,7 +52,7 @@ enum usbmuxd_msgtype { MESSAGE_DEVICE_REMOVE = 5, //??? //??? - //MESSAGE_PLIST = 8, + MESSAGE_PLIST = 8, }; struct usbmuxd_header { -- cgit v1.1-32-gdbae