diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/heartbeat.c | 4 | ||||
| -rw-r--r-- | src/idevice.c | 59 | ||||
| -rw-r--r-- | src/property_list_service.c | 116 | ||||
| -rw-r--r-- | src/service.c | 7 | ||||
| -rw-r--r-- | src/webinspector.c | 4 |
5 files changed, 122 insertions, 68 deletions
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) | |||
| 52 | return HEARTBEAT_E_MUX_ERROR; | 52 | return HEARTBEAT_E_MUX_ERROR; |
| 53 | case PROPERTY_LIST_SERVICE_E_SSL_ERROR: | 53 | case PROPERTY_LIST_SERVICE_E_SSL_ERROR: |
| 54 | return HEARTBEAT_E_SSL_ERROR; | 54 | return HEARTBEAT_E_SSL_ERROR; |
| 55 | case PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA: | ||
| 56 | return HEARTBEAT_E_NOT_ENOUGH_DATA; | ||
| 57 | case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT: | ||
| 58 | return HEARTBEAT_E_TIMEOUT; | ||
| 55 | default: | 59 | default: |
| 56 | break; | 60 | break; |
| 57 | } | 61 | } |
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 @@ | |||
| 43 | 43 | ||
| 44 | #include "idevice.h" | 44 | #include "idevice.h" |
| 45 | #include "common/userpref.h" | 45 | #include "common/userpref.h" |
| 46 | #include "common/socket.h" | ||
| 46 | #include "common/thread.h" | 47 | #include "common/thread.h" |
| 47 | #include "common/debug.h" | 48 | #include "common/debug.h" |
| 48 | 49 | ||
| @@ -381,6 +382,24 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_ | |||
| 381 | return internal_connection_send(connection, data, len, sent_bytes); | 382 | return internal_connection_send(connection, data, len, sent_bytes); |
| 382 | } | 383 | } |
| 383 | 384 | ||
| 385 | static idevice_error_t socket_recv_to_idevice_error(int conn_error, uint32_t len, uint32_t received) | ||
| 386 | { | ||
| 387 | if (conn_error < 0) { | ||
| 388 | switch (conn_error) { | ||
| 389 | case -EAGAIN: | ||
| 390 | debug_info("ERROR: received partial data %d/%d (%s)", received, len, strerror(-conn_error)); | ||
| 391 | return IDEVICE_E_NOT_ENOUGH_DATA; | ||
| 392 | case -ETIMEDOUT: | ||
| 393 | debug_info("ERROR: received timeout (%s)", strerror(-conn_error)); | ||
| 394 | return IDEVICE_E_TIMEOUT; | ||
| 395 | default: | ||
| 396 | return IDEVICE_E_UNKNOWN_ERROR; | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | return IDEVICE_E_SUCCESS; | ||
| 401 | } | ||
| 402 | |||
| 384 | /** | 403 | /** |
| 385 | * Internally used function for receiving raw data over the given connection | 404 | * Internally used function for receiving raw data over the given connection |
| 386 | * using a timeout. | 405 | * using a timeout. |
| @@ -392,12 +411,14 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t | |||
| 392 | } | 411 | } |
| 393 | 412 | ||
| 394 | if (connection->type == CONNECTION_USBMUXD) { | 413 | if (connection->type == CONNECTION_USBMUXD) { |
| 395 | int res = usbmuxd_recv_timeout((int)(long)connection->data, data, len, recv_bytes, timeout); | 414 | int conn_error = usbmuxd_recv_timeout((int)(long)connection->data, data, len, recv_bytes, timeout); |
| 396 | if (res < 0) { | 415 | idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, *recv_bytes); |
| 397 | debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", res, strerror(errno)); | 416 | |
| 398 | return (res == -EAGAIN ? IDEVICE_E_NOT_ENOUGH_DATA : IDEVICE_E_UNKNOWN_ERROR); | 417 | if (error == IDEVICE_E_UNKNOWN_ERROR) { |
| 418 | debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", conn_error, strerror(-conn_error)); | ||
| 399 | } | 419 | } |
| 400 | return IDEVICE_E_SUCCESS; | 420 | |
| 421 | return error; | ||
| 401 | } else { | 422 | } else { |
| 402 | debug_info("Unknown connection type %d", connection->type); | 423 | debug_info("Unknown connection type %d", connection->type); |
| 403 | } | 424 | } |
| @@ -406,13 +427,27 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t | |||
| 406 | 427 | ||
| 407 | 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) | 428 | 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) |
| 408 | { | 429 | { |
| 409 | if (!connection || (connection->ssl_data && !connection->ssl_data->session)) { | 430 | if (!connection || (connection->ssl_data && !connection->ssl_data->session) || len == 0) { |
| 410 | return IDEVICE_E_INVALID_ARG; | 431 | return IDEVICE_E_INVALID_ARG; |
| 411 | } | 432 | } |
| 412 | 433 | ||
| 413 | if (connection->ssl_data) { | 434 | if (connection->ssl_data) { |
| 414 | uint32_t received = 0; | 435 | uint32_t received = 0; |
| 436 | |||
| 415 | while (received < len) { | 437 | while (received < len) { |
| 438 | |||
| 439 | int conn_error = socket_check_fd((int)(long)connection->data, FDM_READ, timeout); | ||
| 440 | idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, received); | ||
| 441 | |||
| 442 | switch (error) { | ||
| 443 | case IDEVICE_E_SUCCESS: | ||
| 444 | break; | ||
| 445 | case IDEVICE_E_UNKNOWN_ERROR: | ||
| 446 | debug_info("ERROR: socket_check_fd returned %d (%s)", conn_error, strerror(-conn_error)); | ||
| 447 | default: | ||
| 448 | return error; | ||
| 449 | } | ||
| 450 | |||
| 416 | #ifdef HAVE_OPENSSL | 451 | #ifdef HAVE_OPENSSL |
| 417 | int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received); | 452 | int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received); |
| 418 | #else | 453 | #else |
| @@ -424,13 +459,15 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_ | |||
| 424 | break; | 459 | break; |
| 425 | } | 460 | } |
| 426 | } | 461 | } |
| 462 | |||
| 427 | debug_info("SSL_read %d, received %d", len, received); | 463 | debug_info("SSL_read %d, received %d", len, received); |
| 428 | if (received > 0) { | 464 | if (received < len) { |
| 429 | *recv_bytes = received; | 465 | *recv_bytes = 0; |
| 430 | return IDEVICE_E_SUCCESS; | 466 | return IDEVICE_E_SSL_ERROR; |
| 431 | } | 467 | } |
| 432 | *recv_bytes = 0; | 468 | |
| 433 | return IDEVICE_E_SSL_ERROR; | 469 | *recv_bytes = received; |
| 470 | return IDEVICE_E_SUCCESS; | ||
| 434 | } | 471 | } |
| 435 | return internal_connection_receive_timeout(connection, data, len, recv_bytes, timeout); | 472 | return internal_connection_receive_timeout(connection, data, len, recv_bytes, timeout); |
| 436 | } | 473 | } |
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 | |||
| 48 | return PROPERTY_LIST_SERVICE_E_MUX_ERROR; | 48 | return PROPERTY_LIST_SERVICE_E_MUX_ERROR; |
| 49 | case SERVICE_E_SSL_ERROR: | 49 | case SERVICE_E_SSL_ERROR: |
| 50 | return PROPERTY_LIST_SERVICE_E_SSL_ERROR; | 50 | return PROPERTY_LIST_SERVICE_E_SSL_ERROR; |
| 51 | case SERIVCE_E_NOT_ENOUGH_DATA: | ||
| 52 | return PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA; | ||
| 53 | case SERVICE_E_TIMEOUT: | ||
| 54 | return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT; | ||
| 51 | default: | 55 | default: |
| 52 | break; | 56 | break; |
| 53 | } | 57 | } |
| @@ -108,7 +112,7 @@ static property_list_service_error_t internal_plist_send(property_list_service_c | |||
| 108 | char *content = NULL; | 112 | char *content = NULL; |
| 109 | uint32_t length = 0; | 113 | uint32_t length = 0; |
| 110 | uint32_t nlen = 0; | 114 | uint32_t nlen = 0; |
| 111 | int bytes = 0; | 115 | uint32_t bytes = 0; |
| 112 | 116 | ||
| 113 | if (!client || (client && !client->parent) || !plist) { | 117 | if (!client || (client && !client->parent) || !plist) { |
| 114 | return PROPERTY_LIST_SERVICE_E_INVALID_ARG; | 118 | return PROPERTY_LIST_SERVICE_E_INVALID_ARG; |
| @@ -126,13 +130,13 @@ static property_list_service_error_t internal_plist_send(property_list_service_c | |||
| 126 | 130 | ||
| 127 | nlen = htobe32(length); | 131 | nlen = htobe32(length); |
| 128 | debug_info("sending %d bytes", length); | 132 | debug_info("sending %d bytes", length); |
| 129 | service_send(client->parent, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); | 133 | service_send(client->parent, (const char*)&nlen, sizeof(nlen), &bytes); |
| 130 | if (bytes == sizeof(nlen)) { | 134 | if (bytes == sizeof(nlen)) { |
| 131 | service_send(client->parent, content, length, (uint32_t*)&bytes); | 135 | service_send(client->parent, content, length, &bytes); |
| 132 | if (bytes > 0) { | 136 | if (bytes > 0) { |
| 133 | debug_info("sent %d bytes", bytes); | 137 | debug_info("sent %d bytes", bytes); |
| 134 | debug_plist(plist); | 138 | debug_plist(plist); |
| 135 | if ((uint32_t)bytes == length) { | 139 | if (bytes == length) { |
| 136 | res = PROPERTY_LIST_SERVICE_E_SUCCESS; | 140 | res = PROPERTY_LIST_SERVICE_E_SUCCESS; |
| 137 | } else { | 141 | } else { |
| 138 | debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length); | 142 | 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 | |||
| 145 | } | 149 | } |
| 146 | 150 | ||
| 147 | free(content); | 151 | free(content); |
| 148 | |||
| 149 | return res; | 152 | return res; |
| 150 | } | 153 | } |
| 151 | 154 | ||
| @@ -170,6 +173,8 @@ LIBIMOBILEDEVICE_API property_list_service_error_t property_list_service_send_bi | |||
| 170 | * | 173 | * |
| 171 | * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, | 174 | * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, |
| 172 | * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, | 175 | * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, |
| 176 | * PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA when not enough data | ||
| 177 | * received, PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT when the connection times out, | ||
| 173 | * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be | 178 | * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be |
| 174 | * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a | 179 | * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a |
| 175 | * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR | 180 | * 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 | |||
| 187 | 192 | ||
| 188 | *plist = NULL; | 193 | *plist = NULL; |
| 189 | service_error_t serr = service_receive_with_timeout(client->parent, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); | 194 | service_error_t serr = service_receive_with_timeout(client->parent, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); |
| 190 | if ((serr == SERVICE_E_SUCCESS) && (bytes == 0)) { | 195 | if (serr != SERVICE_E_SUCCESS) { |
| 191 | return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT; | 196 | debug_info("initial read failed!"); |
| 197 | return service_to_property_list_service_error(serr); | ||
| 192 | } | 198 | } |
| 199 | |||
| 193 | debug_info("initial read=%i", bytes); | 200 | debug_info("initial read=%i", bytes); |
| 194 | if (bytes < 4) { | ||
| 195 | debug_info("initial read failed!"); | ||
| 196 | return PROPERTY_LIST_SERVICE_E_MUX_ERROR; | ||
| 197 | } else { | ||
| 198 | uint32_t curlen = 0; | ||
| 199 | char *content = NULL; | ||
| 200 | 201 | ||
| 201 | pktlen = be32toh(pktlen); | 202 | uint32_t curlen = 0; |
| 202 | debug_info("%d bytes following", pktlen); | 203 | char *content = NULL; |
| 203 | content = (char*)malloc(pktlen); | ||
| 204 | if (!content) { | ||
| 205 | debug_info("out of memory when allocating %d bytes", pktlen); | ||
| 206 | return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; | ||
| 207 | } | ||
| 208 | 204 | ||
| 209 | while (curlen < pktlen) { | 205 | pktlen = be32toh(pktlen); |
| 210 | service_receive(client->parent, content+curlen, pktlen-curlen, &bytes); | 206 | debug_info("%d bytes following", pktlen); |
| 211 | if (bytes <= 0) { | 207 | content = (char*)malloc(pktlen); |
| 212 | res = PROPERTY_LIST_SERVICE_E_MUX_ERROR; | 208 | if (!content) { |
| 213 | break; | 209 | debug_info("out of memory when allocating %d bytes", pktlen); |
| 214 | } | 210 | return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; |
| 215 | debug_info("received %d bytes", bytes); | 211 | } |
| 216 | curlen += bytes; | 212 | |
| 217 | } | 213 | while (curlen < pktlen) { |
| 218 | if (curlen < pktlen) { | 214 | serr = service_receive(client->parent, content+curlen, pktlen-curlen, &bytes); |
| 219 | debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen); | 215 | if (serr != SERVICE_E_SUCCESS) { |
| 220 | if (curlen > 0) { | 216 | res = service_to_property_list_service_error(serr); |
| 221 | debug_info("incomplete packet following:"); | 217 | break; |
| 222 | debug_buffer(content, curlen); | ||
| 223 | } | ||
| 224 | free(content); | ||
| 225 | return res; | ||
| 226 | } | ||
| 227 | if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) { | ||
| 228 | plist_from_bin(content, pktlen, plist); | ||
| 229 | } else if ((pktlen > 5) && !memcmp(content, "<?xml", 5)) { | ||
| 230 | /* iOS 4.3+ hack: plist data might contain invalid characters, thus we convert those to spaces */ | ||
| 231 | for (bytes = 0; bytes < pktlen-1; bytes++) { | ||
| 232 | if ((content[bytes] >= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d)) | ||
| 233 | content[bytes] = 0x20; | ||
| 234 | } | ||
| 235 | plist_from_xml(content, pktlen, plist); | ||
| 236 | } else { | ||
| 237 | debug_info("WARNING: received unexpected non-plist content"); | ||
| 238 | debug_buffer(content, pktlen); | ||
| 239 | } | 218 | } |
| 240 | if (*plist) { | 219 | debug_info("received %d bytes", bytes); |
| 241 | debug_plist(*plist); | 220 | curlen += bytes; |
| 242 | res = PROPERTY_LIST_SERVICE_E_SUCCESS; | 221 | } |
| 243 | } else { | 222 | if (curlen < pktlen) { |
| 244 | res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR; | 223 | debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen); |
| 224 | if (curlen > 0) { | ||
| 225 | debug_info("incomplete packet following:"); | ||
| 226 | debug_buffer(content, curlen); | ||
| 245 | } | 227 | } |
| 246 | free(content); | 228 | free(content); |
| 247 | content = NULL; | 229 | return res; |
| 248 | } | 230 | } |
| 231 | if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) { | ||
| 232 | plist_from_bin(content, pktlen, plist); | ||
| 233 | } else if ((pktlen > 5) && !memcmp(content, "<?xml", 5)) { | ||
| 234 | /* iOS 4.3+ hack: plist data might contain invalid characters, thus we convert those to spaces */ | ||
| 235 | for (bytes = 0; bytes < pktlen-1; bytes++) { | ||
| 236 | if ((content[bytes] >= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d)) | ||
| 237 | content[bytes] = 0x20; | ||
| 238 | } | ||
| 239 | plist_from_xml(content, pktlen, plist); | ||
| 240 | } else { | ||
| 241 | debug_info("WARNING: received unexpected non-plist content"); | ||
| 242 | debug_buffer(content, pktlen); | ||
| 243 | } | ||
| 244 | if (*plist) { | ||
| 245 | debug_plist(*plist); | ||
| 246 | res = PROPERTY_LIST_SERVICE_E_SUCCESS; | ||
| 247 | } else { | ||
| 248 | res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR; | ||
| 249 | } | ||
| 250 | free(content); | ||
| 251 | content = NULL; | ||
| 252 | |||
| 249 | return res; | 253 | return res; |
| 250 | } | 254 | } |
| 251 | 255 | ||
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) | |||
| 46 | return SERVICE_E_INVALID_ARG; | 46 | return SERVICE_E_INVALID_ARG; |
| 47 | case IDEVICE_E_SSL_ERROR: | 47 | case IDEVICE_E_SSL_ERROR: |
| 48 | return SERVICE_E_SSL_ERROR; | 48 | return SERVICE_E_SSL_ERROR; |
| 49 | case IDEVICE_E_NOT_ENOUGH_DATA: | ||
| 50 | return SERIVCE_E_NOT_ENOUGH_DATA; | ||
| 51 | case IDEVICE_E_TIMEOUT: | ||
| 52 | return SERVICE_E_TIMEOUT; | ||
| 49 | default: | 53 | default: |
| 50 | break; | 54 | break; |
| 51 | } | 55 | } |
| @@ -159,8 +163,9 @@ LIBIMOBILEDEVICE_API service_error_t service_receive_with_timeout(service_client | |||
| 159 | } | 163 | } |
| 160 | 164 | ||
| 161 | res = idevice_to_service_error(idevice_connection_receive_timeout(client->connection, data, size, (uint32_t*)&bytes, timeout)); | 165 | res = idevice_to_service_error(idevice_connection_receive_timeout(client->connection, data, size, (uint32_t*)&bytes, timeout)); |
| 162 | if (bytes <= 0) { | 166 | if (res != SERVICE_E_SUCCESS) { |
| 163 | debug_info("could not read data"); | 167 | debug_info("could not read data"); |
| 168 | return res; | ||
| 164 | } | 169 | } |
| 165 | if (received) { | 170 | if (received) { |
| 166 | *received = (uint32_t)bytes; | 171 | *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 | |||
| 52 | return WEBINSPECTOR_E_MUX_ERROR; | 52 | return WEBINSPECTOR_E_MUX_ERROR; |
| 53 | case PROPERTY_LIST_SERVICE_E_SSL_ERROR: | 53 | case PROPERTY_LIST_SERVICE_E_SSL_ERROR: |
| 54 | return WEBINSPECTOR_E_SSL_ERROR; | 54 | return WEBINSPECTOR_E_SSL_ERROR; |
| 55 | case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT: | ||
| 56 | return WEBINSPECTOR_E_RECEIVE_TIMEOUT; | ||
| 57 | case PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA: | ||
| 58 | return WEBINSPECTOR_E_NOT_ENOUGH_DATA; | ||
| 55 | default: | 59 | default: |
| 56 | break; | 60 | break; |
| 57 | } | 61 | } |
