diff options
| -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); +} | 
