From 00c3c56e38f10d0f20145d5735b2fc0fd926555d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 24 May 2010 17:52:53 +0200 Subject: libusbmuxd: add generic receive_packet function and use it --- libusbmuxd/libusbmuxd.c | 208 +++++++++++++++++++++++++++--------------------- 1 file changed, 117 insertions(+), 91 deletions(-) diff --git a/libusbmuxd/libusbmuxd.c b/libusbmuxd/libusbmuxd.c index 9d54a88..db8d1d4 100644 --- a/libusbmuxd/libusbmuxd.c +++ b/libusbmuxd/libusbmuxd.c @@ -74,39 +74,85 @@ static int connect_usbmuxd_socket() #endif } +static int receive_packet(int sfd, struct usbmuxd_header *header, void **payload, int timeout) +{ + int recv_len; + struct usbmuxd_header hdr; + char *payload_loc = NULL; + + header->length = 0; + header->version = 0; + header->message = 0; + header->tag = 0; + + recv_len = recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, timeout); + if (recv_len < 0) { + return recv_len; + } else if (recv_len < sizeof(hdr)) { + return recv_len; + } + + uint32_t payload_size = hdr.length - sizeof(hdr); + if (payload_size > 0) { + payload_loc = (char*)malloc(payload_size); + if (recv_buf_timeout(sfd, payload_loc, payload_size, 0, 5000) != payload_size) { + fprintf(stderr, "%s: Error receiving payload of size %d\n", __func__, payload_size); + free(payload_loc); + return -EBADMSG; + } + } + + *payload = payload_loc; + + memcpy(header, &hdr, sizeof(hdr)); + + return hdr.length; +} + /** * 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_msg res; + struct usbmuxd_header hdr; int recv_len; + uint32_t *res = NULL; if (!result) { return -EINVAL; } + *result = -1; - if ((recv_len = recv_buf(sfd, &res, sizeof(res))) <= 0) { - perror("recv"); + if ((recv_len = receive_packet(sfd, &hdr, (void**)&res, 5000)) < 0) { + fprintf(stderr, "%s: Error receiving packet: %d\n", __func__, errno); + if (res) + free(res); return -errno; - } else { - if ((recv_len == sizeof(res)) - && (res.header.length == (uint32_t) recv_len) - && (res.header.version == USBMUXD_PROTOCOL_VERSION) - && (res.header.message == MESSAGE_RESULT) - ) { - *result = res.result; - if (res.header.tag == tag) { - return 1; - } else { - return 0; - } - } + } + if (recv_len < sizeof(hdr)) { + fprintf(stderr, "%s: Received packet is too small!\n", __func__); + if (res) + free(res); + return -EPROTO; } - return -1; + if (hdr.message == MESSAGE_RESULT) { + int ret = 0; + if (res && (hdr.tag == tag)) { + memcpy(result, res, sizeof(uint32_t)); + ret = 1; + } + if (res) + free(res); + return ret; + } + fprintf(stderr, "%s: Unexpected message of type %d received!\n", __func__, hdr.message); + if (res) + free(res); + return -EPROTO; } + /** * Generates an event, i.e. calls the callback function. * A reference to a populated usbmuxd_event_t with information about the event @@ -163,8 +209,8 @@ static int usbmuxd_listen() return -1; } if (usbmuxd_get_result(sfd, req.header.tag, &res) && (res != 0)) { - fprintf(stderr, "%s: ERROR: did not get OK\n", __func__); close(sfd); + fprintf(stderr, "%s: ERROR: did not get OK but %d\n", __func__, res); return -1; } @@ -177,12 +223,11 @@ static int usbmuxd_listen() */ int get_next_event(int sfd, usbmuxd_event_cb_t callback, void *user_data) { - int recv_len; struct usbmuxd_header hdr; + void *payload = NULL; /* block until we receive something */ - recv_len = recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, 0); - if (recv_len < 0) { + if (receive_packet(sfd, &hdr, &payload, 0) < 0) { // when then usbmuxd connection fails, // generate remove events for every device that // is still present so applications know about it @@ -190,57 +235,48 @@ int get_next_event(int sfd, usbmuxd_event_cb_t callback, void *user_data) generate_event(callback, dev, UE_DEVICE_REMOVE, user_data); collection_remove(&devices, dev); } ENDFOREACH - 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, "%s: Out of memory!\n", __func__); - return -1; - } + return -EIO; + } - if (hdr.length != sizeof(struct usbmuxd_header)+sizeof(struct usbmuxd_device_record)) { - fprintf(stderr, "%s: WARNING: unexpected packet size %d for MESSAGE_DEVICE_ADD (expected %d)!\n", __func__, hdr.length, (int)(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, "%s: ERROR: Could not receive packet\n", __func__); - return recv_len; - } + if ((hdr.length > sizeof(hdr)) && !payload) { + fprintf(stderr, "%s: Invalid packet received, payload is missing!\n", __func__); + return -EBADMSG; + } - 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)); + if (hdr.message == MESSAGE_DEVICE_ADD) { + struct usbmuxd_device_record *dev = payload; + usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t)); + if (!devinfo) { + fprintf(stderr, "%s: Out of memory!\n", __func__); + free(payload); + return -1; + } - collection_add(&devices, devinfo); - generate_event(callback, devinfo, UE_DEVICE_ADD, user_data); - } else if (hdr.message == MESSAGE_DEVICE_REMOVE) { - uint32_t handle; - usbmuxd_device_info_t *dev; + 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)); - if (hdr.length != sizeof(struct usbmuxd_header)+sizeof(uint32_t)) { - fprintf(stderr, "%s: WARNING: unexpected packet size %d for MESSAGE_DEVICE_REMOVE (expected %d)!\n", __func__, hdr.length, (int)(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, "%s: ERROR: Could not receive packet\n", __func__); - return recv_len; - } + collection_add(&devices, devinfo); + generate_event(callback, devinfo, UE_DEVICE_ADD, user_data); + } else if (hdr.message == MESSAGE_DEVICE_REMOVE) { + uint32_t handle; + usbmuxd_device_info_t *devinfo; - dev = devices_find(handle); - if (!dev) { - fprintf(stderr, "%s: 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", __func__, handle); - } else { - generate_event(callback, dev, UE_DEVICE_REMOVE, user_data); - collection_remove(&devices, dev); - } + memcpy(&handle, payload, sizeof(uint32_t)); + + devinfo = devices_find(handle); + if (!devinfo) { + fprintf(stderr, "%s: 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", __func__, handle); } else { - fprintf(stderr, "%s: Unknown message type %d length %d\n", __func__, hdr.message, hdr.length); + generate_event(callback, devinfo, UE_DEVICE_REMOVE, user_data); + collection_remove(&devices, devinfo); } } else { - fprintf(stderr, "%s: ERROR: incomplete packet received!\n", __func__); + fprintf(stderr, "%s: Unexpected message type %d length %d received!\n", __func__, hdr.message, hdr.length); + } + if (payload) { + free(payload); } return 0; } @@ -311,11 +347,11 @@ int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) int sfd; int listen_success = 0; uint32_t res; - int recv_len; usbmuxd_device_info_t *newlist = NULL; struct usbmuxd_header hdr; - struct usbmuxd_device_record dev_info; + struct usbmuxd_device_record *dev_info; int dev_cnt = 0; + void *payload = NULL; sfd = connect_usbmuxd_socket(); if (sfd < 0) { @@ -336,10 +372,10 @@ int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) if (usbmuxd_get_result(sfd, s_req.header.tag, &res) && (res == 0)) { listen_success = 1; } else { + close(sfd); fprintf(stderr, "%s: Did not get response to scan request (with result=0)...\n", __func__); - close(sfd); return res; } } @@ -352,45 +388,35 @@ int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) *device_list = NULL; // receive device list while (1) { - if (recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, 1000) == sizeof(hdr)) { - if ((hdr.length < 48) || (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__, hdr.length); - break; - } - - 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 < hdr.length - sizeof(hdr)) { - fprintf(stderr, - "%s: received less data than specified in header!\n", __func__); - } else { + if (receive_packet(sfd, &hdr, &payload, 1000) > 0) { + if (hdr.message == MESSAGE_DEVICE_ADD) { + dev_info = payload; newlist = (usbmuxd_device_info_t *) realloc(*device_list, sizeof(usbmuxd_device_info_t) * (dev_cnt + 1)); if (newlist) { newlist[dev_cnt].handle = - (int) dev_info.device_id; + (int) dev_info->device_id; newlist[dev_cnt].product_id = - dev_info.product_id; + dev_info->product_id; memset(newlist[dev_cnt].uuid, '\0', sizeof(newlist[dev_cnt].uuid)); memcpy(newlist[dev_cnt].uuid, - dev_info.serial_number, + dev_info->serial_number, sizeof(newlist[dev_cnt].uuid)); *device_list = newlist; dev_cnt++; } else { fprintf(stderr, - "%s: ERROR: out of memory when trying to realloc!\n", - __func__); + "%s: ERROR: out of memory when trying to realloc!\n", + __func__); + if (payload) + free(payload); break; } + } else { + fprintf(stderr, "%s: Unexpected message %d\n", __func__, hdr.message); } + if (payload) + free(payload); } else { // we _should_ have all of them now. // or perhaps an error occured. -- cgit v1.1-32-gdbae