summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2019-09-04 23:56:37 +0200
committerGravatar Nikias Bassen2019-09-04 23:56:37 +0200
commit38befc71844a6108a78e1fe5a76946450d49ca76 (patch)
tree3a886d468803b94f8b3c8fca1fc2d2802414cedc
parent2a38fe45f62cbd5c554293b7d82dbbb74ec8aeca (diff)
downloadlibirecovery-38befc71844a6108a78e1fe5a76946450d49ca76.tar.gz
libirecovery-38befc71844a6108a78e1fe5a76946450d49ca76.tar.bz2
Add device add/remove event subscription API
-rw-r--r--configure.ac96
-rw-r--r--include/libirecovery.h23
-rw-r--r--src/Makefile.am18
-rw-r--r--src/libirecovery.c764
-rw-r--r--tools/irecovery.c4
5 files changed, 809 insertions, 96 deletions
diff --git a/configure.ac b/configure.ac
index 1f10bb7..6481d74 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,36 +28,59 @@ AC_PROG_CXX
28AM_PROG_CC_C_O 28AM_PROG_CC_C_O
29AC_PROG_LIBTOOL 29AC_PROG_LIBTOOL
30 30
31# Checks for header files.
32AC_HEADER_STDC
33AC_CHECK_HEADERS([stdint.h stdlib.h string.h])
34
35# Checks for typedefs, structures, and compiler characteristics.
36AC_C_CONST
37AC_TYPE_SIZE_T
38AC_TYPE_SSIZE_T
39AC_TYPE_UINT16_T
40AC_TYPE_UINT32_T
41AC_TYPE_UINT8_T
42
43# Checks for library functions.
44AC_FUNC_MALLOC
45AC_FUNC_REALLOC
46AC_CHECK_FUNCS([strdup strerror strndup])
47
31# Checks for libraries. 48# Checks for libraries.
32AC_CHECK_HEADERS([readline/readline.h], [], 49AC_CHECK_HEADERS([readline/readline.h], [],
33 [AC_MSG_ERROR([Please install readline development headers])] 50 [AC_MSG_ERROR([Please install readline development headers])]
34) 51)
35 52
36# Check additional platform flags 53# Check additional platform flags
37case "$host_os" in 54AC_MSG_CHECKING([for platform-specific build settings])
55case ${host_os} in
38 darwin*) 56 darwin*)
57 AC_MSG_RESULT([${host_os}])
39 AC_CHECK_HEADER(CoreFoundation/CoreFoundation.h, [ 58 AC_CHECK_HEADER(CoreFoundation/CoreFoundation.h, [
40 AC_CHECK_HEADER(IOKit/usb/IOUSBLib.h, [ 59 AC_CHECK_HEADER(IOKit/usb/IOUSBLib.h, [
41 LIBIRECOVERYLDFLAGS="-framework IOKit -framework CoreFoundation" 60 GLOBAL_LDFLAGS+=" -framework IOKit -framework CoreFoundation"
42 have_iokit=yes 61 have_iokit=yes
43 ], []) 62 ], [])
44 ], []) 63 ], [])
64 AX_PTHREAD([], [AC_MSG_ERROR([pthread is required to build $PACKAGE])])
45 ;; 65 ;;
46 mingw32*) 66 mingw32*)
47 LDFLAGS+=" -static-libgcc" 67 AC_MSG_RESULT([${host_os}])
48 LIBIRECOVERYLDFLAGS=" -lkernel32 -lmsvcrt -lsetupapi" 68 GLOBAL_LDFLAGS+=" -static-libgcc -lkernel32 -lmsvcrt -lsetupapi"
69 win32=true
49 ;; 70 ;;
50 cygwin*) 71 cygwin*)
72 AC_MSG_RESULT([${host_os}])
51 CC=gcc-3 73 CC=gcc-3
52 CFLAGS+=" -mno-cygwin" 74 CFLAGS+=" -mno-cygwin"
53 LDFLAGS+=" -static-libgcc" 75 GLOBAL_LDFLAGS+=" -static-libgcc -lkernel32 -lmsvcrt -lsetupapi"
54 LIBIRECOVERYLDFLAGS=" -lkernel32 -lmsvcrt -lsetupapi" 76 win32=true
55 ;; 77 ;;
56 *) 78 *)
57 LIBIRECOVERYLDFLAGS= 79 AC_MSG_RESULT([${host_os}])
80 AX_PTHREAD([], [AC_MSG_ERROR([pthread is required to build $PACKAGE])])
58 ;; 81 ;;
59esac 82esac
60AC_SUBST(LIBIRECOVERYLDFLAGS) 83AM_CONDITIONAL(WIN32, test x$win32 = xtrue)
61 84
62AC_ARG_WITH([dummy], 85AC_ARG_WITH([dummy],
63 [AS_HELP_STRING([--with-dummy], [Use no USB driver at all [default=no]. This is only useful if you just want to query the device list by product type or hardware model. All other operations are no-ops or will return IRECV_E_UNSUPPORTED.])], 86 [AS_HELP_STRING([--with-dummy], [Use no USB driver at all [default=no]. This is only useful if you just want to query the device list by product type or hardware model. All other operations are no-ops or will return IRECV_E_UNSUPPORTED.])],
@@ -69,61 +92,30 @@ AS_IF([test "x$have_iokit" = "xyes"], [
69 [AS_HELP_STRING([--with-iokit], [Use IOKit instead of libusb on OS X [default=yes]])], 92 [AS_HELP_STRING([--with-iokit], [Use IOKit instead of libusb on OS X [default=yes]])],
70 [], 93 [],
71 [with_iokit=yes]) 94 [with_iokit=yes])
72 ], [] 95 ]
73) 96)
74 97
75AS_IF([test "x$with_dummy" = "xyes"], [ 98AS_IF([test "x$with_dummy" = "xyes"], [
76 AC_DEFINE(USE_DUMMY, 1, [Define if we are using dummy USB driver]) 99 AC_DEFINE(USE_DUMMY, 1, [Define if we are using dummy USB driver])
77 USB_BACKEND="dummy" 100 USB_BACKEND="dummy"
78], [ 101], [
79 AS_IF([test "x$with_iokit" = "xyes" && test "x$have_iokit" = "xyes"] , [ 102 AS_IF([test "x$with_iokit" = "xyes" && test "x$have_iokit" = "xyes"], [
80 AC_DEFINE(HAVE_IOKIT, 1, [Define if we have IOKit]) 103 AC_DEFINE(HAVE_IOKIT, 1, [Define if we have IOKit])
81 USB_BACKEND="IOKit" 104 USB_BACKEND="IOKit"
82 ], 105 ], [
83 [ 106 AS_IF([test "x$win32" = "xtrue"], [
107 USB_BACKEND="win32 native (setupapi)"
108 ], [
84 PKG_CHECK_MODULES(libusb, libusb-1.0 >= $LIBUSB_VERSION) 109 PKG_CHECK_MODULES(libusb, libusb-1.0 >= $LIBUSB_VERSION)
85 USB_BACKEND="libusb `$PKG_CONFIG --modversion libusb-1.0`" 110 USB_BACKEND="libusb `$PKG_CONFIG --modversion libusb-1.0`"
86 LIBUSB_REQUIRED="libusb-1.0 >= $LIBUSB_VERSION" 111 ])
87 AC_SUBST(LIBUSB_REQUIRED) 112 ])
88 ]
89 )
90]) 113])
91 114
92# Checks for header files. 115AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -fvisibility=hidden $PTHREAD_CFLAGS")
93AC_HEADER_STDC 116GLOBAL_LDFLAGS+=" $PTHREAD_LIBS"
94AC_CHECK_HEADERS([stdint.h stdlib.h string.h])
95
96# Checks for typedefs, structures, and compiler characteristics.
97AC_C_CONST
98AC_TYPE_SIZE_T
99AC_TYPE_SSIZE_T
100AC_TYPE_UINT16_T
101AC_TYPE_UINT32_T
102AC_TYPE_UINT8_T
103
104# Checks for library functions.
105AC_FUNC_MALLOC
106AC_FUNC_REALLOC
107AC_CHECK_FUNCS([strcasecmp strdup strerror strndup])
108
109# Check for operating system
110AC_MSG_CHECKING([whether to enable WIN32 build settings])
111case ${host_os} in
112 *mingw32*|*cygwin*)
113 win32=true
114 AC_MSG_RESULT([yes])
115 AC_CHECK_TOOL([WINDRES], [windres], AC_MSG_ERROR([windres not found]))
116 AC_SUBST(WINDRES)
117 ;;
118 *)
119 win32=false
120 AC_MSG_RESULT([no])
121 ;;
122esac
123AM_CONDITIONAL(WIN32, test x$win32 = xtrue)
124
125AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -fvisibility=hidden")
126AC_SUBST(GLOBAL_CFLAGS) 117AC_SUBST(GLOBAL_CFLAGS)
118AC_SUBST(GLOBAL_LDFLAGS)
127 119
128case "$GLOBAL_CFLAGS" in 120case "$GLOBAL_CFLAGS" in
129 *-fvisibility=hidden*) 121 *-fvisibility=hidden*)
diff --git a/include/libirecovery.h b/include/libirecovery.h
index 73fe6f0..201be0d 100644
--- a/include/libirecovery.h
+++ b/include/libirecovery.h
@@ -2,8 +2,8 @@
2 * libirecovery.h 2 * libirecovery.h
3 * Communication to iBoot/iBSS on Apple iOS devices via USB 3 * Communication to iBoot/iBSS on Apple iOS devices via USB
4 * 4 *
5 * Copyright (c) 2012-2019 Nikias Bassen <nikias@gmx.li>
5 * Copyright (c) 2012-2013 Martin Szulecki <m.szulecki@libimobiledevice.org> 6 * Copyright (c) 2012-2013 Martin Szulecki <m.szulecki@libimobiledevice.org>
6 * Copyright (c) 2012-2013 Nikias Bassen
7 * Copyright (c) 2010 Chronic-Dev Team 7 * Copyright (c) 2010 Chronic-Dev Team
8 * Copyright (c) 2010 Joshua Hill 8 * Copyright (c) 2010 Joshua Hill
9 * 9 *
@@ -27,7 +27,7 @@ extern "C" {
27 27
28#include <stdint.h> 28#include <stdint.h>
29 29
30enum { 30enum irecv_mode {
31 IRECV_K_RECOVERY_MODE_1 = 0x1280, 31 IRECV_K_RECOVERY_MODE_1 = 0x1280,
32 IRECV_K_RECOVERY_MODE_2 = 0x1281, 32 IRECV_K_RECOVERY_MODE_2 = 0x1281,
33 IRECV_K_RECOVERY_MODE_3 = 0x1282, 33 IRECV_K_RECOVERY_MODE_3 = 0x1282,
@@ -93,14 +93,25 @@ struct irecv_device_info {
93 unsigned int sep_nonce_size; 93 unsigned int sep_nonce_size;
94}; 94};
95 95
96typedef enum {
97 IRECV_DEVICE_ADD = 1,
98 IRECV_DEVICE_REMOVE = 2
99} irecv_device_event_type;
100
101typedef struct {
102 irecv_device_event_type type;
103 enum irecv_mode mode;
104 struct irecv_device_info *device_info;
105} irecv_device_event_t;
106
96typedef struct irecv_client_private irecv_client_private; 107typedef struct irecv_client_private irecv_client_private;
97typedef irecv_client_private* irecv_client_t; 108typedef irecv_client_private* irecv_client_t;
98 109
99/* library */ 110/* library */
100void irecv_set_debug_level(int level); 111void irecv_set_debug_level(int level);
101const char* irecv_strerror(irecv_error_t error); 112const char* irecv_strerror(irecv_error_t error);
102void irecv_init(void); 113void irecv_init(void); /* deprecated: libirecovery has constructor now */
103void irecv_exit(void); 114void irecv_exit(void); /* deprecated: libirecovery has destructor now */
104 115
105/* device connectivity */ 116/* device connectivity */
106irecv_error_t irecv_open_with_ecid(irecv_client_t* client, unsigned long long ecid); 117irecv_error_t irecv_open_with_ecid(irecv_client_t* client, unsigned long long ecid);
@@ -123,6 +134,10 @@ int irecv_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, u
123int irecv_usb_bulk_transfer(irecv_client_t client, unsigned char endpoint, unsigned char *data, int length, int *transferred, unsigned int timeout); 134int irecv_usb_bulk_transfer(irecv_client_t client, unsigned char endpoint, unsigned char *data, int length, int *transferred, unsigned int timeout);
124 135
125/* events */ 136/* events */
137typedef void(*irecv_device_event_cb_t)(const irecv_device_event_t* event, void *user_data);
138typedef struct irecv_device_event_context* irecv_device_event_context_t;
139irecv_error_t irecv_device_event_subscribe(irecv_device_event_context_t *context, irecv_device_event_cb_t callback, void *user_data);
140irecv_error_t irecv_device_event_unsubscribe(irecv_device_event_context_t context);
126typedef int(*irecv_event_cb_t)(irecv_client_t client, const irecv_event_t* event); 141typedef int(*irecv_event_cb_t)(irecv_client_t client, const irecv_event_t* event);
127irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event_type type, irecv_event_cb_t callback, void *user_data); 142irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event_type type, irecv_event_cb_t callback, void *user_data);
128irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type type); 143irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type type);
diff --git a/src/Makefile.am b/src/Makefile.am
index 73ae945..265c91a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,19 +1,21 @@
1AM_CPPFLAGS = -I$(top_srcdir)/include 1AM_CPPFLAGS = -I$(top_srcdir)/include
2 2
3AM_CFLAGS = \ 3AM_CFLAGS = \
4 $(GLOBAL_CFLAGS) \ 4 $(GLOBAL_CFLAGS) \
5 $(LFS_CFLAGS) \ 5 $(LFS_CFLAGS) \
6 $(libusb_CFLAGS) 6 $(libusb_CFLAGS)
7 7
8AM_LDFLAGS = \ 8AM_LDFLAGS = \
9 $(libusb_LIBS) \ 9 $(GLOBAL_LDFLAGS) \
10 $(LIBIRECOVERYLDFLAGS) 10 $(libusb_LIBS)
11 11
12lib_LTLIBRARIES = libirecovery.la 12lib_LTLIBRARIES = libirecovery.la
13libirecovery_la_CFLAGS = $(AM_CFLAGS) 13libirecovery_la_CFLAGS = $(AM_CFLAGS)
14libirecovery_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBIRECOVERY_SO_VERSION) -no-undefined 14libirecovery_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBIRECOVERY_SO_VERSION) -no-undefined
15libirecovery_la_SOURCES = libirecovery.c 15libirecovery_la_SOURCES = libirecovery.c \
16 utils.c utils.h \
17 thread.c thread.h
16 18
17if WIN32 19if WIN32
18libirecovery_la_LDFLAGS += -avoid-version 20libirecovery_la_LDFLAGS += -avoid-version
19endif \ No newline at end of file 21endif
diff --git a/src/libirecovery.c b/src/libirecovery.c
index be3ee35..5b86786 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -2,7 +2,7 @@
2 * libirecovery.c 2 * libirecovery.c
3 * Communication to iBoot/iBSS on Apple iOS devices via USB 3 * Communication to iBoot/iBSS on Apple iOS devices via USB
4 * 4 *
5 * Copyright (c) 2011-2017 Nikias Bassen 5 * Copyright (c) 2011-2019 Nikias Bassen <nikias@gmx.li>
6 * Copyright (c) 2012-2015 Martin Szulecki <martin.szulecki@libimobiledevice.org> 6 * Copyright (c) 2012-2015 Martin Szulecki <martin.szulecki@libimobiledevice.org>
7 * Copyright (c) 2010 Chronic-Dev Team 7 * Copyright (c) 2010 Chronic-Dev Team
8 * Copyright (c) 2010 Joshua Hill 8 * Copyright (c) 2010 Joshua Hill
@@ -35,6 +35,10 @@
35#ifndef WIN32 35#ifndef WIN32
36#ifndef HAVE_IOKIT 36#ifndef HAVE_IOKIT
37#include <libusb.h> 37#include <libusb.h>
38#include <pthread.h>
39#if (defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000102)) || (defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000102))
40#define HAVE_LIBUSB_HOTPLUG_API 1
41#endif
38#else 42#else
39#include <CoreFoundation/CoreFoundation.h> 43#include <CoreFoundation/CoreFoundation.h>
40#include <IOKit/usb/IOUSBLib.h> 44#include <IOKit/usb/IOUSBLib.h>
@@ -66,6 +70,8 @@
66#endif 70#endif
67 71
68#include "libirecovery.h" 72#include "libirecovery.h"
73#include "utils.h"
74#include "thread.h"
69 75
70struct irecv_client_private { 76struct irecv_client_private {
71 int debug; 77 int debug;
@@ -287,6 +293,78 @@ static unsigned int crc32_lookup_t1[256] = {
287#define crc32_step(a,b) \ 293#define crc32_step(a,b) \
288 a = (crc32_lookup_t1[(a & 0xFF) ^ ((unsigned char)b)] ^ (a >> 8)) 294 a = (crc32_lookup_t1[(a & 0xFF) ^ ((unsigned char)b)] ^ (a >> 8))
289 295
296static THREAD_T th_event_handler = THREAD_T_NULL;
297struct collection listeners;
298static mutex_t listener_mutex;
299struct collection devices;
300static mutex_t device_mutex;
301#ifndef WIN32
302#ifdef HAVE_IOKIT
303static CFRunLoopRef iokit_runloop = NULL;
304#else
305static libusb_context* irecv_hotplug_ctx = NULL;
306#endif
307#endif
308
309static void _irecv_init(void)
310{
311#ifndef USE_DUMMY
312#ifndef WIN32
313#ifndef HAVE_IOKIT
314 libusb_init(&libirecovery_context);
315#endif
316#endif
317 collection_init(&listeners);
318 mutex_init(&listener_mutex);
319#endif
320}
321
322static void _irecv_deinit(void)
323{
324#ifndef USE_DUMMY
325#ifndef WIN32
326#ifndef HAVE_IOKIT
327 if (libirecovery_context != NULL) {
328 libusb_exit(libirecovery_context);
329 libirecovery_context = NULL;
330 }
331#endif
332#endif
333 collection_free(&listeners);
334 mutex_destroy(&listener_mutex);
335#endif
336}
337
338static thread_once_t init_once = THREAD_ONCE_INIT;
339static thread_once_t deinit_once = THREAD_ONCE_INIT;
340
341#ifdef WIN32
342BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
343{
344 switch (dwReason) {
345 case DLL_PROCESS_ATTACH:
346 thread_once(&init_once, _irecv_init);
347 break;
348 case DLL_PROCESS_DETACH:
349 thread_once(&deinit_once, _irecv_deinit);
350 break;
351 default:
352 break;
353 }
354 return 1;
355}
356#else
357static void __attribute__((constructor)) libirecovery_initialize(void)
358{
359 thread_once(&init_once, _irecv_init);
360}
361
362static void __attribute__((destructor)) libirecovery_deinitialize(void)
363{
364 thread_once(&deinit_once, _irecv_deinit);
365}
366#endif
367
290#ifdef HAVE_IOKIT 368#ifdef HAVE_IOKIT
291static int iokit_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size) { 369static int iokit_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size) {
292 370
@@ -794,27 +872,14 @@ static int check_context(irecv_client_t client) {
794} 872}
795#endif 873#endif
796 874
797IRECV_API void irecv_init(void) { 875IRECV_API void irecv_init(void)
798#ifndef USE_DUMMY 876{
799#ifndef WIN32 877 thread_once(&init_once, _irecv_init);
800#ifndef HAVE_IOKIT
801 libusb_init(&libirecovery_context);
802#endif
803#endif
804#endif
805} 878}
806 879
807IRECV_API void irecv_exit(void) { 880IRECV_API void irecv_exit(void)
808#ifndef USE_DUMMY 881{
809#ifndef WIN32 882 thread_once(&deinit_once, _irecv_deinit);
810#ifndef HAVE_IOKIT
811 if (libirecovery_context != NULL) {
812 libusb_exit(libirecovery_context);
813 libirecovery_context = NULL;
814 }
815#endif
816#endif
817#endif
818} 883}
819 884
820#ifndef USE_DUMMY 885#ifndef USE_DUMMY
@@ -1114,8 +1179,8 @@ static irecv_error_t iokit_open_with_ecid(irecv_client_t* pclient, unsigned long
1114 CFRange range; 1179 CFRange range;
1115 1180
1116 UInt16 wtf_pids[] = { IRECV_K_WTF_MODE, 0}; 1181 UInt16 wtf_pids[] = { IRECV_K_WTF_MODE, 0};
1117 UInt16 all_pids[] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_2, 0 }; // 0x1222, 0x1227, 0x1281 1182 UInt16 all_pids[] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, 0 };
1118UInt16 *pids = all_pids; 1183 UInt16 *pids = all_pids;
1119 int i; 1184 int i;
1120 1185
1121 if (pclient == NULL) { 1186 if (pclient == NULL) {
@@ -1187,12 +1252,14 @@ IRECV_API irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned l
1187#ifdef USE_DUMMY 1252#ifdef USE_DUMMY
1188 return IRECV_E_UNSUPPORTED; 1253 return IRECV_E_UNSUPPORTED;
1189#else 1254#else
1255 int ret = IRECV_E_UNABLE_TO_CONNECT;
1256
1190 if(libirecovery_debug) { 1257 if(libirecovery_debug) {
1191 irecv_set_debug_level(libirecovery_debug); 1258 irecv_set_debug_level(libirecovery_debug);
1192 } 1259 }
1193#ifndef WIN32 1260#ifndef WIN32
1194#ifdef HAVE_IOKIT 1261#ifdef HAVE_IOKIT
1195 return iokit_open_with_ecid(pclient, ecid); 1262 ret = iokit_open_with_ecid(pclient, ecid);
1196#else 1263#else
1197 int i = 0; 1264 int i = 0;
1198 struct libusb_device* usb_device = NULL; 1265 struct libusb_device* usb_device = NULL;
@@ -1297,15 +1364,13 @@ IRECV_API irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned l
1297 1364
1298 libusb_free_device_list(usb_device_list, 1); 1365 libusb_free_device_list(usb_device_list, 1);
1299 1366
1300 return IRECV_E_SUCCESS; 1367 ret = IRECV_E_SUCCESS;
1301 } 1368 }
1302 } 1369 }
1303 } 1370 }
1304
1305 return IRECV_E_UNABLE_TO_CONNECT;
1306#endif 1371#endif
1307#else 1372#else
1308 int ret = mobiledevice_connect(pclient, ecid); 1373 ret = mobiledevice_connect(pclient, ecid);
1309 if (ret == IRECV_E_SUCCESS) { 1374 if (ret == IRECV_E_SUCCESS) {
1310 irecv_client_t client = *pclient; 1375 irecv_client_t client = *pclient;
1311 int error = IRECV_E_SUCCESS; 1376 int error = IRECV_E_SUCCESS;
@@ -1321,9 +1386,18 @@ IRECV_API irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned l
1321 debug("WARNING: set interface failed, error %d\n", error); 1386 debug("WARNING: set interface failed, error %d\n", error);
1322 } 1387 }
1323 } 1388 }
1324
1325 return ret;
1326#endif 1389#endif
1390 if (ret == IRECV_E_SUCCESS) {
1391 if ((*pclient)->connected_callback != NULL) {
1392 irecv_event_t event;
1393 event.size = 0;
1394 event.data = NULL;
1395 event.progress = 0;
1396 event.type = IRECV_CONNECTED;
1397 (*pclient)->connected_callback(*pclient, &event);
1398 }
1399 }
1400 return ret;
1327#endif 1401#endif
1328} 1402}
1329 1403
@@ -1609,6 +1683,619 @@ IRECV_API irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_eve
1609#endif 1683#endif
1610} 1684}
1611 1685
1686#ifndef USE_DUMMY
1687struct irecv_device_event_context {
1688 irecv_device_event_cb_t callback;
1689 void *user_data;
1690};
1691
1692struct irecv_usb_device_info {
1693 struct irecv_device_info device_info;
1694 uint32_t location;
1695 int alive;
1696};
1697
1698#ifdef WIN32
1699struct irecv_win_dev_ctx {
1700 PSP_DEVICE_INTERFACE_DETAIL_DATA details;
1701 uint32_t location;
1702};
1703#else
1704#ifdef HAVE_IOKIT
1705struct irecv_iokit_dev_ctx {
1706 io_service_t device;
1707 IOUSBDeviceInterface **dev;
1708};
1709#endif
1710#endif
1711
1712static int _irecv_is_recovery_device(void *device)
1713{
1714 uint16_t vendor_id = 0;
1715 uint16_t product_id = 0;
1716#ifdef WIN32
1717 const char *path = (const char*)device;
1718 unsigned int vendor = 0;
1719 unsigned int product = 0;
1720 if (sscanf(path, "\\usb#vid_%04x&pid_%04x#", &vendor, &product) != 2) {
1721 return 0;
1722 }
1723 vendor_id = (uint16_t)vendor;
1724 product_id = (uint16_t)product;
1725#else
1726#ifdef HAVE_IOKIT
1727 kern_return_t kr;
1728 IOUSBDeviceInterface **dev = device;
1729 kr = (*dev)->GetDeviceVendor(dev, &vendor_id);
1730 kr = (*dev)->GetDeviceProduct(dev, &product_id);
1731#else
1732 libusb_device *device_ = (libusb_device*)device;
1733 struct libusb_device_descriptor devdesc;
1734 int libusb_error;
1735
1736 libusb_error = libusb_get_device_descriptor(device_, &devdesc);
1737 if (libusb_error != 0) {
1738 debug("%s: failed to get device descriptor: %s\n", __func__, libusb_error_name(libusb_error));
1739 return 0;
1740 }
1741 vendor_id = devdesc.idVendor;
1742 product_id = devdesc.idProduct;
1743#endif
1744#endif
1745
1746 if (vendor_id != APPLE_VENDOR_ID) {
1747 return 0;
1748 }
1749
1750 switch (product_id) {
1751 case IRECV_K_DFU_MODE:
1752 case IRECV_K_WTF_MODE:
1753 case IRECV_K_RECOVERY_MODE_1:
1754 case IRECV_K_RECOVERY_MODE_2:
1755 case IRECV_K_RECOVERY_MODE_3:
1756 case IRECV_K_RECOVERY_MODE_4:
1757 break;
1758 default:
1759 return 0;
1760 }
1761 return 1;
1762}
1763
1764static void* _irecv_handle_device_add(void *userdata)
1765{
1766 struct irecv_client_private client_loc;
1767 char serial_str[256];
1768 uint32_t location = 0;
1769 uint16_t product_id = 0;
1770
1771 serial_str[0] = '\0';
1772#ifdef WIN32
1773 struct irecv_win_dev_ctx *win_ctx = (struct irecv_win_dev_ctx*)userdata;
1774 PSP_DEVICE_INTERFACE_DETAIL_DATA details = win_ctx->details;
1775 LPSTR result = (LPSTR)details->DevicePath;
1776 location = win_ctx->location;
1777
1778 char *p = result + strlen(result) - 1;
1779 while (p-- && p > result) {
1780 if (*p == '\\' && (strncmp(p, "\\usb", 4) == 0)) {
1781 break;
1782 }
1783 }
1784
1785 unsigned int pid = 0;
1786 if (!p || (sscanf(p, "\\usb#vid_%*04x&pid_%04x#%s", &pid, serial_str) != 2) || (serial_str[0] == '\0')) {
1787 fprintf(stderr, "%s: ERROR: failed to parse DevicePath?!\n", __func__);
1788 return NULL;
1789 }
1790 if (!_irecv_is_recovery_device(p)) {
1791 return NULL;
1792 }
1793
1794 p = strchr(serial_str, '#');
1795 if (p) {
1796 *p = '\0';
1797 }
1798
1799 unsigned int j;
1800 for (j = 0; j < strlen(serial_str); j++) {
1801 if (serial_str[j] == '_') {
1802 serial_str[j] = ' ';
1803 } else {
1804 serial_str[j] = toupper(serial_str[j]);
1805 }
1806 }
1807 product_id = (uint16_t)pid;
1808
1809#else /* !WIN32 */
1810#ifdef HAVE_IOKIT
1811 struct irecv_iokit_dev_ctx* iokit_ctx = (struct irecv_iokit_dev_ctx*)userdata;
1812 io_service_t device = iokit_ctx->device;
1813 IOUSBDeviceInterface **dev = iokit_ctx->dev;
1814
1815 if (!device) {
1816 fprintf(stderr, "%s: ERROR: no device?!\n", __func__);
1817 return NULL;
1818 }
1819 if (!dev) {
1820 fprintf(stderr, "%s: ERROR: no device interface?!\n", __func__);
1821 return NULL;
1822 }
1823
1824 (*dev)->GetDeviceProduct(dev, &product_id);
1825 if (!product_id) {
1826 fprintf(stderr, "%s: ERROR: could not get product id?!\n", __func__);
1827 return NULL;
1828 }
1829 CFNumberRef locationNum = (CFNumberRef)IORegistryEntryCreateCFProperty(device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0);
1830 if (locationNum) {
1831 CFNumberGetValue(locationNum, kCFNumberSInt32Type, &location);
1832 CFRelease(locationNum);
1833 }
1834 if (!location) {
1835 fprintf(stderr, "%s: ERROR: could not get locationID?!\n", __func__);
1836 return NULL;
1837 }
1838 CFStringRef serialString = (CFStringRef)IORegistryEntryCreateCFProperty(device, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0);
1839 if (serialString) {
1840 CFStringGetCString(serialString, serial_str, sizeof(serial_str), kCFStringEncodingUTF8);
1841 CFRelease(serialString);
1842 }
1843#else /* !HAVE_IOKIT */
1844 libusb_device *device = (libusb_device*)userdata;
1845 struct libusb_device_descriptor devdesc;
1846 struct libusb_device_handle* usb_handle = NULL;
1847 int libusb_error;
1848
1849 libusb_error = libusb_get_device_descriptor(device, &devdesc);
1850 if (libusb_error != 0) {
1851 fprintf(stderr, "%s: ERROR: failed to get device descriptor: %s\n", __func__, libusb_error_name(libusb_error));
1852 return NULL;
1853 }
1854 product_id = devdesc.idProduct;
1855
1856 uint8_t bus = libusb_get_bus_number(device);
1857 uint8_t address = libusb_get_device_address(device);
1858 location = (bus << 16) | address;
1859
1860 libusb_error = libusb_open(device, &usb_handle);
1861 if (usb_handle == NULL || libusb_error != 0) {
1862 fprintf(stderr, "%s: ERROR: can't connect to device: %s\n", __func__, libusb_error_name(libusb_error));
1863 libusb_close(usb_handle);
1864 return 0;
1865 }
1866
1867 libusb_error = libusb_get_string_descriptor_ascii(usb_handle, devdesc.iSerialNumber, (unsigned char*)serial_str, 255);
1868 if (libusb_error < 0) {
1869 fprintf(stderr, "%s: Failed to get string descriptor: %s\n", __func__, libusb_error_name(libusb_error));
1870 return 0;
1871 }
1872 libusb_close(usb_handle);
1873#endif /* !HAVE_IOKIT */
1874#endif /* !WIN32 */
1875 memset(&client_loc, '\0', sizeof(client_loc));
1876 irecv_load_device_info_from_iboot_string(&client_loc, serial_str);
1877 client_loc.mode = product_id;
1878
1879 struct irecv_usb_device_info *usb_dev_info = (struct irecv_usb_device_info*)malloc(sizeof(struct irecv_usb_device_info));
1880 memcpy(&(usb_dev_info->device_info), &(client_loc.device_info), sizeof(struct irecv_device_info));
1881 usb_dev_info->location = location;
1882 usb_dev_info->alive = 1;
1883
1884 collection_add(&devices, usb_dev_info);
1885
1886 irecv_device_event_t dev_event;
1887 dev_event.type = IRECV_DEVICE_ADD;
1888 dev_event.mode = client_loc.mode;
1889 dev_event.device_info = &(usb_dev_info->device_info);
1890
1891 mutex_lock(&listener_mutex);
1892 FOREACH(struct irecv_device_event_context* context, &listeners) {
1893 context->callback(&dev_event, context->user_data);
1894 } ENDFOREACH
1895 mutex_unlock(&listener_mutex);
1896
1897 return NULL;
1898}
1899
1900static void _irecv_handle_device_remove(struct irecv_usb_device_info *devinfo)
1901{
1902 irecv_device_event_t dev_event;
1903 dev_event.type = IRECV_DEVICE_REMOVE;
1904 dev_event.mode = 0;
1905 dev_event.device_info = &(devinfo->device_info);
1906 mutex_lock(&listener_mutex);
1907 FOREACH(struct irecv_device_event_context* context, &listeners) {
1908 context->callback(&dev_event, context->user_data);
1909 } ENDFOREACH
1910 mutex_unlock(&listener_mutex);
1911 free(devinfo->device_info.srnm);
1912 free(devinfo->device_info.imei);
1913 devinfo->device_info.srnm = NULL;
1914 devinfo->device_info.imei = NULL;
1915 devinfo->alive = 0;
1916 collection_remove(&devices, devinfo);
1917 free(devinfo);
1918}
1919
1920#ifndef WIN32
1921#ifdef HAVE_IOKIT
1922static void iokit_device_added(void *refcon, io_iterator_t iterator)
1923{
1924 kern_return_t kr;
1925 io_service_t device;
1926 IOCFPlugInInterface **plugInInterface = NULL;
1927 IOUSBDeviceInterface **dev = NULL;
1928 HRESULT result;
1929 SInt32 score;
1930
1931 while ((device = IOIteratorNext(iterator))) {
1932 kr = IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score);
1933 if ((kIOReturnSuccess != kr) || !plugInInterface) {
1934 fprintf(stderr, "%s: ERROR: Unable to create a plug-in (%08x)\n", __func__, kr);
1935 kr = IOObjectRelease(device);
1936 continue;
1937 }
1938 result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID *)&dev);
1939 (*plugInInterface)->Release(plugInInterface);
1940
1941 if (result || !dev) {
1942 fprintf(stderr, "%s: ERROR: Couldn't create a device interface (%08x)\n", __func__, (int)result);
1943 kr = IOObjectRelease(device);
1944 continue;
1945 }
1946
1947 if (!_irecv_is_recovery_device(dev)) {
1948 (void) (*dev)->Release(dev);
1949 kr = IOObjectRelease(device);
1950 continue;
1951 }
1952
1953 struct irecv_iokit_dev_ctx idev;
1954 idev.device = device;
1955 idev.dev = dev;
1956 _irecv_handle_device_add(&idev);
1957 (void) (*dev)->Release(dev);
1958 kr = IOObjectRelease(device);
1959 }
1960}
1961
1962static void iokit_device_removed(void *refcon, io_iterator_t iterator)
1963{
1964 io_service_t device;
1965
1966 while ((device = IOIteratorNext(iterator))) {
1967 uint32_t location = 0;
1968 CFNumberRef locationNum = (CFNumberRef)IORegistryEntryCreateCFProperty(device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0);
1969 if (locationNum) {
1970 CFNumberGetValue(locationNum, kCFNumberSInt32Type, &location);
1971 CFRelease(locationNum);
1972 }
1973 IOObjectRelease(device);
1974
1975 if (!location) {
1976 continue;
1977 }
1978
1979 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
1980 if (devinfo->location == location) {
1981 _irecv_handle_device_remove(devinfo);
1982 break;
1983 }
1984 } ENDFOREACH
1985 }
1986}
1987#else /* !HAVE_IOKIT */
1988#ifdef HAVE_LIBUSB_HOTPLUG_API
1989static int _irecv_usb_hotplug_cb(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event, void *user_data)
1990{
1991 if (!_irecv_is_recovery_device(device)) {
1992 return 0;
1993 }
1994 if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
1995 THREAD_T th_device;
1996 if (thread_new(&th_device, _irecv_handle_device_add, device) != 0) {
1997 fprintf(stderr, "%s: FATAL: failed to create thread to handle device add\n", __func__);
1998 return 0;
1999 }
2000 thread_detach(th_device);
2001 } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
2002 uint8_t bus = libusb_get_bus_number(device);
2003 uint8_t address = libusb_get_device_address(device);
2004 uint32_t location = (bus << 16) | address;
2005 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2006 if (devinfo->location == location) {
2007 _irecv_handle_device_remove(devinfo);
2008 break;
2009 }
2010 } ENDFOREACH
2011 }
2012
2013 return 0;
2014}
2015#endif /* HAVE_LIBUSB_HOTPLUG_API */
2016#endif /* !HAVE_IOKIT */
2017#endif /* !WIN32 */
2018
2019static void *_irecv_event_handler(void* unused)
2020{
2021#ifdef WIN32
2022 const GUID *guids[] = { &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL };
2023 int running = 1;
2024 do {
2025 SP_DEVICE_INTERFACE_DATA currentInterface;
2026 HDEVINFO usbDevices;
2027 DWORD i;
2028 int k;
2029 for (k = 0; guids[k]; k++) {
2030 usbDevices = SetupDiGetClassDevs(guids[k], NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
2031 if (!usbDevices) {
2032 fprintf(stderr, "%s: ERROR: SetupDiGetClassDevs failed\n", __func__);
2033 return NULL;
2034 }
2035
2036 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2037 devinfo->alive = 0;
2038 } ENDFOREACH
2039
2040 memset(&currentInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA));
2041 currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2042 for (i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, guids[k], i, &currentInterface); i++) {
2043 DWORD requiredSize = 0;
2044 PSP_DEVICE_INTERFACE_DETAIL_DATA details;
2045 SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, NULL, 0, &requiredSize, NULL);
2046 details = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredSize);
2047 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
2048 SP_DEVINFO_DATA devinfodata;
2049 devinfodata.cbSize = sizeof(SP_DEVINFO_DATA);
2050 if(!SetupDiGetDeviceInterfaceDetail(usbDevices, &currentInterface, details, requiredSize, NULL, &devinfodata)) {
2051 free(details);
2052 continue;
2053 }
2054
2055 DWORD sz = REG_SZ;
2056 char driver[256];
2057 driver[0] = '\0';
2058 if (!SetupDiGetDeviceRegistryProperty(usbDevices, &devinfodata, SPDRP_DRIVER, &sz, (PBYTE)driver, sizeof(driver), NULL)) {
2059 fprintf(stderr, "%s: ERROR: Failed to get driver key\n", __func__);
2060 free(details);
2061 continue;
2062 }
2063 char *p = strrchr(driver, '\\');
2064 if (!p) {
2065 fprintf(stderr, "%s: ERROR: Failed to parse device location\n", __func__);
2066 free(details);
2067 continue;
2068 }
2069 uint32_t location = strtoul(p+1, NULL, 10);
2070 int found = 0;
2071
2072 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2073 if (devinfo->location == location) {
2074 devinfo->alive = 1;
2075 found = 1;
2076 break;
2077 }
2078 } ENDFOREACH
2079
2080 if (!found) {
2081 struct irecv_win_dev_ctx win_ctx;
2082 win_ctx.details = details;
2083 win_ctx.location = location;
2084 _irecv_handle_device_add(&win_ctx);
2085 }
2086 free(details);
2087 }
2088 SetupDiDestroyDeviceInfoList(usbDevices);
2089 }
2090
2091 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2092 if (!devinfo->alive) {
2093 _irecv_handle_device_remove(devinfo);
2094 }
2095 } ENDFOREACH
2096
2097 mutex_lock(&listener_mutex);
2098 if (collection_count(&listeners) == 0) {
2099 running = 0;
2100 }
2101 mutex_unlock(&listener_mutex);
2102
2103 Sleep(500);
2104 } while (running);
2105
2106#else /* !WIN32 */
2107#ifdef HAVE_IOKIT
2108 kern_return_t kr;
2109
2110 IONotificationPortRef notifyPort = IONotificationPortCreate(kIOMasterPortDefault);
2111 CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource(notifyPort);
2112 iokit_runloop = CFRunLoopGetCurrent();
2113 CFRunLoopAddSource(iokit_runloop, runLoopSource, kCFRunLoopDefaultMode);
2114
2115 uint16_t pids[7] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, 0 };
2116 int i = 0;
2117 while (pids[i] > 0) {
2118 CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
2119 iokit_cfdictionary_set_short(matchingDict, CFSTR(kUSBVendorID), kAppleVendorID);
2120 iokit_cfdictionary_set_short(matchingDict, CFSTR(kUSBProductID), pids[i]);
2121
2122 matchingDict = (CFMutableDictionaryRef)CFRetain(matchingDict);
2123
2124 io_iterator_t devAddedIter;
2125 kr = IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, matchingDict, iokit_device_added, NULL, &devAddedIter);
2126 iokit_device_added(NULL, devAddedIter);
2127
2128 io_iterator_t devRemovedIter;
2129 kr = IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, matchingDict, iokit_device_removed, NULL, &devRemovedIter);
2130 iokit_device_removed(NULL, devRemovedIter);
2131
2132 i++;
2133 }
2134
2135 CFRunLoopRun();
2136
2137#else /* !HAVE_IOKIT */
2138#ifdef HAVE_LIBUSB_HOTPLUG_API
2139 static libusb_hotplug_callback_handle usb_hotplug_cb_handle;
2140 libusb_hotplug_register_callback(irecv_hotplug_ctx, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, LIBUSB_HOTPLUG_ENUMERATE, APPLE_VENDOR_ID, LIBUSB_HOTPLUG_MATCH_ANY, 0, _irecv_usb_hotplug_cb, NULL, &usb_hotplug_cb_handle);
2141 int running = 1;
2142 do {
2143 struct timeval tv;
2144 tv.tv_sec = tv.tv_usec = 0;
2145 libusb_handle_events_timeout(irecv_hotplug_ctx, &tv);
2146
2147 mutex_lock(&listener_mutex);
2148 if (collection_count(&listeners) == 0) {
2149 running = 0;
2150 }
2151 mutex_unlock(&listener_mutex);
2152
2153 usleep(100000);
2154 } while (running);
2155 libusb_hotplug_deregister_callback(irecv_hotplug_ctx, usb_hotplug_cb_handle);
2156#else /* !HAVE_LIBUSB_HOTPLUG_API */
2157 int i, cnt;
2158 libusb_device **devs;
2159 int running = 1;
2160
2161 do {
2162 cnt = libusb_get_device_list(irecv_hotplug_ctx, &devs);
2163 if (cnt < 0) {
2164 fprintf(stderr, "%s: FATAL: Failed to get device list: %s\n", __func__, libusb_error_name(cnt));
2165 return NULL;
2166 }
2167
2168 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2169 devinfo->alive = 0;
2170 } ENDFOREACH
2171
2172 for (i = 0; i < cnt; i++) {
2173 libusb_device *dev = devs[i];
2174 if (!_irecv_is_recovery_device(dev)) {
2175 continue;
2176 }
2177 uint8_t bus = libusb_get_bus_number(dev);
2178 uint8_t address = libusb_get_device_address(dev);
2179 uint32_t location = (bus << 16) | address;
2180 int found = 0;
2181 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2182 if (devinfo->location == location) {
2183 devinfo->alive = 1;
2184 found = 1;
2185 break;
2186 }
2187 } ENDFOREACH
2188 if (!found) {
2189 _irecv_handle_device_add(dev);
2190 }
2191 }
2192
2193 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2194 if (!devinfo->alive) {
2195 _irecv_handle_device_remove(devinfo);
2196 }
2197 } ENDFOREACH
2198
2199 libusb_free_device_list(devs, 1);
2200
2201 mutex_lock(&listener_mutex);
2202 if (collection_count(&listeners) == 0) {
2203 running = 0;
2204 }
2205 mutex_unlock(&listener_mutex);
2206 if (!running)
2207 break;
2208 usleep(500000);
2209 } while (running);
2210#endif /* !HAVE_LIBUSB_HOTPLUG_API */
2211#endif /* !HAVE_IOKIT */
2212#endif /* !WIN32 */
2213 return NULL;
2214}
2215#endif /* !USE_DUMMY */
2216
2217IRECV_API irecv_error_t irecv_device_event_subscribe(irecv_device_event_context_t *context, irecv_device_event_cb_t callback, void *user_data)
2218{
2219#ifdef USE_DUMMY
2220 return IRECV_E_UNSUPPORTED;
2221#else
2222 if (!context || !callback)
2223 return IRECV_E_INVALID_INPUT;
2224
2225 struct irecv_device_event_context* _context = malloc(sizeof(struct irecv_device_event_context));
2226 if (!_context) {
2227 return IRECV_E_OUT_OF_MEMORY;
2228 }
2229
2230 _context->callback = callback;
2231 _context->user_data = user_data;
2232
2233 mutex_lock(&listener_mutex);
2234 collection_add(&listeners, _context);
2235 mutex_unlock(&listener_mutex);
2236
2237 if (th_event_handler == THREAD_T_NULL || !thread_alive(th_event_handler)) {
2238#ifndef WIN32
2239#ifndef HAVE_IOKIT
2240 libusb_init(&irecv_hotplug_ctx);
2241#endif
2242#endif
2243 collection_init(&devices);
2244 mutex_init(&device_mutex);
2245 thread_new(&th_event_handler, _irecv_event_handler, NULL);
2246 }
2247
2248 *context = _context;
2249
2250 return IRECV_E_SUCCESS;
2251#endif
2252}
2253
2254IRECV_API irecv_error_t irecv_device_event_unsubscribe(irecv_device_event_context_t context)
2255{
2256#ifdef USE_DUMMY
2257 return IRECV_E_UNSUPPORTED;
2258#else
2259 if (!context)
2260 return IRECV_E_INVALID_INPUT;
2261
2262 mutex_lock(&listener_mutex);
2263 collection_remove(&listeners, context);
2264 int num = collection_count(&listeners);
2265 mutex_unlock(&listener_mutex);
2266
2267 if (num == 0) {
2268#ifdef HAVE_IOKIT
2269 CFRunLoopStop(iokit_runloop);
2270#endif
2271 thread_join(th_event_handler);
2272 thread_free(th_event_handler);
2273 th_event_handler = THREAD_T_NULL;
2274 mutex_lock(&device_mutex);
2275 FOREACH(struct irecv_usb_device_info *devinfo, &devices) {
2276 free(devinfo->device_info.srnm);
2277 free(devinfo->device_info.imei);
2278 devinfo->device_info.srnm = NULL;
2279 devinfo->device_info.imei = NULL;
2280 free(devinfo);
2281 } ENDFOREACH
2282 collection_free(&devices);
2283 mutex_unlock(&device_mutex);
2284 mutex_destroy(&device_mutex);
2285#ifndef WIN32
2286#ifndef HAVE_IOKIT
2287 libusb_exit(irecv_hotplug_ctx);
2288 irecv_hotplug_ctx = NULL;
2289#endif
2290#endif
2291 }
2292
2293 free(context);
2294
2295 return IRECV_E_SUCCESS;
2296#endif
2297}
2298
1612IRECV_API irecv_error_t irecv_close(irecv_client_t client) { 2299IRECV_API irecv_error_t irecv_close(irecv_client_t client) {
1613#ifdef USE_DUMMY 2300#ifdef USE_DUMMY
1614 return IRECV_E_UNSUPPORTED; 2301 return IRECV_E_UNSUPPORTED;
@@ -2432,6 +3119,11 @@ IRECV_API irecv_client_t irecv_reconnect(irecv_client_t client, int initial_paus
2432 irecv_error_t error = 0; 3119 irecv_error_t error = 0;
2433 irecv_client_t new_client = NULL; 3120 irecv_client_t new_client = NULL;
2434 irecv_event_cb_t progress_callback = client->progress_callback; 3121 irecv_event_cb_t progress_callback = client->progress_callback;
3122 irecv_event_cb_t received_callback = client->received_callback;
3123 irecv_event_cb_t connected_callback = client->connected_callback;
3124 irecv_event_cb_t precommand_callback = client->precommand_callback;
3125 irecv_event_cb_t postcommand_callback = client->postcommand_callback;
3126 irecv_event_cb_t disconnected_callback = client->disconnected_callback;
2435 3127
2436 unsigned long long ecid = client->device_info.ecid; 3128 unsigned long long ecid = client->device_info.ecid;
2437 3129
@@ -2450,6 +3142,20 @@ IRECV_API irecv_client_t irecv_reconnect(irecv_client_t client, int initial_paus
2450 } 3142 }
2451 3143
2452 new_client->progress_callback = progress_callback; 3144 new_client->progress_callback = progress_callback;
3145 new_client->received_callback = received_callback;
3146 new_client->connected_callback = connected_callback;
3147 new_client->precommand_callback = precommand_callback;
3148 new_client->postcommand_callback = postcommand_callback;
3149 new_client->disconnected_callback = disconnected_callback;
3150
3151 if (new_client->connected_callback != NULL) {
3152 irecv_event_t event;
3153 event.size = 0;
3154 event.data = NULL;
3155 event.progress = 0;
3156 event.type = IRECV_CONNECTED;
3157 new_client->connected_callback(new_client, &event);
3158 }
2453 3159
2454 return new_client; 3160 return new_client;
2455#endif 3161#endif
diff --git a/tools/irecovery.c b/tools/irecovery.c
index 280be7a..c901633 100644
--- a/tools/irecovery.c
+++ b/tools/irecovery.c
@@ -2,7 +2,7 @@
2 * irecovery.c 2 * irecovery.c
3 * Software frontend for iBoot/iBSS communication with iOS devices 3 * Software frontend for iBoot/iBSS communication with iOS devices
4 * 4 *
5 * Copyright (c) 2012-2017 Nikias Bassen 5 * Copyright (c) 2012-2019 Nikias Bassen <nikias@gmx.li>
6 * Copyright (c) 2012-2015 Martin Szulecki <martin.szulecki@libimobiledevice.org> 6 * Copyright (c) 2012-2015 Martin Szulecki <martin.szulecki@libimobiledevice.org>
7 * Copyright (c) 2010-2011 Chronic-Dev Team 7 * Copyright (c) 2010-2011 Chronic-Dev Team
8 * Copyright (c) 2010-2011 Joshua Hill 8 * Copyright (c) 2010-2011 Joshua Hill
@@ -454,7 +454,6 @@ int main(int argc, char* argv[]) {
454 if (verbose) 454 if (verbose)
455 irecv_set_debug_level(verbose); 455 irecv_set_debug_level(verbose);
456 456
457 irecv_init();
458 irecv_client_t client = NULL; 457 irecv_client_t client = NULL;
459 for (i = 0; i <= 5; i++) { 458 for (i = 0; i <= 5; i++) {
460 debug("Attempting to connect... \n"); 459 debug("Attempting to connect... \n");
@@ -565,7 +564,6 @@ int main(int argc, char* argv[]) {
565 } 564 }
566 565
567 irecv_close(client); 566 irecv_close(client);
568 irecv_exit();
569 567
570 return 0; 568 return 0;
571} 569}