diff options
Diffstat (limited to 'libusbmuxd/libusbmuxd.c')
-rw-r--r-- | libusbmuxd/libusbmuxd.c | 782 |
1 files changed, 0 insertions, 782 deletions
diff --git a/libusbmuxd/libusbmuxd.c b/libusbmuxd/libusbmuxd.c deleted file mode 100644 index 5eaf8e6..0000000 --- a/libusbmuxd/libusbmuxd.c +++ /dev/null | |||
@@ -1,782 +0,0 @@ | |||
1 | /* | ||
2 | libusbmuxd - client library to talk to usbmuxd | ||
3 | |||
4 | Copyright (C) 2009-2010 Nikias Bassen <nikias@gmx.li> | ||
5 | Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org> | ||
6 | Copyright (C) 2009 Martin Szulecki <opensuse@sukimashita.com> | ||
7 | |||
8 | This library is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU Lesser General Public License as | ||
10 | published by the Free Software Foundation, either version 2.1 of the | ||
11 | License, or (at your option) any later version. | ||
12 | |||
13 | This library is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU Lesser General Public | ||
19 | License along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | |||
22 | */ | ||
23 | |||
24 | #include <stdint.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <errno.h> | ||
27 | #include <stdio.h> | ||
28 | #include <string.h> | ||
29 | #ifdef WIN32 | ||
30 | #include <windows.h> | ||
31 | #include <winsock2.h> | ||
32 | #define sleep(x) Sleep(x*1000) | ||
33 | #else | ||
34 | #include <sys/socket.h> | ||
35 | #include <arpa/inet.h> | ||
36 | #endif | ||
37 | #include <unistd.h> | ||
38 | #include <signal.h> | ||
39 | #include <pthread.h> | ||
40 | |||
41 | #ifdef HAVE_PLIST | ||
42 | #include <plist/plist.h> | ||
43 | #define PLIST_BUNDLE_ID "com.marcansoft.usbmuxd" | ||
44 | #define PLIST_CLIENT_VERSION_STRING "usbmuxd built for freedom" | ||
45 | #define PLIST_PROGNAME "libusbmuxd" | ||
46 | #endif | ||
47 | |||
48 | // usbmuxd public interface | ||
49 | #include "usbmuxd.h" | ||
50 | // usbmuxd protocol | ||
51 | #include "usbmuxd-proto.h" | ||
52 | // socket utility functions | ||
53 | #include "sock_stuff.h" | ||
54 | // misc utility functions | ||
55 | #include "utils.h" | ||
56 | |||
57 | static struct collection devices; | ||
58 | static usbmuxd_event_cb_t event_cb = NULL; | ||
59 | pthread_t devmon; | ||
60 | static int listenfd = -1; | ||
61 | |||
62 | static int use_tag = 0; | ||
63 | static int proto_version = 0; | ||
64 | |||
65 | /** | ||
66 | * Finds a device info record by its handle. | ||
67 | * if the record is not found, NULL is returned. | ||
68 | */ | ||
69 | static usbmuxd_device_info_t *devices_find(int handle) | ||
70 | { | ||
71 | FOREACH(usbmuxd_device_info_t *dev, &devices) { | ||
72 | if (dev && dev->handle == handle) { | ||
73 | return dev; | ||
74 | } | ||
75 | } ENDFOREACH | ||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * Creates a socket connection to usbmuxd. | ||
81 | * For Mac/Linux it is a unix domain socket, | ||
82 | * for Windows it is a tcp socket. | ||
83 | */ | ||
84 | static int connect_usbmuxd_socket() | ||
85 | { | ||
86 | #if defined(WIN32) || defined(__CYGWIN__) | ||
87 | return connect_socket("127.0.0.1", USBMUXD_SOCKET_PORT); | ||
88 | #else | ||
89 | return connect_unix_socket(USBMUXD_SOCKET_FILE); | ||
90 | #endif | ||
91 | } | ||
92 | |||
93 | static int receive_packet(int sfd, struct usbmuxd_header *header, void **payload, int timeout) | ||
94 | { | ||
95 | int recv_len; | ||
96 | struct usbmuxd_header hdr; | ||
97 | char *payload_loc = NULL; | ||
98 | |||
99 | header->length = 0; | ||
100 | header->version = 0; | ||
101 | header->message = 0; | ||
102 | header->tag = 0; | ||
103 | |||
104 | recv_len = recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, timeout); | ||
105 | if (recv_len < 0) { | ||
106 | return recv_len; | ||
107 | } else if (recv_len < sizeof(hdr)) { | ||
108 | return recv_len; | ||
109 | } | ||
110 | |||
111 | uint32_t payload_size = hdr.length - sizeof(hdr); | ||
112 | if (payload_size > 0) { | ||
113 | payload_loc = (char*)malloc(payload_size); | ||
114 | if (recv_buf_timeout(sfd, payload_loc, payload_size, 0, 5000) != payload_size) { | ||
115 | fprintf(stderr, "%s: Error receiving payload of size %d\n", __func__, payload_size); | ||
116 | free(payload_loc); | ||
117 | return -EBADMSG; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | #ifdef HAVE_PLIST | ||
122 | if (hdr.message == MESSAGE_PLIST) { | ||
123 | char *message = NULL; | ||
124 | plist_t plist = NULL; | ||
125 | plist_from_xml(payload_loc, payload_size, &plist); | ||
126 | free(payload_loc); | ||
127 | |||
128 | if (!plist) { | ||
129 | fprintf(stderr, "%s: Error getting plist from payload!\n", __func__); | ||
130 | return -EBADMSG; | ||
131 | } | ||
132 | |||
133 | plist_t node = plist_dict_get_item(plist, "MessageType"); | ||
134 | if (plist_get_node_type(node) != PLIST_STRING) { | ||
135 | fprintf(stderr, "%s: Error getting message type from plist!\n", __func__); | ||
136 | free(plist); | ||
137 | return -EBADMSG; | ||
138 | } | ||
139 | |||
140 | plist_get_string_val(node, &message); | ||
141 | if (message) { | ||
142 | uint64_t val = 0; | ||
143 | if (strcmp(message, "Result") == 0) { | ||
144 | /* result message */ | ||
145 | uint32_t dwval = 0; | ||
146 | plist_t n = plist_dict_get_item(plist, "Number"); | ||
147 | plist_get_uint_val(n, &val); | ||
148 | *payload = malloc(sizeof(uint32_t)); | ||
149 | dwval = val; | ||
150 | memcpy(*payload, &dwval, sizeof(dwval)); | ||
151 | hdr.length = sizeof(hdr) + sizeof(dwval); | ||
152 | hdr.message = MESSAGE_RESULT; | ||
153 | } else if (strcmp(message, "Attached") == 0) { | ||
154 | /* device add message */ | ||
155 | struct usbmuxd_device_record *dev = NULL; | ||
156 | plist_t props = plist_dict_get_item(plist, "Properties"); | ||
157 | if (!props) { | ||
158 | fprintf(stderr, "%s: Could not get properties for message '%s' from plist!\n", __func__, message); | ||
159 | plist_free(plist); | ||
160 | return -EBADMSG; | ||
161 | } | ||
162 | dev = (struct usbmuxd_device_record*)malloc(sizeof(struct usbmuxd_device_record)); | ||
163 | memset(dev, 0, sizeof(struct usbmuxd_device_record)); | ||
164 | |||
165 | plist_t n = plist_dict_get_item(props, "DeviceID"); | ||
166 | plist_get_uint_val(n, &val); | ||
167 | dev->device_id = (uint32_t)val; | ||
168 | |||
169 | n = plist_dict_get_item(props, "ProductID"); | ||
170 | plist_get_uint_val(n, &val); | ||
171 | dev->product_id = (uint32_t)val; | ||
172 | |||
173 | n = plist_dict_get_item(props, "SerialNumber"); | ||
174 | char *strval = NULL; | ||
175 | plist_get_string_val(n, &strval); | ||
176 | if (strval) { | ||
177 | strcpy(dev->serial_number, strval); | ||
178 | free(strval); | ||
179 | } | ||
180 | n = plist_dict_get_item(props, "LocationID"); | ||
181 | plist_get_uint_val(n, &val); | ||
182 | dev->location = (uint32_t)val; | ||
183 | *payload = (void*)dev; | ||
184 | hdr.length = sizeof(hdr) + sizeof(struct usbmuxd_device_record); | ||
185 | hdr.message = MESSAGE_DEVICE_ADD; | ||
186 | } else if (strcmp(message, "Detached") == 0) { | ||
187 | /* device remove message */ | ||
188 | uint32_t dwval = 0; | ||
189 | plist_t n = plist_dict_get_item(plist, "DeviceID"); | ||
190 | if (n) { | ||
191 | plist_get_uint_val(n, &val); | ||
192 | *payload = malloc(sizeof(uint32_t)); | ||
193 | dwval = val; | ||
194 | memcpy(*payload, &dwval, sizeof(dwval)); | ||
195 | hdr.length = sizeof(hdr) + sizeof(dwval); | ||
196 | hdr.message = MESSAGE_DEVICE_REMOVE; | ||
197 | } | ||
198 | } else { | ||
199 | fprintf(stderr, "%s: Unexpected message '%s' in plist!\n", __func__, message); | ||
200 | plist_free(plist); | ||
201 | return -EBADMSG; | ||
202 | } | ||
203 | } | ||
204 | plist_free(plist); | ||
205 | } else | ||
206 | #endif | ||
207 | { | ||
208 | *payload = payload_loc; | ||
209 | } | ||
210 | |||
211 | memcpy(header, &hdr, sizeof(hdr)); | ||
212 | |||
213 | return hdr.length; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * Retrieves the result code to a previously sent request. | ||
218 | */ | ||
219 | static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result) | ||
220 | { | ||
221 | struct usbmuxd_header hdr; | ||
222 | int recv_len; | ||
223 | uint32_t *res = NULL; | ||
224 | |||
225 | if (!result) { | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | *result = -1; | ||
229 | |||
230 | if ((recv_len = receive_packet(sfd, &hdr, (void**)&res, 5000)) < 0) { | ||
231 | fprintf(stderr, "%s: Error receiving packet: %d\n", __func__, errno); | ||
232 | if (res) | ||
233 | free(res); | ||
234 | return -errno; | ||
235 | } | ||
236 | if (recv_len < sizeof(hdr)) { | ||
237 | fprintf(stderr, "%s: Received packet is too small!\n", __func__); | ||
238 | if (res) | ||
239 | free(res); | ||
240 | return -EPROTO; | ||
241 | } | ||
242 | |||
243 | if (hdr.message == MESSAGE_RESULT) { | ||
244 | int ret = 0; | ||
245 | if (res && (hdr.tag == tag)) { | ||
246 | memcpy(result, res, sizeof(uint32_t)); | ||
247 | ret = 1; | ||
248 | } | ||
249 | if (res) | ||
250 | free(res); | ||
251 | return ret; | ||
252 | } | ||
253 | fprintf(stderr, "%s: Unexpected message of type %d received!\n", __func__, hdr.message); | ||
254 | if (res) | ||
255 | free(res); | ||
256 | return -EPROTO; | ||
257 | } | ||
258 | |||
259 | static int send_packet(int sfd, uint32_t message, uint32_t tag, void *payload, uint32_t payload_size) | ||
260 | { | ||
261 | struct usbmuxd_header header; | ||
262 | |||
263 | header.length = sizeof(struct usbmuxd_header); | ||
264 | header.version = proto_version; | ||
265 | header.message = message; | ||
266 | header.tag = tag; | ||
267 | if (payload && (payload_size > 0)) { | ||
268 | header.length += payload_size; | ||
269 | } | ||
270 | int sent = send_buf(sfd, &header, sizeof(header)); | ||
271 | if (sent != sizeof(header)) { | ||
272 | fprintf(stderr, "%s: ERROR: could not send packet header\n", __func__); | ||
273 | return -1; | ||
274 | } | ||
275 | if (payload && (payload_size > 0)) { | ||
276 | sent += send_buf(sfd, payload, payload_size); | ||
277 | } | ||
278 | if (sent != (int)header.length) { | ||
279 | fprintf(stderr, "%s: ERROR: could not send whole packet\n", __func__); | ||
280 | close_socket(sfd); | ||
281 | return -1; | ||
282 | } | ||
283 | return sent; | ||
284 | } | ||
285 | |||
286 | static int send_listen_packet(int sfd, uint32_t tag) | ||
287 | { | ||
288 | int res = 0; | ||
289 | #ifdef HAVE_PLIST | ||
290 | if (proto_version == 1) { | ||
291 | /* plist packet */ | ||
292 | char *payload = NULL; | ||
293 | uint32_t payload_size = 0; | ||
294 | plist_t plist; | ||
295 | |||
296 | /* construct message plist */ | ||
297 | plist = plist_new_dict(); | ||
298 | plist_dict_insert_item(plist, "BundleID", plist_new_string(PLIST_BUNDLE_ID)); | ||
299 | plist_dict_insert_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING)); | ||
300 | plist_dict_insert_item(plist, "MessageType", plist_new_string("Listen")); | ||
301 | plist_dict_insert_item(plist, "ProgName", plist_new_string(PLIST_PROGNAME)); | ||
302 | plist_to_xml(plist, &payload, &payload_size); | ||
303 | plist_free(plist); | ||
304 | |||
305 | res = send_packet(sfd, MESSAGE_PLIST, tag, payload, payload_size); | ||
306 | free(payload); | ||
307 | } else | ||
308 | #endif | ||
309 | { | ||
310 | /* binary packet */ | ||
311 | res = send_packet(sfd, MESSAGE_LISTEN, tag, NULL, 0); | ||
312 | } | ||
313 | return res; | ||
314 | } | ||
315 | |||
316 | static int send_connect_packet(int sfd, uint32_t tag, uint32_t device_id, uint16_t port) | ||
317 | { | ||
318 | int res = 0; | ||
319 | #ifdef HAVE_PLIST | ||
320 | if (proto_version == 1) { | ||
321 | /* plist packet */ | ||
322 | char *payload = NULL; | ||
323 | uint32_t payload_size = 0; | ||
324 | plist_t plist; | ||
325 | |||
326 | /* construct message plist */ | ||
327 | plist = plist_new_dict(); | ||
328 | plist_dict_insert_item(plist, "BundleID", plist_new_string(PLIST_BUNDLE_ID)); | ||
329 | plist_dict_insert_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING)); | ||
330 | plist_dict_insert_item(plist, "MessageType", plist_new_string("Connect")); | ||
331 | plist_dict_insert_item(plist, "DeviceID", plist_new_uint(device_id)); | ||
332 | plist_dict_insert_item(plist, "PortNumber", plist_new_uint(htons(port))); | ||
333 | plist_dict_insert_item(plist, "ProgName", plist_new_string(PLIST_PROGNAME)); | ||
334 | plist_to_xml(plist, &payload, &payload_size); | ||
335 | plist_free(plist); | ||
336 | |||
337 | res = send_packet(sfd, MESSAGE_PLIST, tag, (void*)payload, payload_size); | ||
338 | free(payload); | ||
339 | } else | ||
340 | #endif | ||
341 | { | ||
342 | /* binary packet */ | ||
343 | struct { | ||
344 | uint32_t device_id; | ||
345 | uint16_t port; | ||
346 | uint16_t reserved; | ||
347 | } conninfo; | ||
348 | |||
349 | conninfo.device_id = device_id; | ||
350 | conninfo.port = htons(port); | ||
351 | conninfo.reserved = 0; | ||
352 | |||
353 | res = send_packet(sfd, MESSAGE_CONNECT, tag, &conninfo, sizeof(conninfo)); | ||
354 | } | ||
355 | return res; | ||
356 | } | ||
357 | |||
358 | /** | ||
359 | * Generates an event, i.e. calls the callback function. | ||
360 | * A reference to a populated usbmuxd_event_t with information about the event | ||
361 | * and the corresponding device will be passed to the callback function. | ||
362 | */ | ||
363 | static void generate_event(usbmuxd_event_cb_t callback, const usbmuxd_device_info_t *dev, enum usbmuxd_event_type event, void *user_data) | ||
364 | { | ||
365 | usbmuxd_event_t ev; | ||
366 | |||
367 | if (!callback || !dev) { | ||
368 | return; | ||
369 | } | ||
370 | |||
371 | ev.event = event; | ||
372 | memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t)); | ||
373 | |||
374 | callback(&ev, user_data); | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * Tries to connect to usbmuxd and wait if it is not running. | ||
379 | * | ||
380 | * TODO inotify support should come here | ||
381 | */ | ||
382 | static int usbmuxd_listen() | ||
383 | { | ||
384 | int sfd; | ||
385 | uint32_t res = -1; | ||
386 | |||
387 | #ifdef HAVE_PLIST | ||
388 | retry: | ||
389 | #endif | ||
390 | sfd = connect_usbmuxd_socket(); | ||
391 | if (sfd < 0) { | ||
392 | while (event_cb) { | ||
393 | if ((sfd = connect_usbmuxd_socket()) > 0) { | ||
394 | break; | ||
395 | } | ||
396 | sleep(1); | ||
397 | } | ||
398 | } | ||
399 | |||
400 | if (sfd < 0) { | ||
401 | fprintf(stderr, "%s: ERROR: usbmuxd was supposed to be running here...\n", __func__); | ||
402 | return sfd; | ||
403 | } | ||
404 | |||
405 | use_tag++; | ||
406 | if (send_listen_packet(sfd, use_tag) <= 0) { | ||
407 | fprintf(stderr, "%s: ERROR: could not send listen packet\n", __func__); | ||
408 | close_socket(sfd); | ||
409 | return -1; | ||
410 | } | ||
411 | if (usbmuxd_get_result(sfd, use_tag, &res) && (res != 0)) { | ||
412 | close_socket(sfd); | ||
413 | #ifdef HAVE_PLIST | ||
414 | if ((res == RESULT_BADVERSION) && (proto_version != 1)) { | ||
415 | proto_version = 1; | ||
416 | goto retry; | ||
417 | } | ||
418 | #endif | ||
419 | fprintf(stderr, "%s: ERROR: did not get OK but %d\n", __func__, res); | ||
420 | return -1; | ||
421 | } | ||
422 | |||
423 | return sfd; | ||
424 | } | ||
425 | |||
426 | /** | ||
427 | * Waits for an event to occur, i.e. a packet coming from usbmuxd. | ||
428 | * Calls generate_event to pass the event via callback to the client program. | ||
429 | */ | ||
430 | int get_next_event(int sfd, usbmuxd_event_cb_t callback, void *user_data) | ||
431 | { | ||
432 | struct usbmuxd_header hdr; | ||
433 | void *payload = NULL; | ||
434 | |||
435 | /* block until we receive something */ | ||
436 | if (receive_packet(sfd, &hdr, &payload, 0) < 0) { | ||
437 | // when then usbmuxd connection fails, | ||
438 | // generate remove events for every device that | ||
439 | // is still present so applications know about it | ||
440 | FOREACH(usbmuxd_device_info_t *dev, &devices) { | ||
441 | generate_event(callback, dev, UE_DEVICE_REMOVE, user_data); | ||
442 | collection_remove(&devices, dev); | ||
443 | } ENDFOREACH | ||
444 | return -EIO; | ||
445 | } | ||
446 | |||
447 | if ((hdr.length > sizeof(hdr)) && !payload) { | ||
448 | fprintf(stderr, "%s: Invalid packet received, payload is missing!\n", __func__); | ||
449 | return -EBADMSG; | ||
450 | } | ||
451 | |||
452 | if (hdr.message == MESSAGE_DEVICE_ADD) { | ||
453 | struct usbmuxd_device_record *dev = payload; | ||
454 | usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t)); | ||
455 | if (!devinfo) { | ||
456 | fprintf(stderr, "%s: Out of memory!\n", __func__); | ||
457 | free(payload); | ||
458 | return -1; | ||
459 | } | ||
460 | |||
461 | devinfo->handle = dev->device_id; | ||
462 | devinfo->product_id = dev->product_id; | ||
463 | memset(devinfo->uuid, '\0', sizeof(devinfo->uuid)); | ||
464 | memcpy(devinfo->uuid, dev->serial_number, sizeof(devinfo->uuid)); | ||
465 | |||
466 | collection_add(&devices, devinfo); | ||
467 | generate_event(callback, devinfo, UE_DEVICE_ADD, user_data); | ||
468 | } else if (hdr.message == MESSAGE_DEVICE_REMOVE) { | ||
469 | uint32_t handle; | ||
470 | usbmuxd_device_info_t *devinfo; | ||
471 | |||
472 | memcpy(&handle, payload, sizeof(uint32_t)); | ||
473 | |||
474 | devinfo = devices_find(handle); | ||
475 | if (!devinfo) { | ||
476 | 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); | ||
477 | } else { | ||
478 | generate_event(callback, devinfo, UE_DEVICE_REMOVE, user_data); | ||
479 | collection_remove(&devices, devinfo); | ||
480 | } | ||
481 | } else { | ||
482 | fprintf(stderr, "%s: Unexpected message type %d length %d received!\n", __func__, hdr.message, hdr.length); | ||
483 | } | ||
484 | if (payload) { | ||
485 | free(payload); | ||
486 | } | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | /** | ||
491 | * Device Monitor thread function. | ||
492 | * | ||
493 | * This function sets up a connection to usbmuxd | ||
494 | */ | ||
495 | static void *device_monitor(void *data) | ||
496 | { | ||
497 | collection_init(&devices); | ||
498 | |||
499 | while (event_cb) { | ||
500 | |||
501 | listenfd = usbmuxd_listen(); | ||
502 | if (listenfd < 0) { | ||
503 | continue; | ||
504 | } | ||
505 | |||
506 | while (event_cb) { | ||
507 | int res = get_next_event(listenfd, event_cb, data); | ||
508 | if (res < 0) { | ||
509 | break; | ||
510 | } | ||
511 | } | ||
512 | } | ||
513 | |||
514 | collection_free(&devices); | ||
515 | |||
516 | return NULL; | ||
517 | } | ||
518 | |||
519 | int usbmuxd_subscribe(usbmuxd_event_cb_t callback, void *user_data) | ||
520 | { | ||
521 | int res; | ||
522 | |||
523 | if (!callback) { | ||
524 | return -EINVAL; | ||
525 | } | ||
526 | event_cb = callback; | ||
527 | |||
528 | res = pthread_create(&devmon, NULL, device_monitor, user_data); | ||
529 | if (res != 0) { | ||
530 | fprintf(stderr, "%s: ERROR: Could not start device watcher thread!\n", __func__); | ||
531 | return res; | ||
532 | } | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | int usbmuxd_unsubscribe() | ||
537 | { | ||
538 | event_cb = NULL; | ||
539 | |||
540 | if (pthread_kill(devmon, 0) == 0) { | ||
541 | close_socket(listenfd); | ||
542 | listenfd = -1; | ||
543 | pthread_kill(devmon, SIGINT); | ||
544 | pthread_join(devmon, NULL); | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list) | ||
551 | { | ||
552 | int sfd; | ||
553 | int listen_success = 0; | ||
554 | uint32_t res; | ||
555 | usbmuxd_device_info_t *newlist = NULL; | ||
556 | struct usbmuxd_header hdr; | ||
557 | struct usbmuxd_device_record *dev_info; | ||
558 | int dev_cnt = 0; | ||
559 | void *payload = NULL; | ||
560 | |||
561 | #ifdef HAVE_PLIST | ||
562 | retry: | ||
563 | #endif | ||
564 | sfd = connect_usbmuxd_socket(); | ||
565 | if (sfd < 0) { | ||
566 | fprintf(stderr, "%s: error opening socket!\n", __func__); | ||
567 | return sfd; | ||
568 | } | ||
569 | |||
570 | use_tag++; | ||
571 | if (send_listen_packet(sfd, use_tag) > 0) { | ||
572 | res = -1; | ||
573 | // get response | ||
574 | if (usbmuxd_get_result(sfd, use_tag, &res) && (res == 0)) { | ||
575 | listen_success = 1; | ||
576 | } else { | ||
577 | close_socket(sfd); | ||
578 | #ifdef HAVE_PLIST | ||
579 | if ((res == RESULT_BADVERSION) && (proto_version != 1)) { | ||
580 | proto_version = 1; | ||
581 | goto retry; | ||
582 | } | ||
583 | #endif | ||
584 | fprintf(stderr, | ||
585 | "%s: Did not get response to scan request (with result=0)...\n", | ||
586 | __func__); | ||
587 | return res; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | if (!listen_success) { | ||
592 | fprintf(stderr, "%s: Could not send listen request!\n", __func__); | ||
593 | return -1; | ||
594 | } | ||
595 | |||
596 | *device_list = NULL; | ||
597 | // receive device list | ||
598 | while (1) { | ||
599 | if (receive_packet(sfd, &hdr, &payload, 1000) > 0) { | ||
600 | if (hdr.message == MESSAGE_DEVICE_ADD) { | ||
601 | dev_info = payload; | ||
602 | newlist = (usbmuxd_device_info_t *) realloc(*device_list, sizeof(usbmuxd_device_info_t) * (dev_cnt + 1)); | ||
603 | if (newlist) { | ||
604 | newlist[dev_cnt].handle = | ||
605 | (int) dev_info->device_id; | ||
606 | newlist[dev_cnt].product_id = | ||
607 | dev_info->product_id; | ||
608 | memset(newlist[dev_cnt].uuid, '\0', | ||
609 | sizeof(newlist[dev_cnt].uuid)); | ||
610 | memcpy(newlist[dev_cnt].uuid, | ||
611 | dev_info->serial_number, | ||
612 | sizeof(newlist[dev_cnt].uuid)); | ||
613 | *device_list = newlist; | ||
614 | dev_cnt++; | ||
615 | } else { | ||
616 | fprintf(stderr, | ||
617 | "%s: ERROR: out of memory when trying to realloc!\n", | ||
618 | __func__); | ||
619 | if (payload) | ||
620 | free(payload); | ||
621 | break; | ||
622 | } | ||
623 | } else { | ||
624 | fprintf(stderr, "%s: Unexpected message %d\n", __func__, hdr.message); | ||
625 | } | ||
626 | if (payload) | ||
627 | free(payload); | ||
628 | } else { | ||
629 | // we _should_ have all of them now. | ||
630 | // or perhaps an error occured. | ||
631 | break; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | // explicitly close connection | ||
636 | close_socket(sfd); | ||
637 | |||
638 | // terminating zero record | ||
639 | newlist = (usbmuxd_device_info_t*) realloc(*device_list, sizeof(usbmuxd_device_info_t) * (dev_cnt + 1)); | ||
640 | memset(newlist + dev_cnt, 0, sizeof(usbmuxd_device_info_t)); | ||
641 | *device_list = newlist; | ||
642 | |||
643 | return dev_cnt; | ||
644 | } | ||
645 | |||
646 | int usbmuxd_device_list_free(usbmuxd_device_info_t **device_list) | ||
647 | { | ||
648 | if (device_list) { | ||
649 | free(*device_list); | ||
650 | } | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | int usbmuxd_get_device_by_uuid(const char *uuid, usbmuxd_device_info_t *device) | ||
655 | { | ||
656 | usbmuxd_device_info_t *dev_list = NULL; | ||
657 | |||
658 | if (!device) { | ||
659 | return -EINVAL; | ||
660 | } | ||
661 | if (usbmuxd_get_device_list(&dev_list) < 0) { | ||
662 | return -ENODEV; | ||
663 | } | ||
664 | |||
665 | int i; | ||
666 | int result = 0; | ||
667 | for (i = 0; dev_list[i].handle > 0; i++) { | ||
668 | if (!uuid) { | ||
669 | device->handle = dev_list[i].handle; | ||
670 | device->product_id = dev_list[i].product_id; | ||
671 | strcpy(device->uuid, dev_list[i].uuid); | ||
672 | result = 1; | ||
673 | break; | ||
674 | } | ||
675 | if (!strcmp(uuid, dev_list[i].uuid)) { | ||
676 | device->handle = dev_list[i].handle; | ||
677 | device->product_id = dev_list[i].product_id; | ||
678 | strcpy(device->uuid, dev_list[i].uuid); | ||
679 | result = 1; | ||
680 | break; | ||
681 | } | ||
682 | } | ||
683 | |||
684 | free(dev_list); | ||
685 | |||
686 | return result; | ||
687 | } | ||
688 | |||
689 | int usbmuxd_connect(const int handle, const unsigned short port) | ||
690 | { | ||
691 | int sfd; | ||
692 | int connected = 0; | ||
693 | uint32_t res = -1; | ||
694 | |||
695 | #ifdef HAVE_PLIST | ||
696 | retry: | ||
697 | #endif | ||
698 | sfd = connect_usbmuxd_socket(); | ||
699 | if (sfd < 0) { | ||
700 | fprintf(stderr, "%s: Error: Connection to usbmuxd failed: %s\n", | ||
701 | __func__, strerror(errno)); | ||
702 | return sfd; | ||
703 | } | ||
704 | |||
705 | use_tag++; | ||
706 | if (send_connect_packet(sfd, use_tag, (uint32_t)handle, (uint16_t)port) <= 0) { | ||
707 | fprintf(stderr, "%s: Error sending connect message!\n", __func__); | ||
708 | } else { | ||
709 | // read ACK | ||
710 | //fprintf(stderr, "%s: Reading connect result...\n", __func__); | ||
711 | if (usbmuxd_get_result(sfd, use_tag, &res)) { | ||
712 | if (res == 0) { | ||
713 | //fprintf(stderr, "%s: Connect success!\n", __func__); | ||
714 | connected = 1; | ||
715 | } else { | ||
716 | #ifdef HAVE_PLIST | ||
717 | if ((res == RESULT_BADVERSION) && (proto_version == 0)) { | ||
718 | proto_version = 1; | ||
719 | close_socket(sfd); | ||
720 | goto retry; | ||
721 | } | ||
722 | #endif | ||
723 | fprintf(stderr, "%s: Connect failed, Error code=%d\n", | ||
724 | __func__, res); | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | |||
729 | if (connected) { | ||
730 | return sfd; | ||
731 | } | ||
732 | |||
733 | close_socket(sfd); | ||
734 | |||
735 | return -1; | ||
736 | } | ||
737 | |||
738 | int usbmuxd_disconnect(int sfd) | ||
739 | { | ||
740 | return close_socket(sfd); | ||
741 | } | ||
742 | |||
743 | int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes) | ||
744 | { | ||
745 | int num_sent; | ||
746 | |||
747 | if (sfd < 0) { | ||
748 | return -EINVAL; | ||
749 | } | ||
750 | |||
751 | num_sent = send(sfd, (void*)data, len, 0); | ||
752 | if (num_sent < 0) { | ||
753 | *sent_bytes = 0; | ||
754 | fprintf(stderr, "%s: Error %d when sending: %s\n", __func__, num_sent, strerror(errno)); | ||
755 | return num_sent; | ||
756 | } else if ((uint32_t)num_sent < len) { | ||
757 | fprintf(stderr, "%s: Warning: Did not send enough (only %d of %d)\n", __func__, num_sent, len); | ||
758 | } | ||
759 | |||
760 | *sent_bytes = num_sent; | ||
761 | |||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) | ||
766 | { | ||
767 | int num_recv = recv_buf_timeout(sfd, (void*)data, len, 0, timeout); | ||
768 | if (num_recv < 0) { | ||
769 | *recv_bytes = 0; | ||
770 | return num_recv; | ||
771 | } | ||
772 | |||
773 | *recv_bytes = num_recv; | ||
774 | |||
775 | return 0; | ||
776 | } | ||
777 | |||
778 | int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes) | ||
779 | { | ||
780 | return usbmuxd_recv_timeout(sfd, data, len, recv_bytes, 5000); | ||
781 | } | ||
782 | |||