Merge "Enable QEMUD over pipe."
diff --git a/android/hw-qemud.c b/android/hw-qemud.c
index e91ec78..16deae8 100644
--- a/android/hw-qemud.c
+++ b/android/hw-qemud.c
@@ -14,12 +14,15 @@
 #include "android/utils/misc.h"
 #include "android/utils/system.h"
 #include "android/utils/bufprint.h"
+#include "android/looper.h"
 #include "hw/hw.h"
+#include "hw/goldfish_pipe.h"
 #include "qemu-char.h"
 #include "charpipe.h"
 #include "cbuffer.h"
 
-#define  D(...)    VERBOSE_PRINT(qemud,__VA_ARGS__)
+//#define  D(...)    VERBOSE_PRINT(qemud,__VA_ARGS__)
+#define  D(...)    printf(__VA_ARGS__), printf("\n")
 #define  D_ACTIVE  VERBOSE_CHECK(qemud)
 
 /* the T(...) macro is used to dump traffic */
@@ -575,18 +578,54 @@
 /** CLIENTS
  **/
 
-/* A QemudClient models a single client as seen by the emulator.
- * Each client has its own channel id, and belongs to a given
- * QemudService (see below).
+/* Descriptor for a data buffer pending to be sent to a qemud pipe client.
  *
- * There is a global list of clients used to multiplex incoming
- * messages from the channel id (see qemud_multiplexer_serial_recv()).
+ * When a service decides to send data to the client, there could be cases when
+ * client is not ready to read them. In this case there is no GoldfishPipeBuffer
+ * available to write service's data to, So, we need to cache that data into the
+ * client descriptor, and "send" them over to the client in _qemudPipe_recvBuffers
+ * callback. Pending service data is stored in the client descriptor as a list
+ * of QemudPipeMessage instances.
+ */
+typedef struct QemudPipeMessage QemudPipeMessage;
+struct QemudPipeMessage {
+    /* Message to send. */
+    uint8_t*            message;
+    /* Message size. */
+    size_t              size;
+    /* Offset in the message buffer of the chunk, that has not been sent
+     * to the pipe yet. */
+    size_t              offset;
+    /* Links next message in the client. */
+    QemudPipeMessage*   next;
+};
+
+
+/* A QemudClient models a single client as seen by the emulator.
+ * Each client has its own channel id (for the serial qemud), or pipe descriptor
+ * (for the pipe based qemud), and belongs to a given QemudService (see below).
+ *
+ * There is a global list of serial clients used to multiplex incoming
+ * messages from the channel id (see qemud_multiplexer_serial_recv()). Pipe
+ * clients don't need multiplexing, because they are communicated via qemud pipes
+ * that are unique for each client.
  *
  */
 
+/* Defines type of the client: pipe, or serial.
+ */
+typedef enum QemudProtocol {
+    /* Client is communicating via pipe. */
+    QEMUD_PROTOCOL_PIPE,
+    /* Client is communicating via serial port. */
+    QEMUD_PROTOCOL_SERIAL
+} QemudProtocol;
+
 struct QemudClient {
-    int               channel;
-    QemudSerial*      serial;
+    /* Defines protocol, used by the client. */
+    QemudProtocol     protocol;
+
+    /* Fields that are common for all protocols. */
     void*             clie_opaque;
     QemudClientRecv   clie_recv;
     QemudClientClose  clie_close;
@@ -604,8 +643,28 @@
     QemudSink         header[1];
     uint8_t           header0[FRAME_HEADER_SIZE];
     QemudSink         payload[1];
+
+    /* Fields that are protocol-specific. */
+    union {
+        /* Serial-specific fields. */
+        struct {
+            int                 channel;
+            QemudSerial*        serial;
+        } Serial;
+        /* Pipe-specific fields. */
+        struct {
+            void*               hwpipe;
+            QemudPipeMessage*   messages;
+        } Pipe;
+    } ProtocolSelector;
 };
 
+static ABool
+_is_pipe_client(QemudClient* client)
+{
+    return (client-> protocol == QEMUD_PROTOCOL_PIPE) ? true : false;
+}
+
 static void  qemud_service_remove_client( QemudService*  service,
                                           QemudClient*   client );
 
@@ -716,6 +775,11 @@
     }
 }
 
+/* Sends data to a pipe-based client.
+ */
+static void
+_qemud_pipe_send(QemudClient*  client, const uint8_t*  msg, int  msglen);
+
 /* disconnect a client. this automatically frees the QemudClient.
  * note that this also removes the client from the global list
  * and from its service's list, if any.
@@ -734,10 +798,15 @@
     qemud_client_remove(c);
 
     /* send a disconnect command to the daemon */
-    if (c->channel > 0) {
+    if (_is_pipe_client(c)) {
         char  tmp[128], *p=tmp, *end=p+sizeof(tmp);
-        p = bufprint(tmp, end, "disconnect:%02x", c->channel);
-        qemud_serial_send(c->serial, 0, 0, (uint8_t*)tmp, p-tmp);
+        p = bufprint(tmp, end, "disconnect:00");
+        _qemud_pipe_send(c, (uint8_t*)tmp, p-tmp);
+    } else if (c->ProtocolSelector.Serial.channel > 0) {
+        char  tmp[128], *p=tmp, *end=p+sizeof(tmp);
+        p = bufprint(tmp, end, "disconnect:%02x",
+                     c->ProtocolSelector.Serial.channel);
+        qemud_serial_send(c->ProtocolSelector.Serial.serial, 0, 0, (uint8_t*)tmp, p-tmp);
     }
 
     /* call the client close callback */
@@ -756,7 +825,10 @@
     AFREE(c);
 }
 
-/* allocate a new QemudClient object */
+/* allocate a new QemudClient object
+ * NOTE: channel_id valie is used as a selector between serial and pipe clients.
+ * Since channel_id < 0 is an invalid value for a serial client, it would
+ * indicate that creating client is a pipe client. */
 static QemudClient*
 qemud_client_alloc( int               channel_id,
                     void*             clie_opaque,
@@ -771,14 +843,25 @@
 
     ANEW0(c);
 
-    c->serial      = serial;
-    c->channel     = channel_id;
+    if (channel_id < 0) {
+        /* Allocating a pipe client. */
+        c->protocol = QEMUD_PROTOCOL_PIPE;
+        c->ProtocolSelector.Pipe.messages   = NULL;
+        c->ProtocolSelector.Pipe.hwpipe     = NULL;
+    } else {
+        /* Allocating a serial client. */
+        c->protocol = QEMUD_PROTOCOL_SERIAL;
+        c->ProtocolSelector.Serial.serial   = serial;
+        c->ProtocolSelector.Serial.channel  = channel_id;
+    }
     c->clie_opaque = clie_opaque;
     c->clie_recv   = clie_recv;
     c->clie_close  = clie_close;
     c->clie_save   = clie_save;
     c->clie_load   = clie_load;
-
+    c->service     = NULL;
+    c->next_serv   = NULL;
+    c->next        = NULL;
     c->framing     = 0;
     c->need_header = 1;
     qemud_sink_reset(c->header, FRAME_HEADER_SIZE, c->header0);
@@ -794,7 +877,7 @@
 static QemudService* qemud_service_find(  QemudService*  service_list,
                                           const char*    service_name );
 static QemudClient*  qemud_service_connect_client(  QemudService  *sv,
-                                                    int           channel_id );
+                                                    int           channel_id);
 
 /* Saves the client state needed to re-establish connections on load.
  */
@@ -803,7 +886,10 @@
 {
     /* save generic information */
     qemud_service_save_name(f, c->service);
-    qemu_put_be32(f, c->channel);
+    qemu_put_be32(f, c->protocol);
+    if (_is_pipe_client(c)) {
+        qemu_put_be32(f, c->ProtocolSelector.Serial.channel);
+    }
 
     /* save client-specific state */
     if (c->clie_save)
@@ -840,8 +926,13 @@
         return -EIO;
     }
 
