summaryrefslogtreecommitdiffstats
path: root/libusbmuxd
diff options
context:
space:
mode:
Diffstat (limited to 'libusbmuxd')
-rw-r--r--libusbmuxd/CMakeLists.txt45
-rw-r--r--libusbmuxd/libusbmuxd.c975
-rw-r--r--libusbmuxd/sock_stuff.c375
-rw-r--r--libusbmuxd/sock_stuff.h65
-rw-r--r--libusbmuxd/usbmuxd-proto.h97
-rw-r--r--libusbmuxd/usbmuxd.h191
6 files changed, 0 insertions, 1748 deletions
diff --git a/libusbmuxd/CMakeLists.txt b/libusbmuxd/CMakeLists.txt
deleted file mode 100644
index 737eb02..0000000
--- a/libusbmuxd/CMakeLists.txt
+++ /dev/null
@@ -1,45 +0,0 @@
1include_directories (${CMAKE_SOURCE_DIR}/common)
2find_package(Threads)
3
4option(WANT_INOTIFY "Build with inotify support" ON)
5if (WANT_INOTIFY)
6find_package(Inotify)
7if (INOTIFY_FOUND)
8 add_definitions("-DHAVE_INOTIFY")
9 message("-- libusbmuxd will be built with inotify support")
10endif()
11endif(WANT_INOTIFY)
12
13add_library (libusbmuxd SHARED libusbmuxd.c sock_stuff.c ${CMAKE_SOURCE_DIR}/common/utils.c)
14find_library (PTHREAD pthread)
15
16if (HAVE_PLIST)
17 add_definitions("-DHAVE_PLIST")
18 message("-- libusbmuxd will be built with protocol version 1 support")
19endif()
20if(WIN32)
21 set(OPT_LIBS ${OPT_LIBS} ws2_32)
22endif()
23include_directories(${OPT_INCLUDES})
24target_link_libraries (libusbmuxd ${CMAKE_THREAD_LIBS_INIT} ${OPT_LIBS})
25
26# 'lib' is a UNIXism, the proper CMake target is usbmuxd
27# But we can't use that due to the conflict with the usbmuxd daemon,
28# so instead change the library output base name to usbmuxd here
29set_target_properties(libusbmuxd PROPERTIES OUTPUT_NAME usbmuxd)
30set_target_properties(libusbmuxd PROPERTIES VERSION ${LIBUSBMUXD_VERSION})
31set_target_properties(libusbmuxd PROPERTIES SOVERSION ${LIBUSBMUXD_SOVERSION})
32
33if(APPLE)
34 set_target_properties(libusbmuxd PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}")
35endif()
36if(WIN32)
37 set_target_properties(libusbmuxd PROPERTIES PREFIX "lib" IMPORT_PREFIX "lib")
38endif()
39
40install(TARGETS libusbmuxd
41 RUNTIME DESTINATION bin
42 ARCHIVE DESTINATION lib${LIB_SUFFIX}
43 LIBRARY DESTINATION lib${LIB_SUFFIX}
44)
45install(FILES usbmuxd.h usbmuxd-proto.h DESTINATION include)
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}
diff --git a/libusbmuxd/sock_stuff.c b/libusbmuxd/sock_stuff.c
deleted file mode 100644
index 609c8ad..0000000
--- a/libusbmuxd/sock_stuff.c
+++ /dev/null
@@ -1,375 +0,0 @@
1/*
2 libusbmuxd - client library to talk to usbmuxd
3
4Copyright (C) 2009 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 <stdio.h>
25#include <stddef.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include <errno.h>
30#include <sys/time.h>
31#include <sys/stat.h>
32#ifdef WIN32
33#include <windows.h>
34#include <winsock2.h>
35static int wsa_init = 0;
36#else
37#include <sys/socket.h>
38#include <sys/un.h>
39#include <netinet/in.h>
40#include <netdb.h>
41#include <arpa/inet.h>
42#endif
43#include "sock_stuff.h"
44
45#define RECV_TIMEOUT 20000
46
47static int verbose = 0;
48
49void sock_stuff_set_verbose(int level)
50{
51 verbose = level;
52}
53
54#ifndef WIN32
55int create_unix_socket(const char *filename)
56{
57 struct sockaddr_un name;
58 int sock;
59 size_t size;
60
61 // remove if still present
62 unlink(filename);
63
64 /* Create the socket. */
65 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
66 if (sock < 0) {
67 perror("socket");
68 return -1;
69 }
70
71 /* Bind a name to the socket. */
72 name.sun_family = AF_LOCAL;
73 strncpy(name.sun_path, filename, sizeof(name.sun_path));
74 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
75
76 /* The size of the address is
77 the offset of the start of the filename,
78 plus its length,
79 plus one for the terminating null byte.
80 Alternatively you can just do:
81 size = SUN_LEN (&name);
82 */
83 size = (offsetof(struct sockaddr_un, sun_path)
84 + strlen(name.sun_path) + 1);
85
86 if (bind(sock, (struct sockaddr *) &name, size) < 0) {
87 perror("bind");
88 close_socket(sock);
89 return -1;
90 }
91
92 if (listen(sock, 10) < 0) {
93 perror("listen");
94 close_socket(sock);
95 return -1;
96 }
97
98 return sock;
99}
100
101int connect_unix_socket(const char *filename)
102{
103 struct sockaddr_un name;
104 int sfd = -1;
105 size_t size;
106 struct stat fst;
107
108 // check if socket file exists...
109 if (stat(filename, &fst) != 0) {
110 if (verbose >= 2)
111 fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename,
112 strerror(errno));
113 return -1;
114 }
115 // ... and if it is a unix domain socket
116 if (!S_ISSOCK(fst.st_mode)) {
117 if (verbose >= 2)
118 fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__,
119 filename);
120 return -1;
121 }
122 // make a new socket
123 if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
124 if (verbose >= 2)
125 fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
126 return -1;
127 }
128 // and connect to 'filename'
129 name.sun_family = AF_LOCAL;
130 strncpy(name.sun_path, filename, sizeof(name.sun_path));
131 name.sun_path[sizeof(name.sun_path) - 1] = 0;
132
133 size = (offsetof(struct sockaddr_un, sun_path)
134 + strlen(name.sun_path) + 1);
135
136 if (connect(sfd, (struct sockaddr *) &name, size) < 0) {
137 close_socket(sfd);
138 if (verbose >= 2)
139 fprintf(stderr, "%s: connect: %s\n", __func__,
140 strerror(errno));
141 return -1;
142 }
143
144 return sfd;
145}
146#endif
147
148int create_socket(uint16_t port)
149{
150 int sfd = -1;
151 int yes = 1;
152#ifdef WIN32
153 WSADATA wsa_data;
154 if (!wsa_init) {
155 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
156 fprintf(stderr, "WSAStartup failed!\n");
157 ExitProcess(-1);
158 }
159 wsa_init = 1;
160 }
161#endif
162 struct sockaddr_in saddr;
163
164 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
165 perror("socket()");
166 return -1;
167 }
168
169 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
170 perror("setsockopt()");
171 close_socket(sfd);
172 return -1;
173 }
174
175 memset((void *) &saddr, 0, sizeof(saddr));
176 saddr.sin_family = AF_INET;
177 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
178 saddr.sin_port = htons(port);
179
180 if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) {
181 perror("bind()");
182 close_socket(sfd);
183 return -1;
184 }
185
186 if (listen(sfd, 1) == -1) {
187 perror("listen()");
188 close_socket(sfd);
189 return -1;
190 }
191
192 return sfd;
193}
194
195#if defined(WIN32) || defined(__CYGWIN__)
196int connect_socket(const char *addr, uint16_t port)
197{
198 int sfd = -1;
199 int yes = 1;
200 struct hostent *hp;
201 struct sockaddr_in saddr;
202#ifdef WIN32
203 WSADATA wsa_data;
204 if (!wsa_init) {
205 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
206 fprintf(stderr, "WSAStartup failed!\n");
207 ExitProcess(-1);
208 }
209 wsa_init = 1;
210 }
211#endif
212
213 if (!addr) {
214 errno = EINVAL;
215 return -1;
216 }
217
218 if ((hp = gethostbyname(addr)) == NULL) {
219 if (verbose >= 2)
220 fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr);
221 return -1;
222 }
223
224 if (!hp->h_addr) {
225 if (verbose >= 2)
226 fprintf(stderr, "%s: gethostbyname returned NULL address!\n",
227 __func__);
228 return -1;
229 }
230
231 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
232 perror("socket()");
233 return -1;
234 }
235
236 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
237 perror("setsockopt()");
238 close_socket(sfd);
239 return -1;
240 }
241
242 memset((void *) &saddr, 0, sizeof(saddr));
243 saddr.sin_family = AF_INET;
244 saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr;
245 saddr.sin_port = htons(port);
246
247 if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
248 perror("connect");
249 close_socket(sfd);
250 return -2;
251 }
252
253 return sfd;
254}
255#endif /* WIN32 || __CYGWIN__ */
256
257int check_fd(int fd, fd_mode fdm, unsigned int timeout)
258{
259 fd_set fds;
260 int sret;
261 int eagain;
262 struct timeval to;
263 struct timeval *pto;
264
265 if (fd <= 0) {
266 if (verbose >= 2)
267 fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
268 return -1;
269 }
270
271 FD_ZERO(&fds);
272 FD_SET(fd, &fds);
273
274 if (timeout > 0) {
275 to.tv_sec = (time_t) (timeout / 1000);
276 to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
277 pto = &to;
278 } else {
279 pto = NULL;
280 }
281
282 sret = -1;
283
284 do {
285 eagain = 0;
286 switch (fdm) {
287 case FDM_READ:
288 sret = select(fd + 1, &fds, NULL, NULL, pto);
289 break;
290 case FDM_WRITE:
291 sret = select(fd + 1, NULL, &fds, NULL, pto);
292 break;
293 case FDM_EXCEPT:
294 sret = select(fd + 1, NULL, NULL, &fds, pto);
295 break;
296 default:
297 return -1;
298 }
299
300 if (sret < 0) {
301 switch (errno) {
302 case EINTR:
303 // interrupt signal in select
304 if (verbose >= 2)
305 fprintf(stderr, "%s: EINTR\n", __func__);
306 eagain = 1;
307 break;
308 case EAGAIN:
309 if (verbose >= 2)
310 fprintf(stderr, "%s: EAGAIN\n", __func__);
311 break;
312 default:
313 if (verbose >= 2)
314 fprintf(stderr, "%s: select failed: %s\n", __func__,
315 strerror(errno));
316 return -1;
317 }
318 }
319 } while (eagain);
320
321 return sret;
322}
323
324int shutdown_socket(int fd, int how)
325{
326 return shutdown(fd, how);
327}
328
329int close_socket(int fd) {
330#ifdef WIN32
331 return closesocket(fd);
332#else
333 return close(fd);
334#endif
335}
336
337int recv_buf(int fd, void *data, size_t length)
338{
339 return recv_buf_timeout(fd, data, length, 0, RECV_TIMEOUT);
340}
341
342int peek_buf(int fd, void *data, size_t length)
343{
344 return recv_buf_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
345}
346
347int recv_buf_timeout(int fd, void *data, size_t length, int flags,
348 unsigned int timeout)
349{
350 int res;
351 int result;
352
353 // check if data is available
354 res = check_fd(fd, FDM_READ, timeout);
355 if (res <= 0) {
356 return res;
357 }
358 // if we get here, there _is_ data available
359 result = recv(fd, data, length, flags);
360 if (res > 0 && result == 0) {
361 // but this is an error condition
362 if (verbose >= 3)
363 fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
364 return -EAGAIN;
365 }
366 if (result < 0) {
367 return -errno;
368 }
369 return result;
370}
371
372int send_buf(int fd, void *data, size_t length)
373{
374 return send(fd, data, length, 0);
375}
diff --git a/libusbmuxd/sock_stuff.h b/libusbmuxd/sock_stuff.h
deleted file mode 100644
index 5efcd27..0000000
--- a/libusbmuxd/sock_stuff.h
+++ /dev/null
@@ -1,65 +0,0 @@
1/*
2 libusbmuxd - client library to talk to usbmuxd
3
4Copyright (C) 2009 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#ifndef __SOCK_STUFF_H
25#define __SOCK_STUFF_H
26
27#include <stdint.h>
28
29enum fd_mode {
30 FDM_READ,
31 FDM_WRITE,
32 FDM_EXCEPT
33};
34typedef enum fd_mode fd_mode;
35
36#ifdef WIN32
37#include <winsock2.h>
38#define SHUT_RD SD_READ
39#define SHUT_WR SD_WRITE
40#define SHUT_RDWR SD_BOTH
41#endif
42
43#ifndef WIN32
44int create_unix_socket(const char *filename);
45int connect_unix_socket(const char *filename);
46#endif
47int create_socket(uint16_t port);
48#if defined(WIN32) || defined(__CYGWIN__)
49int connect_socket(const char *addr, uint16_t port);
50#endif
51int check_fd(int fd, fd_mode fdm, unsigned int timeout);
52
53int shutdown_socket(int fd, int how);
54int close_socket(int fd);
55
56int recv_buf(int fd, void *data, size_t size);
57int peek_buf(int fd, void *data, size_t size);
58int recv_buf_timeout(int fd, void *data, size_t size, int flags,
59 unsigned int timeout);
60
61int send_buf(int fd, void *data, size_t size);
62
63void sock_stuff_set_verbose(int level);
64
65#endif /* __SOCK_STUFF_H */
diff --git a/libusbmuxd/usbmuxd-proto.h b/libusbmuxd/usbmuxd-proto.h
deleted file mode 100644
index be9e709..0000000
--- a/libusbmuxd/usbmuxd-proto.h
+++ /dev/null
@@ -1,97 +0,0 @@
1/*
2 libusbmuxd - client library to talk to usbmuxd
3
4Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.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/* Protocol defintion for usbmuxd proxy protocol */
25#ifndef __USBMUXD_PROTO_H
26#define __USBMUXD_PROTO_H
27
28#include <stdint.h>
29#define USBMUXD_PROTOCOL_VERSION 0
30
31#if defined(WIN32) || defined(__CYGWIN__)
32#define USBMUXD_SOCKET_PORT 27015
33#else
34#define USBMUXD_SOCKET_FILE "/var/run/usbmuxd"
35#endif
36
37#ifdef __cplusplus
38extern "C" {
39#endif
40
41enum usbmuxd_result {
42 RESULT_OK = 0,
43 RESULT_BADCOMMAND = 1,
44 RESULT_BADDEV = 2,
45 RESULT_CONNREFUSED = 3,
46 // ???
47 // ???
48 RESULT_BADVERSION = 6,
49};
50
51enum usbmuxd_msgtype {
52 MESSAGE_RESULT = 1,
53 MESSAGE_CONNECT = 2,
54 MESSAGE_LISTEN = 3,
55 MESSAGE_DEVICE_ADD = 4,
56 MESSAGE_DEVICE_REMOVE = 5,
57 //???
58 //???
59 MESSAGE_PLIST = 8,
60};
61
62struct usbmuxd_header {
63 uint32_t length; // length of message, including header
64 uint32_t version; // protocol version
65 uint32_t message; // message type
66 uint32_t tag; // responses to this query will echo back this tag
67} __attribute__((__packed__));
68
69struct usbmuxd_result_msg {
70 struct usbmuxd_header header;
71 uint32_t result;
72} __attribute__((__packed__));
73
74struct usbmuxd_connect_request {
75 struct usbmuxd_header header;
76 uint32_t device_id;
77 uint16_t port; // TCP port number
78 uint16_t reserved; // set to zero
79} __attribute__((__packed__));
80
81struct usbmuxd_listen_request {
82 struct usbmuxd_header header;
83} __attribute__((__packed__));
84
85struct usbmuxd_device_record {
86 uint32_t device_id;
87 uint16_t product_id;
88 char serial_number[256];
89 uint16_t padding;
90 uint32_t location;
91} __attribute__((__packed__));
92
93#ifdef __cplusplus
94}
95#endif
96
97#endif /* __USBMUXD_PROTO_H */
diff --git a/libusbmuxd/usbmuxd.h b/libusbmuxd/usbmuxd.h
deleted file mode 100644
index 0f7b862..0000000
--- a/libusbmuxd/usbmuxd.h
+++ /dev/null
@@ -1,191 +0,0 @@
1/*
2 libusbmuxd - client library to talk to usbmuxd
3
4Copyright (C) 2009 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#ifndef __USBMUXD_H
25#define __USBMUXD_H
26#include <stdint.h>
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
32/**
33 * Device information structure holding data to identify the device.
34 * The relevant 'handle' should be passed to 'usbmuxd_connect()', to
35 * start a proxy connection. The value 'handle' should be considered
36 * opaque and no presumption made about the meaning of its value.
37 */
38typedef struct {
39 int handle;
40 int product_id;
41 char udid[41];
42} usbmuxd_device_info_t;
43
44/**
45 * event types for event callback function
46 */
47enum usbmuxd_event_type {
48 UE_DEVICE_ADD = 1,
49 UE_DEVICE_REMOVE
50};
51
52/**
53 * Event structure that will be passed to the callback function.
54 * 'event' will contains the type of the event, and 'device' will contains
55 * information about the device.
56 */
57typedef struct {
58 int event;
59 usbmuxd_device_info_t device;
60} usbmuxd_event_t;
61
62/**
63 * Callback function prototype.
64 */
65typedef void (*usbmuxd_event_cb_t) (const usbmuxd_event_t *event, void *user_data);
66
67/**
68 * Subscribe a callback function so that applications get to know about
69 * device add/remove events.
70 *
71 * @param callback A callback function that is executed when an event occurs.
72 *
73 * @return 0 on success or negative on error.
74 */
75int usbmuxd_subscribe(usbmuxd_event_cb_t callback, void *user_data);
76
77/**
78 * Unsubscribe callback.
79 *
80 * @return only 0 for now.
81 */
82int usbmuxd_unsubscribe();
83
84/**
85 * Contacts usbmuxd and retrieves a list of connected devices.
86 *
87 * @param device_list A pointer to an array of usbmuxd_device_info_t
88 * that will hold records of the connected devices. The last record
89 * is a null-terminated record with all fields set to 0/NULL.
90 * @note The user has to free the list returned.
91 *
92 * @return number of attached devices, zero on no devices, or negative
93 * if an error occured.
94 */
95int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list);
96
97/**
98 * Frees the device list returned by an usbmuxd_get_device_list call
99 *
100 * @param device_list A pointer to an array of usbmuxd_device_info_t to free.
101 *
102 * @return 0 on success, -1 on error.
103 */
104int usbmuxd_device_list_free(usbmuxd_device_info_t **device_list);
105
106/**
107 * Gets device information for the device specified by udid.
108 *
109 * @param udid A device UDID of the device to look for. If udid is NULL,
110 * This function will return the first device found.
111 * @param device Pointer to a previously allocated (or static)
112 * usbmuxd_device_info_t that will be filled with the device info.
113 *
114 * @return 0 if no matching device is connected, 1 if the device was found,
115 * or a negative value on error.
116 */
117int usbmuxd_get_device_by_udid(const char *udid, usbmuxd_device_info_t *device);
118
119/**
120 * Request proxy connect to
121 *
122 * @param handle returned by 'usbmuxd_scan()'
123 *
124 * @param tcp_port TCP port number on device, in range 0-65535.
125 * common values are 62078 for lockdown, and 22 for SSH.
126 *
127 * @return file descriptor socket of the connection, or -1 on error
128 */
129int usbmuxd_connect(const int handle, const unsigned short tcp_port);
130
131/**
132 * Disconnect. For now, this just closes the socket file descriptor.
133 *
134 * @param sfd socker file descriptor returned by usbmuxd_connect()
135 *
136 * @return 0 on success, -1 on error.
137 */
138int usbmuxd_disconnect(int sfd);
139
140/**
141 * Send data to the specified socket.
142 *
143 * @param sfd socket file descriptor returned by usbmuxd_connect()
144 * @param data buffer to send
145 * @param len size of buffer to send
146 * @param sent_bytes how many bytes sent
147 *
148 * @return 0 on success, a negative errno value otherwise.
149 */
150int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes);
151
152/**
153 * Receive data from the specified socket.
154 *
155 * @param sfd socket file descriptor returned by usbmuxd_connect()
156 * @param data buffer to put the data to
157 * @param len number of bytes to receive
158 * @param recv_bytes number of bytes received
159 * @param timeout how many milliseconds to wait for data
160 *
161 * @return 0 on success, a negative errno value otherwise.
162 */
163int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout);
164
165/**
166 * Receive data from the specified socket with a default timeout.
167 *
168 * @param sfd socket file descriptor returned by usbmuxd_connect()
169 * @param data buffer to put the data to
170 * @param len number of bytes to receive
171 * @param recv_bytes number of bytes received
172 *
173 * @return 0 on success, a negative errno value otherwise.
174 */
175int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes);
176
177/**
178 * Enable or disable the use of inotify extension. Enabled by default.
179 * Use 0 to disable and 1 to enable inotify support.
180 * This only has an effect on linux systems if inotify support has been built
181 * in. Otherwise and on all other platforms this function has no effect.
182 */
183void libusbmuxd_set_use_inotify(int set);
184
185void libusbmuxd_set_debug_level(int level);
186
187#ifdef __cplusplus
188}
189#endif
190
191#endif /* __USBMUXD_H */