Exemplo n.º 1
0
/**
 * 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 NP_E_SUCCESS when the callback was successfully registered,
 *         or an error value when an error occured.
 */
np_error_t np_set_notify_callback( np_client_t client, np_notify_cb_t notify_cb )
{
	if (!client)
		return NP_E_INVALID_ARG;

	np_error_t res = NP_E_UNKNOWN_ERROR;

	np_lock(client);
	if (client->notifier) {
		log_debug_msg("%s: callback already set, removing\n");
		iphone_connection_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(np_notifier, npt, TRUE, NULL);
			if (client->notifier) {
				res = NP_E_SUCCESS;
			}
		}
	} else {
		log_debug_msg("%s: no callback set\n", __func__);
	}
	np_unlock(client);

	return res;
}
Exemplo n.º 2
0
/** Opens a file on the phone.
 * 
 * @param client The client to use to open the file. 
 * @param filename The file to open. (must be a fully-qualified path)
 * @param file_mode The mode to use to open the file. Can be AFC_FILE_READ or
 * 		    AFC_FILE_WRITE; the former lets you read and write,
 * 		    however, and the second one will *create* the file,
 * 		    destroying anything previously there.
 * @param handle Pointer to a uint64_t that will hold the handle of the file
 * 
 * @return AFC_E_SUCCESS on success or an AFC_E_* error on failure.
 */
iphone_error_t
afc_file_open(afc_client_t client, const char *filename,
					 afc_file_mode_t file_mode, uint64_t *handle)
{
	uint32_t ag = 0;
	int bytes = 0;
	char *data = (char *) malloc(sizeof(char) * (8 + strlen(filename) + 1));
	afc_error_t ret = AFC_E_UNKNOWN_ERROR;

	// set handle to 0 so in case an error occurs, the handle is invalid
	*handle = 0;

	if (!client || !client->connection || !client->afc_packet)
		return AFC_E_INVALID_ARGUMENT;

	afc_lock(client);

	// Send command
	memcpy(data, &file_mode, 4);
	memcpy(data + 4, &ag, 4);
	memcpy(data + 8, filename, strlen(filename));
	data[8 + strlen(filename)] = '\0';
	client->afc_packet->operation = AFC_OP_FILE_OPEN;
	client->afc_packet->entire_length = client->afc_packet->this_length = 0;
	bytes = afc_dispatch_packet(client, data, 8 + strlen(filename) + 1);
	free(data);

	if (bytes <= 0) {
		log_debug_msg("%s: Didn't receive a response to the command\n", __func__);
		afc_unlock(client);
		return AFC_E_NOT_ENOUGH_DATA;
	}
	// Receive the data
	ret = afc_receive_data(client, &data, &bytes);
	if ((ret == AFC_E_SUCCESS) && (bytes > 0) && data) {
		afc_unlock(client);

		// Get the file handle
		memcpy(handle, data, sizeof(uint64_t));
		free(data);
		return ret;
	}

	log_debug_msg("%s: Didn't get any further data\n", __func__);

	afc_unlock(client);

	return ret;
}
Exemplo n.º 3
0
/** Reads the HostID from a previously generated configuration file.
 *
 * @note It is the responsibility of the calling function to free the returned host_id
 *
 * @return The string containing the HostID or NULL
 */
void userpref_get_host_id(char **host_id)
{
	gchar *config_file;
	GKeyFile *key_file;
	gchar *loc_host_id;

	config_file =
		g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_CONF_FILE, NULL);

	/* now parse file to get the HostID */
	key_file = g_key_file_new();
	if (g_key_file_load_from_file(key_file, config_file, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
		loc_host_id = g_key_file_get_value(key_file, "Global", "HostID", NULL);
		if (loc_host_id)
			*host_id = strdup((char *) loc_host_id);
		g_free(loc_host_id);
	}
	g_key_file_free(key_file);
	g_free(config_file);

	if (!*host_id) {
		/* no config, generate host_id */
		*host_id = userpref_generate_host_id();
		userpref_set_host_id(*host_id);
	}

	log_debug_msg("%s: Using %s as HostID\n", __func__, *host_id);
}
Exemplo n.º 4
0
/** 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 to send
 */
np_error_t np_post_notification(np_client_t client, const char *notification)
{
	if (!client || !notification) {
		return NP_E_INVALID_ARG;
	}
	np_lock(client);

	plist_t dict = plist_new_dict();
	plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification"));
	plist_dict_insert_item(dict,"Name", plist_new_string(notification));

	np_error_t res = np_plist_send(client, dict);
	plist_free(dict);

	dict = plist_new_dict();
	plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown"));

	res = np_plist_send(client, dict);
	plist_free(dict);

	if (res != NP_E_SUCCESS) {
		log_debug_msg("%s: Error sending XML plist to device!\n", __func__);
	}

	np_unlock(client);
	return res;
}
Exemplo n.º 5
0
/** Store HostID in config file.
 *
 * @param host_id A null terminated string containing a valid HostID.
 */
