diff options
Diffstat (limited to 'src/debugserver.c')
-rw-r--r-- | src/debugserver.c | 259 |
1 files changed, 139 insertions, 120 deletions
diff --git a/src/debugserver.c b/src/debugserver.c index b6a8b62..74ade8a 100644 --- a/src/debugserver.c +++ b/src/debugserver.c @@ -64,7 +64,7 @@ static debugserver_error_t debugserver_error(service_error_t err) return DEBUGSERVER_E_UNKNOWN_ERROR; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t* client) +debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t* client) { *client = NULL; @@ -89,6 +89,8 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device debugserver_client_t client_loc = (debugserver_client_t) malloc(sizeof(struct debugserver_client_private)); client_loc->parent = parent; client_loc->noack_mode = 0; + client_loc->cancel_receive = NULL; + client_loc->receive_loop_timeout = 1000; *client = client_loc; @@ -96,7 +98,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device return DEBUGSERVER_E_SUCCESS; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label) +debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label) { debugserver_error_t err = DEBUGSERVER_E_UNKNOWN_ERROR; service_client_factory_start_service(device, DEBUGSERVER_SECURE_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err); @@ -107,7 +109,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_start_service(idevic return err; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_free(debugserver_client_t client) +debugserver_error_t debugserver_client_free(debugserver_client_t client) { if (!client) return DEBUGSERVER_E_INVALID_ARG; @@ -119,7 +121,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_free(debugserver_cli return err; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent) +debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent) { debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; int bytes = 0; @@ -140,7 +142,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send(debugserver_cli return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) +debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout) { debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; int bytes = 0; @@ -150,7 +152,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout } res = debugserver_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout)); - if (bytes <= 0) { + if (bytes <= 0 && res != DEBUGSERVER_E_TIMEOUT) { debug_info("Could not read data, error %d", res); } if (received) { @@ -160,12 +162,17 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout return (bytes > 0) ? DEBUGSERVER_E_SUCCESS : res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received) +debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received) { - return debugserver_client_receive_with_timeout(client, data, size, received, 1000); + debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; + do { + /* Is this allowed to return DEBUGSERVER_E_TIMEOUT and also set data and received? */ + res = debugserver_client_receive_with_timeout(client, data, size, received, client->receive_loop_timeout); + } while (res == DEBUGSERVER_E_TIMEOUT && client->cancel_receive != NULL && !client->cancel_receive()); + return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command) +debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command) { int i; debugserver_command_t tmp = (debugserver_command_t) malloc(sizeof(struct debugserver_command_private)); @@ -190,7 +197,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* nam return DEBUGSERVER_E_SUCCESS; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_free(debugserver_command_t command) +debugserver_error_t debugserver_command_free(debugserver_command_t command) { int i; debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; @@ -232,10 +239,10 @@ static char debugserver_int2hex(int x) return hexchars[x]; } -#define DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(byte) debugserver_int2hex((byte >> 0x4) & 0xf) -#define DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(byte) debugserver_int2hex(byte & 0xf) -#define DEBUGSERVER_HEX_DECODE_FIRST_BYTE(byte) ((byte >> 0x4) & 0xf) -#define DEBUGSERVER_HEX_DECODE_SECOND_BYTE(byte) (byte & 0xf) +#define DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(byte) debugserver_int2hex(((byte) >> 0x4) & 0xf) +#define DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(byte) debugserver_int2hex((byte) & 0xf) +#define DEBUGSERVER_HEX_DECODE_FIRST_BYTE(byte) (((byte) >> 0x4) & 0xf) +#define DEBUGSERVER_HEX_DECODE_SECOND_BYTE(byte) ((byte) & 0xf) static uint32_t debugserver_get_checksum_for_buffer(const char* buffer, uint32_t size) { @@ -268,7 +275,7 @@ static int debugserver_response_is_checksum_valid(const char* response, uint32_t return 1; } -LIBIMOBILEDEVICE_API void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length) +void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length) { uint32_t position; uint32_t index; @@ -284,7 +291,7 @@ LIBIMOBILEDEVICE_API void debugserver_encode_string(const char* buffer, char** e } } -LIBIMOBILEDEVICE_API void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer) +void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer) { *buffer = malloc(sizeof(char) * ((encoded_length / 2)+1)); char* t = *buffer; @@ -343,7 +350,7 @@ static debugserver_error_t debugserver_client_send_noack(debugserver_client_t cl return debugserver_client_send(client, "-", sizeof(char), NULL); } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled) +debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled) { if (!client) return DEBUGSERVER_E_INVALID_ARG; @@ -355,130 +362,137 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugse return DEBUGSERVER_E_SUCCESS; } -static int debugserver_client_receive_internal_check(debugserver_client_t client, char* received_char) +debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout) +{ + if (!client) + return DEBUGSERVER_E_INVALID_ARG; + + client->cancel_receive = cancel_receive; + client->receive_loop_timeout = receive_loop_timeout; + + debug_info("receive params: cancel_receive %s, receive_loop_timeout %dms", (client->cancel_receive == NULL ? "unset": "set"), client->receive_loop_timeout); + + return DEBUGSERVER_E_SUCCESS; +} + +static debugserver_error_t debugserver_client_receive_internal_char(debugserver_client_t client, char* received_char) { debugserver_error_t res = DEBUGSERVER_E_SUCCESS; - int did_receive_char = 0; - char buffer = 0; uint32_t bytes = 0; /* we loop here as we expect an answer */ - res = debugserver_client_receive_with_timeout(client, &buffer, sizeof(char), &bytes, 1000); - if (res == DEBUGSERVER_E_SUCCESS && received_char[0] != 0) { - if (memcmp(&buffer, received_char, sizeof(char)) == 0) { - did_receive_char = 1; - } - } else { - did_receive_char = 0; + res = debugserver_client_receive(client, received_char, sizeof(char), &bytes); + if (res != DEBUGSERVER_E_SUCCESS) { + return res; } - - if (!did_receive_char) { - memcpy(received_char, &buffer, sizeof(char)); + if (bytes != 1) { + debug_info("received %d bytes when asking for %d!", bytes, sizeof(char)); + return DEBUGSERVER_E_UNKNOWN_ERROR; } - - return did_receive_char; + return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size) +debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size) { debugserver_error_t res = DEBUGSERVER_E_SUCCESS; - int should_receive = 1; + char data = '\0'; int skip_prefix = 0; - char* command_prefix = strdup("$"); - char* buffer = NULL; + char* buffer = malloc(1024); uint32_t buffer_size = 0; - uint32_t buffer_capacity = 0; + uint32_t buffer_capacity = 1024; if (response) *response = NULL; if (!client->noack_mode) { - char ack[2] = {'+', '\0'}; - debug_info("attempting to receive ACK %c", *ack); - should_receive = debugserver_client_receive_internal_check(client, ack); - debug_info("received char: %c", *ack); - if (strncmp(ack, command_prefix, sizeof(char)) == 0) { - should_receive = 1; + debug_info("attempting to receive ACK (+)"); + res = debugserver_client_receive_internal_char(client, &data); + if (res != DEBUGSERVER_E_SUCCESS) { + goto cleanup; + } + if (data == '+') { + debug_info("received ACK (+)"); + } else if (data == '$') { + debug_info("received prefix ($)"); + buffer[0] = '$'; + buffer_size = 1; skip_prefix = 1; - buffer = malloc(1024); - buffer_capacity = 1024; - strcpy(buffer, command_prefix); - buffer_size += sizeof(char); - debug_info("received ACK"); + } else { + debug_info("unrecognized response when looking for ACK: %c", data); + goto cleanup; } } - debug_info("should_receive: %d, skip_prefix: %d", should_receive, skip_prefix); - - if (should_receive && !skip_prefix) { - debug_info("attempting to receive prefix"); - should_receive = debugserver_client_receive_internal_check(client, command_prefix); - debug_info("received command_prefix: %c", *command_prefix); - if (should_receive) { - if (buffer) { - strcpy(buffer, command_prefix); - } else { - buffer = malloc(1024); - buffer_capacity = 1024; - strcpy(buffer, command_prefix); - buffer_size += sizeof(char); - } + debug_info("skip_prefix: %d", skip_prefix); + + if (!skip_prefix) { + debug_info("attempting to receive prefix ($)"); + res = debugserver_client_receive_internal_char(client, &data); + if (res != DEBUGSERVER_E_SUCCESS) { + goto cleanup; + } + if (data == '$') { + debug_info("received prefix ($)"); + buffer[0] = '$'; + buffer_size = 1; + } else { + debug_info("unrecognized response when looking for prefix: %c", data); + goto cleanup; } } - debug_info("buffer: %*s, should_receive: %d, skip_prefix: %d", buffer_size, buffer, should_receive, skip_prefix); + uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH; + int receiving_checksum_response = 0; + debug_info("attempting to read up response until checksum"); - if (should_receive) { - uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH; - int receiving_checksum_response = 0; - debug_info("attempting to read up response until checksum"); - - while ((checksum_length > 0)) { - char data[2] = {'#', '\0'}; - if (debugserver_client_receive_internal_check(client, data)) { - receiving_checksum_response = 1; - } - if (receiving_checksum_response) { - checksum_length--; - } - if (buffer_size + 1 >= buffer_capacity) { - char* newbuffer = realloc(buffer, buffer_capacity+1024); - if (!newbuffer) { - return DEBUGSERVER_E_UNKNOWN_ERROR; - } - buffer = newbuffer; - buffer[buffer_capacity] = '\0'; - buffer_capacity += 1024; - } - strcat(buffer, data); - buffer_size += sizeof(char); + while ((checksum_length > 0)) { + res = debugserver_client_receive_internal_char(client, &data); + if (res != DEBUGSERVER_E_SUCCESS) { + goto cleanup; } - debug_info("validating response checksum..."); - if (client->noack_mode || debugserver_response_is_checksum_valid(buffer, buffer_size)) { - if (response) { - /* assemble response string */ - uint32_t resp_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1); - *response = (char*)malloc(resp_size + 1); - memcpy(*response, buffer + 1, resp_size); - (*response)[resp_size] = '\0'; - if (response_size) *response_size = resp_size; - } - if (!client->noack_mode) { - /* confirm valid command */ - debugserver_client_send_ack(client); - } - } else { - /* response was invalid */ - res = DEBUGSERVER_E_RESPONSE_ERROR; - if (!client->noack_mode) { - /* report invalid command */ - debugserver_client_send_noack(client); + if (data == '#') { + receiving_checksum_response = 1; + } + if (receiving_checksum_response) { + checksum_length--; + } + if (buffer_size + 1 >= buffer_capacity) { + char* newbuffer = realloc(buffer, buffer_capacity+1024); + if (!newbuffer) { + return DEBUGSERVER_E_UNKNOWN_ERROR; } + buffer = newbuffer; + buffer_capacity += 1024; + } + buffer[buffer_size] = data; + buffer_size += sizeof(char); + } + debug_info("validating response checksum..."); + if (client->noack_mode || debugserver_response_is_checksum_valid(buffer, buffer_size)) { + if (response) { + /* assemble response string */ + uint32_t resp_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1); + *response = (char*)malloc(resp_size + 1); + memcpy(*response, buffer + 1, resp_size); + (*response)[resp_size] = '\0'; + if (response_size) *response_size = resp_size; + } + if (!client->noack_mode) { + /* confirm valid command */ + debugserver_client_send_ack(client); + } + } else { + /* response was invalid */ + res = DEBUGSERVER_E_RESPONSE_ERROR; + if (!client->noack_mode) { + /* report invalid command */ + debugserver_client_send_noack(client); } } +cleanup: if (response) { debug_info("response: %s", *response); } @@ -486,13 +500,10 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_response(deb if (buffer) free(buffer); - if (command_prefix) - free(command_prefix); - return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size) +debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size) { debugserver_error_t res = DEBUGSERVER_E_SUCCESS; int i; @@ -548,7 +559,7 @@ cleanup: return res; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response) +debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response) { if (!client || !env) return DEBUGSERVER_E_INVALID_ARG; @@ -567,21 +578,25 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_ return result; } -LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response) +debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response) { if (!client || !argc) return DEBUGSERVER_E_INVALID_ARG; debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR; char *pkt = NULL; - int pkt_len = 0; + size_t pkt_len = 0; int i = 0; /* calculate total length */ while (i < argc && argv && argv[i]) { char *prefix = NULL; - asprintf(&prefix, ",%d,%d,", (int)strlen(argv[i]) * 2, i); - pkt_len += (int)strlen(prefix) + (int)strlen(argv[i]) * 2; + int ret = asprintf(&prefix, ",%zu,%d,", strlen(argv[i]) * 2, i); + if (ret < 0 || prefix == NULL) { + debug_info("asprintf failed, out of memory?"); + return DEBUGSERVER_E_UNKNOWN_ERROR; + } + pkt_len += strlen(prefix) + strlen(argv[i]) * 2; free(prefix); i++; } @@ -598,10 +613,14 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver char *prefix = NULL; char *m = NULL; - int arg_len = strlen(argv[i]); - int arg_hexlen = arg_len * 2; + size_t arg_len = strlen(argv[i]); + size_t arg_hexlen = arg_len * 2; - asprintf(&prefix, ",%d,%d,", arg_hexlen, i); + int ret = asprintf(&prefix, ",%zu,%d,", arg_hexlen, i); + if (ret < 0 || prefix == NULL) { + debug_info("asprintf failed, out of memory?"); + return DEBUGSERVER_E_UNKNOWN_ERROR; + } m = (char *) malloc(arg_hexlen); char *p = m; |