+    /* get protocol. */
+    QemudProtocol protocol = qemu_get_be32(f);
     /* get channel id */
-    int channel = qemu_get_be32(f);
+    int channel = -1;
+    if (protocol == QEMUD_PROTOCOL_SERIAL) {
+        qemu_get_be32(f);
+    }
     if (channel == 0) {
         D("%s: illegal snapshot: client for control channel must no be saved\n",
           __FUNCTION__);
@@ -849,6 +940,7 @@
     }
 
     /* re-connect client */
+    // TODO: Save / load is_pipe here!
     QemudClient* c = qemud_service_connect_client(sv, channel);
     if(c == NULL)
         return -EIO;
@@ -976,8 +1068,8 @@
     for (;;) {
         node = *pnode;
         if (node == NULL) {
-            D("%s: could not find client %d for service '%s'",
-              __FUNCTION__, c->channel, s->name);
+            D("%s: could not find client for service '%s'",
+              __FUNCTION__, s->name);
             return;
         }
         if (node == c)
@@ -1004,7 +1096,6 @@
           __FUNCTION__, sv->name);
         return NULL;
     }
-
     D("%s: registered client channel %d for '%s' service",
       __FUNCTION__, channel_id, sv->name);
     return client;
@@ -1153,7 +1244,7 @@
      * QemudClient that is setup in qemud_multiplexer_init()
      */
     for ( ; c != NULL; c = c->next ) {
-        if (c->channel == channel) {
+        if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
             qemud_client_recv(c, msg, msglen);
             return;
         }
@@ -1203,13 +1294,13 @@
 
     /* find the client by its channel id, then disconnect it */
     for (c = m->clients; c; c = c->next) {
-        if (c->channel == channel) {
+        if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
             D("%s: disconnecting client %d",
               __FUNCTION__, channel);
             /* note thatt this removes the client from
              * m->clients automatically.
              */
-            c->channel = -1; /* no need to send disconnect:<id> */
+            c->ProtocolSelector.Serial.channel = -1; /* no need to send disconnect:<id> */
             qemud_client_disconnect(c);
             return;
         }
@@ -1233,12 +1324,13 @@
         c = next;
         next = c->next;  /* disconnect frees c, remember next in advance */
 
-        if (c->channel > 0) { /* skip control channel */
+        if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0) {
+            /* skip control channel */
             D("%s: disconnecting client %d",
-              __FUNCTION__, c->channel);
+              __FUNCTION__, c->ProtocolSelector.Serial.channel);
             D("%s: disconnecting client %d\n",
-              __FUNCTION__, c->channel);
-            c->channel = -1; /* do not send disconnect:<id> */
+              __FUNCTION__, c->ProtocolSelector.Serial.channel);
+            c->ProtocolSelector.Serial.channel = -1; /* do not send disconnect:<id> */
             qemud_client_disconnect(c);
         }
     }
@@ -1442,13 +1534,91 @@
     return c;
 }
 