static int userpref_set_host_id(const char *host_id)
{
	GKeyFile *key_file;
	gsize length;
	gchar *buf, *config_file;
	GIOChannel *file;

	if (!host_id)
		return 0;

	/* Make sure config directory exists */
	userpref_create_config_dir();

	/* Now parse file to get the HostID */
	key_file = g_key_file_new();

	/* Store in config file */
	log_debug_msg("%s: setting hostID to %s\n", __func__, host_id);
	g_key_file_set_value(key_file, "Global", "HostID", host_id);

	/* Write config file on disk */
	buf = g_key_file_to_data(key_file, &length, NULL);
	config_file =
		g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_CONF_FILE, NULL);
	file = g_io_channel_new_file(config_file, "w", NULL);
	g_free(config_file);
	g_io_channel_write_chars(file, buf, length, NULL, NULL);
	g_io_channel_shutdown(file, TRUE, NULL);
	g_io_channel_unref(file);

	g_key_file_free(key_file);
	return 1;
}
Exemplo n.º 6
0
/**
 * Get a list of currently available devices.
 *
 * @param devices List of uuids of devices that are currently available.
 *   This list is terminated by a NULL pointer.
 * @param count Number of devices found.
 *
 * @return IPHONE_E_SUCCESS on success or an error value when an error occured.
 */
iphone_error_t iphone_get_device_list(char ***devices, int *count)
{
	usbmuxd_device_info_t *dev_list;

	*devices = NULL;
	*count = 0;

	if (usbmuxd_get_device_list(&dev_list) < 0) {
		log_debug_msg("%s: ERROR: usbmuxd is not running!\n", __func__);
		return IPHONE_E_NO_DEVICE;
	}

	char **newlist = NULL;
	int i, newcount = 0;

	for (i = 0; dev_list[i].handle > 0; i++) {
		newlist = realloc(*devices, sizeof(char*) * (newcount+1));
		newlist[newcount++] = strdup(dev_list[i].uuid);
		*devices = newlist;
	}
	usbmuxd_device_list_free(&dev_list);

	*count = newcount;
	newlist = realloc(*devices, sizeof(char*) * (newcount+1));
	newlist[newcount] = NULL;
	*devices = newlist;

	return IPHONE_E_SUCCESS;
}
Exemplo n.º 7
0
/** Closes a file on the phone. 
 * 
 * @param client The client to close the file with.
 * @param handle File handle of a previously opened file.
 */
afc_error_t afc_file_close(afc_client_t client, uint64_t handle)
{
	char *buffer = malloc(sizeof(char) * 8);
	int bytes = 0;
	afc_error_t ret = AFC_E_UNKNOWN_ERROR;

	if (!client || (handle == 0))
		return AFC_E_INVALID_ARGUMENT;

	afc_lock(client);

	log_debug_msg("%s: File handle %i\n", __func__, handle);

	// Send command
	memcpy(buffer, &handle, sizeof(uint64_t));
	client->afc_packet->operation = AFC_OP_FILE_CLOSE;
	client->afc_packet->entire_length = client->afc_packet->this_length = 0;
	bytes = afc_dispatch_packet(client, buffer, 8);
	free(buffer);
	buffer = NULL;

	if (bytes <= 0) {
		afc_unlock(client);
		return AFC_E_UNKNOWN_ERROR;
	}

	// Receive the response
	ret = afc_receive_data(client, &buffer, &bytes);
	if (buffer)
		free(buffer);

	afc_unlock(client);

	return ret;
}
Exemplo n.º 8
0
/**
 * Receive data from a device via the given connection.
 * This function will return after the given timeout even if no data has been
 * received.
 *
 * @param connection The connection to receive data from.
 * @param data Buffer that will be filled with the received data.
 *   This buffer has to be large enough to hold len bytes.
 * @param len Buffer size or number of bytes to receive.
 * @param recv_bytes Number of bytes actually received.
 * @param timeout Timeout in milliseconds after which this function should
 *   return even if no data has been received.
 *
 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
 */
iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
{
	if (!connection) {
		return IPHONE_E_INVALID_ARG;
	}

	if (connection->type == CONNECTION_USBMUXD) {
		int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout);
		if (res < 0) {
			log_debug_msg("%s: ERROR: usbmuxd_recv_timeout returned %d (%s)\n", __func__, res, strerror(-res));
			return IPHONE_E_UNKNOWN_ERROR;
		}
		return IPHONE_E_SUCCESS;
	} else {
		log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type);
	}
	return IPHONE_E_UNKNOWN_ERROR;
}
Exemplo n.º 9
0
/**
 * Release the event callback function that has been registered with
 *  iphone_event_subscribe().
 *
 * @return IPHONE_E_SUCCESS on success or an error value when an error occured.
 */
