diff options
Diffstat (limited to 'libusbmuxd/libusbmuxd.c')
| -rw-r--r-- | libusbmuxd/libusbmuxd.c | 208 |
1 files 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() | |||
| 74 | #endif | 74 | #endif |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | static int receive_packet(int sfd, struct usbmuxd_header *header, void **payload, int timeout) | ||
| 78 | { | ||
| 79 | int recv_len; | ||
| 80 | struct usbmuxd_header hdr; | ||
| 81 | char *payload_loc = NULL; | ||
| 82 | |||
| 83 | header->length = 0; | ||
| 84 | header->version = 0; | ||
| 85 | header->message = 0; | ||
| 86 | header->tag = 0; | ||
| 87 | |||
| 88 | recv_len = recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, timeout); | ||
| 89 | if (recv_len < 0) { | ||
| 90 | return recv_len; | ||
| 91 | } else if (recv_len < sizeof(hdr)) { | ||
| 92 | return recv_len; | ||
| 93 | } | ||
| 94 | |||
| 95 | uint32_t payload_size = hdr.length - sizeof(hdr); | ||
| 96 | if (payload_size > 0) { | ||
| 97 | payload_loc = (char*)malloc(payload_size); | ||
| 98 | if (recv_buf_timeout(sfd, payload_loc, payload_size, 0, 5000) != payload_size) { | ||
| 99 | fprintf(stderr, "%s: Error receiving payload of size %d\n", __func__, payload_size); | ||
| 100 | free(payload_loc); | ||
| 101 | return -EBADMSG; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | *payload = payload_loc; | ||
| 106 | |||
| 107 | memcpy(header, &hdr, sizeof(hdr)); | ||
| 108 | |||
| 109 | return hdr.length; | ||
| 110 | } | ||
| 111 | |||
| 77 | /** | 112 | /** |
| 78 | * Retrieves the result code to a previously sent request. | 113 | * Retrieves the result code to a previously sent request. |
| 79 | */ | 114 | */ |
| 80 | static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result) | 115 | static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result) |
| 81 | { | 116 | { |
| 82 | struct usbmuxd_result_msg res; | 117 | struct usbmuxd_header hdr; |
| 83 | int recv_len; | 118 | int recv_len; |
| 119 | uint32_t *res = NULL; | ||
| 84 | 120 | ||
| 85 | if (!result) { | 121 | if (!result) { |
| 86 | return -EINVAL; | 122 | return -EINVAL; |
| 87 | } | 123 | } |
| 124 | *result = -1; | ||
| 88 | 125 | ||
| 89 | if ((recv_len = recv_buf(sfd, &res, sizeof(res))) <= 0) { | 126 | if ((recv_len = receive_packet(sfd, &hdr, (void**)&res, 5000)) < 0) { |
| 90 | perror("recv"); | 127 | fprintf(stderr, "%s: Error receiving packet: %d\n", __func__, errno); |
| 128 | if (res) | ||
| 129 | free(res); | ||
| 91 | return -errno; | 130 | return -errno; |
| 92 | } else { | 131 | } |
| 93 | if ((recv_len == sizeof(res)) | 132 | if (recv_len < sizeof(hdr)) { |
| 94 | && (res.header.length == (uint32_t) recv_len) | 133 | fprintf(stderr, "%s: Received packet is too small!\n", __func__); |
| 95 | && (res.header.version == USBMUXD_PROTOCOL_VERSION) | 134 | if (res) |
| 96 | && (res.header.message == MESSAGE_RESULT) | 135 | free(res); |
| 97 | ) { | 136 | return -EPROTO; |
| 98 | *result = res.result; | ||
| 99 | if (res.header.tag == tag) { | ||
| 100 | return 1; | ||
| 101 | } else { | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | 137 | } |
| 106 | 138 | ||
| 107 | return -1; | 139 | if (hdr.message == MESSAGE_RESULT) { |
| 140 | int ret = 0; | ||
| 141 | if (res && (hdr.tag == tag)) { | ||
| 142 | memcpy(result, res, sizeof(uint32_t)); | ||
| 143 | ret = 1; | ||
| 144 | } | ||
| 145 | if (res) | ||
| 146 | free(res); | ||
| 147 | return ret; | ||
| 148 | } | ||
| 149 | fprintf(stderr, "%s: Unexpected message of type %d received!\n", __func__, hdr.message); | ||
| 150 | if (res) | ||
| 151 | free(res); | ||
| 152 | return -EPROTO; | ||
| 108 | } | 153 | } |
| 109 | 154 | ||
| 155 | |||
| 110 | /** | 156 | /** |
| 111 | * Generates an event, i.e. calls the callback function. | 157 | * Generates an event, i.e. calls the callback function. |
| 112 | * A reference to a populated usbmuxd_event_t with information about the event | 158 | * A reference to a populated usbmuxd_event_t with information about the event |
| @@ -163,8 +209,8 @@ static int usbmuxd_listen() | |||
| 163 | return -1; | 209 | return -1; |
| 164 | } | 210 | } |
| 165 | if (usbmuxd_get_result(sfd, req.header.tag, &res) && (res != 0)) { | 211 | if (usbmuxd_get_result(sfd, req.header.tag, &res) && (res != 0)) { |
| 166 | fprintf(stderr, "%s: ERROR: did not get OK\n", __func__); | ||
| 167 | close(sfd); | 212 | close(sfd); |
| 213 | fprintf(stderr, "%s: ERROR: did not get OK but %d\n", __func__, res); | ||
| 168 | return -1; | 214 | return -1; |
| 169 | } | 215 | } |
| 170 | 216 | ||
| @@ -177,12 +223,11 @@ static int usbmuxd_listen() | |||
| 177 | */ | 223 | */ |
| 178 | int get_next_event(int sfd, usbmuxd_event_cb_t callback, void *user_data) | 224 | int get_next_event(int sfd, usbmuxd_event_cb_t callback, void *user_data) |
| 179 | { | 225 | { |
| 180 | int recv_len; | ||
| 181 | struct usbmuxd_header hdr; | 226 | struct usbmuxd_header hdr; |
| 227 | void *payload = NULL; | ||
| 182 | 228 | ||
| 183 | /* block until we receive something */ | 229 | /* block until we receive something */ |
| 184 | recv_len = recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, 0); | 230 | if (receive_packet(sfd, &hdr, &payload, 0) < 0) { |
| 185 | if (recv_len < 0) { | ||
| 186 | // when then usbmuxd connection fails, | 231 | // when then usbmuxd connection fails, |
| 187 | // generate remove events for every device that | 232 | // generate remove events for every device that |
| 188 | // is still present so applications know about it | 233 | // 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) | |||
| 190 | generate_event(callback, dev, UE_DEVICE_REMOVE, user_data); | 235 | generate_event(callback, dev, UE_DEVICE_REMOVE, user_data); |
| 191 | collection_remove(&devices, dev); | 236 | collection_remove(&devices, dev); |
| 192 | } ENDFOREACH | 237 | } ENDFOREACH |
| 193 | return recv_len; | 238 | return -EIO; |
| 194 | } else if (recv_len == sizeof(hdr)) { | 239 | } |
| 195 | if (hdr.message == MESSAGE_DEVICE_ADD) { | ||
| 196 | struct usbmuxd_device_record dev; | ||
| 197 | usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t)); | ||
| 198 | if (!devinfo) { | ||
| 199 | fprintf(stderr, "%s: Out of memory!\n", __func__); | ||
| 200 | return -1; | ||
| 201 | } | ||
| 202 | 240 | ||
| 203 | if (hdr.length != sizeof(struct usbmuxd_header)+sizeof(struct usbmuxd_device_record)) { | 241 | if ((hdr.length > sizeof(hdr)) && !payload) { |
| 204 | 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))); | 242 | fprintf(stderr, "%s: Invalid packet received, payload is missing!\n", __func__); |
| 205 | } | 243 | return -EBADMSG; |
| 206 | recv_len = recv_buf_timeout(sfd, &dev, hdr.length - sizeof(struct usbmuxd_header), 0, 5000); | 244 | } |
| 207 | if (recv_len != (hdr.length - sizeof(struct usbmuxd_header))) { | ||
| 208 | fprintf(stderr, "%s: ERROR: Could not receive packet\n", __func__); | ||
| 209 | return recv_len; | ||
| 210 | } | ||
| 211 | 245 | ||
| 212 | devinfo->handle = dev.device_id; | 246 | if (hdr.message == MESSAGE_DEVICE_ADD) { |
| 213 | devinfo->product_id = dev.product_id; | 247 | struct usbmuxd_device_record *dev = payload; |
| 214 | memset(devinfo->uuid, '\0', sizeof(devinfo->uuid)); | 248 | usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t)); |
| 215 | memcpy(devinfo->uuid, dev.serial_number, sizeof(devinfo->uuid)); | 249 | if (!devinfo) { |
| 250 | fprintf(stderr, "%s: Out of memory!\n", __func__); | ||
| 251 | free(payload); | ||
| 252 | return -1; | ||
| 253 | } | ||
| 216 | 254 | ||
| 217 | collection_add(&devices, devinfo); | 255 | devinfo->handle = dev->device_id; |
| 218 | generate_event(callback, devinfo, UE_DEVICE_ADD, user_data); | 256 | devinfo->product_id = dev->product_id; |
| 219 | } else if (hdr.message == MESSAGE_DEVICE_REMOVE) { | 257 | memset(devinfo->uuid, '\0', sizeof(devinfo->uuid)); |
| 220 | uint32_t handle; | 258 | memcpy(devinfo->uuid, dev->serial_number, sizeof(devinfo->uuid)); |
| 221 | usbmuxd_device_info_t *dev; | ||
| 222 | 259 | ||
| 223 | if (hdr.length != sizeof(struct usbmuxd_header)+sizeof(uint32_t)) { | 260 | collection_add(&devices, devinfo); |
| 224 | 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))); | 261 | generate_event(callback, devinfo, UE_DEVICE_ADD, user_data); |
| 225 | } | 262 | } else if (hdr.message == MESSAGE_DEVICE_REMOVE) { |
| 226 | recv_len = recv_buf_timeout(sfd, &handle, sizeof(uint32_t), 0, 5000); | 263 | uint32_t handle; |
| 227 | if (recv_len != sizeof(uint32_t)) { | 264 | usbmuxd_device_info_t *devinfo; |
| 228 | fprintf(stderr, "%s: ERROR: Could not receive packet\n", __func__); | ||
| 229 | return recv_len; | ||
| 230 | } | ||
| 231 | 265 | ||
| 232 | dev = devices_find(handle); | 266 | memcpy(&handle, payload, sizeof(uint32_t)); |
| 233 | if (!dev) { | 267 | |
| 234 | 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); | 268 | devinfo = devices_find(handle); |
| 235 | } else { | 269 | if (!devinfo) { |
| 236 | generate_event(callback, dev, UE_DEVICE_REMOVE, user_data); | 270 | 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); |
| 237 | collection_remove(&devices, dev); | ||
| 238 | } | ||
| 239 | } else { | 271 | } else { |
| 240 | fprintf(stderr, "%s: Unknown message type %d length %d\n", __func__, hdr.message, hdr.length); | 272 | generate_event(callback, devinfo, UE_DEVICE_REMOVE, user_data); |
| 273 | collection_remove(&devices, devinfo); | ||
| 241 | } | 274 | } |
| 242 | } else { | 275 | } else { |
| 243 | fprintf(stderr, "%s: ERROR: incomplete packet received!\n", __func__); | 276 | fprintf(stderr, "%s: Unexpected message type %d length %d received!\n", __func__, hdr.message, hdr.length); |
| 277 | } | ||
| 278 | if (payload) { | ||
| 279 | free(payload); | ||
| 244 | } | 280 | } |
| 245 | return 0; | 281 | return 0; |
| 246 | } | 282 | } |
| @@ -311,11 +347,11 @@ int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) | |||
| 311 | int sfd; | 347 | int sfd; |
| 312 | int listen_success = 0; | 348 | int listen_success = 0; |
| 313 | uint32_t res; | 349 | uint32_t res; |
| 314 | int recv_len; | ||
| 315 | usbmuxd_device_info_t *newlist = NULL; | 350 | usbmuxd_device_info_t *newlist = NULL; |
| 316 | struct usbmuxd_header hdr; | 351 | struct usbmuxd_header hdr; |
| 317 | struct usbmuxd_device_record dev_info; | 352 | struct usbmuxd_device_record *dev_info; |
| 318 | int dev_cnt = 0; | 353 | int dev_cnt = 0; |
| 354 | void *payload = NULL; | ||
| 319 | 355 | ||
| 320 | sfd = connect_usbmuxd_socket(); | 356 | sfd = connect_usbmuxd_socket(); |
| 321 | if (sfd < 0) { | 357 | if (sfd < 0) { |
| @@ -336,10 +372,10 @@ int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) | |||
| 336 | if (usbmuxd_get_result(sfd, s_req.header.tag, &res) && (res == 0)) { | 372 | if (usbmuxd_get_result(sfd, s_req.header.tag, &res) && (res == 0)) { |
| 337 | listen_success = 1; | 373 | listen_success = 1; |
| 338 | } else { | 374 | } else { |
| 375 | close(sfd); | ||
| 339 | fprintf(stderr, | 376 | fprintf(stderr, |
| 340 | "%s: Did not get response to scan request (with result=0)...\n", | 377 | "%s: Did not get response to scan request (with result=0)...\n", |
| 341 | __func__); | 378 | __func__); |
| 342 | close(sfd); | ||
| 343 | return res; | 379 | return res; |
| 344 | } | 380 | } |
| 345 | } | 381 | } |
| @@ -352,45 +388,35 @@ int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) | |||
| 352 | *device_list = NULL; | 388 | *device_list = NULL; |
| 353 | // receive device list | 389 | // receive device list |
| 354 | while (1) { | 390 | while (1) { |
| 355 | if (recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, 1000) == sizeof(hdr)) { | 391 | if (receive_packet(sfd, &hdr, &payload, 1000) > 0) { |
| 356 | if ((hdr.length < 48) || (hdr.length > sizeof(hdr)+sizeof(dev_info))) { | 392 | if (hdr.message == MESSAGE_DEVICE_ADD) { |
| 357 | // invalid packet size received! | 393 | dev_info = payload; |
| 358 | fprintf(stderr, | ||
| 359 | "%s: Invalid packet size (%d) received when expecting a device info record.\n", | ||
| 360 | __func__, hdr.length); | ||
| 361 | break; | ||
| 362 | } | ||
| 363 | |||
| 364 | recv_len = recv_buf(sfd, &dev_info, hdr.length - sizeof(hdr)); | ||
| 365 | if (recv_len <= 0) { | ||
| 366 | fprintf(stderr, | ||
| 367 | "%s: Error when receiving device info record\n", | ||
| 368 | __func__); | ||
| 369 | break; | ||
| 370 | } else if ((uint32_t) recv_len < hdr.length - sizeof(hdr)) { | ||
| 371 | fprintf(stderr, | ||
| 372 | "%s: received less data than specified in header!\n", __func__); | ||
| 373 | } else { | ||
| 374 | newlist = (usbmuxd_device_info_t *) realloc(*device_list, sizeof(usbmuxd_device_info_t) * (dev_cnt + 1)); | 394 | newlist = (usbmuxd_device_info_t *) realloc(*device_list, sizeof(usbmuxd_device_info_t) * (dev_cnt + 1)); |
| 375 | if (newlist) { | 395 | if (newlist) { |
| 376 | newlist[dev_cnt].handle = | 396 | newlist[dev_cnt].handle = |
| 377 | (int) dev_info.device_id; | 397 | (int) dev_info->device_id; |
| 378 | newlist[dev_cnt].product_id = | 398 | newlist[dev_cnt].product_id = |
| 379 | dev_info.product_id; | 399 | dev_info->product_id; |
| 380 | memset(newlist[dev_cnt].uuid, '\0', | 400 | memset(newlist[dev_cnt].uuid, '\0', |
| 381 | sizeof(newlist[dev_cnt].uuid)); | 401 | sizeof(newlist[dev_cnt].uuid)); |
| 382 | memcpy(newlist[dev_cnt].uuid, | 402 | memcpy(newlist[dev_cnt].uuid, |
| 383 | dev_info.serial_number, | 403 | dev_info->serial_number, |
| 384 | sizeof(newlist[dev_cnt].uuid)); | 404 | sizeof(newlist[dev_cnt].uuid)); |
| 385 | *device_list = newlist; | 405 | *device_list = newlist; |
| 386 | dev_cnt++; | 406 | dev_cnt++; |
| 387 | } else { | 407 | } else { |
| 388 | fprintf(stderr, | 408 | fprintf(stderr, |
| 389 | "%s: ERROR: out of memory when trying to realloc!\n", | 409 | "%s: ERROR: out of memory when trying to realloc!\n", |
| 390 | __func__); | 410 | __func__); |
| 411 | if (payload) | ||
| 412 | free(payload); | ||
| 391 | break; | 413 | break; |
| 392 | } | 414 | } |
| 415 | } else { | ||
| 416 | fprintf(stderr, "%s: Unexpected message %d\n", __func__, hdr.message); | ||
| 393 | } | 417 | } |
| 418 | if (payload) | ||
| 419 | free(payload); | ||
| 394 | } else { | 420 | } else { |
| 395 | // we _should_ have all of them now. | 421 | // we _should_ have all of them now. |
| 396 | // or perhaps an error occured. | 422 | // or perhaps an error occured. |