+/* Caches a service message into the client's descriptor.
+ *
+ * See comments on QemudPipeMessage structure for more info.
+ */
+static void
+_qemud_pipe_cache_buffer(QemudClient* client, const uint8_t*  msg, int  msglen)
+{
+    QemudPipeMessage* buf;
+    QemudPipeMessage** ins_at = &client->ProtocolSelector.Pipe.messages;
+
+    /* Allocate descriptor big enough to contain message as well. */
+    buf = (QemudPipeMessage*)malloc(msglen + sizeof(QemudPipeMessage));
+    if (buf != NULL) {
+        /* Message starts right after the descriptor. */
+        buf->message = (uint8_t*)buf + sizeof(QemudPipeMessage);
+        buf->size = msglen;
+        memcpy(buf->message, msg, msglen);
+        buf->offset = 0;
+        buf->next = NULL;
+        while (*ins_at != NULL) {
+            ins_at = &(*ins_at)->next;
+        }
+        *ins_at = buf;
+        /* Notify the pipe that there is data to read. */
+        goldfish_pipe_wake(client->ProtocolSelector.Pipe.hwpipe, PIPE_WAKE_READ);
+    }
+}
+
+/* Sends service message to the client.
+ */
+static void
+_qemud_pipe_send(QemudClient*  client, const uint8_t*  msg, int  msglen)
+{
+    uint8_t   frame[FRAME_HEADER_SIZE];
+    int       avail, len = msglen;
+    int framing = client->framing;
+
+    if (msglen <= 0)
+        return;
+
+    D("%s: len=%3d '%s'",
+      __FUNCTION__, msglen, quote_bytes((const void*)msg, msglen));
+
+    if (framing) {
+        len += FRAME_HEADER_SIZE;
+    }
+
+    /* packetize the payload for the serial MTU */
+    while (len > 0)
+    {
+        avail = len;
+        if (avail > MAX_SERIAL_PAYLOAD)
+            avail = MAX_SERIAL_PAYLOAD;
+
+        /* insert frame header when needed */
+        if (framing) {
+            int2hex(frame, FRAME_HEADER_SIZE, msglen);
+            T("%s: '%.*s'", __FUNCTION__, FRAME_HEADER_SIZE, frame);
+            _qemud_pipe_cache_buffer(client, frame, FRAME_HEADER_SIZE);
+            avail  -= FRAME_HEADER_SIZE;
+            len    -= FRAME_HEADER_SIZE;
+            framing = 0;
+        }
+
+        /* write message content */
+        T("%s: '%.*s'", __FUNCTION__, avail, msg);
+        _qemud_pipe_cache_buffer(client, msg, avail);
+        msg += avail;
+        len -= avail;
+    }
+}
+
 /* this can be used by a service implementation to send an answer
  * or message to a specific client.
  */
 void
 qemud_client_send ( QemudClient*  client, const uint8_t*  msg, int  msglen )
 {
-    qemud_serial_send(client->serial, client->channel, client->framing != 0, msg, msglen);
+    if (_is_pipe_client(client)) {
+        _qemud_pipe_send(client, msg, msglen);
+    } else {
+        qemud_serial_send(client->ProtocolSelector.Serial.serial,
+                          client->ProtocolSelector.Serial.channel,
+                          client->framing != 0, msg, msglen);
+    }
 }
 
 /* enable framing for this client. When TRUE, this will
@@ -1488,7 +1658,8 @@
 {
     unsigned int client_count = 0;
     for( ; c; c = c->next)   // walk over linked list
-        if (c->channel > 0)  // skip control channel, which is not saved
+        // skip control channel, which is not saved
+        if (_is_pipe_client(c) || c->ProtocolSelector.Serial.channel > 0)
             client_count++;
 
     qemu_put_be32(f, client_count);
@@ -1530,7 +1701,8 @@
     qemud_client_save_count(f, m->clients);
     QemudClient *c;
     for (c = m->clients; c; c = c->next) {
-        if (c->channel > 0) {         /* skip control channel client */
+        /* skip control channel client */
+        if (_is_pipe_client(c) || c->ProtocolSelector.Serial.channel > 0) {
             qemud_client_save(f, c);
         }
     }
@@ -1604,6 +1776,211 @@
     return 0;
 }
 