iphone_error_t iphone_event_unsubscribe()
{
	event_cb = NULL;
	int res = usbmuxd_unsubscribe();
	if (res != 0) {
		log_debug_msg("%s: Error %d when unsubscribing usbmux event callback!\n", __func__, res);
		return IPHONE_E_UNKNOWN_ERROR;
	}
	return IPHONE_E_SUCCESS;
}
Exemplo n.º 10
0
/**
 * Register a callback function that will be called when device add/remove
 * events occur.
 *
 * @param callback Callback function to call.
 * @param user_data Application-specific data passed as parameter
 *   to the registered callback function.
 *
 * @return IPHONE_E_SUCCESS on success or an error value when an error occured.
 */
iphone_error_t iphone_event_subscribe(iphone_event_cb_t callback, void *user_data)
{
	event_cb = callback;
	int res = usbmuxd_subscribe(usbmux_event_cb, user_data);
        if (res != 0) {
		event_cb = NULL;
		log_debug_msg("%s: Error %d when subscribing usbmux event callback!\n", __func__, res);
		return IPHONE_E_UNKNOWN_ERROR;
	}
	return IPHONE_E_SUCCESS;
}
Exemplo n.º 11
0
/**
 * Retrieves a list of connected devices from usbmuxd and matches their
 * UUID with the given UUID. If the given UUID is NULL then the first
 * device reported by usbmuxd is used.
 *
 * @param device Upon calling this function, a pointer to a location of type
 *  iphone_device_t, which must have the value NULL. On return, this location
 *  will be filled with a handle to the device.
 * @param uuid The UUID to match.
 *
 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
 */
iphone_error_t iphone_get_device_by_uuid(iphone_device_t * device, const char *uuid)
{
	iphone_device_t phone;
	uint32_t handle = 0;
	char *serial_number = malloc(41);
	usbmuxd_scan_result *dev_list = NULL;
	int i;

	if (usbmuxd_scan(&dev_list) < 0) {
		log_debug_msg("%s: usbmuxd_scan returned an error, is usbmuxd running?\n", __func__);
	}
	if (dev_list && dev_list[0].handle > 0) {
		if (!uuid) {
			// select first device found if no UUID specified
			handle = dev_list[0].handle;
			strcpy(serial_number, dev_list[0].serial_number);
		} else {
			// otherwise walk through the list
			for (i = 0; dev_list[i].handle > 0; i++) {
				log_debug_msg("%s: device handle=%d, uuid=%s\n", __func__, dev_list[i].handle, dev_list[i].serial_number);
				if (strcasecmp(uuid, dev_list[i].serial_number) == 0) {
					handle = dev_list[i].handle;
					strcpy(serial_number, dev_list[i].serial_number);
					break;
				}
			}
		}
		free(dev_list);

		if (handle > 0) {
			phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int));
			phone->handle = handle;
			phone->serial_number = serial_number;
			*device = phone;
			return IPHONE_E_SUCCESS;
		}
	}

	return IPHONE_E_NO_DEVICE;
}
Exemplo n.º 12
0
iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle)
{
	if (!device)
		return IPHONE_E_INVALID_ARG;

	if (device->conn_type == CONNECTION_USBMUXD) {
		*handle = (uint32_t)device->conn_data;
		return IPHONE_E_SUCCESS;
	} else {
		log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type);
	}
	return IPHONE_E_UNKNOWN_ERROR;
}
Exemplo n.º 13
0
/** Locks or unlocks a file on the phone. 
 *
 * makes use of flock on the device, see
 * http://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/flock.2.html
 *
 * @param client The client to lock the file with.
 * @param handle File handle of a previously opened file.
 * @param operation the lock or unlock operation to perform, this is one of
 *        AFC_LOCK_SH (shared lock), AFC_LOCK_EX (exclusive lock),
 *        or AFC_LOCK_UN (unlock).
 */
afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation)
{
	char *buffer = malloc(16);
	int bytes = 0;
	uint64_t op = operation;
	afc_error_t ret = AFC_E_UNKNOWN_ERROR;

	if (!client || (handle == 0))
		return AFC_E_INVALID_ARGUMENT;

	afc_lock(client);

	log_debug_msg("%s: file handle %i\n", __func__, handle);

	// Send command
	memcpy(buffer, &handle, sizeof(uint64_t));
	memcpy(buffer + 8, &op, 8);

	client->afc_packet->operation = AFC_OP_FILE_LOCK;
	client->afc_packet->entire_length = client->afc_packet->this_length = 0;
	bytes = afc_dispatch_packet(client, buffer, 16);
	free(buffer);
	buffer = NULL;

	if (bytes <= 0) {
		afc_unlock(client);
		log_debug_msg("%s: could not send lock command\n", __func__);
		return AFC_E_UNKNOWN_ERROR;
	}
	// Receive the response
	ret = afc_receive_data(client, &buffer, &bytes);
	if (buffer) {
		log_debug_buffer(buffer, bytes);
		free(buffer);
	}
	afc_unlock(client);

	return ret;
}
Exemplo n.º 14
0
/**
 * 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 NP_E_SUCCESS or an error code.
 */
static np_error_t np_plist_send(np_client_t client, plist_t dict)
{
	char *XML_content = NULL;
	uint32_t length = 0;
	uint32_t nlen = 0;
	int bytes = 0;
	np_error_t res = NP_E_UNKNOWN_ERROR;

	if (!client || !dict) {
		return NP_E_INVALID_ARG;
	}

	plist_to_xml(dict, &XML_content, &length);

	if (!XML_content || length == 0) {
		return NP_E_PLIST_ERROR;
	}

	nlen = htonl(length);
	iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
	if (bytes == sizeof(nlen)) {
		iphone_device_send(client->connection, XML_content, length, (uint32_t*)&bytes);
		if (bytes > 0) {
			if ((uint32_t)bytes == length) {
				res = NP_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;
}
Exemplo n.º 15
0
/** Creates a hard link or symbolic link on the device. 
 * 
 * @param client The client to use for making a link
 * @param type 1 = hard link, 2 = symlink
 * @param target The file to be linked.
 * @param linkname The name of link.
 * 
 * @return AFC_E_SUCCESS if everything went well, AFC_E_INVALID_ARGUMENT
 *         if arguments are NULL or invalid, AFC_E_NOT_ENOUGH_DATA otherwise.
 */
afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname)
{
	char *response = NULL;
	char *send = (char *) malloc(sizeof(char) * (strlen(target)+1 + strlen(linkname)+1 + 8));
	int bytes = 0;
	uint64_t type = linktype;
	afc_error_t ret = AFC_E_UNKNOWN_ERROR;

	if (!client || !target || !linkname || !client->afc_packet || !client->connection)
		return AFC_E_INVALID_ARGUMENT;

	afc_lock(client);

	log_debug_msg("%s: link type: %lld\n", __func__, type);
	log_debug_msg("%s: target: %s, length:%d\n", __func__, target, strlen(target));
	log_debug_msg("%s: linkname: %s, length:%d\n", __func__, linkname, strlen(linkname));

	// Send command
	memcpy(send, &type, 8);
	memcpy(send + 8, target, strlen(target) + 1);
	memcpy(send + 8 + strlen(target) + 1, linkname, strlen(linkname) + 1);
	client->afc_packet->entire_length = client->afc_packet->this_length = 0;
	client->afc_packet->operation = AFC_OP_MAKE_LINK;
	bytes = afc_dispatch_packet(client, send, 8 + strlen(linkname) + 1 + strlen(target) + 1);
	free(send);
	if (bytes <= 0) {
		afc_unlock(client);
		return AFC_E_NOT_ENOUGH_DATA;
	}
	// Receive response
	ret = afc_receive_data(client, &response, &bytes);
	if (response)
		free(response);

	afc_unlock(client);

	return ret;
}
Exemplo n.º 16
0
/**
 * Set up a connection to the given device.
 *
 * @param device The device to connect to.
 * @param dst_port The destination port to connect to.
 * @param connection Pointer to an iphone_connection_t that will be filled
 *   with the necessary data of the connection.
 *
 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
 */
iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t dst_port, iphone_connection_t *connection)
{
	if (!device) {
		return IPHONE_E_INVALID_ARG;
	}

	if (device->conn_type == CONNECTION_USBMUXD) {
		int sfd = usbmuxd_connect((uint32_t)(device->conn_data), dst_port);
		if (sfd < 0) {
			log_debug_msg("%s: ERROR: Connecting to usbmuxd failed: %d (%s)\n", __func__, sfd, strerror(-sfd));
			return IPHONE_E_UNKNOWN_ERROR;
		}
		iphone_connection_t new_connection = (iphone_connection_t)malloc(sizeof(struct iphone_connection_int));
		new_connection->type = CONNECTION_USBMUXD;
		new_connection->data = (void*)sfd;
		*connection = new_connection;
		return IPHONE_E_SUCCESS;
	} else {
		log_debug_msg("%s: Unknown connection type %d\n", __func__, device->conn_type);
	}

	return IPHONE_E_UNKNOWN_ERROR;
}
Exemplo n.º 17
0
/**
 * Disconnect from the device and clean up the connection structure.
 *
 * @param connection The connection to close.
 *
 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
 */
iphone_error_t iphone_device_disconnect(iphone_connection_t connection)
{
	if (!connection) {
		return IPHONE_E_INVALID_ARG;
	}
	iphone_error_t result = IPHONE_E_UNKNOWN_ERROR;
	if (connection->type == CONNECTION_USBMUXD) {
		usbmuxd_disconnect((int)(connection->data));
		result = IPHONE_E_SUCCESS;
	} else {
		log_debug_msg("%s: Unknown connection type %d\n", __func__, connection->type);
	}
	free(connection);
	return result;
}
Exemplo n.º 18
0
/** Disconnects an NP client from the phone.
 * 
 * @param client The client to disconnect.
 */
np_error_t np_client_free(np_client_t client)
{
	if (!client)
		return NP_E_INVALID_ARG;

	iphone_device_disconnect(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 NP_E_SUCCESS;
}
Exemplo n.º 19
0
/**
 * Internally used thread function.
 */
gpointer 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) {
		np_get_notification(npt->client, &notification);
		if (notification) {
			npt->cbfunc(notification);
			free(notification);
			notification = NULL;
		}
		sleep(1);
	}
	if (npt) {
		free(npt);
	}

	return NULL;
}
Exemplo n.º 20
0
/** Unlocks an NP client, done for thread safety stuff.
 * 
 * @param client The NP
 */
