static void wait_for_state(int fd, void* data) { std::unique_ptr<state_info> sinfo(reinterpret_cast<state_info*>(data)); D("wait_for_state %d", sinfo->state); while (true) { bool is_ambiguous = false; std::string error = "unknown error"; const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL; atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error); if (t != nullptr && t->connection_state == sinfo->state) { SendOkay(fd); break; } else if (!is_ambiguous) { adb_sleep_ms(1000); // Try again... } else { SendFail(fd, error); break; } } adb_close(fd); D("wait_for_state is done"); }
int adb_remove_forward(unsigned short local, transport_type ttype, const char* serial) { char *err; atransport *transport = acquire_one_transport(CS_ANY, ttype, serial, &err); if(!transport) { return 1; } char local_name[32]; snprintf(local_name, sizeof(local_name), "tcp:%u", local); int r = remove_listener(local_name, transport); return r==0; }
int adb_create_forward(unsigned short local, unsigned short remote, transport_type ttype, const char* serial, int no_rebind) { char *err; atransport *transport = acquire_one_transport(CS_ANY, ttype, serial, &err); if (!transport) { return 1; } char local_name[32]; char remote_name[32]; snprintf(local_name, sizeof(local_name), "tcp:%u", local); snprintf(remote_name, sizeof(remote_name), "tcp:%u", remote); int r = install_listener(local_name, remote_name, transport, no_rebind); return r==0; }
static void wait_for_state(int fd, void* cookie) { struct state_info* sinfo = cookie; char* err = "unknown error"; D("wait_for_state %d\n", sinfo->state); atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err); if(t != 0) { writex(fd, "OKAY", 4); } else { sendfailmsg(fd, err); } if (sinfo->serial) free(sinfo->serial); free(sinfo); adb_close(fd); D("wait_for_state is done\n"); }
static void wait_for_state(int fd, void* cookie) { state_info* sinfo = reinterpret_cast<state_info*>(cookie); D("wait_for_state %d\n", sinfo->state); std::string error_msg = "unknown error"; atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg); if (t != 0) { SendOkay(fd); } else { SendFail(fd, error_msg); } if (sinfo->serial) free(sinfo->serial); free(sinfo); adb_close(fd); D("wait_for_state is done\n"); }
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) { atransport *transport = NULL; char buf[4096]; if(!strcmp(service, "kill")) { fprintf(stderr,"adb server killed by remote request\n"); fflush(stdout); adb_write(reply_fd, "OKAY", 4); usb_cleanup(); exit(0); } #if ADB_HOST // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { char* error_string = "unknown failure"; transport_type type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = strdup(service); } transport = acquire_one_transport(CS_ANY, type, serial, &error_string); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } else { sendfailmsg(reply_fd, error_string); } return 1; } // return a list of all connected devices if (!strcmp(service, "devices")) { char buffer[4096]; memset(buf, 0, sizeof(buf)); memset(buffer, 0, sizeof(buffer)); D("Getting device list \n"); list_transports(buffer, sizeof(buffer)); snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer); D("Wrote device list \n"); writex(reply_fd, buf, strlen(buf)); return 0; } // add a new TCP transport, device or emulator if (!strncmp(service, "connect:", 8)) { char buffer[4096]; char* host = service + 8; if (!strncmp(host, "emu:", 4)) { connect_emulator(host + 4, buffer, sizeof(buffer)); } else { connect_device(host, buffer, sizeof(buffer)); } // Send response for emulator and device snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); writex(reply_fd, buf, strlen(buf)); return 0; } // remove TCP transport if (!strncmp(service, "disconnect:", 11)) { char buffer[4096]; memset(buffer, 0, sizeof(buffer)); char* serial = service + 11; if (serial[0] == 0) { // disconnect from all TCP devices unregister_all_tcp_transports(); } else { char hostbuf[100]; // assume port 5555 if no port is specified if (!strchr(serial, ':')) { snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial); serial = hostbuf; } atransport *t = find_transport(serial); if (t) { unregister_transport(t); } else { snprintf(buffer, sizeof(buffer), "No such device %s", serial); } } snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); writex(reply_fd, buf, strlen(buf)); return 0; } // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { char version[12]; snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION); snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version); writex(reply_fd, buf, strlen(buf)); return 0; } if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->serial) { out = transport->serial; } snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out); writex(reply_fd, buf, strlen(buf)); return 0; } // indicates a new emulator instance has started if (!strncmp(service,"emulator:",9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } #endif // ADB_HOST if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) { char *local, *remote, *err; int r; atransport *transport; int createForward = strncmp(service,"kill",4); local = service + (createForward ? 8 : 12); remote = strchr(local,';'); if(remote == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 0; } *remote++ = 0; if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){ sendfailmsg(reply_fd, "malformed forward spec"); return 0; } transport = acquire_one_transport(CS_ANY, ttype, serial, &err); if (!transport) { sendfailmsg(reply_fd, err); return 0; } if (createForward) { r = install_listener(local, remote, transport); } else { r = remove_listener(local, remote, transport); } if(r == 0) { /* 1st OKAY is connect, 2nd OKAY is status */ writex(reply_fd, "OKAYOKAY", 8); return 0; } if (createForward) { sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket"); } else { sendfailmsg(reply_fd, "cannot remove listener"); } return 0; } if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); char *state = connection_state_name(transport); snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state); writex(reply_fd, buf, strlen(buf)); return 0; } return -1; }
static int smart_socket_enqueue(asocket* s, apacket* p) { unsigned len; #if ADB_HOST char* service = nullptr; char* serial = nullptr; TransportId transport_id = 0; TransportType type = kTransportAny; #endif D("SS(%d): enqueue %zu", s->id, p->len); if (s->pkt_first == 0) { s->pkt_first = p; s->pkt_last = p; } else { if ((s->pkt_first->len + p->len) > s->get_max_payload()) { D("SS(%d): overflow", s->id); put_apacket(p); goto fail; } memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len); s->pkt_first->len += p->len; put_apacket(p); p = s->pkt_first; } /* don't bother if we can't decode the length */ if (p->len < 4) { return 0; } len = unhex(p->data, 4); if ((len < 1) || (len > MAX_PAYLOAD)) { D("SS(%d): bad size (%d)", s->id, len); goto fail; } D("SS(%d): len is %d", s->id, len); /* can't do anything until we have the full header */ if ((len + 4) > p->len) { D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - p->len); return 0; } p->data[len + 4] = 0; D("SS(%d): '%s'", s->id, (char*)(p->data + 4)); #if ADB_HOST service = (char*)p->data + 4; if (!strncmp(service, "host-serial:", strlen("host-serial:"))) { char* serial_end; service += strlen("host-serial:"); // serial number should follow "host:" and could be a host:port string. serial_end = internal::skip_host_serial(service); if (serial_end) { *serial_end = 0; // terminate string serial = service; service = serial_end + 1; } } else if (!strncmp(service, "host-transport-id:", strlen("host-transport-id:"))) { service += strlen("host-transport-id:"); transport_id = strtoll(service, &service, 10); if (*service != ':') { return -1; } service++; } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) { type = kTransportUsb; service += strlen("host-usb:"); } else if (!strncmp(service, "host-local:", strlen("host-local:"))) { type = kTransportLocal; service += strlen("host-local:"); } else if (!strncmp(service, "host:", strlen("host:"))) { type = kTransportAny; service += strlen("host:"); } else { service = nullptr; } if (service) { asocket* s2; /* some requests are handled immediately -- in that ** case the handle_host_request() routine has sent ** the OKAY or FAIL message and all we have to do ** is clean up. */ if (handle_host_request(service, type, serial, transport_id, s->peer->fd, s) == 0) { /* XXX fail message? */ D("SS(%d): handled host service '%s'", s->id, service); goto fail; } if (!strncmp(service, "transport", strlen("transport"))) { D("SS(%d): okay transport", s->id); p->len = 0; return 0; } /* try to find a local service with this name. ** if no such service exists, we'll fail out ** and tear down here. */ s2 = create_host_service_socket(service, serial, transport_id); if (s2 == 0) { D("SS(%d): couldn't create host service '%s'", s->id, service); SendFail(s->peer->fd, "unknown host service"); goto fail; } /* we've connected to a local host service, ** so we make our peer back into a regular ** local socket and bind it to the new local ** service socket, acknowledge the successful ** connection, and close this smart socket now ** that its work is done. */ SendOkay(s->peer->fd); s->peer->ready = local_socket_ready; s->peer->shutdown = nullptr; s->peer->close = local_socket_close; s->peer->peer = s2; s2->peer = s->peer; s->peer = 0; D("SS(%d): okay", s->id); s->close(s); /* initial state is "ready" */ s2->ready(s2); return 0; } #else /* !ADB_HOST */ if (s->transport == nullptr) { std::string error_msg = "unknown failure"; s->transport = acquire_one_transport(kTransportAny, nullptr, 0, nullptr, &error_msg); if (s->transport == nullptr) { SendFail(s->peer->fd, error_msg); goto fail; } } #endif if (!s->transport) { SendFail(s->peer->fd, "device offline (no transport)"); goto fail; } else if (s->transport->GetConnectionState() == kCsOffline) { /* if there's no remote we fail the connection ** right here and terminate it */ SendFail(s->peer->fd, "device offline (transport offline)"); goto fail; } /* instrument our peer to pass the success or fail ** message back once it connects or closes, then ** detach from it, request the connection, and ** tear down */ s->peer->ready = local_socket_ready_notify; s->peer->shutdown = nullptr; s->peer->close = local_socket_close_notify; s->peer->peer = 0; /* give him our transport and upref it */ s->peer->transport = s->transport; connect_to_remote(s->peer, (char*)(p->data + 4)); s->peer = 0; s->close(s); return 1; fail: /* we're going to close our peer as a side-effect, so ** return -1 to signal that state to the local socket ** who is enqueueing against us */ s->close(s); return -1; }
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) { if(!strcmp(service, "kill")) { fprintf(stderr,"adb server killed by remote request\n"); fflush(stdout); SendOkay(reply_fd); usb_cleanup(); exit(0); } #if ADB_HOST atransport *transport = NULL; // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { transport_type type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = service; } std::string error_msg = "unknown failure"; transport = acquire_one_transport(CS_ANY, type, serial, &error_msg); if (transport) { s->transport = transport; SendOkay(reply_fd); } else { SendFail(reply_fd, error_msg); } return 1; } // return a list of all connected devices if (!strncmp(service, "devices", 7)) { bool long_listing = (strcmp(service+7, "-l") == 0); if (long_listing || service[7] == 0) { D("Getting device list...\n"); std::string device_list = list_transports(long_listing); D("Sending device list...\n"); SendOkay(reply_fd); SendProtocolString(reply_fd, device_list); return 0; } return 1; } // remove TCP transport if (!strncmp(service, "disconnect:", 11)) { char buffer[4096]; memset(buffer, 0, sizeof(buffer)); char* serial = service + 11; if (serial[0] == 0) { // disconnect from all TCP devices unregister_all_tcp_transports(); } else { char hostbuf[100]; // assume port 5555 if no port is specified if (!strchr(serial, ':')) { snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial); serial = hostbuf; } atransport *t = find_transport(serial); if (t) { unregister_transport(t); } else { snprintf(buffer, sizeof(buffer), "No such device %s", serial); } } SendOkay(reply_fd); SendProtocolString(reply_fd, buffer); return 0; } // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { SendOkay(reply_fd); SendProtocolString(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION)); return 0; } if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { const char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->serial) { out = transport->serial; } SendOkay(reply_fd); SendProtocolString(reply_fd, out); return 0; } if(!strncmp(service,"get-devpath",strlen("get-devpath"))) { const char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->devpath) { out = transport->devpath; } SendOkay(reply_fd); SendProtocolString(reply_fd, out); return 0; } // indicates a new emulator instance has started if (!strncmp(service,"emulator:",9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); SendOkay(reply_fd); SendProtocolString(reply_fd, transport ? transport->connection_state_name() : "unknown"); return 0; } #endif // ADB_HOST int ret = handle_forward_request(service, ttype, serial, reply_fd); if (ret >= 0) return ret - 1; return -1; }
// Try to handle a network forwarding request. // This returns 1 on success, 0 on failure, and -1 to indicate this is not // a forwarding-related request. int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd) { if (!strcmp(service, "list-forward")) { // Create the list of forward redirections. std::string listeners = format_listeners(); #if ADB_HOST SendOkay(reply_fd); #endif SendProtocolString(reply_fd, listeners); return 1; } if (!strcmp(service, "killforward-all")) { remove_all_listeners(); #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ SendOkay(reply_fd); #endif SendOkay(reply_fd); return 1; } if (!strncmp(service, "forward:",8) || !strncmp(service, "killforward:",12)) { char *local, *remote; atransport *transport; int createForward = strncmp(service, "kill", 4); int no_rebind = 0; local = strchr(service, ':') + 1; // Handle forward:norebind:<local>... here if (createForward && !strncmp(local, "norebind:", 9)) { no_rebind = 1; local = strchr(local, ':') + 1; } remote = strchr(local,';'); if (createForward) { // Check forward: parameter format: '<local>;<remote>' if(remote == 0) { SendFail(reply_fd, "malformed forward spec"); return 1; } *remote++ = 0; if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) { SendFail(reply_fd, "malformed forward spec"); return 1; } } else { // Check killforward: parameter format: '<local>' if (local[0] == 0) { SendFail(reply_fd, "malformed forward spec"); return 1; } } std::string error_msg; transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg); if (!transport) { SendFail(reply_fd, error_msg); return 1; } install_status_t r; if (createForward) { r = install_listener(local, remote, transport, no_rebind); } else { r = remove_listener(local, transport); } if (r == INSTALL_STATUS_OK) { #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ SendOkay(reply_fd); #endif SendOkay(reply_fd); return 1; } std::string message; switch (r) { case INSTALL_STATUS_OK: message = " "; break; case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break; case INSTALL_STATUS_CANNOT_BIND: message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno)); break; case INSTALL_STATUS_CANNOT_REBIND: message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno)); break; case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break; } SendFail(reply_fd, message); return 1; } return 0; }
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) { D("service=%s, ttype=%d, serial=%s, reply_fd=%d, asocket=?\n", service, ttype, serial, reply_fd); atransport *transport = NULL; char buf[4096]; if(!strcmp(service, "kill")) { fprintf(stderr,"adb server killed by remote request\n"); fflush(stdout); adb_write(reply_fd, "OKAY", 4); usb_cleanup(); exit(0); } #if ADB_HOST // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { char* error_string = "unknown failure"; transport_type type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = service; } transport = acquire_one_transport(CS_ANY, type, serial, &error_string); if (transport) { s->transport = transport; adb_write(reply_fd, "OKAY", 4); } else { sendfailmsg(reply_fd, error_string); } return 1; } // return a list of all connected devices if (!strncmp(service, "devices", 7)) { char buffer[4096]; int use_long = !strcmp(service+7, "-l"); if (use_long || service[7] == 0) { memset(buf, 0, sizeof(buf)); memset(buffer, 0, sizeof(buffer)); D("Getting device list \n"); list_transports(buffer, sizeof(buffer), use_long); snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer); D("Wrote device list \n"); writex(reply_fd, buf, strlen(buf)); return 0; } } // add a new TCP transport, device or emulator if (!strncmp(service, "connect:", 8)) { char buffer[4096]; char* host = service + 8; if (!strncmp(host, "emu:", 4)) { connect_emulator(host + 4, buffer, sizeof(buffer)); } else { connect_device(host, buffer, sizeof(buffer)); } // Send response for emulator and device snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); writex(reply_fd, buf, strlen(buf)); return 0; } // remove TCP transport // Disable the disconnect service to prevent complexity with Windows // // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { printf("the version service is disabled.\n"); return -1; } if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->serial) { out = transport->serial; } snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out); writex(reply_fd, buf, strlen(buf)); return 0; } if(!strncmp(service,"get-devpath",strlen("get-devpath"))) { char *out = "unknown"; transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); if (transport && transport->devpath) { out = transport->devpath; } snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out); writex(reply_fd, buf, strlen(buf)); return 0; } // indicates a new emulator instance has started if (!strncmp(service,"emulator:",9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } #endif // ADB_HOST if(!strcmp(service,"list-forward")) { // Create the list of forward redirections. char header[9]; int buffer_size = format_listeners(NULL, 0); // Add one byte for the trailing zero. char* buffer = (char*)malloc(buffer_size+1); (void) format_listeners(buffer, buffer_size+1); snprintf(header, sizeof header, "OKAY%04x", buffer_size); writex(reply_fd, header, 8); writex(reply_fd, buffer, buffer_size); free(buffer); return 0; } if (!strcmp(service,"killforward-all")) { remove_all_listeners(); adb_write(reply_fd, "OKAYOKAY", 8); return 0; } if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) { char *local, *remote, *err; int r; atransport *transport; int createForward = strncmp(service,"kill",4); int no_rebind = 0; local = strchr(service, ':') + 1; // Handle forward:norebind:<local>... here if (createForward && !strncmp(local, "norebind:", 9)) { no_rebind = 1; local = strchr(local, ':') + 1; } remote = strchr(local,';'); if (createForward) { // Check forward: parameter format: '<local>;<remote>' if(remote == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 0; } *remote++ = 0; if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){ sendfailmsg(reply_fd, "malformed forward spec"); return 0; } } else { // Check killforward: parameter format: '<local>' if (local[0] == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 0; } } transport = acquire_one_transport(CS_ANY, ttype, serial, &err); if (!transport) { sendfailmsg(reply_fd, err); return 0; } if (createForward) { r = install_listener(local, remote, transport, no_rebind); } else { r = remove_listener(local, transport); } if(r == 0) { /* 1st OKAY is connect, 2nd OKAY is status */ writex(reply_fd, "OKAYOKAY", 8); return 0; } if (createForward) { const char* message; switch (r) { case INSTALL_STATUS_CANNOT_BIND: message = "cannot bind to socket"; break; case INSTALL_STATUS_CANNOT_REBIND: message = "cannot rebind existing socket"; break; default: message = "internal error"; } sendfailmsg(reply_fd, message); } else { sendfailmsg(reply_fd, "cannot remove listener"); } return 0; } if(!strncmp(service,"get-state",strlen("get-state"))) { transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); char *state = connection_state_name(transport); snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state); writex(reply_fd, buf, strlen(buf)); return 0; } return -1; }
// Try to handle a network forwarding request. // This returns 1 on success, 0 on failure, and -1 to indicate this is not // a forwarding-related request. int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd) { if (!strcmp(service, "list-forward")) { // Create the list of forward redirections. int buffer_size = format_listeners(NULL, 0); // Add one byte for the trailing zero. char* buffer = malloc(buffer_size + 1); if (buffer == NULL) { sendfailmsg(reply_fd, "not enough memory"); return 1; } (void) format_listeners(buffer, buffer_size + 1); #if ADB_HOST send_msg_with_okay(reply_fd, buffer, buffer_size); #else send_msg_with_header(reply_fd, buffer, buffer_size); #endif free(buffer); return 1; } if (!strcmp(service, "killforward-all")) { remove_all_listeners(); #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ adb_write(reply_fd, "OKAY", 4); #endif adb_write(reply_fd, "OKAY", 4); return 1; } if (!strncmp(service, "forward:",8) || !strncmp(service, "killforward:",12)) { char *local, *remote, *err; int r; atransport *transport; int createForward = strncmp(service, "kill", 4); int no_rebind = 0; local = strchr(service, ':') + 1; // Handle forward:norebind:<local>... here if (createForward && !strncmp(local, "norebind:", 9)) { no_rebind = 1; local = strchr(local, ':') + 1; } remote = strchr(local,';'); if (createForward) { // Check forward: parameter format: '<local>;<remote>' if(remote == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 1; } *remote++ = 0; if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) { sendfailmsg(reply_fd, "malformed forward spec"); return 1; } } else { // Check killforward: parameter format: '<local>' if (local[0] == 0) { sendfailmsg(reply_fd, "malformed forward spec"); return 1; } } transport = acquire_one_transport(CS_ANY, ttype, serial, &err); if (!transport) { sendfailmsg(reply_fd, err); return 1; } if (createForward) { r = install_listener(local, remote, transport, no_rebind); } else { r = remove_listener(local, transport); } if(r == 0) { #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ writex(reply_fd, "OKAY", 4); #endif writex(reply_fd, "OKAY", 4); return 1; } if (createForward) { const char* message; switch (r) { case INSTALL_STATUS_CANNOT_BIND: message = "cannot bind to socket"; break; case INSTALL_STATUS_CANNOT_REBIND: message = "cannot rebind existing socket"; break; default: message = "internal error"; } sendfailmsg(reply_fd, message); } else { sendfailmsg(reply_fd, "cannot remove listener"); } return 1; } return 0; }
// Try to handle a network forwarding request. // This returns 1 on success, 0 on failure, and -1 to indicate this is not // a forwarding-related request. int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd) { if (!strcmp(service, "list-forward")) { // Create the list of forward redirections. std::string listeners = format_listeners(); #if ADB_HOST SendOkay(reply_fd); #endif return SendProtocolString(reply_fd, listeners); } if (!strcmp(service, "killforward-all")) { remove_all_listeners(); #if ADB_HOST /* On the host: 1st OKAY is connect, 2nd OKAY is status */ SendOkay(reply_fd); #endif SendOkay(reply_fd); return 1; } if (!strncmp(service, "forward:", 8) || !strncmp(service, "killforward:", 12)) { // killforward:local // forward:(norebind:)?local;remote bool kill_forward = false; bool no_rebind = false; if (android::base::StartsWith(service, "killforward:")) { kill_forward = true; service += 12; } else { service += 8; // skip past "forward:" if (android::base::StartsWith(service, "norebind:")) { no_rebind = true; service += 9; } } std::vector<std::string> pieces = android::base::Split(service, ";"); if (kill_forward) { // Check killforward: parameter format: '<local>' if (pieces.size() != 1 || pieces[0].empty()) { SendFail(reply_fd, android::base::StringPrintf("bad killforward: %s", service)); return 1; } } else { // Check forward: parameter format: '<local>;<remote>' if (pieces.size() != 2 || pieces[0].empty() || pieces[1].empty() || pieces[1][0] == '*') { SendFail(reply_fd, android::base::StringPrintf("bad forward: %s", service)); return 1; } } std::string error_msg; atransport* transport = acquire_one_transport(type, serial, nullptr, &error_msg); if (!transport) { SendFail(reply_fd, error_msg); return 1; } std::string error; InstallStatus r; int resolved_tcp_port = 0; if (kill_forward) { r = remove_listener(pieces[0].c_str(), transport); } else { r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind, &resolved_tcp_port, &error); } if (r == INSTALL_STATUS_OK) { #if ADB_HOST // On the host: 1st OKAY is connect, 2nd OKAY is status. SendOkay(reply_fd); #endif SendOkay(reply_fd); // If a TCP port was resolved, send the actual port number back. if (resolved_tcp_port != 0) { SendProtocolString(reply_fd, android::base::StringPrintf("%d", resolved_tcp_port)); } return 1; } std::string message; switch (r) { case INSTALL_STATUS_OK: message = "success (!)"; break; case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break; case INSTALL_STATUS_CANNOT_BIND: message = android::base::StringPrintf("cannot bind listener: %s", error.c_str()); break; case INSTALL_STATUS_CANNOT_REBIND: message = android::base::StringPrintf("cannot rebind existing socket"); break; case INSTALL_STATUS_LISTENER_NOT_FOUND: message = android::base::StringPrintf("listener '%s' not found", service); break; } SendFail(reply_fd, message); return 1; } return 0; }
int handle_host_request(const char* service, TransportType type, const char* serial, int reply_fd, asocket* s) { if (strcmp(service, "kill") == 0) { fprintf(stderr, "adb server killed by remote request\n"); fflush(stdout); SendOkay(reply_fd); // On Windows, if the process exits with open sockets that // shutdown(SD_SEND) has not been called on, TCP RST segments will be // sent to the peers which will cause their next recv() to error-out // with WSAECONNRESET. In the case of this code, that means the client // may not read the OKAY sent above. adb_shutdown(reply_fd); exit(0); } #if ADB_HOST // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { TransportType type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = service; } std::string error; atransport* t = acquire_one_transport(type, serial, nullptr, &error); if (t != nullptr) { s->transport = t; SendOkay(reply_fd); } else { SendFail(reply_fd, error); } return 1; } // return a list of all connected devices if (!strncmp(service, "devices", 7)) { bool long_listing = (strcmp(service+7, "-l") == 0); if (long_listing || service[7] == 0) { D("Getting device list..."); std::string device_list = list_transports(long_listing); D("Sending device list..."); return SendOkay(reply_fd, device_list); } return 1; } if (!strcmp(service, "features")) { std::string error; atransport* t = acquire_one_transport(type, serial, nullptr, &error); if (t != nullptr) { SendOkay(reply_fd, FeatureSetToString(t->features())); } else { SendFail(reply_fd, error); } return 0; } // remove TCP transport if (!strncmp(service, "disconnect:", 11)) { const std::string address(service + 11); if (address.empty()) { kick_all_tcp_devices(); return SendOkay(reply_fd, "disconnected everything"); } std::string serial; std::string host; int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; std::string error; if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) { return SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s", address.c_str(), error.c_str())); } atransport* t = find_transport(serial.c_str()); if (t == nullptr) { return SendFail(reply_fd, android::base::StringPrintf("no such device '%s'", serial.c_str())); } kick_transport(t); return SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str())); } // Returns our value for ADB_SERVER_VERSION. if (!strcmp(service, "version")) { return SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION)); } // These always report "unknown" rather than the actual error, for scripts. if (!strcmp(service, "get-serialno")) { std::string error; atransport* t = acquire_one_transport(type, serial, nullptr, &error); if (t) { return SendOkay(reply_fd, t->serial ? t->serial : "unknown"); } else { return SendFail(reply_fd, error); } } if (!strcmp(service, "get-devpath")) { std::string error; atransport* t = acquire_one_transport(type, serial, nullptr, &error); if (t) { return SendOkay(reply_fd, t->devpath ? t->devpath : "unknown"); } else { return SendFail(reply_fd, error); } } if (!strcmp(service, "get-state")) { std::string error; atransport* t = acquire_one_transport(type, serial, nullptr, &error); if (t) { return SendOkay(reply_fd, t->connection_state_name()); } else { return SendFail(reply_fd, error); } } // Indicates a new emulator instance has started. if (!strncmp(service, "emulator:", 9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } if (!strcmp(service, "reconnect")) { if (s->transport != nullptr) { kick_transport(s->transport); } return SendOkay(reply_fd, "done"); } #endif // ADB_HOST int ret = handle_forward_request(service, type, serial, reply_fd); if (ret >= 0) return ret - 1; return -1; }
int handle_host_request(const char* service, TransportType type, const char* serial, int reply_fd, asocket* s) { if (strcmp(service, "kill") == 0) { fprintf(stderr, "adb server killed by remote request\n"); fflush(stdout); SendOkay(reply_fd); exit(0); } #if ADB_HOST // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { TransportType type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = service; } std::string error_msg; atransport* t = acquire_one_transport(kCsAny, type, serial, &error_msg); if (t != nullptr) { s->transport = t; SendOkay(reply_fd); } else { SendFail(reply_fd, error_msg); } return 1; } // return a list of all connected devices if (!strncmp(service, "devices", 7)) { bool long_listing = (strcmp(service+7, "-l") == 0); if (long_listing || service[7] == 0) { D("Getting device list...\n"); std::string device_list = list_transports(long_listing); D("Sending device list...\n"); return SendOkay(reply_fd, device_list); } return 1; } // remove TCP transport if (!strncmp(service, "disconnect:", 11)) { const std::string address(service + 11); if (address.empty()) { // disconnect from all TCP devices unregister_all_tcp_transports(); return SendOkay(reply_fd, "disconnected everything"); } std::string serial; std::string host; int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; std::string error; if (!parse_host_and_port(address, &serial, &host, &port, &error)) { return SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s", address.c_str(), error.c_str())); } atransport* t = find_transport(serial.c_str()); if (t == nullptr) { return SendFail(reply_fd, android::base::StringPrintf("no such device '%s'", serial.c_str())); } unregister_transport(t); return SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str())); } // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { return SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION)); } // These always report "unknown" rather than the actual error, for scripts. if (!strcmp(service, "get-serialno")) { std::string ignored; atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored); return SendOkay(reply_fd, (t && t->serial) ? t->serial : "unknown"); } if (!strcmp(service, "get-devpath")) { std::string ignored; atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored); return SendOkay(reply_fd, (t && t->devpath) ? t->devpath : "unknown"); } if (!strcmp(service, "get-state")) { std::string ignored; atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored); return SendOkay(reply_fd, t ? t->connection_state_name() : "unknown"); } // indicates a new emulator instance has started if (!strncmp(service, "emulator:", 9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } #endif // ADB_HOST int ret = handle_forward_request(service, type, serial, reply_fd); if (ret >= 0) return ret - 1; return -1; }
int handle_host_request(const char* service, TransportType type, const char* serial, int reply_fd, asocket* s) { if (strcmp(service, "kill") == 0) { fprintf(stderr, "adb server killed by remote request\n"); fflush(stdout); SendOkay(reply_fd); // At least on Windows, if we exit() without shutdown(SD_SEND) or // closesocket(), the client's next recv() will error-out with // WSAECONNRESET and they'll never read the OKAY. adb_shutdown(reply_fd); exit(0); } #if ADB_HOST // "transport:" is used for switching transport with a specified serial number // "transport-usb:" is used for switching transport to the only USB transport // "transport-local:" is used for switching transport to the only local transport // "transport-any:" is used for switching transport to the only transport if (!strncmp(service, "transport", strlen("transport"))) { TransportType type = kTransportAny; if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { type = kTransportUsb; } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { type = kTransportLocal; } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { type = kTransportAny; } else if (!strncmp(service, "transport:", strlen("transport:"))) { service += strlen("transport:"); serial = service; } std::string error_msg; atransport* t = acquire_one_transport(kCsAny, type, serial, &error_msg); if (t != nullptr) { s->transport = t; SendOkay(reply_fd); } else { SendFail(reply_fd, error_msg); } return 1; } // return a list of all connected devices if (!strncmp(service, "devices", 7)) { bool long_listing = (strcmp(service+7, "-l") == 0); if (long_listing || service[7] == 0) { D("Getting device list..."); std::string device_list = list_transports(long_listing); D("Sending device list..."); return SendOkay(reply_fd, device_list); } return 1; } if (!strcmp(service, "features")) { std::string error_msg; atransport* t = acquire_one_transport(kCsAny, type, serial, &error_msg); if (t != nullptr) { SendOkay(reply_fd, android::base::Join(t->features(), '\n')); } else { SendFail(reply_fd, error_msg); } return 0; } if (!strncmp(service, "check-feature:", strlen("check-feature:"))) { std::string error_msg; atransport* t = acquire_one_transport(kCsAny, type, serial, &error_msg); if (t && t->CanUseFeature(service + strlen("check-feature:"))) { // We could potentially extend this to reply with the feature // version if that becomes necessary. SendOkay(reply_fd, "1"); } else { // Empty response means unsupported feature. SendOkay(reply_fd, ""); } return 0; } // remove TCP transport if (!strncmp(service, "disconnect:", 11)) { const std::string address(service + 11); if (address.empty()) { kick_all_tcp_devices(); return SendOkay(reply_fd, "disconnected everything"); } std::string serial; std::string host; int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; std::string error; if (!parse_host_and_port(address, &serial, &host, &port, &error)) { return SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s", address.c_str(), error.c_str())); } atransport* t = find_transport(serial.c_str()); if (t == nullptr) { return SendFail(reply_fd, android::base::StringPrintf("no such device '%s'", serial.c_str())); } kick_transport(t); return SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str())); } // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { return SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION)); } // These always report "unknown" rather than the actual error, for scripts. if (!strcmp(service, "get-serialno")) { std::string ignored; atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored); return SendOkay(reply_fd, (t && t->serial) ? t->serial : "unknown"); } if (!strcmp(service, "get-devpath")) { std::string ignored; atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored); return SendOkay(reply_fd, (t && t->devpath) ? t->devpath : "unknown"); } if (!strcmp(service, "get-state")) { std::string ignored; atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored); return SendOkay(reply_fd, t ? t->connection_state_name() : "unknown"); } // indicates a new emulator instance has started if (!strncmp(service, "emulator:", 9)) { int port = atoi(service+9); local_connect(port); /* we don't even need to send a reply */ return 0; } #endif // ADB_HOST int ret = handle_forward_request(service, type, serial, reply_fd); if (ret >= 0) return ret - 1; return -1; }