transport.c revision 8cf0d59f61ae0b8554ecf3fe051850508b761b79
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <string.h>
21#include <errno.h>
22
23#include "sysdeps.h"
24
25#define   TRACE_TAG  TRACE_TRANSPORT
26#include "adb.h"
27
28static void transport_unref(atransport *t);
29
30static atransport transport_list = {
31    .next = &transport_list,
32    .prev = &transport_list,
33};
34
35ADB_MUTEX_DEFINE( transport_lock );
36
37#if ADB_TRACE
38static void  dump_hex( const unsigned char*  ptr, size_t  len )
39{
40    int  nn, len2 = len;
41
42    if (len2 > 16) len2 = 16;
43
44    for (nn = 0; nn < len2; nn++)
45        D("%02x", ptr[nn]);
46    D("  ");
47
48    for (nn = 0; nn < len2; nn++) {
49        int  c = ptr[nn];
50        if (c < 32 || c > 127)
51            c = '.';
52        D("%c", c);
53    }
54    D("\n");
55    fflush(stdout);
56}
57#endif
58
59void
60kick_transport(atransport*  t)
61{
62    if (t && !t->kicked)
63    {
64        int  kicked;
65
66        adb_mutex_lock(&transport_lock);
67        kicked = t->kicked;
68        if (!kicked)
69            t->kicked = 1;
70        adb_mutex_unlock(&transport_lock);
71
72        if (!kicked)
73            t->kick(t);
74    }
75}
76
77void
78run_transport_disconnects(atransport*  t)
79{
80    adisconnect*  dis = t->disconnects.next;
81
82    D("run_transport_disconnects: %p (%s)\n", t, t->serial ? t->serial : "unknown" );
83    while (dis != &t->disconnects) {
84        adisconnect*  next = dis->next;
85        dis->func( dis->opaque, t );
86        dis = next;
87    }
88}
89
90static int
91read_packet(int  fd, apacket** ppacket)
92{
93    char *p = (char*)ppacket;  /* really read a packet address */
94    int   r;
95    int   len = sizeof(*ppacket);
96    while(len > 0) {
97        r = adb_read(fd, p, len);
98        if(r > 0) {
99            len -= r;
100            p   += r;
101        } else {
102            D("read_packet: %d error %d %d\n", fd, r, errno);
103            if((r < 0) && (errno == EINTR)) continue;
104            return -1;
105        }
106    }
107
108#if ADB_TRACE
109    if (ADB_TRACING)
110    {
111        unsigned  command = (*ppacket)->msg.command;
112        int       len     = (*ppacket)->msg.data_length;
113        char      cmd[5];
114        int       n;
115
116        for (n = 0; n < 4; n++) {
117            int  b = (command >> (n*8)) & 255;
118            if (b >= 32 && b < 127)
119                cmd[n] = (char)b;
120            else
121                cmd[n] = '.';
122        }
123        cmd[4] = 0;
124
125        D("read_packet: %d ok: [%08x %s] %08x %08x (%d) ",
126          fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len);
127        dump_hex((*ppacket)->data, len);
128    }
129#endif
130    return 0;
131}
132
133static int
134write_packet(int  fd, apacket** ppacket)
135{
136    char *p = (char*) ppacket;  /* we really write the packet address */
137    int r, len = sizeof(ppacket);
138
139#if ADB_TRACE
140    if (ADB_TRACING)
141    {
142        unsigned  command = (*ppacket)->msg.command;
143        int       len     = (*ppacket)->msg.data_length;
144        char      cmd[5];
145        int       n;
146
147        for (n = 0; n < 4; n++) {
148            int  b = (command >> (n*8)) & 255;
149            if (b >= 32 && b < 127)
150                cmd[n] = (char)b;
151            else
152                cmd[n] = '.';
153        }
154        cmd[4] = 0;
155
156        D("write_packet: %d [%08x %s] %08x %08x (%d) ",
157          fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len);
158        dump_hex((*ppacket)->data, len);
159    }
160#endif
161    len = sizeof(ppacket);
162    while(len > 0) {
163        r = adb_write(fd, p, len);
164        if(r > 0) {
165            len -= r;
166            p += r;
167        } else {
168            D("write_packet: %d error %d %d\n", fd, r, errno);
169            if((r < 0) && (errno == EINTR)) continue;
170            return -1;
171        }
172    }
173    return 0;
174}
175
176static void transport_socket_events(int fd, unsigned events, void *_t)
177{
178    if(events & FDE_READ){
179        apacket *p = 0;
180        if(read_packet(fd, &p)){
181            D("failed to read packet from transport socket on fd %d\n", fd);
182        } else {
183            handle_packet(p, (atransport *) _t);
184        }
185    }
186}
187
188void send_packet(apacket *p, atransport *t)
189{
190    unsigned char *x;
191    unsigned sum;
192    unsigned count;
193
194    p->msg.magic = p->msg.command ^ 0xffffffff;
195
196    count = p->msg.data_length;
197    x = (unsigned char *) p->data;
198    sum = 0;
199    while(count-- > 0){
200        sum += *x++;
201    }
202    p->msg.data_check = sum;
203
204    print_packet("send", p);
205
206    if (t == NULL) {
207        fatal_errno("Transport is null");
208        D("Transport is null \n");
209    }
210
211    if(write_packet(t->transport_socket, &p)){
212        fatal_errno("cannot enqueue packet on transport socket");
213    }
214}
215
216/* The transport is opened by transport_register_func before
217** the input and output threads are started.
218**
219** The output thread issues a SYNC(1, token) message to let
220** the input thread know to start things up.  In the event
221** of transport IO failure, the output thread will post a
222** SYNC(0,0) message to ensure shutdown.
223**
224** The transport will not actually be closed until both
225** threads exit, but the input thread will kick the transport
226** on its way out to disconnect the underlying device.
227*/
228
229static void *output_thread(void *_t)
230{
231    atransport *t = _t;
232    apacket *p;
233
234    D("from_remote: starting thread for transport %p, on fd %d\n", t, t->fd );
235
236    D("from_remote: transport %p SYNC online (%d)\n", t, t->sync_token + 1);
237    p = get_apacket();
238    p->msg.command = A_SYNC;
239    p->msg.arg0 = 1;
240    p->msg.arg1 = ++(t->sync_token);
241    p->msg.magic = A_SYNC ^ 0xffffffff;
242    if(write_packet(t->fd, &p)) {
243        put_apacket(p);
244        D("from_remote: failed to write SYNC apacket to transport %p", t);
245        goto oops;
246    }
247
248    D("from_remote: data pump  for transport %p\n", t);
249    for(;;) {
250        p = get_apacket();
251
252        if(t->read_from_remote(p, t) == 0){
253            D("from_remote: received remote packet, sending to transport %p\n",
254              t);
255            if(write_packet(t->fd, &p)){
256                put_apacket(p);
257                D("from_remote: failed to write apacket to transport %p", t);
258                goto oops;
259            }
260        } else {
261            D("from_remote: remote read failed for transport %p\n", p);
262            put_apacket(p);
263            break;
264        }
265    }
266
267    D("from_remote: SYNC offline for transport %p\n", t);
268    p = get_apacket();
269    p->msg.command = A_SYNC;
270    p->msg.arg0 = 0;
271    p->msg.arg1 = 0;
272    p->msg.magic = A_SYNC ^ 0xffffffff;
273    if(write_packet(t->fd, &p)) {
274        put_apacket(p);
275        D("from_remote: failed to write SYNC apacket to transport %p", t);
276    }
277
278oops:
279    D("from_remote: thread is exiting for transport %p\n", t);
280    kick_transport(t);
281    transport_unref(t);
282    return 0;
283}
284
285static void *input_thread(void *_t)
286{
287    atransport *t = _t;
288    apacket *p;
289    int active = 0;
290
291    D("to_remote: starting input_thread for %p, reading from fd %d\n",
292       t, t->fd);
293
294    for(;;){
295        if(read_packet(t->fd, &p)) {
296            D("to_remote: failed to read apacket from transport %p on fd %d\n",
297               t, t->fd );
298            break;
299        }
300        if(p->msg.command == A_SYNC){
301            if(p->msg.arg0 == 0) {
302                D("to_remote: transport %p SYNC offline\n", t);
303                put_apacket(p);
304                break;
305            } else {
306                if(p->msg.arg1 == t->sync_token) {
307                    D("to_remote: transport %p SYNC online\n", t);
308                    active = 1;
309                } else {
310                    D("to_remote: trandport %p ignoring SYNC %d != %d\n",
311                      t, p->msg.arg1, t->sync_token);
312                }
313            }
314        } else {
315            if(active) {
316                D("to_remote: transport %p got packet, sending to remote\n", t);
317                t->write_to_remote(p, t);
318            } else {
319                D("to_remote: transport %p ignoring packet while offline\n", t);
320            }
321        }
322
323        put_apacket(p);
324    }
325
326    // this is necessary to avoid a race condition that occured when a transport closes
327    // while a client socket is still active.
328    close_all_sockets(t);
329
330    D("to_remote: thread is exiting for transport %p, fd %d\n", t, t->fd);
331    kick_transport(t);
332    transport_unref(t);
333    return 0;
334}
335
336
337static int transport_registration_send = -1;
338static int transport_registration_recv = -1;
339static fdevent transport_registration_fde;
340
341
342#if ADB_HOST
343static int list_transports_msg(char*  buffer, size_t  bufferlen)
344{
345    char  head[5];
346    int   len;
347
348    len = list_transports(buffer+4, bufferlen-4);
349    snprintf(head, sizeof(head), "%04x", len);
350    memcpy(buffer, head, 4);
351    len += 4;
352    return len;
353}
354
355/* this adds support required by the 'track-devices' service.
356 * this is used to send the content of "list_transport" to any
357 * number of client connections that want it through a single
358 * live TCP connection
359 */
360typedef struct device_tracker  device_tracker;
361struct device_tracker {
362    asocket          socket;
363    int              update_needed;
364    device_tracker*  next;
365};
366
367/* linked list of all device trackers */
368static device_tracker*   device_tracker_list;
369
370static void
371device_tracker_remove( device_tracker*  tracker )
372{
373    device_tracker**  pnode = &device_tracker_list;
374    device_tracker*   node  = *pnode;
375
376    adb_mutex_lock( &transport_lock );
377    while (node) {
378        if (node == tracker) {
379            *pnode = node->next;
380            break;
381        }
382        pnode = &node->next;
383        node  = *pnode;
384    }
385    adb_mutex_unlock( &transport_lock );
386}
387
388static void
389device_tracker_close( asocket*  socket )
390{
391    device_tracker*  tracker = (device_tracker*) socket;
392    asocket*         peer    = socket->peer;
393
394    D( "device tracker %p removed\n", tracker);
395    if (peer) {
396        peer->peer = NULL;
397        peer->close(peer);
398    }
399    device_tracker_remove(tracker);
400    free(tracker);
401}
402
403static int
404device_tracker_enqueue( asocket*  socket, apacket*  p )
405{
406    /* you can't read from a device tracker, close immediately */
407    put_apacket(p);
408    device_tracker_close(socket);
409    return -1;
410}
411
412static int
413device_tracker_send( device_tracker*  tracker,
414                     const char*      buffer,
415                     int              len )
416{
417    apacket*  p = get_apacket();
418    asocket*  peer = tracker->socket.peer;
419
420    memcpy(p->data, buffer, len);
421    p->len = len;
422    return peer->enqueue( peer, p );
423}
424
425
426static void
427device_tracker_ready( asocket*  socket )
428{
429    device_tracker*  tracker = (device_tracker*) socket;
430
431    /* we want to send the device list when the tracker connects
432    * for the first time, even if no update occured */
433    if (tracker->update_needed > 0) {
434        char  buffer[1024];
435        int   len;
436
437        tracker->update_needed = 0;
438
439        len = list_transports_msg(buffer, sizeof(buffer));
440        device_tracker_send(tracker, buffer, len);
441    }
442}
443
444
445asocket*
446create_device_tracker(void)
447{
448    device_tracker*  tracker = calloc(1,sizeof(*tracker));
449
450    if(tracker == 0) fatal("cannot allocate device tracker");
451
452    D( "device tracker %p created\n", tracker);
453
454    tracker->socket.enqueue = device_tracker_enqueue;
455    tracker->socket.ready   = device_tracker_ready;
456    tracker->socket.close   = device_tracker_close;
457    tracker->update_needed  = 1;
458
459    tracker->next       = device_tracker_list;
460    device_tracker_list = tracker;
461
462    return &tracker->socket;
463}
464
465
466/* call this function each time the transport list has changed */
467void  update_transports(void)
468{
469    char             buffer[1024];
470    int              len;
471    device_tracker*  tracker;
472
473    len = list_transports_msg(buffer, sizeof(buffer));
474
475    tracker = device_tracker_list;
476    while (tracker != NULL) {
477        device_tracker*  next = tracker->next;
478        /* note: this may destroy the tracker if the connection is closed */
479        device_tracker_send(tracker, buffer, len);
480        tracker = next;
481    }
482}
483#else
484void  update_transports(void)
485{
486    // nothing to do on the device side
487}
488#endif // ADB_HOST
489
490typedef struct tmsg tmsg;
491struct tmsg
492{
493    atransport *transport;
494    int         action;
495};
496
497static int
498transport_read_action(int  fd, struct tmsg*  m)
499{
500    char *p   = (char*)m;
501    int   len = sizeof(*m);
502    int   r;
503
504    while(len > 0) {
505        r = adb_read(fd, p, len);
506        if(r > 0) {
507            len -= r;
508            p   += r;
509        } else {
510            if((r < 0) && (errno == EINTR)) continue;
511            D("transport_read_action: on fd %d, error %d: %s\n",
512              fd, errno, strerror(errno));
513            return -1;
514        }
515    }
516    return 0;
517}
518
519static int
520transport_write_action(int  fd, struct tmsg*  m)
521{
522    char *p   = (char*)m;
523    int   len = sizeof(*m);
524    int   r;
525
526    while(len > 0) {
527        r = adb_write(fd, p, len);
528        if(r > 0) {
529            len -= r;
530            p   += r;
531        } else {
532            if((r < 0) && (errno == EINTR)) continue;
533            D("transport_write_action: on fd %d, error %d: %s\n",
534              fd, errno, strerror(errno));
535            return -1;
536        }
537    }
538    return 0;
539}
540
541static void transport_registration_func(int _fd, unsigned ev, void *data)
542{
543    tmsg m;
544    adb_thread_t output_thread_ptr;
545    adb_thread_t input_thread_ptr;
546    int s[2];
547    atransport *t;
548
549    if(!(ev & FDE_READ)) {
550        return;
551    }
552
553    if(transport_read_action(_fd, &m)) {
554        fatal_errno("cannot read transport registration socket");
555    }
556
557    t = m.transport;
558
559    if(m.action == 0){
560        D("transport: %p removing and free'ing %d\n", t, t->transport_socket);
561
562            /* IMPORTANT: the remove closes one half of the
563            ** socket pair.  The close closes the other half.
564            */
565        fdevent_remove(&(t->transport_fde));
566        adb_close(t->fd);
567
568        adb_mutex_lock(&transport_lock);
569        t->next->prev = t->prev;
570        t->prev->next = t->next;
571        adb_mutex_unlock(&transport_lock);
572
573        run_transport_disconnects(t);
574
575        if (t->product)
576            free(t->product);
577        if (t->serial)
578            free(t->serial);
579
580        memset(t,0xee,sizeof(atransport));
581        free(t);
582
583        update_transports();
584        return;
585    }
586
587    /* don't create transport threads for inaccessible devices */
588    if (t->connection_state != CS_NOPERM) {
589        /* initial references are the two threads */
590        t->ref_count = 2;
591
592        if(adb_socketpair(s)) {
593            fatal_errno("cannot open transport socketpair");
594        }
595
596        D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
597
598        t->transport_socket = s[0];
599        t->fd = s[1];
600
601        D("transport: %p install %d\n", t, t->transport_socket );
602        fdevent_install(&(t->transport_fde),
603                        t->transport_socket,
604                        transport_socket_events,
605                        t);
606
607        fdevent_set(&(t->transport_fde), FDE_READ);
608
609        if(adb_thread_create(&input_thread_ptr, input_thread, t)){
610            fatal_errno("cannot create input thread");
611        }
612
613        if(adb_thread_create(&output_thread_ptr, output_thread, t)){
614            fatal_errno("cannot create output thread");
615        }
616    }
617
618        /* put us on the master device list */
619    adb_mutex_lock(&transport_lock);
620    t->next = &transport_list;
621    t->prev = transport_list.prev;
622    t->next->prev = t;
623    t->prev->next = t;
624    adb_mutex_unlock(&transport_lock);
625
626    t->disconnects.next = t->disconnects.prev = &t->disconnects;
627
628    update_transports();
629}
630
631void init_transport_registration(void)
632{
633    int s[2];
634
635    if(adb_socketpair(s)){
636        fatal_errno("cannot open transport registration socketpair");
637    }
638
639    transport_registration_send = s[0];
640    transport_registration_recv = s[1];
641
642    fdevent_install(&transport_registration_fde,
643                    transport_registration_recv,
644                    transport_registration_func,
645                    0);
646
647    fdevent_set(&transport_registration_fde, FDE_READ);
648}
649
650/* the fdevent select pump is single threaded */
651static void register_transport(atransport *transport)
652{
653    tmsg m;
654    m.transport = transport;
655    m.action = 1;
656    D("transport: %p registered\n", transport);
657    if(transport_write_action(transport_registration_send, &m)) {
658        fatal_errno("cannot write transport registration socket\n");
659    }
660}
661
662static void remove_transport(atransport *transport)
663{
664    tmsg m;
665    m.transport = transport;
666    m.action = 0;
667    D("transport: %p removed\n", transport);
668    if(transport_write_action(transport_registration_send, &m)) {
669        fatal_errno("cannot write transport registration socket\n");
670    }
671}
672
673
674static void transport_unref(atransport *t)
675{
676    if (t) {
677        adb_mutex_lock(&transport_lock);
678        t->ref_count--;
679        D("transport: %p R- (ref=%d)\n", t, t->ref_count);
680        if (t->ref_count == 0) {
681            D("transport: %p kicking and closing\n", t);
682            if (!t->kicked) {
683                t->kicked = 1;
684                t->kick(t);
685            }
686            t->close(t);
687            remove_transport(t);
688        }
689        adb_mutex_unlock(&transport_lock);
690    }
691}
692
693void add_transport_disconnect(atransport*  t, adisconnect*  dis)
694{
695    adb_mutex_lock(&transport_lock);
696    dis->next       = &t->disconnects;
697    dis->prev       = dis->next->prev;
698    dis->prev->next = dis;
699    dis->next->prev = dis;
700    adb_mutex_unlock(&transport_lock);
701}
702
703void remove_transport_disconnect(atransport*  t, adisconnect*  dis)
704{
705    dis->prev->next = dis->next;
706    dis->next->prev = dis->prev;
707    dis->next = dis->prev = dis;
708}
709
710
711atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
712{
713    atransport *t;
714    atransport *result = NULL;
715    int ambiguous = 0;
716
717retry:
718    if (error_out)
719        *error_out = "device not found";
720
721    adb_mutex_lock(&transport_lock);
722    for (t = transport_list.next; t != &transport_list; t = t->next) {
723        if (t->connection_state == CS_NOPERM) {
724        if (error_out)
725            *error_out = "insufficient permissions for device";
726            continue;
727        }
728
729        /* check for matching serial number */
730        if (serial) {
731            if (t->serial && !strcmp(serial, t->serial)) {
732                result = t;
733                break;
734            }
735        } else {
736            if (ttype == kTransportUsb && t->type == kTransportUsb) {
737                if (result) {
738                    if (error_out)
739                        *error_out = "more than one device";
740                    ambiguous = 1;
741                    result = NULL;
742                    break;
743                }
744                result = t;
745            } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
746                if (result) {
747                    if (error_out)
748                        *error_out = "more than one emulator";
749                    ambiguous = 1;
750                    result = NULL;
751                    break;
752                }
753                result = t;
754            } else if (ttype == kTransportAny) {
755                if (result) {
756                    if (error_out)
757                        *error_out = "more than one device and emulator";
758                    ambiguous = 1;
759                    result = NULL;
760                    break;
761                }
762                result = t;
763            }
764        }
765    }
766    adb_mutex_unlock(&transport_lock);
767
768    if (result) {
769         /* offline devices are ignored -- they are either being born or dying */
770        if (result && result->connection_state == CS_OFFLINE) {
771            if (error_out)
772                *error_out = "device offline";
773            result = NULL;
774        }
775         /* check for required connection state */
776        if (result && state != CS_ANY && result->connection_state != state) {
777            if (error_out)
778                *error_out = "invalid device state";
779            result = NULL;
780        }
781    }
782
783    if (result) {
784        /* found one that we can take */
785        if (error_out)
786            *error_out = NULL;
787    } else if (state != CS_ANY && (serial || !ambiguous)) {
788        adb_sleep_ms(1000);
789        goto retry;
790    }
791
792    return result;
793}
794
795#if ADB_HOST
796static const char *statename(atransport *t)
797{
798    switch(t->connection_state){
799    case CS_OFFLINE: return "offline";
800    case CS_BOOTLOADER: return "bootloader";
801    case CS_DEVICE: return "device";
802    case CS_HOST: return "host";
803    case CS_RECOVERY: return "recovery";
804    case CS_NOPERM: return "no permissions";
805    default: return "unknown";
806    }
807}
808
809int list_transports(char *buf, size_t  bufsize)
810{
811    char*       p   = buf;
812    char*       end = buf + bufsize;
813    int         len;
814    atransport *t;
815
816        /* XXX OVERRUN PROBLEMS XXX */
817    adb_mutex_lock(&transport_lock);
818    for(t = transport_list.next; t != &transport_list; t = t->next) {
819        const char* serial = t->serial;
820        if (!serial || !serial[0])
821            serial = "????????????";
822        len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
823
824        if (p + len >= end) {
825            /* discard last line if buffer is too short */
826            break;
827        }
828        p += len;
829    }
830    p[0] = 0;
831    adb_mutex_unlock(&transport_lock);
832    return p - buf;
833}
834
835
836/* hack for osx */
837void close_usb_devices()
838{
839    atransport *t;
840
841    adb_mutex_lock(&transport_lock);
842    for(t = transport_list.next; t != &transport_list; t = t->next) {
843        if ( !t->kicked ) {
844            t->kicked = 1;
845            t->kick(t);
846        }
847    }
848    adb_mutex_unlock(&transport_lock);
849}
850#endif // ADB_HOST
851
852void register_socket_transport(int s, const char *serial, int port, int local)
853{
854    atransport *t = calloc(1, sizeof(atransport));
855    D("transport: %p init'ing for socket %d, on port %d\n", t, s, port);
856    if ( init_socket_transport(t, s, port, local) < 0 ) {
857        adb_close(s);
858        free(t);
859        return;
860    }
861    if(serial) {
862        t->serial = strdup(serial);
863    }
864    register_transport(t);
865}
866
867#if ADB_HOST
868atransport *find_transport(const char *serial)
869{
870    atransport *t;
871
872    adb_mutex_lock(&transport_lock);
873    for(t = transport_list.next; t != &transport_list; t = t->next) {
874        if (t->serial && !strcmp(serial, t->serial)) {
875            break;
876        }
877     }
878    adb_mutex_unlock(&transport_lock);
879
880    if (t != &transport_list)
881        return t;
882    else
883        return 0;
884}
885
886void unregister_transport(atransport *t)
887{
888    adb_mutex_lock(&transport_lock);
889    t->next->prev = t->prev;
890    t->prev->next = t->next;
891    adb_mutex_unlock(&transport_lock);
892
893    kick_transport(t);
894    transport_unref(t);
895}
896
897#endif
898
899void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
900{
901    atransport *t = calloc(1, sizeof(atransport));
902    D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
903      serial ? serial : "");
904    init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
905    if(serial) {
906        t->serial = strdup(serial);
907    }
908    register_transport(t);
909}
910
911/* this should only be used for transports with connection_state == CS_NOPERM */
912void unregister_usb_transport(usb_handle *usb)
913{
914    atransport *t;
915    adb_mutex_lock(&transport_lock);
916    for(t = transport_list.next; t != &transport_list; t = t->next) {
917        if (t->usb == usb && t->connection_state == CS_NOPERM) {
918            t->next->prev = t->prev;
919            t->prev->next = t->next;
920            break;
921        }
922     }
923    adb_mutex_unlock(&transport_lock);
924}
925
926#undef TRACE_TAG
927#define TRACE_TAG  TRACE_RWX
928
929int readx(int fd, void *ptr, size_t len)
930{
931    char *p = ptr;
932    int r;
933#if ADB_TRACE
934    int  len0 = len;
935#endif
936    D("readx: %d %p %d\n", fd, ptr, (int)len);
937    while(len > 0) {
938        r = adb_read(fd, p, len);
939        if(r > 0) {
940            len -= r;
941            p += r;
942        } else {
943            D("readx: %d %d %s\n", fd, r, strerror(errno));
944            if((r < 0) && (errno == EINTR)) continue;
945            return -1;
946        }
947    }
948
949#if ADB_TRACE
950    D("readx: %d ok: ", fd);
951    dump_hex( ptr, len0 );
952#endif
953    return 0;
954}
955
956int writex(int fd, const void *ptr, size_t len)
957{
958    char *p = (char*) ptr;
959    int r;
960
961#if ADB_TRACE
962    D("writex: %d %p %d: ", fd, ptr, (int)len);
963    dump_hex( ptr, len );
964#endif
965    while(len > 0) {
966        r = adb_write(fd, p, len);
967        if(r > 0) {
968            len -= r;
969            p += r;
970        } else {
971            D("writex: %d %d %s\n", fd, r, strerror(errno));
972            if((r < 0) && (errno == EINTR)) continue;
973            return -1;
974        }
975    }
976
977    D("writex: %d ok\n", fd);
978    return 0;
979}
980
981int check_header(apacket *p)
982{
983    if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
984        D("check_header(): invalid magic\n");
985        return -1;
986    }
987
988    if(p->msg.data_length > MAX_PAYLOAD) {
989        D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length);
990        return -1;
991    }
992
993    return 0;
994}
995
996int check_data(apacket *p)
997{
998    unsigned count, sum;
999    unsigned char *x;
1000
1001    count = p->msg.data_length;
1002    x = p->data;
1003    sum = 0;
1004    while(count-- > 0) {
1005        sum += *x++;
1006    }
1007
1008    if(sum != p->msg.data_check) {
1009        return -1;
1010    } else {
1011        return 0;
1012    }
1013}
1014
1015