static void np_unlock(np_client_t client)
{
	log_debug_msg("NP: Unlocked\n");
	g_mutex_unlock(client->mutex);
}
Exemplo n.º 21
0
/** Writes a given number of bytes to a file.
 * 
 * @param client The client to use to write to the file.
 * @param handle File handle of previously opened file. 
 * @param data The data to write to the file.
 * @param length How much data to write.
 * 
 * @return The number of bytes written to the file, or a value less than 0 if
 *         none were written...
 */
iphone_error_t
afc_file_write(afc_client_t client, uint64_t handle,
					  const char *data, int length, uint32_t * bytes)
{
	char *acknowledgement = NULL;
	const int MAXIMUM_WRITE_SIZE = 1 << 15;
	uint32_t zero = 0, current_count = 0, i = 0;
	uint32_t segments = (length / MAXIMUM_WRITE_SIZE);
	int bytes_loc = 0;
	char *out_buffer = NULL;
	afc_error_t ret = AFC_E_SUCCESS;

	if (!client || !client->afc_packet || !client->connection || !bytes || (handle == 0))
		return AFC_E_INVALID_ARGUMENT;

	afc_lock(client);

	log_debug_msg("%s: Write length: %i\n", __func__, length);

	// Divide the file into segments.
	for (i = 0; i < segments; i++) {
		// Send the segment
		client->afc_packet->this_length = sizeof(AFCPacket) + 8;
		client->afc_packet->entire_length = client->afc_packet->this_length + MAXIMUM_WRITE_SIZE;
		client->afc_packet->operation = AFC_OP_WRITE;
		out_buffer = (char *) malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket));
		memcpy(out_buffer, (char *)&handle, sizeof(uint64_t));
		memcpy(out_buffer + 8, data + current_count, MAXIMUM_WRITE_SIZE);
		bytes_loc = afc_dispatch_packet(client, out_buffer, MAXIMUM_WRITE_SIZE + 8);
		if (bytes_loc < 0) {
			afc_unlock(client);
			return AFC_E_NOT_ENOUGH_DATA;
		}
		free(out_buffer);
		out_buffer = NULL;

		current_count += bytes_loc;
		ret = afc_receive_data(client, &acknowledgement, &bytes_loc);
		if (ret != AFC_E_SUCCESS) {
			afc_unlock(client);
			return ret;
		} else {
			free(acknowledgement);
		}
	}

	// By this point, we should be at the end. i.e. the last segment that
	// didn't get sent in the for loop
	// this length is fine because it's always sizeof(AFCPacket) + 8, but
	// to be sure we do it again
	if (current_count == (uint32_t)length) {
		afc_unlock(client);
		*bytes = current_count;
		return ret;
	}

	client->afc_packet->this_length = sizeof(AFCPacket) + 8;
	client->afc_packet->entire_length = client->afc_packet->this_length + (length - current_count);
	client->afc_packet->operation = AFC_OP_WRITE;
	out_buffer = (char *) malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket));
	memcpy(out_buffer, (char *) &handle, sizeof(uint64_t));
	memcpy(out_buffer + 8, data + current_count, (length - current_count));
	bytes_loc = afc_dispatch_packet(client, out_buffer, (length - current_count) + 8);
	free(out_buffer);
	out_buffer = NULL;

	current_count += bytes_loc;

	if (bytes_loc <= 0) {
		afc_unlock(client);
		*bytes = current_count;
		return AFC_E_SUCCESS;
	}

	zero = bytes_loc;
	ret = afc_receive_data(client, &acknowledgement, &bytes_loc);
	afc_unlock(client);
	if (ret != AFC_E_SUCCESS) {
		log_debug_msg("%s: uh oh?\n", __func__);
	} else {
		free(acknowledgement);
	}
	*bytes = current_count;
	return ret;
}
Exemplo n.º 22
0
/** Attempts to the read the given number of bytes from the given file.
 * 
 * @param client The relevant AFC client
 * @param handle File handle of a previously opened file
 * @param data The pointer to the memory region to store the read data
 * @param length The number of bytes to read
 *
 * @return The number of bytes read if successful. If there was an error -1.
 */
