diff options
| author | 2021-02-01 11:49:31 +0100 | |
|---|---|---|
| committer | 2021-02-01 11:49:31 +0100 | |
| commit | 51fd30fcdad901a14aa777c92a92a04ccf569298 (patch) | |
| tree | 760fd8329ec6081bf2f5628754c5938dd6968403 /tools | |
| parent | f6eb49bdd0997b834d215cc01029454ed5d2f3d1 (diff) | |
| download | libimobiledevice-51fd30fcdad901a14aa777c92a92a04ccf569298.tar.gz libimobiledevice-51fd30fcdad901a14aa777c92a92a04ccf569298.tar.bz2 | |
tools: Improve idevicedebugserverproxy with select() and less threads
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/idevicedebugserverproxy.c | 196 |
1 files changed, 61 insertions, 135 deletions
diff --git a/tools/idevicedebugserverproxy.c b/tools/idevicedebugserverproxy.c index 5b42473..c094c30 100644 --- a/tools/idevicedebugserverproxy.c +++ b/tools/idevicedebugserverproxy.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * idevicedebugserverproxy.c | 2 | * idevicedebugserverproxy.c |
| 3 | * Proxy a debugserver connection from device for remote debugging | 3 | * Proxy a debugserver connection from device for remote debugging |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2021 Nikias Bassen, All Rights Reserved. | ||
| 5 | * Copyright (c) 2012 Martin Szulecki All Rights Reserved. | 6 | * Copyright (c) 2012 Martin Szulecki All Rights Reserved. |
| 6 | * | 7 | * |
| 7 | * This library is free software; you can redistribute it and/or | 8 | * This library is free software; you can redistribute it and/or |
| @@ -30,6 +31,7 @@ | |||
| 30 | #include <string.h> | 31 | #include <string.h> |
| 31 | #include <errno.h> | 32 | #include <errno.h> |
| 32 | #include <signal.h> | 33 | #include <signal.h> |
| 34 | #include <sys/select.h> | ||
| 33 | 35 | ||
| 34 | #include <libimobiledevice/libimobiledevice.h> | 36 | #include <libimobiledevice/libimobiledevice.h> |
| 35 | #include <libimobiledevice/debugserver.h> | 37 | #include <libimobiledevice/debugserver.h> |
| @@ -47,12 +49,11 @@ typedef struct { | |||
| 47 | int client_fd; | 49 | int client_fd; |
| 48 | idevice_t device; | 50 | idevice_t device; |
| 49 | debugserver_client_t debugserver_client; | 51 | debugserver_client_t debugserver_client; |
| 50 | volatile int stop_ctod; | ||
| 51 | volatile int stop_dtoc; | ||
| 52 | } socket_info_t; | 52 | } socket_info_t; |
| 53 | 53 | ||
| 54 | struct thread_info { | 54 | struct thread_info { |
| 55 | THREAD_T th; | 55 | THREAD_T th; |
| 56 | int client_fd; | ||
| 56 | struct thread_info *next; | 57 | struct thread_info *next; |
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| @@ -85,153 +86,75 @@ static void print_usage(int argc, char **argv) | |||
| 85 | printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n"); | 86 | printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n"); |
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | static void *thread_device_to_client(void *data) | 89 | struct service_client_private { |
| 89 | { | 90 | idevice_connection_t connection; |
| 90 | socket_info_t* socket_info = (socket_info_t*)data; | 91 | }; |
| 91 | debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; | 92 | struct debugserver_client_private { |
| 92 | 93 | struct service_client_private* parent; | |
| 93 | int recv_len; | 94 | int noack_mode; |
| 94 | int sent; | 95 | }; |
| 95 | char buffer[131072]; | ||
| 96 | |||
| 97 | debug("%s: started thread...\n", __func__); | ||
| 98 | |||
| 99 | debug("%s: client_fd = %d\n", __func__, socket_info->client_fd); | ||
| 100 | |||
| 101 | while (!quit_flag && !socket_info->stop_dtoc && socket_info->client_fd > 0) { | ||
| 102 | debug("%s: receiving data from device...\n", __func__); | ||
| 103 | |||
| 104 | res = debugserver_client_receive_with_timeout(socket_info->debugserver_client, buffer, sizeof(buffer), (uint32_t*)&recv_len, 5000); | ||
| 105 | |||
| 106 | if (recv_len <= 0) { | ||
| 107 | if (recv_len == 0 && res == DEBUGSERVER_E_SUCCESS) { | ||
| 108 | // try again | ||
| 109 | continue; | ||
| 110 | } else { | ||
| 111 | fprintf(stderr, "recv failed: %s\n", strerror(errno)); | ||
| 112 | break; | ||
| 113 | } | ||
| 114 | } else { | ||
| 115 | /* send to device */ | ||
| 116 | debug("%s: sending data to client...\n", __func__); | ||
| 117 | sent = socket_send(socket_info->client_fd, buffer, recv_len); | ||
| 118 | if (sent < recv_len) { | ||
| 119 | if (sent <= 0) { | ||
| 120 | fprintf(stderr, "send failed: %s\n", strerror(errno)); | ||
| 121 | break; | ||
| 122 | } else { | ||
| 123 | fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); | ||
| 124 | } | ||
| 125 | } else { | ||
| 126 | // sending succeeded, receive from device | ||
| 127 | debug("%s: pushed %d bytes to client\n", __func__, sent); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | debug("%s: shutting down...\n", __func__); | ||
| 133 | |||
| 134 | socket_shutdown(socket_info->client_fd, SHUT_RDWR); | ||
| 135 | socket_close(socket_info->client_fd); | ||
| 136 | |||
| 137 | socket_info->client_fd = -1; | ||
| 138 | socket_info->stop_ctod = 1; | ||
| 139 | |||
| 140 | return NULL; | ||
| 141 | } | ||
| 142 | |||
| 143 | static void *thread_client_to_device(void *data) | ||
| 144 | { | ||
| 145 | socket_info_t* socket_info = (socket_info_t*)data; | ||
| 146 | debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR; | ||
| 147 | |||
| 148 | int recv_len; | ||
| 149 | int sent; | ||
| 150 | char buffer[131072]; | ||
| 151 | THREAD_T dtoc; | ||
| 152 | |||
| 153 | debug("%s: started thread...\n", __func__); | ||
| 154 | |||
| 155 | debug("%s: client_fd = %d\n", __func__, socket_info->client_fd); | ||
| 156 | |||
| 157 | /* spawn server to client thread */ | ||
| 158 | socket_info->stop_dtoc = 0; | ||
| 159 | if (thread_new(&dtoc, thread_device_to_client, data) != 0) { | ||
| 160 | fprintf(stderr, "Failed to start device to client thread...\n"); | ||
| 161 | } | ||
| 162 | |||
| 163 | while (!quit_flag && !socket_info->stop_ctod && socket_info->client_fd > 0) { | ||
| 164 | debug("%s: receiving data from client...\n", __func__); | ||
| 165 | |||
| 166 | /* attempt to read incoming data from client */ | ||
| 167 | recv_len = socket_receive_timeout(socket_info->client_fd, buffer, sizeof(buffer), 0, 5000); | ||
| 168 | |||
| 169 | /* any data received? */ | ||
| 170 | if (recv_len <= 0) { | ||
| 171 | if (recv_len == 0) { | ||
| 172 | /* try again */ | ||
| 173 | continue; | ||
| 174 | } else { | ||
| 175 | fprintf(stderr, "Receive failed: %s\n", strerror(errno)); | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | } else { | ||
| 179 | /* forward data to device */ | ||
| 180 | debug("%s: sending data to device...\n", __func__); | ||
| 181 | res = debugserver_client_send(socket_info->debugserver_client, buffer, recv_len, (uint32_t*)&sent); | ||
| 182 | |||
| 183 | if (sent < recv_len || res != DEBUGSERVER_E_SUCCESS) { | ||
| 184 | if (sent <= 0) { | ||
| 185 | fprintf(stderr, "send failed: %s\n", strerror(errno)); | ||
| 186 | break; | ||
| 187 | } else { | ||
| 188 | fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len); | ||
| 189 | } | ||
| 190 | } else { | ||
| 191 | // sending succeeded, receive from device | ||
| 192 | debug("%s: sent %d bytes to device\n", __func__, sent); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | debug("%s: shutting down...\n", __func__); | ||
| 198 | |||
| 199 | socket_shutdown(socket_info->client_fd, SHUT_RDWR); | ||
| 200 | socket_close(socket_info->client_fd); | ||
| 201 | |||
| 202 | socket_info->client_fd = -1; | ||
| 203 | socket_info->stop_dtoc = 1; | ||
| 204 | |||
| 205 | /* join other thread to allow it to stop */ | ||
| 206 | thread_join(dtoc); | ||
| 207 | thread_free(dtoc); | ||
| 208 | |||
| 209 | return NULL; | ||
| 210 | } | ||
| 211 | 96 | ||
| 212 | static void* connection_handler(void* data) | 97 | static void* connection_handler(void* data) |
| 213 | { | 98 | { |
| 214 | debugserver_error_t derr = DEBUGSERVER_E_SUCCESS; | 99 | debugserver_error_t derr = DEBUGSERVER_E_SUCCESS; |
| 215 | socket_info_t* socket_info = (socket_info_t*)data; | 100 | socket_info_t* socket_info = (socket_info_t*)data; |
| 216 | THREAD_T ctod; | 101 | char buf[4096]; |
| 102 | |||
| 103 | int client_fd = socket_info->client_fd; | ||
| 217 | 104 | ||
| 218 | debug("%s: client_fd = %d\n", __func__, socket_info->client_fd); | 105 | debug("%s: client_fd = %d\n", __func__, client_fd); |
| 219 | 106 | ||
| 220 | derr = debugserver_client_start_service(socket_info->device, &socket_info->debugserver_client, TOOL_NAME); | 107 | derr = debugserver_client_start_service(socket_info->device, &socket_info->debugserver_client, TOOL_NAME); |
| 221 | if (derr != DEBUGSERVER_E_SUCCESS) { | 108 | if (derr != DEBUGSERVER_E_SUCCESS) { |
| 222 | fprintf(stderr, "Could not start debugserver on device!\nPlease make sure to mount a developer disk image first.\n"); | 109 | fprintf(stderr, "Could not start debugserver on device!\nPlease make sure to mount a developer disk image first.\n"); |
| 223 | return NULL; | 110 | return NULL; |
| 224 | } | 111 | } |
| 225 | 112 | int dbgsvr_fd = -1; | |
| 226 | /* spawn client to device thread */ | 113 | idevice_connection_get_fd(socket_info->debugserver_client->parent->connection, &dbgsvr_fd); |
| 227 | socket_info->stop_ctod = 0; | 114 | if (dbgsvr_fd == -1) { |
| 228 | if (thread_new(&ctod, thread_client_to_device, data) != 0) { | 115 | fprintf(stderr, "Could not get debugserver connection fd.\n"); |
| 229 | fprintf(stderr, "Failed to start client to device thread...\n"); | 116 | return NULL; |
| 230 | } | 117 | } |
| 231 | 118 | ||
| 232 | /* join the fun */ | 119 | fd_set fds; |
| 233 | thread_join(ctod); | 120 | int maxfd = 0; |
| 234 | thread_free(ctod); | 121 | FD_ZERO(&fds); |
| 122 | FD_SET(client_fd, &fds); | ||
| 123 | if (client_fd > maxfd) maxfd = client_fd; | ||
| 124 | FD_SET(dbgsvr_fd, &fds); | ||
| 125 | if (dbgsvr_fd > maxfd) maxfd = dbgsvr_fd; | ||
| 126 | |||
| 127 | while (!quit_flag) { | ||
| 128 | fd_set read_fds = fds; | ||
| 129 | int ret_sel = select(maxfd+1, &read_fds, NULL, NULL, NULL); | ||
| 130 | if (ret_sel < 0) { | ||
| 131 | perror("select"); | ||
| 132 | break; | ||
| 133 | } | ||
| 134 | if (FD_ISSET(client_fd, &read_fds)) { | ||
| 135 | ssize_t n = socket_receive(client_fd, buf, sizeof(buf)); | ||
| 136 | if (n < 0) { | ||
| 137 | fprintf(stderr, "Failed to read from client fd: %s\n", strerror(-n)); | ||
| 138 | break; | ||
| 139 | } else if (n == 0) { | ||
| 140 | fprintf(stderr, "connection closed\n"); | ||
| 141 | break; | ||
| 142 | } | ||
| 143 | |||
| 144 | uint32_t sent = 0; | ||
| 145 | debugserver_client_send(socket_info->debugserver_client, buf, n, &sent); | ||
| 146 | } | ||
| 147 | if (FD_ISSET(dbgsvr_fd, &read_fds)) { | ||
| 148 | uint32_t r = 0; | ||
| 149 | derr = debugserver_client_receive_with_timeout(socket_info->debugserver_client, buf, sizeof(buf), &r, 1); | ||
| 150 | if (r > 0) { | ||
| 151 | socket_send(client_fd, buf, r); | ||
| 152 | } else if (derr != DEBUGSERVER_E_TIMEOUT) { | ||
| 153 | fprintf(stderr, "Failed to read from debugserver (%d)\n", derr); | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 235 | 158 | ||
| 236 | debug("%s: shutting down...\n", __func__); | 159 | debug("%s: shutting down...\n", __func__); |
| 237 | 160 | ||
| @@ -361,6 +284,7 @@ int main(int argc, char *argv[]) | |||
| 361 | fprintf(stderr, "Out of memory\n"); | 284 | fprintf(stderr, "Out of memory\n"); |
| 362 | exit(EXIT_FAILURE); | 285 | exit(EXIT_FAILURE); |
| 363 | } | 286 | } |
| 287 | el->client_fd = client_fd; | ||
| 364 | el->next = NULL; | 288 | el->next = NULL; |
| 365 | 289 | ||
| 366 | if (thread_list) { | 290 | if (thread_list) { |
| @@ -390,6 +314,8 @@ int main(int argc, char *argv[]) | |||
| 390 | /* join and clean up threads */ | 314 | /* join and clean up threads */ |
| 391 | while (thread_list) { | 315 | while (thread_list) { |
| 392 | thread_info_t *el = thread_list; | 316 | thread_info_t *el = thread_list; |
| 317 | socket_shutdown(el->client_fd, SHUT_RDWR); | ||
| 318 | socket_close(el->client_fd); | ||
| 393 | thread_join(el->th); | 319 | thread_join(el->th); |
| 394 | thread_free(el->th); | 320 | thread_free(el->th); |
| 395 | thread_list = el->next; | 321 | thread_list = el->next; |
