diff options
Diffstat (limited to 'adb/jdwp_service.c')
-rw-r--r-- | adb/jdwp_service.c | 709 |
1 files changed, 709 insertions, 0 deletions
diff --git a/adb/jdwp_service.c b/adb/jdwp_service.c new file mode 100644 index 000000000..43dc69eb4 --- /dev/null +++ b/adb/jdwp_service.c | |||
@@ -0,0 +1,709 @@ | |||
1 | /* implement the "debug-ports" and "track-debug-ports" device services */ | ||
2 | #include "sysdeps.h" | ||
3 | #define TRACE_TAG TRACE_JDWP | ||
4 | #include "adb.h" | ||
5 | #include <errno.h> | ||
6 | #include <stdio.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | /* here's how these things work. | ||
10 | |||
11 | when adbd starts, it creates a unix server socket | ||
12 | named @vm-debug-control (@ is a shortcut for "first byte is zero" | ||
13 | to use the private namespace instead of the file system) | ||
14 | |||
15 | when a new JDWP daemon thread starts in a new VM process, it creates | ||
16 | a connection to @vm-debug-control to announce its availability. | ||
17 | |||
18 | |||
19 | JDWP thread @vm-debug-control | ||
20 | | | | ||
21 | |-------------------------------> | | ||
22 | | hello I'm in process <pid> | | ||
23 | | | | ||
24 | | | | ||
25 | |||
26 | the connection is kept alive. it will be closed automatically if | ||
27 | the JDWP process terminates (this allows adbd to detect dead | ||
28 | processes). | ||
29 | |||
30 | adbd thus maintains a list of "active" JDWP processes. it can send | ||
31 | its content to clients through the "device:debug-ports" service, | ||
32 | or even updates through the "device:track-debug-ports" service. | ||
33 | |||
34 | when a debugger wants to connect, it simply runs the command | ||
35 | equivalent to "adb forward tcp:<hostport> jdwp:<pid>" | ||
36 | |||
37 | "jdwp:<pid>" is a new forward destination format used to target | ||
38 | a given JDWP process on the device. when sutch a request arrives, | ||
39 | adbd does the following: | ||
40 | |||
41 | - first, it calls socketpair() to create a pair of equivalent | ||
42 | sockets. | ||
43 | |||
44 | - it attaches the first socket in the pair to a local socket | ||
45 | which is itself attached to the transport's remote socket: | ||
46 | |||
47 | |||
48 | - it sends the file descriptor of the second socket directly | ||
49 | to the JDWP process with the help of sendmsg() | ||
50 | |||
51 | |||
52 | JDWP thread @vm-debug-control | ||
53 | | | | ||
54 | | <----------------------| | ||
55 | | OK, try this file descriptor | | ||
56 | | | | ||
57 | | | | ||
58 | |||
59 | then, the JDWP thread uses this new socket descriptor as its | ||
60 | pass-through connection to the debugger (and receives the | ||
61 | JDWP-Handshake message, answers to it, etc...) | ||
62 | |||
63 | this gives the following graphics: | ||
64 | ____________________________________ | ||
65 | | | | ||
66 | | ADB Server (host) | | ||
67 | | | | ||
68 | Debugger <---> LocalSocket <----> RemoteSocket | | ||
69 | | ^^ | | ||
70 | |___________________________||_______| | ||
71 | || | ||
72 | Transport || | ||
73 | (TCP for emulator - USB for device) || | ||
74 | || | ||
75 | ___________________________||_______ | ||
76 | | || | | ||
77 | | ADBD (device) || | | ||
78 | | VV | | ||
79 | JDWP <======> LocalSocket <----> RemoteSocket | | ||
80 | | | | ||
81 | |____________________________________| | ||
82 | |||
83 | due to the way adb works, this doesn't need a special socket | ||
84 | type or fancy handling of socket termination if either the debugger | ||
85 | or the JDWP process closes the connection. | ||
86 | |||
87 | THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN | ||
88 | TO HAVE A BETTER IDEA, LET ME KNOW - Digit | ||
89 | |||
90 | **********************************************************************/ | ||
91 | |||
92 | /** JDWP PID List Support Code | ||
93 | ** for each JDWP process, we record its pid and its connected socket | ||
94 | **/ | ||
95 | |||
96 | #define MAX_OUT_FDS 4 | ||
97 | |||
98 | #if !ADB_HOST | ||
99 | |||
100 | #include <sys/socket.h> | ||
101 | #include <sys/un.h> | ||
102 | |||
103 | typedef struct JdwpProcess JdwpProcess; | ||
104 | struct JdwpProcess { | ||
105 | JdwpProcess* next; | ||
106 | JdwpProcess* prev; | ||
107 | int pid; | ||
108 | int socket; | ||
109 | fdevent* fde; | ||
110 | |||
111 | char in_buff[4]; /* input character to read PID */ | ||
112 | int in_len; /* number from JDWP process */ | ||
113 | |||
114 | int out_fds[MAX_OUT_FDS]; /* output array of file descriptors */ | ||
115 | int out_count; /* to send to the JDWP process */ | ||
116 | }; | ||
117 | |||
118 | static JdwpProcess _jdwp_list; | ||
119 | |||
120 | static int | ||
121 | jdwp_process_list( char* buffer, int bufferlen ) | ||
122 | { | ||
123 | char* end = buffer + bufferlen; | ||
124 | char* p = buffer; | ||
125 | JdwpProcess* proc = _jdwp_list.next; | ||
126 | |||
127 | for ( ; proc != &_jdwp_list; proc = proc->next ) { | ||
128 | int len; | ||
129 | |||
130 | /* skip transient connections */ | ||
131 | if (proc->pid < 0) | ||
132 | continue; | ||
133 | |||
134 | len = snprintf(p, end-p, "%d\n", proc->pid); | ||
135 | if (p + len >= end) | ||
136 | break; | ||
137 | p += len; | ||
138 | } | ||
139 | p[0] = 0; | ||
140 | return (p - buffer); | ||
141 | } | ||
142 | |||
143 | |||
144 | static int | ||
145 | jdwp_process_list_msg( char* buffer, int bufferlen ) | ||
146 | { | ||
147 | char head[5]; | ||
148 | int len = jdwp_process_list( buffer+4, bufferlen-4 ); | ||
149 | snprintf(head, sizeof head, "%04x", len); | ||
150 | memcpy(buffer, head, 4); | ||
151 | return len + 4; | ||
152 | } | ||
153 | |||
154 | |||
155 | static void jdwp_process_list_updated(void); | ||
156 | |||
157 | static void | ||
158 | jdwp_process_free( JdwpProcess* proc ) | ||
159 | { | ||
160 | if (proc) { | ||
161 | int n; | ||
162 | |||
163 | proc->prev->next = proc->next; | ||
164 | proc->next->prev = proc->prev; | ||
165 | |||
166 | if (proc->socket >= 0) { | ||
167 | shutdown(proc->socket, SHUT_RDWR); | ||
168 | adb_close(proc->socket); | ||
169 | proc->socket = -1; | ||
170 | } | ||
171 | |||
172 | if (proc->fde != NULL) { | ||
173 | fdevent_destroy(proc->fde); | ||
174 | proc->fde = NULL; | ||
175 | } | ||
176 | proc->pid = -1; | ||
177 | |||
178 | for (n = 0; n < proc->out_count; n++) { | ||
179 | adb_close(proc->out_fds[n]); | ||
180 | } | ||
181 | proc->out_count = 0; | ||
182 | |||
183 | free(proc); | ||
184 | |||
185 | jdwp_process_list_updated(); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | |||
190 | static void jdwp_process_event(int, unsigned, void*); /* forward */ | ||
191 | |||
192 | |||
193 | static JdwpProcess* | ||
194 | jdwp_process_alloc( int socket ) | ||
195 | { | ||
196 | JdwpProcess* proc = calloc(1,sizeof(*proc)); | ||
197 | |||
198 | if (proc == NULL) { | ||
199 | D("not enough memory to create new JDWP process\n"); | ||
200 | return NULL; | ||
201 | } | ||
202 | |||
203 | proc->socket = socket; | ||
204 | proc->pid = -1; | ||
205 | proc->next = proc; | ||
206 | proc->prev = proc; | ||
207 | |||
208 | proc->fde = fdevent_create( socket, jdwp_process_event, proc ); | ||
209 | if (proc->fde == NULL) { | ||
210 | D("could not create fdevent for new JDWP process\n" ); | ||
211 | free(proc); | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | proc->fde->state |= FDE_DONT_CLOSE; | ||
216 | proc->in_len = 0; | ||
217 | proc->out_count = 0; | ||
218 | |||
219 | /* append to list */ | ||
220 | proc->next = &_jdwp_list; | ||
221 | proc->prev = proc->next->prev; | ||
222 | |||
223 | proc->prev->next = proc; | ||
224 | proc->next->prev = proc; | ||
225 | |||
226 | /* start by waiting for the PID */ | ||
227 | fdevent_add(proc->fde, FDE_READ); | ||
228 | |||
229 | return proc; | ||
230 | } | ||
231 | |||
232 | |||
233 | static void | ||
234 | jdwp_process_event( int socket, unsigned events, void* _proc ) | ||
235 | { | ||
236 | JdwpProcess* proc = _proc; | ||
237 | |||
238 | if (events & FDE_READ) { | ||
239 | if (proc->pid < 0) { | ||
240 | /* read the PID as a 4-hexchar string */ | ||
241 | char* p = proc->in_buff + proc->in_len; | ||
242 | int size = 4 - proc->in_len; | ||
243 | char temp[5]; | ||
244 | while (size > 0) { | ||
245 | int len = recv( socket, p, size, 0 ); | ||
246 | if (len < 0) { | ||
247 | if (errno == EINTR) | ||
248 | continue; | ||
249 | if (errno == EAGAIN) | ||
250 | return; | ||
251 | /* this can fail here if the JDWP process crashes very fast */ | ||
252 | D("weird unknown JDWP process failure: %s\n", | ||
253 | strerror(errno)); | ||
254 | |||
255 | goto CloseProcess; | ||
256 | } | ||
257 | if (len == 0) { /* end of stream ? */ | ||
258 | D("weird end-of-stream from unknown JDWP process\n"); | ||
259 | goto CloseProcess; | ||
260 | } | ||
261 | p += len; | ||
262 | proc->in_len += len; | ||
263 | size -= len; | ||
264 | } | ||
265 | /* we have read 4 characters, now decode the pid */ | ||
266 | memcpy(temp, proc->in_buff, 4); | ||
267 | temp[4] = 0; | ||
268 | |||
269 | if (sscanf( temp, "%04x", &proc->pid ) != 1) { | ||
270 | D("could not decode JDWP %p PID number: '%s'\n", proc, temp); | ||
271 | goto CloseProcess; | ||
272 | } | ||
273 | |||
274 | /* all is well, keep reading to detect connection closure */ | ||
275 | D("Adding pid %d to jdwp process list\n", proc->pid); | ||
276 | jdwp_process_list_updated(); | ||
277 | } | ||
278 | else | ||
279 | { | ||
280 | /* the pid was read, if we get there it's probably because the connection | ||
281 | * was closed (e.g. the JDWP process exited or crashed) */ | ||
282 | char buf[32]; | ||
283 | |||
284 | for (;;) { | ||
285 | int len = recv(socket, buf, sizeof(buf), 0); | ||
286 | |||
287 | if (len <= 0) { | ||
288 | if (len < 0 && errno == EINTR) | ||
289 | continue; | ||
290 | if (len < 0 && errno == EAGAIN) | ||
291 | return; | ||
292 | else { | ||
293 | D("terminating JDWP %d connection: %s\n", proc->pid, | ||
294 | strerror(errno)); | ||
295 | break; | ||
296 | } | ||
297 | } | ||
298 | else { | ||
299 | D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n", | ||
300 | proc->pid, len ); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | CloseProcess: | ||
305 | if (proc->pid >= 0) | ||
306 | D( "remove pid %d to jdwp process list\n", proc->pid ); | ||
307 | jdwp_process_free(proc); | ||
308 | return; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | if (events & FDE_WRITE) { | ||
313 | D("trying to write to JDWP pid controli (count=%d first=%d) %d\n", | ||
314 | proc->pid, proc->out_count, proc->out_fds[0]); | ||
315 | if (proc->out_count > 0) { | ||
316 | int fd = proc->out_fds[0]; | ||
317 | int n, ret; | ||
318 | struct cmsghdr* cmsg; | ||
319 | struct msghdr msg; | ||
320 | struct iovec iov; | ||
321 | char dummy = '!'; | ||
322 | char buffer[sizeof(struct cmsghdr) + sizeof(int)]; | ||
323 | |||
324 | iov.iov_base = &dummy; | ||
325 | iov.iov_len = 1; | ||
326 | msg.msg_name = NULL; | ||
327 | msg.msg_namelen = 0; | ||
328 | msg.msg_iov = &iov; | ||
329 | msg.msg_iovlen = 1; | ||
330 | msg.msg_flags = 0; | ||
331 | msg.msg_control = buffer; | ||
332 | msg.msg_controllen = sizeof(buffer); | ||
333 | |||
334 | cmsg = CMSG_FIRSTHDR(&msg); | ||
335 | cmsg->cmsg_len = msg.msg_controllen; | ||
336 | cmsg->cmsg_level = SOL_SOCKET; | ||
337 | cmsg->cmsg_type = SCM_RIGHTS; | ||
338 | ((int*)CMSG_DATA(cmsg))[0] = fd; | ||
339 | |||
340 | for (;;) { | ||
341 | ret = sendmsg(proc->socket, &msg, 0); | ||
342 | if (ret >= 0) | ||
343 | break; | ||
344 | if (errno == EINTR) | ||
345 | continue; | ||
346 | D("sending new file descriptor to JDWP %d failed: %s\n", | ||
347 | proc->pid, strerror(errno)); | ||
348 | goto CloseProcess; | ||
349 | } | ||
350 | |||
351 | D("sent file descriptor %d to JDWP process %d\n", | ||
352 | fd, proc->pid); | ||
353 | |||
354 | for (n = 1; n < proc->out_count; n++) | ||
355 | proc->out_fds[n-1] = proc->out_fds[n]; | ||
356 | |||
357 | if (--proc->out_count == 0) | ||
358 | fdevent_del( proc->fde, FDE_WRITE ); | ||
359 | } | ||
360 | } | ||
361 | } | ||
362 | |||
363 | |||
364 | int | ||
365 | create_jdwp_connection_fd(int pid) | ||
366 | { | ||
367 | JdwpProcess* proc = _jdwp_list.next; | ||
368 | |||
369 | D("looking for pid %d in JDWP process list\n", pid); | ||
370 | for ( ; proc != &_jdwp_list; proc = proc->next ) { | ||
371 | if (proc->pid == pid) { | ||
372 | goto FoundIt; | ||
373 | } | ||
374 | } | ||
375 | D("search failed !!\n"); | ||
376 | return -1; | ||
377 | |||
378 | FoundIt: | ||
379 | { | ||
380 | int fds[2]; | ||
381 | |||
382 | if (proc->out_count >= MAX_OUT_FDS) { | ||
383 | D("%s: too many pending JDWP connection for pid %d\n", | ||
384 | __FUNCTION__, pid); | ||
385 | return -1; | ||
386 | } | ||
387 | |||
388 | if (adb_socketpair(fds) < 0) { | ||
389 | D("%s: socket pair creation failed: %s\n", | ||
390 | __FUNCTION__, strerror(errno)); | ||
391 | return -1; | ||
392 | } | ||
393 | |||
394 | proc->out_fds[ proc->out_count ] = fds[1]; | ||
395 | if (++proc->out_count == 1) | ||
396 | fdevent_add( proc->fde, FDE_WRITE ); | ||
397 | |||
398 | return fds[0]; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /** VM DEBUG CONTROL SOCKET | ||
403 | ** | ||
404 | ** we do implement a custom asocket to receive the data | ||
405 | **/ | ||
406 | |||
407 | /* name of the debug control Unix socket */ | ||
408 | #define JDWP_CONTROL_NAME "\0jdwp-control" | ||
409 | #define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME)-1) | ||
410 | |||
411 | typedef struct { | ||
412 | int listen_socket; | ||
413 | fdevent* fde; | ||
414 | |||
415 | } JdwpControl; | ||
416 | |||
417 | |||
418 | static void | ||
419 | jdwp_control_event(int s, unsigned events, void* user); | ||
420 | |||
421 | |||
422 | static int | ||
423 | jdwp_control_init( JdwpControl* control, | ||
424 | const char* sockname, | ||
425 | int socknamelen ) | ||
426 | { | ||
427 | struct sockaddr_un addr; | ||
428 | socklen_t addrlen; | ||
429 | int s; | ||
430 | int maxpath = sizeof(addr.sun_path); | ||
431 | int pathlen = socknamelen; | ||
432 | |||
433 | if (pathlen >= maxpath) { | ||
434 | D( "vm debug control socket name too long (%d extra chars)\n", | ||
435 | pathlen+1-maxpath ); | ||
436 | return -1; | ||
437 | } | ||
438 | |||
439 | memset(&addr, 0, sizeof(addr)); | ||
440 | addr.sun_family = AF_UNIX; | ||
441 | memcpy(addr.sun_path, sockname, socknamelen); | ||
442 | |||
443 | s = socket( AF_UNIX, SOCK_STREAM, 0 ); | ||
444 | if (s < 0) { | ||
445 | D( "could not create vm debug control socket. %d: %s\n", | ||
446 | errno, strerror(errno)); | ||
447 | return -1; | ||
448 | } | ||
449 | |||
450 | addrlen = (pathlen + sizeof(addr.sun_family)); | ||
451 | |||
452 | if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) { | ||
453 | D( "could not bind vm debug control socket: %d: %s\n", | ||
454 | errno, strerror(errno) ); | ||
455 | adb_close(s); | ||
456 | return -1; | ||
457 | } | ||
458 | |||
459 | if ( listen(s, 4) < 0 ) { | ||
460 | D("listen failed in jdwp control socket: %d: %s\n", | ||
461 | errno, strerror(errno)); | ||
462 | adb_close(s); | ||
463 | return -1; | ||
464 | } | ||
465 | |||
466 | control->listen_socket = s; | ||
467 | |||
468 | control->fde = fdevent_create(s, jdwp_control_event, control); | ||
469 | if (control->fde == NULL) { | ||
470 | D( "could not create fdevent for jdwp control socket\n" ); | ||
471 | adb_close(s); | ||
472 | return -1; | ||
473 | } | ||
474 | |||
475 | /* only wait for incoming connections */ | ||
476 | fdevent_add(control->fde, FDE_READ); | ||
477 | |||
478 | D("jdwp control socket started (%d)\n", control->listen_socket); | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | |||
483 | static void | ||
484 | jdwp_control_event( int s, unsigned events, void* _control ) | ||
485 | { | ||
486 | JdwpControl* control = (JdwpControl*) _control; | ||
487 | |||
488 | if (events & FDE_READ) { | ||
489 | struct sockaddr addr; | ||
490 | socklen_t addrlen = sizeof(addr); | ||
491 | int s = -1; | ||
492 | JdwpProcess* proc; | ||
493 | |||
494 | do { | ||
495 | s = adb_socket_accept( control->listen_socket, &addr, &addrlen ); | ||
496 | if (s < 0) { | ||
497 | if (errno == EINTR) | ||
498 | continue; | ||
499 | if (errno == ECONNABORTED) { | ||
500 | /* oops, the JDWP process died really quick */ | ||
501 | D("oops, the JDWP process died really quick\n"); | ||
502 | return; | ||
503 | } | ||
504 | /* the socket is probably closed ? */ | ||
505 | D( "weird accept() failed on jdwp control socket: %s\n", | ||
506 | strerror(errno) ); | ||
507 | return; | ||
508 | } | ||
509 | } | ||
510 | while (s < 0); | ||
511 | |||
512 | proc = jdwp_process_alloc( s ); | ||
513 | if (proc == NULL) | ||
514 | return; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | |||
519 | static JdwpControl _jdwp_control; | ||
520 | |||
521 | /** "jdwp" local service implementation | ||
522 | ** this simply returns the list of known JDWP process pids | ||
523 | **/ | ||
524 | |||
525 | typedef struct { | ||
526 | asocket socket; | ||
527 | int pass; | ||
528 | } JdwpSocket; | ||
529 | |||
530 | static void | ||
531 | jdwp_socket_close( asocket* s ) | ||
532 | { | ||
533 | asocket* peer = s->peer; | ||
534 | |||
535 | remove_socket(s); | ||
536 | |||
537 | if (peer) { | ||
538 | peer->peer = NULL; | ||
539 | peer->close(peer); | ||
540 | } | ||
541 | free(s); | ||
542 | } | ||
543 | |||
544 | static int | ||
545 | jdwp_socket_enqueue( asocket* s, apacket* p ) | ||
546 | { | ||
547 | /* you can't write to this asocket */ | ||
548 | put_apacket(p); | ||
549 | s->peer->close(s->peer); | ||
550 | return -1; | ||
551 | } | ||
552 | |||
553 | |||
554 | static void | ||
555 | jdwp_socket_ready( asocket* s ) | ||
556 | { | ||
557 | JdwpSocket* jdwp = (JdwpSocket*)s; | ||
558 | asocket* peer = jdwp->socket.peer; | ||
559 | |||
560 | /* on the first call, send the list of pids, | ||
561 | * on the second one, close the connection | ||
562 | */ | ||
563 | if (jdwp->pass == 0) { | ||
564 | apacket* p = get_apacket(); | ||
565 | p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD); | ||
566 | peer->enqueue(peer, p); | ||
567 | jdwp->pass = 1; | ||
568 | } | ||
569 | else { | ||
570 | peer->close(peer); | ||
571 | } | ||
572 | } | ||
573 | |||
574 | asocket* | ||
575 | create_jdwp_service_socket( void ) | ||
576 | { | ||
577 | JdwpSocket* s = calloc(sizeof(*s),1); | ||
578 | |||
579 | if (s == NULL) | ||
580 | return NULL; | ||
581 | |||
582 | install_local_socket(&s->socket); | ||
583 | |||
584 | s->socket.ready = jdwp_socket_ready; | ||
585 | s->socket.enqueue = jdwp_socket_enqueue; | ||
586 | s->socket.close = jdwp_socket_close; | ||
587 | s->pass = 0; | ||
588 | |||
589 | return &s->socket; | ||
590 | } | ||
591 | |||
592 | /** "track-jdwp" local service implementation | ||
593 | ** this periodically sends the list of known JDWP process pids | ||
594 | ** to the client... | ||
595 | **/ | ||
596 | |||
597 | typedef struct JdwpTracker JdwpTracker; | ||
598 | |||
599 | struct JdwpTracker { | ||
600 | asocket socket; | ||
601 | JdwpTracker* next; | ||
602 | JdwpTracker* prev; | ||
603 | int need_update; | ||
604 | }; | ||
605 | |||
606 | static JdwpTracker _jdwp_trackers_list; | ||
607 | |||
608 | |||
609 | static void | ||
610 | jdwp_process_list_updated(void) | ||
611 | { | ||
612 | char buffer[1024]; | ||
613 | int len; | ||
614 | JdwpTracker* t = _jdwp_trackers_list.next; | ||
615 | |||
616 | len = jdwp_process_list_msg(buffer, sizeof(buffer)); | ||
617 | |||
618 | for ( ; t != &_jdwp_trackers_list; t = t->next ) { | ||
619 | apacket* p = get_apacket(); | ||
620 | asocket* peer = t->socket.peer; | ||
621 | memcpy(p->data, buffer, len); | ||
622 | p->len = len; | ||
623 | peer->enqueue( peer, p ); | ||
624 | } | ||
625 | } | ||
626 | |||
627 | static void | ||
628 | jdwp_tracker_close( asocket* s ) | ||
629 | { | ||
630 | JdwpTracker* tracker = (JdwpTracker*) s; | ||
631 | asocket* peer = s->peer; | ||
632 | |||
633 | if (peer) { | ||
634 | peer->peer = NULL; | ||
635 | peer->close(peer); | ||
636 | } | ||
637 | |||
638 | remove_socket(s); | ||
639 | |||
640 | tracker->prev->next = tracker->next; | ||
641 | tracker->next->prev = tracker->prev; | ||
642 | |||
643 | free(s); | ||
644 | } | ||
645 | |||
646 | static void | ||
647 | jdwp_tracker_ready( asocket* s ) | ||
648 | { | ||
649 | JdwpTracker* t = (JdwpTracker*) s; | ||
650 | |||
651 | if (t->need_update) { | ||
652 | apacket* p = get_apacket(); | ||
653 | t->need_update = 0; | ||
654 | p->len = jdwp_process_list_msg((char*)p->data, sizeof(p->data)); | ||
655 | s->peer->enqueue(s->peer, p); | ||
656 | } | ||
657 | } | ||
658 | |||
659 | static int | ||
660 | jdwp_tracker_enqueue( asocket* s, apacket* p ) | ||
661 | { | ||
662 | /* you can't write to this socket */ | ||
663 | put_apacket(p); | ||
664 | s->peer->close(s->peer); | ||
665 | return -1; | ||
666 | } | ||
667 | |||
668 | |||
669 | asocket* | ||
670 | create_jdwp_tracker_service_socket( void ) | ||
671 | { | ||
672 | JdwpTracker* t = calloc(sizeof(*t),1); | ||
673 | |||
674 | if (t == NULL) | ||
675 | return NULL; | ||
676 | |||
677 | t->next = &_jdwp_trackers_list; | ||
678 | t->prev = t->next->prev; | ||
679 | |||
680 | t->next->prev = t; | ||
681 | t->prev->next = t; | ||
682 | |||
683 | install_local_socket(&t->socket); | ||
684 | |||
685 | t->socket.ready = jdwp_tracker_ready; | ||
686 | t->socket.enqueue = jdwp_tracker_enqueue; | ||
687 | t->socket.close = jdwp_tracker_close; | ||
688 | t->need_update = 1; | ||
689 | |||
690 | return &t->socket; | ||
691 | } | ||
692 | |||
693 | |||
694 | int | ||
695 | init_jdwp(void) | ||
696 | { | ||
697 | _jdwp_list.next = &_jdwp_list; | ||
698 | _jdwp_list.prev = &_jdwp_list; | ||
699 | |||
700 | _jdwp_trackers_list.next = &_jdwp_trackers_list; | ||
701 | _jdwp_trackers_list.prev = &_jdwp_trackers_list; | ||
702 | |||
703 | return jdwp_control_init( &_jdwp_control, | ||
704 | JDWP_CONTROL_NAME, | ||
705 | JDWP_CONTROL_NAME_LEN ); | ||
706 | } | ||
707 | |||
708 | #endif /* !ADB_HOST */ | ||
709 | |||