iphone_error_t
afc_file_read(afc_client_t client, uint64_t handle, char *data, int length, uint32_t * bytes)
{
	char *input = NULL;
	int current_count = 0, bytes_loc = 0;
	const int MAXIMUM_READ_SIZE = 1 << 16;
	afc_error_t ret = AFC_E_SUCCESS;

	if (!client || !client->afc_packet || !client->connection || handle == 0)
		return AFC_E_INVALID_ARGUMENT;
	log_debug_msg("%s: called for length %i\n", __func__, length);

	afc_lock(client);

	// Looping here to get around the maximum amount of data that
	// afc_receive_data can handle
	while (current_count < length) {
		log_debug_msg("%s: current count is %i but length is %i\n", __func__, current_count, length);

		// Send the read command
		AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket));
		packet->filehandle = handle;
		packet->size = ((length - current_count) < MAXIMUM_READ_SIZE) ? (length - current_count) : MAXIMUM_READ_SIZE;
		client->afc_packet->operation = AFC_OP_READ;
		client->afc_packet->entire_length = client->afc_packet->this_length = 0;
		bytes_loc = afc_dispatch_packet(client, (char *) packet, sizeof(AFCFilePacket));
		free(packet);

		if (bytes_loc <= 0) {
			afc_unlock(client);
			return AFC_E_NOT_ENOUGH_DATA;
		}
		// Receive the data
		ret = afc_receive_data(client, &input, &bytes_loc);
		log_debug_msg("%s: afc_receive_data returned error: %d\n", __func__, ret);
		log_debug_msg("%s: bytes returned: %i\n", __func__, bytes_loc);
		if (ret != AFC_E_SUCCESS) {
			afc_unlock(client);
			return ret;
		} else if (bytes_loc == 0) {
			if (input)
				free(input);
			afc_unlock(client);
			*bytes = current_count;
			/* FIXME: check that's actually a success */
			return ret;
		} else {
			if (input) {
				log_debug_msg("%s: %d\n", __func__, bytes_loc);
				memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc);
				free(input);
				input = NULL;
				current_count += (bytes_loc > length) ? length : bytes_loc;
			}
		}
	}
	log_debug_msg("%s: returning current_count as %i\n", __func__, current_count);

	afc_unlock(client);
	*bytes = current_count;
	return ret;
}
Exemplo n.º 23
0
/**
 * 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 0 if a notification has been received or nothing has been received,
 *         or an error value if an error occured.
 *
 * @note You probably want to check out np_set_notify_callback
 * @see np_set_notify_callback
 */
static int np_get_notification(np_client_t client, char **notification)
{
	uint32_t bytes = 0;
	int res = 0;
	uint32_t pktlen = 0;
	char *XML_content = NULL;
	plist_t dict = NULL;

	if (!client || !client->connection || *notification)
		return -1;

	np_lock(client);

	iphone_device_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 = 0;
	} 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_device_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000);
			if (bytes <= 0) {
				res = -1;
			} 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 -2;
				}

				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 = -2;
					if (name_key && name_value && !strcmp(name_key, "Name")) {
						*notification = name_value;
						log_debug_msg("%s: got notification %s\n", __func__, name_value);
						res = 0;
					}
					free(name_key);
				} else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) {
					log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__);
					res = -1;
				} else if (cmd_value) {
					log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__);
					res = -1;
				} else {
					res = -2;
				}
				if (cmd_value) {
					free(cmd_value);
				}
				plist_free(dict);
				dict = NULL;
				free(XML_content);
				XML_content = NULL;
			}
		} else {
			res = -1;
		}
	}

	np_unlock(client);

	return res;
}
Exemplo n.º 24
0
/** Unlocks an AFC client, done for thread safety stuff.
 * 
 * @param client The AFC 
 */
