diff options
| author | 2013-02-26 17:24:23 +0100 | |
|---|---|---|
| committer | 2013-02-27 16:18:15 +0100 | |
| commit | f8066bbf5169b7d7e68771bce677355e33a595c1 (patch) | |
| tree | 8e8ee0a82c3a363c171c7124884af80a68e7cd08 /src | |
| parent | ca23188eaab07d744e9cf85d9bf69ed323e94186 (diff) | |
| download | libimobiledevice-f8066bbf5169b7d7e68771bce677355e33a595c1.tar.gz libimobiledevice-f8066bbf5169b7d7e68771bce677355e33a595c1.tar.bz2  | |
implement base service that all other services inherit from
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 3 | ||||
| -rw-r--r-- | src/afc.c | 71 | ||||
| -rw-r--r-- | src/afc.h | 5 | ||||
| -rw-r--r-- | src/file_relay.c | 2 | ||||
| -rw-r--r-- | src/house_arrest.c | 4 | ||||
| -rw-r--r-- | src/misagent.c | 2 | ||||
| -rw-r--r-- | src/mobilebackup2.c | 8 | ||||
| -rw-r--r-- | src/property_list_service.c | 51 | ||||
| -rw-r--r-- | src/property_list_service.h | 3 | ||||
| -rw-r--r-- | src/service.c | 276 | ||||
| -rw-r--r-- | src/service.h | 59 | 
11 files changed, 404 insertions, 80 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 136baf4..574075e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,7 @@ libimobiledevice_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBIMOBILEDEVICE_SO_  libimobiledevice_la_SOURCES = idevice.c idevice.h \  		       debug.c debug.h\  		       userpref.c userpref.h\ +		       service.c service.h\  		       property_list_service.c property_list_service.h\  		       device_link_service.c device_link_service.h\  		       lockdown.c lockdown.h\ @@ -31,4 +32,4 @@ libimobiledevice_la_SOURCES = idevice.c idevice.h \  if WIN32  libimobiledevice_la_LIBADD += -lole32 -endif
\ No newline at end of file +endif @@ -69,9 +69,7 @@ static void afc_unlock(afc_client_t client)   * Makes a connection to the AFC service on the device using the given   * connection.   * - * @param connection An idevice_connection_t that must have been previously - *     connected using idevice_connect(). Note that this connection will - *     not be closed by calling afc_client_free(). + * @param serviceclient A connected service client   * @param client Pointer that will be set to a newly allocated afc_client_t   *     upon successful return.   *  @@ -79,14 +77,14 @@ static void afc_unlock(afc_client_t client)   *  invalid, or AFC_E_NO_MEM if there is a memory allocation problem.   */ -afc_error_t afc_client_new_from_connection(idevice_connection_t connection, afc_client_t *client) +afc_error_t afc_client_new_with_service_client(service_client_t serviceclient, afc_client_t *client)  { -	if (!connection) +	if (!serviceclient)  		return AFC_E_INVALID_ARG;  	afc_client_t client_loc = (afc_client_t) malloc(sizeof(struct afc_client_private)); -	client_loc->connection = connection; -	client_loc->own_connection = 0; +	client_loc->parent = serviceclient; +	client_loc->free_parent = 0;  	/* allocate a packet */  	client_loc->afc_packet = (AFCPacket *) malloc(sizeof(AFCPacket)); @@ -113,10 +111,6 @@ afc_error_t afc_client_new_from_connection(idevice_connection_t connection, afc_  /**   * Makes a connection to the AFC service on the device. - * This function calls afc_client_new_from_connection() after creating - * a connection to the specified device and port. - * - * @see afc_client_new_from_connection   *    * @param device The device to connect to.   * @param service The service descriptor returned by lockdownd_start_service. @@ -132,21 +126,16 @@ afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t serv  	if (!device || service->port == 0)  		return AFC_E_INVALID_ARG; -	/* attempt connection */ -	idevice_connection_t connection = NULL; -	if (idevice_connect(device, service->port, &connection) != IDEVICE_E_SUCCESS) { +	service_client_t parent = NULL; +	if (service_client_new(device, service, &parent) != SERVICE_E_SUCCESS) {  		return AFC_E_MUX_ERROR;  	} -	/* enable SSL if requested */ -	if (service->ssl_enabled) -		idevice_connection_enable_ssl(connection); - -	afc_error_t err = afc_client_new_from_connection(connection, client); +	afc_error_t err = afc_client_new_with_service_client(parent, client);  	if (err != AFC_E_SUCCESS) { -		idevice_disconnect(connection); +		service_client_free(parent);  	} else { -		(*client)->own_connection = 1; +		(*client)->free_parent = 1;  	}  	return err;  } @@ -162,9 +151,9 @@ afc_error_t afc_client_free(afc_client_t client)  	if (!client || !client->afc_packet)  		return AFC_E_INVALID_ARG; -	if (client->own_connection && client->connection) { -		idevice_disconnect(client->connection); -		client->connection = NULL; +	if (client->free_parent && client->parent) { +		service_client_free(client->parent); +		client->parent = NULL;  	}  	free(client->afc_packet);  #ifdef WIN32 @@ -196,7 +185,7 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui  	uint32_t offset = 0;  	uint32_t sent = 0; -	if (!client || !client->connection || !client->afc_packet) +	if (!client || !client->parent || !client->afc_packet)  		return AFC_E_INVALID_ARG;  	*bytes_sent = 0; @@ -229,7 +218,7 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui  		/* send AFC packet header */  		AFCPacket_to_LE(client->afc_packet);  		sent = 0; -		idevice_connection_send(client->connection, (void*)client->afc_packet, sizeof(AFCPacket), &sent); +		service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket), &sent);  		AFCPacket_from_LE(client->afc_packet);  		if (sent == 0) {  			/* FIXME: should this be handled as success?! */ @@ -239,7 +228,7 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui  		/* send AFC packet data */  		sent = 0; -		idevice_connection_send(client->connection, data, offset, &sent); +		service_send(client->parent, data, offset, &sent);  		if (sent == 0) {  			return AFC_E_SUCCESS;  		} @@ -251,7 +240,7 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui  		debug_buffer(data + offset, length - offset);  		sent = 0; -		idevice_connection_send(client->connection, data + offset, length - offset, &sent); +		service_send(client->parent, data + offset, length - offset, &sent);  		*bytes_sent = sent;  		return AFC_E_SUCCESS; @@ -264,7 +253,7 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui  		/* send AFC packet header */  		AFCPacket_to_LE(client->afc_packet);  		sent = 0; -		idevice_connection_send(client->connection, (void*)client->afc_packet, sizeof(AFCPacket), &sent); +		service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket), &sent);  		AFCPacket_from_LE(client->afc_packet);  		if (sent == 0) {  			return AFC_E_SUCCESS; @@ -275,7 +264,7 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, ui  			debug_info("packet data follows");  			debug_buffer(data, length); -			idevice_connection_send(client->connection, data, length, &sent); +			service_send(client->parent, data, length, &sent);  			*bytes_sent += sent;  		}  		return AFC_E_SUCCESS; @@ -303,7 +292,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3  	*bytes_recv = 0;  	/* first, read the AFC header */ -	idevice_connection_receive(client->connection, (char*)&header, sizeof(AFCPacket), bytes_recv); +	service_receive(client->parent, (char*)&header, sizeof(AFCPacket), bytes_recv);  	AFCPacket_from_LE(&header);  	if (*bytes_recv == 0) {  		debug_info("Just didn't get enough."); @@ -357,7 +346,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3  	*dump_here = (char*)malloc(entire_len);  	if (this_len > 0) { -		idevice_connection_receive(client->connection, *dump_here, this_len, bytes_recv); +		service_receive(client->parent, *dump_here, this_len, bytes_recv);  		if (*bytes_recv <= 0) {  			free(*dump_here);  			*dump_here = NULL; @@ -375,7 +364,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3  	if (entire_len > this_len) {  		while (current_count < entire_len) { -			idevice_connection_receive(client->connection, (*dump_here)+current_count, entire_len - current_count, bytes_recv); +			service_receive(client->parent, (*dump_here)+current_count, entire_len - current_count, bytes_recv);  			if (*bytes_recv <= 0) {  				debug_info("Error receiving data (recv returned %d)", *bytes_recv);  				break; @@ -625,7 +614,7 @@ afc_error_t afc_remove_path(afc_client_t client, const char *path)  	uint32_t bytes = 0;  	afc_error_t ret = AFC_E_UNKNOWN_ERROR; -	if (!client || !path || !client->afc_packet || !client->connection) +	if (!client || !path || !client->afc_packet || !client->parent)  		return AFC_E_INVALID_ARG;  	afc_lock(client); @@ -668,7 +657,7 @@ afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *t  	uint32_t bytes = 0;  	afc_error_t ret = AFC_E_UNKNOWN_ERROR; -	if (!client || !from || !to || !client->afc_packet || !client->connection) +	if (!client || !from || !to || !client->afc_packet || !client->parent)  		return AFC_E_INVALID_ARG;  	afc_lock(client); @@ -800,7 +789,7 @@ afc_file_open(afc_client_t client, const char *filename,  	/* set handle to 0 so in case an error occurs, the handle is invalid */  	*handle = 0; -	if (!client || !client->connection || !client->afc_packet) +	if (!client || !client->parent || !client->afc_packet)  		return AFC_E_INVALID_ARG;  	afc_lock(client); @@ -856,7 +845,7 @@ afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length,  	const uint32_t MAXIMUM_READ_SIZE = 1 << 16;  	afc_error_t ret = AFC_E_SUCCESS; -	if (!client || !client->afc_packet || !client->connection || handle == 0) +	if (!client || !client->afc_packet || !client->parent || handle == 0)  		return AFC_E_INVALID_ARG;  	debug_info("called for length %i", length); @@ -933,7 +922,7 @@ afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t  	char *out_buffer = NULL;  	afc_error_t ret = AFC_E_SUCCESS; -	if (!client || !client->afc_packet || !client->connection || !bytes_written || (handle == 0)) +	if (!client || !client->afc_packet || !client->parent || !bytes_written || (handle == 0))  		return AFC_E_INVALID_ARG;  	afc_lock(client); @@ -1258,7 +1247,7 @@ afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize  	uint64_t size_requested = htole64(newsize);  	afc_error_t ret = AFC_E_UNKNOWN_ERROR; -	if (!client || !path || !client->afc_packet || !client->connection) +	if (!client || !path || !client->afc_packet || !client->parent)  		return AFC_E_INVALID_ARG;  	afc_lock(client); @@ -1302,7 +1291,7 @@ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const c  	uint64_t type = htole64(linktype);  	afc_error_t ret = AFC_E_UNKNOWN_ERROR; -	if (!client || !target || !linkname || !client->afc_packet || !client->connection) +	if (!client || !target || !linkname || !client->afc_packet || !client->parent)  		return AFC_E_INVALID_ARG;  	afc_lock(client); @@ -1350,7 +1339,7 @@ afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mt  	uint64_t mtime_loc = htole64(mtime);  	afc_error_t ret = AFC_E_UNKNOWN_ERROR; -	if (!client || !path || !client->afc_packet || !client->connection) +	if (!client || !path || !client->afc_packet || !client->parent)  		return AFC_E_INVALID_ARG;  	afc_lock(client); @@ -30,6 +30,7 @@  #endif  #include "libimobiledevice/afc.h" +#include "service.h"  #include "endianness.h"  #define AFC_MAGIC "CFA6LPAA" @@ -57,7 +58,7 @@ typedef struct {  } AFCFilePacket;  struct afc_client_private { -	idevice_connection_t connection; +	service_client_t parent;  	AFCPacket *afc_packet;  	int file_handle;  	int lock; @@ -66,7 +67,7 @@ struct afc_client_private {  #else  	pthread_mutex_t mutex;  #endif -	int own_connection; +	int free_parent;  };  /* AFC Operations */ diff --git a/src/file_relay.c b/src/file_relay.c index e72be66..39382fb 100644 --- a/src/file_relay.c +++ b/src/file_relay.c @@ -188,7 +188,7 @@ file_relay_error_t file_relay_request_sources(file_relay_client_t client, const  	free(ack);  	err = FILE_RELAY_E_SUCCESS; -	*connection = client->parent->connection; +	*connection = client->parent->parent->connection;  leave:  	if (dict) { diff --git a/src/house_arrest.c b/src/house_arrest.c index e0d7771..ec76346 100644 --- a/src/house_arrest.c +++ b/src/house_arrest.c @@ -105,7 +105,7 @@ house_arrest_error_t house_arrest_client_free(house_arrest_client_t client)  		return HOUSE_ARREST_E_INVALID_ARG;  	house_arrest_error_t err = HOUSE_ARREST_E_SUCCESS; -	if (client->parent && client->parent->connection) { +	if (client->parent && client->parent->parent->connection) {  		house_arrest_error(property_list_service_client_free(client->parent));  	}  	client->parent = NULL; @@ -242,7 +242,7 @@ afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client  	if (!client || !client->parent || (client->mode == HOUSE_ARREST_CLIENT_MODE_AFC)) {  		return AFC_E_INVALID_ARG;  	} -	afc_error_t err = afc_client_new_from_connection(client->parent->connection, afc_client); +	afc_error_t err = afc_client_new_with_service_client(client->parent->parent, afc_client);  	if (err == AFC_E_SUCCESS) {  		client->mode = HOUSE_ARREST_CLIENT_MODE_AFC;  	} diff --git a/src/misagent.c b/src/misagent.c index c624603..cb84188 100644 --- a/src/misagent.c +++ b/src/misagent.c @@ -132,7 +132,7 @@ misagent_error_t misagent_client_free(misagent_client_t client)  		return MISAGENT_E_INVALID_ARG;  	misagent_error_t err = MISAGENT_E_SUCCESS; -	if (client->parent && client->parent->connection) { +	if (client->parent && client->parent->parent) {  		misagent_error(property_list_service_client_free(client->parent));  	}  	client->parent = NULL; diff --git a/src/mobilebackup2.c b/src/mobilebackup2.c index bcf5944..15ba469 100644 --- a/src/mobilebackup2.c +++ b/src/mobilebackup2.c @@ -279,13 +279,13 @@ mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, cons  	*bytes = 0; -	idevice_connection_t conn = client->parent->parent->connection; +	service_client_t raw = client->parent->parent->parent;  	int bytes_loc = 0;  	uint32_t sent = 0;  	do {  		bytes_loc = 0; -		idevice_connection_send(conn, data+sent, length-sent, (uint32_t*)&bytes_loc); +		service_send(raw, data+sent, length-sent, (uint32_t*)&bytes_loc);  		if (bytes_loc <= 0)  			break;  		sent += bytes_loc; @@ -321,7 +321,7 @@ mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, c  	if (!client || !client->parent || !data || (length == 0) || !bytes)  		return MOBILEBACKUP2_E_INVALID_ARG; -	idevice_connection_t conn = client->parent->parent->connection; +	service_client_t raw = client->parent->parent->parent;  	*bytes = 0; @@ -329,7 +329,7 @@ mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, c  	uint32_t received = 0;  	do {  		bytes_loc = 0; -		idevice_connection_receive(conn, data+received, length-received, (uint32_t*)&bytes_loc); +		service_receive(raw, data+received, length-received, (uint32_t*)&bytes_loc);  		if (bytes_loc <= 0) break;  		received += bytes_loc;  	} while (received < length); diff --git a/src/property_list_service.c b/src/property_list_service.c index 15adbc8..025a9bc 100644 --- a/src/property_list_service.c +++ b/src/property_list_service.c @@ -25,27 +25,28 @@  #include <string.h>  #include "property_list_service.h" -#include "idevice.h"  #include "debug.h"  #include "endianness.h"  /** - * Convert an idevice_error_t value to an property_list_service_error_t value. + * Convert a service_error_t value to a property_list_service_error_t value.   * Used internally to get correct error codes.   * - * @param err An idevice_error_t error code + * @param err A service_error_t error code   *   * @return A matching property_list_service_error_t error code,   *     PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR otherwise.   */ -static property_list_service_error_t idevice_to_property_list_service_error(idevice_error_t err) +static property_list_service_error_t service_to_property_list_service_error(service_error_t err)  {  	switch (err) { -		case IDEVICE_E_SUCCESS: +		case SERVICE_E_SUCCESS:  			return PROPERTY_LIST_SERVICE_E_SUCCESS; -		case IDEVICE_E_INVALID_ARG: +		case SERVICE_E_INVALID_ARG:  			return PROPERTY_LIST_SERVICE_E_INVALID_ARG; -		case IDEVICE_E_SSL_ERROR: +		case SERVICE_E_MUX_ERROR: +			return PROPERTY_LIST_SERVICE_E_MUX_ERROR; +		case SERVICE_E_SSL_ERROR:  			return PROPERTY_LIST_SERVICE_E_SSL_ERROR;  		default:  			break; @@ -70,19 +71,15 @@ property_list_service_error_t property_list_service_client_new(idevice_t device,  	if (!device || (service->port == 0) || !client || *client)  		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; -	/* Attempt connection */ -	idevice_connection_t connection = NULL; -	if (idevice_connect(device, service->port, &connection) != IDEVICE_E_SUCCESS) { -		return PROPERTY_LIST_SERVICE_E_MUX_ERROR; +	service_client_t parent = NULL; +	service_error_t rerr = service_client_new(device, service, &parent); +	if (rerr != SERVICE_E_SUCCESS) { +		return service_to_property_list_service_error(rerr);  	}  	/* create client object */  	property_list_service_client_t client_loc = (property_list_service_client_t)malloc(sizeof(struct property_list_service_client_private)); -	client_loc->connection = connection; - -	/* enable SSL if requested */ -	if (service->ssl_enabled == 1) -		property_list_service_enable_ssl(client_loc); +	client_loc->parent = parent;  	/* all done, return success */  	*client = client_loc; @@ -103,7 +100,7 @@ property_list_service_error_t property_list_service_client_free(property_list_se  	if (!client)  		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; -	property_list_service_error_t err = idevice_to_property_list_service_error(idevice_disconnect(client->connection)); +	property_list_service_error_t err = service_to_property_list_service_error(service_client_free(client->parent));  	free(client);  	return err;  } @@ -130,7 +127,7 @@ static property_list_service_error_t internal_plist_send(property_list_service_c  	uint32_t nlen = 0;  	int bytes = 0; -	if (!client || (client && !client->connection) || !plist) { +	if (!client || (client && !client->parent) || !plist) {  		return PROPERTY_LIST_SERVICE_E_INVALID_ARG;  	} @@ -146,9 +143,9 @@ static property_list_service_error_t internal_plist_send(property_list_service_c  	nlen = htobe32(length);  	debug_info("sending %d bytes", length); -	idevice_connection_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); +	service_send(client->parent, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);  	if (bytes == sizeof(nlen)) { -		idevice_connection_send(client->connection, content, length, (uint32_t*)&bytes); +		service_send(client->parent, content, length, (uint32_t*)&bytes);  		if (bytes > 0) {  			debug_info("sent %d bytes", bytes);  			debug_plist(plist); @@ -222,11 +219,11 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis  	uint32_t pktlen = 0;  	uint32_t bytes = 0; -	if (!client || (client && !client->connection) || !plist) { +	if (!client || (client && !client->parent) || !plist) {  		return PROPERTY_LIST_SERVICE_E_INVALID_ARG;  	} -	idevice_connection_receive_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); +	service_receive_with_timeout(client->parent, (char*)&pktlen, sizeof(pktlen), &bytes, timeout);  	debug_info("initial read=%i", bytes);  	if (bytes < 4) {  		debug_info("initial read failed!"); @@ -240,7 +237,7 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis  			content = (char*)malloc(pktlen);  			while (curlen < pktlen) { -				idevice_connection_receive(client->connection, content+curlen, pktlen-curlen, &bytes); +				service_receive(client->parent, content+curlen, pktlen-curlen, &bytes);  				if (bytes <= 0) {  					res = PROPERTY_LIST_SERVICE_E_MUX_ERROR;  					break; @@ -332,9 +329,9 @@ property_list_service_error_t property_list_service_receive_plist(property_list_   */  property_list_service_error_t property_list_service_enable_ssl(property_list_service_client_t client)  { -	if (!client || !client->connection) +	if (!client || !client->parent)  		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; -	return idevice_to_property_list_service_error(idevice_connection_enable_ssl(client->connection)); +	return service_to_property_list_service_error(service_enable_ssl(client->parent));  }  /** @@ -349,8 +346,8 @@ property_list_service_error_t property_list_service_enable_ssl(property_list_ser   */  property_list_service_error_t property_list_service_disable_ssl(property_list_service_client_t client)  { -	if (!client || !client->connection) +	if (!client || !client->parent)  		return PROPERTY_LIST_SERVICE_E_INVALID_ARG; -	return idevice_to_property_list_service_error(idevice_connection_disable_ssl(client->connection)); +	return service_to_property_list_service_error(service_disable_ssl(client->parent));  } diff --git a/src/property_list_service.h b/src/property_list_service.h index 8b15c09..c18fd76 100644 --- a/src/property_list_service.h +++ b/src/property_list_service.h @@ -23,6 +23,7 @@  #define __PROPERTY_LIST_SERVICE_H  #include <libimobiledevice/lockdown.h> +#include "service.h"  #include "idevice.h"  /* Error Codes */ @@ -35,7 +36,7 @@  #define PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR       -256  struct property_list_service_client_private { -	idevice_connection_t connection; +	service_client_t parent;  };  typedef struct property_list_service_client_private *property_list_service_client_t; diff --git a/src/service.c b/src/service.c new file mode 100644 index 0000000..929beff --- /dev/null +++ b/src/service.c @@ -0,0 +1,276 @@ +/*  + * service.c + * generic service implementation. + * + * Copyright (c) 2013 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  + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> + +#include "service.h" +#include "idevice.h" +#include "debug.h" + +/** + * Convert an idevice_error_t value to an service_error_t value. + * Used internally to get correct error codes. + * + * @param err An idevice_error_t error code + * + * @return A matching service_error_t error code, + *     SERVICE_E_UNKNOWN_ERROR otherwise. + */ +static service_error_t idevice_to_service_error(idevice_error_t err) +{ +	switch (err) { +		case IDEVICE_E_SUCCESS: +			return SERVICE_E_SUCCESS; +		case IDEVICE_E_INVALID_ARG: +			return SERVICE_E_INVALID_ARG; +		case IDEVICE_E_SSL_ERROR: +			return SERVICE_E_SSL_ERROR; +		default: +			break; +	} +	return SERVICE_E_UNKNOWN_ERROR; +} + +/** + * Creates a new service for the specified service descriptor. + *  + * @param device The device to connect to. + * @param service The service descriptor returned by lockdownd_start_service.  + * @param client Pointer that will be set to a newly allocated + *     service_client_t upon successful return. + * + * @return SERVICE_E_SUCCESS on success, + *     SERVICE_E_INVALID_ARG when one of the arguments is invalid, + *     or SERVICE_E_MUX_ERROR when connecting to the device failed. + */ +service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client) +{ +	if (!device || (service->port == 0) || !client || *client) +		return SERVICE_E_INVALID_ARG; + +	/* Attempt connection */ +	idevice_connection_t connection = NULL; +	if (idevice_connect(device, service->port, &connection) != IDEVICE_E_SUCCESS) { +		return SERVICE_E_MUX_ERROR; +	} + +	/* create client object */ +	service_client_t client_loc = (service_client_t)malloc(sizeof(struct service_client_private)); +	client_loc->connection = connection; + +	/* enable SSL if requested */ +	if (service->ssl_enabled == 1) +		service_enable_ssl(client_loc); + +	/* all done, return success */ +	*client = client_loc; +	return SERVICE_E_SUCCESS; +} + +/** + * Starts a new service on the specified device with given name and + * connects to it. + * + * @param device The device to connect to. + * @param service_name The name of the service to start. + * @param client Pointer that will point to a newly allocated service_client_t + *     upon successful return. Must be freed using service_client_free() after + *     use. + * + * @return SERVICE_E_SUCCESS on success, or a SERVICE_E_* error code + *     otherwise. + */ +service_error_t service_start_service(idevice_t device, const char* service_name, service_client_t *client) +{ +	*client = NULL; + +	lockdownd_client_t lckd = NULL; +	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &lckd, NULL)) { +		debug_info("Could not create a lockdown client."); +		return SERVICE_E_START_SERVICE_ERROR; +	} + +	lockdownd_service_descriptor_t service = NULL; +	lockdownd_start_service(lckd, service_name, &service); +	lockdownd_client_free(lckd); + +	if (service->port <= 0) { +		debug_info("Could not start service %s!", service_name); +		return SERVICE_E_START_SERVICE_ERROR; +	} + +	service_error_t res = service_client_new(device, service, client); +	if (res != SERVICE_E_SUCCESS) { +		debug_info("Could not connect to service %s! Port: %i, error: %i", service_name, service->port, res); +		return res; +	} + +	if (service) { +		lockdownd_service_descriptor_free(service); +		service = NULL; +	} + +	return SERVICE_E_SUCCESS; +} + +/** + * Frees a service instance. + * + * @param client The service instance to free. + * + * @return SERVICE_E_SUCCESS on success, + *     SERVICE_E_INVALID_ARG when client is invalid, or a + *     SERVICE_E_UNKNOWN_ERROR when another error occured. + */ +service_error_t service_client_free(service_client_t client) +{ +	if (!client) +		return SERVICE_E_INVALID_ARG; + +	service_error_t err = idevice_to_service_error(idevice_disconnect(client->connection)); +	free(client); +	return err; +} + +/** + * Sends data using the given service client. + * + * @param client The service client to use for sending. + * @param data Data to send + * @param size Size of the data to send + * @param sent Number of bytes sent (can be NULL to ignore) + * + * @return SERVICE_E_SUCCESS on success, + *      SERVICE_E_INVALID_ARG when one or more parameters are + *      invalid, or SERVICE_E_UNKNOWN_ERROR when an unspecified + *      error occurs. + */ +service_error_t service_send(service_client_t client, const char* data, uint32_t size, uint32_t *sent) +{ +	service_error_t res = SERVICE_E_UNKNOWN_ERROR; +	int bytes = 0; + +	if (!client || (client && !client->connection) || !data || (size == 0)) { +		return SERVICE_E_INVALID_ARG; +	} + +	debug_info("sending %d bytes", size); +	res = idevice_to_service_error(idevice_connection_send(client->connection, data, size, (uint32_t*)&bytes)); +	if (bytes <= 0) { +		debug_info("ERROR: sending to device failed."); +	} +	if (sent) { +		*sent = (uint32_t)bytes; +	} + +	return res; +} +  +/** + * Receives data using the given service client with specified timeout. + * + * @param client The service client to use for receiving + * @param data Buffer that will be filled with the data received + * @param size Number of bytes to receive + * @param received Number of bytes received (can be NULL to ignore) + * @param timeout Maximum time in milliseconds to wait for data. + * + * @return SERVICE_E_SUCCESS on success, + *      SERVICE_E_INVALID_ARG when one or more parameters are + *      invalid, SERVICE_E_MUX_ERROR when a communication error + *      occurs, or SERVICE_E_UNKNOWN_ERROR when an unspecified + *      error occurs. + */ +service_error_t service_receive_with_timeout(service_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +{ +	service_error_t res = SERVICE_E_UNKNOWN_ERROR; +	int bytes = 0; + +	if (!client || (client && !client->connection) || !data || (size == 0)) { +		return SERVICE_E_INVALID_ARG; +	} + +	res = idevice_to_service_error(idevice_connection_receive_timeout(client->connection, data, size, (uint32_t*)&bytes, timeout)); +	if (bytes <= 0) { +		debug_info("could not read data"); +	} +	if (received) { +		*received = (uint32_t)bytes; +	} + +	return res; +} + +/** + * Receives data using the given service client. + * + * @param client The service client to use for receiving + * @param data Buffer that will be filled with the data received + * @param size Number of bytes to receive + * @param received Number of bytes received (can be NULL to ignore) + * + * @return SERVICE_E_SUCCESS on success, + *      SERVICE_E_INVALID_ARG when one or more parameters are + *      invalid, SERVICE_E_MUX_ERROR when a communication error + *      occurs, or SERVICE_E_UNKNOWN_ERROR when an unspecified + *      error occurs. + */ +service_error_t service_receive(service_client_t client, char* data, uint32_t size, uint32_t *received) +{ +	return service_receive_with_timeout(client, data, size, received, 10000); +} + +/** + * Enable SSL for the given service client. + * + * @param client The connected service client for that SSL should be enabled. + * + * @return SERVICE_E_SUCCESS on success, + *     SERVICE_E_INVALID_ARG if client or client->connection is + *     NULL, SERVICE_E_SSL_ERROR when SSL could not be enabled, + *     or SERVICE_E_UNKNOWN_ERROR otherwise. + */ +service_error_t service_enable_ssl(service_client_t client) +{ +	if (!client || !client->connection) +		return SERVICE_E_INVALID_ARG; +	return idevice_to_service_error(idevice_connection_enable_ssl(client->connection)); +} + +/** + * Disable SSL for the given service client. + * + * @param client The connected service client for that SSL should be disabled. + * + * @return SERVICE_E_SUCCESS on success, + *     SERVICE_E_INVALID_ARG if client or client->connection is + *     NULL, or SERVICE_E_UNKNOWN_ERROR otherwise. + */ +service_error_t service_disable_ssl(service_client_t client) +{ +	if (!client || !client->connection) +		return SERVICE_E_INVALID_ARG; +	return idevice_to_service_error(idevice_connection_disable_ssl(client->connection)); +} + diff --git a/src/service.h b/src/service.h new file mode 100644 index 0000000..e498ed7 --- /dev/null +++ b/src/service.h @@ -0,0 +1,59 @@ +/*  + * service.h + * Definitions for the generic service implementation + *  + * Copyright (c) 2013 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 SERVICE_H +#define SERVICE_H + +#include "libimobiledevice/lockdown.h" +#include "idevice.h" + +/* Error Codes */ +#define SERVICE_E_SUCCESS                0 +#define SERVICE_E_INVALID_ARG           -1 +#define SERVICE_E_MUX_ERROR             -3 +#define SERVICE_E_SSL_ERROR             -4 +#define SERVICE_E_START_SERVICE_ERROR   -5 +#define SERVICE_E_UNKNOWN_ERROR       -256 + +struct service_client_private { +	idevice_connection_t connection; +}; + +typedef struct service_client_private *service_client_t; + +typedef int16_t service_error_t; + +/* creation and destruction */ +service_error_t service_client_new(idevice_t device, lockdownd_service_descriptor_t service, service_client_t *client); +service_error_t service_start_service(idevice_t device, const char* service_name, service_client_t *client); +service_error_t service_client_free(service_client_t client); + +/* sending */ +service_error_t service_send(service_client_t client, const char *data, uint32_t size, uint32_t *sent); + +/* receiving */ +service_error_t service_receive_with_timeout(service_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); +service_error_t service_receive(service_client_t client, char *data, uint32_t size, uint32_t *received); + +/* misc */ +service_error_t service_enable_ssl(service_client_t client); +service_error_t service_disable_ssl(service_client_t client); + +#endif  | 
