* initial contribution for 2.0 beta (0.0.2)
[framework/system/sdbd.git] / src / transport.c
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 "sdb.h"
27
28 static void transport_unref(atransport *t);
29
30 static atransport transport_list = {
31     .next = &transport_list,
32     .prev = &transport_list,
33 };
34
35 SDB_MUTEX_DEFINE( transport_lock );
36
37 #if SDB_TRACE
38 static 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
59 void
60 kick_transport(atransport*  t)
61 {
62     if (t && !t->kicked)
63     {
64         int  kicked;
65
66         sdb_mutex_lock(&transport_lock);
67         kicked = t->kicked;
68         if (!kicked)
69             t->kicked = 1;
70         sdb_mutex_unlock(&transport_lock);
71
72         if (!kicked)
73             t->kick(t);
74     }
75 }
76
77 void
78 run_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
90 static int
91 read_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 = sdb_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 SDB_TRACE
109     if (SDB_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
133 static int
134 write_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 SDB_TRACE
140     if (SDB_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 = sdb_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
176 static 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
188 void 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
229 static 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
278 oops:
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
285 static 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
337 static int transport_registration_send = -1;
338 static int transport_registration_recv = -1;
339 static fdevent transport_registration_fde;
340
341
342 #if SDB_HOST
343 static 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  */
360 typedef struct device_tracker  device_tracker;
361 struct device_tracker {
362     asocket          socket;
363     int              update_needed;
364     device_tracker*  next;
365 };
366
367 /* linked list of all device trackers */
368 static device_tracker*   device_tracker_list;
369
370 static void
371 device_tracker_remove( device_tracker*  tracker )
372 {
373     device_tracker**  pnode = &device_tracker_list;
374     device_tracker*   node  = *pnode;
375
376     sdb_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     sdb_mutex_unlock( &transport_lock );
386 }
387
388 static void
389 device_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
403 static int
404 device_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
412 static int
413 device_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
426 static void
427 device_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
445 asocket*
446 create_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 */
467 void  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
484 void  update_transports(void)
485 {
486     // nothing to do on the device side
487 }
488 #endif // SDB_HOST
489
490 typedef struct tmsg tmsg;
491 struct tmsg
492 {
493     atransport *transport;
494     int         action;
495 };
496
497 static int
498 transport_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 = sdb_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
519 static int
520 transport_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 = sdb_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
541 static void transport_registration_func(int _fd, unsigned ev, void *data)
542 {
543     tmsg m;
544     sdb_thread_t output_thread_ptr;
545     sdb_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         sdb_close(t->fd);
567
568         sdb_mutex_lock(&transport_lock);
569         t->next->prev = t->prev;
570         t->prev->next = t->next;
571         sdb_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(sdb_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(sdb_thread_create(&input_thread_ptr, input_thread, t)){
610             fatal_errno("cannot create input thread");
611         }
612
613         if(sdb_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     sdb_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     sdb_mutex_unlock(&transport_lock);
625
626     t->disconnects.next = t->disconnects.prev = &t->disconnects;
627
628     update_transports();
629 }
630
631 void init_transport_registration(void)
632 {
633     int s[2];
634
635     if(sdb_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 */
651 static 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
662 static 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
674 static void transport_unref_locked(atransport *t)
675 {
676     t->ref_count--;
677     D("transport: %p R- (ref=%d)\n", t, t->ref_count);
678     if (t->ref_count == 0) {
679         D("transport: %p kicking and closing\n", t);
680         if (!t->kicked) {
681             t->kicked = 1;
682             t->kick(t);
683         }
684         t->close(t);
685         remove_transport(t);
686     }
687 }
688
689 static void transport_unref(atransport *t)
690 {
691     if (t) {
692         sdb_mutex_lock(&transport_lock);
693         transport_unref_locked(t);
694         sdb_mutex_unlock(&transport_lock);
695     }
696 }
697
698 void add_transport_disconnect(atransport*  t, adisconnect*  dis)
699 {
700     sdb_mutex_lock(&transport_lock);
701     dis->next       = &t->disconnects;
702     dis->prev       = dis->next->prev;
703     dis->prev->next = dis;
704     dis->next->prev = dis;
705     sdb_mutex_unlock(&transport_lock);
706 }
707
708 void remove_transport_disconnect(atransport*  t, adisconnect*  dis)
709 {
710     dis->prev->next = dis->next;
711     dis->next->prev = dis->prev;
712     dis->next = dis->prev = dis;
713 }
714
715
716 atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
717 {
718     atransport *t;
719     atransport *result = NULL;
720     int ambiguous = 0;
721
722 retry:
723     if (error_out)
724         *error_out = "device not found";
725
726     sdb_mutex_lock(&transport_lock);
727     for (t = transport_list.next; t != &transport_list; t = t->next) {
728         if (t->connection_state == CS_NOPERM) {
729         if (error_out)
730             *error_out = "insufficient permissions for device";
731             continue;
732         }
733
734         /* check for matching serial number */
735         if (serial) {
736             if (t->serial && !strcmp(serial, t->serial)) {
737                 result = t;
738                 break;
739             }
740         } else {
741             if (ttype == kTransportUsb && t->type == kTransportUsb) {
742                 if (result) {
743                     if (error_out)
744                         *error_out = "more than one device";
745                     ambiguous = 1;
746                     result = NULL;
747                     break;
748                 }
749                 result = t;
750             } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
751                 if (result) {
752                     if (error_out)
753                         *error_out = "more than one emulator";
754                     ambiguous = 1;
755                     result = NULL;
756                     break;
757                 }
758                 result = t;
759             } else if (ttype == kTransportAny) {
760                 if (result) {
761                     if (error_out)
762                         *error_out = "more than one device and emulator";
763                     ambiguous = 1;
764                     result = NULL;
765                     break;
766                 }
767                 result = t;
768             }
769         }
770     }
771     sdb_mutex_unlock(&transport_lock);
772
773     if (result) {
774          /* offline devices are ignored -- they are either being born or dying */
775         if (result && result->connection_state == CS_OFFLINE) {
776             if (error_out)
777                 *error_out = "device offline";
778             result = NULL;
779         }
780          /* check for required connection state */
781         if (result && state != CS_ANY && result->connection_state != state) {
782             if (error_out)
783                 *error_out = "invalid device state";
784             result = NULL;
785         }
786     }
787
788     if (result) {
789         /* found one that we can take */
790         if (error_out)
791             *error_out = NULL;
792     } else if (state != CS_ANY && (serial || !ambiguous)) {
793         sdb_sleep_ms(1000);
794         goto retry;
795     }
796
797     return result;
798 }
799
800 #if SDB_HOST
801 static const char *statename(atransport *t)
802 {
803     switch(t->connection_state){
804     case CS_OFFLINE: return "offline";
805     case CS_BOOTLOADER: return "bootloader";
806     case CS_DEVICE: return "device";
807     case CS_HOST: return "host";
808     case CS_RECOVERY: return "recovery";
809     case CS_NOPERM: return "no permissions";
810     default: return "unknown";
811     }
812 }
813
814 int list_transports(char *buf, size_t  bufsize)
815 {
816     char*       p   = buf;
817     char*       end = buf + bufsize;
818     int         len;
819     atransport *t;
820
821         /* XXX OVERRUN PROBLEMS XXX */
822     sdb_mutex_lock(&transport_lock);
823     for(t = transport_list.next; t != &transport_list; t = t->next) {
824         const char* serial = t->serial;
825         if (!serial || !serial[0])
826             serial = "????????????";
827         len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
828
829         if (p + len >= end) {
830             /* discard last line if buffer is too short */
831             break;
832         }
833         p += len;
834     }
835     p[0] = 0;
836     sdb_mutex_unlock(&transport_lock);
837     return p - buf;
838 }
839
840
841 /* hack for osx */
842 void close_usb_devices()
843 {
844     atransport *t;
845
846     sdb_mutex_lock(&transport_lock);
847     for(t = transport_list.next; t != &transport_list; t = t->next) {
848         if ( !t->kicked ) {
849             t->kicked = 1;
850             t->kick(t);
851         }
852     }
853     sdb_mutex_unlock(&transport_lock);
854 }
855 #endif // SDB_HOST
856
857 void register_socket_transport(int s, const char *serial, int port, int local)
858 {
859     atransport *t = calloc(1, sizeof(atransport));
860     D("transport: %p init'ing for socket %d, on port %d\n", t, s, port);
861     if ( init_socket_transport(t, s, port, local) < 0 ) {
862         sdb_close(s);
863         free(t);
864         return;
865     }
866     if(serial) {
867         t->serial = strdup(serial);
868     }
869     register_transport(t);
870 }
871
872 #if SDB_HOST
873 atransport *find_transport(const char *serial)
874 {
875     atransport *t;
876
877     sdb_mutex_lock(&transport_lock);
878     for(t = transport_list.next; t != &transport_list; t = t->next) {
879         if (t->serial && !strcmp(serial, t->serial)) {
880             break;
881         }
882      }
883     sdb_mutex_unlock(&transport_lock);
884
885     if (t != &transport_list)
886         return t;
887     else
888         return 0;
889 }
890
891 void unregister_transport(atransport *t)
892 {
893     sdb_mutex_lock(&transport_lock);
894     t->next->prev = t->prev;
895     t->prev->next = t->next;
896     sdb_mutex_unlock(&transport_lock);
897
898     kick_transport(t);
899     transport_unref(t);
900 }
901
902 // unregisters all non-emulator TCP transports
903 void unregister_all_tcp_transports()
904 {
905     atransport *t, *next;
906     sdb_mutex_lock(&transport_lock);
907     for (t = transport_list.next; t != &transport_list; t = next) {
908         next = t->next;
909         if (t->type == kTransportLocal && t->sdb_port == 0) {
910             t->next->prev = t->prev;
911             t->prev->next = next;
912             // we cannot call kick_transport when holding transport_lock
913             if (!t->kicked)
914             {
915                 t->kicked = 1;
916                 t->kick(t);
917             }
918             transport_unref_locked(t);
919         }
920      }
921
922     sdb_mutex_unlock(&transport_lock);
923 }
924
925 #endif
926
927 void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
928 {
929     atransport *t = calloc(1, sizeof(atransport));
930     D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
931       serial ? serial : "");
932     init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
933     if(serial) {
934         t->serial = strdup(serial);
935     }
936     register_transport(t);
937 }
938
939 /* this should only be used for transports with connection_state == CS_NOPERM */
940 void unregister_usb_transport(usb_handle *usb)
941 {
942     atransport *t;
943     sdb_mutex_lock(&transport_lock);
944     for(t = transport_list.next; t != &transport_list; t = t->next) {
945         if (t->usb == usb && t->connection_state == CS_NOPERM) {
946             t->next->prev = t->prev;
947             t->prev->next = t->next;
948             break;
949         }
950      }
951     sdb_mutex_unlock(&transport_lock);
952 }
953
954 #undef TRACE_TAG
955 #define TRACE_TAG  TRACE_RWX
956
957 int readx(int fd, void *ptr, size_t len)
958 {
959     char *p = ptr;
960     int r;
961 #if SDB_TRACE
962     int  len0 = len;
963 #endif
964     D("readx: %d %p %d\n", fd, ptr, (int)len);
965     while(len > 0) {
966         r = sdb_read(fd, p, len);
967         if(r > 0) {
968             len -= r;
969             p += r;
970         } else {
971             D("readx: %d %d %s\n", fd, r, strerror(errno));
972             if((r < 0) && (errno == EINTR)) continue;
973             return -1;
974         }
975     }
976
977 #if SDB_TRACE
978     D("readx: %d ok: ", fd);
979     dump_hex( ptr, len0 );
980 #endif
981     return 0;
982 }
983
984 int writex(int fd, const void *ptr, size_t len)
985 {
986     char *p = (char*) ptr;
987     int r;
988
989 #if SDB_TRACE
990     D("writex: %d %p %d: ", fd, ptr, (int)len);
991     dump_hex( ptr, len );
992 #endif
993     while(len > 0) {
994         r = sdb_write(fd, p, len);
995         if(r > 0) {
996             len -= r;
997             p += r;
998         } else {
999             D("writex: %d %d %s\n", fd, r, strerror(errno));
1000             if((r < 0) && (errno == EINTR)) continue;
1001             return -1;
1002         }
1003     }
1004
1005     D("writex: %d ok\n", fd);
1006     return 0;
1007 }
1008
1009 int check_header(apacket *p)
1010 {
1011     if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
1012         D("check_header(): invalid magic\n");
1013         return -1;
1014     }
1015
1016     if(p->msg.data_length > MAX_PAYLOAD) {
1017         D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length);
1018         return -1;
1019     }
1020
1021     return 0;
1022 }
1023
1024 int check_data(apacket *p)
1025 {
1026     unsigned count, sum;
1027     unsigned char *x;
1028
1029     count = p->msg.data_length;
1030     x = p->data;
1031     sum = 0;
1032     while(count-- > 0) {
1033         sum += *x++;
1034     }
1035
1036     if(sum != p->msg.data_check) {
1037         return -1;
1038     } else {
1039         return 0;
1040     }
1041 }
1042