static void afc_unlock(afc_client_t client)
{
	log_debug_msg("%s: Unlocked\n", __func__);
	g_mutex_unlock(client->mutex);
}
Exemplo n.º 25
0
/** Receives data through an AFC client and sets a variable to the received data.
 * 
 * @param client The client to receive data on.
 * @param dump_here The char* to point to the newly-received data.
 * 
 * @return How much data was received, 0 on successful receive with no errors,
 *         -1 if there was an error involved with receiving or if the packet
 *         received raised a non-trivial error condition (i.e. non-zero with
 *         AFC_ERROR operation)
 */
static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, int *bytes)
{
	AFCPacket header;
	uint32_t entire_len = 0;
	uint32_t this_len = 0;
	uint32_t current_count = 0;
	uint64_t param1 = -1;

	*bytes = 0;

	/* first, read the AFC header */
	iphone_device_recv(client->connection, (char*)&header, sizeof(AFCPacket), (uint32_t*)bytes);
	if (*bytes <= 0) {
		log_debug_msg("%s: Just didn't get enough.\n", __func__);
		*dump_here = NULL;
		return AFC_E_MUX_ERROR;
	} else if ((uint32_t)*bytes < sizeof(AFCPacket)) {
		log_debug_msg("%s: Did not even get the AFCPacket header\n", __func__);
		*dump_here = NULL;
		return AFC_E_MUX_ERROR;
	}

	/* check if it's a valid AFC header */
	if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) {
		log_debug_msg("%s: Invalid AFC packet received (magic != " AFC_MAGIC ")!\n", __func__);
	}

	/* check if it has the correct packet number */
	if (header.packet_num != client->afc_packet->packet_num) {
		/* otherwise print a warning but do not abort */
		log_debug_msg("%s: ERROR: Unexpected packet number (%lld != %lld) aborting.\n", __func__, header.packet_num, client->afc_packet->packet_num);
		*dump_here = NULL;
		return AFC_E_OP_HEADER_INVALID;
	}

	/* then, read the attached packet */
	if (header.this_length < sizeof(AFCPacket)) {
		log_debug_msg("%s: Invalid AFCPacket header received!\n", __func__);
		*dump_here = NULL;
		return AFC_E_OP_HEADER_INVALID;
	} else if ((header.this_length == header.entire_length)
			&& header.entire_length == sizeof(AFCPacket)) {
		log_debug_msg("%s: Empty AFCPacket received!\n", __func__);
		*dump_here = NULL;
		*bytes = 0;
		if (header.operation == AFC_OP_DATA) {
			return AFC_E_SUCCESS;
		} else {
			return AFC_E_IO_ERROR;
		}
	}

	log_debug_msg("%s: received AFC packet, full len=%lld, this len=%lld, operation=0x%llx\n", __func__, header.entire_length, header.this_length, header.operation);

	entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket);
	this_len = (uint32_t)header.this_length - sizeof(AFCPacket);

	/* this is here as a check (perhaps a different upper limit is good?) */
	if (entire_len > (uint32_t)MAXIMUM_PACKET_SIZE) {
		fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!\n", __func__, entire_len, MAXIMUM_PACKET_SIZE);
	}

	*dump_here = (char*)malloc(entire_len);
	if (this_len > 0) {
		iphone_device_recv(client->connection, *dump_here, this_len, (uint32_t*)bytes);
		if (*bytes <= 0) {
			free(*dump_here);
			*dump_here = NULL;
			log_debug_msg("%s: Did not get packet contents!\n", __func__);
			return AFC_E_NOT_ENOUGH_DATA;
		} else if ((uint32_t)*bytes < this_len) {
			free(*dump_here);
			*dump_here = NULL;
			log_debug_msg("%s: Could not receive this_len=%d bytes\n", __func__, this_len);
			return AFC_E_NOT_ENOUGH_DATA;
		}
	}

	current_count = this_len;

	if (entire_len > this_len) {
		while (current_count < entire_len) {
			iphone_device_recv(client->connection, (*dump_here)+current_count, entire_len - current_count, (uint32_t*)bytes);
			if (*bytes <= 0) {
				log_debug_msg("%s: Error receiving data (recv returned %d)\n", __func__, *bytes);
				break;
			}
			current_count += *bytes;
		}
		if (current_count < entire_len) {
			log_debug_msg("%s: WARNING: could not receive full packet (read %s, size %d)\n", __func__, current_count, entire_len);
		}
	}

	if (current_count >= sizeof(uint64_t)) {
		param1 = *(uint64_t*)(*dump_here);
	}

	log_debug_msg("%s: packet data size = %i\n", __func__, current_count);
	log_debug_msg("%s: packet data follows\n", __func__);
	log_debug_buffer(*dump_here, current_count);

	/* check operation types */
	if (header.operation == AFC_OP_STATUS) {
		/* status response */
		log_debug_msg("%s: got a status response, code=%lld\n", __func__, param1);

		if (param1 != AFC_E_SUCCESS) {
			/* error status */
			/* free buffer */
			free(*dump_here);
			*dump_here = NULL;
			return (afc_error_t)param1;
		}
	} else if (header.operation == AFC_OP_DATA) {
		/* data response */
		log_debug_msg("%s: got a data response\n", __func__);
	} else if (header.operation == AFC_OP_FILE_OPEN_RES) {
		/* file handle response */
		log_debug_msg("%s: got a file handle response, handle=%lld\n", __func__, param1);
	} else if (header.operation == AFC_OP_FILE_TELL_RES) {
		/* tell response */
		log_debug_msg("%s: got a tell response, position=%lld\n", __func__, param1);
	} else {
		/* unknown operation code received */
		free(*dump_here);
		*dump_here = NULL;
		*bytes = 0;

		log_debug_msg("%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, header.operation, param1);
		fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, (long long)header.operation, (long long)param1);

		return AFC_E_OP_NOT_SUPPORTED;
	}

	*bytes = current_count;
	return AFC_E_SUCCESS;
}
Exemplo n.º 26
0
/** Dispatches an AFC packet over a client.
 * 
 * @param client The client to send data through.
 * @param data The data to send.
 * @param length The length to send.
 * 
 * @return The number of bytes actually sent, or -1 on error. 
 * 
 * @warning set client->afc_packet->this_length and
 *          client->afc_packet->entire_length to 0 before calling this.  The
 *          reason is that if you set them to different values, it indicates
 *          you want to send the data as two packets.
 */
