sockets.c revision d15e6ac95dc898fb78fb5917bb2e4498b40b716f
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 <errno.h>
21#include <string.h>
22#include <ctype.h>
23
24#include "sysdeps.h"
25
26#define  TRACE_TAG  TRACE_SOCKETS
27#include "adb.h"
28
29ADB_MUTEX_DEFINE( socket_list_lock );
30
31static void local_socket_close_locked(asocket *s);
32
33int sendfailmsg(int fd, const char *reason)
34{
35    char buf[9];
36    int len;
37    len = strlen(reason);
38    if(len > 0xffff) len = 0xffff;
39    snprintf(buf, sizeof buf, "FAIL%04x", len);
40    if(writex(fd, buf, 8)) return -1;
41    return writex(fd, reason, len);
42}
43
44//extern int online;
45
46static unsigned local_socket_next_id = 1;
47
48static asocket local_socket_list = {
49    .next = &local_socket_list,
50    .prev = &local_socket_list,
51};
52
53/* the the list of currently closing local sockets.
54** these have no peer anymore, but still packets to
55** write to their fd.
56*/
57static asocket local_socket_closing_list = {
58    .next = &local_socket_closing_list,
59    .prev = &local_socket_closing_list,
60};
61
62asocket *find_local_socket(unsigned id)
63{
64    asocket *s;
65    asocket *result = NULL;
66
67    adb_mutex_lock(&socket_list_lock);
68    for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
69        if (s->id == id) {
70            result = s;
71            break;
72        }
73    }
74    adb_mutex_unlock(&socket_list_lock);
75
76    return result;
77}
78
79static void
80insert_local_socket(asocket*  s, asocket*  list)
81{
82    s->next       = list;
83    s->prev       = s->next->prev;
84    s->prev->next = s;
85    s->next->prev = s;
86}
87
88
89void install_local_socket(asocket *s)
90{
91    adb_mutex_lock(&socket_list_lock);
92
93    s->id = local_socket_next_id++;
94    insert_local_socket(s, &local_socket_list);
95
96    adb_mutex_unlock(&socket_list_lock);
97}
98
99void remove_socket(asocket *s)
100{
101    // socket_list_lock should already be held
102    if (s->prev && s->next)
103    {
104        s->prev->next = s->next;
105        s->next->prev = s->prev;
106        s->next = 0;
107        s->prev = 0;
108        s->id = 0;
109    }
110}
111
112void close_all_sockets(atransport *t)
113{
114    asocket *s;
115
116        /* this is a little gross, but since s->close() *will* modify
117        ** the list out from under you, your options are limited.
118        */
119    adb_mutex_lock(&socket_list_lock);
120restart:
121    for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
122        if(s->transport == t || (s->peer && s->peer->transport == t)) {
123            local_socket_close_locked(s);
124            goto restart;
125        }
126    }
127    adb_mutex_unlock(&socket_list_lock);
128}
129
130static int local_socket_enqueue(asocket *s, apacket *p)
131{
132    D("LS(%d): enqueue %d\n", s->id, p->len);
133
134    p->ptr = p->data;
135
136        /* if there is already data queue'd, we will receive
137        ** events when it's time to write.  just add this to
138        ** the tail
139        */
140    if(s->pkt_first) {
141        goto enqueue;
142    }
143
144        /* write as much as we can, until we
145        ** would block or there is an error/eof
146        */
147    while(p->len > 0) {
148        int r = adb_write(s->fd, p->ptr, p->len);
149        if(r > 0) {
150            p->len -= r;
151            p->ptr += r;
152            continue;
153        }
154        if((r == 0) || (errno != EAGAIN)) {
155            D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) );
156            s->close(s);
157            return 1; /* not ready (error) */
158        } else {
159            break;
160        }
161    }
162
163    if(p->len == 0) {
164        put_apacket(p);
165        return 0; /* ready for more data */
166    }
167
168enqueue:
169    p->next = 0;
170    if(s->pkt_first) {
171        s->pkt_last->next = p;
172    } else {
173        s->pkt_first = p;
174    }
175    s->pkt_last = p;
176
177        /* make sure we are notified when we can drain the queue */
178    fdevent_add(&s->fde, FDE_WRITE);
179
180    return 1; /* not ready (backlog) */
181}
182
183static void local_socket_ready(asocket *s)
184{
185        /* far side is ready for data, pay attention to
186           readable events */
187    fdevent_add(&s->fde, FDE_READ);
188//    D("LS(%d): ready()\n", s->id);
189}
190
191static void local_socket_close(asocket *s)
192{
193#if ADB_HOST
194    /* to special case commands that cause the remote daemon to terminate */
195    if (s->kick_on_close && s->transport) {
196        kick_transport(s->transport);
197        /* delay to work around a race condition */
198        sleep(1);
199    }
200#endif
201    adb_mutex_lock(&socket_list_lock);
202    local_socket_close_locked(s);
203    adb_mutex_unlock(&socket_list_lock);
204}
205
206// be sure to hold the socket list lock when calling this
207static void local_socket_destroy(asocket  *s)
208{
209    apacket *p, *n;
210    D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd);
211
212        /* IMPORTANT: the remove closes the fd
213        ** that belongs to this socket
214        */
215    fdevent_remove(&s->fde);
216
217        /* dispose of any unwritten data */
218    for(p = s->pkt_first; p; p = n) {
219        D("LS(%d): discarding %d bytes\n", s->id, p->len);
220        n = p->next;
221        put_apacket(p);
222    }
223    remove_socket(s);
224    free(s);
225}
226
227
228static void local_socket_close_locked(asocket *s)
229{
230    D("entered. LS(%d) fd=%d\n", s->id, s->fd);
231    if(s->peer) {
232        D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
233          s->id, s->peer->id, s->peer->fd);
234        s->peer->peer = 0;
235        // tweak to avoid deadlock
236        if (s->peer->close == local_socket_close) {
237            local_socket_close_locked(s->peer);
238        } else {
239            s->peer->close(s->peer);
240        }
241        s->peer = 0;
242    }
243
244        /* If we are already closing, or if there are no
245        ** pending packets, destroy immediately
246        */
247    if (s->closing || s->pkt_first == NULL) {
248        int   id = s->id;
249        local_socket_destroy(s);
250        D("LS(%d): closed\n", id);
251        return;
252    }
253
254        /* otherwise, put on the closing list
255        */
256    D("LS(%d): closing\n", s->id);
257    s->closing = 1;
258    fdevent_del(&s->fde, FDE_READ);
259    remove_socket(s);
260    D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd);
261    insert_local_socket(s, &local_socket_closing_list);
262}
263
264static void local_socket_event_func(int fd, unsigned ev, void *_s)
265{
266    asocket *s = _s;
267
268    D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
269
270    /* put the FDE_WRITE processing before the FDE_READ
271    ** in order to simplify the code.
272    */
273    if(ev & FDE_WRITE){
274        apacket *p;
275
276        while((p = s->pkt_first) != 0) {
277            while(p->len > 0) {
278                int r = adb_write(fd, p->ptr, p->len);
279                if(r > 0) {
280                    p->ptr += r;
281                    p->len -= r;
282                    continue;
283                }
284                if(r < 0) {
285                    /* returning here is ok because FDE_READ will
286                    ** be processed in the next iteration loop
287                    */
288                    if(errno == EAGAIN) return;
289                    if(errno == EINTR) continue;
290                }
291                s->close(s);
292                return;
293            }
294
295            if(p->len == 0) {
296                s->pkt_first = p->next;
297                if(s->pkt_first == 0) s->pkt_last = 0;
298                put_apacket(p);
299            }
300        }
301
302            /* if we sent the last packet of a closing socket,
303            ** we can now destroy it.
304            */
305        if (s->closing) {
306            s->close(s);
307            return;
308        }
309
310            /* no more packets queued, so we can ignore
311            ** writable events again and tell our peer
312            ** to resume writing
313            */
314        fdevent_del(&s->fde, FDE_WRITE);
315        s->peer->ready(s->peer);
316    }
317
318
319    if(ev & FDE_READ){
320        apacket *p = get_apacket();
321        unsigned char *x = p->data;
322        size_t avail = MAX_PAYLOAD;
323        int r;
324        int is_eof = 0;
325
326        while(avail > 0) {
327            r = adb_read(fd, x, avail);
328            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);
329            if(r > 0) {
330                avail -= r;
331                x += r;
332                continue;
333            }
334            if(r < 0) {
335                if(errno == EAGAIN) break;
336                if(errno == EINTR) continue;
337            }
338
339                /* r = 0 or unhandled error */
340            is_eof = 1;
341            break;
342        }
343        D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
344          s->id, s->fd, r, is_eof, s->fde.force_eof);
345        if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
346            put_apacket(p);
347        } else {
348            p->len = MAX_PAYLOAD - avail;
349
350            r = s->peer->enqueue(s->peer, p);
351            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
352
353            if(r < 0) {
354                    /* error return means they closed us as a side-effect
355                    ** and we must return immediately.
356                    **
357                    ** note that if we still have buffered packets, the
358                    ** socket will be placed on the closing socket list.
359                    ** this handler function will be called again
360                    ** to process FDE_WRITE events.
361                    */
362                return;
363            }
364
365            if(r > 0) {
366                    /* if the remote cannot accept further events,
367                    ** we disable notification of READs.  They'll
368                    ** be enabled again when we get a call to ready()
369                    */
370                fdevent_del(&s->fde, FDE_READ);
371            }
372        }
373        /* Don't allow a forced eof if data is still there */
374        if((s->fde.force_eof && !r) || is_eof) {
375            s->close(s);
376        }
377    }
378
379    if(ev & FDE_ERROR){
380            /* this should be caught be the next read or write
381            ** catching it here means we may skip the last few
382            ** bytes of readable data.
383            */
384//        s->close(s);
385        D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
386
387        return;
388    }
389}
390
391asocket *create_local_socket(int fd)
392{
393    asocket *s = calloc(1, sizeof(asocket));
394    if (s == NULL) fatal("cannot allocate socket");
395    s->fd = fd;
396    s->enqueue = local_socket_enqueue;
397    s->ready = local_socket_ready;
398    s->close = local_socket_close;
399    install_local_socket(s);
400
401    fdevent_install(&s->fde, fd, local_socket_event_func, s);
402/*    fdevent_add(&s->fde, FDE_ERROR); */
403    //fprintf(stderr, "Created local socket in create_local_socket \n");
404    D("LS(%d): created (fd=%d)\n", s->id, s->fd);
405    return s;
406}
407
408asocket *create_local_service_socket(const char *name)
409{
410    asocket *s;
411    int fd;
412
413#if !ADB_HOST
414    if (!strcmp(name,"jdwp")) {
415        return create_jdwp_service_socket();
416    }
417    if (!strcmp(name,"track-jdwp")) {
418        return create_jdwp_tracker_service_socket();
419    }
420#endif
421    fd = service_to_fd(name);
422    if(fd < 0) return 0;
423
424    s = create_local_socket(fd);
425    D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
426    return s;
427}
428
429#if ADB_HOST
430static asocket *create_host_service_socket(const char *name, const char* serial)
431{
432    asocket *s;
433
434    s = host_service_to_socket(name, serial);
435
436    if (s != NULL) {
437        D("LS(%d) bound to '%s'\n", s->id, name);
438        return s;
439    }
440
441    return s;
442}
443#endif /* ADB_HOST */
444
445/* a Remote socket is used to send/receive data to/from a given transport object
446** it needs to be closed when the transport is forcibly destroyed by the user
447*/
448typedef struct aremotesocket {
449    asocket      socket;
450    adisconnect  disconnect;
451} aremotesocket;
452
453static int remote_socket_enqueue(asocket *s, apacket *p)
454{
455    D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
456      s->id, s->fd, s->peer->fd);
457    p->msg.command = A_WRTE;
458    p->msg.arg0 = s->peer->id;
459    p->msg.arg1 = s->id;
460    p->msg.data_length = p->len;
461    send_packet(p, s->transport);
462    return 1;
463}
464
465static void remote_socket_ready(asocket *s)
466{
467    D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n",
468      s->id, s->fd, s->peer->fd);
469    apacket *p = get_apacket();
470    p->msg.command = A_OKAY;
471    p->msg.arg0 = s->peer->id;
472    p->msg.arg1 = s->id;
473    send_packet(p, s->transport);
474}
475
476static void remote_socket_close(asocket *s)
477{
478    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
479      s->id, s->fd, s->peer?s->peer->fd:-1);
480    apacket *p = get_apacket();
481    p->msg.command = A_CLSE;
482    if(s->peer) {
483        p->msg.arg0 = s->peer->id;
484        s->peer->peer = 0;
485        D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
486          s->id, s->peer->id, s->peer->fd);
487        s->peer->close(s->peer);
488    }
489    p->msg.arg1 = s->id;
490    send_packet(p, s->transport);
491    D("RS(%d): closed\n", s->id);
492    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
493    free(s);
494}
495
496static void remote_socket_disconnect(void*  _s, atransport*  t)
497{
498    asocket*  s    = _s;
499    asocket*  peer = s->peer;
500
501    D("remote_socket_disconnect RS(%d)\n", s->id);
502    if (peer) {
503        peer->peer = NULL;
504        peer->close(peer);
505    }
506    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
507    free(s);
508}
509
510asocket *create_remote_socket(unsigned id, atransport *t)
511{
512    asocket *s = calloc(1, sizeof(aremotesocket));
513    adisconnect*  dis = &((aremotesocket*)s)->disconnect;
514
515    if (s == NULL) fatal("cannot allocate socket");
516    s->id = id;
517    s->enqueue = remote_socket_enqueue;
518    s->ready = remote_socket_ready;
519    s->close = remote_socket_close;
520    s->transport = t;
521
522    dis->func   = remote_socket_disconnect;
523    dis->opaque = s;
524    add_transport_disconnect( t, dis );
525    D("RS(%d): created\n", s->id);
526    return s;
527}
528
529void connect_to_remote(asocket *s, const char *destination)
530{
531    D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd);
532    apacket *p = get_apacket();
533    int len = strlen(destination) + 1;
534
535#if ADB_HOST
536    /* special case commands that cause the remote daemon to terminate */
537    if (!strcmp(destination, "root:")) {
538        D("connect_to_remote setting kick_on_close for %s\n", destination);
539        s->kick_on_close = 1;
540    }
541#endif
542
543    if(len > (MAX_PAYLOAD-1)) {
544        fatal("destination oversized");
545    }
546
547    D("LS(%d): connect('%s')\n", s->id, destination);
548    p->msg.command = A_OPEN;
549    p->msg.arg0 = s->id;
550    p->msg.data_length = len;
551    strcpy((char*) p->data, destination);
552    send_packet(p, s->transport);
553}
554
555
556/* this is used by magic sockets to rig local sockets to
557   send the go-ahead message when they connect */
558static void local_socket_ready_notify(asocket *s)
559{
560    s->ready = local_socket_ready;
561    s->close = local_socket_close;
562    adb_write(s->fd, "OKAY", 4);
563    s->ready(s);
564}
565
566/* this is used by magic sockets to rig local sockets to
567   send the failure message if they are closed before
568   connected (to avoid closing them without a status message) */
569static void local_socket_close_notify(asocket *s)
570{
571    s->ready = local_socket_ready;
572    s->close = local_socket_close;
573    sendfailmsg(s->fd, "closed");
574    s->close(s);
575}
576
577unsigned unhex(unsigned char *s, int len)
578{
579    unsigned n = 0, c;
580
581    while(len-- > 0) {
582        switch((c = *s++)) {
583        case '0': case '1': case '2':
584        case '3': case '4': case '5':
585        case '6': case '7': case '8':
586        case '9':
587            c -= '0';
588            break;
589        case 'a': case 'b': case 'c':
590        case 'd': case 'e': case 'f':
591            c = c - 'a' + 10;
592            break;
593        case 'A': case 'B': case 'C':
594        case 'D': case 'E': case 'F':
595            c = c - 'A' + 10;
596            break;
597        default:
598            return 0xffffffff;
599        }
600
601        n = (n << 4) | c;
602    }
603
604    return n;
605}
606
607/* skip_host_serial return the position in a string
608   skipping over the 'serial' parameter in the ADB protocol,
609   where parameter string may be a host:port string containing
610   the protocol delimiter (colon). */
611char *skip_host_serial(char *service) {
612    char *first_colon, *serial_end;
613
614    first_colon = strchr(service, ':');
615    if (!first_colon) {
616        /* No colon in service string. */
617        return NULL;
618    }
619    serial_end = first_colon;
620    if (isdigit(serial_end[1])) {
621        serial_end++;
622        while ((*serial_end) && isdigit(*serial_end)) {
623            serial_end++;
624        }
625        if ((*serial_end) != ':') {
626            // Something other than numbers was found, reset the end.
627            serial_end = first_colon;
628        }
629    }
630    return serial_end;
631}
632
633static int smart_socket_enqueue(asocket *s, apacket *p)
634{
635    unsigned len;
636#if ADB_HOST
637    char *service = NULL;
638    char* serial = NULL;
639    transport_type ttype = kTransportAny;
640#endif
641
642    D("SS(%d): enqueue %d\n", s->id, p->len);
643
644    if(s->pkt_first == 0) {
645        s->pkt_first = p;
646        s->pkt_last = p;
647    } else {
648        if((s->pkt_first->len + p->len) > MAX_PAYLOAD) {
649            D("SS(%d): overflow\n", s->id);
650            put_apacket(p);
651            goto fail;
652        }
653
654        memcpy(s->pkt_first->data + s->pkt_first->len,
655               p->data, p->len);
656        s->pkt_first->len += p->len;
657        put_apacket(p);
658
659        p = s->pkt_first;
660    }
661
662        /* don't bother if we can't decode the length */
663    if(p->len < 4) return 0;
664
665    len = unhex(p->data, 4);
666    if((len < 1) ||  (len > 1024)) {
667        D("SS(%d): bad size (%d)\n", s->id, len);
668        goto fail;
669    }
670
671    D("SS(%d): len is %d\n", s->id, len );
672        /* can't do anything until we have the full header */
673    if((len + 4) > p->len) {
674        D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len);
675        return 0;
676    }
677
678    p->data[len + 4] = 0;
679
680    D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
681
682#if ADB_HOST
683    service = (char *)p->data + 4;
684    if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
685        char* serial_end;
686        service += strlen("host-serial:");
687
688        // serial number should follow "host:" and could be a host:port string.
689        serial_end = skip_host_serial(service);
690        if (serial_end) {
691            *serial_end = 0; // terminate string
692            serial = service;
693            service = serial_end + 1;
694        }
695    } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
696        ttype = kTransportUsb;
697        service += strlen("host-usb:");
698    } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
699        ttype = kTransportLocal;
700        service += strlen("host-local:");
701    } else if (!strncmp(service, "host:", strlen("host:"))) {
702        ttype = kTransportAny;
703        service += strlen("host:");
704    } else {
705        service = NULL;
706    }
707
708    if (service) {
709        asocket *s2;
710
711            /* some requests are handled immediately -- in that
712            ** case the handle_host_request() routine has sent
713            ** the OKAY or FAIL message and all we have to do
714            ** is clean up.
715            */
716        if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
717                /* XXX fail message? */
718            D( "SS(%d): handled host service '%s'\n", s->id, service );
719            goto fail;
720        }
721        if (!strncmp(service, "transport", strlen("transport"))) {
722            D( "SS(%d): okay transport\n", s->id );
723            p->len = 0;
724            return 0;
725        }
726
727            /* try to find a local service with this name.
728            ** if no such service exists, we'll fail out
729            ** and tear down here.
730            */
731        s2 = create_host_service_socket(service, serial);
732        if(s2 == 0) {
733            D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
734            sendfailmsg(s->peer->fd, "unknown host service");
735            goto fail;
736        }
737
738            /* we've connected to a local host service,
739            ** so we make our peer back into a regular
740            ** local socket and bind it to the new local
741            ** service socket, acknowledge the successful
742            ** connection, and close this smart socket now
743            ** that its work is done.
744            */
745        adb_write(s->peer->fd, "OKAY", 4);
746
747        s->peer->ready = local_socket_ready;
748        s->peer->close = local_socket_close;
749        s->peer->peer = s2;
750        s2->peer = s->peer;
751        s->peer = 0;
752        D( "SS(%d): okay\n", s->id );
753        s->close(s);
754
755            /* initial state is "ready" */
756        s2->ready(s2);
757        return 0;
758    }
759#else /* !ADB_HOST */
760    if (s->transport == NULL) {
761        char* error_string = "unknown failure";
762        s->transport = acquire_one_transport (CS_ANY,
763                kTransportAny, NULL, &error_string);
764
765        if (s->transport == NULL) {
766            sendfailmsg(s->peer->fd, error_string);
767            goto fail;
768        }
769    }
770#endif
771
772    if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
773           /* if there's no remote we fail the connection
774            ** right here and terminate it
775            */
776        sendfailmsg(s->peer->fd, "device offline (x)");
777        goto fail;
778    }
779
780
781        /* instrument our peer to pass the success or fail
782        ** message back once it connects or closes, then
783        ** detach from it, request the connection, and
784        ** tear down
785        */
786    s->peer->ready = local_socket_ready_notify;
787    s->peer->close = local_socket_close_notify;
788    s->peer->peer = 0;
789        /* give him our transport and upref it */
790    s->peer->transport = s->transport;
791
792    connect_to_remote(s->peer, (char*) (p->data + 4));
793    s->peer = 0;
794    s->close(s);
795    return 1;
796
797fail:
798        /* we're going to close our peer as a side-effect, so
799        ** return -1 to signal that state to the local socket
800        ** who is enqueueing against us
801        */
802    s->close(s);
803    return -1;
804}
805
806static void smart_socket_ready(asocket *s)
807{
808    D("SS(%d): ready\n", s->id);
809}
810
811static void smart_socket_close(asocket *s)
812{
813    D("SS(%d): closed\n", s->id);
814    if(s->pkt_first){
815        put_apacket(s->pkt_first);
816    }
817    if(s->peer) {
818        s->peer->peer = 0;
819        s->peer->close(s->peer);
820        s->peer = 0;
821    }
822    free(s);
823}
824
825asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
826{
827    D("Creating smart socket \n");
828    asocket *s = calloc(1, sizeof(asocket));
829    if (s == NULL) fatal("cannot allocate socket");
830    s->enqueue = smart_socket_enqueue;
831    s->ready = smart_socket_ready;
832    s->close = smart_socket_close;
833    s->extra = action_cb;
834
835    D("SS(%d): created %p\n", s->id, action_cb);
836    return s;
837}
838
839void smart_socket_action(asocket *s, const char *act)
840{
841
842}
843
844void connect_to_smartsocket(asocket *s)
845{
846    D("Connecting to smart socket \n");
847    asocket *ss = create_smart_socket(smart_socket_action);
848    s->peer = ss;
849    ss->peer = s;
850    s->ready(s);
851}
852