static void *output_thread(void *_t)
{
    atransport *t = reinterpret_cast<atransport*>(_t);
    apacket *p;

    ADB_LOGD(ADB_TSPT,
             "%s: starting transport output thread on fd %d, SYNC online (%d)",
             t->serial, t->fd, 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, t->serial, &p)) {
        put_apacket(p);
        ADB_LOGE(ADB_TSPT, "%s: failed to write SYNC packet", t->serial);
        goto oops;
    }

    ADB_LOGD(ADB_TSPT, "%s: data pump started", t->serial);
    for (;;) {
        p = get_apacket();

        if (t->read_from_remote(p, t) == 0) {
            ADB_LOGD(ADB_TSPT,
                     "%s: received remote packet, sending to transport",
                     t->serial);
            if (write_packet(t->fd, t->serial, &p)) {
                put_apacket(p);
                ADB_LOGE(ADB_TSPT,
                         "%s: failed to write apacket to transport", t->serial);
                goto oops;
            }
        } else {
            ADB_LOGE(ADB_TSPT,
                     "%s: remote read failed for transport", t->serial);
            put_apacket(p);
            break;
        }
    }

    ADB_LOGD(ADB_TSPT, "%s: SYNC offline for transport", t->serial);
    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, t->serial, &p)) {
        put_apacket(p);
        ADB_LOGW(ADB_TSPT,
                 "%s: failed to write SYNC apacket to transport", t->serial);
    }

