diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 1 | ||||
| -rw-r--r-- | src/device_link_service.c | 299 | ||||
| -rw-r--r-- | src/device_link_service.h | 51 | 
3 files changed, 351 insertions, 0 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index 0352f64..bc98de4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ AM_LDFLAGS = $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_L  lib_LTLIBRARIES = libiphone.la  libiphone_la_SOURCES = iphone.c iphone.h \  		       property_list_service.c property_list_service.h\ +		       device_link_service.c device_link_service.h\  		       lockdown.c lockdown.h\  		       AFC.c AFC.h\  		       NotificationProxy.c NotificationProxy.h\ diff --git a/src/device_link_service.c b/src/device_link_service.c new file mode 100644 index 0000000..83b0676 --- /dev/null +++ b/src/device_link_service.c @@ -0,0 +1,299 @@ + /*  + * device_link_service.c + * DeviceLink service implementation. + *  + * Copyright (c) 2010 Nikias Bassen, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  + */ +#include <string.h> +#include <stdlib.h> +#include "device_link_service.h" +#include "property_list_service.h" +#include "utils.h" + +/** + * Internally used function to extract the message string from a DLMessage* + * plist. + * + * @param dl_msg The DeviceLink property list to parse. + * + * @return An allocated char* with the DLMessage from the given plist, + *     or NULL when the plist does not contain any DLMessage. It is up to + *     the caller to free the allocated memory. + */ +static char *device_link_service_get_message(plist_t dl_msg) +{ +	uint32_t cnt = 0; +	plist_t cmd = 0; +	char *cmd_str = NULL; + +	/* sanity check */ +	if ((plist_get_node_type(dl_msg) != PLIST_ARRAY) || ((cnt = plist_array_get_size(dl_msg)) < 1)) { +		return NULL; +	} + +	/* get dl command */ +	cmd = plist_array_get_item(dl_msg, 0); +	if (!cmd || (plist_get_node_type(cmd) != PLIST_STRING)) { +		return NULL; +	} + +	plist_get_string_val(cmd, &cmd_str); +	if (!cmd_str) { +		return NULL; +	} + +	if ((strlen(cmd_str) < (strlen("DLMessage")+1)) +	    || (strncmp(cmd_str, "DLMessage", strlen("DLMessage")))) { +		free(cmd_str); +		return NULL; +	} + +	/* we got a DLMessage* command */ +	return cmd_str; +} + +/** + * Creates a new device link service client. + * + * @param device The device to connect to. + * @param port Port on device to connect to. + * @param client Reference that will point to a newly allocated + *     device_link_service_client_t upon successful return. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when one of the parameters is invalid, + *     or DEVICE_LINK_SERVICE_E_MUX_ERROR when the connection failed. + */ +device_link_service_error_t device_link_service_client_new(iphone_device_t device, uint16_t port, device_link_service_client_t *client) +{ +	if (!device || port == 0 || !client || *client) { +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; +	} + +	property_list_service_client_t plistclient = NULL; +	if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		return DEVICE_LINK_SERVICE_E_MUX_ERROR; +	} + +	/* create client object */ +	device_link_service_client_t client_loc = (device_link_service_client_t) malloc(sizeof(struct device_link_service_client_int)); +	client_loc->parent = plistclient; + +	/* all done, return success */ +	*client = client_loc; +	return DEVICE_LINK_SERVICE_E_SUCCESS; +} + +/** + * Frees a device link service client. + * + * @param client The device_link_service_client_t to free. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when one of client or client->parent + *     is invalid, or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR when the was an error + *     freeing the parent property_list_service client. + */ +device_link_service_error_t device_link_service_client_free(device_link_service_client_t client) +{ +	if (!client) +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; + +	if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		return DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR; +	} +	return DEVICE_LINK_SERVICE_E_SUCCESS; +} + +/** + * Performs the DLMessageVersionExchange with the connected device. + * This should be the first operation to be executed by an implemented + * device link service client. + * + * @param client The device_link_service client to use. + * @param version_major The major version number to check. + * @param version_minor The minor version number to check. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL, + *     DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs, + *     DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the + *     expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version + *     given by the device is larger than the given version, + *     or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise. + */ +device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor) +{ +	if (!client) +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; +	 +	device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR; + +	/* perform version exchange */ +	plist_t array = NULL; +	char *msg = NULL; + +	/* receive DLMessageVersionExchange from device */ +	if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		log_debug_msg("%s: Did not receive initial message from device!\n", __func__); +		err = DEVICE_LINK_SERVICE_E_MUX_ERROR; +		goto leave; +	} +	msg = device_link_service_get_message(array); +	if (!msg || strcmp(msg, "DLMessageVersionExchange")) { +		log_debug_msg("%s: Did not receive DLMessageVersionExchange from device!\n", __func__); +		err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; +		goto leave; +	} +	free(msg); +	msg = NULL; + +	/* get major and minor version number */ +	if (plist_array_get_size(array) < 3) { +		log_debug_msg("%s: DLMessageVersionExchange has unexpected format!\n", __func__); +		err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; +		goto leave; +	} +	plist_t maj = plist_array_get_item(array, 1); +	plist_t min = plist_array_get_item(array, 2); +	uint64_t vmajor = 0; +	uint64_t vminor = 0; +	if (maj) { +		plist_get_uint_val(maj, &vmajor); +	} +	if (min) { +		plist_get_uint_val(min, &vminor); +	} +	if (vmajor > version_major) { +		log_debug_msg("%s: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)\n", __func__, vmajor, vminor, version_major, version_minor); +		err = DEVICE_LINK_SERVICE_E_BAD_VERSION; +		goto leave; +	} else if ((vmajor == version_major) && (vminor > version_minor)) { +		log_debug_msg("%s: WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)\n", __func__, vmajor, vminor, version_major, version_minor); +		err = DEVICE_LINK_SERVICE_E_BAD_VERSION; +		goto leave; +	} +	plist_free(array); + +	/* version is ok, send reply */ +	array = plist_new_array(); +	plist_array_append_item(array, plist_new_string("DLMessageVersionExchange")); +	plist_array_append_item(array, plist_new_string("DLVersionsOk")); +	if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		log_debug_msg("%s: Error when sending DLVersionsOk", __func__); +		err = DEVICE_LINK_SERVICE_E_MUX_ERROR; +		goto leave; +	} +	plist_free(array); + +	/* receive DeviceReady message */ +	array = NULL; +	if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		log_debug_msg("%s: Error when receiving DLMessageDeviceReady!\n", __func__); +		err = DEVICE_LINK_SERVICE_E_MUX_ERROR; +		goto leave; +	} +	msg = device_link_service_get_message(array); +	if (!msg || strcmp(msg, "DLMessageDeviceReady")) { +		log_debug_msg("%s: Did not get DLMessageDeviceReady!\n", __func__); +		err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; +		goto leave; +	} +	err = DEVICE_LINK_SERVICE_E_SUCCESS; + +leave: +	if (msg) { +		free(msg); +	} +	if (array) { +		plist_free(array); +	} +	return err; +} + +/** + * Performs a disconnect with the connected device link service client. + * + * @param client The device link service client to disconnect. + *  + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG if client is NULL, + *     or DEVICE_LINK_SERVICE_E_MUX_ERROR when there's an error when sending + *     the the disconnect message. + */ +device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client) +{ +	if (!client) +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; + +	plist_t array = plist_new_array(); +	plist_array_append_item(array, plist_new_string("DLMessageDisconnect")); +	plist_array_append_item(array, plist_new_string("All done, thanks for the memories")); + +	device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS; +	if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		err = DEVICE_LINK_SERVICE_E_MUX_ERROR; +	} +	plist_free(array); +	return err; +} + +/** + * Generic device link service send function. + * + * @param client The device link service client to use for sending + * @param plist The property list to send + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL, + *     or DEVICE_LINK_SERVICE_E_MUX_ERROR when the given property list could + *     not be sent. + */ +device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist) +{ +	if (!client || !plist) { +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; +	} +	if (property_list_service_send_binary_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		return DEVICE_LINK_SERVICE_E_MUX_ERROR; +	} +	return DEVICE_LINK_SERVICE_E_SUCCESS; +} + +/* Generic device link service receive function. + * + * @param client The device link service client to use for sending + * @param plist Pointer that will point to the property list received upon + *     successful return. + * + * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, + *     DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL, + *     or DEVICE_LINK_SERVICE_E_MUX_ERROR when no property list could be + *     received. + */ +device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist) +{ +	if (!client || !plist || (plist && *plist)) { +		return DEVICE_LINK_SERVICE_E_INVALID_ARG; +	} + +	if (property_list_service_receive_plist(client->parent, plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) { +		return DEVICE_LINK_SERVICE_E_MUX_ERROR; +	} +	return DEVICE_LINK_SERVICE_E_SUCCESS; +} + diff --git a/src/device_link_service.h b/src/device_link_service.h new file mode 100644 index 0000000..e14d897 --- /dev/null +++ b/src/device_link_service.h @@ -0,0 +1,51 @@ + /*  + * device_link_service.h + * Definitions for the DeviceLink service + *  + * Copyright (c) 2010 Nikias Bassen, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  + */ +#ifndef DEVICE_LINK_SERVICE_H +#define DEVICE_LINK_SERVICE_H + +#include "property_list_service.h" + +/* Error Codes */ +#define DEVICE_LINK_SERVICE_E_SUCCESS                0 +#define DEVICE_LINK_SERVICE_E_INVALID_ARG           -1 +#define DEVICE_LINK_SERVICE_E_PLIST_ERROR           -2 +#define DEVICE_LINK_SERVICE_E_MUX_ERROR             -3 +#define DEVICE_LINK_SERVICE_E_BAD_VERSION           -4 + +#define DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR       -256 + + +struct device_link_service_client_int { +	property_list_service_client_t parent; +}; + +typedef struct device_link_service_client_int *device_link_service_client_t; + +typedef int16_t device_link_service_error_t; + +device_link_service_error_t device_link_service_client_new(iphone_device_t device, uint16_t port, device_link_service_client_t *client); +device_link_service_error_t device_link_service_client_free(device_link_service_client_t client); +device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor); +device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client); +device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist); +device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist); + +#endif | 
