📄 transport.c
字号:
/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include "sysdeps.h"#define TRACE_TAG TRACE_TRANSPORT#include "adb.h"static void transport_unref(atransport *t);static atransport transport_list = { .next = &transport_list, .prev = &transport_list,};ADB_MUTEX_DEFINE( transport_lock );#if ADB_TRACEstatic void dump_hex( const unsigned char* ptr, size_t len ){ int nn, len2 = len; if (len2 > 16) len2 = 16; for (nn = 0; nn < len2; nn++) D("%02x", ptr[nn]); D(" "); for (nn = 0; nn < len2; nn++) { int c = ptr[nn]; if (c < 32 || c > 127) c = '.'; D("%c", c); } D("\n"); fflush(stdout);}#endifvoidkick_transport(atransport* t){ if (t && !t->kicked) { int kicked; adb_mutex_lock(&transport_lock); kicked = t->kicked; if (!kicked) t->kicked = 1; adb_mutex_unlock(&transport_lock); if (!kicked) t->kick(t); }}voidrun_transport_disconnects(atransport* t){ adisconnect* dis = t->disconnects.next; D("run_transport_disconnects: %p (%s)\n", t, t->serial ? t->serial : "unknown" ); while (dis != &t->disconnects) { adisconnect* next = dis->next; dis->func( dis->opaque, t ); dis = next; }}static intread_packet(int fd, apacket** ppacket){ char *p = (char*)ppacket; /* really read a packet address */ int r; int len = sizeof(*ppacket); while(len > 0) { r = adb_read(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("read_packet: %d error %d %d\n", fd, r, errno); if((r < 0) && (errno == EINTR)) continue; return -1; } }#if ADB_TRACE if (ADB_TRACING) { unsigned command = (*ppacket)->msg.command; int len = (*ppacket)->msg.data_length; char cmd[5]; int n; for (n = 0; n < 4; n++) { int b = (command >> (n*8)) & 255; if (b >= 32 && b < 127) cmd[n] = (char)b; else cmd[n] = '.'; } cmd[4] = 0; D("read_packet: %d ok: [%08x %s] %08x %08x (%d) ", fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len); dump_hex((*ppacket)->data, len); }#endif return 0;}static intwrite_packet(int fd, apacket** ppacket){ char *p = (char*) ppacket; /* we really write the packet address */ int r, len = sizeof(ppacket);#if ADB_TRACE if (ADB_TRACING) { unsigned command = (*ppacket)->msg.command; int len = (*ppacket)->msg.data_length; char cmd[5]; int n; for (n = 0; n < 4; n++) { int b = (command >> (n*8)) & 255; if (b >= 32 && b < 127) cmd[n] = (char)b; else cmd[n] = '.'; } cmd[4] = 0; D("write_packet: %d [%08x %s] %08x %08x (%d) ", fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len); dump_hex((*ppacket)->data, len); }#endif len = sizeof(ppacket); while(len > 0) { r = adb_write(fd, p, len); if(r > 0) { len -= r; p += r; } else { D("write_packet: %d error %d %d\n", fd, r, errno); if((r < 0) && (errno == EINTR)) continue; return -1; } } return 0;}static void transport_socket_events(int fd, unsigned events, void *_t){ if(events & FDE_READ){ apacket *p = 0; if(read_packet(fd, &p)){ D("failed to read packet from transport socket on fd %d\n", fd); } else { handle_packet(p, (atransport *) _t); } }}void send_packet(apacket *p, atransport *t){ unsigned char *x; unsigned sum; unsigned count; p->msg.magic = p->msg.command ^ 0xffffffff; count = p->msg.data_length; x = (unsigned char *) p->data; sum = 0; while(count-- > 0){ sum += *x++; } p->msg.data_check = sum; print_packet("send", p); if (t == NULL) { fatal_errno("Transport is null"); D("Transport is null \n"); } if(write_packet(t->transport_socket, &p)){ fatal_errno("cannot enqueue packet on transport socket"); }}/* The transport is opened by transport_register_func before** the input and output threads are started.**** The output thread issues a SYNC(1, token) message to let** the input thread know to start things up. In the event** of transport IO failure, the output thread will post a** SYNC(0,0) message to ensure shutdown.**** The transport will not actually be closed until both** threads exit, but the input thread will kick the transport** on its way out to disconnect the underlying device.*/static void *output_thread(void *_t){ atransport *t = _t; apacket *p; D("from_remote: starting thread for transport %p, on fd %d\n", t, t->fd ); D("from_remote: transport %p SYNC online (%d)\n", t, t->sync_token + 1); p = get_apacket(); p->msg.command = A_SYNC; p->msg.arg0 = 1; p->msg.arg1 = ++(t->sync_token); p->msg.magic = A_SYNC ^ 0xffffffff; if(write_packet(t->fd, &p)) { put_apacket(p); D("from_remote: failed to write SYNC apacket to transport %p", t); goto oops; } D("from_remote: data pump for transport %p\n", t); for(;;) { p = get_apacket(); if(t->read_from_remote(p, t) == 0){ D("from_remote: received remote packet, sending to transport %p\n", t); if(write_packet(t->fd, &p)){ put_apacket(p); D("from_remote: failed to write apacket to transport %p", t); goto oops; } } else { D("from_remote: remote read failed for transport %p\n", p); put_apacket(p); break; } } D("from_remote: SYNC offline for transport %p\n", t); p = get_apacket(); p->msg.command = A_SYNC; p->msg.arg0 = 0; p->msg.arg1 = 0; p->msg.magic = A_SYNC ^ 0xffffffff; if(write_packet(t->fd, &p)) { put_apacket(p); D("from_remote: failed to write SYNC apacket to transport %p", t); }oops: D("from_remote: thread is exiting for transport %p\n", t); kick_transport(t); transport_unref(t); return 0;}static void *input_thread(void *_t){ atransport *t = _t; apacket *p; int active = 0; D("to_remote: starting input_thread for %p, reading from fd %d\n", t, t->fd); for(;;){ if(read_packet(t->fd, &p)) { D("to_remote: failed to read apacket from transport %p on fd %d\n", t, t->fd ); break; } if(p->msg.command == A_SYNC){ if(p->msg.arg0 == 0) { D("to_remote: transport %p SYNC offline\n", t); put_apacket(p); break; } else { if(p->msg.arg1 == t->sync_token) { D("to_remote: transport %p SYNC online\n", t); active = 1; } else { D("to_remote: trandport %p ignoring SYNC %d != %d\n", t, p->msg.arg1, t->sync_token); } } } else { if(active) { D("to_remote: transport %p got packet, sending to remote\n", t); t->write_to_remote(p, t); } else { D("to_remote: transport %p ignoring packet while offline\n", t); } } put_apacket(p); } // this is necessary to avoid a race condition that occured when a transport closes // while a client socket is still active. close_all_sockets(t); D("to_remote: thread is exiting for transport %p, fd %d\n", t, t->fd); kick_transport(t); transport_unref(t); return 0;}static int transport_registration_send = -1;static int transport_registration_recv = -1;static fdevent transport_registration_fde;#if ADB_HOSTstatic int list_transports_msg(char* buffer, size_t bufferlen){ char head[5]; int len; len = list_transports(buffer+4, bufferlen-4); snprintf(head, sizeof(head), "%04x", len); memcpy(buffer, head, 4); len += 4; return len;}/* this adds support required by the 'track-devices' service. * this is used to send the content of "list_transport" to any * number of client connections that want it through a single * live TCP connection */typedef struct device_tracker device_tracker;struct device_tracker { asocket socket; int update_needed; device_tracker* next;};/* linked list of all device trackers */static device_tracker* device_tracker_list;static voiddevice_tracker_remove( device_tracker* tracker ){ device_tracker** pnode = &device_tracker_list; device_tracker* node = *pnode; adb_mutex_lock( &transport_lock ); while (node) { if (node == tracker) { *pnode = node->next; break; } pnode = &node->next; node = *pnode; } adb_mutex_unlock( &transport_lock );}static voiddevice_tracker_close( asocket* socket ){ device_tracker* tracker = (device_tracker*) socket; asocket* peer = socket->peer; D( "device tracker %p removed\n", tracker); if (peer) { peer->peer = NULL; peer->close(peer); } device_tracker_remove(tracker); free(tracker);}static intdevice_tracker_enqueue( asocket* socket, apacket* p ){ /* you can't read from a device tracker, close immediately */ put_apacket(p); device_tracker_close(socket); return -1;}static intdevice_tracker_send( device_tracker* tracker, const char* buffer, int len ){ apacket* p = get_apacket(); asocket* peer = tracker->socket.peer; memcpy(p->data, buffer, len); p->len = len; return peer->enqueue( peer, p );}static voiddevice_tracker_ready( asocket* socket ){ device_tracker* tracker = (device_tracker*) socket; /* we want to send the device list when the tracker connects * for the first time, even if no update occured */ if (tracker->update_needed > 0) { char buffer[1024]; int len; tracker->update_needed = 0; len = list_transports_msg(buffer, sizeof(buffer)); device_tracker_send(tracker, buffer, len); }}asocket*create_device_tracker(void){ device_tracker* tracker = calloc(1,sizeof(*tracker)); if(tracker == 0) fatal("cannot allocate device tracker"); D( "device tracker %p created\n", tracker); tracker->socket.enqueue = device_tracker_enqueue; tracker->socket.ready = device_tracker_ready; tracker->socket.close = device_tracker_close; tracker->update_needed = 1; tracker->next = device_tracker_list; device_tracker_list = tracker; return &tracker->socket;}/* call this function each time the transport list has changed */void update_transports(void){ char buffer[1024]; int len; device_tracker* tracker; len = list_transports_msg(buffer, sizeof(buffer)); tracker = device_tracker_list; while (tracker != NULL) { device_tracker* next = tracker->next; /* note: this may destroy the tracker if the connection is closed */ device_tracker_send(tracker, buffer, len); tracker = next;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -