static void jdwp_process_free( JdwpProcess* proc ) { if (proc) { int n; proc->prev->next = proc->next; proc->next->prev = proc->prev; if (proc->socket >= 0) { adb_shutdown(proc->socket); adb_close(proc->socket); proc->socket = -1; } if (proc->fde != NULL) { fdevent_destroy(proc->fde); proc->fde = NULL; } proc->pid = -1; for (n = 0; n < proc->out_count; n++) { adb_close(proc->out_fds[n]); } proc->out_count = 0; free(proc); jdwp_process_list_updated(); } }
static void jdwp_process_event( int socket, unsigned events, void* _proc ) { JdwpProcess* proc = _proc; if (events & FDE_READ) { if (proc->pid < 0) { /* read the PID as a 4-hexchar string */ char* p = proc->in_buff + proc->in_len; int size = 4 - proc->in_len; char temp[5]; while (size > 0) { int len = recv( socket, p, size, 0 ); if (len < 0) { if (errno == EINTR) continue; if (errno == EAGAIN) return; /* this can fail here if the JDWP process crashes very fast */ D("weird unknown JDWP process failure: %s\n", strerror(errno)); goto CloseProcess; } if (len == 0) { /* end of stream ? */ D("weird end-of-stream from unknown JDWP process\n"); goto CloseProcess; } p += len; proc->in_len += len; size -= len; } /* we have read 4 characters, now decode the pid */ memcpy(temp, proc->in_buff, 4); temp[4] = 0; if (sscanf( temp, "%04x", &proc->pid ) != 1) { D("could not decode JDWP %p PID number: '%s'\n", proc, temp); goto CloseProcess; } /* all is well, keep reading to detect connection closure */ D("Adding pid %d to jdwp process list\n", proc->pid); jdwp_process_list_updated(); } else { /* the pid was read, if we get there it's probably because the connection * was closed (e.g. the JDWP process exited or crashed) */ char buf[32]; for (;;) { int len = recv(socket, buf, sizeof(buf), 0); if (len <= 0) { if (len < 0 && errno == EINTR) continue; if (len < 0 && errno == EAGAIN) return; else { D("terminating JDWP %d connection: %s\n", proc->pid, strerror(errno)); break; } } else { D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n", proc->pid, len ); } } CloseProcess: if (proc->pid >= 0) D( "remove pid %d to jdwp process list\n", proc->pid ); jdwp_process_free(proc); return; } } if (events & FDE_WRITE) { D("trying to write to JDWP pid controli (count=%d first=%d) %d\n", proc->pid, proc->out_count, proc->out_fds[0]); if (proc->out_count > 0) { int fd = proc->out_fds[0]; int n, ret; struct cmsghdr* cmsg; struct msghdr msg; struct iovec iov; char dummy = '!'; char buffer[sizeof(struct cmsghdr) + sizeof(int)]; int flags; iov.iov_base = &dummy; iov.iov_len = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = buffer; msg.msg_controllen = sizeof(buffer); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = msg.msg_controllen; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; ((int*)CMSG_DATA(cmsg))[0] = fd; flags = fcntl(proc->socket,F_GETFL,0); if (flags == -1) { D("failed to get cntl flags for socket %d: %s\n", proc->pid, strerror(errno)); goto CloseProcess; } if (fcntl(proc->socket, F_SETFL, flags & ~O_NONBLOCK) == -1) { D("failed to remove O_NONBLOCK flag for socket %d: %s\n", proc->pid, strerror(errno)); goto CloseProcess; } for (;;) { ret = sendmsg(proc->socket, &msg, 0); if (ret >= 0) { adb_close(fd); break; } if (errno == EINTR) continue; D("sending new file descriptor to JDWP %d failed: %s\n", proc->pid, strerror(errno)); goto CloseProcess; } D("sent file descriptor %d to JDWP process %d\n", fd, proc->pid); for (n = 1; n < proc->out_count; n++) proc->out_fds[n-1] = proc->out_fds[n]; if (fcntl(proc->socket, F_SETFL, flags) == -1) { D("failed to set O_NONBLOCK flag for socket %d: %s\n", proc->pid, strerror(errno)); goto CloseProcess; } if (--proc->out_count == 0) fdevent_del( proc->fde, FDE_WRITE ); } } }
static void jdwp_process_event(int socket, unsigned events, void* _proc) { JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc); CHECK_EQ(socket, proc->socket); if (events & FDE_READ) { if (proc->pid < 0) { ssize_t rc = TEMP_FAILURE_RETRY(recv(socket, &proc->pid, sizeof(proc->pid), 0)); if (rc != sizeof(proc->pid)) { D("failed to read jdwp pid: rc = %zd, errno = %s", rc, strerror(errno)); goto CloseProcess; } /* all is well, keep reading to detect connection closure */ D("Adding pid %d to jdwp process list", proc->pid); jdwp_process_list_updated(); } else { // We already have the PID, if we can read from the socket, we've probably hit EOF. D("terminating JDWP connection %d", proc->pid); goto CloseProcess; } } if (events & FDE_WRITE) { D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size()); CHECK(!proc->out_fds.empty()); int fd = proc->out_fds.back().get(); struct cmsghdr* cmsg; struct msghdr msg; struct iovec iov; char dummy = '!'; char buffer[sizeof(struct cmsghdr) + sizeof(int)]; iov.iov_base = &dummy; iov.iov_len = 1; msg.msg_name = nullptr; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = buffer; msg.msg_controllen = sizeof(buffer); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = msg.msg_controllen; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; ((int*)CMSG_DATA(cmsg))[0] = fd; int ret = TEMP_FAILURE_RETRY(sendmsg(socket, &msg, 0)); if (ret < 0) { D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno)); goto CloseProcess; } D("sent file descriptor %d to JDWP process %d", fd, proc->pid); proc->out_fds.pop_back(); if (proc->out_fds.empty()) { fdevent_del(proc->fde, FDE_WRITE); } } return; CloseProcess: proc->RemoveFromList(); jdwp_process_list_updated(); }