diff options
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/client.c | 43 | ||||
-rw-r--r-- | src/conf.c | 2 | ||||
-rw-r--r-- | src/device.c | 69 | ||||
-rw-r--r-- | src/preflight.c | 15 | ||||
-rw-r--r-- | src/usb.c | 2 | ||||
-rw-r--r-- | src/utils.c | 248 | ||||
-rw-r--r-- | src/utils.h | 43 |
10 files changed, 74 insertions, 357 deletions
@@ -45,6 +45,7 @@ sudo apt-get install \ | |||
45 | libplist-dev \ | 45 | libplist-dev \ |
46 | libusbmuxd-dev \ | 46 | libusbmuxd-dev \ |
47 | libimobiledevice-dev \ | 47 | libimobiledevice-dev \ |
48 | libimobiledevice-glue-dev \ | ||
48 | libusb-1.0-0-dev \ | 49 | libusb-1.0-0-dev \ |
49 | udev | 50 | udev |
50 | ``` | 51 | ``` |
@@ -152,4 +153,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc. | |||
152 | usbmuxd is an independent software application and has not been | 153 | usbmuxd is an independent software application and has not been |
153 | authorized, sponsored, or otherwise approved by Apple Inc. | 154 | authorized, sponsored, or otherwise approved by Apple Inc. |
154 | 155 | ||
155 | README Updated on: 2020-06-13 | 156 | README Updated on: 2021-08-30 |
diff --git a/configure.ac b/configure.ac index 7a70be9..b751cc2 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -18,7 +18,7 @@ LT_INIT | |||
18 | PKG_CHECK_MODULES(libusb, libusb-1.0 >= 1.0.9) | 18 | PKG_CHECK_MODULES(libusb, libusb-1.0 >= 1.0.9) |
19 | PKG_CHECK_MODULES(libplist, libplist-2.0 >= 2.2.0) | 19 | PKG_CHECK_MODULES(libplist, libplist-2.0 >= 2.2.0) |
20 | PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.3.0, have_limd=yes, have_limd=no) | 20 | PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.3.0, have_limd=yes, have_limd=no) |
21 | AC_CHECK_LIB(pthread, [pthread_create, pthread_mutex_lock], [AC_SUBST(libpthread_LIBS,[-lpthread])], [AC_MSG_ERROR([libpthread is required to build usbmuxd])]) | 21 | PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= 1.0.0) |
22 | 22 | ||
23 | AC_ARG_WITH([preflight], | 23 | AC_ARG_WITH([preflight], |
24 | [AS_HELP_STRING([--without-preflight], | 24 | [AS_HELP_STRING([--without-preflight], |
@@ -106,7 +106,7 @@ AC_TYPE_UINT8_T | |||
106 | AC_SEARCH_LIBS([clock_gettime],[rt posix4]) | 106 | AC_SEARCH_LIBS([clock_gettime],[rt posix4]) |
107 | 107 | ||
108 | # Checks for library functions. | 108 | # Checks for library functions. |
109 | AC_CHECK_FUNCS([strcasecmp strdup strerror strndup stpcpy malloc realloc]) | 109 | AC_CHECK_FUNCS([strcasecmp strdup strerror strndup malloc realloc]) |
110 | AC_CHECK_FUNCS([ppoll clock_gettime localtime_r]) | 110 | AC_CHECK_FUNCS([ppoll clock_gettime localtime_r]) |
111 | 111 | ||
112 | # Check for operating system | 112 | # Check for operating system |
diff --git a/src/Makefile.am b/src/Makefile.am index 328b700..8a96e46 100644 --- a/src/Makefile.am +++ b/src/Makefile.am | |||
@@ -6,11 +6,13 @@ AM_CFLAGS = \ | |||
6 | $(GLOBAL_CFLAGS) \ | 6 | $(GLOBAL_CFLAGS) \ |
7 | $(libplist_CFLAGS) \ | 7 | $(libplist_CFLAGS) \ |
8 | $(libusb_CFLAGS) \ | 8 | $(libusb_CFLAGS) \ |
9 | $(limd_glue_CFLAGS) \ | ||
9 | $(libimobiledevice_CFLAGS) | 10 | $(libimobiledevice_CFLAGS) |
10 | 11 | ||
11 | AM_LDFLAGS = \ | 12 | AM_LDFLAGS = \ |
12 | $(libplist_LIBS) \ | 13 | $(libplist_LIBS) \ |
13 | $(libusb_LIBS) \ | 14 | $(libusb_LIBS) \ |
15 | $(limd_glue_LIBS) \ | ||
14 | $(libimobiledevice_LIBS) \ | 16 | $(libimobiledevice_LIBS) \ |
15 | $(libpthread_LIBS) | 17 | $(libpthread_LIBS) |
16 | 18 | ||
diff --git a/src/client.c b/src/client.c index 7395046..75a526d 100644 --- a/src/client.c +++ b/src/client.c | |||
@@ -34,10 +34,11 @@ | |||
34 | #include <netinet/tcp.h> | 34 | #include <netinet/tcp.h> |
35 | #include <sys/un.h> | 35 | #include <sys/un.h> |
36 | #include <arpa/inet.h> | 36 | #include <arpa/inet.h> |
37 | #include <pthread.h> | ||
38 | #include <fcntl.h> | 37 | #include <fcntl.h> |
39 | 38 | ||
40 | #include <plist/plist.h> | 39 | #include <plist/plist.h> |
40 | #include <libimobiledevice-glue/collection.h> | ||
41 | #include <libimobiledevice-glue/thread.h> | ||
41 | 42 | ||
42 | #include "log.h" | 43 | #include "log.h" |
43 | #include "usb.h" | 44 | #include "usb.h" |
@@ -75,7 +76,7 @@ struct mux_client { | |||
75 | }; | 76 | }; |
76 | 77 | ||
77 | static struct collection client_list; | 78 | static struct collection client_list; |
78 | pthread_mutex_t client_list_mutex; | 79 | mutex_t client_list_mutex; |
79 | static uint32_t client_number = 0; | 80 | static uint32_t client_number = 0; |
80 | 81 | ||
81 | #ifdef SO_PEERCRED | 82 | #ifdef SO_PEERCRED |
@@ -224,10 +225,10 @@ int client_accept(int listenfd) | |||
224 | client->events = POLLIN; | 225 | client->events = POLLIN; |
225 | client->info = NULL; | 226 | client->info = NULL; |
226 | 227 | ||
227 | pthread_mutex_lock(&client_list_mutex); | 228 | mutex_lock(&client_list_mutex); |
228 | client->number = client_number++; | 229 | client->number = client_number++; |
229 | collection_add(&client_list, client); | 230 | collection_add(&client_list, client); |
230 | pthread_mutex_unlock(&client_list_mutex); | 231 | mutex_unlock(&client_list_mutex); |
231 | 232 | ||
232 | #ifdef SO_PEERCRED | 233 | #ifdef SO_PEERCRED |
233 | if (log_level >= LL_INFO) { | 234 | if (log_level >= LL_INFO) { |
@@ -252,7 +253,7 @@ int client_accept(int listenfd) | |||
252 | void client_close(struct mux_client *client) | 253 | void client_close(struct mux_client *client) |
253 | { | 254 | { |
254 | int found = 0; | 255 | int found = 0; |
255 | pthread_mutex_lock(&client_list_mutex); | 256 | mutex_lock(&client_list_mutex); |
256 | FOREACH(struct mux_client *lc, &client_list) { | 257 | FOREACH(struct mux_client *lc, &client_list) { |
257 | if (client == lc) { | 258 | if (client == lc) { |
258 | found = 1; | 259 | found = 1; |
@@ -262,7 +263,7 @@ void client_close(struct mux_client *client) | |||
262 | if (!found) { | 263 | if (!found) { |
263 | // in case we get called again but client was already freed | 264 | // in case we get called again but client was already freed |
264 | usbmuxd_log(LL_DEBUG, "%s: ignoring for non-existing client %p", __func__, client); | 265 | usbmuxd_log(LL_DEBUG, "%s: ignoring for non-existing client %p", __func__, client); |
265 | pthread_mutex_unlock(&client_list_mutex); | 266 | mutex_unlock(&client_list_mutex); |
266 | return; | 267 | return; |
267 | } | 268 | } |
268 | #ifdef SO_PEERCRED | 269 | #ifdef SO_PEERCRED |
@@ -293,17 +294,17 @@ void client_close(struct mux_client *client) | |||
293 | plist_free(client->info); | 294 | plist_free(client->info); |
294 | 295 | ||
295 | collection_remove(&client_list, client); | 296 | collection_remove(&client_list, client); |
296 | pthread_mutex_unlock(&client_list_mutex); | 297 | mutex_unlock(&client_list_mutex); |
297 | free(client); | 298 | free(client); |
298 | } | 299 | } |
299 | 300 | ||
300 | void client_get_fds(struct fdlist *list) | 301 | void client_get_fds(struct fdlist *list) |
301 | { | 302 | { |
302 | pthread_mutex_lock(&client_list_mutex); | 303 | mutex_lock(&client_list_mutex); |
303 | FOREACH(struct mux_client *client, &client_list) { | 304 | FOREACH(struct mux_client *client, &client_list) { |
304 | fdlist_add(list, FD_CLIENT, client->fd, client->events); | 305 | fdlist_add(list, FD_CLIENT, client->fd, client->events); |
305 | } ENDFOREACH | 306 | } ENDFOREACH |
306 | pthread_mutex_unlock(&client_list_mutex); | 307 | mutex_unlock(&client_list_mutex); |
307 | } | 308 | } |
308 | 309 | ||
309 | static int output_buffer_add_message(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length) | 310 | static int output_buffer_add_message(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length) |
@@ -442,7 +443,7 @@ static int send_listener_list(struct mux_client *client, uint32_t tag) | |||
442 | plist_t dict = plist_new_dict(); | 443 | plist_t dict = plist_new_dict(); |
443 | plist_t listeners = plist_new_array(); | 444 | plist_t listeners = plist_new_array(); |
444 | 445 | ||
445 | pthread_mutex_lock(&client_list_mutex); | 446 | mutex_lock(&client_list_mutex); |
446 | FOREACH(struct mux_client *lc, &client_list) { | 447 | FOREACH(struct mux_client *lc, &client_list) { |
447 | if (lc->state == CLIENT_LISTEN) { | 448 | if (lc->state == CLIENT_LISTEN) { |
448 | plist_t n = NULL; | 449 | plist_t n = NULL; |
@@ -489,7 +490,7 @@ static int send_listener_list(struct mux_client *client, uint32_t tag) | |||
489 | plist_array_append_item(listeners, l); | 490 | plist_array_append_item(listeners, l); |
490 | } | 491 | } |
491 | } ENDFOREACH | 492 | } ENDFOREACH |
492 | pthread_mutex_unlock(&client_list_mutex); | 493 | mutex_unlock(&client_list_mutex); |
493 | 494 | ||
494 | plist_dict_set_item(dict, "ListenerList", listeners); | 495 | plist_dict_set_item(dict, "ListenerList", listeners); |
495 | res = send_plist(client, tag, dict); | 496 | res = send_plist(client, tag, dict); |
@@ -975,14 +976,14 @@ static void input_buffer_process(struct mux_client *client) | |||
975 | void client_process(int fd, short events) | 976 | void client_process(int fd, short events) |
976 | { | 977 | { |
977 | struct mux_client *client = NULL; | 978 | struct mux_client *client = NULL; |
978 | pthread_mutex_lock(&client_list_mutex); | 979 | mutex_lock(&client_list_mutex); |
979 | FOREACH(struct mux_client *lc, &client_list) { | 980 | FOREACH(struct mux_client *lc, &client_list) { |
980 | if(lc->fd == fd) { | 981 | if(lc->fd == fd) { |
981 | client = lc; | 982 | client = lc; |
982 | break; | 983 | break; |
983 | } | 984 | } |
984 | } ENDFOREACH | 985 | } ENDFOREACH |
985 | pthread_mutex_unlock(&client_list_mutex); | 986 | mutex_unlock(&client_list_mutex); |
986 | 987 | ||
987 | if(!client) { | 988 | if(!client) { |
988 | usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd); | 989 | usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd); |
@@ -1004,45 +1005,45 @@ void client_process(int fd, short events) | |||
1004 | 1005 | ||
1005 | void client_device_add(struct device_info *dev) | 1006 | void client_device_add(struct device_info *dev) |
1006 | { | 1007 | { |
1007 | pthread_mutex_lock(&client_list_mutex); | 1008 | mutex_lock(&client_list_mutex); |
1008 | usbmuxd_log(LL_DEBUG, "client_device_add: id %d, location 0x%x, serial %s", dev->id, dev->location, dev->serial); | 1009 | usbmuxd_log(LL_DEBUG, "client_device_add: id %d, location 0x%x, serial %s", dev->id, dev->location, dev->serial); |
1009 | device_set_visible(dev->id); | 1010 | device_set_visible(dev->id); |
1010 | FOREACH(struct mux_client *client, &client_list) { | 1011 | FOREACH(struct mux_client *client, &client_list) { |
1011 | if(client->state == CLIENT_LISTEN) | 1012 | if(client->state == CLIENT_LISTEN) |
1012 | send_device_add(client, dev); | 1013 | send_device_add(client, dev); |
1013 | } ENDFOREACH | 1014 | } ENDFOREACH |
1014 | pthread_mutex_unlock(&client_list_mutex); | 1015 | mutex_unlock(&client_list_mutex); |
1015 | } | 1016 | } |
1016 | 1017 | ||
1017 | void client_device_remove(int device_id) | 1018 | void client_device_remove(int device_id) |
1018 | { | 1019 | { |
1019 | pthread_mutex_lock(&client_list_mutex); | 1020 | mutex_lock(&client_list_mutex); |
1020 | uint32_t id = device_id; | 1021 | uint32_t id = device_id; |
1021 | usbmuxd_log(LL_DEBUG, "client_device_remove: id %d", device_id); | 1022 | usbmuxd_log(LL_DEBUG, "client_device_remove: id %d", device_id); |
1022 | FOREACH(struct mux_client *client, &client_list) { | 1023 | FOREACH(struct mux_client *client, &client_list) { |
1023 | if(client->state == CLIENT_LISTEN) | 1024 | if(client->state == CLIENT_LISTEN) |
1024 | send_device_remove(client, id); | 1025 | send_device_remove(client, id); |
1025 | } ENDFOREACH | 1026 | } ENDFOREACH |
1026 | pthread_mutex_unlock(&client_list_mutex); | 1027 | mutex_unlock(&client_list_mutex); |
1027 | } | 1028 | } |
1028 | 1029 | ||
1029 | void client_device_paired(int device_id) | 1030 | void client_device_paired(int device_id) |
1030 | { | 1031 | { |
1031 | pthread_mutex_lock(&client_list_mutex); | 1032 | mutex_lock(&client_list_mutex); |
1032 | uint32_t id = device_id; | 1033 | uint32_t id = device_id; |
1033 | usbmuxd_log(LL_DEBUG, "client_device_paired: id %d", device_id); | 1034 | usbmuxd_log(LL_DEBUG, "client_device_paired: id %d", device_id); |
1034 | FOREACH(struct mux_client *client, &client_list) { | 1035 | FOREACH(struct mux_client *client, &client_list) { |
1035 | if (client->state == CLIENT_LISTEN) | 1036 | if (client->state == CLIENT_LISTEN) |
1036 | send_device_paired(client, id); | 1037 | send_device_paired(client, id); |
1037 | } ENDFOREACH | 1038 | } ENDFOREACH |
1038 | pthread_mutex_unlock(&client_list_mutex); | 1039 | mutex_unlock(&client_list_mutex); |
1039 | } | 1040 | } |
1040 | 1041 | ||
1041 | void client_init(void) | 1042 | void client_init(void) |
1042 | { | 1043 | { |
1043 | usbmuxd_log(LL_DEBUG, "client_init"); | 1044 | usbmuxd_log(LL_DEBUG, "client_init"); |
1044 | collection_init(&client_list); | 1045 | collection_init(&client_list); |
1045 | pthread_mutex_init(&client_list_mutex, NULL); | 1046 | mutex_init(&client_list_mutex); |
1046 | } | 1047 | } |
1047 | 1048 | ||
1048 | void client_shutdown(void) | 1049 | void client_shutdown(void) |
@@ -1051,6 +1052,6 @@ void client_shutdown(void) | |||
1051 | FOREACH(struct mux_client *client, &client_list) { | 1052 | FOREACH(struct mux_client *client, &client_list) { |
1052 | client_close(client); | 1053 | client_close(client); |
1053 | } ENDFOREACH | 1054 | } ENDFOREACH |
1054 | pthread_mutex_destroy(&client_list_mutex); | 1055 | mutex_destroy(&client_list_mutex); |
1055 | collection_free(&client_list); | 1056 | collection_free(&client_list); |
1056 | } | 1057 | } |
@@ -39,6 +39,8 @@ | |||
39 | #include <shlobj.h> | 39 | #include <shlobj.h> |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | #include <libimobiledevice-glue/utils.h> | ||
43 | |||
42 | #include "conf.h" | 44 | #include "conf.h" |
43 | #include "utils.h" | 45 | #include "utils.h" |
44 | #include "log.h" | 46 | #include "log.h" |
diff --git a/src/device.c b/src/device.c index aac40b1..0928021 100644 --- a/src/device.c +++ b/src/device.c | |||
@@ -32,8 +32,11 @@ | |||
32 | #include <string.h> | 32 | #include <string.h> |
33 | #include <stdint.h> | 33 | #include <stdint.h> |
34 | #include <inttypes.h> | 34 | #include <inttypes.h> |
35 | #include <pthread.h> | ||
36 | #include <unistd.h> | 35 | #include <unistd.h> |
36 | |||
37 | #include <libimobiledevice-glue/collection.h> | ||
38 | #include <libimobiledevice-glue/thread.h> | ||
39 | |||
37 | #include "device.h" | 40 | #include "device.h" |
38 | #include "client.h" | 41 | #include "client.h" |
39 | #include "preflight.h" | 42 | #include "preflight.h" |
@@ -127,19 +130,19 @@ struct mux_device | |||
127 | }; | 130 | }; |
128 | 131 | ||
129 | static struct collection device_list; | 132 | static struct collection device_list; |
130 | pthread_mutex_t device_list_mutex; | 133 | mutex_t device_list_mutex; |
131 | 134 | ||
132 | static struct mux_device* get_mux_device_for_id(int device_id) | 135 | static struct mux_device* get_mux_device_for_id(int device_id) |
133 | { | 136 | { |
134 | struct mux_device *dev = NULL; | 137 | struct mux_device *dev = NULL; |
135 | pthread_mutex_lock(&device_list_mutex); | 138 | mutex_lock(&device_list_mutex); |
136 | FOREACH(struct mux_device *cdev, &device_list) { | 139 | FOREACH(struct mux_device *cdev, &device_list) { |
137 | if(cdev->id == device_id) { | 140 | if(cdev->id == device_id) { |
138 | dev = cdev; | 141 | dev = cdev; |
139 | break; | 142 | break; |
140 | } | 143 | } |
141 | } ENDFOREACH | 144 | } ENDFOREACH |
142 | pthread_mutex_unlock(&device_list_mutex); | 145 | mutex_unlock(&device_list_mutex); |
143 | 146 | ||
144 | return dev; | 147 | return dev; |
145 | } | 148 | } |
@@ -166,7 +169,7 @@ static int get_next_device_id(void) | |||
166 | { | 169 | { |
167 | while(1) { | 170 | while(1) { |
168 | int ok = 1; | 171 | int ok = 1; |
169 | pthread_mutex_lock(&device_list_mutex); | 172 | mutex_lock(&device_list_mutex); |
170 | FOREACH(struct mux_device *dev, &device_list) { | 173 | FOREACH(struct mux_device *dev, &device_list) { |
171 | if(dev->id == next_device_id) { | 174 | if(dev->id == next_device_id) { |
172 | next_device_id++; | 175 | next_device_id++; |
@@ -174,7 +177,7 @@ static int get_next_device_id(void) | |||
174 | break; | 177 | break; |
175 | } | 178 | } |
176 | } ENDFOREACH | 179 | } ENDFOREACH |
177 | pthread_mutex_unlock(&device_list_mutex); | 180 | mutex_unlock(&device_list_mutex); |
178 | if(ok) | 181 | if(ok) |
179 | return next_device_id++; | 182 | return next_device_id++; |
180 | } | 183 | } |
@@ -464,9 +467,9 @@ static int send_tcp_ack(struct mux_connection *conn) | |||
464 | */ | 467 | */ |
465 | void device_client_process(int device_id, struct mux_client *client, short events) | 468 | void device_client_process(int device_id, struct mux_client *client, short events) |
466 | { | 469 | { |
467 | pthread_mutex_lock(&device_list_mutex); | 470 | mutex_lock(&device_list_mutex); |
468 | struct mux_connection *conn = get_mux_connection(device_id, client); | 471 | struct mux_connection *conn = get_mux_connection(device_id, client); |
469 | pthread_mutex_unlock(&device_list_mutex); | 472 | mutex_unlock(&device_list_mutex); |
470 | if(!conn) { | 473 | if(!conn) { |
471 | usbmuxd_log(LL_WARNING, "Could not find connection for device %d client %p", device_id, client); | 474 | usbmuxd_log(LL_WARNING, "Could not find connection for device %d client %p", device_id, client); |
472 | return; | 475 | return; |
@@ -566,9 +569,9 @@ static void device_version_input(struct mux_device *dev, struct version_header * | |||
566 | vh->minor = ntohl(vh->minor); | 569 | vh->minor = ntohl(vh->minor); |
567 | if(vh->major != 2 && vh->major != 1) { | 570 | if(vh->major != 2 && vh->major != 1) { |
568 | usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d", dev->id, vh->major, vh->minor); | 571 | usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d", dev->id, vh->major, vh->minor); |
569 | pthread_mutex_lock(&device_list_mutex); | 572 | mutex_lock(&device_list_mutex); |
570 | collection_remove(&device_list, dev); | 573 | collection_remove(&device_list, dev); |
571 | pthread_mutex_unlock(&device_list_mutex); | 574 | mutex_unlock(&device_list_mutex); |
572 | free(dev); | 575 | free(dev); |
573 | return; | 576 | return; |
574 | } | 577 | } |
@@ -726,14 +729,14 @@ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned | |||
726 | void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_t length) | 729 | void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_t length) |
727 | { | 730 | { |
728 | struct mux_device *dev = NULL; | 731 | struct mux_device *dev = NULL; |
729 | pthread_mutex_lock(&device_list_mutex); | 732 | mutex_lock(&device_list_mutex); |
730 | FOREACH(struct mux_device *tdev, &device_list) { | 733 | FOREACH(struct mux_device *tdev, &device_list) { |
731 | if(tdev->usbdev == usbdev) { | 734 | if(tdev->usbdev == usbdev) { |
732 | dev = tdev; | 735 | dev = tdev; |
733 | break; | 736 | break; |
734 | } | 737 | } |
735 | } ENDFOREACH | 738 | } ENDFOREACH |
736 | pthread_mutex_unlock(&device_list_mutex); | 739 | mutex_unlock(&device_list_mutex); |
737 | if(!dev) { | 740 | if(!dev) { |
738 | usbmuxd_log(LL_WARNING, "Cannot find device entry for RX input from USB device %p on location 0x%x", usbdev, usb_get_location(usbdev)); | 741 | usbmuxd_log(LL_WARNING, "Cannot find device entry for RX input from USB device %p on location 0x%x", usbdev, usb_get_location(usbdev)); |
739 | return; | 742 | return; |
@@ -850,15 +853,15 @@ int device_add(struct usb_device *usbdev) | |||
850 | free(dev); | 853 | free(dev); |
851 | return res; | 854 | return res; |
852 | } | 855 | } |
853 | pthread_mutex_lock(&device_list_mutex); | 856 | mutex_lock(&device_list_mutex); |
854 | collection_add(&device_list, dev); | 857 | collection_add(&device_list, dev); |
855 | pthread_mutex_unlock(&device_list_mutex); | 858 | mutex_unlock(&device_list_mutex); |
856 | return 0; | 859 | return 0; |
857 | } | 860 | } |
858 | 861 | ||
859 | void device_remove(struct usb_device *usbdev) | 862 | void device_remove(struct usb_device *usbdev) |
860 | { | 863 | { |
861 | pthread_mutex_lock(&device_list_mutex); | 864 | mutex_lock(&device_list_mutex); |
862 | FOREACH(struct mux_device *dev, &device_list) { | 865 | FOREACH(struct mux_device *dev, &device_list) { |
863 | if(dev->usbdev == usbdev) { | 866 | if(dev->usbdev == usbdev) { |
864 | usbmuxd_log(LL_NOTICE, "Removed device %d on location 0x%x", dev->id, usb_get_location(usbdev)); | 867 | usbmuxd_log(LL_NOTICE, "Removed device %d on location 0x%x", dev->id, usb_get_location(usbdev)); |
@@ -874,48 +877,48 @@ void device_remove(struct usb_device *usbdev) | |||
874 | preflight_device_remove_cb(dev->preflight_cb_data); | 877 | preflight_device_remove_cb(dev->preflight_cb_data); |
875 | } | 878 | } |
876 | collection_remove(&device_list, dev); | 879 | collection_remove(&device_list, dev); |
877 | pthread_mutex_unlock(&device_list_mutex); | 880 | mutex_unlock(&device_list_mutex); |
878 | free(dev->pktbuf); | 881 | free(dev->pktbuf); |
879 | free(dev); | 882 | free(dev); |
880 | return; | 883 | return; |
881 | } | 884 | } |
882 | } ENDFOREACH | 885 | } ENDFOREACH |
883 | pthread_mutex_unlock(&device_list_mutex); | 886 | mutex_unlock(&device_list_mutex); |
884 | 887 | ||
885 | usbmuxd_log(LL_WARNING, "Cannot find device entry while removing USB device %p on location 0x%x", usbdev, usb_get_location(usbdev)); | 888 | usbmuxd_log(LL_WARNING, "Cannot find device entry while removing USB device %p on location 0x%x", usbdev, usb_get_location(usbdev)); |
886 | } | 889 | } |
887 | 890 | ||
888 | void device_set_visible(int device_id) | 891 | void device_set_visible(int device_id) |
889 | { | 892 | { |
890 | pthread_mutex_lock(&device_list_mutex); | 893 | mutex_lock(&device_list_mutex); |
891 | FOREACH(struct mux_device *dev, &device_list) { | 894 | FOREACH(struct mux_device *dev, &device_list) { |
892 | if(dev->id == device_id) { | 895 | if(dev->id == device_id) { |
893 | dev->visible = 1; | 896 | dev->visible = 1; |
894 | break; | 897 | break; |
895 | } | 898 | } |
896 | } ENDFOREACH | 899 | } ENDFOREACH |
897 | pthread_mutex_unlock(&device_list_mutex); | 900 | mutex_unlock(&device_list_mutex); |
898 | } | 901 | } |
899 | 902 | ||
900 | void device_set_preflight_cb_data(int device_id, void* data) | 903 | void device_set_preflight_cb_data(int device_id, void* data) |
901 | { | 904 | { |
902 | pthread_mutex_lock(&device_list_mutex); | 905 | mutex_lock(&device_list_mutex); |
903 | FOREACH(struct mux_device *dev, &device_list) { | 906 | FOREACH(struct mux_device *dev, &device_list) { |
904 | if(dev->id == device_id) { | 907 | if(dev->id == device_id) { |
905 | dev->preflight_cb_data = data; | 908 | dev->preflight_cb_data = data; |
906 | break; | 909 | break; |
907 | } | 910 | } |
908 | } ENDFOREACH | 911 | } ENDFOREACH |
909 | pthread_mutex_unlock(&device_list_mutex); | 912 | mutex_unlock(&device_list_mutex); |
910 | } | 913 | } |
911 | 914 | ||
912 | int device_get_count(int include_hidden) | 915 | int device_get_count(int include_hidden) |
913 | { | 916 | { |
914 | int count = 0; | 917 | int count = 0; |
915 | struct collection dev_list = {NULL, 0}; | 918 | struct collection dev_list = {NULL, 0}; |
916 | pthread_mutex_lock(&device_list_mutex); | 919 | mutex_lock(&device_list_mutex); |
917 | collection_copy(&dev_list, &device_list); | 920 | collection_copy(&dev_list, &device_list); |
918 | pthread_mutex_unlock(&device_list_mutex); | 921 | mutex_unlock(&device_list_mutex); |
919 | 922 | ||
920 | FOREACH(struct mux_device *dev, &dev_list) { | 923 | FOREACH(struct mux_device *dev, &dev_list) { |
921 | if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) | 924 | if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) |
@@ -930,9 +933,9 @@ int device_get_list(int include_hidden, struct device_info **devices) | |||
930 | { | 933 | { |
931 | int count = 0; | 934 | int count = 0; |
932 | struct collection dev_list = {NULL, 0}; | 935 | struct collection dev_list = {NULL, 0}; |
933 | pthread_mutex_lock(&device_list_mutex); | 936 | mutex_lock(&device_list_mutex); |
934 | collection_copy(&dev_list, &device_list); | 937 | collection_copy(&dev_list, &device_list); |
935 | pthread_mutex_unlock(&device_list_mutex); | 938 | mutex_unlock(&device_list_mutex); |
936 | 939 | ||
937 | *devices = malloc(sizeof(struct device_info) * dev_list.capacity); | 940 | *devices = malloc(sizeof(struct device_info) * dev_list.capacity); |
938 | struct device_info *p = *devices; | 941 | struct device_info *p = *devices; |
@@ -957,7 +960,7 @@ int device_get_list(int include_hidden, struct device_info **devices) | |||
957 | int device_get_timeout(void) | 960 | int device_get_timeout(void) |
958 | { | 961 | { |
959 | uint64_t oldest = (uint64_t)-1LL; | 962 | uint64_t oldest = (uint64_t)-1LL; |
960 | pthread_mutex_lock(&device_list_mutex); | 963 | mutex_lock(&device_list_mutex); |
961 | FOREACH(struct mux_device *dev, &device_list) { | 964 | FOREACH(struct mux_device *dev, &device_list) { |
962 | if(dev->state == MUXDEV_ACTIVE) { | 965 | if(dev->state == MUXDEV_ACTIVE) { |
963 | FOREACH(struct mux_connection *conn, &dev->connections) { | 966 | FOREACH(struct mux_connection *conn, &dev->connections) { |
@@ -966,7 +969,7 @@ int device_get_timeout(void) | |||
966 | } ENDFOREACH | 969 | } ENDFOREACH |
967 | } | 970 | } |
968 | } ENDFOREACH | 971 | } ENDFOREACH |
969 | pthread_mutex_unlock(&device_list_mutex); | 972 | mutex_unlock(&device_list_mutex); |
970 | uint64_t ct = mstime64(); | 973 | uint64_t ct = mstime64(); |
971 | if((int64_t)oldest == -1LL) | 974 | if((int64_t)oldest == -1LL) |
972 | return 100000; //meh | 975 | return 100000; //meh |
@@ -978,7 +981,7 @@ int device_get_timeout(void) | |||
978 | void device_check_timeouts(void) | 981 | void device_check_timeouts(void) |
979 | { | 982 | { |
980 | uint64_t ct = mstime64(); | 983 | uint64_t ct = mstime64(); |
981 | pthread_mutex_lock(&device_list_mutex); | 984 | mutex_lock(&device_list_mutex); |
982 | FOREACH(struct mux_device *dev, &device_list) { | 985 | FOREACH(struct mux_device *dev, &device_list) { |
983 | if(dev->state == MUXDEV_ACTIVE) { | 986 | if(dev->state == MUXDEV_ACTIVE) { |
984 | FOREACH(struct mux_connection *conn, &dev->connections) { | 987 | FOREACH(struct mux_connection *conn, &dev->connections) { |
@@ -991,14 +994,14 @@ void device_check_timeouts(void) | |||
991 | } ENDFOREACH | 994 | } ENDFOREACH |
992 | } | 995 | } |
993 | } ENDFOREACH | 996 | } ENDFOREACH |
994 | pthread_mutex_unlock(&device_list_mutex); | 997 | mutex_unlock(&device_list_mutex); |
995 | } | 998 | } |
996 | 999 | ||
997 | void device_init(void) | 1000 | void device_init(void) |
998 | { | 1001 | { |
999 | usbmuxd_log(LL_DEBUG, "device_init"); | 1002 | usbmuxd_log(LL_DEBUG, "device_init"); |
1000 | collection_init(&device_list); | 1003 | collection_init(&device_list); |
1001 | pthread_mutex_init(&device_list_mutex, NULL); | 1004 | mutex_init(&device_list_mutex); |
1002 | next_device_id = 1; | 1005 | next_device_id = 1; |
1003 | } | 1006 | } |
1004 | 1007 | ||
@@ -1019,7 +1022,7 @@ void device_kill_connections(void) | |||
1019 | void device_shutdown(void) | 1022 | void device_shutdown(void) |
1020 | { | 1023 | { |
1021 | usbmuxd_log(LL_DEBUG, "device_shutdown"); | 1024 | usbmuxd_log(LL_DEBUG, "device_shutdown"); |
1022 | pthread_mutex_lock(&device_list_mutex); | 1025 | mutex_lock(&device_list_mutex); |
1023 | FOREACH(struct mux_device *dev, &device_list) { | 1026 | FOREACH(struct mux_device *dev, &device_list) { |
1024 | FOREACH(struct mux_connection *conn, &dev->connections) { | 1027 | FOREACH(struct mux_connection *conn, &dev->connections) { |
1025 | connection_teardown(conn); | 1028 | connection_teardown(conn); |
@@ -1028,7 +1031,7 @@ void device_shutdown(void) | |||
1028 | collection_remove(&device_list, dev); | 1031 | collection_remove(&device_list, dev); |
1029 | free(dev); | 1032 | free(dev); |
1030 | } ENDFOREACH | 1033 | } ENDFOREACH |
1031 | pthread_mutex_unlock(&device_list_mutex); | 1034 | mutex_unlock(&device_list_mutex); |
1032 | pthread_mutex_destroy(&device_list_mutex); | 1035 | mutex_destroy(&device_list_mutex); |
1033 | collection_free(&device_list); | 1036 | collection_free(&device_list); |
1034 | } | 1037 | } |
diff --git a/src/preflight.c b/src/preflight.c index 6a303c2..5902f5d 100644 --- a/src/preflight.c +++ b/src/preflight.c | |||
@@ -26,8 +26,6 @@ | |||
26 | #include <unistd.h> | 26 | #include <unistd.h> |
27 | #include <errno.h> | 27 | #include <errno.h> |
28 | 28 | ||
29 | #include <pthread.h> | ||
30 | |||
31 | #include <sys/time.h> | 29 | #include <sys/time.h> |
32 | 30 | ||
33 | #ifdef HAVE_LIBIMOBILEDEVICE | 31 | #ifdef HAVE_LIBIMOBILEDEVICE |
@@ -36,6 +34,8 @@ | |||
36 | #include <libimobiledevice/notification_proxy.h> | 34 | #include <libimobiledevice/notification_proxy.h> |
37 | #endif | 35 | #endif |
38 | 36 | ||
37 | #include <libimobiledevice-glue/thread.h> | ||
38 | |||
39 | #include "preflight.h" | 39 | #include "preflight.h" |
40 | #include "device.h" | 40 | #include "device.h" |
41 | #include "client.h" | 41 | #include "client.h" |
@@ -389,18 +389,15 @@ void preflight_worker_device_add(struct device_info* info) | |||
389 | infocopy->serial = strdup(info->serial); | 389 | infocopy->serial = strdup(info->serial); |
390 | } | 390 | } |
391 | 391 | ||
392 | pthread_t th; | 392 | THREAD_T th; |
393 | pthread_attr_t attr; | 393 | int perr = thread_new(&th, preflight_worker_handle_device_add, infocopy); |
394 | |||
395 | pthread_attr_init(&attr); | ||
396 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | ||
397 | |||
398 | int perr = pthread_create(&th, &attr, preflight_worker_handle_device_add, infocopy); | ||
399 | if (perr != 0) { | 394 | if (perr != 0) { |
400 | free((char*)infocopy->serial); | 395 | free((char*)infocopy->serial); |
401 | free(infocopy); | 396 | free(infocopy); |
402 | usbmuxd_log(LL_ERROR, "ERROR: failed to start preflight worker thread for device %s: %s (%d). Invoking client_device_add() directly but things might not work as expected.", info->serial, strerror(perr), perr); | 397 | usbmuxd_log(LL_ERROR, "ERROR: failed to start preflight worker thread for device %s: %s (%d). Invoking client_device_add() directly but things might not work as expected.", info->serial, strerror(perr), perr); |
403 | client_device_add(info); | 398 | client_device_add(info); |
399 | } else { | ||
400 | thread_detach(th); | ||
404 | } | 401 | } |
405 | #else | 402 | #else |
406 | client_device_add(info); | 403 | client_device_add(info); |
@@ -31,6 +31,8 @@ | |||
31 | 31 | ||
32 | #include <libusb.h> | 32 | #include <libusb.h> |
33 | 33 | ||
34 | #include <libimobiledevice-glue/collection.h> | ||
35 | |||
34 | #include "usb.h" | 36 | #include "usb.h" |
35 | #include "log.h" | 37 | #include "log.h" |
36 | #include "device.h" | 38 | #include "device.h" |
diff --git a/src/utils.c b/src/utils.c index 206c684..2cc5675 100644 --- a/src/utils.c +++ b/src/utils.c | |||
@@ -76,254 +76,6 @@ void fdlist_reset(struct fdlist *list) | |||
76 | list->count = 0; | 76 | list->count = 0; |
77 | } | 77 | } |
78 | 78 | ||
79 | #define CAPACITY_STEP 8 | ||
80 | |||
81 | void collection_init(struct collection *col) | ||
82 | { | ||
83 | col->list = malloc(sizeof(void *) * CAPACITY_STEP); | ||
84 | memset(col->list, 0, sizeof(void *) * CAPACITY_STEP); | ||
85 | col->capacity = CAPACITY_STEP; | ||
86 | } | ||
87 | |||
88 | void collection_free(struct collection *col) | ||
89 | { | ||
90 | free(col->list); | ||
91 | col->list = NULL; | ||
92 | col->capacity = 0; | ||
93 | } | ||
94 | |||
95 | void collection_add(struct collection *col, void *element) | ||
96 | { | ||
97 | int i; | ||
98 | for(i=0; i<col->capacity; i++) { | ||
99 | if(!col->list[i]) { | ||
100 | col->list[i] = element; | ||
101 | return; | ||
102 | } | ||
103 | } | ||
104 | col->list = realloc(col->list, sizeof(void*) * (col->capacity + CAPACITY_STEP)); | ||
105 | memset(&col->list[col->capacity], 0, sizeof(void *) * CAPACITY_STEP); | ||
106 | col->list[col->capacity] = element; | ||
107 | col->capacity += CAPACITY_STEP; | ||
108 | } | ||
109 | |||
110 | void collection_remove(struct collection *col, void *element) | ||
111 | { | ||
112 | int i; | ||
113 | for(i=0; i<col->capacity; i++) { | ||
114 | if(col->list[i] == element) { | ||
115 | col->list[i] = NULL; | ||
116 | return; | ||
117 | } | ||
118 | } | ||
119 | util_error("collection_remove: element %p not present in collection %p (cap %d)", element, col, col->capacity); | ||
120 | } | ||
121 | |||
122 | int collection_count(struct collection *col) | ||
123 | { | ||
124 | int i, cnt = 0; | ||
125 | for(i=0; i<col->capacity; i++) { | ||
126 | if(col->list[i]) | ||
127 | cnt++; | ||
128 | } | ||
129 | return cnt; | ||
130 | } | ||
131 | |||
132 | void collection_copy(struct collection *dest, struct collection *src) | ||
133 | { | ||
134 | if (!dest || !src) return; | ||
135 | dest->capacity = src->capacity; | ||
136 | dest->list = malloc(sizeof(void*) * src->capacity); | ||
137 | memcpy(dest->list, src->list, sizeof(void*) * src->capacity); | ||
138 | } | ||
139 | |||
140 | #ifndef HAVE_STPCPY | ||
141 | /** | ||
142 | * Copy characters from one string into another | ||
143 | * | ||
144 | * @note: The strings should not overlap, as the behavior is undefined. | ||
145 | * | ||
146 | * @s1: The source string. | ||
147 | * @s2: The destination string. | ||
148 | * | ||
149 | * @return a pointer to the terminating `\0' character of @s1, | ||
150 | * or NULL if @s1 or @s2 is NULL. | ||
151 | */ | ||
152 | char *stpcpy(char * s1, const char * s2) | ||
153 | { | ||
154 | if (s1 == NULL || s2 == NULL) | ||
155 | return NULL; | ||
156 | |||
157 | strcpy(s1, s2); | ||
158 | |||
159 | return s1 + strlen(s2); | ||
160 | } | ||
161 | #endif | ||
162 | |||
163 | /** | ||
164 | * Concatenate strings into a newly allocated string | ||
165 | * | ||
166 | * @note: Specify NULL for the last string in the varargs list | ||
167 | * | ||
168 | * @str: The first string in the list | ||
169 | * @...: Subsequent strings. Use NULL for the last item. | ||
170 | * | ||
171 | * @return a newly allocated string, or NULL if @str is NULL. This will also | ||
172 | * return NULL and set errno to ENOMEM if memory is exhausted. | ||
173 | */ | ||
174 | char *string_concat(const char *str, ...) | ||
175 | { | ||
176 | size_t len; | ||
177 | va_list args; | ||
178 | char *s; | ||
179 | char *result; | ||
180 | char *dest; | ||
181 | |||
182 | if (!str) | ||
183 | return NULL; | ||
184 | |||
185 | /* Compute final length */ | ||
186 | |||
187 | len = strlen(str) + 1; /* plus 1 for the null terminator */ | ||
188 | |||
189 | va_start(args, str); | ||
190 | s = va_arg(args, char *); | ||
191 | while (s) { | ||
192 | len += strlen(s); | ||
193 | s = va_arg(args, char*); | ||
194 | } | ||
195 | va_end(args); | ||
196 | |||
197 | /* Concat each string */ | ||
198 | |||
199 | result = malloc(len); | ||
200 | if (!result) | ||
201 | return NULL; /* errno remains set */ | ||
202 | |||
203 | dest = result; | ||
204 | |||
205 | dest = stpcpy(dest, str); | ||
206 | |||
207 | va_start(args, str); | ||
208 | s = va_arg(args, char *); | ||
209 | while (s) { | ||
210 | dest = stpcpy(dest, s); | ||
211 | s = va_arg(args, char *); | ||
212 | } | ||
213 | va_end(args); | ||
214 | |||
215 | return result; | ||
216 | } | ||
217 | |||
218 | int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length) | ||
219 | { | ||
220 | FILE *f; | ||
221 | uint64_t size; | ||
222 | |||
223 | *length = 0; | ||
224 | |||
225 | f = fopen(filename, "rb"); | ||
226 | if (!f) { | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | fseek(f, 0, SEEK_END); | ||
231 | size = ftell(f); | ||
232 | rewind(f); | ||
233 | |||
234 | if (size == 0) { | ||
235 | fclose(f); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | *buffer = (char*)malloc(sizeof(char)*(size+1)); | ||
240 | |||
241 | if (!buffer) { | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | int ret = 1; | ||
246 | if (fread(*buffer, sizeof(char), size, f) != size) { | ||
247 | usbmuxd_log(LL_ERROR, "%s: ERROR: couldn't read %d bytes from %s", __func__, (int)size, filename); | ||
248 | free(*buffer); | ||
249 | ret = 0; | ||
250 | errno = EIO; | ||
251 | } | ||
252 | fclose(f); | ||
253 | |||
254 | *length = size; | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length) | ||
259 | { | ||
260 | FILE *f; | ||
261 | |||
262 | f = fopen(filename, "wb"); | ||
263 | if (f) { | ||
264 | size_t written = fwrite(buffer, sizeof(char), length, f); | ||
265 | fclose(f); | ||
266 | |||
267 | if (written == length) { | ||
268 | return 1; | ||
269 | } | ||
270 | else { | ||
271 | // Not all data could be written. | ||
272 | errno = EIO; | ||
273 | return 0; | ||
274 | } | ||
275 | } | ||
276 | else { | ||
277 | // Failed to open the file, let the caller know. | ||
278 | return 0; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | int plist_read_from_filename(plist_t *plist, const char *filename) | ||
283 | { | ||
284 | char *buffer = NULL; | ||
285 | uint64_t length; | ||
286 | |||
287 | if (!filename) | ||
288 | return 0; | ||
289 | |||
290 | if (!buffer_read_from_filename(filename, &buffer, &length)) { | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) { | ||
295 | plist_from_bin(buffer, length, plist); | ||
296 | } else { | ||
297 | plist_from_xml(buffer, length, plist); | ||
298 | } | ||
299 | |||
300 | free(buffer); | ||
301 | |||
302 | return 1; | ||
303 | } | ||
304 | |||
305 | int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format) | ||
306 | { | ||
307 | char *buffer = NULL; | ||
308 | uint32_t length; | ||
309 | |||
310 | if (!plist || !filename) | ||
311 | return 0; | ||
312 | |||
313 | if (format == PLIST_FORMAT_XML) | ||
314 | plist_to_xml(plist, &buffer, &length); | ||
315 | else if (format == PLIST_FORMAT_BINARY) | ||
316 | plist_to_bin(plist, &buffer, &length); | ||
317 | else | ||
318 | return 0; | ||
319 | |||
320 | int res = buffer_write_to_filename(filename, buffer, length); | ||
321 | |||
322 | free(buffer); | ||
323 | |||
324 | return res; | ||
325 | } | ||
326 | |||
327 | #ifndef HAVE_CLOCK_GETTIME | 79 | #ifndef HAVE_CLOCK_GETTIME |
328 | typedef int clockid_t; | 80 | typedef int clockid_t; |
329 | #define CLOCK_MONOTONIC 1 | 81 | #define CLOCK_MONOTONIC 1 |
diff --git a/src/utils.h b/src/utils.h index b5cab3f..ce3b2e0 100644 --- a/src/utils.h +++ b/src/utils.h | |||
@@ -43,49 +43,6 @@ void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events); | |||
43 | void fdlist_free(struct fdlist *list); | 43 | void fdlist_free(struct fdlist *list); |
44 | void fdlist_reset(struct fdlist *list); | 44 | void fdlist_reset(struct fdlist *list); |
45 | 45 | ||
46 | struct collection { | ||
47 | void **list; | ||
48 | int capacity; | ||
49 | }; | ||
50 | |||
51 | void collection_init(struct collection *col); | ||
52 | void collection_add(struct collection *col, void *element); | ||
53 | void collection_remove(struct collection *col, void *element); | ||
54 | int collection_count(struct collection *col); | ||
55 | void collection_free(struct collection *col); | ||
56 | void collection_copy(struct collection *dest, struct collection *src); | ||
57 | |||
58 | #define MERGE_(a,b) a ## _ ## b | ||
59 | #define LABEL_(a,b) MERGE_(a, b) | ||
60 | #define UNIQUE_VAR(a) LABEL_(a, __LINE__) | ||
61 | |||
62 | #define FOREACH(var, col) \ | ||
63 | do { \ | ||
64 | int UNIQUE_VAR(_iter); \ | ||
65 | for(UNIQUE_VAR(_iter)=0; UNIQUE_VAR(_iter)<(col)->capacity; UNIQUE_VAR(_iter)++) { \ | ||
66 | if(!(col)->list[UNIQUE_VAR(_iter)]) continue; \ | ||
67 | var = (col)->list[UNIQUE_VAR(_iter)]; | ||
68 | |||
69 | #define ENDFOREACH \ | ||
70 | } \ | ||
71 | } while(0); | ||
72 | |||
73 | #ifndef HAVE_STPCPY | ||
74 | char *stpcpy(char * s1, const char * s2); | ||
75 | #endif | ||
76 | char *string_concat(const char *str, ...); | ||
77 | |||
78 | int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length); | ||
79 | int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length); | ||
80 | |||
81 | enum plist_format_t { | ||
82 | PLIST_FORMAT_XML, | ||
83 | PLIST_FORMAT_BINARY | ||
84 | }; | ||
85 | |||
86 | int plist_read_from_filename(plist_t *plist, const char *filename); | ||
87 | int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format); | ||
88 | |||
89 | uint64_t mstime64(void); | 46 | uint64_t mstime64(void); |
90 | void get_tick_count(struct timeval * tv); | 47 | void get_tick_count(struct timeval * tv); |
91 | 48 | ||