summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/heartbeat.c4
-rw-r--r--src/idevice.c59
-rw-r--r--src/property_list_service.c116
-rw-r--r--src/service.c7
-rw-r--r--src/webinspector.c4
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
385static 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
407LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) 428LIBIMOBILEDEVICE_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 }