oops:
    ADB_LOGD(ADB_TSPT, "%s: transport output thread is exiting", t->serial);
    kick_transport(t);
    transport_unref(t);
    return 0;
}
static void dump_packet(const char* name, const char* func, apacket* p) {
    unsigned  command = p->msg.command;
    int       len     = p->msg.data_length;
    char      cmd[9];
    char      arg0[12], arg1[12];
    int       n;

    for (n = 0; n < 4; n++) {
        int  b = (command >> (n*8)) & 255;
        if (b < 32 || b >= 127)
            break;
        cmd[n] = (char)b;
    }
    if (n == 4) {
        cmd[4] = 0;
    } else {
        /* There is some non-ASCII name in the command, so dump
            * the hexadecimal value instead */
        snprintf(cmd, sizeof cmd, "%08x", command);
    }

    if (p->msg.arg0 < 256U)
        snprintf(arg0, sizeof arg0, "%d", p->msg.arg0);
    else
        snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0);

    if (p->msg.arg1 < 256U)
        snprintf(arg1, sizeof arg1, "%d", p->msg.arg1);
    else
        snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);

    ADB_LOGD(ADB_TSPT, "%s: %s: [%s] arg0=%s arg1=%s (len=%d) ",
             name, func, cmd, arg0, arg1, len);
    dump_hex(p->data, len);
}
static void transport_unref_locked(atransport *t)
{
    t->ref_count--;
    if (t->ref_count == 0) {
        ADB_LOGD(ADB_TSPT, "transport: %s unref (kicking and closing)",
                 t->serial);
        if (!t->kicked) {
            t->kicked = 1;
            t->kick(t);
        }
        t->close(t);
        remove_transport(t);
    } else {
        ADB_LOGD(ADB_TSPT, "transport: %s unref (count=%d)",
                 t->serial, t->ref_count);
    }
}
Exemple #4
0
static void dump_fde(fdevent *fde, const char *info)
{
    pthread_mutex_lock(&D_lock);
    ADB_LOGD(ADB_FDEV, "FDE #%03d %c%c%c %s\n", fde->fd,
            fde->state & FDE_READ ? 'R' : ' ',
            fde->state & FDE_WRITE ? 'W' : ' ',
            fde->state & FDE_ERROR ? 'E' : ' ',
            info);
    pthread_mutex_unlock(&D_lock);
}
static void remove_transport(atransport *transport)
{
    tmsg m;
    m.transport = transport;
    m.action = 0;
    ADB_LOGD(ADB_TSPT, "transport: %s removed", transport->serial);
    if (transport_write_action(transport_registration_send, &m)) {
        fatal_errno("cannot write transport registration socket");
    }
}
// Each atransport contains a list of adisconnects (t->disconnects).
// An adisconnect contains a link to the next/prev adisconnect, a function
// pointer to a disconnect callback which takes a void* piece of user data and
// the atransport, and some user data for the callback (helpfully named
// "opaque").
//
// The list is circular. New items are added to the entry member of the list
// (t->disconnects) by add_transport_disconnect.
//
// run_transport_disconnects invokes each function in the list.
//
// Gotchas:
//   * run_transport_disconnects assumes that t->disconnects is non-null, so
//     this can't be run on a zeroed atransport.
//   * The callbacks in this list are not removed when called, and this function
//     is not guarded against running more than once. As such, ensure that this
//     function is not called multiple times on the same atransport.
//     TODO(danalbert): Just fix this so that it is guarded once you have tests.
void run_transport_disconnects(atransport* t)
{
    adisconnect* dis = t->disconnects.next;

    ADB_LOGD(ADB_TSPT, "%s: run_transport_disconnects", t->serial);
    while (dis != &t->disconnects) {
        adisconnect* next = dis->next;
        dis->func(dis->opaque, t);
        dis = next;
    }
}
Exemple #7
0
static void fdevent_subproc_event_func(int fd, unsigned ev,
                                       void* /* userdata */)
{

    ADB_LOGD(ADB_FDEV, "subproc handling on fd=%d ev=%04x", fd, ev);

    // Hook oneself back into the fde's suitable for select() on read.
    if ((fd < 0) || (fd >= fd_table_max)) {
        FATAL("fd %d out of range for fd_table", fd);
    }
    fdevent *fde = fd_table[fd];
    fdevent_add(fde, FDE_READ);

    if (ev & FDE_READ) {
        int subproc_fd;

        if (!ReadFdExactly(fd, &subproc_fd, sizeof(subproc_fd))) {
            FATAL("Failed to read the subproc's fd from fd=%d", fd);
        }
        if ((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
            ADB_LOGD(ADB_FDEV, "subproc_fd %d out of range 0, fd_table_max=%d",
                     subproc_fd, fd_table_max);
            return;
        }
        fdevent *subproc_fde = fd_table[subproc_fd];
        if (!subproc_fde) {
            ADB_LOGD(ADB_FDEV, "subproc_fd %d cleared from fd_table",
                     subproc_fd);
            return;
        }
        if (subproc_fde->fd != subproc_fd) {
            // Already reallocated?
            ADB_LOGD(ADB_FDEV, "subproc_fd %d != fd_table[].fd %d",
                     subproc_fd, subproc_fde->fd);
            return;
        }

        subproc_fde->force_eof = 1;

        int rcount = 0;
        ioctl(subproc_fd, FIONREAD, &rcount);
        ADB_LOGD(ADB_FDEV, "subproc with fd=%d  has rcount=%d err=%d",
                 subproc_fd, rcount, errno);

        if (rcount) {
            // If there is data left, it will show up in the select().
            // This works because there is no other thread reading that
            // data when in this fd_func().
            return;
        }

        ADB_LOGD(ADB_FDEV, "subproc_fde.state=%04x", subproc_fde->state);
        subproc_fde->events |= FDE_READ;
        if (subproc_fde->state & FDE_PENDING) {
            return;
        }
        subproc_fde->state |= FDE_PENDING;
        fdevent_call_fdfunc(subproc_fde);
    }
}
static void *input_thread(void *_t)
{
    atransport *t = reinterpret_cast<atransport*>(_t);
    apacket *p;
    int active = 0;

    ADB_LOGD(ADB_TSPT,
             "%s: starting transport input thread, reading from fd %d",
             t->serial, t->fd);

    for (;;) {
        if (read_packet(t->fd, t->serial, &p)) {
            ADB_LOGE(ADB_TSPT,
                     "%s: failed to read apacket from transport on fd %d",
                     t->serial, t->fd);
            break;
        }
        if (p->msg.command == A_SYNC) {
            if (p->msg.arg0 == 0) {
                ADB_LOGE(ADB_TSPT, "%s: transport SYNC offline", t->serial);
                put_apacket(p);
                break;
            } else {
                if (p->msg.arg1 == t->sync_token) {
                    ADB_LOGD(ADB_TSPT, "%s: transport SYNC online", t->serial);
                    active = 1;
                } else {
                    ADB_LOGD(ADB_TSPT, "%s: transport ignoring SYNC %d != %d",
                             t->serial, p->msg.arg1, t->sync_token);
                }
            }
        } else {
            if (active) {
                ADB_LOGD(ADB_TSPT,
                         "%s: transport got packet, sending to remote",
                         t->serial);
                t->write_to_remote(p, t);
            } else {
                ADB_LOGD(ADB_TSPT,
                         "%s: transport ignoring packet while offline",
                         t->serial);
            }
        }

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

    ADB_LOGD(ADB_TSPT, "%s: transport input thread is exiting, fd %d",
             t->serial, t->fd);
    kick_transport(t);
    transport_unref(t);
    return 0;
}
Exemple #9
0
void fdevent_loop()
{
    fdevent *fde;
    fdevent_subproc_setup();

    for (;;) {
        ADB_LOGD(ADB_FDEV, "--- ---- waiting for events");

        fdevent_process();

        while ((fde = fdevent_plist_dequeue())) {
            fdevent_call_fdfunc(fde);
        }
    }
}
static void transport_socket_events(int fd, unsigned events, void *_t)
{
    atransport *t = reinterpret_cast<atransport*>(_t);
    ADB_LOGD(ADB_TSPT, "transport_socket_events(fd=%d, events=%04x,...)",
             fd, events);
    if (events & FDE_READ) {
        apacket *p = 0;
        if (read_packet(fd, t->serial, &p)) {
            ADB_LOGE(ADB_TSPT,
                     "%s: failed to read packet from transport socket on fd %d",
                     t->serial, fd);
        } else {
            handle_packet(p, (atransport *) _t);
        }
    }
}
Exemple #11
0
void fdevent_subproc_setup()
{
    int s[2];

    if (adb_socketpair(s)) {
        FATAL("cannot create shell-exit socket-pair");
    }
    ADB_LOGD(ADB_FDEV, "socketpair: (%d,%d)", s[0], s[1]);

    SHELL_EXIT_NOTIFY_FD = s[0];
    fdevent *fde;
    fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
    if (!fde) {
        FATAL("cannot create fdevent for shell-exit handler");
    }
    fdevent_add(fde, FDE_READ);
}
void init_transport_registration(void)
{
    int s[2];

    if (adb_socketpair(s)) {
        fatal_errno("cannot open transport registration socketpair");
    }
    ADB_LOGD(ADB_TSPT, "socketpair: (%d,%d)", s[0], s[1]);

    transport_registration_send = s[0];
    transport_registration_recv = s[1];

    fdevent_install(&transport_registration_fde,
                    transport_registration_recv,
                    transport_registration_func,
                    0);

    fdevent_set(&transport_registration_fde, FDE_READ);
}
void dump_hex(const void* data, size_t byte_count) {
    byte_count = std::min(byte_count, size_t(16));

    const uint8_t* p = reinterpret_cast<const uint8_t*>(data);

    std::string line;
    for (size_t i = 0; i < byte_count; ++i) {
        line += mb::util::format("%02x", p[i]);
    }
    line.push_back(' ');

    for (size_t i = 0; i < byte_count; ++i) {
        int c = p[i];
        if (c < 32 || c > 127) {
            c = '.';
        }
        line.push_back(c);
    }

    ADB_LOGD(ADB_LLIO, "%s", line.c_str());
}
void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
{
    atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
    if (t == nullptr) fatal("cannot allocate USB atransport");
    ADB_LOGD(ADB_TSPT, "transport: %p init'ing for usb_handle %p (sn='%s')",
             t, usb, serial ? serial : "");
    init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
    if (serial) {
        t->serial = strdup(serial);
    }
    if (devpath) {
        t->devpath = strdup(devpath);
    }

    pthread_mutex_lock(&transport_lock);
    t->next = &pending_list;
    t->prev = pending_list.prev;
    t->next->prev = t;
    t->prev->next = t;
    pthread_mutex_unlock(&transport_lock);

    register_transport(t);
}
Exemple #15
0
static void dump_all_fds(const char *extra_msg)
{
int i;
    fdevent *fde;
    // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
    char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
    size_t max_chars = FD_SETSIZE * 6 + 1;
    int printed_out;
#define SAFE_SPRINTF(...)                                                    \
    do {                                                                     \
        printed_out = snprintf(pb, max_chars, __VA_ARGS__);                  \
        if (printed_out <= 0) {                                              \
            ADB_LOGE(ADB_FDEV, "... snprintf failed.");                      \
            return;                                                          \
        }                                                                    \
        if (max_chars < (unsigned int)printed_out) {                         \
            ADB_LOGE(ADB_FDEV, "... snprintf out of space.");                \
            return;                                                          \
        }                                                                    \
        pb += printed_out;                                                   \
        max_chars -= printed_out;                                            \
    } while (0)

    for (i = 0; i < select_n; i++) {
        fde = fd_table[i];
        SAFE_SPRINTF("%d", i);
        if (fde == 0) {
            SAFE_SPRINTF("? ");
            continue;
        }
        if (fcntl(i, F_GETFL, NULL) < 0) {
            SAFE_SPRINTF("b");
        }
        SAFE_SPRINTF(" ");
    }
    ADB_LOGD(ADB_FDEV, "%s fd_table[]->fd = {%s}", extra_msg, msg_buff);
}
static void transport_registration_func(int _fd, unsigned ev, void *data)
{
    tmsg m;
    pthread_t output_thread_ptr;
    pthread_t input_thread_ptr;
    int s[2];
    atransport *t;

    if (!(ev & FDE_READ)) {
        return;
    }

    if (transport_read_action(_fd, &m)) {
        fatal_errno("cannot read transport registration socket");
    }

    t = m.transport;

    if (m.action == 0) {
        ADB_LOGD(ADB_TSPT, "transport: %s removing and free'ing %d",
                 t->serial, t->transport_socket);

            /* IMPORTANT: the remove closes one half of the
            ** socket pair.  The close closes the other half.
            */
        fdevent_remove(&(t->transport_fde));
        close(t->fd);

        pthread_mutex_lock(&transport_lock);
        t->next->prev = t->prev;
        t->prev->next = t->next;
        pthread_mutex_unlock(&transport_lock);

        run_transport_disconnects(t);

        if (t->product)
            free(t->product);
        if (t->serial)
            free(t->serial);
        if (t->model)
            free(t->model);
        if (t->device)
            free(t->device);
        if (t->devpath)
            free(t->devpath);

        memset(t,0xee,sizeof(atransport));
        free(t);

        update_transports();
        return;
    }

    /* don't create transport threads for inaccessible devices */
    if (t->connection_state != CS_NOPERM) {
        /* initial references are the two threads */
        t->ref_count = 2;

        if (adb_socketpair(s)) {
            fatal_errno("cannot open transport socketpair");
        }

        ADB_LOGD(ADB_TSPT, "transport: %s socketpair: (%d,%d) starting",
                 t->serial, s[0], s[1]);

        t->transport_socket = s[0];
        t->fd = s[1];

        fdevent_install(&(t->transport_fde),
                        t->transport_socket,
                        transport_socket_events,
                        t);

        fdevent_set(&(t->transport_fde), FDE_READ);

        if (adb_thread_create(&input_thread_ptr, input_thread, t)) {
            fatal_errno("cannot create input thread");
        }

        if (adb_thread_create(&output_thread_ptr, output_thread, t)) {
            fatal_errno("cannot create output thread");
        }
    }

    pthread_mutex_lock(&transport_lock);
    /* remove from pending list */
    t->next->prev = t->prev;
    t->prev->next = t->next;
    /* put us on the master device list */
    t->next = &transport_list;
    t->prev = transport_list.prev;
    t->next->prev = t;
    t->prev->next = t;
    pthread_mutex_unlock(&transport_lock);

    t->disconnects.next = t->disconnects.prev = &t->disconnects;

    update_transports();
}
Exemple #17
0
static void fdevent_process()
{
    int i, n;
    fdevent *fde;
    unsigned events;
    fd_set rfd, wfd, efd;

    memcpy(&rfd, &read_fds, sizeof(fd_set));
    memcpy(&wfd, &write_fds, sizeof(fd_set));
    memcpy(&efd, &error_fds, sizeof(fd_set));

    dump_all_fds("pre select()");

    n = select(select_n, &rfd, &wfd, &efd, NULL);
    int saved_errno = errno;
    ADB_LOGD(ADB_FDEV, "select() returned n=%d, errno=%d",
             n, n < 0 ? saved_errno : 0);

    dump_all_fds("post select()");

    if (n < 0) {
        switch (saved_errno) {
        case EINTR: return;
        case EBADF:
            // Can't trust the FD sets after an error.
            FD_ZERO(&wfd);
            FD_ZERO(&efd);
            FD_ZERO(&rfd);
            break;
        default:
            ADB_LOGW(ADB_FDEV, "Unexpected select() error=%d", saved_errno);
            return;
        }
    }
    if (n <= 0) {
        // We fake a read, as the rest of the code assumes
        // that errors will be detected at that point.
        n = fdevent_fd_check(&rfd);
    }

    for (i = 0; (i < select_n) && (n > 0); i++) {
        events = 0;
        if (FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
        if (FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
        if (FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }

        if (events) {
            fde = fd_table[i];
            if (fde == 0) {
                FATAL("missing fde for fd %d", i);
            }

            fde->events |= events;

            ADB_LOGD(ADB_FDEV, "got events fde->fd=%d events=%04x, state=%04x",
                     fde->fd, fde->events, fde->state);
            if (fde->state & FDE_PENDING) continue;
            fde->state |= FDE_PENDING;
            fdevent_plist_enqueue(fde);
        }
    }
}