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; |