diff options
author | Nikias Bassen | 2009-05-10 08:27:53 -0700 |
---|---|---|
committer | Matt Colyer | 2009-05-10 08:28:04 -0700 |
commit | 1351b686d450112ae55d26d81d9d59c5f542f12e (patch) | |
tree | 442c7e48eb83f96a22f7c6d889e8fe26151d6cba | |
parent | e91caeb1c9929f9dc8af747bb3a2e52ec06b03af (diff) | |
download | libimobiledevice-0.9.0.tar.gz libimobiledevice-0.9.0.tar.bz2 |
NotificationProxy support added.0.9.0
[#27 state:resolved]
Signed-off-by: Matt Colyer <matt@colyer.name>
-rw-r--r-- | dev/main.c | 95 | ||||
-rw-r--r-- | include/libiphone/libiphone.h | 32 | ||||
-rw-r--r-- | src/NotificationProxy.c | 404 | ||||
-rw-r--r-- | src/NotificationProxy.h | 16 | ||||
-rw-r--r-- | src/iphone.c | 5 | ||||
-rw-r--r-- | src/iphone.h | 2 | ||||
-rw-r--r-- | src/lockdown.c | 13 | ||||
-rw-r--r-- | src/usbmux.c | 31 |
8 files changed, 461 insertions, 137 deletions
@@ -27,26 +27,14 @@ #include <libiphone/libiphone.h> #include "../src/utils.h" -void perform_syncWillStart(iphone_device_t phone, iphone_lckd_client_t control) +void notifier(const char *notification) { - int nport = 0; - iphone_np_client_t np; - - iphone_lckd_start_service(control, "com.apple.mobile.notification_proxy", &nport); - if (nport) { - printf("::::::::::::::: np was started ::::::::::::\n"); - iphone_np_new_client(phone, 3555, nport, &np); - if (np) { - printf("::::::::: PostNotification com.apple.itunes-mobdev.syncWillStart\n"); - iphone_np_post_notification(np, "com.apple.itunes-mobdev.syncWillStart"); - iphone_np_free_client(np); - } - } else { - printf("::::::::::::::: np was NOT started ::::::::::::\n"); - } + printf("---------------------------------------------------------\n"); + printf("------> Notification received: %s\n", notification); + printf("---------------------------------------------------------\n"); } -void perform_syncDidStart(iphone_device_t phone, iphone_lckd_client_t control) +void perform_notification(iphone_device_t phone, iphone_lckd_client_t control, const char *notification) { int nport = 0; iphone_np_client_t np; @@ -54,11 +42,10 @@ void perform_syncDidStart(iphone_device_t phone, iphone_lckd_client_t control) iphone_lckd_start_service(control, "com.apple.mobile.notification_proxy", &nport); if (nport) { printf("::::::::::::::: np was started ::::::::::::\n"); - sleep(1); iphone_np_new_client(phone, 3555, nport, &np); if (np) { - printf("::::::::: PostNotification com.apple.itunes-mobdev.syncDidStart\n"); - iphone_np_post_notification(np, "com.apple.itunes-mobdev.syncDidStart"); + printf("::::::::: PostNotification %s\n", notification); + iphone_np_post_notification(np, notification); iphone_np_free_client(np); } } else { @@ -69,9 +56,11 @@ void perform_syncDidStart(iphone_device_t phone, iphone_lckd_client_t control) int main(int argc, char *argv[]) { int bytes = 0, port = 0, i = 0; + int npp; iphone_lckd_client_t control = NULL; iphone_device_t phone = NULL; iphone_afc_file_t lockfile = NULL; + iphone_np_client_t gnp = NULL; if (argc > 1 && !strcasecmp(argv[1], "--debug")) { iphone_set_debug(1); @@ -88,6 +77,7 @@ int main(int argc, char *argv[]) if (IPHONE_E_SUCCESS != iphone_lckd_new_client(phone, &control)) { iphone_free_device(phone); + printf("Exiting.\n"); return -1; } @@ -97,20 +87,45 @@ int main(int argc, char *argv[]) free(uid); } + + char *nnn = NULL; + if (IPHONE_E_SUCCESS == lockdownd_get_device_name(control, &nnn)) { + printf("DeviceName : %s\n", nnn); + free(nnn); + } + iphone_lckd_start_service(control, "com.apple.afc", &port); if (port) { iphone_afc_client_t afc = NULL; iphone_afc_new_client(phone, 3432, port, &afc); if (afc) { - perform_syncWillStart(phone, control); + iphone_lckd_start_service(control, "com.apple.mobile.notification_proxy", &npp); + if (npp) { + printf("Notification Proxy started.\n"); + iphone_np_new_client(phone, 3756, npp, &gnp); + } else { + printf("ERROR: Notification proxy could not be started.\n"); + } + if (gnp) { + const char *nspec[4] = { + NP_SYNC_CANCEL_REQUEST, + NP_SYNC_SUSPEND_REQUEST, + NP_SYNC_RESUME_REQUEST, + NULL + }; + iphone_np_observe_notifications(gnp, nspec); + //iphone_np_set_notify_callback(gnp, notifier); + } + + perform_notification(phone, control, NP_SYNC_WILL_START); iphone_afc_open_file(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile); if (lockfile) { printf("locking file\n"); iphone_afc_lock_file(afc, lockfile, 2 | 4); - perform_syncDidStart(phone, control); + perform_notification(phone, control, NP_SYNC_DID_START); } char **dirs = NULL; @@ -123,6 +138,8 @@ int main(int argc, char *argv[]) } g_strfreev(dirs); + + dirs = NULL; iphone_afc_get_devinfo(afc, &dirs); if (dirs) { for (i = 0; dirs[i]; i += 2) { @@ -189,9 +206,31 @@ int main(int argc, char *argv[]) iphone_afc_close_file(afc, my_file); } - if (lockfile) { - printf("XXX sleeping 2 seconds\n"); - sleep(2); + if (gnp && lockfile) { + char *noti; + + noti = NULL; + iphone_np_get_notification(gnp, ¬i); + if (noti) { + printf("------> received notification '%s'\n", noti); + free(noti); + } + + printf("XXX sleeping\n"); + for (i = 0; i < 5; i++) { + noti = NULL; + printf("--- getting notification\n"); + iphone_np_get_notification(gnp, ¬i); + if (noti) { + printf("------> received notification '%s'\n", noti); + free(noti); + } else { + printf("---- no notification\n"); + } + sleep(1); + } + + //perform_notification(phone, control, NP_SYNC_DID_FINISH); printf("XXX unlocking file\n"); iphone_afc_lock_file(afc, lockfile, 8 | 4); @@ -199,6 +238,12 @@ int main(int argc, char *argv[]) printf("XXX closing file\n"); iphone_afc_close_file(afc, lockfile); } + + if (gnp) { + iphone_np_free_client(gnp); + gnp = NULL; + } + iphone_afc_free_client(afc); } else { printf("Start service failure.\n"); diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h index a45319f..dedc78f 100644 --- a/include/libiphone/libiphone.h +++ b/include/libiphone/libiphone.h @@ -101,6 +101,7 @@ iphone_error_t iphone_free_device ( iphone_device_t device ); //lockdownd related functions iphone_error_t lockdownd_get_device_uid(iphone_lckd_client_t control, char **uid); +iphone_error_t lockdownd_get_device_name ( iphone_lckd_client_t client, char **device_name ); iphone_error_t iphone_lckd_new_client ( iphone_device_t device, iphone_lckd_client_t *client ); iphone_error_t iphone_lckd_free_client( iphone_lckd_client_t client ); @@ -115,6 +116,7 @@ iphone_error_t iphone_mux_free_client ( iphone_umux_client_t client ); iphone_error_t iphone_mux_send ( iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t *sent_bytes ); iphone_error_t iphone_mux_recv ( iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t *recv_bytes ); +iphone_error_t iphone_mux_recv_timeout ( iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t *recv_bytes, int timeout); //afc related functions @@ -148,6 +150,36 @@ iphone_error_t iphone_msync_free_client(iphone_msync_client_t client); iphone_error_t iphone_msync_recv(iphone_msync_client_t client, plist_t * plist); iphone_error_t iphone_msync_send(iphone_msync_client_t client, plist_t plist); +// NotificationProxy related +// notifications for use with post_notification (client --> device) +#define NP_SYNC_WILL_START "com.apple.itunes-mobdev.syncWillStart" +#define NP_SYNC_DID_START "com.apple.itunes-mobdev.syncDidStart" +#define NP_SYNC_DID_FINISH "com.apple.itunes-mobdev.syncDidFinish" + +// notifications for use with observe_notification (device --> client) +#define NP_SYNC_CANCEL_REQUEST "com.apple.itunes-client.syncCancelRequest" +#define NP_SYNC_SUSPEND_REQUEST "com.apple.itunes-client.syncSuspendRequest" +#define NP_SYNC_RESUME_REQUEST "com.apple.itunes-client.syncResumeRequest" +#define NP_PHONE_NUMBER_CHANGED "com.apple.mobile.lockdown.phone_number_changed" +#define NP_DEVICE_NAME_CHANGED "com.apple.mobile.lockdown.device_name_changed" +#define NP_ATTEMPTACTIVATION "com.apple.springboard.attemptactivation" +#define NP_DS_DOMAIN_CHANGED "com.apple.mobile.data_sync.domain_changed" +#define NP_APP_INSTALLED "com.apple.mobile.application_installed" +#define NP_APP_UNINSTALLED "com.apple.mobile.application_uninstalled" + +iphone_error_t iphone_np_new_client ( iphone_device_t device, int src_port, int dst_port, iphone_np_client_t *client ); +iphone_error_t iphone_np_free_client ( iphone_np_client_t client ); + +iphone_error_t iphone_np_post_notification ( iphone_np_client_t client, const char *notification ); + +iphone_error_t iphone_np_observe_notification ( iphone_np_client_t client, const char *notification ); +iphone_error_t iphone_np_observe_notifications ( iphone_np_client_t client, const char **notification_spec ); +iphone_error_t iphone_np_get_notification ( iphone_np_client_t client, char **notification ); + +typedef void (*iphone_np_notify_cb_t) ( const char *notification ); + +iphone_error_t iphone_np_set_notify_callback ( iphone_np_client_t client, iphone_np_notify_cb_t notify_cb ); + #ifdef __cplusplus } #endif 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 @@ #include <string.h> #include <stdio.h> +#include <arpa/inet.h> #include <plist/plist.h> #include "NotificationProxy.h" #include "utils.h" +struct np_thread { + iphone_np_client_t client; + iphone_np_notify_cb_t cbfunc; +}; + /** Locks an NP client, done for thread safety stuff. * * @param client The NP @@ -45,6 +51,54 @@ static void np_unlock(iphone_np_client_t client) g_mutex_unlock(client->mutex); } +/** + * Sends an xml plist to the device using the connection specified in client. + * This function is only used internally. + * + * @param client NP to send data to + * @param dict plist to send + * + * @return IPHONE_E_SUCCESS or an error code. + */ +static iphone_error_t np_plist_send(iphone_np_client_t client, plist_t dict) +{ + char *XML_content = NULL; + uint32_t length = 0; + uint32_t nlen = 0; + int bytes = 0; + iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; + + if (!client || !dict) { + return IPHONE_E_INVALID_ARG; + } + + plist_to_xml(dict, &XML_content, &length); + + if (!XML_content || length == 0) { + return IPHONE_E_PLIST_ERROR; + } + + nlen = htonl(length); + iphone_mux_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); + if (bytes == sizeof(nlen)) { + iphone_mux_send(client->connection, XML_content, length, (uint32_t*)&bytes); + if (bytes > 0) { + if ((uint32_t)bytes == length) { + res = IPHONE_E_SUCCESS; + } else { + log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length); + } + } + } + if (bytes <= 0) { + log_debug_msg("%s: ERROR: sending to device failed.\n", __func__); + } + + free(XML_content); + + return res; +} + /** Makes a connection to the NP service on the phone. * * @param phone The iPhone to connect on. @@ -53,7 +107,7 @@ static void np_unlock(iphone_np_client_t client) * * @return A handle to the newly-connected client or NULL upon error. */ -iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int dst_port, iphone_np_client_t * client) +iphone_error_t iphone_np_new_client ( iphone_device_t device, int src_port, int dst_port, iphone_np_client_t *client ) { int ret = IPHONE_E_SUCCESS; @@ -75,6 +129,8 @@ iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int ds client_loc->mutex = g_mutex_new(); + client_loc->notifier = NULL; + *client = client_loc; return IPHONE_E_SUCCESS; } @@ -83,91 +139,97 @@ iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int ds * * @param client The client to disconnect. */ -iphone_error_t iphone_np_free_client(iphone_np_client_t client) +iphone_error_t iphone_np_free_client ( iphone_np_client_t client ) { - if (!client || !client->connection) + if (!client) return IPHONE_E_INVALID_ARG; - iphone_mux_free_client(client->connection); + if (client->connection) { + iphone_mux_free_client(client->connection); + client->connection = NULL; + if (client->notifier) { + log_debug_msg("joining np callback\n"); + g_thread_join(client->notifier); + } + } + if (client->mutex) { + g_mutex_free(client->mutex); + } free(client); + return IPHONE_E_SUCCESS; } -/** Sends a notification to the NP client. +/** Sends a notification to the device's Notification Proxy. * * notification messages seen so far: * com.apple.itunes-mobdev.syncWillStart * com.apple.itunes-mobdev.syncDidStart * * @param client The client to send to - * @param notification The notification Message + * @param notification The notification message to send */ -iphone_error_t iphone_np_post_notification(iphone_np_client_t client, const char *notification) +iphone_error_t iphone_np_post_notification( iphone_np_client_t client, const char *notification ) { - char *XML_content = NULL; - uint32_t length = 0; - int bytes = 0; - iphone_error_t ret; - unsigned char sndbuf[4096]; - int sndlen = 0; - int nlen = 0; - plist_t dict = NULL; - if (!client || !notification) { return IPHONE_E_INVALID_ARG; } np_lock(client); - dict = plist_new_dict(); + plist_t dict = plist_new_dict(); plist_add_sub_key_el(dict, "Command"); plist_add_sub_string_el(dict, "PostNotification"); plist_add_sub_key_el(dict, "Name"); plist_add_sub_string_el(dict, notification); - plist_to_xml(dict, &XML_content, &length); - - nlen = htonl(length); - - memcpy(sndbuf + sndlen, &nlen, 4); - sndlen += 4; - memcpy(sndbuf + sndlen, XML_content, length); - sndlen += length; + iphone_error_t res = np_plist_send(client, dict); plist_free(dict); - dict = NULL; - free(XML_content); - XML_content = NULL; dict = plist_new_dict(); plist_add_sub_key_el(dict, "Command"); plist_add_sub_string_el(dict, "Shutdown"); - plist_to_xml(dict, &XML_content, &length); - nlen = htonl(length); + res = np_plist_send(client, dict); + plist_free(dict); - memcpy(sndbuf + sndlen, &nlen, 4); - sndlen += 4; + if (res != IPHONE_E_SUCCESS) { + log_debug_msg("%s: Error sending XML plist to device!\n", __func__); + } - memcpy(sndbuf + sndlen, XML_content, length); - sndlen += length; + np_unlock(client); + return res; +} - plist_free(dict); - dict = NULL; - free(XML_content); - XML_content = NULL; +/** Notifies the iphone to send a notification on the specified event. + * + * @param client The client to send to + * @param notification The notifications that should be observed. + */ +iphone_error_t iphone_np_observe_notification( iphone_np_client_t client, const char *notification ) +{ + if (!client || !notification) { + return IPHONE_E_INVALID_ARG; + } + np_lock(client); - log_debug_buffer(sndbuf, sndlen); + plist_t dict = plist_new_dict(); + plist_add_sub_key_el(dict, "Command"); + plist_add_sub_string_el(dict, "ObserveNotification"); + plist_add_sub_key_el(dict, "Name"); + plist_add_sub_string_el(dict, notification); - iphone_mux_send(client->connection, sndbuf, sndlen, &bytes); - if (bytes <= 0) { - np_unlock(client); - return bytes; + iphone_error_t res = np_plist_send(client, dict); + if (res != IPHONE_E_SUCCESS) { + log_debug_msg("%s: Error sending XML plist to device!\n", __func__); } + plist_free(dict); np_unlock(client); - return bytes; + return res; } -/** Notifies the iphone to send a notification on certain events. + +/** Notifies the iphone to send a notification on specified events. * * observation messages seen so far: * com.apple.itunes-client.syncCancelRequest @@ -181,85 +243,217 @@ iphone_error_t iphone_np_post_notification(iphone_np_client_t client, const char * com.apple.mobile.application_uninstalled * * @param client The client to send to + * @param notification_spec Specification of the notifications that should be + * observed. This is expected to be an array of const char* that MUST have a + * terminating NULL entry. However this parameter can be NULL; in this case, + * the default set of notifications will be used. */ -iphone_error_t iphone_np_observe_notification(iphone_np_client_t client) +iphone_error_t iphone_np_observe_notifications( iphone_np_client_t client, const char **notification_spec ) { - plist_t dict = NULL; - char *XML_content = NULL; - uint32_t length = 0; - int bytes = 0; - iphone_error_t ret; - unsigned char sndbuf[4096]; - int sndlen = 0; - int nlen = 0; int i = 0; - const char *notifications[10] = { - "com.apple.itunes-client.syncCancelRequest", - "com.apple.itunes-client.syncSuspendRequest", - "com.apple.itunes-client.syncResumeRequest", - "com.apple.mobile.lockdown.phone_number_changed", - "com.apple.mobile.lockdown.device_name_changed", - "com.apple.springboard.attemptactivation", - "com.apple.mobile.data_sync.domain_changed", - "com.apple.mobile.application_installed", - "com.apple.mobile.application_uninstalled", - NULL - }; - - sndlen = 0; + iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; + const char **notifications = notification_spec; if (!client) { return IPHONE_E_INVALID_ARG; } - np_lock(client); + + if (!notifications) { + notifications = np_default_notifications; + } while (notifications[i]) { + res = iphone_np_observe_notification(client, notifications[i]); + if (res != IPHONE_E_SUCCESS) { + break; + } + i++; + } + + return res; +} - dict = plist_new_dict(); - plist_add_sub_key_el(dict, "Command"); - plist_add_sub_string_el(dict, "ObserveNotification"); - plist_add_sub_key_el(dict, "Name"); - plist_add_sub_string_el(dict, notifications[i++]); - plist_to_xml(dict, &XML_content, &length); - - nlen = htonl(length); - memcpy(sndbuf + sndlen, &nlen, 4); - sndlen += 4; - memcpy(sndbuf + sndlen, XML_content, length); - sndlen += length; - - plist_free(dict); - dict = NULL; - free(XML_content); - XML_content = NULL; +/** + * Checks if a notification has been sent. + * + * @param client NP to get a notification from + * @param notification Pointer to a buffer that will be allocated and filled + * with the notification that has been received. + * + * @return IPHONE_E_SUCCESS if a notification has been received, + * IPHONE_E_TIMEOUT if nothing has been received, + * or an error value if an error occured. + * + * @note You probably want to check out iphone_np_set_notify_callback + * @see iphone_np_set_notify_callback + */ +iphone_error_t iphone_np_get_notification( iphone_np_client_t client, char **notification ) +{ + uint32_t bytes = 0; + iphone_error_t res; + uint32_t pktlen = 0; + char *XML_content = NULL; + plist_t dict = NULL; + + if (!client || !client->connection || *notification) { + return IPHONE_E_INVALID_ARG; } - dict = plist_new_dict(); - plist_add_sub_key_el(dict, "Command"); - plist_add_sub_string_el(dict, "Shutdown"); - plist_to_xml(dict, &XML_content, &length); + np_lock(client); - nlen = htonl(length); + iphone_mux_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 500); + log_debug_msg("NotificationProxy: initial read=%i\n", bytes); + if (bytes < 4) { + log_debug_msg("NotificationProxy: no notification received!\n"); + res = IPHONE_E_TIMEOUT; + } else { + if ((char)pktlen == 0) { + pktlen = ntohl(pktlen); + log_debug_msg("NotificationProxy: %d bytes following\n", pktlen); + XML_content = (char*)malloc(pktlen); + log_debug_msg("pointer %p\n", XML_content); + + iphone_mux_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000); + if (bytes <= 0) { + res = IPHONE_E_UNKNOWN_ERROR; + } else { + log_debug_msg("NotificationProxy: received data:\n"); + log_debug_buffer(XML_content, pktlen); + + plist_from_xml(XML_content, bytes, &dict); + if (!dict) { + np_unlock(client); + return IPHONE_E_PLIST_ERROR; + } + + plist_t cmd_key_node = plist_find_node_by_key(dict, "Command"); + plist_t cmd_value_node = plist_get_next_sibling(cmd_key_node); + char *cmd_value = NULL; + + if (plist_get_node_type(cmd_value_node) == PLIST_STRING) { + plist_get_string_val(cmd_value_node, &cmd_value); + } + + if (cmd_value && !strcmp(cmd_value, "RelayNotification")) { + plist_t name_key_node = plist_get_next_sibling(cmd_value_node); + plist_t name_value_node = plist_get_next_sibling(name_key_node); + + char *name_key = NULL; + char *name_value = NULL; + + if (plist_get_node_type(name_key_node) == PLIST_KEY) { + plist_get_key_val(name_key_node, &name_key); + } + if (plist_get_node_type(name_value_node) == PLIST_STRING) { + plist_get_string_val(name_value_node, &name_value); + } + + res = IPHONE_E_PLIST_ERROR; + if (name_key && name_value && !strcmp(name_key, "Name")) { + *notification = name_value; + log_debug_msg("%s: got notification %s\n", __func__, name_value); + res = IPHONE_E_SUCCESS; + } + free(name_key); + } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { + log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__); + res = IPHONE_E_UNKNOWN_ERROR; + } else if (cmd_value) { + log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__); + res = IPHONE_E_UNKNOWN_ERROR; + } else { + res = IPHONE_E_PLIST_ERROR; + } + if (cmd_value) { + free(cmd_value); + } + plist_free(dict); + dict = NULL; + free(XML_content); + XML_content = NULL; + } + } else { + res = IPHONE_E_UNKNOWN_ERROR; + } + } - memcpy(sndbuf + sndlen, &nlen, 4); - sndlen += 4; + np_unlock(client); - memcpy(sndbuf + sndlen, XML_content, length); - sndlen += length; + return res; +} - plist_free(dict); - dict = NULL; - free(XML_content); - XML_content = NULL; +/** + * Internally used thread function. + */ +gpointer iphone_np_notifier( gpointer arg ) +{ + char *notification = NULL; + struct np_thread *npt = (struct np_thread*)arg; + + if (!npt) return NULL; + + log_debug_msg("%s: starting callback.\n", __func__); + while (npt->client->connection) { + iphone_np_get_notification(npt->client, ¬ification); + if (notification) { + npt->cbfunc(notification); + free(notification); + notification = NULL; + } + sleep(1); + } + if (npt) { + free(npt); + } - log_debug_buffer(sndbuf, sndlen); + return NULL; +} - iphone_mux_send(client->connection, sndbuf, sndlen, &bytes); - if (bytes <= 0) { - np_unlock(client); - return bytes; +/** + * This function allows an application to define a callback function that will + * be called when a notification has been received. + * It will start a thread that polls for notifications and calls the callback + * function if a notification has been received. + * + * @param client the NP client + * @param notify_cb pointer to a callback function or NULL to de-register a + * previously set callback function + * + * @return IPHONE_E_SUCCESS when the callback was successfully registered, + * or an error value when an error occured. + */ +iphone_error_t iphone_np_set_notify_callback( iphone_np_client_t client, iphone_np_notify_cb_t notify_cb ) +{ + if (!client) { + return IPHONE_E_INVALID_ARG; + } + iphone_error_t res = IPHONE_E_UNKNOWN_ERROR; + + np_lock(client); + if (client->notifier) { + log_debug_msg("%s: callback already set, removing\n"); + iphone_umux_client_t conn = client->connection; + client->connection = NULL; + g_thread_join(client->notifier); + client->notifier = NULL; + client->connection = conn; } + if (notify_cb) { + struct np_thread *npt = (struct np_thread*)malloc(sizeof(struct np_thread)); + if (npt) { + npt->client = client; + npt->cbfunc = notify_cb; + + client->notifier = g_thread_create(iphone_np_notifier, npt, TRUE, NULL); + if (client->notifier) { + res = IPHONE_E_SUCCESS; + } + } + } else { + log_debug_msg("%s: no callback set\n", __func__); + } np_unlock(client); - return bytes; + + return res; } 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 @@ struct iphone_np_client_int { iphone_umux_client_t connection; GMutex *mutex; + GThread *notifier; }; + +static const char *np_default_notifications[10] = { + NP_SYNC_SUSPEND_REQUEST, + NP_SYNC_RESUME_REQUEST, + NP_PHONE_NUMBER_CHANGED, + NP_SYNC_CANCEL_REQUEST, + NP_DEVICE_NAME_CHANGED, + NP_ATTEMPTACTIVATION, + NP_DS_DOMAIN_CHANGED, + NP_APP_INSTALLED, + NP_APP_UNINSTALLED, + NULL +}; + +gpointer 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) * @param phone The iPhone to receive data from * @param data Where to put data read * @param datalen How much data to read in + * @param timeout How many milliseconds to wait for data * * @return How many bytes were read in, or -1 on error. */ -int recv_from_phone(iphone_device_t phone, char *data, int datalen) +int recv_from_phone(iphone_device_t phone, char *data, int datalen, int timeout) { if (!phone) return -1; @@ -301,7 +302,7 @@ int recv_from_phone(iphone_device_t phone, char *data, int datalen) return -1; log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen); - bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, 3500); + bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, timeout); if (bytes < 0) { log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(), 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 { // Function definitions int send_to_phone(iphone_device_t phone, char *data, int datalen); -int recv_from_phone(iphone_device_t phone, char *data, int datalen); +int recv_from_phone(iphone_device_t phone, char *data, int datalen, int timeout); #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 return lockdownd_generic_get_value(control, "Key", "DevicePublicKey", public_key); } +/** Askes for the device's name. + * + * @return IPHONE_E_SUCCESS on succes or an error value < 0 on failure. + */ +iphone_error_t lockdownd_get_device_name(iphone_lckd_client_t control, char **device_name) +{ + gnutls_datum_t temp = { NULL, 0 }; + iphone_error_t res = lockdownd_generic_get_value(control, "Key", "DeviceName", &temp); + log_debug_msg("%s: %s\n", __func__, temp.data); + *device_name = (char*)temp.data; + return res; +} + /** Completes the entire lockdownd handshake. * * @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, if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { usbmux_tcp_header *response; response = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); - bytes = recv_from_phone(device, (char *) response, sizeof(*response)); + bytes = recv_from_phone(device, (char *) response, sizeof(*response), 3500); if (response->tcp_flags != 0x12) { free(response); return IPHONE_E_UNKNOWN_ERROR; @@ -268,10 +268,13 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui * @param connection The connection to receive data on. * @param data Where to put the data we receive. * @param datalen How much data to read. + * @param recv_bytes Pointer to a uint32_t that will be set + * to the number of bytes received. + * @param timeout How many milliseconds to wait for data. * - * @return How many bytes were read, or -1 if something bad happens. + * @return IPHONE_E_SUCCESS on success, or and error value. */ -iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes) +iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout) { 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 buffer = (char *) malloc(sizeof(char) * 131072); // make sure we get enough ;) // See #3. - bytes = recv_from_phone(client->phone, buffer, 131072); + bytes = recv_from_phone(client->phone, buffer, 131072, timeout); if (bytes < 28) { free(buffer); 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 log_debug_msg("mux_recv: Heisenbug: bytes and datalen not matching up\n"); return IPHONE_E_UNKNOWN_ERROR; } + +/** + * This function is just like 'iphone_mux_recv_timeout' but you do not need + * to specify a timeout. It simply calls iphone_mux_recv_timeout with a + * timeout value of 3500 milliseconds. + * + * @param connection The connection to receive data on. + * @param data Where to put the data we receive. + * @param datalen How much data to read. + * @param recv_bytes Pointer to a uint32_t that will be set + * to the number of bytes received. + * + * @return The return value of iphone_mux_recv_timeout. + * + * @see iphone_mux_recv_timeout + */ +iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes) +{ + return iphone_mux_recv_timeout(client, data, datalen, recv_bytes, 3500); +} |