summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Ben Wagner2020-02-11 14:45:46 -0500
committerGravatar Nikias Bassen2022-03-29 12:11:18 +0200
commit2f1e0660ef0a3dcfa35c8003b0806bae3acd411d (patch)
tree75fdfa5356f92dbae0b71bb7d308a6a8be64db63
parent66a56a1e37e6df108c8dbcd99b7f60dec1fe4622 (diff)
downloadlibimobiledevice-2f1e0660ef0a3dcfa35c8003b0806bae3acd411d.tar.gz
libimobiledevice-2f1e0660ef0a3dcfa35c8003b0806bae3acd411d.tar.bz2
Add timeout and interrupt handling to debugserver. Fix debugserver_client_handle_response
-rw-r--r--include/libimobiledevice/debugserver.h17
-rw-r--r--src/debugserver.c25
-rw-r--r--src/debugserver.h2
-rw-r--r--tools/idevicedebug.c100
4 files changed, 74 insertions, 70 deletions
diff --git a/include/libimobiledevice/debugserver.h b/include/libimobiledevice/debugserver.h
index ce8176c..03f97a4 100644
--- a/include/libimobiledevice/debugserver.h
+++ b/include/libimobiledevice/debugserver.h
@@ -119,7 +119,8 @@ debugserver_error_t debugserver_client_send(debugserver_client_t client, const c
119 * @return DEBUGSERVER_E_SUCCESS on success, 119 * @return DEBUGSERVER_E_SUCCESS on success,
120 * DEBUGSERVER_E_INVALID_ARG when one or more parameters are 120 * DEBUGSERVER_E_INVALID_ARG when one or more parameters are
121 * invalid, DEBUGSERVER_E_MUX_ERROR when a communication error 121 * invalid, DEBUGSERVER_E_MUX_ERROR when a communication error
122 * occurs, or DEBUGSERVER_E_UNKNOWN_ERROR when an unspecified 122 * occurs, DEBUGSERVER_E_TIMEOUT when the timeout is reached,
123 * or DEBUGSERVER_E_UNKNOWN_ERROR when an unspecified
123 * error occurs. 124 * error occurs.
124 */ 125 */
125debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout); 126debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout);
@@ -178,6 +179,20 @@ debugserver_error_t debugserver_client_receive_response(debugserver_client_t cli
178debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled); 179debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled);
179 180
180/** 181/**
182 * Sets behavior when awaiting a response from the server.
183 *
184 * @see debugserver_client_send_command, debugserver_client_receive_response, debugserver_client_receive
185 *
186 * @param client The debugserver client
187 * @param cancel_receive A function pointer that will be called approximately every receive_loop_timeout milliseconds; the function should return a boolean flag specifying whether to stop waiting for a response. If NULL, behaves as if it always returns true.
188 * @param receive_loop_timeout Time in milliseconds between calls to cancel_receive.
189 *
190 * @return DEBUGSERVER_E_SUCCESS on success, or an DEBUGSERVER_E_* error
191 * code otherwise.
192 */
193debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout);
194
195/**
181 * Sets the argv which launches an app. 196 * Sets the argv which launches an app.
182 * 197 *
183 * @param client The debugserver client 198 * @param client The debugserver client
diff --git a/src/debugserver.c b/src/debugserver.c
index 46686f6..20ffe01 100644
--- a/src/debugserver.c
+++ b/src/debugserver.c
@@ -89,6 +89,8 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device
89 debugserver_client_t client_loc = (debugserver_client_t) malloc(sizeof(struct debugserver_client_private)); 89 debugserver_client_t client_loc = (debugserver_client_t) malloc(sizeof(struct debugserver_client_private));
90 client_loc->parent = parent; 90 client_loc->parent = parent;
91 client_loc->noack_mode = 0; 91 client_loc->noack_mode = 0;
92 client_loc->cancel_receive = NULL;
93 client_loc->receive_loop_timeout = 1000;
92 94
93 *client = client_loc; 95 *client = client_loc;
94 96
@@ -150,7 +152,7 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout
150 } 152 }
151 153
152 res = debugserver_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout)); 154 res = debugserver_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
153 if (bytes <= 0) { 155 if (bytes <= 0 && res != DEBUGSERVER_E_TIMEOUT) {
154 debug_info("Could not read data, error %d", res); 156 debug_info("Could not read data, error %d", res);
155 } 157 }
156 if (received) { 158 if (received) {
@@ -162,7 +164,11 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout
162 164
163LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received) 165LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received)
164{ 166{
165 return debugserver_client_receive_with_timeout(client, data, size, received, 1000); 167 debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
168 do {
169 res = debugserver_client_receive_with_timeout(client, data, size, received, client->receive_loop_timeout);
170 while (res == DEBUGSERVER_E_TIMEOUT && client->cancel_receive != NULL && !client->cancel_receive());
171 return res;
166} 172}
167 173
168LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command) 174LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command)
@@ -355,6 +361,19 @@ LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugse
355 return DEBUGSERVER_E_SUCCESS; 361 return DEBUGSERVER_E_SUCCESS;
356} 362}
357 363
364LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout)
365{
366 if (!client)
367 return DEBUGSERVER_E_INVALID_ARG;
368
369 client->cancel_receive = cancel_receive;
370 client->receive_loop_timeout = receive_loop_timeout;
371
372 debug_info("receive params: cancel_receive %s, receive_loop_timeout %dms", (client->cancel_receive == NULL ? "unset": "set"), client->receive_loop_timeout);
373
374 return DEBUGSERVER_E_SUCCESS;
375}
376
358static int debugserver_client_receive_internal_check(debugserver_client_t client, char* received_char) 377static int debugserver_client_receive_internal_check(debugserver_client_t client, char* received_char)
359{ 378{
360 debugserver_error_t res = DEBUGSERVER_E_SUCCESS; 379 debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
@@ -363,7 +382,7 @@ static int debugserver_client_receive_internal_check(debugserver_client_t client
363 uint32_t bytes = 0; 382 uint32_t bytes = 0;
364 383
365 /* we loop here as we expect an answer */ 384 /* we loop here as we expect an answer */
366 res = debugserver_client_receive_with_timeout(client, &buffer, sizeof(char), &bytes, 1000); 385 res = debugserver_client_receive(client, &buffer, sizeof(char), &bytes);
367 if (res == DEBUGSERVER_E_SUCCESS && received_char[0] != 0) { 386 if (res == DEBUGSERVER_E_SUCCESS && received_char[0] != 0) {
368 if (memcmp(&buffer, received_char, sizeof(char)) == 0) { 387 if (memcmp(&buffer, received_char, sizeof(char)) == 0) {
369 did_receive_char = 1; 388 did_receive_char = 1;
diff --git a/src/debugserver.h b/src/debugserver.h
index 05cd97b..ee3ba62 100644
--- a/src/debugserver.h
+++ b/src/debugserver.h
@@ -30,6 +30,8 @@
30struct debugserver_client_private { 30struct debugserver_client_private {
31 service_client_t parent; 31 service_client_t parent;
32 int noack_mode; 32 int noack_mode;
33 int (*cancel_receive)();
34 int receive_loop_timeout;
33}; 35};
34 36
35struct debugserver_command_private { 37struct debugserver_command_private {
diff --git a/tools/idevicedebug.c b/tools/idevicedebug.c
index ca4cb18..4c1ca89 100644
--- a/tools/idevicedebug.c
+++ b/tools/idevicedebug.c
@@ -61,6 +61,11 @@ static void on_signal(int sig)
61 quit_flag++; 61 quit_flag++;
62} 62}
63 63
64static void cancel_receive()
65{
66 return quit_flag;
67}
68
64static instproxy_error_t instproxy_client_get_object_by_key_from_info_dictionary_for_bundle_identifier(instproxy_client_t client, const char* appid, const char* key, plist_t* node) 69static instproxy_error_t instproxy_client_get_object_by_key_from_info_dictionary_for_bundle_identifier(instproxy_client_t client, const char* appid, const char* key, plist_t* node)
65{ 70{
66 if (!client || !appid || !key) 71 if (!client || !appid || !key)
@@ -108,10 +113,9 @@ static instproxy_error_t instproxy_client_get_object_by_key_from_info_dictionary
108 return INSTPROXY_E_SUCCESS; 113 return INSTPROXY_E_SUCCESS;
109} 114}
110 115
111static debugserver_error_t debugserver_client_handle_response(debugserver_client_t client, char** response, int send_reply, int* exit_status) 116static debugserver_error_t debugserver_client_handle_response(debugserver_client_t client, char** response, int* exit_status)
112{ 117{
113 debugserver_error_t dres = DEBUGSERVER_E_SUCCESS; 118 debugserver_error_t dres = DEBUGSERVER_E_SUCCESS;
114 debugserver_command_t command = NULL;
115 char* o = NULL; 119 char* o = NULL;
116 char* r = *response; 120 char* r = *response;
117 121
@@ -123,49 +127,13 @@ static debugserver_error_t debugserver_client_handle_response(debugserver_client
123 debugserver_decode_string(r + 1, strlen(r) - 1, &o); 127 debugserver_decode_string(r + 1, strlen(r) - 1, &o);
124 printf("%s", o); 128 printf("%s", o);
125 fflush(stdout); 129 fflush(stdout);
126 if (o != NULL) {
127 free(o);
128 o = NULL;
129 }
130
131 free(*response);
132 *response = NULL;
133
134 if (!send_reply)
135 return dres;
136
137 /* send reply */
138 debugserver_command_new("OK", 0, NULL, &command);
139 dres = debugserver_client_send_command(client, command, response, NULL);
140 log_debug("result: %d", dres);
141 debugserver_command_free(command);
142 command = NULL;
143 } else if (r[0] == 'T') { 130 } else if (r[0] == 'T') {
144 /* thread stopped information */ 131 /* thread stopped information */
145 log_debug("Thread stopped. Details:\n%s", r + 1); 132 log_debug("Thread stopped. Details:\n%s", r + 1);
146 133 /* Break out of the loop. */
147 free(*response);
148 *response = NULL;
149
150 if (!send_reply)
151 return dres;
152
153 dres = DEBUGSERVER_E_UNKNOWN_ERROR; 134 dres = DEBUGSERVER_E_UNKNOWN_ERROR;
154 } else if (r[0] == 'E') { 135 } else if (r[0] == 'E') {
155 printf("ERROR: %s\n", r + 1); 136 printf("ERROR: %s\n", r + 1);
156
157 free(*response);
158 *response = NULL;
159
160 if (!send_reply)
161 return dres;
162
163 /* send reply */
164 debugserver_command_new("OK", 0, NULL, &command);
165 dres = debugserver_client_send_command(client, command, response, NULL);
166 log_debug("result: %d", dres);
167 debugserver_command_free(command);
168 command = NULL;
169 } else if (r[0] == 'W' || r[0] == 'X') { 137 } else if (r[0] == 'W' || r[0] == 'X') {
170 /* process exited */ 138 /* process exited */
171 debugserver_decode_string(r + 1, strlen(r) - 1, &o); 139 debugserver_decode_string(r + 1, strlen(r) - 1, &o);
@@ -173,29 +141,23 @@ static debugserver_error_t debugserver_client_handle_response(debugserver_client
173 printf("Exit %s: %u\n", (r[0] == 'W' ? "status" : "due to signal"), o[0]); 141 printf("Exit %s: %u\n", (r[0] == 'W' ? "status" : "due to signal"), o[0]);
174 /* Use bash convention where signals cause an exit status of 128 + signal */ 142 /* Use bash convention where signals cause an exit status of 128 + signal */
175 *exit_status = o[0] + (r[0] == 'W' ? 0 : 128); 143 *exit_status = o[0] + (r[0] == 'W' ? 0 : 128);
176 free(o); 144 } else {
177 o = NULL; 145 debug_info("Unable to decode exit status from %s", r);
178 } 146 dres = DEBUGSERVER_E_UNKNOWN_ERROR;
179 free(*response); 147 }
180 *response = NULL;
181 return dres;
182 } else if (r && strlen(r) == 0) { 148 } else if (r && strlen(r) == 0) {
183 if (!send_reply) 149 log_debug("empty response");
184 return dres;
185
186 free(*response);
187 *response = NULL;
188
189 /* no command */
190 debugserver_command_new("OK", 0, NULL, &command);
191 dres = debugserver_client_send_command(client, command, response, NULL);
192 log_debug("result: %d", dres);
193 debugserver_command_free(command);
194 command = NULL;
195 } else { 150 } else {
196 log_debug("ERROR: unhandled response '%s'", r); 151 log_debug("ERROR: unhandled response '%s'", r);
197 } 152 }
198 153
154 if (o != NULL) {
155 free(o);
156 o = NULL;
157 }
158
159 free(*response);
160 *response = NULL;
199 return dres; 161 return dres;
200} 162}
201 163
@@ -383,6 +345,12 @@ int main(int argc, char *argv[])
383 goto cleanup; 345 goto cleanup;
384 } 346 }
385 347
348 /* set receive params */
349 if (debugserver_client_set_receive_params(debugserver_client, cancel_receive, 250) != DEBUGSERVER_E_SUCCESS) {
350 fprintf(stderr, "Error in debugserver_client_set_receive_params\n");
351 goto cleanup;
352 }
353
386 /* enable logging for the session in debug mode */ 354 /* enable logging for the session in debug mode */
387 if (debug_level) { 355 if (debug_level) {
388 log_debug("Setting logging bitmask..."); 356 log_debug("Setting logging bitmask...");
@@ -392,7 +360,7 @@ int main(int argc, char *argv[])
392 command = NULL; 360 command = NULL;
393 if (response) { 361 if (response) {
394 if (strncmp(response, "OK", 2)) { 362 if (strncmp(response, "OK", 2)) {
395 debugserver_client_handle_response(debugserver_client, &response, 0, NULL); 363 debugserver_client_handle_response(debugserver_client, &response, NULL);
396 goto cleanup; 364 goto cleanup;
397 } 365 }
398 free(response); 366 free(response);
@@ -410,7 +378,7 @@ int main(int argc, char *argv[])
410 command = NULL; 378 command = NULL;
411 if (response) { 379 if (response) {
412 if (strncmp(response, "OK", 2)) { 380 if (strncmp(response, "OK", 2)) {
413 debugserver_client_handle_response(debugserver_client, &response, 0, NULL); 381 debugserver_client_handle_response(debugserver_client, &response, NULL);
414 goto cleanup; 382 goto cleanup;
415 } 383 }
416 free(response); 384 free(response);
@@ -426,7 +394,7 @@ int main(int argc, char *argv[])
426 command = NULL; 394 command = NULL;
427 if (response) { 395 if (response) {
428 if (strncmp(response, "OK", 2)) { 396 if (strncmp(response, "OK", 2)) {
429 debugserver_client_handle_response(debugserver_client, &response, 0, NULL); 397 debugserver_client_handle_response(debugserver_client, &response, NULL);
430 goto cleanup; 398 goto cleanup;
431 } 399 }
432 free(response); 400 free(response);
@@ -467,7 +435,7 @@ int main(int argc, char *argv[])
467 command = NULL; 435 command = NULL;
468 if (response) { 436 if (response) {
469 if (strncmp(response, "OK", 2)) { 437 if (strncmp(response, "OK", 2)) {
470 debugserver_client_handle_response(debugserver_client, &response, 0, NULL); 438 debugserver_client_handle_response(debugserver_client, &response, NULL);
471 goto cleanup; 439 goto cleanup;
472 } 440 }
473 free(response); 441 free(response);
@@ -493,7 +461,7 @@ int main(int argc, char *argv[])
493 command = NULL; 461 command = NULL;
494 if (response) { 462 if (response) {
495 if (strncmp(response, "OK", 2)) { 463 if (strncmp(response, "OK", 2)) {
496 debugserver_client_handle_response(debugserver_client, &response, 0, NULL); 464 debugserver_client_handle_response(debugserver_client, &response, NULL);
497 goto cleanup; 465 goto cleanup;
498 } 466 }
499 free(response); 467 free(response);
@@ -511,21 +479,21 @@ int main(int argc, char *argv[])
511 log_debug("Entering run loop..."); 479 log_debug("Entering run loop...");
512 while (!quit_flag) { 480 while (!quit_flag) {
513 if (dres != DEBUGSERVER_E_SUCCESS) { 481 if (dres != DEBUGSERVER_E_SUCCESS) {
514 log_debug("failed to receive response"); 482 log_debug("failed to receive response; error %d", dres);
515 break; 483 break;
516 } 484 }
517 485
518 if (response) { 486 if (response) {
519 log_debug("response: %s", response); 487 log_debug("response: %s", response);
520 if (strncmp(response, "OK", 2)) { 488 if (strncmp(response, "OK", 2)) {
521 dres = debugserver_client_handle_response(debugserver_client, &response, 1, &res); 489 dres = debugserver_client_handle_response(debugserver_client, &response, &res);
522 } 490 }
523 } 491 }
524 if (res >= 0) { 492 if (res >= 0) {
525 goto cleanup; 493 goto cleanup;
526 } 494 }
527 495
528 sleep(1); 496 dres = debugserver_client_receive(debugserver_client, &response, NULL);
529 } 497 }
530 498
531 /* kill process after we finished */ 499 /* kill process after we finished */
@@ -536,7 +504,7 @@ int main(int argc, char *argv[])
536 command = NULL; 504 command = NULL;
537 if (response) { 505 if (response) {
538 if (strncmp(response, "OK", 2)) { 506 if (strncmp(response, "OK", 2)) {
539 debugserver_client_handle_response(debugserver_client, &response, 0, NULL); 507 debugserver_client_handle_response(debugserver_client, &response, NULL);
540 goto cleanup; 508 goto cleanup;
541 } 509 }
542 free(response); 510 free(response);