diff options
| author | 2013-05-23 14:14:48 +0200 | |
|---|---|---|
| committer | 2013-05-23 14:14:48 +0200 | |
| commit | 06d2399461182e0c0c113fb473902e204117641e (patch) | |
| tree | a246259839027fbf1cf5064a1a6c8c132bdce70e | |
| parent | c68121961226dcce52ad38daced6ad848555849e (diff) | |
| download | libimobiledevice-06d2399461182e0c0c113fb473902e204117641e.tar.gz libimobiledevice-06d2399461182e0c0c113fb473902e204117641e.tar.bz2 | |
Add protocol implementation for syslog_relay service
| -rw-r--r-- | include/Makefile.am | 3 | ||||
| -rw-r--r-- | include/libimobiledevice/syslog_relay.h | 72 | ||||
| -rw-r--r-- | src/Makefile.am | 3 | ||||
| -rw-r--r-- | src/syslog_relay.c | 304 | ||||
| -rw-r--r-- | src/syslog_relay.h | 36 | 
5 files changed, 416 insertions, 2 deletions
| diff --git a/include/Makefile.am b/include/Makefile.am index a697453..39a8d60 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -17,4 +17,5 @@ nobase_include_HEADERS = libimobiledevice/libimobiledevice.h \  			 libimobiledevice/restore.h\  			 libimobiledevice/webinspector.h\  			 libimobiledevice/heartbeat.h\ -			 libimobiledevice/diagnostics_relay.h +			 libimobiledevice/diagnostics_relay.h\ +			 libimobiledevice/syslog_relay.h
\ No newline at end of file diff --git a/include/libimobiledevice/syslog_relay.h b/include/libimobiledevice/syslog_relay.h new file mode 100644 index 0000000..9152d79 --- /dev/null +++ b/include/libimobiledevice/syslog_relay.h @@ -0,0 +1,72 @@ +/** + * @file libimobiledevice/syslog_relay.h + * @brief Capture the syslog output from a device. + * \internal + * + * Copyright (c) 2013 Martin Szulecki 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 ISYSLOG_RELAY_H +#define ISYSLOG_RELAY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libimobiledevice/libimobiledevice.h> +#include <libimobiledevice/lockdown.h> + +#define SYSLOG_RELAY_SERVICE_NAME "com.apple.syslog_relay" + +/** @name Error Codes */ +/*@{*/ +#define SYSLOG_RELAY_E_SUCCESS                0 +#define SYSLOG_RELAY_E_INVALID_ARG           -1 +#define SYSLOG_RELAY_E_MUX_ERROR             -2 +#define SYSLOG_RELAY_E_SSL_ERROR             -3 +#define SYSLOG_RELAY_E_UNKNOWN_ERROR       -256 +/*@}*/ + +/** Represents an error code. */ +typedef int16_t syslog_relay_error_t; + +typedef struct syslog_relay_client_private syslog_relay_client_private; +typedef syslog_relay_client_private *syslog_relay_client_t; /**< The client handle. */ + +/** Receives each character received from the device. */ +typedef void (*syslog_relay_receive_cb_t)(char c, void *user_data); + +/* Interface */ +syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client); +syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label); +syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client); + +syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data); +syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client); + +/* sending */ +syslog_relay_error_t syslog_relay_send(syslog_relay_client_t client, const char *data, uint32_t size, uint32_t *sent); + +/* receiving */ +syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); +syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char *data, uint32_t size, uint32_t *received); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 7024ead..d47bee6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,8 @@ libimobiledevice_la_SOURCES = idevice.c idevice.h \  		       restore.c restore.h\  		       diagnostics_relay.c diagnostics_relay.h\  		       heartbeat.c heartbeat.h\ -		       webinspector.c webinspector.h +		       webinspector.c webinspector.h\ +		       syslog_relay.c syslog_relay.h  if WIN32  libimobiledevice_la_LIBADD += -lole32 diff --git a/src/syslog_relay.c b/src/syslog_relay.c new file mode 100644 index 0000000..807305b --- /dev/null +++ b/src/syslog_relay.c @@ -0,0 +1,304 @@ +/* + * syslog_relay.c  + * com.apple.syslog_relay service implementation. + *  + * Copyright (c) 2013 Martin Szulecki 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 <string.h> +#include <stdlib.h> + +#include "syslog_relay.h" +#include "lockdown.h" +#include "common/debug.h" + +struct syslog_relay_worker_thread { +	syslog_relay_client_t client; +	syslog_relay_receive_cb_t cbfunc; +	void *user_data; +}; + +/** + * Convert a service_error_t value to a syslog_relay_error_t value. + * Used internally to get correct error codes. + * + * @param err An service_error_t error code + * + * @return A matching syslog_relay_error_t error code, + *     SYSLOG_RELAY_E_UNKNOWN_ERROR otherwise. + */ +static syslog_relay_error_t syslog_relay_error(service_error_t err) +{ +	switch (err) { +		case SERVICE_E_SUCCESS: +			return SYSLOG_RELAY_E_SUCCESS; +		case SERVICE_E_INVALID_ARG: +			return SYSLOG_RELAY_E_INVALID_ARG; +		case SERVICE_E_MUX_ERROR: +			return SYSLOG_RELAY_E_MUX_ERROR; +		case SERVICE_E_SSL_ERROR: +			return SYSLOG_RELAY_E_SSL_ERROR; +		default: +			break; +	} +	return SYSLOG_RELAY_E_UNKNOWN_ERROR; +} + +/** + * Connects to the syslog_relay service on the specified device. + * + * @param device The device to connect to. + * @param service The service descriptor returned by lockdownd_start_service. + * @param client Pointer that will point to a newly allocated + *     syslog_relay_client_t upon successful return. Must be freed using + *     syslog_relay_client_free() after use. + * + * @return SYSLOG_RELAY_E_SUCCESS on success, SYSLOG_RELAY_E_INVALID_ARG when + *     client is NULL, or an SYSLOG_RELAY_E_* error code otherwise. + */ +syslog_relay_error_t syslog_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, syslog_relay_client_t * client) +{ +	*client = NULL; + +	if (!device || !service || service->port == 0 || !client || *client) { +		debug_info("Incorrect parameter passed to syslog_relay_client_new."); +		return SYSLOG_RELAY_E_INVALID_ARG; +	} + +	debug_info("Creating syslog_relay_client, port = %d.", service->port); + +	service_client_t parent = NULL; +	syslog_relay_error_t ret = syslog_relay_error(service_client_new(device, service, &parent)); +	if (ret != SYSLOG_RELAY_E_SUCCESS) { +		debug_info("Creating base service client failed. Error: %i", ret); +		return ret; +	} + +	syslog_relay_client_t client_loc = (syslog_relay_client_t) malloc(sizeof(struct syslog_relay_client_private)); +	client_loc->parent = parent; +	client_loc->worker = (thread_t)NULL; + +	*client = client_loc; + +	debug_info("syslog_relay_client successfully created."); +	return 0; +} + +/** + * Starts a new syslog_relay service on the specified device and connects to it. + * + * @param device The device to connect to. + * @param client Pointer that will point to a newly allocated + *     syslog_relay_client_t upon successful return. Must be freed using + *     syslog_relay_client_free() after use. + * @param label The label to use for communication. Usually the program name. + *  Pass NULL to disable sending the label in requests to lockdownd. + * + * @return SYSLOG_RELAY_E_SUCCESS on success, or an SYSLOG_RELAY_E_* error + *     code otherwise. + */ +syslog_relay_error_t syslog_relay_client_start_service(idevice_t device, syslog_relay_client_t * client, const char* label) +{ +	syslog_relay_error_t err = SYSLOG_RELAY_E_UNKNOWN_ERROR; +	service_client_factory_start_service(device, SYSLOG_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(syslog_relay_client_new), &err); +	return err; +} + +/** + * Disconnects a syslog_relay client from the device and frees up the + * syslog_relay client data. + * + * @param client The syslog_relay client to disconnect and free. + * + * @return SYSLOG_RELAY_E_SUCCESS on success, SYSLOG_RELAY_E_INVALID_ARG when + *     client is NULL, or an SYSLOG_RELAY_E_* error code otherwise. + */ +syslog_relay_error_t syslog_relay_client_free(syslog_relay_client_t client) +{ +	if (!client) +		return SYSLOG_RELAY_E_INVALID_ARG; + +	syslog_relay_error_t err = syslog_relay_error(service_client_free(client->parent)); +	client->parent = NULL; +	if (client->worker) { +		debug_info("Joining syslog capture callback worker thread"); +		thread_join(client->worker); +	} +	free(client); + +	return err; +} + +/** + * Sends data to the service. + * + * @param client The syslog_relay client + * @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 SYSLOG_RELAY_E_SUCCESS on success, + *  SYSLOG_RELAY_E_INVALID_ARG when client or plist is NULL + */ +syslog_relay_error_t syslog_relay_send(syslog_relay_client_t client, const char* data, uint32_t size, uint32_t *sent) +{ +	syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR; +	int bytes = 0; + +	if (!client || !data || (size == 0)) { +		return SYSLOG_RELAY_E_INVALID_ARG; +	} + +	res = syslog_relay_error(service_send(client->parent, 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 from the service. + * + * @param client The syslog_relay client + * @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 SYSLOG_RELAY_E_SUCCESS on success, + *  SYSLOG_RELAY_E_INVALID_ARG when client or plist is NULL + */ +syslog_relay_error_t syslog_relay_receive(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received) +{ +	return syslog_relay_receive_with_timeout(client, data, size, received, 1000); +} + +/** + * Receives data using the given syslog_relay client with specified timeout. + * + * @param client The syslog_relay 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 SYSLOG_RELAY_E_SUCCESS on success, + *      SYSLOG_RELAY_E_INVALID_ARG when one or more parameters are + *      invalid, SYSLOG_RELAY_E_MUX_ERROR when a communication error + *      occurs, or SYSLOG_RELAY_E_UNKNOWN_ERROR when an unspecified + *      error occurs. + */ +syslog_relay_error_t syslog_relay_receive_with_timeout(syslog_relay_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +{ +	syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR; +	int bytes = 0; + +	if (!client || !data || (size == 0)) { +		return SYSLOG_RELAY_E_INVALID_ARG; +	} + +	res = syslog_relay_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout)); +	if (bytes <= 0) { +		debug_info("Could not read data, error %d", res); +	} +	if (received) { +		*received = (uint32_t)bytes; +	} + +	return res; +} + +void *syslog_relay_worker(void *arg) +{ +	service_error_t ret = SERVICE_E_UNKNOWN_ERROR; +	struct syslog_relay_worker_thread *srwt = (struct syslog_relay_worker_thread*)arg; + +	if (!srwt) +		return NULL; + +	debug_info("Running"); + +	while (srwt->client->parent) { +		char c; +		uint32_t bytes = 0; +		ret = syslog_relay_receive_with_timeout(srwt->client, &c, 1, &bytes, 0); +		if (ret < 0 || (bytes != 1)) { +			debug_info("Connection to syslog relay interrupted"); +			break; +		} +		if(c != 0) { +			srwt->cbfunc(c, srwt->user_data); +		} +	} + +	if (srwt) { +		free(srwt); +	} + +	debug_info("Exiting"); + +	return NULL; +} + +syslog_relay_error_t syslog_relay_start_capture(syslog_relay_client_t client, syslog_relay_receive_cb_t callback, void* user_data) +{ +	if (!client || !callback) +		return SYSLOG_RELAY_E_INVALID_ARG; + +	syslog_relay_error_t res = SYSLOG_RELAY_E_UNKNOWN_ERROR; + +	if (client->worker) { +		debug_info("Another syslog capture thread appears to be running already."); +		return res; +	} + +	/* start worker thread */ +	struct syslog_relay_worker_thread *srwt = (struct syslog_relay_worker_thread*)malloc(sizeof(struct syslog_relay_worker_thread)); +	if (srwt) { +		srwt->client = client; +		srwt->cbfunc = callback; +		srwt->user_data = user_data; + +		if (thread_create(&client->worker, syslog_relay_worker, srwt) == 0) { +			res = SYSLOG_RELAY_E_SUCCESS; +		} +	} + +	return res; +} + +syslog_relay_error_t syslog_relay_stop_capture(syslog_relay_client_t client) +{ +	if (client->worker) { +		/* notify thread to finish */ +		service_client_t parent = client->parent; +		client->parent = NULL; +		/* join thread to make it exit */ +		thread_join(client->worker); +		client->worker = (thread_t)NULL; +		client->parent = parent; +	} + +	return SYSLOG_RELAY_E_SUCCESS; +}
\ No newline at end of file diff --git a/src/syslog_relay.h b/src/syslog_relay.h new file mode 100644 index 0000000..c6dcf32 --- /dev/null +++ b/src/syslog_relay.h @@ -0,0 +1,36 @@ +/* + * syslog_relay.h + * com.apple.syslog_relay service header file. + *  + * Copyright (c) 2013 Martin Szulecki 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 _SYSLOG_RELAY_H +#define _SYSLOG_RELAY_H + +#include "libimobiledevice/syslog_relay.h" +#include "service.h" +#include "common/thread.h" + +struct syslog_relay_client_private { +	service_client_t parent; +	thread_t worker; +}; + +void *syslog_relay_worker(void *arg); + +#endif | 