static int afc_dispatch_packet(afc_client_t client, const char *data, uint64_t length)
{
	int bytes = 0, offset = 0;
	char *buffer;

	if (!client || !client->connection || !client->afc_packet)
		return 0;

	if (!data || !length)
		length = 0;

	client->afc_packet->packet_num++;
	if (!client->afc_packet->entire_length) {
		client->afc_packet->entire_length = (length) ? sizeof(AFCPacket) + length : sizeof(AFCPacket);
		client->afc_packet->this_length = client->afc_packet->entire_length;
	}
	if (!client->afc_packet->this_length) {
		client->afc_packet->this_length = sizeof(AFCPacket);
	}
	// We want to send two segments; buffer+sizeof(AFCPacket) to
	// this_length is the parameters
	// And everything beyond that is the next packet. (for writing)
	if (client->afc_packet->this_length != client->afc_packet->entire_length) {
		buffer = (char *) malloc(client->afc_packet->this_length);
		memcpy(buffer, (char *) client->afc_packet, sizeof(AFCPacket));
		offset = client->afc_packet->this_length - sizeof(AFCPacket);

		log_debug_msg("%s: Offset: %i\n", __func__, offset);
		if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) {
			log_debug_msg("%s: Length did not resemble what it was supposed", __func__);
			log_debug_msg("to based on the packet.\n");
			log_debug_msg("%s: length minus offset: %i\n", __func__, length - offset);
			log_debug_msg("%s: rest of packet: %i\n", __func__, client->afc_packet->entire_length - client->afc_packet->this_length);
			free(buffer);
			return -1;
		}
		memcpy(buffer + sizeof(AFCPacket), data, offset);
		iphone_device_send(client->connection, buffer, client->afc_packet->this_length, (uint32_t*)&bytes);
		free(buffer);
		if (bytes <= 0) {
			return bytes;
		}

		log_debug_msg("%s: sent the first now go with the second\n", __func__);
		log_debug_msg("%s: Length: %i\n", __func__, length - offset);
		log_debug_msg("%s: Buffer: \n", __func__);
		log_debug_buffer(data + offset, length - offset);

		iphone_device_send(client->connection, data + offset, length - offset, (uint32_t*)&bytes);
		return bytes;
	} else {
		log_debug_msg("%s: doin things the old way\n", __func__);
		buffer = (char *) malloc(sizeof(char) * client->afc_packet->this_length);
		log_debug_msg("%s: packet length = %i\n", __func__, client->afc_packet->this_length);
		memcpy(buffer, (char *) client->afc_packet, sizeof(AFCPacket));
		log_debug_msg("%s: packet data follows\n", __func__);
		if (length > 0) {
			memcpy(buffer + sizeof(AFCPacket), data, length);
		}
		log_debug_buffer(buffer, client->afc_packet->this_length);
		log_debug_msg("\n");
		iphone_device_send(client->connection, buffer, client->afc_packet->this_length, (uint32_t*)&bytes);

		if (buffer) {
			free(buffer);
			buffer = NULL;
		}
		return bytes;
	}
	return -1;
}