summaryrefslogtreecommitdiffstats
path: root/libusbmuxd
diff options
context:
space:
mode:
Diffstat (limited to 'libusbmuxd')
-rw-r--r--libusbmuxd/CMakeLists.txt29
-rw-r--r--libusbmuxd/libusbmuxd.c782
-rw-r--r--libusbmuxd/sock_stuff.c370
-rw-r--r--libusbmuxd/sock_stuff.h57
-rw-r--r--libusbmuxd/usbmuxd-proto.h97
-rw-r--r--libusbmuxd/usbmuxd.h181
6 files changed, 0 insertions, 1516 deletions
diff --git a/libusbmuxd/CMakeLists.txt b/libusbmuxd/CMakeLists.txt
deleted file mode 100644
index 81203d3..0000000
--- a/libusbmuxd/CMakeLists.txt
+++ /dev/null
@@ -1,29 +0,0 @@
1include_directories (${CMAKE_SOURCE_DIR}/common)
2find_package(Threads)
3
4add_library (libusbmuxd SHARED libusbmuxd.c sock_stuff.c ${CMAKE_SOURCE_DIR}/common/utils.c)
5find_library (PTHREAD pthread)
6
7if (HAVE_PLIST)
8 add_definitions("-DHAVE_PLIST")
9 message("-- libusbmuxd will be built with protocol version 1 support")
10endif()
11if(WIN32)
12 set(OPT_LIBS ${OPT_LIBS} ws2_32)
13endif()
14include_directories(${OPT_INCLUDES})
15target_link_libraries (libusbmuxd ${CMAKE_THREAD_LIBS_INIT} ${OPT_LIBS})
16
17# 'lib' is a UNIXism, the proper CMake target is usbmuxd
18# But we can't use that due to the conflict with the usbmuxd daemon,
19# so instead change the library output base name to usbmuxd here
20set_target_properties(libusbmuxd PROPERTIES OUTPUT_NAME usbmuxd)
21set_target_properties(libusbmuxd PROPERTIES VERSION ${LIBUSBMUXD_VERSION})
22set_target_properties(libusbmuxd PROPERTIES SOVERSION ${LIBUSBMUXD_SOVERSION})
23
24install(TARGETS libusbmuxd
25 RUNTIME DESTINATION bin
26 ARCHIVE DESTINATION lib${LIB_SUFFIX}
27 LIBRARY DESTINATION lib${LIB_SUFFIX}
28)
29install(FILES usbmuxd.h usbmuxd-proto.h DESTINATION include)
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
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#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
57static struct collection devices;
58static usbmuxd_event_cb_t event_cb = NULL;
59pthread_t devmon;
60static int listenfd = -1;
61
62static int use_tag = 0;
63static 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 */
69static 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 */
84static 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
93static 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 */
219static 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
259static 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
286static 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
316static 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 */
363static 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 */
382static int usbmuxd_listen()
383{
384 int sfd;
385 uint32_t res = -1;
386
387#ifdef HAVE_PLIST
388retry:
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 */
430int 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 */
495static 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
519int 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
536int 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
550int 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
562retry:
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
646int 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
654int 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
689int 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
696retry:
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
738int usbmuxd_disconnect(int sfd)
739{
740 return close_socket(sfd);
741}
742
743int 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
765int 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
778int 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
diff --git a/libusbmuxd/sock_stuff.c b/libusbmuxd/sock_stuff.c
deleted file mode 100644
index edc738e..0000000
--- a/libusbmuxd/sock_stuff.c
+++ /dev/null
@@ -1,370 +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 close_socket(int fd) {
325#ifdef WIN32
326 return closesocket(fd);
327#else
328 return close(fd);
329#endif
330}
331
332int recv_buf(int fd, void *data, size_t length)
333{
334 return recv_buf_timeout(fd, data, length, 0, RECV_TIMEOUT);
335}
336
337int peek_buf(int fd, void *data, size_t length)
338{
339 return recv_buf_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
340}
341
342int recv_buf_timeout(int fd, void *data, size_t length, int flags,
343 unsigned int timeout)
344{
345 int res;
346 int result;
347
348 // check if data is available
349 res = check_fd(fd, FDM_READ, timeout);
350 if (res <= 0) {
351 return res;
352 }
353 // if we get here, there _is_ data available
354 result = recv(fd, data, length, flags);
355 if (res > 0 && result == 0) {
356 // but this is an error condition
357 if (verbose >= 3)
358 fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
359 return -EAGAIN;
360 }
361 if (result < 0) {
362 return -errno;
363 }
364 return result;
365}
366
367int send_buf(int fd, void *data, size_t length)
368{
369 return send(fd, data, length, 0);
370}
diff --git a/libusbmuxd/sock_stuff.h b/libusbmuxd/sock_stuff.h
deleted file mode 100644
index eb9622c..0000000
--- a/libusbmuxd/sock_stuff.h
+++ /dev/null
@@ -1,57 +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#ifndef WIN32
37int create_unix_socket(const char *filename);
38int connect_unix_socket(const char *filename);
39#endif
40int create_socket(uint16_t port);
41#if defined(WIN32) || defined(__CYGWIN__)
42int connect_socket(const char *addr, uint16_t port);
43#endif
44int check_fd(int fd, fd_mode fdm, unsigned int timeout);
45
46int close_socket(int fd);
47
48int recv_buf(int fd, void *data, size_t size);
49int peek_buf(int fd, void *data, size_t size);
50int recv_buf_timeout(int fd, void *data, size_t size, int flags,
51 unsigned int timeout);
52
53int send_buf(int fd, void *data, size_t size);
54
55void sock_stuff_set_verbose(int level);
56
57#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 eabd216..0000000
--- a/libusbmuxd/usbmuxd.h
+++ /dev/null
@@ -1,181 +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 uuid[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 uuid.
108 *
109 * @param uuid A device uuid of the device to look for. If uuid 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_uuid(const char *uuid, 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#ifdef __cplusplus
178}
179#endif
180
181#endif /* __USBMUXD_H */