summaryrefslogtreecommitdiffstats
path: root/libusbmuxd/libusbmuxd.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2013-09-17 11:30:01 +0200
committerGravatar Nikias Bassen2013-09-17 11:30:01 +0200
commitf4758e8b15cd30fe3f7f18de42e2ea20bc5696f0 (patch)
tree671e85e639b689b0b888a0f51c7dd5e15d408930 /libusbmuxd/libusbmuxd.c
parent10939f3ad5755d1117f20df2b97c0cbbd83bbcbe (diff)
downloadusbmuxd-f4758e8b15cd30fe3f7f18de42e2ea20bc5696f0.tar.gz
usbmuxd-f4758e8b15cd30fe3f7f18de42e2ea20bc5696f0.tar.bz2
remove libusbmuxd sources and adapt source tree to use autotools
libusbmuxd has been split off and is now managed in a separate repository. By the time of this commit, the repository is: git clone http://git.sukimashita.com/libusbmuxd.git
Diffstat (limited to 'libusbmuxd/libusbmuxd.c')
-rw-r--r--libusbmuxd/libusbmuxd.c975
1 files changed, 0 insertions, 975 deletions
diff --git a/libusbmuxd/libusbmuxd.c b/libusbmuxd/libusbmuxd.c
deleted file mode 100644
index 20ac8ab..0000000
--- a/libusbmuxd/libusbmuxd.c
+++ /dev/null
@@ -1,975 +0,0 @@
1/*
2 libusbmuxd - client library to talk to usbmuxd
3
4Copyright (C) 2009-2010 Nikias Bassen <nikias@gmx.li>
5Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org>
6Copyright (C) 2009 Martin Szulecki <opensuse@sukimashita.com>
7
8This library is free software; you can redistribute it and/or modify
9it under the terms of the GNU Lesser General Public License as
10published by the Free Software Foundation, either version 2.1 of the
11License, or (at your option) any later version.
12
13This library is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU Lesser General Public
19License along with this program; if not, write to the Free Software
20Foundation, 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#ifndef EPROTO
34#define EPROTO 134
35#endif
36#ifndef EBADMSG
37#define EBADMSG 104
38#endif
39#else
40#include <sys/socket.h>
41#include <arpa/inet.h>
42#include <pthread.h>
43#endif
44
45#ifdef HAVE_INOTIFY
46#include <sys/inotify.h>
47#define EVENT_SIZE (sizeof (struct inotify_event))
48#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
49#define USBMUXD_DIRNAME "/var/run"
50#define USBMUXD_SOCKET_NAME "usbmuxd"
51#endif /* HAVE_INOTIFY */
52
53#include <unistd.h>
54#include <signal.h>
55
56#ifdef HAVE_PLIST
57#include <plist/plist.h>
58#define PLIST_BUNDLE_ID "com.marcansoft.usbmuxd"
59#define PLIST_CLIENT_VERSION_STRING "usbmuxd built for freedom"
60#define PLIST_PROGNAME "libusbmuxd"
61#endif
62
63// usbmuxd public interface
64#include "usbmuxd.h"
65// usbmuxd protocol
66#include "usbmuxd-proto.h"
67// socket utility functions
68#include "sock_stuff.h"
69// misc utility functions
70#include "utils.h"
71
72static int libusbmuxd_debug = 0;
73#define DEBUG(x, y, ...) if (x <= libusbmuxd_debug) fprintf(stderr, (y), __VA_ARGS__);
74
75static struct collection devices;
76static usbmuxd_event_cb_t event_cb = NULL;
77#ifdef WIN32
78HANDLE devmon = NULL;
79CRITICAL_SECTION mutex;
80static int mutex_initialized = 0;
81#define LOCK if (!mutex_initialized) { InitializeCriticalSection(&mutex); mutex_initialized = 1; } EnterCriticalSection(&mutex);
82#define UNLOCK LeaveCriticalSection(&mutex);
83#else
84pthread_t devmon;
85pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
86#define LOCK pthread_mutex_lock(&mutex)
87#define UNLOCK pthread_mutex_unlock(&mutex)
88#endif
89static int listenfd = -1;
90
91static int use_tag = 0;
92static int proto_version = 0;
93
94/**
95 * Finds a device info record by its handle.
96 * if the record is not found, NULL is returned.
97 */
98static usbmuxd_device_info_t *devices_find(int handle)
99{
100 FOREACH(usbmuxd_device_info_t *dev, &devices) {
101 if (dev && dev->handle == handle) {
102 return dev;
103 }
104 } ENDFOREACH
105 return NULL;
106}
107
108/**
109 * Creates a socket connection to usbmuxd.
110 * For Mac/Linux it is a unix domain socket,
111 * for Windows it is a tcp socket.
112 */
113static int connect_usbmuxd_socket()
114{
115#if defined(WIN32) || defined(__CYGWIN__)
116 return connect_socket("127.0.0.1", USBMUXD_SOCKET_PORT);
117#else
118 return connect_unix_socket(USBMUXD_SOCKET_FILE);
119#endif
120}
121
122static int receive_packet(int sfd, struct usbmuxd_header *header, void **payload, int timeout)
123{
124 int recv_len;
125 struct usbmuxd_header hdr;
126 char *payload_loc = NULL;
127
128 header->length = 0;
129 header->version = 0;
130 header->message = 0;
131 header->tag = 0;
132
133 recv_len = recv_buf_timeout(sfd, &hdr, sizeof(hdr), 0, timeout);
134 if (recv_len < 0) {
135 return recv_len;
136 } else if (recv_len < sizeof(hdr)) {
137 return recv_len;
138 }
139
140 uint32_t payload_size = hdr.length - sizeof(hdr);
141 if (payload_size > 0) {
142 payload_loc = (char*)malloc(payload_size);
143 if (recv_buf_timeout(sfd, payload_loc, payload_size, 0, 5000) != payload_size) {
144 DEBUG(1, "%s: Error receiving payload of size %d\n", __func__, payload_size);
145 free(payload_loc);
146 return -EBADMSG;
147 }
148 }
149
150#ifdef HAVE_PLIST
151 if (hdr.message == MESSAGE_PLIST) {
152 char *message = NULL;
153 plist_t plist = NULL;
154 plist_from_xml(payload_loc, payload_size, &plist);
155 free(payload_loc);
156
157 if (!plist) {
158 DEBUG(1, "%s: Error getting plist from payload!\n", __func__);
159 return -EBADMSG;
160 }
161
162 plist_t node = plist_dict_get_item(plist, "MessageType");
163 if (plist_get_node_type(node) != PLIST_STRING) {
164 DEBUG(1, "%s: Error getting message type from plist!\n", __func__);
165 free(plist);
166 return -EBADMSG;
167 }
168
169 plist_get_string_val(node, &message);
170 if (message) {
171 uint64_t val = 0;
172 if (strcmp(message, "Result") == 0) {
173 /* result message */
174 uint32_t dwval = 0;
175 plist_t n = plist_dict_get_item(plist, "Number");
176 plist_get_uint_val(n, &val);
177 *payload = malloc(sizeof(uint32_t));
178 dwval = val;
179 memcpy(*payload, &dwval, sizeof(dwval));
180 hdr.length = sizeof(hdr) + sizeof(dwval);
181 hdr.message = MESSAGE_RESULT;
182 } else if (strcmp(message, "Attached") == 0) {
183 /* device add message */
184 struct usbmuxd_device_record *dev = NULL;
185 plist_t props = plist_dict_get_item(plist, "Properties");
186 if (!props) {
187 DEBUG(1, "%s: Could not get properties for message '%s' from plist!\n", __func__, message);
188 free(message);
189 plist_free(plist);
190 return -EBADMSG;
191 }
192 dev = (struct usbmuxd_device_record*)malloc(sizeof(struct usbmuxd_device_record));
193 memset(dev, 0, sizeof(struct usbmuxd_device_record));
194
195 plist_t n = plist_dict_get_item(props, "DeviceID");
196 plist_get_uint_val(n, &val);
197 dev->device_id = (uint32_t)val;
198
199 n = plist_dict_get_item(props, "ProductID");
200 plist_get_uint_val(n, &val);
201 dev->product_id = (uint32_t)val;
202
203 n = plist_dict_get_item(props, "SerialNumber");
204 char *strval = NULL;
205 plist_get_string_val(n, &strval);
206 if (strval) {
207 strncpy(dev->serial_number, strval, 255);
208 free(strval);
209 }
210 n = plist_dict_get_item(props, "LocationID");
211 plist_get_uint_val(n, &val);
212 dev->location = (uint32_t)val;
213 *payload = (void*)dev;
214 hdr.length = sizeof(hdr) + sizeof(struct usbmuxd_device_record);
215 hdr.message = MESSAGE_DEVICE_ADD;
216 } else if (strcmp(message, "Detached") == 0) {
217 /* device remove message */
218 uint32_t dwval = 0;
219 plist_t n = plist_dict_get_item(plist, "DeviceID");
220 if (n) {
221 plist_get_uint_val(n, &val);
222 *payload = malloc(sizeof(uint32_t));
223 dwval = val;
224 memcpy(*payload, &dwval, sizeof(dwval));
225 hdr.length = sizeof(hdr) + sizeof(dwval);
226 hdr.message = MESSAGE_DEVICE_REMOVE;
227 }
228 } else {
229 DEBUG(1, "%s: Unexpected message '%s' in plist!\n", __func__, message);
230 free(message);
231 plist_free(plist);
232 return -EBADMSG;
233 }
234 free(message);
235 }
236 plist_free(plist);
237 } else
238#endif
239 {
240 *payload = payload_loc;
241 }
242
243 memcpy(header, &hdr, sizeof(hdr));
244
245 return hdr.length;
246}
247
248/**
249 * Retrieves the result code to a previously sent request.
250 */
251static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result)
252{
253 struct usbmuxd_header hdr;
254 int recv_len;
255 uint32_t *res = NULL;
256
257 if (!result) {
258 return -EINVAL;
259 }
260 *result = -1;
261
262 if ((recv_len = receive_packet(sfd, &hdr, (void**)&res, 5000)) < 0) {
263 DEBUG(1, "%s: Error receiving packet: %d\n", __func__, errno);
264 if (res)
265 free(res);
266 return -errno;
267 }
268 if (recv_len < sizeof(hdr)) {
269 DEBUG(1, "%s: Received packet is too small!\n", __func__);
270 if (res)
271 free(res);
272 return -EPROTO;
273 }
274
275 if (hdr.message == MESSAGE_RESULT) {
276 int ret = 0;
277 if (res && (hdr.tag == tag)) {
278 memcpy(result, res, sizeof(uint32_t));
279 ret = 1;
280 }
281 if (res)
282 free(res);
283 return ret;
284 }
285 DEBUG(1, "%s: Unexpected message of type %d received!\n", __func__, hdr.message);
286 if (res)
287 free(res);
288 return -EPROTO;
289}
290
291static int send_packet(int sfd, uint32_t message, uint32_t tag, void *payload, uint32_t payload_size)
292{
293 struct usbmuxd_header header;
294
295 header.length = sizeof(struct usbmuxd_header);
296 header.version = proto_version;
297 header.message = message;
298 header.tag = tag;
299 if (payload && (payload_size > 0)) {
300 header.length += payload_size;
301 }
302 int sent = send_buf(sfd, &header, sizeof(header));
303 if (sent != sizeof(header)) {
304 DEBUG(1, "%s: ERROR: could not send packet header\n", __func__);
305 return -1;
306 }
307 if (payload && (payload_size > 0)) {
308 sent += send_buf(sfd, payload, payload_size);
309 }
310 if (sent != (int)header.length) {
311 DEBUG(1, "%s: ERROR: could not send whole packet\n", __func__);
312 close_socket(sfd);
313 return -1;
314 }
315 return sent;
316}
317
318static int send_listen_packet(int sfd, uint32_t tag)
319{
320 int res = 0;
321#ifdef HAVE_PLIST
322 if (proto_version == 1) {
323 /* plist packet */
324 char *payload = NULL;
325 uint32_t payload_size = 0;
326 plist_t plist;
327
328 /* construct message plist */
329 plist = plist_new_dict();
330 plist_dict_insert_item(plist, "BundleID", plist_new_string(PLIST_BUNDLE_ID));
331 plist_dict_insert_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING));
332 plist_dict_insert_item(plist, "MessageType", plist_new_string("Listen"));
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, payload, payload_size);
338 free(payload);
339 } else
340#endif
341 {
342 /* binary packet */
343 res = send_packet(sfd, MESSAGE_LISTEN, tag, NULL, 0);
344 }
345 return res;
346}
347
348static int send_connect_packet(int sfd, uint32_t tag, uint32_t device_id, uint16_t port)
349{
350 int res = 0;
351#ifdef HAVE_PLIST
352 if (proto_version == 1) {
353 /* plist packet */
354 char *payload = NULL;
355 uint32_t payload_size = 0;
356 plist_t plist;
357
358 /* construct message plist */
359 plist = plist_new_dict();
360 plist_dict_insert_item(plist, "BundleID", plist_new_string(PLIST_BUNDLE_ID));
361 plist_dict_insert_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING));
362 plist_dict_insert_item(plist, "MessageType", plist_new_string("Connect"));
363 plist_dict_insert_item(plist, "DeviceID", plist_new_uint(device_id));
364 plist_dict_insert_item(plist, "PortNumber", plist_new_uint(htons(port)));
365 plist_dict_insert_item(plist, "ProgName", plist_new_string(PLIST_PROGNAME));
366 plist_to_xml(plist, &payload, &payload_size);
367 plist_free(plist);
368
369 res = send_packet(sfd, MESSAGE_PLIST, tag, (void*)payload, payload_size);
370 free(payload);
371 } else
372#endif
373 {
374 /* binary packet */
375 struct {
376 uint32_t device_id;
377 uint16_t port;
378 uint16_t reserved;
379 } conninfo;
380
381 conninfo.device_id = device_id;
382 conninfo.port = htons(port);
383 conninfo.reserved = 0;
384
385 res = send_packet(sfd, MESSAGE_CONNECT, tag, &conninfo, sizeof(conninfo));
386 }
387 return res;
388}
389
390/**
391 * Generates an event, i.e. calls the callback function.
392 * A reference to a populated usbmuxd_event_t with information about the event
393 * and the corresponding device will be passed to the callback function.
394 */
395static void generate_event(usbmuxd_event_cb_t callback, const usbmuxd_device_info_t *dev, enum usbmuxd_event_type event, void *user_data)
396{
397 usbmuxd_event_t ev;
398
399 if (!callback || !dev) {
400 return;
401 }
402
403 ev.event = event;
404 memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t));
405
406 callback(&ev, user_data);
407}
408
409static int usbmuxd_listen_poll()
410{
411 int sfd;
412
413 sfd = connect_usbmuxd_socket();
414 if (sfd < 0) {
415 while (event_cb) {
416 if ((sfd = connect_usbmuxd_socket()) > 0) {
417 break;
418 }
419 sleep(1);
420 }
421 }
422
423 return sfd;
424}
425
426#ifdef HAVE_INOTIFY
427static int use_inotify = 1;
428
429static int usbmuxd_listen_inotify()
430{
431 int inot_fd;
432 int watch_d;
433 int sfd;
434
435 if (!use_inotify) {
436 return -2;
437 }
438
439 sfd = connect_usbmuxd_socket();
440 if (sfd >= 0)
441 return sfd;
442
443 sfd = -1;
444 inot_fd = inotify_init ();
445 if (inot_fd < 0) {
446 DEBUG(1, "%s: Failed to setup inotify\n", __func__);
447 return -2;
448 }
449
450 /* inotify is setup, listen for events that concern us */
451 watch_d = inotify_add_watch (inot_fd, USBMUXD_DIRNAME, IN_CREATE);
452 if (watch_d < 0) {
453 DEBUG(1, "%s: Failed to setup watch descriptor for socket dir\n", __func__);
454 close (inot_fd);
455 return -2;
456 }
457
458 while (1) {
459 ssize_t len, i;
460 char buff[EVENT_BUF_LEN] = {0};
461
462 i = 0;
463 len = read (inot_fd, buff, EVENT_BUF_LEN -1);
464 if (len < 0)
465 goto end;
466 while (i < len) {
467 struct inotify_event *pevent = (struct inotify_event *) & buff[i];
468
469 /* check that it's ours */
470 if (pevent->mask & IN_CREATE &&
471 pevent->len &&
472 pevent->name != NULL &&
473 strcmp(pevent->name, USBMUXD_SOCKET_NAME) == 0) {
474 sfd = connect_usbmuxd_socket ();
475 goto end;
476 }
477 i += EVENT_SIZE + pevent->len;
478 }
479 }
480
481end:
482 inotify_rm_watch(inot_fd, watch_d);
483 close(inot_fd);
484
485 return sfd;
486}
487#endif /* HAVE_INOTIFY */
488
489/**
490 * Tries to connect to usbmuxd and wait if it is not running.
491 */
492static int usbmuxd_listen()
493{
494 int sfd;
495 uint32_t res = -1;
496
497#ifdef HAVE_PLIST
498retry:
499#endif
500
501#ifdef HAVE_INOTIFY
502 sfd = usbmuxd_listen_inotify();
503 if (sfd == -2)
504 sfd = usbmuxd_listen_poll();
505#else
506 sfd = usbmuxd_listen_poll();
507#endif
508
509 if (sfd < 0) {
510 DEBUG(1, "%s: ERROR: usbmuxd was supposed to be running here...\n", __func__);
511 return sfd;
512 }
513
514 use_tag++;
515 LOCK;
516 if (send_listen_packet(sfd, use_tag) <= 0) {
517 UNLOCK;
518 DEBUG(1, "%s: ERROR: could not send listen packet\n", __func__);
519 close_socket(sfd);
520 return -1;
521 }
522 if (usbmuxd_get_result(sfd, use_tag, &res) && (res != 0)) {
523 UNLOCK;
524 close_socket(sfd);
525#ifdef HAVE_PLIST
526 if ((res == RESULT_BADVERSION) && (proto_version != 1)) {
527 proto_version = 1;
528 goto retry;
529 }
530#endif
531 DEBUG(1, "%s: ERROR: did not get OK but %d\n", __func__, res);
532 return -1;
533 }
534 UNLOCK;
535
536 return sfd;
537}
538
539/**
540 * Waits for an event to occur, i.e. a packet coming from usbmuxd.
541 * Calls generate_event to pass the event via callback to the client program.
542 */
543int get_next_event(int sfd, usbmuxd_event_cb_t callback, void *user_data)
544{
545 struct usbmuxd_header hdr;
546 void *payload = NULL;
547
548 /* block until we receive something */
549 if (receive_packet(sfd, &hdr, &payload, 0) < 0) {
550 // when then usbmuxd connection fails,
551 // generate remove events for every device that
552 // is still present so applications know about it
553 FOREACH(usbmuxd_device_info_t *dev, &devices) {
554 generate_event(callback, dev, UE_DEVICE_REMOVE, user_data);
555 collection_remove(&devices, dev);
556 free(dev);
557 } ENDFOREACH
558 return -EIO;
559 }
560
561 if ((hdr.length > sizeof(hdr)) && !payload) {
562 DEBUG(1, "%s: Invalid packet received, payload is missing!\n", __func__);
563 return -EBADMSG;
564 }
565
566 if (hdr.message == MESSAGE_DEVICE_ADD) {
567 struct usbmuxd_device_record *dev = payload;
568 usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t));
569 if (!devinfo) {
570 DEBUG(1, "%s: Out of memory!\n", __func__);
571 free(payload);
572 return -1;
573 }
574
575 devinfo->handle = dev->device_id;
576 devinfo->product_id = dev->product_id;
577 memset(devinfo->udid, '\0', sizeof(devinfo->udid));
578 memcpy(devinfo->udid, dev->serial_number, sizeof(devinfo->udid));
579
580 if (strcasecmp(devinfo->udid, "ffffffffffffffffffffffffffffffffffffffff") == 0) {
581 sprintf(devinfo->udid + 32, "%08x", devinfo->handle);
582 }
583
584 collection_add(&devices, devinfo);
585 generate_event(callback, devinfo, UE_DEVICE_ADD, user_data);
586 } else if (hdr.message == MESSAGE_DEVICE_REMOVE) {
587 uint32_t handle;
588 usbmuxd_device_info_t *devinfo;
589
590 memcpy(&handle, payload, sizeof(uint32_t));
591
592 devinfo = devices_find(handle);
593 if (!devinfo) {
594 DEBUG(1, "%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);
595 } else {
596 generate_event(callback, devinfo, UE_DEVICE_REMOVE, user_data);
597 collection_remove(&devices, devinfo);
598 free(devinfo);
599 }
600 } else if (hdr.length > 0) {
601 DEBUG(1, "%s: Unexpected message type %d length %d received!\n", __func__, hdr.message, hdr.length);
602 }
603 if (payload) {
604 free(payload);
605 }
606 return 0;
607}
608
609static void device_monitor_cleanup(void* data)
610{
611 FOREACH(usbmuxd_device_info_t *dev, &devices) {
612 collection_remove(&devices, dev);
613 free(dev);
614 } ENDFOREACH
615 collection_free(&devices);
616
617 close_socket(listenfd);
618 listenfd = -1;
619}
620
621/**
622 * Device Monitor thread function.
623 *
624 * This function sets up a connection to usbmuxd
625 */
626static void *device_monitor(void *data)
627{
628 collection_init(&devices);
629
630#ifndef WIN32
631 pthread_cleanup_push(device_monitor_cleanup, NULL);
632#endif
633 while (event_cb) {
634
635 listenfd = usbmuxd_listen();
636 if (listenfd < 0) {
637 continue;
638 }
639
640 while (event_cb) {
641 int res = get_next_event(listenfd, event_cb, data);
642 if (res < 0) {
643 break;
644 }
645 }
646 }
647
648#ifndef WIN32
649 pthread_cleanup_pop(1);
650#else
651 device_monitor_cleanup(NULL);
652#endif
653 return NULL;
654}
655
656int usbmuxd_subscribe(usbmuxd_event_cb_t callback, void *user_data)
657{
658 int res;
659
660 if (!callback) {
661 return -EINVAL;
662 }
663 event_cb = callback;
664
665#ifdef WIN32
666 res = 0;
667 devmon = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)device_monitor, user_data, 0, NULL);
668 if (devmon == NULL) {
669 res = GetLastError();
670 }
671#else
672 res = pthread_create(&devmon, NULL, device_monitor, user_data);
673#endif
674 if (res != 0) {
675 DEBUG(1, "%s: ERROR: Could not start device watcher thread!\n", __func__);
676 return res;
677 }
678 return 0;
679}
680
681int usbmuxd_unsubscribe()
682{
683 event_cb = NULL;
684
685 shutdown_socket(listenfd, SHUT_RDWR);
686
687#ifdef WIN32
688 if (devmon != NULL) {
689 WaitForSingleObject(devmon, INFINITE);
690 }
691#else
692 if (pthread_kill(devmon, 0) == 0) {
693 pthread_cancel(devmon);
694 pthread_join(devmon, NULL);
695 }
696#endif
697
698 return 0;
699}
700
701int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list)
702{
703 int sfd;
704 int listen_success = 0;
705 uint32_t res;
706 struct collection tmpdevs;
707 usbmuxd_device_info_t *newlist = NULL;
708 struct usbmuxd_header hdr;
709 struct usbmuxd_device_record *dev;
710 int dev_cnt = 0;
711 void *payload = NULL;
712
713 *device_list = NULL;
714
715#ifdef HAVE_PLIST
716retry:
717#endif
718 sfd = connect_usbmuxd_socket();
719 if (sfd < 0) {
720 DEBUG(1, "%s: error opening socket!\n", __func__);
721 return sfd;
722 }
723
724 use_tag++;
725 LOCK;
726 if (send_listen_packet(sfd, use_tag) > 0) {
727 res = -1;
728 // get response
729 if (usbmuxd_get_result(sfd, use_tag, &res) && (res == 0)) {
730 listen_success = 1;
731 } else {
732 UNLOCK;
733 close_socket(sfd);
734#ifdef HAVE_PLIST
735 if ((res == RESULT_BADVERSION) && (proto_version != 1)) {
736 proto_version = 1;
737 goto retry;
738 }
739#endif
740 DEBUG(1, "%s: Did not get response to scan request (with result=0)...\n", __func__);
741 return res;
742 }
743 }
744
745 if (!listen_success) {
746 UNLOCK;
747 DEBUG(1, "%s: Could not send listen request!\n", __func__);
748 return -1;
749 }
750
751 collection_init(&tmpdevs);
752
753 // receive device list
754 while (1) {
755 if (receive_packet(sfd, &hdr, &payload, 1000) > 0) {
756 if (hdr.message == MESSAGE_DEVICE_ADD) {
757 dev = payload;
758 usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t));
759 if (!devinfo) {
760 UNLOCK;
761 DEBUG(1, "%s: Out of memory!\n", __func__);
762 free(payload);
763 return -1;
764 }
765
766 devinfo->handle = dev->device_id;
767 devinfo->product_id = dev->product_id;
768 memset(devinfo->udid, '\0', sizeof(devinfo->udid));
769 memcpy(devinfo->udid, dev->serial_number, sizeof(devinfo->udid));
770
771 if (strcasecmp(devinfo->udid, "ffffffffffffffffffffffffffffffffffffffff") == 0) {
772 sprintf(devinfo->udid + 32, "%08x", devinfo->handle);
773 }
774
775 collection_add(&tmpdevs, devinfo);
776
777 } else if (hdr.message == MESSAGE_DEVICE_REMOVE) {
778 uint32_t handle;
779 usbmuxd_device_info_t *devinfo = NULL;
780
781 memcpy(&handle, payload, sizeof(uint32_t));
782
783 FOREACH(usbmuxd_device_info_t *di, &tmpdevs) {
784 if (di && di->handle == handle) {
785 devinfo = di;
786 break;
787 }
788 } ENDFOREACH
789 if (devinfo) {
790 collection_remove(&tmpdevs, devinfo);
791 free(devinfo);
792 }
793 } else {
794 DEBUG(1, "%s: Unexpected message %d\n", __func__, hdr.message);
795 }
796 if (payload)
797 free(payload);
798 } else {
799 // we _should_ have all of them now.
800 // or perhaps an error occured.
801 break;
802 }
803 }
804 UNLOCK;
805
806 // explicitly close connection
807 close_socket(sfd);
808
809 // create copy of device info entries from collection
810 newlist = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t) * (collection_count(&tmpdevs) + 1));
811 dev_cnt = 0;
812 FOREACH(usbmuxd_device_info_t *di, &tmpdevs) {
813 if (di) {
814 memcpy(&newlist[dev_cnt], di, sizeof(usbmuxd_device_info_t));
815 free(di);
816 dev_cnt++;
817 }
818 } ENDFOREACH
819 collection_free(&tmpdevs);
820
821 memset(&newlist[dev_cnt], 0, sizeof(usbmuxd_device_info_t));
822 *device_list = newlist;
823
824 return dev_cnt;
825}
826
827int usbmuxd_device_list_free(usbmuxd_device_info_t **device_list)
828{
829 if (device_list) {
830 free(*device_list);
831 }
832 return 0;
833}
834
835int usbmuxd_get_device_by_udid(const char *udid, usbmuxd_device_info_t *device)
836{
837 usbmuxd_device_info_t *dev_list = NULL;
838
839 if (!device) {
840 return -EINVAL;
841 }
842 if (usbmuxd_get_device_list(&dev_list) < 0) {
843 return -ENODEV;
844 }
845
846 int i;
847 int result = 0;
848 for (i = 0; dev_list[i].handle > 0; i++) {
849 if (!udid) {
850 device->handle = dev_list[i].handle;
851 device->product_id = dev_list[i].product_id;
852 strcpy(device->udid, dev_list[i].udid);
853 result = 1;
854 break;
855 }
856 if (!strcmp(udid, dev_list[i].udid)) {
857 device->handle = dev_list[i].handle;
858 device->product_id = dev_list[i].product_id;
859 strcpy(device->udid, dev_list[i].udid);
860 result = 1;
861 break;
862 }
863 }
864
865 free(dev_list);
866
867 return result;
868}
869
870int usbmuxd_connect(const int handle, const unsigned short port)
871{
872 int sfd;
873 int connected = 0;
874 uint32_t res = -1;
875
876#ifdef HAVE_PLIST
877retry:
878#endif
879 sfd = connect_usbmuxd_socket();
880 if (sfd < 0) {
881 DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n",
882 __func__, strerror(errno));
883 return sfd;
884 }
885
886 use_tag++;
887 if (send_connect_packet(sfd, use_tag, (uint32_t)handle, (uint16_t)port) <= 0) {
888 DEBUG(1, "%s: Error sending connect message!\n", __func__);
889 } else {
890 // read ACK
891 DEBUG(2, "%s: Reading connect result...\n", __func__);
892 if (usbmuxd_get_result(sfd, use_tag, &res)) {
893 if (res == 0) {
894 DEBUG(2, "%s: Connect success!\n", __func__);
895 connected = 1;
896 } else {
897#ifdef HAVE_PLIST
898 if ((res == RESULT_BADVERSION) && (proto_version == 0)) {
899 proto_version = 1;
900 close_socket(sfd);
901 goto retry;
902 }
903#endif
904 DEBUG(1, "%s: Connect failed, Error code=%d\n", __func__, res);
905 }
906 }
907 }
908
909 if (connected) {
910 return sfd;
911 }
912
913 close_socket(sfd);
914
915 return -1;
916}
917
918int usbmuxd_disconnect(int sfd)
919{
920 return close_socket(sfd);
921}
922
923int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes)
924{
925 int num_sent;
926
927 if (sfd < 0) {
928 return -EINVAL;
929 }
930
931 num_sent = send(sfd, (void*)data, len, 0);
932 if (num_sent < 0) {
933 *sent_bytes = 0;
934 DEBUG(1, "%s: Error %d when sending: %s\n", __func__, num_sent, strerror(errno));
935 return num_sent;
936 } else if ((uint32_t)num_sent < len) {
937 DEBUG(1, "%s: Warning: Did not send enough (only %d of %d)\n", __func__, num_sent, len);
938 }
939
940 *sent_bytes = num_sent;
941
942 return 0;
943}
944
945int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
946{
947 int num_recv = recv_buf_timeout(sfd, (void*)data, len, 0, timeout);
948 if (num_recv < 0) {
949 *recv_bytes = 0;
950 return num_recv;
951 }
952
953 *recv_bytes = num_recv;
954
955 return 0;
956}
957
958int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes)
959{
960 return usbmuxd_recv_timeout(sfd, data, len, recv_bytes, 5000);
961}
962
963void libusbmuxd_set_use_inotify(int set)
964{
965#ifdef HAVE_INOTIFY
966 use_inotify = set;
967#endif
968 return;
969}
970
971void libusbmuxd_set_debug_level(int level)
972{
973 libusbmuxd_debug = level;
974 sock_stuff_set_verbose(level);
975}