1 /*
2  * libusbmuxd.c
3  *
4  * Copyright (C) 2009-2019 Nikias Bassen <nikias@gmx.li>
5  * Copyright (C) 2009-2014 Martin Szulecki <m.szulecki@libimobiledevice.org>
6  * Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the 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 GNU
16  * Lesser 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 library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <string.h>
31 
32 #ifdef WIN32
33   #define USBMUXD_API __declspec( dllexport )
34 #else
35   #ifdef HAVE_FVISIBILITY
36     #define USBMUXD_API __attribute__((visibility("default")))
37   #else
38     #define USBMUXD_API
39   #endif
40 #endif
41 
42 #ifndef EPROTO
43 #define EPROTO 134
44 #endif
45 #ifndef EBADMSG
46 #define EBADMSG 104
47 #endif
48 #ifndef ECONNREFUSED
49 #define ECONNREFUSED 107
50 #endif
51 
52 #include <unistd.h>
53 #include <signal.h>
54 
55 #ifdef WIN32
56 #include <winsock2.h>
57 #include <windows.h>
58 #ifndef HAVE_SLEEP
59 #define sleep(x) Sleep(x*1000)
60 #endif
61 #else
62 #include <sys/socket.h>
63 #include <arpa/inet.h>
64 #include <pthread.h>
65 #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME) && !defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME_ERRNO_H)
66 extern char *program_invocation_short_name;
67 #endif
68 #ifdef __APPLE__
69 extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize);
70 #include <sys/stat.h>
71 #endif
72 #endif
73 
74 #ifdef HAVE_INOTIFY
75 #include <sys/inotify.h>
76 #include <sys/select.h>
77 #define EVENT_SIZE  (sizeof (struct inotify_event))
78 #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
79 #define USBMUXD_DIRNAME "/var/run"
80 #define USBMUXD_SOCKET_NAME "usbmuxd"
81 static int use_inotify = 1;
82 #endif /* HAVE_INOTIFY */
83 
84 #ifndef HAVE_STPNCPY
stpncpy(char * dst,const char * src,size_t len)85 static char* stpncpy(char *dst, const char *src, size_t len)
86 {
87 	size_t n = strlen(src);
88 	if (n > len)
89 		n = len;
90 	return strncpy(dst, src, len) + n;
91 }
92 #endif
93 
94 #include <plist/plist.h>
95 #define PLIST_CLIENT_VERSION_STRING PACKAGE_STRING
96 #define PLIST_LIBUSBMUX_VERSION 3
97 
98 static char *bundle_id = NULL;
99 static char *prog_name = NULL;
100 
101 // usbmuxd public interface
102 #include "usbmuxd.h"
103 // usbmuxd protocol
104 #include "usbmuxd-proto.h"
105 // socket utility functions
106 #include "socket.h"
107 // misc utility functions
108 #include "collection.h"
109 // threads
110 #include "thread.h"
111 
112 static int libusbmuxd_debug = 0;
113 #ifndef PACKAGE
114 #define PACKAGE "libusbmuxd"
115 #endif
116 #define LIBUSBMUXD_DEBUG(level, format, ...) if (level <= libusbmuxd_debug) fprintf(stderr, ("[" PACKAGE "] " format), __VA_ARGS__); fflush(stderr);
117 #define LIBUSBMUXD_ERROR(format, ...) LIBUSBMUXD_DEBUG(0, format, __VA_ARGS__)
118 
119 static struct collection devices;
120 static THREAD_T devmon = THREAD_T_NULL;
121 static int listenfd = -1;
122 static int running = 0;
123 static int cancelling = 0;
124 
125 static volatile int use_tag = 0;
126 static volatile int proto_version = 1;
127 static volatile int try_list_devices = 1;
128 
129 struct usbmuxd_subscription_context {
130 	usbmuxd_event_cb_t callback;
131 	void *user_data;
132 };
133 
134 static struct usbmuxd_subscription_context *event_ctx = NULL;
135 
136 static struct collection listeners;
137 thread_once_t listener_init_once = THREAD_ONCE_INIT;
138 mutex_t listener_mutex;
139 
140 /**
141  * Finds a device info record by its handle.
142  * if the record is not found, NULL is returned.
143  */
devices_find(uint32_t handle)144 static usbmuxd_device_info_t *devices_find(uint32_t handle)
145 {
146 	FOREACH(usbmuxd_device_info_t *dev, &devices) {
147 		if (dev && dev->handle == handle) {
148 			return dev;
149 		}
150 	} ENDFOREACH
151 	return NULL;
152 }
153 
154 /**
155  * Creates a socket connection to usbmuxd.
156  * For Mac/Linux it is a unix domain socket,
157  * for Windows it is a tcp socket.
158  */
connect_usbmuxd_socket()159 static int connect_usbmuxd_socket()
160 {
161 	char *usbmuxd_socket_addr = getenv("USBMUXD_SOCKET_ADDRESS");
162 	if (usbmuxd_socket_addr) {
163 		if (strncmp(usbmuxd_socket_addr, "UNIX:", 5) == 0) {
164 #if defined(WIN32) || defined(__CYGWIN__)
165 			/* not supported, ignore */
166 #else
167 			if (usbmuxd_socket_addr[5] != '\0') {
168 				return socket_connect_unix(usbmuxd_socket_addr+5);
169 			}
170 #endif
171 		} else {
172 			uint16_t port = 0;
173 			char *p = strrchr(usbmuxd_socket_addr, ':');
174 			if (p) {
175 				char *endp = NULL;
176 				long l_port = strtol(p+1, &endp, 10);
177 				if (endp && *endp == '\0') {
178 					if (l_port > 0 && l_port < 65536) {
179 						port = (uint16_t)l_port;
180 					}
181 				}
182 			}
183 			if (p && port > 0) {
184 				char *connect_addr = NULL;
185 				if (usbmuxd_socket_addr[0] == '[') {
186 					connect_addr = strdup(usbmuxd_socket_addr+1);
187 					connect_addr[p - usbmuxd_socket_addr - 1] = '\0';
188 					p = strrchr(connect_addr, ']');
189 					if (p) {
190 						*p = '\0';
191 					}
192 				} else {
193 					connect_addr = strdup(usbmuxd_socket_addr);
194 					connect_addr[p - usbmuxd_socket_addr] = '\0';
195 				}
196 				if (connect_addr && *connect_addr != '\0') {
197 					int res = socket_connect(connect_addr, port);
198 #ifdef HAVE_INOTIFY
199 					use_inotify = 0;
200 #endif
201 					free(connect_addr);
202 					return res;
203 				}
204 				free(connect_addr);
205 			}
206 		}
207 	}
208 #if defined(WIN32) || defined(__CYGWIN__)
209 	return socket_connect("127.0.0.1", USBMUXD_SOCKET_PORT);
210 #else
211 	return socket_connect_unix(USBMUXD_SOCKET_FILE);
212 #endif
213 }
214 
sanitize_udid(usbmuxd_device_info_t * devinfo)215 static void sanitize_udid(usbmuxd_device_info_t *devinfo)
216 {
217 	if (!devinfo)
218 		return;
219 	if (strlen(devinfo->udid) == 24) {
220 		memmove(&devinfo->udid[9], &devinfo->udid[8], 17);
221 		devinfo->udid[8] = '-';
222 	}
223 	if (strcasecmp(devinfo->udid, "ffffffffffffffffffffffffffffffffffffffff") == 0) {
224 		sprintf(devinfo->udid + 32, "%08x", devinfo->handle);
225 	}
226 }
227 
device_info_from_plist(plist_t props)228 static usbmuxd_device_info_t *device_info_from_plist(plist_t props)
229 {
230 	usbmuxd_device_info_t* devinfo = NULL;
231 	plist_t n = NULL;
232 	uint64_t val = 0;
233 	char *strval = NULL;
234 
235 	devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t));
236 	if (!devinfo)
237 		return NULL;
238 	memset(devinfo, 0, sizeof(usbmuxd_device_info_t));
239 
240 	n = plist_dict_get_item(props, "DeviceID");
241 	if (n && plist_get_node_type(n) == PLIST_UINT) {
242 		plist_get_uint_val(n, &val);
243 		devinfo->handle = (uint32_t)val;
244 	}
245 
246 	n = plist_dict_get_item(props, "ProductID");
247 	if (n && plist_get_node_type(n) == PLIST_UINT) {
248 		plist_get_uint_val(n, &val);
249 		devinfo->product_id = (uint32_t)val;
250 	}
251 
252 	n = plist_dict_get_item(props, "SerialNumber");
253 	if (n && plist_get_node_type(n) == PLIST_STRING) {
254 		plist_get_string_val(n, &strval);
255 		if (strval) {
256 			char *t = stpncpy(devinfo->udid, strval, sizeof(devinfo->udid)-1);
257 			*t = '\0';
258 			sanitize_udid(devinfo);
259 			free(strval);
260 		}
261 	}
262 
263 	n = plist_dict_get_item(props, "ConnectionType");
264 	if (n && plist_get_node_type(n) == PLIST_STRING) {
265 		plist_get_string_val(n, &strval);
266 		if (strval) {
267 			if (strcmp(strval, "USB") == 0) {
268 				devinfo->conn_type = CONNECTION_TYPE_USB;
269 			} else if (strcmp(strval, "Network") == 0) {
270 				devinfo->conn_type = CONNECTION_TYPE_NETWORK;
271 				n = plist_dict_get_item(props, "NetworkAddress");
272 				if (n && plist_get_node_type(n) == PLIST_DATA) {
273 					char *netaddr = NULL;
274 					uint64_t addr_len = 0;
275 					plist_get_data_val(n, &netaddr, &addr_len);
276 					if (netaddr && addr_len > 0 && addr_len < sizeof(devinfo->conn_data)) {
277 						memcpy(devinfo->conn_data, netaddr, addr_len);
278 					}
279 					free(netaddr);
280 				}
281 			} else {
282 				LIBUSBMUXD_ERROR("%s: Unexpected ConnectionType '%s'\n", __func__, strval);
283 			}
284 			free(strval);
285 		}
286 	}
287 
288 	if (!devinfo->udid[0]) {
289 		LIBUSBMUXD_ERROR("%s: Failed to get SerialNumber (UDID)!\n", __func__);
290 		free(devinfo);
291 		return NULL;
292 	}
293 	if (!devinfo->conn_type) {
294 		LIBUSBMUXD_ERROR("%s: Failed to get ConnectionType!\n", __func__);
295 		free(devinfo);
296 		devinfo = NULL;
297 	} else if (devinfo->conn_type == CONNECTION_TYPE_NETWORK && !devinfo->conn_data[0]) {
298 		LIBUSBMUXD_ERROR("%s: Failed to get EscapedFullServiceName!\n", __func__);
299 		free(devinfo);
300 		devinfo = NULL;
301 	}
302 
303 	return devinfo;
304 }
305 
device_info_from_device_record(struct usbmuxd_device_record * dev)306 static usbmuxd_device_info_t *device_info_from_device_record(struct usbmuxd_device_record *dev)
307 {
308 	if (!dev) {
309 		return NULL;
310 	}
311 	usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t));
312 	if (!devinfo) {
313 		LIBUSBMUXD_ERROR("%s: Out of memory while allocating device info object\n", __func__);
314 		return NULL;
315 	}
316 
317 	devinfo->handle = dev->device_id;
318 	devinfo->product_id = dev->product_id;
319 	char *t = stpncpy(devinfo->udid, dev->serial_number, sizeof(devinfo->udid)-2);
320 	*t = '\0';
321 	sanitize_udid(devinfo);
322 
323 	return devinfo;
324 }
325 
receive_packet(int sfd,struct usbmuxd_header * header,void ** payload,int timeout)326 static int receive_packet(int sfd, struct usbmuxd_header *header, void **payload, int timeout)
327 {
328 	int recv_len;
329 	struct usbmuxd_header hdr;
330 	char *payload_loc = NULL;
331 
332 	header->length = 0;
333 	header->version = 0;
334 	header->message = 0;
335 	header->tag = 0;
336 
337 	recv_len = socket_receive_timeout(sfd, &hdr, sizeof(hdr), 0, timeout);
338 	if (recv_len < 0) {
339 		if (!cancelling) {
340 			LIBUSBMUXD_DEBUG(1, "%s: Error receiving packet: %s\n", __func__, strerror(-recv_len));
341 		}
342 		return recv_len;
343 	} else if ((size_t)recv_len < sizeof(hdr)) {
344 		LIBUSBMUXD_DEBUG(1, "%s: Received packet is too small, got %d bytes!\n", __func__, recv_len);
345 		return recv_len;
346 	}
347 
348 	uint32_t payload_size = hdr.length - sizeof(hdr);
349 	if (payload_size > 0) {
350 		payload_loc = (char*)malloc(payload_size);
351 		uint32_t rsize = 0;
352 		do {
353 			int res = socket_receive_timeout(sfd, payload_loc + rsize, payload_size - rsize, 0, 5000);
354 			if (res < 0) {
355 				break;
356 			}
357 			rsize += res;
358 		} while (rsize < payload_size);
359 		if (rsize != payload_size) {
360 			LIBUSBMUXD_DEBUG(1, "%s: Error receiving payload of size %d (bytes received: %d)\n", __func__, payload_size, rsize);
361 			free(payload_loc);
362 			return -EBADMSG;
363 		}
364 	}
365 
366 	if (hdr.message == MESSAGE_PLIST) {
367 		char *message = NULL;
368 		plist_t plist = NULL;
369 		plist_from_xml(payload_loc, payload_size, &plist);
370 		free(payload_loc);
371 
372 		if (!plist) {
373 			LIBUSBMUXD_DEBUG(1, "%s: Error getting plist from payload!\n", __func__);
374 			return -EBADMSG;
375 		}
376 
377 		plist_t node = plist_dict_get_item(plist, "MessageType");
378 		if (!node || plist_get_node_type(node) != PLIST_STRING) {
379 			*payload = plist;
380 			hdr.length = sizeof(hdr);
381 			memcpy(header, &hdr, sizeof(hdr));
382 			return hdr.length;
383 		}
384 
385 		plist_get_string_val(node, &message);
386 		if (message) {
387 			uint64_t val = 0;
388 			if (strcmp(message, "Result") == 0) {
389 				/* result message */
390 				uint32_t dwval = 0;
391 				plist_t n = plist_dict_get_item(plist, "Number");
392 				plist_get_uint_val(n, &val);
393 				*payload = malloc(sizeof(uint32_t));
394 				dwval = val;
395 				memcpy(*payload, &dwval, sizeof(dwval));
396 				hdr.length = sizeof(hdr) + sizeof(dwval);
397 				hdr.message = MESSAGE_RESULT;
398 			} else if (strcmp(message, "Attached") == 0) {
399 				/* device add message */
400 				usbmuxd_device_info_t *devinfo = NULL;
401 				plist_t props = plist_dict_get_item(plist, "Properties");
402 				if (!props) {
403 					LIBUSBMUXD_DEBUG(1, "%s: Could not get properties for message '%s' from plist!\n", __func__, message);
404 					free(message);
405 					plist_free(plist);
406 					return -EBADMSG;
407 				}
408 
409 				devinfo = device_info_from_plist(props);
410 				if (!devinfo) {
411 					LIBUSBMUXD_DEBUG(1, "%s: Could not create device info object from properties!\n", __func__);
412 					free(message);
413 					plist_free(plist);
414 					return -EBADMSG;
415 				}
416 				*payload = (void*)devinfo;
417 				hdr.length = sizeof(hdr) + sizeof(usbmuxd_device_info_t);
418 				hdr.message = MESSAGE_DEVICE_ADD;
419 			} else if (strcmp(message, "Detached") == 0) {
420 				/* device remove message */
421 				uint32_t dwval = 0;
422 				plist_t n = plist_dict_get_item(plist, "DeviceID");
423 				if (n) {
424 					plist_get_uint_val(n, &val);
425 					*payload = malloc(sizeof(uint32_t));
426 					dwval = val;
427 					memcpy(*payload, &dwval, sizeof(dwval));
428 					hdr.length = sizeof(hdr) + sizeof(dwval);
429 					hdr.message = MESSAGE_DEVICE_REMOVE;
430 				}
431 			} else if (strcmp(message, "Paired") == 0) {
432 				/* device pair message */
433 				uint32_t dwval = 0;
434 				plist_t n = plist_dict_get_item(plist, "DeviceID");
435 				if (n) {
436 					plist_get_uint_val(n, &val);
437 					*payload = malloc(sizeof(uint32_t));
438 					dwval = val;
439 					memcpy(*payload, &dwval, sizeof(dwval));
440 					hdr.length = sizeof(hdr) + sizeof(dwval);
441 					hdr.message = MESSAGE_DEVICE_PAIRED;
442 				}
443 			} else {
444 				char *xml = NULL;
445 				uint32_t len = 0;
446 				plist_to_xml(plist, &xml, &len);
447 				LIBUSBMUXD_DEBUG(1, "%s: Unexpected message '%s' in plist:\n%s\n", __func__, message, xml);
448 				free(xml);
449 				free(message);
450 				plist_free(plist);
451 				return -EBADMSG;
452 			}
453 			free(message);
454 		}
455 		plist_free(plist);
456 	} else if (hdr.message == MESSAGE_DEVICE_ADD) {
457 		usbmuxd_device_info_t *devinfo = device_info_from_device_record((struct usbmuxd_device_record*)payload_loc);
458 		free(payload_loc);
459 		*payload = devinfo;
460 	} else {
461 		*payload = payload_loc;
462 	}
463 
464 	memcpy(header, &hdr, sizeof(hdr));
465 
466 	return hdr.length;
467 }
468 
469 /**
470  * Retrieves the result code to a previously sent request.
471  */
usbmuxd_get_result(int sfd,uint32_t tag,uint32_t * result,void ** result_plist)472 static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result, void **result_plist)
473 {
474 	struct usbmuxd_header hdr;
475 	int recv_len;
476 	uint32_t *res = NULL;
477 
478 	if (!result) {
479 		return -EINVAL;
480 	}
481 	*result = -1;
482 	if (result_plist) {
483 		*result_plist = NULL;
484 	}
485 
486 	recv_len = receive_packet(sfd, &hdr, (void**)&res, 5000);
487 	if (recv_len < 0 || (size_t)recv_len < sizeof(hdr)) {
488 		free(res);
489 		return (recv_len < 0 ? recv_len : -EPROTO);
490 	}
491 
492 	if (hdr.message == MESSAGE_RESULT) {
493 		int ret = 0;
494 		if (hdr.tag != tag) {
495 			LIBUSBMUXD_DEBUG(1, "%s: WARNING: tag mismatch (%d != %d). Proceeding anyway.\n", __func__, hdr.tag, tag);
496 		}
497 		if (res) {
498 			memcpy(result, res, sizeof(uint32_t));
499 			ret = 1;
500 		}
501 		free(res);
502 		return ret;
503 	} else if (hdr.message == MESSAGE_PLIST) {
504 		if (!result_plist) {
505 			LIBUSBMUXD_DEBUG(1, "%s: MESSAGE_PLIST result but result_plist pointer is NULL!\n", __func__);
506 			return -1;
507 		}
508 		*result_plist = (plist_t)res;
509 		*result = RESULT_OK;
510 		return 1;
511 	}
512 
513 	LIBUSBMUXD_DEBUG(1, "%s: Unexpected message of type %d received!\n", __func__, hdr.message);
514 	free(res);
515 	return -EPROTO;
516 }
517 
send_packet(int sfd,uint32_t message,uint32_t tag,void * payload,uint32_t payload_size)518 static int send_packet(int sfd, uint32_t message, uint32_t tag, void *payload, uint32_t payload_size)
519 {
520 	struct usbmuxd_header header;
521 
522 	header.length = sizeof(struct usbmuxd_header);
523 	header.version = proto_version;
524 	header.message = message;
525 	header.tag = tag;
526 	if (payload && (payload_size > 0)) {
527 		header.length += payload_size;
528 	}
529 	int sent = socket_send(sfd, &header, sizeof(header));
530 	if (sent != sizeof(header)) {
531 		LIBUSBMUXD_DEBUG(1, "%s: ERROR: could not send packet header\n", __func__);
532 		return -1;
533 	}
534 	if (payload && (payload_size > 0)) {
535 		uint32_t ssize = 0;
536 		do {
537 			int res = socket_send(sfd, (char*)payload + ssize, payload_size - ssize);
538 			if (res < 0) {
539 				break;
540 			}
541 			ssize += res;
542 		} while (ssize < payload_size);
543 		sent += ssize;
544 	}
545 	if (sent != (int)header.length) {
546 		LIBUSBMUXD_DEBUG(1, "%s: ERROR: could not send whole packet (sent %d of %d)\n", __func__, sent, header.length);
547 		socket_close(sfd);
548 		return -1;
549 	}
550 	return sent;
551 }
552 
send_plist_packet(int sfd,uint32_t tag,plist_t message)553 static int send_plist_packet(int sfd, uint32_t tag, plist_t message)
554 {
555 	int res;
556 	char *payload = NULL;
557 	uint32_t payload_size = 0;
558 
559 	plist_to_xml(message, &payload, &payload_size);
560 	res = send_packet(sfd, MESSAGE_PLIST, tag, payload, payload_size);
561 	free(payload);
562 
563 	return res;
564 }
565 
get_bundle_id()566 static void get_bundle_id()
567 {
568 #if defined (__APPLE__)
569 	char CONTENTS_INFO_PLIST[] = "Contents/Info.plist";
570 	char* execpath = malloc(1024);
571 	uint32_t size = 1024;
572 	if (_NSGetExecutablePath(execpath, &size) != 0) {
573 		free(execpath);
574 		return;
575 	}
576 	// strip off executable name
577 	char *p = execpath + strlen(execpath) - 1;
578 	while (p > execpath && *p != '/') p--;
579 	if (*p == '/') *p = '\0';
580 	// now walk back trying to find "/Contents/MacOS", and strip it off
581 	int macos_found = 0;
582 	while (p > execpath) {
583 		p--;
584 		if (*p != '/') continue;
585 		if (strcmp(p, "/.") == 0) {
586 			*p = '\0';
587 		} else if (!macos_found && strcmp(p, "/MacOS") == 0) {
588 			*p = '\0';
589 			macos_found++;
590 		} else if (macos_found && strcmp(p, "/Contents") == 0) {
591 			*p = '\0';
592 			break;
593 		} else {
594 			break;
595 		}
596 	}
597 	// now just append "/Contents/Info.plist"
598 	size_t len = strlen(execpath) + sizeof(CONTENTS_INFO_PLIST) + 1;
599 	char *infopl = malloc(len);
600 	snprintf(infopl, len, "%s/%s", execpath, CONTENTS_INFO_PLIST);
601 	free(execpath);
602 	struct stat fst;
603 	fst.st_size = 0;
604 	if (stat(infopl, &fst) != 0) {
605 		free(infopl);
606 		return;
607 	}
608 	size_t fsize = fst.st_size;
609 	if (fsize < 8) {
610 		free(infopl);
611 		return;
612 	}
613 	FILE *f = fopen(infopl, "r");
614 	free(infopl);
615 	if (!f)
616 		return;
617 	char *buf = malloc(fsize);
618 	if (!buf)
619 		return;
620 	if (fread(buf, 1, fsize, f) == fsize) {
621 		plist_t pl = NULL;
622 		if (memcmp(buf, "bplist00", 8) == 0) {
623 			plist_from_bin(buf, fst.st_size, &pl);
624 		} else {
625 			plist_from_xml(buf, fst.st_size, &pl);
626 		}
627 		if (pl) {
628 			plist_t bid = plist_dict_get_item(pl, "CFBundleIdentifier");
629 			if (plist_get_node_type(bid) == PLIST_STRING) {
630 				plist_get_string_val(bid, &bundle_id);
631 			}
632 			plist_free(pl);
633 		}
634 	}
635 	free(buf);
636 	fclose(f);
637 #endif
638 }
639 
get_prog_name()640 static void get_prog_name()
641 {
642 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
643 	const char *pname = getprogname();
644 	if (pname) {
645 		prog_name = strdup(pname);
646 	}
647 #elif defined (WIN32)
648 	TCHAR *_pname = malloc((MAX_PATH+1) * sizeof(TCHAR));
649 	if (GetModuleFileName(NULL, _pname, MAX_PATH+1) > 0) {
650 		char* pname = NULL;
651 	#if defined(UNICODE) || defined(_UNICODE)
652 		char* __pname = NULL;
653 		int l = WideCharToMultiByte(CP_UTF8, 0, _pname, -1, NULL, 0, NULL, NULL);
654 		if (l > 0) {
655 			__pname = malloc(l);
656 			if (WideCharToMultiByte(CP_UTF8, 0, _pname, -1, __pname, l, NULL, NULL) > 0) {
657 				pname = __pname;
658 			}
659 		}
660 	#else
661 		pname = _pname;
662 	#endif
663 		if (pname) {
664 			char *p = pname+strlen(pname)-1;
665 			while (p > pname && *p != '\\' && *p != '/') p--;
666 			if (*p == '\\' || *p == '/') p++;
667 			prog_name = strdup(p);
668 		}
669 	#if defined(UNICODE) || defined(_UNICODE)
670 		free(__pname);
671 	#endif
672 	}
673 	free(_pname);
674 #elif defined (HAVE_PROGRAM_INVOCATION_SHORT_NAME)
675 	char *pname = program_invocation_short_name;
676 	if (pname) {
677 		prog_name = strdup(pname);
678 	}
679 #elif defined (__linux__)
680 	FILE *f = fopen("/proc/self/stat", "r");
681 	if (!f) {
682 		return;
683 	}
684 	char *tmpbuf = malloc(512);
685 	size_t r = fread(tmpbuf, 1, 512, f);
686 	if (r > 0) {
687 		char *p = tmpbuf;
688 		while ((p-tmpbuf < r) && (*p != '(') && (*p != '\0')) p++;
689 		if (*p == '(') {
690 			p++;
691 			char *pname = p;
692 			while ((p-tmpbuf < r) && (*p != ')') && (*p != '\0')) p++;
693 			if (*p == ')') {
694 				*p = '\0';
695 				prog_name = strdup(pname);
696 			}
697 		}
698 	}
699 	free(tmpbuf);
700 	fclose(f);
701 #else
702 	#warning FIXME: no method to determine program name
703 #endif
704 }
705 
create_plist_message(const char * message_type)706 static plist_t create_plist_message(const char* message_type)
707 {
708 	if (!bundle_id) {
709 		get_bundle_id();
710 	}
711 	if (!prog_name) {
712 		get_prog_name();
713 	}
714 	plist_t plist = plist_new_dict();
715 	if (bundle_id) {
716 		plist_dict_set_item(plist, "BundleID", plist_new_string(bundle_id));
717 	}
718 	plist_dict_set_item(plist, "ClientVersionString", plist_new_string(PLIST_CLIENT_VERSION_STRING));
719 	plist_dict_set_item(plist, "MessageType", plist_new_string(message_type));
720 	if (prog_name) {
721 		plist_dict_set_item(plist, "ProgName", plist_new_string(prog_name));
722 	}
723 	plist_dict_set_item(plist, "kLibUSBMuxVersion", plist_new_uint(PLIST_LIBUSBMUX_VERSION));
724 	return plist;
725 }
726 
send_listen_packet(int sfd,uint32_t tag)727 static int send_listen_packet(int sfd, uint32_t tag)
728 {
729 	int res = 0;
730 	if (proto_version == 1) {
731 		/* construct message plist */
732 		plist_t plist = create_plist_message("Listen");
733 
734 		res = send_plist_packet(sfd, tag, plist);
735 		plist_free(plist);
736 	} else {
737 		/* binary packet */
738 		res = send_packet(sfd, MESSAGE_LISTEN, tag, NULL, 0);
739 	}
740 	return res;
741 }
742 
send_connect_packet(int sfd,uint32_t tag,uint32_t device_id,uint16_t port)743 static int send_connect_packet(int sfd, uint32_t tag, uint32_t device_id, uint16_t port)
744 {
745 	int res = 0;
746 	if (proto_version == 1) {
747 		/* construct message plist */
748 		plist_t plist = create_plist_message("Connect");
749 		plist_dict_set_item(plist, "DeviceID", plist_new_uint(device_id));
750 		plist_dict_set_item(plist, "PortNumber", plist_new_uint(htons(port)));
751 
752 		res = send_plist_packet(sfd, tag, plist);
753 		plist_free(plist);
754 	} else {
755 		/* binary packet */
756 		struct {
757 			uint32_t device_id;
758 			uint16_t port;
759 			uint16_t reserved;
760 		} conninfo;
761 
762 		conninfo.device_id = device_id;
763 		conninfo.port = htons(port);
764 		conninfo.reserved = 0;
765 
766 		res = send_packet(sfd, MESSAGE_CONNECT, tag, &conninfo, sizeof(conninfo));
767 	}
768 	return res;
769 }
770 
send_list_devices_packet(int sfd,uint32_t tag)771 static int send_list_devices_packet(int sfd, uint32_t tag)
772 {
773 	int res = -1;
774 
775 	/* construct message plist */
776 	plist_t plist = create_plist_message("ListDevices");
777 
778 	res = send_plist_packet(sfd, tag, plist);
779 	plist_free(plist);
780 
781 	return res;
782 }
783 
send_read_buid_packet(int sfd,uint32_t tag)784 static int send_read_buid_packet(int sfd, uint32_t tag)
785 {
786 	int res = -1;
787 
788 	/* construct message plist */
789 	plist_t plist = create_plist_message("ReadBUID");
790 
791 	res = send_plist_packet(sfd, tag, plist);
792 	plist_free(plist);
793 
794 	return res;
795 }
796 
send_pair_record_packet(int sfd,uint32_t tag,const char * msgtype,const char * pair_record_id,uint32_t device_id,plist_t data)797 static int send_pair_record_packet(int sfd, uint32_t tag, const char* msgtype, const char* pair_record_id, uint32_t device_id, plist_t data)
798 {
799 	int res = -1;
800 
801 	/* construct message plist */
802 	plist_t plist = create_plist_message(msgtype);
803 	plist_dict_set_item(plist, "PairRecordID", plist_new_string(pair_record_id));
804 	if (data) {
805 		plist_dict_set_item(plist, "PairRecordData", plist_copy(data));
806 	}
807 	if (device_id > 0) {
808 		plist_dict_set_item(plist, "DeviceID", plist_new_uint(device_id));
809 	}
810 
811 	res = send_plist_packet(sfd, tag, plist);
812 	plist_free(plist);
813 
814 	return res;
815 }
816 
817 /**
818  * Generates an event, i.e. calls the callback function.
819  * A reference to a populated usbmuxd_event_t with information about the event
820  * and the corresponding device will be passed to the callback function.
821  */
generate_event(const usbmuxd_device_info_t * dev,enum usbmuxd_event_type event)822 static void generate_event(const usbmuxd_device_info_t *dev, enum usbmuxd_event_type event)
823 {
824 	usbmuxd_event_t ev;
825 
826 	if (!dev) {
827 		return;
828 	}
829 
830 	ev.event = event;
831 	memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t));
832 
833 	mutex_lock(&listener_mutex);
834 	FOREACH(struct usbmuxd_subscription_context* context, &listeners) {
835 		context->callback(&ev, context->user_data);
836 	} ENDFOREACH
837 	mutex_unlock(&listener_mutex);
838 }
839 
usbmuxd_listen_poll()840 static int usbmuxd_listen_poll()
841 {
842 	int sfd;
843 
844 	sfd = connect_usbmuxd_socket();
845 	if (sfd < 0) {
846 		while (1) {
847 			mutex_lock(&listener_mutex);
848 			int num = collection_count(&listeners);
849 			mutex_unlock(&listener_mutex);
850 			if (num <= 0) {
851 				break;
852 			}
853 			if ((sfd = connect_usbmuxd_socket()) >= 0) {
854 				break;
855 			}
856 			sleep(1);
857 		}
858 	}
859 
860 	return sfd;
861 }
862 
863 #ifdef HAVE_INOTIFY
864 #ifndef HAVE_PSELECT
pselect(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,const struct timespec * timeout,const sigset_t * sigmask)865 static int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask)
866 {
867 	int ready;
868 	struct timeval tv;
869 	struct timeval *p_timeout;
870 	sigset_t origmask;
871 
872 	if (timeout) {
873 		tv.tv_sec = timeout->tv_sec;
874 		tv.tv_usec = timeout->tv_nsec / 1000;
875 		p_timeout = &tv;
876 	} else {
877 		p_timeout = NULL;
878 	}
879 
880 	pthread_sigmask(SIG_SETMASK, sigmask, &origmask);
881 	ready = select(nfds, readfds, writefds, exceptfds, p_timeout);
882 	pthread_sigmask(SIG_SETMASK, &origmask, NULL);
883 
884 	return ready;
885 }
886 #endif
887 
usbmuxd_listen_inotify()888 static int usbmuxd_listen_inotify()
889 {
890 	int inot_fd;
891 	int watch_d;
892 	int sfd;
893 
894 	if (!use_inotify) {
895 		return -2;
896 	}
897 
898 	sfd = connect_usbmuxd_socket();
899 	if (sfd >= 0)
900 		return sfd;
901 
902 	sfd = -1;
903 	inot_fd = inotify_init ();
904 	if (inot_fd < 0) {
905 		LIBUSBMUXD_DEBUG(1, "%s: Failed to setup inotify\n", __func__);
906 		return -2;
907 	}
908 
909 	/* inotify is setup, listen for events that concern us */
910 	watch_d = inotify_add_watch (inot_fd, USBMUXD_DIRNAME, IN_CREATE);
911 	if (watch_d < 0) {
912 		LIBUSBMUXD_DEBUG(1, "%s: Failed to setup watch descriptor for socket dir\n", __func__);
913 		close (inot_fd);
914 		return -2;
915 	}
916 
917 	while (1) {
918 		fd_set rfds;
919 		struct timespec tv = {1, 0};
920 
921 		FD_ZERO(&rfds);
922 		FD_SET(inot_fd, &rfds);
923 		int r = pselect(inot_fd+1, &rfds, NULL, NULL, &tv, NULL);
924 		if (r < 0) {
925 			break;
926 		} else if (r == 0) {
927 			continue;
928 		}
929 
930 		ssize_t len, i;
931 		char buff[EVENT_BUF_LEN] = {0};
932 
933 		i = 0;
934 		len = read (inot_fd, buff, EVENT_BUF_LEN -1);
935 		if (len < 0)
936 			goto end;
937 		while (i < len) {
938 			struct inotify_event *pevent = (struct inotify_event *) & buff[i];
939 
940 			/* check that it's ours */
941 			if (pevent->mask & IN_CREATE &&
942 				pevent->len &&
943 				pevent->name[0] != 0 &&
944 				strcmp(pevent->name, USBMUXD_SOCKET_NAME) == 0) {
945 				/* retry if usbmuxd isn't ready yet */
946 				int retry = 10;
947 				while (--retry >= 0) {
948 					if ((sfd = connect_usbmuxd_socket ()) >= 0) {
949 						break;
950 					}
951 					sleep(1);
952 				}
953 				goto end;
954 			}
955 			i += EVENT_SIZE + pevent->len;
956 		}
957 	}
958 
959 end:
960 	inotify_rm_watch(inot_fd, watch_d);
961 	close(inot_fd);
962 
963 	return sfd;
964 }
965 #endif /* HAVE_INOTIFY */
966 
967 /**
968  * Tries to connect to usbmuxd and wait if it is not running.
969  */
usbmuxd_listen()970 static int usbmuxd_listen()
971 {
972 	int sfd;
973 	uint32_t res = -1;
974 	int tag;
975 
976 retry:
977 
978 #ifdef HAVE_INOTIFY
979 	sfd = usbmuxd_listen_inotify();
980 	if (sfd == -2)
981 		sfd = usbmuxd_listen_poll();
982 #else
983 	sfd = usbmuxd_listen_poll();
984 #endif
985 
986 	if (sfd < 0) {
987 		if (!cancelling) {
988 			LIBUSBMUXD_DEBUG(1, "%s: ERROR: usbmuxd was supposed to be running here...\n", __func__);
989 		}
990 		return sfd;
991 	}
992 
993 	tag = ++use_tag;
994 	if (send_listen_packet(sfd, tag) <= 0) {
995 		LIBUSBMUXD_DEBUG(1, "%s: ERROR: could not send listen packet\n", __func__);
996 		socket_close(sfd);
997 		return -1;
998 	}
999 	if ((usbmuxd_get_result(sfd, tag, &res, NULL) == 1) && (res != 0)) {
1000 		socket_close(sfd);
1001 		if ((res == RESULT_BADVERSION) && (proto_version == 1)) {
1002 			proto_version = 0;
1003 			goto retry;
1004 		}
1005 		LIBUSBMUXD_DEBUG(1, "%s: ERROR: did not get OK but %d\n", __func__, res);
1006 		return -1;
1007 	}
1008 	return sfd;
1009 }
1010 
1011 /**
1012  * Waits for an event to occur, i.e. a packet coming from usbmuxd.
1013  * Calls generate_event to pass the event via callback to the client program.
1014  */
get_next_event(int sfd)1015 static int get_next_event(int sfd)
1016 {
1017 	struct usbmuxd_header hdr;
1018 	void *payload = NULL;
1019 
1020 	/* block until we receive something */
1021 	if (receive_packet(sfd, &hdr, &payload, 0) < 0) {
1022 		if (!cancelling) {
1023 			LIBUSBMUXD_DEBUG(1, "%s: Error in usbmuxd connection, disconnecting all devices!\n", __func__);
1024 		}
1025 		// when then usbmuxd connection fails,
1026 		// generate remove events for every device that
1027 		// is still present so applications know about it
1028 		FOREACH(usbmuxd_device_info_t *dev, &devices) {
1029 			generate_event(dev, UE_DEVICE_REMOVE);
1030 			collection_remove(&devices, dev);
1031 			free(dev);
1032 		} ENDFOREACH
1033 		return -EIO;
1034 	}
1035 
1036 	if ((hdr.length > sizeof(hdr)) && !payload) {
1037 		LIBUSBMUXD_DEBUG(1, "%s: Invalid packet received, payload is missing!\n", __func__);
1038 		return -EBADMSG;
1039 	}
1040 
1041 	if (hdr.message == MESSAGE_DEVICE_ADD) {
1042 		usbmuxd_device_info_t *devinfo = (usbmuxd_device_info_t*)payload;
1043 		collection_add(&devices, devinfo);
1044 		generate_event(devinfo, UE_DEVICE_ADD);
1045 		payload = NULL;
1046 	} else if (hdr.message == MESSAGE_DEVICE_REMOVE) {
1047 		uint32_t handle;
1048 		usbmuxd_device_info_t *devinfo;
1049 
1050 		memcpy(&handle, payload, sizeof(uint32_t));
1051 
1052 		devinfo = devices_find(handle);
1053 		if (!devinfo) {
1054 			LIBUSBMUXD_DEBUG(1, "%s: WARNING: got device remove message for handle %d, but couldn't find the corresponding handle in the device list. This event will be ignored.\n", __func__, handle);
1055 		} else {
1056 			generate_event(devinfo, UE_DEVICE_REMOVE);
1057 			collection_remove(&devices, devinfo);
1058 			free(devinfo);
1059 		}
1060 	} else if (hdr.message == MESSAGE_DEVICE_PAIRED) {
1061 		uint32_t handle;
1062 		usbmuxd_device_info_t *devinfo;
1063 
1064 		memcpy(&handle, payload, sizeof(uint32_t));
1065 
1066 		devinfo = devices_find(handle);
1067 		if (!devinfo) {
1068 			LIBUSBMUXD_DEBUG(1, "%s: WARNING: got paired message for device handle %d, but couldn't find the corresponding handle in the device list. This event will be ignored.\n", __func__, handle);
1069 		} else {
1070 			generate_event(devinfo, UE_DEVICE_PAIRED);
1071 		}
1072 	} else if (hdr.length > 0) {
1073 		LIBUSBMUXD_DEBUG(1, "%s: Unexpected message type %d length %d received!\n", __func__, hdr.message, hdr.length);
1074 	}
1075 	free(payload);
1076 	return 0;
1077 }
1078 
device_monitor_cleanup(void * data)1079 static void device_monitor_cleanup(void* data)
1080 {
1081 	FOREACH(usbmuxd_device_info_t *dev, &devices) {
1082 		collection_remove(&devices, dev);
1083 		free(dev);
1084 	} ENDFOREACH
1085 	collection_free(&devices);
1086 
1087 	socket_close(listenfd);
1088 	listenfd = -1;
1089 }
1090 
1091 /**
1092  * Device Monitor thread function.
1093  *
1094  * This function sets up a connection to usbmuxd
1095  */
device_monitor(void * data)1096 static void *device_monitor(void *data)
1097 {
1098 	running = 1;
1099 	collection_init(&devices);
1100 	cancelling = 0;
1101 
1102 #ifdef HAVE_THREAD_CLEANUP
1103 	thread_cleanup_push(device_monitor_cleanup, NULL);
1104 #endif
1105 	do {
1106 
1107 		listenfd = usbmuxd_listen();
1108 		if (listenfd < 0) {
1109 			continue;
1110 		}
1111 
1112 		while (running) {
1113 			int res = get_next_event(listenfd);
1114 			if (res < 0) {
1115 				break;
1116 			}
1117 		}
1118 
1119 		mutex_lock(&listener_mutex);
1120 		if (collection_count(&listeners) == 0) {
1121 			running = 0;
1122 		}
1123 		mutex_unlock(&listener_mutex);
1124 	} while (running);
1125 
1126 #ifdef HAVE_THREAD_CLEANUP
1127 	thread_cleanup_pop(1);
1128 #else
1129 	device_monitor_cleanup(NULL);
1130 #endif
1131 
1132 	return NULL;
1133 }
1134 
init_listeners(void)1135 static void init_listeners(void)
1136 {
1137 	collection_init(&listeners);
1138 	mutex_init(&listener_mutex);
1139 }
1140 
usbmuxd_events_subscribe(usbmuxd_subscription_context_t * ctx,usbmuxd_event_cb_t callback,void * user_data)1141 USBMUXD_API int usbmuxd_events_subscribe(usbmuxd_subscription_context_t *ctx, usbmuxd_event_cb_t callback, void *user_data)
1142 {
1143 	if (!ctx || !callback) {
1144 		return -EINVAL;
1145 	}
1146 
1147 	thread_once(&listener_init_once, init_listeners);
1148 
1149 	mutex_lock(&listener_mutex);
1150 	*ctx = malloc(sizeof(struct usbmuxd_subscription_context));
1151 	if (!*ctx) {
1152 		mutex_unlock(&listener_mutex);
1153 		LIBUSBMUXD_ERROR("ERROR: %s: malloc failed\n", __func__);
1154 		return -ENOMEM;
1155 	}
1156 	(*ctx)->callback = callback;
1157 	(*ctx)->user_data = user_data;
1158 
1159 	collection_add(&listeners, *ctx);
1160 
1161 	if (devmon == THREAD_T_NULL || !thread_alive(devmon)) {
1162 		mutex_unlock(&listener_mutex);
1163 		int res = thread_new(&devmon, device_monitor, NULL);
1164 		if (res != 0) {
1165 			free(*ctx);
1166 			LIBUSBMUXD_DEBUG(1, "%s: ERROR: Could not start device watcher thread!\n", __func__);
1167 			return res;
1168 		}
1169 	} else {
1170 		/* we need to submit DEVICE_ADD events to the new listener */
1171 		FOREACH(usbmuxd_device_info_t *dev, &devices) {
1172 			if (dev) {
1173 				usbmuxd_event_t ev;
1174 				ev.event = UE_DEVICE_ADD;
1175 				memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t));
1176 				(*ctx)->callback(&ev, (*ctx)->user_data);
1177 			}
1178 		} ENDFOREACH
1179 		mutex_unlock(&listener_mutex);
1180 	}
1181 
1182 	return 0;
1183 }
1184 
usbmuxd_events_unsubscribe(usbmuxd_subscription_context_t ctx)1185 USBMUXD_API int usbmuxd_events_unsubscribe(usbmuxd_subscription_context_t ctx)
1186 {
1187 	int ret = 0;
1188 	int num = 0;
1189 
1190 	if (!ctx) {
1191 		return -EINVAL;
1192 	}
1193 
1194 	mutex_lock(&listener_mutex);
1195 	if (collection_remove(&listeners, ctx) == 0) {
1196 		FOREACH(usbmuxd_device_info_t *dev, &devices) {
1197 			if (dev) {
1198 				usbmuxd_event_t ev;
1199 				ev.event = UE_DEVICE_REMOVE;
1200 				memcpy(&ev.device, dev, sizeof(usbmuxd_device_info_t));
1201 				(ctx)->callback(&ev, (ctx)->user_data);
1202 			}
1203 		} ENDFOREACH
1204 		free(ctx);
1205 	}
1206 	num = collection_count(&listeners);
1207 	mutex_unlock(&listener_mutex);
1208 
1209 	if (num == 0) {
1210 		int res = 0;
1211 		cancelling = 1;
1212 		socket_shutdown(listenfd, SHUT_RDWR);
1213 		if (thread_alive(devmon)) {
1214 			if (thread_cancel(devmon) < 0) {
1215 				running = 0;
1216 			}
1217 #if defined(HAVE_INOTIFY) && !defined(HAVE_PTHREAD_CANCEL)
1218 			pthread_kill(devmon, SIGINT);
1219 #endif
1220 			res = thread_join(devmon);
1221 			thread_free(devmon);
1222 			devmon = THREAD_T_NULL;
1223 		}
1224 		if ((res != 0) && (res != ESRCH)) {
1225 			ret = res;
1226 		}
1227 	}
1228 
1229 	return ret;
1230 }
1231 
usbmuxd_subscribe(usbmuxd_event_cb_t callback,void * user_data)1232 USBMUXD_API int usbmuxd_subscribe(usbmuxd_event_cb_t callback, void *user_data)
1233 {
1234 	if (!callback) {
1235 		return -EINVAL;
1236 	}
1237 
1238 	if (event_ctx) {
1239 		usbmuxd_events_unsubscribe(event_ctx);
1240 		event_ctx = NULL;
1241 	}
1242 	return usbmuxd_events_subscribe(&event_ctx, callback, user_data);
1243 }
1244 
usbmuxd_unsubscribe(void)1245 USBMUXD_API int usbmuxd_unsubscribe(void)
1246 {
1247 	int res = usbmuxd_events_unsubscribe(event_ctx);
1248 	event_ctx = NULL;
1249 	return res;
1250 }
1251 
usbmuxd_get_device_list(usbmuxd_device_info_t ** device_list)1252 USBMUXD_API int usbmuxd_get_device_list(usbmuxd_device_info_t **device_list)
1253 {
1254 	int sfd;
1255 	int tag;
1256 	int listen_success = 0;
1257 	uint32_t res;
1258 	struct collection tmpdevs;
1259 	usbmuxd_device_info_t *newlist = NULL;
1260 	struct usbmuxd_header hdr;
1261 	int dev_cnt = 0;
1262 	void *payload = NULL;
1263 
1264 	*device_list = NULL;
1265 
1266 retry:
1267 	sfd = connect_usbmuxd_socket();
1268 	if (sfd < 0) {
1269 		LIBUSBMUXD_DEBUG(1, "%s: error opening socket!\n", __func__);
1270 		return sfd;
1271 	}
1272 
1273 	tag = ++use_tag;
1274 	if ((proto_version == 1) && (try_list_devices)) {
1275 		if (send_list_devices_packet(sfd, tag) > 0) {
1276 			plist_t list = NULL;
1277 			if ((usbmuxd_get_result(sfd, tag, &res, &list) == 1) && (res == 0)) {
1278 				plist_t devlist = plist_dict_get_item(list, "DeviceList");
1279 				if (devlist && plist_get_node_type(devlist) == PLIST_ARRAY) {
1280 					collection_init(&tmpdevs);
1281 					uint32_t numdevs = plist_array_get_size(devlist);
1282 					uint32_t i;
1283 					for (i = 0; i < numdevs; i++) {
1284 						plist_t pdev = plist_array_get_item(devlist, i);
1285 						plist_t props = plist_dict_get_item(pdev, "Properties");
1286 						usbmuxd_device_info_t *devinfo = device_info_from_plist(props);
1287 						if (!devinfo) {
1288 							socket_close(sfd);
1289 							LIBUSBMUXD_DEBUG(1, "%s: Could not create device info object from properties!\n", __func__);
1290 							plist_free(list);
1291 							return -1;
1292 						}
1293 						collection_add(&tmpdevs, devinfo);
1294 					}
1295 					plist_free(list);
1296 					goto got_device_list;
1297 				}
1298 			} else {
1299 				if (res == RESULT_BADVERSION) {
1300 					proto_version = 0;
1301 				}
1302 				socket_close(sfd);
1303 				try_list_devices = 0;
1304 				plist_free(list);
1305 				goto retry;
1306 			}
1307 			plist_free(list);
1308 		}
1309 	}
1310 
1311 	tag = ++use_tag;
1312 	if (send_listen_packet(sfd, tag) > 0) {
1313 		res = -1;
1314 		// get response
1315 		if ((usbmuxd_get_result(sfd, tag, &res, NULL) == 1) && (res == 0)) {
1316 			listen_success = 1;
1317 		} else {
1318 			socket_close(sfd);
1319 			if ((res == RESULT_BADVERSION) && (proto_version == 1)) {
1320 				proto_version = 0;
1321 				goto retry;
1322 			}
1323 			LIBUSBMUXD_DEBUG(1, "%s: Did not get response to scan request (with result=0)...\n", __func__);
1324 			return res;
1325 		}
1326 	}
1327 
1328 	if (!listen_success) {
1329 		socket_close(sfd);
1330 		LIBUSBMUXD_DEBUG(1, "%s: Could not send listen request!\n", __func__);
1331 		return -1;
1332 	}
1333 
1334 	collection_init(&tmpdevs);
1335 
1336 	// receive device list
1337 	while (1) {
1338 		if (receive_packet(sfd, &hdr, &payload, 100) > 0) {
1339 			if (hdr.message == MESSAGE_DEVICE_ADD) {
1340 				usbmuxd_device_info_t *devinfo = payload;
1341 				collection_add(&tmpdevs, devinfo);
1342 				payload = NULL;
1343 			} else if (hdr.message == MESSAGE_DEVICE_REMOVE) {
1344 				uint32_t handle;
1345 				usbmuxd_device_info_t *devinfo = NULL;
1346 
1347 				memcpy(&handle, payload, sizeof(uint32_t));
1348 
1349 				FOREACH(usbmuxd_device_info_t *di, &tmpdevs) {
1350 					if (di && di->handle == handle) {
1351 						devinfo = di;
1352 						break;
1353 					}
1354 				} ENDFOREACH
1355 				if (devinfo) {
1356 					collection_remove(&tmpdevs, devinfo);
1357 					free(devinfo);
1358 				}
1359 			} else {
1360 				LIBUSBMUXD_DEBUG(1, "%s: Unexpected message %d\n", __func__, hdr.message);
1361 			}
1362 			free(payload);
1363 		} else {
1364 			// we _should_ have all of them now.
1365 			// or perhaps an error occured.
1366 			break;
1367 		}
1368 	}
1369 
1370 got_device_list:
1371 
1372 	// explicitly close connection
1373 	socket_close(sfd);
1374 
1375 	// create copy of device info entries from collection
1376 	newlist = (usbmuxd_device_info_t*)malloc(sizeof(usbmuxd_device_info_t) * (collection_count(&tmpdevs) + 1));
1377 	dev_cnt = 0;
1378 	FOREACH(usbmuxd_device_info_t *di, &tmpdevs) {
1379 		if (di) {
1380 			memcpy(&newlist[dev_cnt], di, sizeof(usbmuxd_device_info_t));
1381 			free(di);
1382 			dev_cnt++;
1383 		}
1384 	} ENDFOREACH
1385 	collection_free(&tmpdevs);
1386 
1387 	memset(&newlist[dev_cnt], 0, sizeof(usbmuxd_device_info_t));
1388 	*device_list = newlist;
1389 
1390 	return dev_cnt;
1391 }
1392 
usbmuxd_device_list_free(usbmuxd_device_info_t ** device_list)1393 USBMUXD_API int usbmuxd_device_list_free(usbmuxd_device_info_t **device_list)
1394 {
1395 	if (device_list) {
1396 		free(*device_list);
1397 	}
1398 	return 0;
1399 }
1400 
usbmuxd_get_device_by_udid(const char * udid,usbmuxd_device_info_t * device)1401 USBMUXD_API int usbmuxd_get_device_by_udid(const char *udid, usbmuxd_device_info_t *device)
1402 {
1403 	usbmuxd_device_info_t *dev_list = NULL;
1404 	usbmuxd_device_info_t *dev = NULL;
1405 	int result = 0;
1406 	int i;
1407 
1408 	if (!device) {
1409 		return -EINVAL;
1410 	}
1411 	if (usbmuxd_get_device_list(&dev_list) < 0) {
1412 		return -ENODEV;
1413 	}
1414 
1415 	for (i = 0; dev_list[i].handle > 0; i++) {
1416 	 	if (!udid) {
1417 			if (dev_list[i].conn_type == CONNECTION_TYPE_USB) {
1418 				dev = &dev_list[i];
1419 				break;
1420 			}
1421 		} else if (!strcmp(udid, dev_list[i].udid)) {
1422 			if (dev_list[i].conn_type == CONNECTION_TYPE_USB) {
1423 				dev = &dev_list[i];
1424 				break;
1425 			}
1426 		}
1427 	}
1428 
1429 	if (dev) {
1430 		device->handle = dev->handle;
1431 		device->product_id = dev->product_id;
1432 		char *t = stpncpy(device->udid, dev->udid, sizeof(device->udid)-1);
1433 		*t = '\0';
1434 		device->conn_type = dev->conn_type;
1435 		memcpy(device->conn_data, dev->conn_data, sizeof(device->conn_data));
1436 		result = 1;
1437 	}
1438 
1439 	usbmuxd_device_list_free(&dev_list);
1440 
1441 	return result;
1442 }
1443 
usbmuxd_get_device(const char * udid,usbmuxd_device_info_t * device,enum usbmux_lookup_options options)1444 USBMUXD_API int usbmuxd_get_device(const char *udid, usbmuxd_device_info_t *device, enum usbmux_lookup_options options)
1445 {
1446 	usbmuxd_device_info_t *dev_list = NULL;
1447 	usbmuxd_device_info_t *dev_network = NULL;
1448 	usbmuxd_device_info_t *dev_usbmuxd = NULL;
1449 	usbmuxd_device_info_t *dev = NULL;
1450 	int result = 0;
1451 	int i;
1452 
1453 	if (!device) {
1454 		return -EINVAL;
1455 	}
1456 	if (usbmuxd_get_device_list(&dev_list) < 0) {
1457 		return -ENODEV;
1458 	}
1459 
1460 	if (options == 0) {
1461 		options = DEVICE_LOOKUP_USBMUX;
1462 	}
1463 
1464 	for (i = 0; dev_list[i].handle > 0; i++) {
1465 		if (!udid) {
1466 			if ((options & DEVICE_LOOKUP_USBMUX) && (dev_list[i].conn_type == CONNECTION_TYPE_USB)) {
1467 				dev_usbmuxd = &dev_list[i];
1468 				break;
1469 			} else if ((options & DEVICE_LOOKUP_NETWORK) && (dev_list[i].conn_type == CONNECTION_TYPE_NETWORK)) {
1470 				dev_network = &dev_list[i];
1471 				break;
1472 			}
1473 		} else if (!strcmp(udid, dev_list[i].udid)) {
1474 			if ((options & DEVICE_LOOKUP_USBMUX) && (dev_list[i].conn_type == CONNECTION_TYPE_USB)) {
1475 				dev_usbmuxd = &dev_list[i];
1476 			} else if ((options & DEVICE_LOOKUP_NETWORK) && (dev_list[i].conn_type == CONNECTION_TYPE_NETWORK)) {
1477 				dev_network = &dev_list[i];
1478 			}
1479 		}
1480 		if (dev_usbmuxd && dev_network) {
1481 			break;
1482 		}
1483 	}
1484 
1485 	if (dev_network && dev_usbmuxd) {
1486 		dev = (options & DEVICE_LOOKUP_PREFER_NETWORK) ? dev_network : dev_usbmuxd;
1487 	} else if (dev_network) {
1488 		dev = dev_network;
1489 	} else if (dev_usbmuxd) {
1490 		dev = dev_usbmuxd;
1491 	}
1492 
1493 	if (dev) {
1494 		device->handle = dev->handle;
1495 		device->product_id = dev->product_id;
1496 		char *t = stpncpy(device->udid, dev->udid, sizeof(device->udid)-1);
1497 		*t = '\0';
1498 		device->conn_type = dev->conn_type;
1499 		memcpy(device->conn_data, dev->conn_data, sizeof(device->conn_data));
1500 		result = 1;
1501 	}
1502 
1503 	free(dev_list);
1504 
1505 	return result;
1506 }
1507 
usbmuxd_connect(const uint32_t handle,const unsigned short port)1508 USBMUXD_API int usbmuxd_connect(const uint32_t handle, const unsigned short port)
1509 {
1510 	int sfd;
1511 	int tag;
1512 	int connected = 0;
1513 	int result = EBADF;
1514 
1515 retry:
1516 	sfd = connect_usbmuxd_socket();
1517 	if (sfd < 0) {
1518 		result = errno;
1519 		LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n", __func__, strerror(result));
1520 		return -result;
1521 	}
1522 
1523 	tag = ++use_tag;
1524 	if (send_connect_packet(sfd, tag, (uint32_t)handle, (uint16_t)port) <= 0) {
1525 		LIBUSBMUXD_DEBUG(1, "%s: Error sending connect message!\n", __func__);
1526 	} else {
1527 		// read ACK
1528 		uint32_t res = -1;
1529 		LIBUSBMUXD_DEBUG(2, "%s: Reading connect result...\n", __func__);
1530 		if (usbmuxd_get_result(sfd, tag, &res, NULL) == 1) {
1531 			if (res == 0) {
1532 				LIBUSBMUXD_DEBUG(2, "%s: Connect success!\n", __func__);
1533 				connected = 1;
1534 			} else {
1535 				if ((res == RESULT_BADVERSION) && (proto_version == 1)) {
1536 					proto_version = 0;
1537 					socket_close(sfd);
1538 					goto retry;
1539 				}
1540 				LIBUSBMUXD_DEBUG(1, "%s: Connect failed, Error code=%d\n", __func__, res);
1541 				if (res == RESULT_CONNREFUSED) {
1542 					result = ECONNREFUSED;
1543 				} else if (res == RESULT_BADDEV) {
1544 					result = ENODEV;
1545 				} else {
1546 					result = EBADF;
1547 				}
1548 			}
1549 		}
1550 	}
1551 
1552 	if (connected) {
1553 		return sfd;
1554 	}
1555 
1556 	socket_close(sfd);
1557 
1558 	return -result;
1559 }
1560 
usbmuxd_disconnect(int sfd)1561 USBMUXD_API int usbmuxd_disconnect(int sfd)
1562 {
1563 	return socket_close(sfd);
1564 }
1565 
usbmuxd_send(int sfd,const char * data,uint32_t len,uint32_t * sent_bytes)1566 USBMUXD_API int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes)
1567 {
1568 	int num_sent;
1569 
1570 	if (sfd < 0) {
1571 		return -EINVAL;
1572 	}
1573 
1574 	num_sent = socket_send(sfd, (void*)data, len);
1575 	if (num_sent < 0) {
1576 		*sent_bytes = 0;
1577 		num_sent = errno;
1578 		LIBUSBMUXD_DEBUG(1, "%s: Error %d when sending: %s\n", __func__, num_sent, strerror(num_sent));
1579 		return -num_sent;
1580 	} else if ((uint32_t)num_sent < len) {
1581 		LIBUSBMUXD_DEBUG(1, "%s: Warning: Did not send enough (only %d of %d)\n", __func__, num_sent, len);
1582 	}
1583 
1584 	*sent_bytes = num_sent;
1585 
1586 	return 0;
1587 }
1588 
usbmuxd_recv_timeout(int sfd,char * data,uint32_t len,uint32_t * recv_bytes,unsigned int timeout)1589 USBMUXD_API int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
1590 {
1591 	int num_recv = socket_receive_timeout(sfd, (void*)data, len, 0, timeout);
1592 	if (num_recv < 0) {
1593 		*recv_bytes = 0;
1594 		return num_recv;
1595 	}
1596 
1597 	*recv_bytes = num_recv;
1598 
1599 	return 0;
1600 }
1601 
usbmuxd_recv(int sfd,char * data,uint32_t len,uint32_t * recv_bytes)1602 USBMUXD_API int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes)
1603 {
1604 	return usbmuxd_recv_timeout(sfd, data, len, recv_bytes, 5000);
1605 }
1606 
usbmuxd_read_buid(char ** buid)1607 USBMUXD_API int usbmuxd_read_buid(char **buid)
1608 {
1609 	int sfd;
1610 	int tag;
1611 	int ret = -1;
1612 
1613 	if (!buid) {
1614 		return -EINVAL;
1615 	}
1616 	*buid = NULL;
1617 
1618 	sfd = connect_usbmuxd_socket();
1619 	if (sfd < 0) {
1620 		LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n", __func__, strerror(errno));
1621 		return sfd;
1622 	}
1623 
1624 	proto_version = 1;
1625 	tag = ++use_tag;
1626 	if (send_read_buid_packet(sfd, tag) <= 0) {
1627 		LIBUSBMUXD_DEBUG(1, "%s: Error sending ReadBUID message!\n", __func__);
1628 	} else {
1629 		uint32_t rc = 0;
1630 		plist_t pl = NULL;
1631 		ret = usbmuxd_get_result(sfd, tag, &rc, &pl);
1632 		if ((ret == 1) && (rc == 0)) {
1633 			plist_t node = plist_dict_get_item(pl, "BUID");
1634 			if (node && plist_get_node_type(node) == PLIST_STRING) {
1635 				plist_get_string_val(node, buid);
1636 			}
1637 			ret = 0;
1638 		} else if (ret == 1) {
1639 			ret = -(int)rc;
1640 		}
1641 		plist_free(pl);
1642 	}
1643 	socket_close(sfd);
1644 
1645 	return ret;
1646 }
1647 
usbmuxd_read_pair_record(const char * record_id,char ** record_data,uint32_t * record_size)1648 USBMUXD_API int usbmuxd_read_pair_record(const char* record_id, char **record_data, uint32_t *record_size)
1649 {
1650 	int sfd;
1651 	int tag;
1652 	int ret = -1;
1653 
1654 	if (!record_id || !record_data || !record_size) {
1655 		return -EINVAL;
1656 	}
1657 	*record_data = NULL;
1658 	*record_size = 0;
1659 
1660 	sfd = connect_usbmuxd_socket();
1661 	if (sfd < 0) {
1662 		LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n",
1663 				__func__, strerror(errno));
1664 		return sfd;
1665 	}
1666 
1667 	proto_version = 1;
1668 	tag = ++use_tag;
1669 
1670 	if (send_pair_record_packet(sfd, tag, "ReadPairRecord", record_id, 0, NULL) <= 0) {
1671 		LIBUSBMUXD_DEBUG(1, "%s: Error sending ReadPairRecord message!\n", __func__);
1672 	} else {
1673 		uint32_t rc = 0;
1674 		plist_t pl = NULL;
1675 		ret = usbmuxd_get_result(sfd, tag, &rc, &pl);
1676 		if ((ret == 1) && (rc == 0)) {
1677 			plist_t node = plist_dict_get_item(pl, "PairRecordData");
1678 			if (node && plist_get_node_type(node) == PLIST_DATA) {
1679 				uint64_t int64val = 0;
1680 				plist_get_data_val(node, record_data, &int64val);
1681 				if (*record_data && int64val > 0) {
1682 					*record_size = (uint32_t)int64val;
1683 					ret = 0;
1684 				}
1685 			}
1686 		} else if (ret == 1) {
1687 			ret = -(int)rc;
1688 		}
1689 		plist_free(pl);
1690 	}
1691 	socket_close(sfd);
1692 
1693 	return ret;
1694 }
1695 
usbmuxd_save_pair_record_with_device_id(const char * record_id,uint32_t device_id,const char * record_data,uint32_t record_size)1696 USBMUXD_API int usbmuxd_save_pair_record_with_device_id(const char* record_id, uint32_t device_id, const char *record_data, uint32_t record_size)
1697 {
1698 	int sfd;
1699 	int tag;
1700 	int ret = -1;
1701 
1702 	if (!record_id || !record_data || !record_size) {
1703 		return -EINVAL;
1704 	}
1705 
1706 	sfd = connect_usbmuxd_socket();
1707 	if (sfd < 0) {
1708 		LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n",
1709 				__func__, strerror(errno));
1710 		return sfd;
1711 	}
1712 
1713 	proto_version = 1;
1714 	tag = ++use_tag;
1715 
1716 	plist_t data = plist_new_data(record_data, record_size);
1717 	if (send_pair_record_packet(sfd, tag, "SavePairRecord", record_id, device_id, data) <= 0) {
1718 		LIBUSBMUXD_DEBUG(1, "%s: Error sending SavePairRecord message!\n", __func__);
1719 	} else {
1720 		uint32_t rc = 0;
1721 		ret = usbmuxd_get_result(sfd, tag, &rc, NULL);
1722 		if ((ret == 1) && (rc == 0)) {
1723 			ret = 0;
1724 		} else if (ret == 1) {
1725 			ret = -(int)rc;
1726 			LIBUSBMUXD_DEBUG(1, "%s: Error: saving pair record failed: %d\n", __func__, ret);
1727 		}
1728 	}
1729 	plist_free(data);
1730 	socket_close(sfd);
1731 
1732 	return ret;
1733 }
1734 
usbmuxd_save_pair_record(const char * record_id,const char * record_data,uint32_t record_size)1735 USBMUXD_API int usbmuxd_save_pair_record(const char* record_id, const char *record_data, uint32_t record_size)
1736 {
1737 	return usbmuxd_save_pair_record_with_device_id(record_id, 0, record_data, record_size);
1738 }
1739 
usbmuxd_delete_pair_record(const char * record_id)1740 USBMUXD_API int usbmuxd_delete_pair_record(const char* record_id)
1741 {
1742 	int sfd;
1743 	int tag;
1744 	int ret = -1;
1745 
1746 	if (!record_id) {
1747 		return -EINVAL;
1748 	}
1749 
1750 	sfd = connect_usbmuxd_socket();
1751 	if (sfd < 0) {
1752 		LIBUSBMUXD_DEBUG(1, "%s: Error: Connection to usbmuxd failed: %s\n",
1753 				__func__, strerror(errno));
1754 		return sfd;
1755 	}
1756 
1757 	proto_version = 1;
1758 	tag = ++use_tag;
1759 
1760 	if (send_pair_record_packet(sfd, tag, "DeletePairRecord", record_id, 0, NULL) <= 0) {
1761 		LIBUSBMUXD_DEBUG(1, "%s: Error sending DeletePairRecord message!\n", __func__);
1762 	} else {
1763 		uint32_t rc = 0;
1764 		ret = usbmuxd_get_result(sfd, tag, &rc, NULL);
1765 		if ((ret == 1) && (rc == 0)) {
1766 			ret = 0;
1767 		} else if (ret == 1) {
1768 			ret = -(int)rc;
1769 			LIBUSBMUXD_DEBUG(1, "%s: Error: deleting pair record failed: %d\n", __func__, ret);
1770 		}
1771 	}
1772 	socket_close(sfd);
1773 
1774 	return ret;
1775 }
1776 
libusbmuxd_set_use_inotify(int set)1777 USBMUXD_API void libusbmuxd_set_use_inotify(int set)
1778 {
1779 #ifdef HAVE_INOTIFY
1780 	use_inotify = set;
1781 #endif
1782 	return;
1783 }
1784 
libusbmuxd_set_debug_level(int level)1785 USBMUXD_API void libusbmuxd_set_debug_level(int level)
1786 {
1787 	libusbmuxd_debug = level;
1788 	socket_set_verbose(level);
1789 }
1790