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