+/*------------------------------------------------------------------------------
+ *
+ * QEMUD PIPE service callbacks
+ *
+ * ----------------------------------------------------------------------------*/
+
+/* Descriptor for a QEMUD pipe connection.
+ *
+ * Every time a client connects to the QEMUD via pipe, an instance of this
+ * structure is created to represent a connection used by new pipe client.
+ */
+typedef struct QemudPipe {
+    /* Pipe descriptor. */
+    void*           hwpipe;
+    /* Looper used for I/O */
+    void*           looper;
+    /* Service for this pipe. */
+    QemudService*   service;
+    /* Client for this pipe. */
+    QemudClient*    client;
+} QemudPipe;
+
+/* This is a callback that gets invoked when guest is connecting to the service.
+ *
+ * Here we will create a new client as well as pipe descriptor representing new
+ * connection.
+ */
+static void*
+_qemudPipe_init(void* hwpipe, void* _looper, const char* args)
+{
+    QemudMultiplexer *m = _multiplexer;
+    QemudService* sv = m->services;
+    QemudClient* client;
+    QemudPipe* pipe = NULL;
+
+    /* 'args' passed in this callback represents name of the service the guest is
+     * connecting to. It can't be NULL. */
+    if (args == NULL) {
+        D("%s: Missing address!", __FUNCTION__);
+        return NULL;
+    }
+
+    /* Lookup registered service by its name. */
+    while (sv != NULL && strcmp(sv->name, args)) {
+        sv = sv->next;
+    }
+    if (sv == NULL) {
+        D("%s: Service '%s' has not been registered!", __FUNCTION__, args);
+        return NULL;
+    }
+
+    /* Create a client for this connection. -1 as a channel ID signals that this
+     * is a pipe client. */
+    client = qemud_service_connect_client(sv, -1);
+    if (client != NULL) {
+        ANEW0(pipe);
+        pipe->hwpipe = hwpipe;
+        pipe->looper = _looper;
+        pipe->service = sv;
+        pipe->client = client;
+        client->ProtocolSelector.Pipe.hwpipe = hwpipe;
+    }
+
+    return pipe;
+}
+
+/* Called when the guest wants to close the channel.
+*/
+static void
+_qemudPipe_closeFromGuest( void* opaque )
+{
+    QemudPipe* pipe = opaque;
+    QemudClient*  client = pipe->client;
+    D("%s", __FUNCTION__);
+    qemud_client_disconnect(client);
+}
+
+/* Called when the guest has sent some data to the client.
+ */
+static int
+_qemudPipe_sendBuffers(void* opaque,
+                       const GoldfishPipeBuffer* buffers,
+                       int numBuffers)
+{
+    QemudPipe* pipe = opaque;
+    QemudClient*  client = pipe->client;
+    size_t transferred = 0;
+
+    if (numBuffers == 1) {
+        /* Simple case: all data are in one buffer. */
+        D("%s: %s", __FUNCTION__, quote_bytes((char*)buffers->data, buffers->size));
+        qemud_client_recv(client, buffers->data, buffers->size);
+        transferred = buffers->size;
+    } else {
+        /* If there are multiple buffers involved, collect all data in one buffer
+         * before calling the high level client. */
+        uint8_t* msg, *wrk;
+        int n;
+        for (n = 0; n < numBuffers; n++) {
+            transferred += buffers[n].size;
+        }
+        msg = malloc(transferred);
+        wrk = msg;
+        for (n = 0; n < numBuffers; n++) {
+            memcpy(wrk, buffers[n].data, buffers[n].size);
+            wrk += buffers[n].size;
+        }
+        D("%s: %s", __FUNCTION__, quote_bytes((char*)msg, transferred));
+        qemud_client_recv(client, msg, transferred);
+        free(msg);
+    }
+
+    return transferred;
+}
+
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+/* Called when the guest is reading data from the client.
+ */
+static int
+_qemudPipe_recvBuffers(void* opaque, GoldfishPipeBuffer* buffers, int numBuffers)
+{
+    QemudPipe* pipe = opaque;
+    QemudClient*  client = pipe->client;
+    QemudPipeMessage** msg_list = &client->ProtocolSelector.Pipe.messages;
+    GoldfishPipeBuffer* buff = buffers;
+    GoldfishPipeBuffer* endbuff = buffers + numBuffers;
+    size_t sent_bytes = 0;
+    size_t off_in_buff = 0;
+
+    if (*msg_list == NULL) {
+        /* No data to send. Let it block until we wake it up with
+         * PIPE_WAKE_READ when service sends data to the client. */
+        return PIPE_ERROR_AGAIN;
+    }
+
+    /* Fill in goldfish buffers while they are still available, and there are
+     * messages in the client's message list. */
+    while (buff != endbuff && *msg_list != NULL) {
+        QemudPipeMessage* msg = *msg_list;
+        /* Message data fiting the current pipe's buffer. */
+        size_t to_copy = min(msg->size - msg->offset, buff->size);
+        memcpy(buff->data + off_in_buff, msg->message + msg->offset, to_copy);
+        /* Update offsets. */
+        off_in_buff += to_copy;
+        msg->offset += to_copy;
+        sent_bytes += to_copy;
+        if (msg->size == msg->offset) {
+            /* We're done with the current message. Go to the next one. */
+            *msg_list = msg->next;
+            free(msg);
+        }
+        if (off_in_buff == buff->size) {
+            /* Current pipe buffer is full. Continue with the next one. */
+            buff++;
+        }
+    }
+
+    D("%s: -> %u (of %u)", __FUNCTION__, sent_bytes, buffers->size);
+
+    return sent_bytes;
+}
+
+static unsigned
+_qemudPipe_poll(void* opaque)
+{
+    QemudPipe* pipe = opaque;
+    QemudClient*  client = pipe->client;
+    unsigned ret = PIPE_WAKE_WRITE;
+    if (client->ProtocolSelector.Pipe.messages != NULL) {
+        ret |= PIPE_WAKE_WRITE;
+    }
+
+    return ret;
+}
+
+static void
+_qemudPipe_wakeOn(void* opaque, int flags)
+{
+    D("%s: -> %X", __FUNCTION__, flags);
+}
+
+/* QEMUD pipe functions.
+ */
+static const GoldfishPipeFuncs _qemudPipe_funcs = {
+    _qemudPipe_init,
+    _qemudPipe_closeFromGuest,
+    _qemudPipe_sendBuffers,
+    _qemudPipe_recvBuffers,
+    _qemudPipe_poll,
+    _qemudPipe_wakeOn,
+};
+
+/* Initializes QEMUD pipe interface.
+ */
+static void
+_android_qemud_pipe_init(void)
+{
+    static ABool _qemud_pipe_initialized = false;
+
+    if (!_qemud_pipe_initialized) {
+        goldfish_pipe_add_type( "qemud", looper_newCore(), &_qemudPipe_funcs );
+        _qemud_pipe_initialized = true;
+    }
+}
 
 /* this is the end of the serial charpipe that must be passed
  * to the emulated tty implementation. The other end of the
@@ -1611,8 +1988,10 @@
  */
 static CharDriverState*  android_qemud_cs;
 
