summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2009-05-10 08:27:53 -0700
committerGravatar Matt Colyer2009-05-10 08:28:04 -0700
commit1351b686d450112ae55d26d81d9d59c5f542f12e (patch)
tree442c7e48eb83f96a22f7c6d889e8fe26151d6cba /src
parente91caeb1c9929f9dc8af747bb3a2e52ec06b03af (diff)
downloadlibimobiledevice-1351b686d450112ae55d26d81d9d59c5f542f12e.tar.gz
libimobiledevice-1351b686d450112ae55d26d81d9d59c5f542f12e.tar.bz2
NotificationProxy support added.0.9.0
[#27 state:resolved] Signed-off-by: Matt Colyer <matt@colyer.name>
Diffstat (limited to 'src')
-rw-r--r--src/NotificationProxy.c404
-rw-r--r--src/NotificationProxy.h16
-rw-r--r--src/iphone.c5
-rw-r--r--src/iphone.h2
-rw-r--r--src/lockdown.c13
-rw-r--r--src/usbmux.c31
6 files changed, 359 insertions, 112 deletions
diff --git a/src/NotificationProxy.c b/src/NotificationProxy.c
index bf837bf..d8bcc34 100644
--- a/src/NotificationProxy.c
+++ b/src/NotificationProxy.c
@@ -21,10 +21,16 @@
21 21
22#include <string.h> 22#include <string.h>
23#include <stdio.h> 23#include <stdio.h>
24#include <arpa/inet.h>
24#include <plist/plist.h> 25#include <plist/plist.h>
25#include "NotificationProxy.h" 26#include "NotificationProxy.h"
26#include "utils.h" 27#include "utils.h"
27 28
29struct np_thread {
30 iphone_np_client_t client;
31 iphone_np_notify_cb_t cbfunc;
32};
33
28/** Locks an NP client, done for thread safety stuff. 34/** Locks an NP client, done for thread safety stuff.
29 * 35 *
30 * @param client The NP 36 * @param client The NP
@@ -45,6 +51,54 @@ static void np_unlock(iphone_np_client_t client)
45 g_mutex_unlock(client->mutex); 51 g_mutex_unlock(client->mutex);
46} 52}
47 53
54/**
55 * Sends an xml plist to the device using the connection specified in client.
56 * This function is only used internally.
57 *
58 * @param client NP to send data to
59 * @param dict plist to send
60 *
61 * @return IPHONE_E_SUCCESS or an error code.
62 */
63static iphone_error_t np_plist_send(iphone_np_client_t client, plist_t dict)
64{
65 char *XML_content = NULL;
66 uint32_t length = 0;
67 uint32_t nlen = 0;
68 int bytes = 0;
69 iphone_error_t res = IPHONE_E_UNKNOWN_ERROR;
70
71 if (!client || !dict) {
72 return IPHONE_E_INVALID_ARG;
73 }
74
75 plist_to_xml(dict, &XML_content, &length);
76
77 if (!XML_content || length == 0) {
78 return IPHONE_E_PLIST_ERROR;
79 }
80
81 nlen = htonl(length);
82 iphone_mux_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
83 if (bytes == sizeof(nlen)) {
84 iphone_mux_send(client->connection, XML_content, length, (uint32_t*)&bytes);
85 if (bytes > 0) {
86 if ((uint32_t)bytes == length) {
87 res = IPHONE_E_SUCCESS;
88 } else {
89 log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length);
90 }
91 }
92 }
93 if (bytes <= 0) {
94 log_debug_msg("%s: ERROR: sending to device failed.\n", __func__);
95 }
96
97 free(XML_content);
98
99 return res;
100}
101
48/** Makes a connection to the NP service on the phone. 102/** Makes a connection to the NP service on the phone.
49 * 103 *
50 * @param phone The iPhone to connect on. 104 * @param phone The iPhone to connect on.
@@ -53,7 +107,7 @@ static void np_unlock(iphone_np_client_t client)
53 * 107 *
54 * @return A handle to the newly-connected client or NULL upon error. 108 * @return A handle to the newly-connected client or NULL upon error.
55 */ 109 */
56iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int dst_port, iphone_np_client_t * client) 110iphone_error_t iphone_np_new_client ( iphone_device_t device, int src_port, int dst_port, iphone_np_client_t *client )
57{ 111{
58 int ret = IPHONE_E_SUCCESS; 112 int ret = IPHONE_E_SUCCESS;
59 113
@@ -75,6 +129,8 @@ iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int ds
75 129
76 client_loc->mutex = g_mutex_new(); 130 client_loc->mutex = g_mutex_new();
77 131
132 client_loc->notifier = NULL;
133
78 *client = client_loc; 134 *client = client_loc;
79 return IPHONE_E_SUCCESS; 135 return IPHONE_E_SUCCESS;
80} 136}
@@ -83,91 +139,97 @@ iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int ds
83 * 139 *
84 * @param client The client to disconnect. 140 * @param client The client to disconnect.
85 */ 141 */
86iphone_error_t iphone_np_free_client(iphone_np_client_t client) 142iphone_error_t iphone_np_free_client ( iphone_np_client_t client )
87{ 143{
88 if (!client || !client->connection) 144 if (!client)
89 return IPHONE_E_INVALID_ARG; 145 return IPHONE_E_INVALID_ARG;
90 146
91 iphone_mux_free_client(client->connection); 147 if (client->connection) {
148 iphone_mux_free_client(client->connection);
149 client->connection = NULL;
150 if (client->notifier) {
151 log_debug_msg("joining np callback\n");
152 g_thread_join(client->notifier);
153 }
154 }
155 if (client->mutex) {
156 g_mutex_free(client->mutex);
157 }
92 free(client); 158 free(client);
159
93 return IPHONE_E_SUCCESS; 160 return IPHONE_E_SUCCESS;
94} 161}
95 162
96/** Sends a notification to the NP client. 163/** Sends a notification to the device's Notification Proxy.
97 * 164 *
98 * notification messages seen so far: 165 * notification messages seen so far:
99 * com.apple.itunes-mobdev.syncWillStart 166 * com.apple.itunes-mobdev.syncWillStart
100 * com.apple.itunes-mobdev.syncDidStart 167 * com.apple.itunes-mobdev.syncDidStart
101 * 168 *
102 * @param client The client to send to 169 * @param client The client to send to
103 * @param notification The notification Message 170 * @param notification The notification message to send
104 */ 171 */
105iphone_error_t iphone_np_post_notification(iphone_np_client_t client, const char *notification) 172iphone_error_t iphone_np_post_notification( iphone_np_client_t client, const char *notification )
106{ 173{
107 char *XML_content = NULL;
108 uint32_t length = 0;
109 int bytes = 0;
110 iphone_error_t ret;
111 unsigned char sndbuf[4096];
112 int sndlen = 0;
113 int nlen = 0;
114 plist_t dict = NULL;
115
116 if (!client || !notification) { 174 if (!client || !notification) {
117 return IPHONE_E_INVALID_ARG; 175 return IPHONE_E_INVALID_ARG;
118 } 176 }
119 np_lock(client); 177 np_lock(client);
120 178
121 dict = plist_new_dict(); 179 plist_t dict = plist_new_dict();
122 plist_add_sub_key_el(dict, "Command"); 180 plist_add_sub_key_el(dict, "Command");
123 plist_add_sub_string_el(dict, "PostNotification"); 181 plist_add_sub_string_el(dict, "PostNotification");
124 plist_add_sub_key_el(dict, "Name"); 182 plist_add_sub_key_el(dict, "Name");
125 plist_add_sub_string_el(dict, notification); 183 plist_add_sub_string_el(dict, notification);
126 plist_to_xml(dict, &XML_content, &length);
127
128 nlen = htonl(length);
129
130 memcpy(sndbuf + sndlen, &nlen, 4);
131 sndlen += 4;
132 memcpy(sndbuf + sndlen, XML_content, length);
133 sndlen += length;
134 184
185 iphone_error_t res = np_plist_send(client, dict);
135 plist_free(dict); 186 plist_free(dict);
136 dict = NULL;
137 free(XML_content);
138 XML_content = NULL;
139 187
140 dict = plist_new_dict(); 188 dict = plist_new_dict();
141 plist_add_sub_key_el(dict, "Command"); 189 plist_add_sub_key_el(dict, "Command");
142 plist_add_sub_string_el(dict, "Shutdown"); 190 plist_add_sub_string_el(dict, "Shutdown");
143 plist_to_xml(dict, &XML_content, &length);
144 191
145 nlen = htonl(length); 192 res = np_plist_send(client, dict);
193 plist_free(dict);
146 194
147 memcpy(sndbuf + sndlen, &nlen, 4); 195 if (res != IPHONE_E_SUCCESS) {
148 sndlen += 4; 196 log_debug_msg("%s: Error sending XML plist to device!\n", __func__);
197 }
149 198
150 memcpy(sndbuf + sndlen, XML_content, length); 199 np_unlock(client);
151 sndlen += length; 200 return res;
201}
152 202
153 plist_free(dict); 203/** Notifies the iphone to send a notification on the specified event.
154 dict = NULL; 204 *
155 free(XML_content); 205 * @param client The client to send to
156 XML_content = NULL; 206 * @param notification The notifications that should be observed.
207 */
208iphone_error_t iphone_np_observe_notification( iphone_np_client_t client, const char *notification )
209{
210 if (!client || !notification) {
211 return IPHONE_E_INVALID_ARG;
212 }
213 np_lock(client);
157 214
158 log_debug_buffer(sndbuf, sndlen); 215 plist_t dict = plist_new_dict();
216 plist_add_sub_key_el(dict, "Command");
217 plist_add_sub_string_el(dict, "ObserveNotification");
218 plist_add_sub_key_el(dict, "Name");
219 plist_add_sub_string_el(dict, notification);
159 220
160 iphone_mux_send(client->connection, sndbuf, sndlen, &bytes); 221 iphone_error_t res = np_plist_send(client, dict);
161 if (bytes <= 0) { 222 if (res != IPHONE_E_SUCCESS) {
162 np_unlock(client); 223 log_debug_msg("%s: Error sending XML plist to device!\n", __func__);
163 return bytes;
164 } 224 }
225 plist_free(dict);
165 226
166 np_unlock(client); 227 np_unlock(client);
167 return bytes; 228 return res;
168} 229}
169 230
170/** Notifies the iphone to send a notification on certain events. 231
232/** Notifies the iphone to send a notification on specified events.
171 * 233 *
172 * observation messages seen so far: 234 * observation messages seen so far:
173 * com.apple.itunes-client.syncCancelRequest 235 * com.apple.itunes-client.syncCancelRequest
@@ -181,85 +243,217 @@ iphone_error_t iphone_np_post_notification(iphone_np_client_t client, const char
181 * com.apple.mobile.application_uninstalled 243 * com.apple.mobile.application_uninstalled
182 * 244 *
183 * @param client The client to send to 245 * @param client The client to send to
246 * @param notification_spec Specification of the notifications that should be
247 * observed. This is expected to be an array of const char* that MUST have a
248 * terminating NULL entry. However this parameter can be NULL; in this case,
249 * the default set of notifications will be used.
184 */ 250 */
185iphone_error_t iphone_np_observe_notification(iphone_np_client_t client) 251iphone_error_t iphone_np_observe_notifications( iphone_np_client_t client, const char **notification_spec )
186{ 252{
187 plist_t dict = NULL;
188 char *XML_content = NULL;
189 uint32_t length = 0;
190 int bytes = 0;
191 iphone_error_t ret;
192 unsigned char sndbuf[4096];
193 int sndlen = 0;
194 int nlen = 0;
195 int i = 0; 253 int i = 0;
196 const char *notifications[10] = { 254 iphone_error_t res = IPHONE_E_UNKNOWN_ERROR;
197 "com.apple.itunes-client.syncCancelRequest", 255 const char **notifications = notification_spec;
198 "com.apple.itunes-client.syncSuspendRequest",
199 "com.apple.itunes-client.syncResumeRequest",
200 "com.apple.mobile.lockdown.phone_number_changed",
201 "com.apple.mobile.lockdown.device_name_changed",
202 "com.apple.springboard.attemptactivation",
203 "com.apple.mobile.data_sync.domain_changed",
204 "com.apple.mobile.application_installed",
205 "com.apple.mobile.application_uninstalled",
206 NULL
207 };
208
209 sndlen = 0;
210 256
211 if (!client) { 257 if (!client) {
212 return IPHONE_E_INVALID_ARG; 258 return IPHONE_E_INVALID_ARG;
213 } 259 }
214 np_lock(client); 260
261 if (!notifications) {
262 notifications = np_default_notifications;
263 }
215 264
216 while (notifications[i]) { 265 while (notifications[i]) {
266 res = iphone_np_observe_notification(client, notifications[i]);
267 if (res != IPHONE_E_SUCCESS) {
268 break;
269 }
270 i++;
271 }
272
273 return res;
274}
217 275
218 dict = plist_new_dict(); 276/**
219 plist_add_sub_key_el(dict, "Command"); 277 * Checks if a notification has been sent.
220 plist_add_sub_string_el(dict, "ObserveNotification"); 278 *
221 plist_add_sub_key_el(dict, "Name"); 279 * @param client NP to get a notification from
222 plist_add_sub_string_el(dict, notifications[i++]); 280 * @param notification Pointer to a buffer that will be allocated and filled
223 plist_to_xml(dict, &XML_content, &length); 281 * with the notification that has been received.
224 282 *
225 nlen = htonl(length); 283 * @return IPHONE_E_SUCCESS if a notification has been received,
226 memcpy(sndbuf + sndlen, &nlen, 4); 284 * IPHONE_E_TIMEOUT if nothing has been received,
227 sndlen += 4; 285 * or an error value if an error occured.
228 memcpy(sndbuf + sndlen, XML_content, length); 286 *
229 sndlen += length; 287 * @note You probably want to check out iphone_np_set_notify_callback
230 288 * @see iphone_np_set_notify_callback
231 plist_free(dict); 289 */
232 dict = NULL; 290iphone_error_t iphone_np_get_notification( iphone_np_client_t client, char **notification )
233 free(XML_content); 291{
234 XML_content = NULL; 292 uint32_t bytes = 0;
293 iphone_error_t res;
294 uint32_t pktlen = 0;
295 char *XML_content = NULL;
296 plist_t dict = NULL;
297
298 if (!client || !client->connection || *notification) {
299 return IPHONE_E_INVALID_ARG;
235 } 300 }
236 301
237 dict = plist_new_dict(); 302 np_lock(client);
238 plist_add_sub_key_el(dict, "Command");
239 plist_add_sub_string_el(dict, "Shutdown");
240 plist_to_xml(dict, &XML_content, &length);
241 303
242 nlen = htonl(length); 304 iphone_mux_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 500);
305 log_debug_msg("NotificationProxy: initial read=%i\n", bytes);
306 if (bytes < 4) {
307 log_debug_msg("NotificationProxy: no notification received!\n");
308 res = IPHONE_E_TIMEOUT;
309 } else {
310 if ((char)pktlen == 0) {
311 pktlen = ntohl(pktlen);
312 log_debug_msg("NotificationProxy: %d bytes following\n", pktlen);
313 XML_content = (char*)malloc(pktlen);
314 log_debug_msg("pointer %p\n", XML_content);
315
316 iphone_mux_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000);
317 if (bytes <= 0) {
318 res = IPHONE_E_UNKNOWN_ERROR;
319 } else {
320 log_debug_msg("NotificationProxy: received data:\n");
321 log_debug_buffer(XML_content, pktlen);
322
323 plist_from_xml(XML_content, bytes, &dict);
324 if (!dict) {
325 np_unlock(client);
326 return IPHONE_E_PLIST_ERROR;
327 }
328
329 plist_t cmd_key_node = plist_find_node_by_key(dict, "Command");
330 plist_t cmd_value_node = plist_get_next_sibling(cmd_key_node);
331 char *cmd_value = NULL;
332
333 if (plist_get_node_type(cmd_value_node) == PLIST_STRING) {
334 plist_get_string_val(cmd_value_node, &cmd_value);
335 }
336
337 if (cmd_value && !strcmp(cmd_value, "RelayNotification")) {
338 plist_t name_key_node = plist_get_next_sibling(cmd_value_node);
339 plist_t name_value_node = plist_get_next_sibling(name_key_node);
340
341 char *name_key = NULL;
342 char *name_value = NULL;
343
344 if (plist_get_node_type(name_key_node) == PLIST_KEY) {
345 plist_get_key_val(name_key_node, &name_key);
346 }
347 if (plist_get_node_type(name_value_node) == PLIST_STRING) {
348 plist_get_string_val(name_value_node, &name_value);
349 }
350
351 res = IPHONE_E_PLIST_ERROR;
352 if (name_key && name_value && !strcmp(name_key, "Name")) {
353 *notification = name_value;
354 log_debug_msg("%s: got notification %s\n", __func__, name_value);
355 res = IPHONE_E_SUCCESS;
356 }
357 free(name_key);
358 } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) {
359 log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__);
360 res = IPHONE_E_UNKNOWN_ERROR;
361 } else if (cmd_value) {
362 log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__);
363 res = IPHONE_E_UNKNOWN_ERROR;
364 } else {
365 res = IPHONE_E_PLIST_ERROR;
366 }
367 if (cmd_value) {
368 free(cmd_value);
369 }
370 plist_free(dict);
371 dict = NULL;
372 free(XML_content);
373 XML_content = NULL;
374 }
375 } else {
376 res = IPHONE_E_UNKNOWN_ERROR;
377 }
378 }
243 379
244 memcpy(sndbuf + sndlen, &nlen, 4); 380 np_unlock(client);
245 sndlen += 4;
246 381
247 memcpy(sndbuf + sndlen, XML_content, length); 382 return res;
248 sndlen += length; 383}
249 384
250 plist_free(dict); 385/**
251 dict = NULL; 386 * Internally used thread function.
252 free(XML_content); 387 */
253 XML_content = NULL; 388gpointer iphone_np_notifier( gpointer arg )
389{
390 char *notification = NULL;
391 struct np_thread *npt = (struct np_thread*)arg;
392
393 if (!npt) return NULL;
394
395 log_debug_msg("%s: starting callback.\n", __func__);
396 while (npt->client->connection) {
397 iphone_np_get_notification(npt->client, &notification);
398 if (notification) {
399 npt->cbfunc(notification);
400 free(notification);
401 notification = NULL;
402 }
403 sleep(1);
404 }
405 if (npt) {
406 free(npt);
407 }
254 408
255 log_debug_buffer(sndbuf, sndlen); 409 return NULL;
410}
256 411
257 iphone_mux_send(client->connection, sndbuf, sndlen, &bytes); 412/**
258 if (bytes <= 0) { 413 * This function allows an application to define a callback function that will
259 np_unlock(client); 414 * be called when a notification has been received.
260 return bytes; 415 * It will start a thread that polls for notifications and calls the callback
416 * function if a notification has been received.
417 *
418 * @param client the NP client
419 * @param notify_cb pointer to a callback function or NULL to de-register a
420 * previously set callback function
421 *
422 * @return IPHONE_E_SUCCESS when the callback was successfully registered,
423 * or an error value when an error occured.
424 */
425iphone_error_t iphone_np_set_notify_callback( iphone_np_client_t client, iphone_np_notify_cb_t notify_cb )
426{
427 if (!client) {
428 return IPHONE_E_INVALID_ARG;
429 }
430 iphone_error_t res = IPHONE_E_UNKNOWN_ERROR;
431
432 np_lock(client);
433 if (client->notifier) {
434 log_debug_msg("%s: callback already set, removing\n");
435 iphone_umux_client_t conn = client->connection;
436 client->connection = NULL;
437 g_thread_join(client->notifier);
438 client->notifier = NULL;
439 client->connection = conn;
261 } 440 }
262 441
442 if (notify_cb) {
443 struct np_thread *npt = (struct np_thread*)malloc(sizeof(struct np_thread));
444 if (npt) {
445 npt->client = client;
446 npt->cbfunc = notify_cb;
447
448 client->notifier = g_thread_create(iphone_np_notifier, npt, TRUE, NULL);
449 if (client->notifier) {
450 res = IPHONE_E_SUCCESS;
451 }
452 }
453 } else {
454 log_debug_msg("%s: no callback set\n", __func__);
455 }
263 np_unlock(client); 456 np_unlock(client);
264 return bytes; 457
458 return res;
265} 459}
diff --git a/src/NotificationProxy.h b/src/NotificationProxy.h
index 7b4b48d..3552b79 100644
--- a/src/NotificationProxy.h
+++ b/src/NotificationProxy.h
@@ -27,4 +27,20 @@
27struct iphone_np_client_int { 27struct iphone_np_client_int {
28 iphone_umux_client_t connection; 28 iphone_umux_client_t connection;
29 GMutex *mutex; 29 GMutex *mutex;
30 GThread *notifier;
30}; 31};
32
33static const char *np_default_notifications[10] = {
34 NP_SYNC_SUSPEND_REQUEST,
35 NP_SYNC_RESUME_REQUEST,
36 NP_PHONE_NUMBER_CHANGED,
37 NP_SYNC_CANCEL_REQUEST,
38 NP_DEVICE_NAME_CHANGED,
39 NP_ATTEMPTACTIVATION,
40 NP_DS_DOMAIN_CHANGED,
41 NP_APP_INSTALLED,
42 NP_APP_UNINSTALLED,
43 NULL
44};
45
46gpointer iphone_np_notifier( gpointer arg );
diff --git a/src/iphone.c b/src/iphone.c
index 3c3034e..9dd3c07 100644
--- a/src/iphone.c
+++ b/src/iphone.c
@@ -288,10 +288,11 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen)
288 * @param phone The iPhone to receive data from 288 * @param phone The iPhone to receive data from
289 * @param data Where to put data read 289 * @param data Where to put data read
290 * @param datalen How much data to read in 290 * @param datalen How much data to read in
291 * @param timeout How many milliseconds to wait for data
291 * 292 *
292 * @return How many bytes were read in, or -1 on error. 293 * @return How many bytes were read in, or -1 on error.
293 */ 294 */
294int recv_from_phone(iphone_device_t phone, char *data, int datalen) 295int recv_from_phone(iphone_device_t phone, char *data, int datalen, int timeout)
295{ 296{
296 if (!phone) 297 if (!phone)
297 return -1; 298 return -1;
@@ -301,7 +302,7 @@ int recv_from_phone(iphone_device_t phone, char *data, int datalen)
301 return -1; 302 return -1;
302 log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); 303 log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen);
303 304
304 bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, 3500); 305 bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, timeout);
305 if (bytes < 0) { 306 if (bytes < 0) {
306 log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), 307 log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(),
307 strerror(-bytes)); 308 strerror(-bytes));
diff --git a/src/iphone.h b/src/iphone.h
index 222a1be..15515e3 100644
--- a/src/iphone.h
+++ b/src/iphone.h
@@ -41,5 +41,5 @@ struct iphone_device_int {
41 41
42// Function definitions 42// Function definitions
43int send_to_phone(iphone_device_t phone, char *data, int datalen); 43int send_to_phone(iphone_device_t phone, char *data, int datalen);
44int recv_from_phone(iphone_device_t phone, char *data, int datalen); 44int recv_from_phone(iphone_device_t phone, char *data, int datalen, int timeout);
45#endif 45#endif
diff --git a/src/lockdown.c b/src/lockdown.c
index c017cdf..5ade79a 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -472,6 +472,19 @@ iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, gnu
472 return lockdownd_generic_get_value(control, "Key", "DevicePublicKey", public_key); 472 return lockdownd_generic_get_value(control, "Key", "DevicePublicKey", public_key);
473} 473}
474 474
475/** Askes for the device's name.
476 *
477 * @return IPHONE_E_SUCCESS on succes or an error value < 0 on failure.
478 */
479iphone_error_t lockdownd_get_device_name(iphone_lckd_client_t control, char **device_name)
480{
481 gnutls_datum_t temp = { NULL, 0 };
482 iphone_error_t res = lockdownd_generic_get_value(control, "Key", "DeviceName", &temp);
483 log_debug_msg("%s: %s\n", __func__, temp.data);
484 *device_name = (char*)temp.data;
485 return res;
486}
487
475/** Completes the entire lockdownd handshake. 488/** Completes the entire lockdownd handshake.
476 * 489 *
477 * @param phone The iPhone 490 * @param phone The iPhone
diff --git a/src/usbmux.c b/src/usbmux.c
index 22ce588..7d74b4b 100644
--- a/src/usbmux.c
+++ b/src/usbmux.c
@@ -143,7 +143,7 @@ iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port,
143 if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { 143 if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) {
144 usbmux_tcp_header *response; 144 usbmux_tcp_header *response;
145 response = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); 145 response = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header));
146 bytes = recv_from_phone(device, (char *) response, sizeof(*response)); 146 bytes = recv_from_phone(device, (char *) response, sizeof(*response), 3500);
147 if (response->tcp_flags != 0x12) { 147 if (response->tcp_flags != 0x12) {
148 free(response); 148 free(response);
149 return IPHONE_E_UNKNOWN_ERROR; 149 return IPHONE_E_UNKNOWN_ERROR;
@@ -268,10 +268,13 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui
268 * @param connection The connection to receive data on. 268 * @param connection The connection to receive data on.
269 * @param data Where to put the data we receive. 269 * @param data Where to put the data we receive.
270 * @param datalen How much data to read. 270 * @param datalen How much data to read.
271 * @param recv_bytes Pointer to a uint32_t that will be set
272 * to the number of bytes received.
273 * @param timeout How many milliseconds to wait for data.
271 * 274 *
272 * @return How many bytes were read, or -1 if something bad happens. 275 * @return IPHONE_E_SUCCESS on success, or and error value.
273 */ 276 */
274iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes) 277iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout)
275{ 278{
276 279
277 if (!client || !data || datalen == 0 || !recv_bytes) 280 if (!client || !data || datalen == 0 || !recv_bytes)
@@ -323,7 +326,7 @@ iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t
323 buffer = (char *) malloc(sizeof(char) * 131072); // make sure we get enough ;) 326 buffer = (char *) malloc(sizeof(char) * 131072); // make sure we get enough ;)
324 327
325 // See #3. 328 // See #3.
326 bytes = recv_from_phone(client->phone, buffer, 131072); 329 bytes = recv_from_phone(client->phone, buffer, 131072, timeout);
327 if (bytes < 28) { 330 if (bytes < 28) {
328 free(buffer); 331 free(buffer);
329 log_debug_msg("mux_recv: Did not even get the header.\n"); 332 log_debug_msg("mux_recv: Did not even get the header.\n");
@@ -385,3 +388,23 @@ iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t
385 log_debug_msg("mux_recv: Heisenbug: bytes and datalen not matching up\n"); 388 log_debug_msg("mux_recv: Heisenbug: bytes and datalen not matching up\n");
386 return IPHONE_E_UNKNOWN_ERROR; 389 return IPHONE_E_UNKNOWN_ERROR;
387} 390}
391
392/**
393 * This function is just like 'iphone_mux_recv_timeout' but you do not need
394 * to specify a timeout. It simply calls iphone_mux_recv_timeout with a
395 * timeout value of 3500 milliseconds.
396 *
397 * @param connection The connection to receive data on.
398 * @param data Where to put the data we receive.
399 * @param datalen How much data to read.
400 * @param recv_bytes Pointer to a uint32_t that will be set
401 * to the number of bytes received.
402 *
403 * @return The return value of iphone_mux_recv_timeout.
404 *
405 * @see iphone_mux_recv_timeout
406 */
407iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes)
408{
409 return iphone_mux_recv_timeout(client, data, datalen, recv_bytes, 3500);
410}