| #include <stdint.h> | 
 | #include <stdarg.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <fcntl.h> | 
 | #include <errno.h> | 
 | #include <string.h> | 
 | #include <sys/socket.h> | 
 | #include <termios.h> | 
 | #include <cutils/sockets.h> | 
 |  | 
 | /* | 
 |  *  the qemud daemon program is only used within Android as a bridge | 
 |  *  between the emulator program and the emulated system. it really works as | 
 |  *  a simple stream multiplexer that works as follows: | 
 |  * | 
 |  *    - qemud is started by init following instructions in | 
 |  *      /system/etc/init.goldfish.rc (i.e. it is never started on real devices) | 
 |  * | 
 |  *    - qemud communicates with the emulator program through a single serial | 
 |  *      port, whose name is passed through a kernel boot parameter | 
 |  *      (e.g. android.qemud=ttyS1) | 
 |  * | 
 |  *    - qemud binds one unix local stream socket (/dev/socket/qemud, created | 
 |  *      by init through /system/etc/init.goldfish.rc). | 
 |  * | 
 |  * | 
 |  *      emulator <==serial==> qemud <---> /dev/socket/qemud <-+--> client1 | 
 |  *                                                            | | 
 |  *                                                            +--> client2 | 
 |  * | 
 |  *   - the special channel index 0 is used by the emulator and qemud only. | 
 |  *     other channel numbers correspond to clients. More specifically, | 
 |  *     connection are created like this: | 
 |  * | 
 |  *     * the client connects to /dev/socket/qemud | 
 |  * | 
 |  *     * the client sends the service name through the socket, as | 
 |  *            <service-name> | 
 |  * | 
 |  *     * qemud creates a "Client" object internally, assigns it an | 
 |  *       internal unique channel number > 0, then sends a connection | 
 |  *       initiation request to the emulator (i.e. through channel 0): | 
 |  * | 
 |  *           connect:<id>:<name> | 
 |  * | 
 |  *       where <name> is the service name, and <id> is a 2-hexchar | 
 |  *       number corresponding to the channel number. | 
 |  * | 
 |  *     * in case of success, the emulator responds through channel 0 | 
 |  *       with: | 
 |  * | 
 |  *           ok:connect:<id> | 
 |  * | 
 |  *       after this, all messages between the client and the emulator | 
 |  *       are passed in pass-through mode. | 
 |  * | 
 |  *     * if the emulator refuses the service connection, it will | 
 |  *       send the following through channel 0: | 
 |  * | 
 |  *           ko:connect:<id>:reason-for-failure | 
 |  * | 
 |  *     * If the client closes the connection, qemud sends the following | 
 |  *       to the emulator: | 
 |  * | 
 |  *           disconnect:<id> | 
 |  * | 
 |  *       The same message is the opposite direction if the emulator | 
 |  *       chooses to close the connection. | 
 |  * | 
 |  *     * any command sent through channel 0 to the emulator that is | 
 |  *       not properly recognized will be answered by: | 
 |  * | 
 |  *           ko:unknown command | 
 |  * | 
 |  * | 
 |  *  Internally, the daemon maintains a "Client" object for each client | 
 |  *  connection (i.e. accepting socket connection). | 
 |  */ | 
 |  | 
 | /* name of the single control socket used by the daemon */ | 
 | #define CONTROL_SOCKET_NAME  "qemud" | 
 |  | 
 | #define  DEBUG     1 | 
 | #define  T_ACTIVE  0  /* set to 1 to dump traffic */ | 
 |  | 
 | #if DEBUG | 
 | #  define LOG_TAG  "qemud" | 
 | #  include <cutils/log.h> | 
 | #  define  D(...)   LOGD(__VA_ARGS__) | 
 | #else | 
 | #  define  D(...)  ((void)0) | 
 | #  define  T(...)  ((void)0) | 
 | #endif | 
 |  | 
 | #if T_ACTIVE | 
 | #  define  T(...)   D(__VA_ARGS__) | 
 | #else | 
 | #  define  T(...)   ((void)0) | 
 | #endif | 
 |  | 
 | /** UTILITIES | 
 |  **/ | 
 |  | 
 | static void | 
 | fatal( const char*  fmt, ... ) | 
 | { | 
 |     va_list  args; | 
 |     va_start(args, fmt); | 
 |     fprintf(stderr, "PANIC: "); | 
 |     vfprintf(stderr, fmt, args); | 
 |     fprintf(stderr, "\n" ); | 
 |     va_end(args); | 
 |     exit(1); | 
 | } | 
 |  | 
 | static void* | 
 | xalloc( size_t   sz ) | 
 | { | 
 |     void*  p; | 
 |  | 
 |     if (sz == 0) | 
 |         return NULL; | 
 |  | 
 |     p = malloc(sz); | 
 |     if (p == NULL) | 
 |         fatal( "not enough memory" ); | 
 |  | 
 |     return p; | 
 | } | 
 |  | 
 | #define  xnew(p)   (p) = xalloc(sizeof(*(p))) | 
 |  | 
 | static void* | 
 | xalloc0( size_t  sz ) | 
 | { | 
 |     void*  p = xalloc(sz); | 
 |     memset( p, 0, sz ); | 
 |     return p; | 
 | } | 
 |  | 
 | #define  xnew0(p)   (p) = xalloc0(sizeof(*(p))) | 
 |  | 
 | #define  xfree(p)    (free((p)), (p) = NULL) | 
 |  | 
 | static void* | 
 | xrealloc( void*  block, size_t  size ) | 
 | { | 
 |     void*  p = realloc( block, size ); | 
 |  | 
 |     if (p == NULL && size > 0) | 
 |         fatal( "not enough memory" ); | 
 |  | 
 |     return p; | 
 | } | 
 |  | 
 | #define  xrenew(p,count)  (p) = xrealloc((p),sizeof(*(p))*(count)) | 
 |  | 
 | static int | 
 | hex2int( const uint8_t*  data, int  len ) | 
 | { | 
 |     int  result = 0; | 
 |     while (len > 0) { | 
 |         int       c = *data++; | 
 |         unsigned  d; | 
 |  | 
 |         result <<= 4; | 
 |         do { | 
 |             d = (unsigned)(c - '0'); | 
 |             if (d < 10) | 
 |                 break; | 
 |  | 
 |             d = (unsigned)(c - 'a'); | 
 |             if (d < 6) { | 
 |                 d += 10; | 
 |                 break; | 
 |             } | 
 |  | 
 |             d = (unsigned)(c - 'A'); | 
 |             if (d < 6) { | 
 |                 d += 10; | 
 |                 break; | 
 |             } | 
 |  | 
 |             return -1; | 
 |         } | 
 |         while (0); | 
 |  | 
 |         result |= d; | 
 |         len    -= 1; | 
 |     } | 
 |     return  result; | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | int2hex( int  value, uint8_t*  to, int  width ) | 
 | { | 
 |     int  nn = 0; | 
 |     static const char hexchars[16] = "0123456789abcdef"; | 
 |  | 
 |     for ( --width; width >= 0; width--, nn++ ) { | 
 |         to[nn] = hexchars[(value >> (width*4)) & 15]; | 
 |     } | 
 | } | 
 |  | 
 | static int | 
 | fd_read(int  fd, void*  to, int  len) | 
 | { | 
 |     int  ret; | 
 |  | 
 |     do { | 
 |         ret = read(fd, to, len); | 
 |     } while (ret < 0 && errno == EINTR); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | static int | 
 | fd_write(int  fd, const void*  from, int  len) | 
 | { | 
 |     int  ret; | 
 |  | 
 |     do { | 
 |         ret = write(fd, from, len); | 
 |     } while (ret < 0 && errno == EINTR); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | static void | 
 | fd_setnonblock(int  fd) | 
 | { | 
 |     int  ret, flags; | 
 |  | 
 |     do { | 
 |         flags = fcntl(fd, F_GETFD); | 
 |     } while (flags < 0 && errno == EINTR); | 
 |  | 
 |     if (flags < 0) { | 
 |         fatal( "%s: could not get flags for fd %d: %s", | 
 |                __FUNCTION__, fd, strerror(errno) ); | 
 |     } | 
 |  | 
 |     do { | 
 |         ret = fcntl(fd, F_SETFD, flags | O_NONBLOCK); | 
 |     } while (ret < 0 && errno == EINTR); | 
 |  | 
 |     if (ret < 0) { | 
 |         fatal( "%s: could not set fd %d to non-blocking: %s", | 
 |                __FUNCTION__, fd, strerror(errno) ); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | static int | 
 | fd_accept(int  fd) | 
 | { | 
 |     struct sockaddr  from; | 
 |     socklen_t        fromlen = sizeof(from); | 
 |     int              ret; | 
 |  | 
 |     do { | 
 |         ret = accept(fd, &from, &fromlen); | 
 |     } while (ret < 0 && errno == EINTR); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | /** FD EVENT LOOP | 
 |  **/ | 
 |  | 
 | /* A Looper object is used to monitor activity on one or more | 
 |  * file descriptors (e.g sockets). | 
 |  * | 
 |  * - call looper_add() to register a function that will be | 
 |  *   called when events happen on the file descriptor. | 
 |  * | 
 |  * - call looper_enable() or looper_disable() to enable/disable | 
 |  *   the set of monitored events for a given file descriptor. | 
 |  * | 
 |  * - call looper_del() to unregister a file descriptor. | 
 |  *   this does *not* close the file descriptor. | 
 |  * | 
 |  * Note that you can only provide a single function to handle | 
 |  * all events related to a given file descriptor. | 
 |  | 
 |  * You can call looper_enable/_disable/_del within a function | 
 |  * callback. | 
 |  */ | 
 |  | 
 | /* the current implementation uses Linux's epoll facility | 
 |  * the event mask we use are simply combinations of EPOLLIN | 
 |  * EPOLLOUT, EPOLLHUP and EPOLLERR | 
 |  */ | 
 | #include <sys/epoll.h> | 
 |  | 
 | #define  MAX_CHANNELS  16 | 
 | #define  MAX_EVENTS    (MAX_CHANNELS+1)  /* each channel + the serial fd */ | 
 |  | 
 | /* the event handler function type, 'user' is a user-specific | 
 |  * opaque pointer passed to looper_add(). | 
 |  */ | 
 | typedef void (*EventFunc)( void*  user, int  events ); | 
 |  | 
 | /* bit flags for the LoopHook structure. | 
 |  * | 
 |  * HOOK_PENDING means that an event happened on the | 
 |  * corresponding file descriptor. | 
 |  * | 
 |  * HOOK_CLOSING is used to delay-close monitored | 
 |  * file descriptors. | 
 |  */ | 
 | enum { | 
 |     HOOK_PENDING = (1 << 0), | 
 |     HOOK_CLOSING = (1 << 1), | 
 | }; | 
 |  | 
 | /* A LoopHook structure is used to monitor a given | 
 |  * file descriptor and record its event handler. | 
 |  */ | 
 | typedef struct { | 
 |     int        fd; | 
 |     int        wanted;  /* events we are monitoring */ | 
 |     int        events;  /* events that occured */ | 
 |     int        state;   /* see HOOK_XXX constants */ | 
 |     void*      ev_user; /* user-provided handler parameter */ | 
 |     EventFunc  ev_func; /* event handler callback */ | 
 | } LoopHook; | 
 |  | 
 | /* Looper is the main object modeling a looper object | 
 |  */ | 
 | typedef struct { | 
 |     int                  epoll_fd; | 
 |     int                  num_fds; | 
 |     int                  max_fds; | 
 |     struct epoll_event*  events; | 
 |     LoopHook*            hooks; | 
 | } Looper; | 
 |  | 
 | /* initialize a looper object */ | 
 | static void | 
 | looper_init( Looper*  l ) | 
 | { | 
 |     l->epoll_fd = epoll_create(4); | 
 |     l->num_fds  = 0; | 
 |     l->max_fds  = 0; | 
 |     l->events   = NULL; | 
 |     l->hooks    = NULL; | 
 | } | 
 |  | 
 | /* finalize a looper object */ | 
 | static void | 
 | looper_done( Looper*  l ) | 
 | { | 
 |     xfree(l->events); | 
 |     xfree(l->hooks); | 
 |     l->max_fds = 0; | 
 |     l->num_fds = 0; | 
 |  | 
 |     close(l->epoll_fd); | 
 |     l->epoll_fd  = -1; | 
 | } | 
 |  | 
 | /* return the LoopHook corresponding to a given | 
 |  * monitored file descriptor, or NULL if not found | 
 |  */ | 
 | static LoopHook* | 
 | looper_find( Looper*  l, int  fd ) | 
 | { | 
 |     LoopHook*  hook = l->hooks; | 
 |     LoopHook*  end  = hook + l->num_fds; | 
 |  | 
 |     for ( ; hook < end; hook++ ) { | 
 |         if (hook->fd == fd) | 
 |             return hook; | 
 |     } | 
 |     return NULL; | 
 | } | 
 |  | 
 | /* grow the arrays in the looper object */ | 
 | static void | 
 | looper_grow( Looper*  l ) | 
 | { | 
 |     int  old_max = l->max_fds; | 
 |     int  new_max = old_max + (old_max >> 1) + 4; | 
 |     int  n; | 
 |  | 
 |     xrenew( l->events, new_max ); | 
 |     xrenew( l->hooks,  new_max ); | 
 |     l->max_fds = new_max; | 
 |  | 
 |     /* now change the handles to all events */ | 
 |     for (n = 0; n < l->num_fds; n++) { | 
 |         struct epoll_event ev; | 
 |         LoopHook*          hook = l->hooks + n; | 
 |  | 
 |         ev.events   = hook->wanted; | 
 |         ev.data.ptr = hook; | 
 |         epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, hook->fd, &ev ); | 
 |     } | 
 | } | 
 |  | 
 | /* register a file descriptor and its event handler. | 
 |  * no event mask will be enabled | 
 |  */ | 
 | static void | 
 | looper_add( Looper*  l, int  fd, EventFunc  func, void*  user ) | 
 | { | 
 |     struct epoll_event  ev; | 
 |     LoopHook*           hook; | 
 |  | 
 |     if (l->num_fds >= l->max_fds) | 
 |         looper_grow(l); | 
 |  | 
 |     hook = l->hooks + l->num_fds; | 
 |  | 
 |     hook->fd      = fd; | 
 |     hook->ev_user = user; | 
 |     hook->ev_func = func; | 
 |     hook->state   = 0; | 
 |     hook->wanted  = 0; | 
 |     hook->events  = 0; | 
 |  | 
 |     fd_setnonblock(fd); | 
 |  | 
 |     ev.events   = 0; | 
 |     ev.data.ptr = hook; | 
 |     epoll_ctl( l->epoll_fd, EPOLL_CTL_ADD, fd, &ev ); | 
 |  | 
 |     l->num_fds += 1; | 
 | } | 
 |  | 
 | /* unregister a file descriptor and its event handler | 
 |  */ | 
 | static void | 
 | looper_del( Looper*  l, int  fd ) | 
 | { | 
 |     LoopHook*  hook = looper_find( l, fd ); | 
 |  | 
 |     if (!hook) { | 
 |         D( "%s: invalid fd: %d", __FUNCTION__, fd ); | 
 |         return; | 
 |     } | 
 |     /* don't remove the hook yet */ | 
 |     hook->state |= HOOK_CLOSING; | 
 |  | 
 |     epoll_ctl( l->epoll_fd, EPOLL_CTL_DEL, fd, NULL ); | 
 | } | 
 |  | 
 | /* enable monitoring of certain events for a file | 
 |  * descriptor. This adds 'events' to the current | 
 |  * event mask | 
 |  */ | 
 | static void | 
 | looper_enable( Looper*  l, int  fd, int  events ) | 
 | { | 
 |     LoopHook*  hook = looper_find( l, fd ); | 
 |  | 
 |     if (!hook) { | 
 |         D("%s: invalid fd: %d", __FUNCTION__, fd ); | 
 |         return; | 
 |     } | 
 |  | 
 |     if (events & ~hook->wanted) { | 
 |         struct epoll_event  ev; | 
 |  | 
 |         hook->wanted |= events; | 
 |         ev.events   = hook->wanted; | 
 |         ev.data.ptr = hook; | 
 |  | 
 |         epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, fd, &ev ); | 
 |     } | 
 | } | 
 |  | 
 | /* disable monitoring of certain events for a file | 
 |  * descriptor. This ignores events that are not | 
 |  * currently enabled. | 
 |  */ | 
 | static void | 
 | looper_disable( Looper*  l, int  fd, int  events ) | 
 | { | 
 |     LoopHook*  hook = looper_find( l, fd ); | 
 |  | 
 |     if (!hook) { | 
 |         D("%s: invalid fd: %d", __FUNCTION__, fd ); | 
 |         return; | 
 |     } | 
 |  | 
 |     if (events & hook->wanted) { | 
 |         struct epoll_event  ev; | 
 |  | 
 |         hook->wanted &= ~events; | 
 |         ev.events   = hook->wanted; | 
 |         ev.data.ptr = hook; | 
 |  | 
 |         epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, fd, &ev ); | 
 |     } | 
 | } | 
 |  | 
 | /* wait until an event occurs on one of the registered file | 
 |  * descriptors. Only returns in case of error !! | 
 |  */ | 
 | static void | 
 | looper_loop( Looper*  l ) | 
 | { | 
 |     for (;;) { | 
 |         int  n, count; | 
 |  | 
 |         do { | 
 |             count = epoll_wait( l->epoll_fd, l->events, l->num_fds, -1 ); | 
 |         } while (count < 0 && errno == EINTR); | 
 |  | 
 |         if (count < 0) { | 
 |             D("%s: error: %s", __FUNCTION__, strerror(errno) ); | 
 |             return; | 
 |         } | 
 |  | 
 |         if (count == 0) { | 
 |             D("%s: huh ? epoll returned count=0", __FUNCTION__); | 
 |             continue; | 
 |         } | 
 |  | 
 |         /* mark all pending hooks */ | 
 |         for (n = 0; n < count; n++) { | 
 |             LoopHook*  hook = l->events[n].data.ptr; | 
 |             hook->state  = HOOK_PENDING; | 
 |             hook->events = l->events[n].events; | 
 |         } | 
 |  | 
 |         /* execute hook callbacks. this may change the 'hooks' | 
 |          * and 'events' array, as well as l->num_fds, so be careful */ | 
 |         for (n = 0; n < l->num_fds; n++) { | 
 |             LoopHook*  hook = l->hooks + n; | 
 |             if (hook->state & HOOK_PENDING) { | 
 |                 hook->state &= ~HOOK_PENDING; | 
 |                 hook->ev_func( hook->ev_user, hook->events ); | 
 |             } | 
 |         } | 
 |  | 
 |         /* now remove all the hooks that were closed by | 
 |          * the callbacks */ | 
 |         for (n = 0; n < l->num_fds;) { | 
 |             LoopHook*  hook = l->hooks + n; | 
 |  | 
 |             if (!(hook->state & HOOK_CLOSING)) { | 
 |                 n++; | 
 |                 continue; | 
 |             } | 
 |  | 
 |             hook[0]     = l->hooks[l->num_fds-1]; | 
 |             l->num_fds -= 1; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | #if T_ACTIVE | 
 | char* | 
 | quote( const void*  data, int  len ) | 
 | { | 
 |     const char*  p   = data; | 
 |     const char*  end = p + len; | 
 |     int          count = 0; | 
 |     int          phase = 0; | 
 |     static char*  buff = NULL; | 
 |  | 
 |     for (phase = 0; phase < 2; phase++) { | 
 |         if (phase != 0) { | 
 |             xfree(buff); | 
 |             buff = xalloc(count+1); | 
 |         } | 
 |         count = 0; | 
 |         for (p = data; p < end; p++) { | 
 |             int  c = *p; | 
 |  | 
 |             if (c == '\\') { | 
 |                 if (phase != 0) { | 
 |                     buff[count] = buff[count+1] = '\\'; | 
 |                 } | 
 |                 count += 2; | 
 |                 continue; | 
 |             } | 
 |  | 
 |             if (c >= 32 && c < 127) { | 
 |                 if (phase != 0) | 
 |                     buff[count] = c; | 
 |                 count += 1; | 
 |                 continue; | 
 |             } | 
 |  | 
 |  | 
 |             if (c == '\t') { | 
 |                 if (phase != 0) { | 
 |                     memcpy(buff+count, "<TAB>", 5); | 
 |                 } | 
 |                 count += 5; | 
 |                 continue; | 
 |             } | 
 |             if (c == '\n') { | 
 |                 if (phase != 0) { | 
 |                     memcpy(buff+count, "<LN>", 4); | 
 |                 } | 
 |                 count += 4; | 
 |                 continue; | 
 |             } | 
 |             if (c == '\r') { | 
 |                 if (phase != 0) { | 
 |                     memcpy(buff+count, "<CR>", 4); | 
 |                 } | 
 |                 count += 4; | 
 |                 continue; | 
 |             } | 
 |  | 
 |             if (phase != 0) { | 
 |                 buff[count+0] = '\\'; | 
 |                 buff[count+1] = 'x'; | 
 |                 buff[count+2] = "0123456789abcdef"[(c >> 4) & 15]; | 
 |                 buff[count+3] = "0123456789abcdef"[     (c) & 15]; | 
 |             } | 
 |             count += 4; | 
 |         } | 
 |     } | 
 |     buff[count] = 0; | 
 |     return buff; | 
 | } | 
 | #endif /* T_ACTIVE */ | 
 |  | 
 | /** PACKETS | 
 |  ** | 
 |  ** We need a way to buffer data before it can be sent to the | 
 |  ** corresponding file descriptor. We use linked list of Packet | 
 |  ** objects to do this. | 
 |  **/ | 
 |  | 
 | typedef struct Packet   Packet; | 
 |  | 
 | #define  MAX_PAYLOAD  4000 | 
 |  | 
 | struct Packet { | 
 |     Packet*   next; | 
 |     int       len; | 
 |     int       channel; | 
 |     uint8_t   data[ MAX_PAYLOAD ]; | 
 | }; | 
 |  | 
 | /* we expect to alloc/free a lot of packets during | 
 |  * operations so use a single linked list of free packets | 
 |  * to keep things speedy and simple. | 
 |  */ | 
 | static Packet*   _free_packets; | 
 |  | 
 | /* Allocate a packet */ | 
 | static Packet* | 
 | packet_alloc(void) | 
 | { | 
 |     Packet*  p = _free_packets; | 
 |     if (p != NULL) { | 
 |         _free_packets = p->next; | 
 |     } else { | 
 |         xnew(p); | 
 |     } | 
 |     p->next    = NULL; | 
 |     p->len     = 0; | 
 |     p->channel = -1; | 
 |     return p; | 
 | } | 
 |  | 
 | /* Release a packet. This takes the address of a packet | 
 |  * pointer that will be set to NULL on exit (avoids | 
 |  * referencing dangling pointers in case of bugs) | 
 |  */ | 
 | static void | 
 | packet_free( Packet*  *ppacket ) | 
 | { | 
 |     Packet*  p = *ppacket; | 
 |     if (p) { | 
 |         p->next       = _free_packets; | 
 |         _free_packets = p; | 
 |         *ppacket = NULL; | 
 |     } | 
 | } | 
 |  | 
 | /** PACKET RECEIVER | 
 |  ** | 
 |  ** Simple abstraction for something that can receive a packet | 
 |  ** from a FDHandler (see below) or something else. | 
 |  ** | 
 |  ** Send a packet to it with 'receiver_post' | 
 |  ** | 
 |  ** Call 'receiver_close' to indicate that the corresponding | 
 |  ** packet source was closed. | 
 |  **/ | 
 |  | 
 | typedef void (*PostFunc) ( void*  user, Packet*  p ); | 
 | typedef void (*CloseFunc)( void*  user ); | 
 |  | 
 | typedef struct { | 
 |     PostFunc   post; | 
 |     CloseFunc  close; | 
 |     void*      user; | 
 | } Receiver; | 
 |  | 
 | /* post a packet to a receiver. Note that this transfers | 
 |  * ownership of the packet to the receiver. | 
 |  */ | 
 | static __inline__ void | 
 | receiver_post( Receiver*  r, Packet*  p ) | 
 | { | 
 |     if (r->post) | 
 |         r->post( r->user, p ); | 
 |     else | 
 |         packet_free(&p); | 
 | } | 
 |  | 
 | /* tell a receiver the packet source was closed. | 
 |  * this will also prevent further posting to the | 
 |  * receiver. | 
 |  */ | 
 | static __inline__ void | 
 | receiver_close( Receiver*  r ) | 
 | { | 
 |     if (r->close) { | 
 |         r->close( r->user ); | 
 |         r->close = NULL; | 
 |     } | 
 |     r->post  = NULL; | 
 | } | 
 |  | 
 |  | 
 | /** FD HANDLERS | 
 |  ** | 
 |  ** these are smart listeners that send incoming packets to a receiver | 
 |  ** and can queue one or more outgoing packets and send them when | 
 |  ** possible to the FD. | 
 |  ** | 
 |  ** note that we support clean shutdown of file descriptors, | 
 |  ** i.e. we try to send all outgoing packets before destroying | 
 |  ** the FDHandler. | 
 |  **/ | 
 |  | 
 | typedef struct FDHandler      FDHandler; | 
 | typedef struct FDHandlerList  FDHandlerList; | 
 |  | 
 | struct FDHandler { | 
 |     int             fd; | 
 |     FDHandlerList*  list; | 
 |     char            closing; | 
 |     Receiver        receiver[1]; | 
 |  | 
 |     /* queue of outgoing packets */ | 
 |     int             out_pos; | 
 |     Packet*         out_first; | 
 |     Packet**        out_ptail; | 
 |  | 
 |     FDHandler*      next; | 
 |     FDHandler**     pref; | 
 |  | 
 | }; | 
 |  | 
 | struct FDHandlerList { | 
 |     /* the looper that manages the fds */ | 
 |     Looper*      looper; | 
 |  | 
 |     /* list of active FDHandler objects */ | 
 |     FDHandler*   active; | 
 |  | 
 |     /* list of closing FDHandler objects. | 
 |      * these are waiting to push their | 
 |      * queued packets to the fd before | 
 |      * freeing themselves. | 
 |      */ | 
 |     FDHandler*   closing; | 
 |  | 
 | }; | 
 |  | 
 | /* remove a FDHandler from its current list */ | 
 | static void | 
 | fdhandler_remove( FDHandler*  f ) | 
 | { | 
 |     f->pref[0] = f->next; | 
 |     if (f->next) | 
 |         f->next->pref = f->pref; | 
 | } | 
 |  | 
 | /* add a FDHandler to a given list */ | 
 | static void | 
 | fdhandler_prepend( FDHandler*  f, FDHandler**  list ) | 
 | { | 
 |     f->next = list[0]; | 
 |     f->pref = list; | 
 |     list[0] = f; | 
 |     if (f->next) | 
 |         f->next->pref = &f->next; | 
 | } | 
 |  | 
 | /* initialize a FDHandler list */ | 
 | static void | 
 | fdhandler_list_init( FDHandlerList*  list, Looper*  looper ) | 
 | { | 
 |     list->looper  = looper; | 
 |     list->active  = NULL; | 
 |     list->closing = NULL; | 
 | } | 
 |  | 
 |  | 
 | /* close a FDHandler (and free it). Note that this will not | 
 |  * perform a graceful shutdown, i.e. all packets in the | 
 |  * outgoing queue will be immediately free. | 
 |  * | 
 |  * this *will* notify the receiver that the file descriptor | 
 |  * was closed. | 
 |  * | 
 |  * you should call fdhandler_shutdown() if you want to | 
 |  * notify the FDHandler that its packet source is closed. | 
 |  */ | 
 | static void | 
 | fdhandler_close( FDHandler*  f ) | 
 | { | 
 |     /* notify receiver */ | 
 |     receiver_close(f->receiver); | 
 |  | 
 |     /* remove the handler from its list */ | 
 |     fdhandler_remove(f); | 
 |  | 
 |     /* get rid of outgoing packet queue */ | 
 |     if (f->out_first != NULL) { | 
 |         Packet*  p; | 
 |         while ((p = f->out_first) != NULL) { | 
 |             f->out_first = p->next; | 
 |             packet_free(&p); | 
 |         } | 
 |     } | 
 |  | 
 |     /* get rid of file descriptor */ | 
 |     if (f->fd >= 0) { | 
 |         looper_del( f->list->looper, f->fd ); | 
 |         close(f->fd); | 
 |         f->fd = -1; | 
 |     } | 
 |  | 
 |     f->list = NULL; | 
 |     xfree(f); | 
 | } | 
 |  | 
 | /* Ask the FDHandler to cleanly shutdown the connection, | 
 |  * i.e. send any pending outgoing packets then auto-free | 
 |  * itself. | 
 |  */ | 
 | static void | 
 | fdhandler_shutdown( FDHandler*  f ) | 
 | { | 
 |  | 
 |     if (f->out_first != NULL && !f->closing) | 
 |     { | 
 |         /* move the handler to the 'closing' list */ | 
 |         f->closing = 1; | 
 |         fdhandler_remove(f); | 
 |         fdhandler_prepend(f, &f->list->closing); | 
 |  | 
 |         /* notify the receiver that we're closing */ | 
 |         receiver_close(f->receiver); | 
 |         return; | 
 |     } | 
 |  | 
 |     fdhandler_close(f); | 
 | } | 
 |  | 
 | /* Enqueue a new packet that the FDHandler will | 
 |  * send through its file descriptor. | 
 |  */ | 
 | static void | 
 | fdhandler_enqueue( FDHandler*  f, Packet*  p ) | 
 | { | 
 |     Packet*  first = f->out_first; | 
 |  | 
 |     p->next         = NULL; | 
 |     f->out_ptail[0] = p; | 
 |     f->out_ptail    = &p->next; | 
 |  | 
 |     if (first == NULL) { | 
 |         f->out_pos = 0; | 
 |         looper_enable( f->list->looper, f->fd, EPOLLOUT ); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* FDHandler file descriptor event callback for read/write ops */ | 
 | static void | 
 | fdhandler_event( FDHandler*  f, int  events ) | 
 | { | 
 |    int  len; | 
 |  | 
 |     /* in certain cases, it's possible to have both EPOLLIN and | 
 |      * EPOLLHUP at the same time. This indicates that there is incoming | 
 |      * data to read, but that the connection was nonetheless closed | 
 |      * by the sender. Be sure to read the data before closing | 
 |      * the receiver to avoid packet loss. | 
 |      */ | 
 |  | 
 |     if (events & EPOLLIN) { | 
 |         Packet*  p = packet_alloc(); | 
 |         int      len; | 
 |  | 
 |         if ((len = fd_read(f->fd, p->data, MAX_PAYLOAD)) < 0) { | 
 |             D("%s: can't recv: %s", __FUNCTION__, strerror(errno)); | 
 |             packet_free(&p); | 
 |         } else if (len > 0) { | 
 |             p->len     = len; | 
 |             p->channel = -101;  /* special debug value, not used */ | 
 |             receiver_post( f->receiver, p ); | 
 |         } | 
 |     } | 
 |  | 
 |     if (events & (EPOLLHUP|EPOLLERR)) { | 
 |         /* disconnection */ | 
 |         D("%s: disconnect on fd %d", __FUNCTION__, f->fd); | 
 |         fdhandler_close(f); | 
 |         return; | 
 |     } | 
 |  | 
 |     if (events & EPOLLOUT && f->out_first) { | 
 |         Packet*  p = f->out_first; | 
 |         int      avail, len; | 
 |  | 
 |         avail = p->len - f->out_pos; | 
 |         if ((len = fd_write(f->fd, p->data + f->out_pos, avail)) < 0) { | 
 |             D("%s: can't send: %s", __FUNCTION__, strerror(errno)); | 
 |         } else { | 
 |             f->out_pos += len; | 
 |             if (f->out_pos >= p->len) { | 
 |                 f->out_pos   = 0; | 
 |                 f->out_first = p->next; | 
 |                 packet_free(&p); | 
 |                 if (f->out_first == NULL) { | 
 |                     f->out_ptail = &f->out_first; | 
 |                     looper_disable( f->list->looper, f->fd, EPOLLOUT ); | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Create a new FDHandler that monitors read/writes */ | 
 | static FDHandler* | 
 | fdhandler_new( int             fd, | 
 |                FDHandlerList*  list, | 
 |                Receiver*       receiver ) | 
 | { | 
 |     FDHandler*  f = xalloc0(sizeof(*f)); | 
 |  | 
 |     f->fd          = fd; | 
 |     f->list        = list; | 
 |     f->receiver[0] = receiver[0]; | 
 |     f->out_first   = NULL; | 
 |     f->out_ptail   = &f->out_first; | 
 |     f->out_pos     = 0; | 
 |  | 
 |     fdhandler_prepend(f, &list->active); | 
 |  | 
 |     looper_add( list->looper, fd, (EventFunc) fdhandler_event, f ); | 
 |     looper_enable( list->looper, fd, EPOLLIN ); | 
 |  | 
 |     return f; | 
 | } | 
 |  | 
 |  | 
 | /* event callback function to monitor accepts() on server sockets. | 
 |  * the convention used here is that the receiver will receive a | 
 |  * dummy packet with the new client socket in p->channel | 
 |  */ | 
 | static void | 
 | fdhandler_accept_event( FDHandler*  f, int  events ) | 
 | { | 
 |     if (events & EPOLLIN) { | 
 |         /* this is an accept - send a dummy packet to the receiver */ | 
 |         Packet*  p = packet_alloc(); | 
 |  | 
 |         D("%s: accepting on fd %d", __FUNCTION__, f->fd); | 
 |         p->data[0] = 1; | 
 |         p->len     = 1; | 
 |         p->channel = fd_accept(f->fd); | 
 |         if (p->channel < 0) { | 
 |             D("%s: accept failed ?: %s", __FUNCTION__, strerror(errno)); | 
 |             packet_free(&p); | 
 |             return; | 
 |         } | 
 |         receiver_post( f->receiver, p ); | 
 |     } | 
 |  | 
 |     if (events & (EPOLLHUP|EPOLLERR)) { | 
 |         /* disconnecting !! */ | 
 |         D("%s: closing accept fd %d", __FUNCTION__, f->fd); | 
 |         fdhandler_close(f); | 
 |         return; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Create a new FDHandler used to monitor new connections on a | 
 |  * server socket. The receiver must expect the new connection | 
 |  * fd in the 'channel' field of a dummy packet. | 
 |  */ | 
 | static FDHandler* | 
 | fdhandler_new_accept( int             fd, | 
 |                       FDHandlerList*  list, | 
 |                       Receiver*       receiver ) | 
 | { | 
 |     FDHandler*  f = xalloc0(sizeof(*f)); | 
 |  | 
 |     f->fd          = fd; | 
 |     f->list        = list; | 
 |     f->receiver[0] = receiver[0]; | 
 |  | 
 |     fdhandler_prepend(f, &list->active); | 
 |  | 
 |     looper_add( list->looper, fd, (EventFunc) fdhandler_accept_event, f ); | 
 |     looper_enable( list->looper, fd, EPOLLIN ); | 
 |     listen( fd, 5 ); | 
 |  | 
 |     return f; | 
 | } | 
 |  | 
 | /** SERIAL CONNECTION STATE | 
 |  ** | 
 |  ** The following is used to handle the framing protocol | 
 |  ** used on the serial port connection. | 
 |  **/ | 
 |  | 
 | /* each packet is made of a 6 byte header followed by a payload | 
 |  * the header looks like: | 
 |  * | 
 |  *   offset   size    description | 
 |  *       0       2    a 2-byte hex string for the channel number | 
 |  *       4       4    a 4-char hex string for the size of the payload | 
 |  *       6       n    the payload itself | 
 |  */ | 
 | #define  HEADER_SIZE    6 | 
 | #define  CHANNEL_OFFSET 0 | 
 | #define  LENGTH_OFFSET  2 | 
 | #define  CHANNEL_SIZE   2 | 
 | #define  LENGTH_SIZE    4 | 
 |  | 
 | #define  CHANNEL_CONTROL  0 | 
 |  | 
 | /* The Serial object receives data from the serial port, | 
 |  * extracts the payload size and channel index, then sends | 
 |  * the resulting messages as a packet to a generic receiver. | 
 |  * | 
 |  * You can also use serial_send to send a packet through | 
 |  * the serial port. | 
 |  */ | 
 | typedef struct Serial { | 
 |     FDHandler*  fdhandler;   /* used to monitor serial port fd */ | 
 |     Receiver    receiver[1]; /* send payload there */ | 
 |     int         in_len;      /* current bytes in input packet */ | 
 |     int         in_datalen;  /* payload size, or 0 when reading header */ | 
 |     int         in_channel;  /* extracted channel number */ | 
 |     Packet*     in_packet;   /* used to read incoming packets */ | 
 | } Serial; | 
 |  | 
 |  | 
 | /* a callback called when the serial port's fd is closed */ | 
 | static void | 
 | serial_fd_close( Serial*  s ) | 
 | { | 
 |     fatal("unexpected serial port close !!"); | 
 | } | 
 |  | 
 | static void | 
 | serial_dump( Packet*  p, const char*  funcname ) | 
 | { | 
 |     T("%s: %03d bytes: '%s'", | 
 |       funcname, p->len, quote(p->data, p->len)); | 
 | } | 
 |  | 
 | /* a callback called when a packet arrives from the serial port's FDHandler. | 
 |  * | 
 |  * This will essentially parse the header, extract the channel number and | 
 |  * the payload size and store them in 'in_datalen' and 'in_channel'. | 
 |  * | 
 |  * After that, the payload is sent to the receiver once completed. | 
 |  */ | 
 | static void | 
 | serial_fd_receive( Serial*  s, Packet*  p ) | 
 | { | 
 |     int      rpos  = 0, rcount = p->len; | 
 |     Packet*  inp   = s->in_packet; | 
 |     int      inpos = s->in_len; | 
 |  | 
 |     serial_dump( p, __FUNCTION__ ); | 
 |  | 
 |     while (rpos < rcount) | 
 |     { | 
 |         int  avail = rcount - rpos; | 
 |  | 
 |         /* first, try to read the header */ | 
 |         if (s->in_datalen == 0) { | 
 |             int  wanted = HEADER_SIZE - inpos; | 
 |             if (avail > wanted) | 
 |                 avail = wanted; | 
 |  | 
 |             memcpy( inp->data + inpos, p->data + rpos, avail ); | 
 |             inpos += avail; | 
 |             rpos  += avail; | 
 |  | 
 |             if (inpos == HEADER_SIZE) { | 
 |                 s->in_datalen = hex2int( inp->data + LENGTH_OFFSET,  LENGTH_SIZE ); | 
 |                 s->in_channel = hex2int( inp->data + CHANNEL_OFFSET, CHANNEL_SIZE ); | 
 |  | 
 |                 if (s->in_datalen <= 0) { | 
 |                     D("ignoring %s packet from serial port", | 
 |                       s->in_datalen ? "empty" : "malformed"); | 
 |                     s->in_datalen = 0; | 
 |                 } | 
 |  | 
 |                 //D("received %d bytes packet for channel %d", s->in_datalen, s->in_channel); | 
 |                 inpos = 0; | 
 |             } | 
 |         } | 
 |         else /* then, populate the packet itself */ | 
 |         { | 
 |             int   wanted = s->in_datalen - inpos; | 
 |  | 
 |             if (avail > wanted) | 
 |                 avail = wanted; | 
 |  | 
 |             memcpy( inp->data + inpos, p->data + rpos, avail ); | 
 |             inpos += avail; | 
 |             rpos  += avail; | 
 |  | 
 |             if (inpos == s->in_datalen) { | 
 |                 if (s->in_channel < 0) { | 
 |                     D("ignoring %d bytes addressed to channel %d", | 
 |                        inpos, s->in_channel); | 
 |                 } else { | 
 |                     inp->len     = inpos; | 
 |                     inp->channel = s->in_channel; | 
 |                     receiver_post( s->receiver, inp ); | 
 |                     s->in_packet  = inp = packet_alloc(); | 
 |                 } | 
 |                 s->in_datalen = 0; | 
 |                 inpos         = 0; | 
 |             } | 
 |         } | 
 |     } | 
 |     s->in_len = inpos; | 
 |     packet_free(&p); | 
 | } | 
 |  | 
 |  | 
 | /* send a packet to the serial port. | 
 |  * this assumes that p->len and p->channel contain the payload's | 
 |  * size and channel and will add the appropriate header. | 
 |  */ | 
 | static void | 
 | serial_send( Serial*  s, Packet*  p ) | 
 | { | 
 |     Packet*  h = packet_alloc(); | 
 |  | 
 |     //D("sending to serial %d bytes from channel %d: '%.*s'", p->len, p->channel, p->len, p->data); | 
 |  | 
 |     /* insert a small header before this packet */ | 
 |     h->len = HEADER_SIZE; | 
 |     int2hex( p->len,     h->data + LENGTH_OFFSET,  LENGTH_SIZE ); | 
 |     int2hex( p->channel, h->data + CHANNEL_OFFSET, CHANNEL_SIZE ); | 
 |  | 
 |     serial_dump( h, __FUNCTION__ ); | 
 |     serial_dump( p, __FUNCTION__ ); | 
 |  | 
 |     fdhandler_enqueue( s->fdhandler, h ); | 
 |     fdhandler_enqueue( s->fdhandler, p ); | 
 | } | 
 |  | 
 |  | 
 | /* initialize serial reader */ | 
 | static void | 
 | serial_init( Serial*         s, | 
 |              int             fd, | 
 |              FDHandlerList*  list, | 
 |              Receiver*       receiver ) | 
 | { | 
 |     Receiver  recv; | 
 |  | 
 |     recv.user  = s; | 
 |     recv.post  = (PostFunc)  serial_fd_receive; | 
 |     recv.close = (CloseFunc) serial_fd_close; | 
 |  | 
 |     s->receiver[0] = receiver[0]; | 
 |  | 
 |     s->fdhandler = fdhandler_new( fd, list, &recv ); | 
 |     s->in_len     = 0; | 
 |     s->in_datalen = 0; | 
 |     s->in_channel = 0; | 
 |     s->in_packet  = packet_alloc(); | 
 | } | 
 |  | 
 |  | 
 | /** CLIENTS | 
 |  **/ | 
 |  | 
 | typedef struct Client       Client; | 
 | typedef struct Multiplexer  Multiplexer; | 
 |  | 
 | /* A Client object models a single qemud client socket | 
 |  * connection in the emulated system. | 
 |  * | 
 |  * the client first sends the name of the system service | 
 |  * it wants to contact (no framing), then waits for a 2 | 
 |  * byte answer from qemud. | 
 |  * | 
 |  * the answer is either "OK" or "KO" to indicate | 
 |  * success or failure. | 
 |  * | 
 |  * In case of success, the client can send messages | 
 |  * to the service. | 
 |  * | 
 |  * In case of failure, it can disconnect or try sending | 
 |  * the name of another service. | 
 |  */ | 
 | struct Client { | 
 |     Client*       next; | 
 |     Client**      pref; | 
 |     int           channel; | 
 |     char          registered; | 
 |     FDHandler*    fdhandler; | 
 |     Multiplexer*  multiplexer; | 
 | }; | 
 |  | 
 | struct Multiplexer { | 
 |     Client*        clients; | 
 |     int            last_channel; | 
 |     Serial         serial[1]; | 
 |     Looper         looper[1]; | 
 |     FDHandlerList  fdhandlers[1]; | 
 | }; | 
 |  | 
 |  | 
 | static int   multiplexer_open_channel( Multiplexer*  mult, Packet*  p ); | 
 | static void  multiplexer_close_channel( Multiplexer*  mult, int  channel ); | 
 | static void  multiplexer_serial_send( Multiplexer* mult, int  channel, Packet*  p ); | 
 |  | 
 | static void | 
 | client_dump( Client*  c, Packet*  p, const char*  funcname ) | 
 | { | 
 |     T("%s: client %p (%d): %3d bytes: '%s'", | 
 |       funcname, c, c->fdhandler->fd, | 
 |       p->len, quote(p->data, p->len)); | 
 | } | 
 |  | 
 | /* destroy a client */ | 
 | static void | 
 | client_free( Client*  c ) | 
 | { | 
 |     /* remove from list */ | 
 |     c->pref[0] = c->next; | 
 |     if (c->next) | 
 |         c->next->pref = c->pref; | 
 |  | 
 |     c->channel    = -1; | 
 |     c->registered = 0; | 
 |  | 
 |     /* gently ask the FDHandler to shutdown to | 
 |      * avoid losing queued outgoing packets */ | 
 |     if (c->fdhandler != NULL) { | 
 |         fdhandler_shutdown(c->fdhandler); | 
 |         c->fdhandler = NULL; | 
 |     } | 
 |  | 
 |     xfree(c); | 
 | } | 
 |  | 
 |  | 
 | /* a function called when a client socket receives data */ | 
 | static void | 
 | client_fd_receive( Client*  c, Packet*  p ) | 
 | { | 
 |     client_dump(c, p, __FUNCTION__); | 
 |  | 
 |     if (c->registered) { | 
 |         /* the client is registered, just send the | 
 |          * data through the serial port | 
 |          */ | 
 |         multiplexer_serial_send(c->multiplexer, c->channel, p); | 
 |         return; | 
 |     } | 
 |  | 
 |     if (c->channel > 0) { | 
 |         /* the client is waiting registration results. | 
 |          * this should not happen because the client | 
 |          * should wait for our 'ok' or 'ko'. | 
 |          * close the connection. | 
 |          */ | 
 |          D("%s: bad client sending data before end of registration", | 
 |            __FUNCTION__); | 
 |      BAD_CLIENT: | 
 |          packet_free(&p); | 
 |          client_free(c); | 
 |          return; | 
 |     } | 
 |  | 
 |     /* the client hasn't registered a service yet, | 
 |      * so this must be the name of a service, call | 
 |      * the multiplexer to start registration for | 
 |      * it. | 
 |      */ | 
 |     D("%s: attempting registration for service '%.*s'", | 
 |       __FUNCTION__, p->len, p->data); | 
 |     c->channel = multiplexer_open_channel(c->multiplexer, p); | 
 |     if (c->channel < 0) { | 
 |         D("%s: service name too long", __FUNCTION__); | 
 |         goto BAD_CLIENT; | 
 |     } | 
 |     D("%s:    -> received channel id %d", __FUNCTION__, c->channel); | 
 |     packet_free(&p); | 
 | } | 
 |  | 
 |  | 
 | /* a function called when the client socket is closed. */ | 
 | static void | 
 | client_fd_close( Client*  c ) | 
 | { | 
 |     T("%s: client %p (%d)", __FUNCTION__, c, c->fdhandler->fd); | 
 |  | 
 |     /* no need to shutdown the FDHandler */ | 
 |     c->fdhandler = NULL; | 
 |  | 
 |     /* tell the emulator we're out */ | 
 |     if (c->channel > 0) | 
 |         multiplexer_close_channel(c->multiplexer, c->channel); | 
 |  | 
 |     /* free the client */ | 
 |     client_free(c); | 
 | } | 
 |  | 
 | /* a function called when the multiplexer received a registration | 
 |  * response from the emulator for a given client. | 
 |  */ | 
 | static void | 
 | client_registration( Client*  c, int  registered ) | 
 | { | 
 |     Packet*  p = packet_alloc(); | 
 |  | 
 |     /* sends registration status to client */ | 
 |     if (!registered) { | 
 |         D("%s: registration failed for client %d", __FUNCTION__, c->channel); | 
 |         memcpy( p->data, "KO", 2 ); | 
 |         p->len = 2; | 
 |     } else { | 
 |         D("%s: registration succeeded for client %d", __FUNCTION__, c->channel); | 
 |         memcpy( p->data, "OK", 2 ); | 
 |         p->len = 2; | 
 |     } | 
 |     client_dump(c, p, __FUNCTION__); | 
 |     fdhandler_enqueue(c->fdhandler, p); | 
 |  | 
 |     /* now save registration state | 
 |      */ | 
 |     c->registered = registered; | 
 |     if (!registered) { | 
 |         /* allow the client to try registering another service */ | 
 |         c->channel = -1; | 
 |     } | 
 | } | 
 |  | 
 | /* send data to a client */ | 
 | static void | 
 | client_send( Client*  c, Packet*  p ) | 
 | { | 
 |     client_dump(c, p, __FUNCTION__); | 
 |     fdhandler_enqueue(c->fdhandler, p); | 
 | } | 
 |  | 
 |  | 
 | /* Create new client socket handler */ | 
 | static Client* | 
 | client_new( Multiplexer*    mult, | 
 |             int             fd, | 
 |             FDHandlerList*  pfdhandlers, | 
 |             Client**        pclients ) | 
 | { | 
 |     Client*   c; | 
 |     Receiver  recv; | 
 |  | 
 |     xnew(c); | 
 |  | 
 |     c->multiplexer = mult; | 
 |     c->next        = NULL; | 
 |     c->pref        = &c->next; | 
 |     c->channel     = -1; | 
 |     c->registered  = 0; | 
 |  | 
 |     recv.user  = c; | 
 |     recv.post  = (PostFunc)  client_fd_receive; | 
 |     recv.close = (CloseFunc) client_fd_close; | 
 |  | 
 |     c->fdhandler = fdhandler_new( fd, pfdhandlers, &recv ); | 
 |  | 
 |     /* add to client list */ | 
 |     c->next   = *pclients; | 
 |     c->pref   = pclients; | 
 |     *pclients = c; | 
 |     if (c->next) | 
 |         c->next->pref = &c->next; | 
 |  | 
 |     return c; | 
 | } | 
 |  | 
 | /**  GLOBAL MULTIPLEXER | 
 |  **/ | 
 |  | 
 | /* find a client by its channel */ | 
 | static Client* | 
 | multiplexer_find_client( Multiplexer*  mult, int  channel ) | 
 | { | 
 |     Client* c = mult->clients; | 
 |  | 
 |     for ( ; c != NULL; c = c->next ) { | 
 |         if (c->channel == channel) | 
 |             return c; | 
 |     } | 
 |     return NULL; | 
 | } | 
 |  | 
 | /* handle control messages coming from the serial port | 
 |  * on CONTROL_CHANNEL. | 
 |  */ | 
 | static void | 
 | multiplexer_handle_control( Multiplexer*  mult, Packet*  p ) | 
 | { | 
 |     /* connection registration success */ | 
 |     if (p->len == 13 && !memcmp(p->data, "ok:connect:", 11)) { | 
 |         int      channel = hex2int(p->data+11, 2); | 
 |         Client*  client  = multiplexer_find_client(mult, channel); | 
 |  | 
 |         /* note that 'client' can be NULL if the corresponding | 
 |          * socket was closed before the emulator response arrived. | 
 |          */ | 
 |         if (client != NULL) { | 
 |             client_registration(client, 1); | 
 |         } else { | 
 |             D("%s: NULL client: '%.*s'", __FUNCTION__, p->len, p->data+11); | 
 |         } | 
 |         goto EXIT; | 
 |     } | 
 |  | 
 |     /* connection registration failure */ | 
 |     if (p->len == 13 && !memcmp(p->data, "ko:connect:",11)) { | 
 |         int     channel = hex2int(p->data+11, 2); | 
 |         Client* client  = multiplexer_find_client(mult, channel); | 
 |  | 
 |         if (client != NULL) | 
 |             client_registration(client, 0); | 
 |  | 
 |         goto EXIT; | 
 |     } | 
 |  | 
 |     /* emulator-induced client disconnection */ | 
 |     if (p->len == 13 && !memcmp(p->data, "disconnect:",11)) { | 
 |         int      channel = hex2int(p->data+11, 2); | 
 |         Client*  client  = multiplexer_find_client(mult, channel); | 
 |  | 
 |         if (client != NULL) | 
 |             client_free(client); | 
 |  | 
 |         goto EXIT; | 
 |     } | 
 |  | 
 |     /* A message that begins with "X00" is a probe sent by | 
 |      * the emulator used to detect which version of qemud it runs | 
 |      * against (in order to detect 1.0/1.1 system images. Just | 
 |      * silently ignore it there instead of printing an error | 
 |      * message. | 
 |      */ | 
 |     if (p->len >= 3 && !memcmp(p->data,"X00",3)) { | 
 |         goto EXIT; | 
 |     } | 
 |  | 
 |     D("%s: unknown control message (%d bytes): '%.*s'", | 
 |       __FUNCTION__, p->len, p->len, p->data); | 
 |  | 
 | EXIT: | 
 |     packet_free(&p); | 
 | } | 
 |  | 
 | /* a function called when an incoming packet comes from the serial port */ | 
 | static void | 
 | multiplexer_serial_receive( Multiplexer*  mult, Packet*  p ) | 
 | { | 
 |     Client*  client; | 
 |  | 
 |     T("%s: channel=%d '%.*s'", __FUNCTION__, p->channel, p->len, p->data); | 
 |  | 
 |     if (p->channel == CHANNEL_CONTROL) { | 
 |         multiplexer_handle_control(mult, p); | 
 |         return; | 
 |     } | 
 |  | 
 |     client = multiplexer_find_client(mult, p->channel); | 
 |     if (client != NULL) { | 
 |         client_send(client, p); | 
 |         return; | 
 |     } | 
 |  | 
 |     D("%s: discarding packet for unknown channel %d", __FUNCTION__, p->channel); | 
 |     packet_free(&p); | 
 | } | 
 |  | 
 | /* a function called when the serial reader closes */ | 
 | static void | 
 | multiplexer_serial_close( Multiplexer*  mult ) | 
 | { | 
 |     fatal("unexpected close of serial reader"); | 
 | } | 
 |  | 
 | /* a function called to send a packet to the serial port */ | 
 | static void | 
 | multiplexer_serial_send( Multiplexer*  mult, int  channel, Packet*  p ) | 
 | { | 
 |     p->channel = channel; | 
 |     serial_send( mult->serial, p ); | 
 | } | 
 |  | 
 |  | 
 |  | 
 | /* a function used by a client to allocate a new channel id and | 
 |  * ask the emulator to open it. 'service' must be a packet containing | 
 |  * the name of the service in its payload. | 
 |  * | 
 |  * returns -1 if the service name is too long. | 
 |  * | 
 |  * notice that client_registration() will be called later when | 
 |  * the answer arrives. | 
 |  */ | 
 | static int | 
 | multiplexer_open_channel( Multiplexer*  mult, Packet*  service ) | 
 | { | 
 |     Packet*   p = packet_alloc(); | 
 |     int       len, channel; | 
 |  | 
 |     /* find a free channel number, assume we don't have many | 
 |      * clients here. */ | 
 |     { | 
 |         Client*  c; | 
 |     TRY_AGAIN: | 
 |         channel = (++mult->last_channel) & 0xff; | 
 |  | 
 |         for (c = mult->clients; c != NULL; c = c->next) | 
 |             if (c->channel == channel) | 
 |                 goto TRY_AGAIN; | 
 |     } | 
 |  | 
 |     len = snprintf((char*)p->data, sizeof p->data, "connect:%.*s:%02x", service->len, service->data, channel); | 
 |     if (len >= (int)sizeof(p->data)) { | 
 |         D("%s: weird, service name too long (%d > %d)", __FUNCTION__, len, sizeof(p->data)); | 
 |         packet_free(&p); | 
 |         return -1; | 
 |     } | 
 |     p->channel = CHANNEL_CONTROL; | 
 |     p->len     = len; | 
 |  | 
 |     serial_send(mult->serial, p); | 
 |     return channel; | 
 | } | 
 |  | 
 | /* used to tell the emulator a channel was closed by a client */ | 
 | static void | 
 | multiplexer_close_channel( Multiplexer*  mult, int  channel ) | 
 | { | 
 |     Packet*  p   = packet_alloc(); | 
 |     int      len = snprintf((char*)p->data, sizeof(p->data), "disconnect:%02x", channel); | 
 |  | 
 |     if (len > (int)sizeof(p->data)) { | 
 |         /* should not happen */ | 
 |         return; | 
 |     } | 
 |  | 
 |     p->channel = CHANNEL_CONTROL; | 
 |     p->len     = len; | 
 |  | 
 |     serial_send(mult->serial, p); | 
 | } | 
 |  | 
 | /* this function is used when a new connection happens on the control | 
 |  * socket. | 
 |  */ | 
 | static void | 
 | multiplexer_control_accept( Multiplexer*  m, Packet*  p ) | 
 | { | 
 |     /* the file descriptor for the new socket connection is | 
 |      * in p->channel. See fdhandler_accept_event() */ | 
 |     int      fd     = p->channel; | 
 |     Client*  client = client_new( m, fd, m->fdhandlers, &m->clients ); | 
 |  | 
 |     D("created client %p listening on fd %d", client, fd); | 
 |  | 
 |     /* free dummy packet */ | 
 |     packet_free(&p); | 
 | } | 
 |  | 
 | static void | 
 | multiplexer_control_close( Multiplexer*  m ) | 
 | { | 
 |     fatal("unexpected multiplexer control close"); | 
 | } | 
 |  | 
 | static void | 
 | multiplexer_init( Multiplexer*  m, const char*  serial_dev ) | 
 | { | 
 |     int       fd, control_fd; | 
 |     Receiver  recv; | 
 |  | 
 |     /* initialize looper and fdhandlers list */ | 
 |     looper_init( m->looper ); | 
 |     fdhandler_list_init( m->fdhandlers, m->looper ); | 
 |  | 
 |     /* open the serial port */ | 
 |     do { | 
 |         fd = open(serial_dev, O_RDWR); | 
 |     } while (fd < 0 && errno == EINTR); | 
 |  | 
 |     if (fd < 0) { | 
 |         fatal( "%s: could not open '%s': %s", __FUNCTION__, serial_dev, | 
 |                strerror(errno) ); | 
 |     } | 
 |     // disable echo on serial lines | 
 |     if ( !memcmp( serial_dev, "/dev/ttyS", 9 ) ) { | 
 |         struct termios  ios; | 
 |         tcgetattr( fd, &ios ); | 
 |         ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */ | 
 |         tcsetattr( fd, TCSANOW, &ios ); | 
 |     } | 
 |  | 
 |     /* initialize the serial reader/writer */ | 
 |     recv.user  = m; | 
 |     recv.post  = (PostFunc)  multiplexer_serial_receive; | 
 |     recv.close = (CloseFunc) multiplexer_serial_close; | 
 |  | 
 |     serial_init( m->serial, fd, m->fdhandlers, &recv ); | 
 |  | 
 |     /* open the qemud control socket */ | 
 |     recv.user  = m; | 
 |     recv.post  = (PostFunc)  multiplexer_control_accept; | 
 |     recv.close = (CloseFunc) multiplexer_control_close; | 
 |  | 
 |     fd = android_get_control_socket(CONTROL_SOCKET_NAME); | 
 |     if (fd < 0) { | 
 |         fatal("couldn't get fd for control socket '%s'", CONTROL_SOCKET_NAME); | 
 |     } | 
 |  | 
 |     fdhandler_new_accept( fd, m->fdhandlers, &recv ); | 
 |  | 
 |     /* initialize clients list */ | 
 |     m->clients = NULL; | 
 | } | 
 |  | 
 | /** MAIN LOOP | 
 |  **/ | 
 |  | 
 | static Multiplexer  _multiplexer[1]; | 
 |  | 
 | int  main( void ) | 
 | { | 
 |     Multiplexer*  m = _multiplexer; | 
 |  | 
 |    /* extract the name of our serial device from the kernel | 
 |     * boot options that are stored in /proc/cmdline | 
 |     */ | 
 | #define  KERNEL_OPTION  "android.qemud=" | 
 |  | 
 |     { | 
 |         char          buff[1024]; | 
 |         int           fd, len; | 
 |         char*         p; | 
 |         char*         q; | 
 |  | 
 |         fd = open( "/proc/cmdline", O_RDONLY ); | 
 |         if (fd < 0) { | 
 |             D("%s: can't open /proc/cmdline !!: %s", __FUNCTION__, | 
 |             strerror(errno)); | 
 |             exit(1); | 
 |         } | 
 |  | 
 |         len = fd_read( fd, buff, sizeof(buff)-1 ); | 
 |         close(fd); | 
 |         if (len < 0) { | 
 |             D("%s: can't read /proc/cmdline: %s", __FUNCTION__, | 
 |             strerror(errno)); | 
 |             exit(1); | 
 |         } | 
 |         buff[len] = 0; | 
 |  | 
 |         p = strstr( buff, KERNEL_OPTION ); | 
 |         if (p == NULL) { | 
 |             D("%s: can't find '%s' in /proc/cmdline", | 
 |             __FUNCTION__, KERNEL_OPTION ); | 
 |             exit(1); | 
 |         } | 
 |  | 
 |         p += sizeof(KERNEL_OPTION)-1;  /* skip option */ | 
 |         q  = p; | 
 |         while ( *q && *q != ' ' && *q != '\t' ) | 
 |             q += 1; | 
 |  | 
 |         snprintf( buff, sizeof(buff), "/dev/%.*s", q-p, p ); | 
 |  | 
 |         multiplexer_init( m, buff ); | 
 |     } | 
 |  | 
 |     D( "entering main loop"); | 
 |     looper_loop( m->looper ); | 
 |     D( "unexpected termination !!" ); | 
 |     return 0; | 
 | } |