-extern void
-android_qemud_init( void )
+/* Initializes QEMUD serial interface.
+ */
+static void
+_android_qemud_serial_init(void)
 {
     CharDriverState*    cs;
 
@@ -1631,6 +2010,18 @@
                       qemud_save, qemud_load, _multiplexer);
 }
 
+extern void
+android_qemud_init( void )
+{
+    D("%s", __FUNCTION__);
+    /* We don't know in advance whether the guest system supports qemud pipes,
+     * so we will initialize both qemud machineries, the legacy (over serial
+     * port), and the new one (over qemu pipe). Then we let the guest to connect
+     * via one, or the other. */
+    _android_qemud_serial_init();
+    _android_qemud_pipe_init();
+}
+
 /* return the serial charpipe endpoint that must be used
  * by the emulated tty implementation.
  */
@@ -1663,20 +2054,19 @@
                         QemudServiceSave     serv_save,
                         QemudServiceLoad     serv_load )
 {
-    QemudMultiplexer*  m  = _multiplexer;
     QemudService*      sv;
+    QemudMultiplexer*  m  = _multiplexer;
 
-    if (android_qemud_cs == NULL)
-        android_qemud_init();
+    android_qemud_init();
 
     sv = qemud_service_new(service_name,
-                             max_clients,
-                             serv_opaque,
-                             serv_connect,
-                             serv_save,
-                             serv_load,
-                             &m->services);
-
+                           max_clients,
+                           serv_opaque,
+                           serv_connect,
+                           serv_save,
+                           serv_load,
+                           &m->services);
+    D("Registered QEMUD service %s", service_name);
     return sv;
 }