|  | #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 ) | 
|  | { | 
|  | /* prevent later fdhandler_close() to | 
|  | * call the receiver's close. | 
|  | */ | 
|  | f->receiver->close = NULL; | 
|  |  | 
|  | 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); | 
|  | 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; | 
|  | } |