From 4d8b89223cbc9f530cc650ab5131c09eab1af258 Mon Sep 17 00:00:00 2001 From: DanyL Date: Thu, 13 Jun 2019 02:01:04 +0300 Subject: Timeout support for SSL connections and better timeout handeling. --- src/heartbeat.c | 4 ++ src/idevice.c | 59 +++++++++++++++++----- src/property_list_service.c | 116 +++++++++++++++++++++++--------------------- src/service.c | 7 ++- src/webinspector.c | 4 ++ 5 files changed, 122 insertions(+), 68 deletions(-) (limited to 'src') diff --git a/src/heartbeat.c b/src/heartbeat.c index fe7e63a..9a527cc 100644 --- a/src/heartbeat.c +++ b/src/heartbeat.c @@ -52,6 +52,10 @@ static heartbeat_error_t heartbeat_error(property_list_service_error_t err) return HEARTBEAT_E_MUX_ERROR; case PROPERTY_LIST_SERVICE_E_SSL_ERROR: return HEARTBEAT_E_SSL_ERROR; + case PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA: + return HEARTBEAT_E_NOT_ENOUGH_DATA; + case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT: + return HEARTBEAT_E_TIMEOUT; default: break; } diff --git a/src/idevice.c b/src/idevice.c index be29884..5d5c950 100644 --- a/src/idevice.c +++ b/src/idevice.c @@ -43,6 +43,7 @@ #include "idevice.h" #include "common/userpref.h" +#include "common/socket.h" #include "common/thread.h" #include "common/debug.h" @@ -381,6 +382,24 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_ return internal_connection_send(connection, data, len, sent_bytes); } +static idevice_error_t socket_recv_to_idevice_error(int conn_error, uint32_t len, uint32_t received) +{ + if (conn_error < 0) { + switch (conn_error) { + case -EAGAIN: + debug_info("ERROR: received partial data %d/%d (%s)", received, len, strerror(-conn_error)); + return IDEVICE_E_NOT_ENOUGH_DATA; + case -ETIMEDOUT: + debug_info("ERROR: received timeout (%s)", strerror(-conn_error)); + return IDEVICE_E_TIMEOUT; + default: + return IDEVICE_E_UNKNOWN_ERROR; + } + } + + return IDEVICE_E_SUCCESS; +} + /** * Internally used function for receiving raw data over the given connection * using a timeout. @@ -392,12 +411,14 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t } if (connection->type == CONNECTION_USBMUXD) { - int res = usbmuxd_recv_timeout((int)(long)connection->data, data, len, recv_bytes, timeout); - if (res < 0) { - debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", res, strerror(errno)); - return (res == -EAGAIN ? IDEVICE_E_NOT_ENOUGH_DATA : IDEVICE_E_UNKNOWN_ERROR); + int conn_error = usbmuxd_recv_timeout((int)(long)connection->data, data, len, recv_bytes, timeout); + idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, *recv_bytes); + + if (error == IDEVICE_E_UNKNOWN_ERROR) { + debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", conn_error, strerror(-conn_error)); } - return IDEVICE_E_SUCCESS; + + return error; } else { debug_info("Unknown connection type %d", connection->type); } @@ -406,13 +427,27 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) { - if (!connection || (connection->ssl_data && !connection->ssl_data->session)) { + if (!connection || (connection->ssl_data && !connection->ssl_data->session) || len == 0) { return IDEVICE_E_INVALID_ARG; } if (connection->ssl_data) { uint32_t received = 0; + while (received < len) { + + int conn_error = socket_check_fd((int)(long)connection->data, FDM_READ, timeout); + idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, received); + + switch (error) { + case IDEVICE_E_SUCCESS: + break; + case IDEVICE_E_UNKNOWN_ERROR: + debug_info("ERROR: socket_check_fd returned %d (%s)", conn_error, strerror(-conn_error)); + default: + return error; + } + #ifdef HAVE_OPENSSL int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received); #else @@ -424,13 +459,15 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_ break; } } + debug_info("SSL_read %d, received %d", len, received); - if (received > 0) { - *recv_bytes = received; - return IDEVICE_E_SUCCESS; + if (received < len) { + *recv_bytes = 0; + return IDEVICE_E_SSL_ERROR; } - *recv_bytes = 0; - return IDEVICE_E_SSL_ERROR; + + *recv_bytes = received; + return IDEVICE_E_SUCCESS; } return internal_connection_receive_timeout(connection, data, len, recv_bytes, timeout); } diff --git a/src/property_list_service.c b/src/property_list_service.c index f411699..a6e3e24 100644 --- a/src/property_list_service.c +++ b/src/property_list_service.c @@ -48,6 +48,10 @@ static property_list_service_error_t service_to_property_list_service_error(serv return PROPERTY_LIST_SERVICE_E_MUX_ERROR; case SERVICE_E_SSL_ERROR: return PROPERTY_LIST_SERVICE_E_SSL_ERROR; + case SERIVCE_E_NOT_ENOUGH_DATA: + return PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA; + case SERVICE_E_TIMEOUT: + return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT; default: break; } @@ -108,7 +112,7 @@ static property_list_service_error_t internal_plist_send(property_list_service_c char *content = NULL; uint32_t length = 0; uint32_t nlen = 0; - int bytes = 0; + uint32_t bytes = 0; if (!client || (client && !client->parent) || !plist) { return PROPERTY_LIST_SERVICE_E_INVALID_ARG; @@ -126,13 +130,13 @@ static property_list_service_error_t internal_plist_send(property_list_service_c nlen = htobe32(length); debug_info("sending %d bytes", length); - service_send(client->parent, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); + service_send(client->parent, (const char*)&nlen, sizeof(nlen), &bytes); if (bytes == sizeof(nlen)) { - service_send(client->parent, content, length, (uint32_t*)&bytes); + service_send(client->parent, content, length, &bytes); if (bytes > 0) { debug_info("sent %d bytes", bytes); debug_plist(plist); - if ((uint32_t)bytes == length) { + if (bytes == length) { res = PROPERTY_LIST_SERVICE_E_SUCCESS; } else { debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length); @@ -145,7 +149,6 @@ static property_list_service_error_t internal_plist_send(property_list_service_c } free(content); - return res; } @@ -170,6 +173,8 @@ LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_send_bi * * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, + * PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA when not enough data + * received, PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT when the connection times out, * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR @@ -187,65 +192,64 @@ static property_list_service_error_t internal_plist_receive_timeout(property_lis *plist = NULL; service_error_t serr = service_receive_with_timeout(client->parent, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); - if ((serr == SERVICE_E_SUCCESS) && (bytes == 0)) { - return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT; + if (serr != SERVICE_E_SUCCESS) { + debug_info("initial read failed!"); + return service_to_property_list_service_error(serr); } + debug_info("initial read=%i", bytes); - if (bytes < 4) { - debug_info("initial read failed!"); - return PROPERTY_LIST_SERVICE_E_MUX_ERROR; - } else { - uint32_t curlen = 0; - char *content = NULL; - pktlen = be32toh(pktlen); - debug_info("%d bytes following", pktlen); - content = (char*)malloc(pktlen); - if (!content) { - debug_info("out of memory when allocating %d bytes", pktlen); - return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; - } + uint32_t curlen = 0; + char *content = NULL; - while (curlen < pktlen) { - service_receive(client->parent, content+curlen, pktlen-curlen, &bytes); - if (bytes <= 0) { - res = PROPERTY_LIST_SERVICE_E_MUX_ERROR; - break; - } - debug_info("received %d bytes", bytes); - curlen += bytes; - } - if (curlen < pktlen) { - debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen); - if (curlen > 0) { - debug_info("incomplete packet following:"); - debug_buffer(content, curlen); - } - free(content); - return res; - } - if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) { - plist_from_bin(content, pktlen, plist); - } else if ((pktlen > 5) && !memcmp(content, "= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d)) - content[bytes] = 0x20; - } - plist_from_xml(content, pktlen, plist); - } else { - debug_info("WARNING: received unexpected non-plist content"); - debug_buffer(content, pktlen); + pktlen = be32toh(pktlen); + debug_info("%d bytes following", pktlen); + content = (char*)malloc(pktlen); + if (!content) { + debug_info("out of memory when allocating %d bytes", pktlen); + return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; + } + + while (curlen < pktlen) { + serr = service_receive(client->parent, content+curlen, pktlen-curlen, &bytes); + if (serr != SERVICE_E_SUCCESS) { + res = service_to_property_list_service_error(serr); + break; } - if (*plist) { - debug_plist(*plist); - res = PROPERTY_LIST_SERVICE_E_SUCCESS; - } else { - res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR; + debug_info("received %d bytes", bytes); + curlen += bytes; + } + if (curlen < pktlen) { + debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen); + if (curlen > 0) { + debug_info("incomplete packet following:"); + debug_buffer(content, curlen); } free(content); - content = NULL; + return res; } + if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) { + plist_from_bin(content, pktlen, plist); + } else if ((pktlen > 5) && !memcmp(content, "= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d)) + content[bytes] = 0x20; + } + plist_from_xml(content, pktlen, plist); + } else { + debug_info("WARNING: received unexpected non-plist content"); + debug_buffer(content, pktlen); + } + if (*plist) { + debug_plist(*plist); + res = PROPERTY_LIST_SERVICE_E_SUCCESS; + } else { + res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR; + } + free(content); + content = NULL; + return res; } diff --git a/src/service.c b/src/service.c index 2dc42b2..57d987c 100644 --- a/src/service.c +++ b/src/service.c @@ -46,6 +46,10 @@ static service_error_t idevice_to_service_error(idevice_error_t err) return SERVICE_E_INVALID_ARG; case IDEVICE_E_SSL_ERROR: return SERVICE_E_SSL_ERROR; + case IDEVICE_E_NOT_ENOUGH_DATA: + return SERIVCE_E_NOT_ENOUGH_DATA; + case IDEVICE_E_TIMEOUT: + return SERVICE_E_TIMEOUT; default: break; } @@ -159,8 +163,9 @@ LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client } res = idevice_to_service_error(idevice_connection_receive_timeout(client->connection, data, size, (uint32_t*)&bytes, timeout)); - if (bytes <= 0) { + if (res != SERVICE_E_SUCCESS) { debug_info("could not read data"); + return res; } if (received) { *received = (uint32_t)bytes; diff --git a/src/webinspector.c b/src/webinspector.c index c81f4c7..3360597 100644 --- a/src/webinspector.c +++ b/src/webinspector.c @@ -52,6 +52,10 @@ static webinspector_error_t webinspector_error(property_list_service_error_t err return WEBINSPECTOR_E_MUX_ERROR; case PROPERTY_LIST_SERVICE_E_SSL_ERROR: return WEBINSPECTOR_E_SSL_ERROR; + case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT: + return WEBINSPECTOR_E_RECEIVE_TIMEOUT; + case PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA: + return WEBINSPECTOR_E_NOT_ENOUGH_DATA; default: break; } -- cgit v1.1-32-gdbae