aboutsummaryrefslogtreecommitdiffstats
path: root/android/hw-qemud-pipe-net.c
diff options
context:
space:
mode:
Diffstat (limited to 'android/hw-qemud-pipe-net.c')
-rw-r--r--android/hw-qemud-pipe-net.c788
1 files changed, 0 insertions, 788 deletions
diff --git a/android/hw-qemud-pipe-net.c b/android/hw-qemud-pipe-net.c
deleted file mode 100644
index 874bc69..0000000
--- a/android/hw-qemud-pipe-net.c
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "sockets.h"
-#include "android/utils/assert.h"
-#include "android/utils/panic.h"
-#include "android/utils/system.h"
-#include "android/async-utils.h"
-#include "android/looper.h"
-#include "android/hw-qemud-pipe.h"
-#include "hw/goldfish_pipe.h"
-
-/* Implement the OpenGL fast-pipe */
-
-/* Set to 1 or 2 for debug traces */
-#define DEBUG 0
-
-#if DEBUG >= 1
-# define D(...) printf(__VA_ARGS__), printf("\n")
-#else
-# define D(...) ((void)0)
-#endif
-
-#if DEBUG >= 2
-# define DD(...) printf(__VA_ARGS__), printf("\n")
-# define DDASSERT(cond) _ANDROID_ASSERT(cond, "Assertion failure: ", #cond)
-# define DDASSERT_INT_OP(cond,val,op) _ANDROID_ASSERT_INT_OP(cond,val,op)
-#else
-# define DD(...) ((void)0)
-# define DDASSERT(cond) ((void)0)
-# define DDASSERT_INT_OP(cond,val,op) ((void)0)
-#endif
-
-#define DDASSERT_INT_LT(cond,val) DDASSERT_INT_OP(cond,val,<)
-#define DDASSERT_INT_LTE(cond,val) DDASSERT_INT_OP(cond,val,<=)
-#define DDASSERT_INT_GT(cond,val) DDASSERT_INT_OP(cond,val,>)
-#define DDASSERT_INT_GTE(cond,val) DDASSERT_INT_OP(cond,val,>=)
-#define DDASSERT_INT_EQ(cond,val) DDASSERT_INT_OP(cond,val,==)
-#define DDASSERT_INT_NEQ(cond,val) DDASSERT_INT_OP(cond,val,!=)
-
-
-/* Forward declarations */
-
-typedef struct NetPipeInit {
- Looper* looper;
- SockAddress serverAddress[1];
-} NetPipeInit;
-
-/**********************************************************************
- **********************************************************************
- *****
- ***** P I P E M E S S A G E S
- *****
- *****/
-
-typedef struct PipeMsg {
- struct PipeMsg* next;
- size_t size;
- uint8_t data[1];
-} PipeMsg;
-
-static PipeMsg*
-pipeMsg_alloc( size_t size )
-{
- PipeMsg* msg = android_alloc(sizeof(*msg) + size);
-
- msg->next = NULL;
- msg->size = size;
- return msg;
-}
-
-static void
-pipeMsg_free( PipeMsg* msg )
-{
- AFREE(msg);
-}
-
-/**********************************************************************
- **********************************************************************
- *****
- ***** M E S S A G E L I S T
- *****
- *****/
-
-typedef struct {
- PipeMsg* firstMsg; /* first message in list */
- PipeMsg* lastMsg; /* last message in list */
- size_t firstBytes; /* bytes in firstMsg that were already sent */
- size_t lastBytes; /* bytes in lastMsg that were already received */
- size_t totalBytes; /* total bytes in list */
-} MsgList;
-
-/* Default receiver buffer size to accept incoming data */
-#define DEFAULT_RECEIVER_SIZE 8180
-
-/* Initialize a message list - appropriate for sending them out */
-static void
-msgList_initSend( MsgList* list )
-{
- list->firstMsg = NULL;
- list->lastMsg = NULL;
- list->firstBytes = 0;
- list->lastBytes = 0;
- list->totalBytes = 0;
-}
-
-/* Initialize a message list for receiving data */
-static void
-msgList_initReceive( MsgList* list )
-{
- msgList_initSend(list);
- list->firstMsg = list->lastMsg = pipeMsg_alloc( DEFAULT_RECEIVER_SIZE );
-}
-
-/* Finalize a message list */
-static void
-msgList_done( MsgList* list )
-{
- PipeMsg* msg;
-
- while ((msg = list->firstMsg) != NULL) {
- list->firstMsg = msg->next;
- pipeMsg_free(msg);
- }
- list->lastMsg = NULL;
-
- list->firstBytes = 0;
- list->lastBytes = 0;
- list->totalBytes = 0;
-}
-
-static int
-msgList_hasData( MsgList* list )
-{
- return list->totalBytes > 0;
-}
-
-/* Append a list of buffers to a message list.
- *
- * This is a very simple implementation that simply mallocs a single
- * new message containing all of the buffer's data, and append it to
- * our link list. This also makes the implementation of msgList_send()
- * quite simple, since there is no need to deal with the 'lastBytes'
- * pointer (it is always assumed to be 'lastMsg->size').
- */
-static int
-msgList_sendBuffers( MsgList* list,
- const GoldfishPipeBuffer* buffers,
- int numBuffers )
-{
- const GoldfishPipeBuffer* buff = buffers;
- const GoldfishPipeBuffer* buffEnd = buff + numBuffers;
- PipeMsg* msg;
- size_t msgSize = 0;
- size_t pos;
-
- /* Count the total number of bytes */
- for ( ; buff < buffEnd; buff++ ) {
- msgSize += buff[0].size;
- }
-
- /* Allocate a new message */
- msg = pipeMsg_alloc(msgSize);
- if (msg == NULL) {
- errno = ENOMEM;
- return -1;
- }
-
- /* Copy data from buffers to message */
- for ( pos = 0, buff = buffers; buff < buffEnd; buff++ ) {
- memcpy(msg->data + pos, buff->data, buff->size);
- pos += buff->size;
- }
-
- /* Append message to current list */
- if (list->lastMsg != NULL) {
- list->lastMsg->next = msg;
- } else {
- list->firstMsg = msg;
- list->firstBytes = 0;
- }
- list->lastMsg = msg;
-
- list->totalBytes += msgSize;
-
- /* We are done */
- return 0;
-}
-
-/* Try to send outgoing messages in the list through non-blocking socket 'fd'.
- * Return 0 on success, and -1 on failure, where errno will be:
- *
- * ECONNRESET - connection reset by peer
- *
- * Note that 0 will be returned if socket_send() returns EAGAIN/EWOULDBLOCK.
- */
-static int
-msgList_send( MsgList* list, int fd )
-{
- int ret = 0;
-
- for (;;) {
- PipeMsg* msg = list->firstMsg;
- size_t sentBytes = list->firstBytes;
- size_t availBytes;
-
- if (msg == NULL) {
- /* We sent everything */
- return 0;
- }
- DDASSERT(sentBytes < msg->size);
- availBytes = msg->size - sentBytes;
-
- ret = socket_send(fd, msg->data + sentBytes, availBytes);
- if (ret <= 0) {
- goto ERROR;
- }
-
- list->totalBytes -= ret;
- list->firstBytes += ret;
-
- if (list->firstBytes < msg->size) {
- continue;
- }
-
- /* We sent the full first packet - remove it from the head */
- list->firstBytes = 0;
- list->firstMsg = msg->next;
- if (list->firstMsg == NULL) {
- list->lastMsg = NULL;
- }
- pipeMsg_free(msg);
- }
-
-ERROR:
- if (ret < 0) { /* EAGAIN/EWOULDBLOCK or disconnection */
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- ret = 0; /* clear error - this is normal */
- } else {
- DD("%s: socket_send() returned %d: %s\n", __FUNCTION__, errno, errno_str);
- errno = ECONNRESET;
- }
- } else {
-#if DEBUG >= 2
- int err = socket_get_error(fd);
- DD("%s: socket_send() returned 0 (error=%d: %s)", __FUNCTION__,
- err, strerror(err));
-#endif
- errno = ECONNRESET;
- ret = -1;
- }
- return ret;
-}
-
-
-/* Try to receive data into caller-provided buffers, and return the total
- * size of bytes that were read. Returns -1 on error, with errno:
- *
- * ECONNRESET: Connection reset by peer
- * EAGAIN: No incoming data, wait for it to arrive.
- */
-static int
-msgList_recvBuffers( MsgList* list,
- GoldfishPipeBuffer* buffers,
- int numBuffers )
-{
- GoldfishPipeBuffer* buff = buffers;
- GoldfishPipeBuffer* buffEnd = buff + numBuffers;
- size_t buffStart = 0;
- PipeMsg* msg = list->firstMsg;
- size_t msgStart = list->firstBytes;
- size_t totalSize = 0;
-
- DDASSERT(msg != NULL);
-
- D("%s: ENTER list.firstBytes=%d list.lastBytes=%d list.totalBytes=%d list.firstSize=%d list.lastSize=%d list.firstEqualLast=%d",
- __FUNCTION__, list->firstBytes, list->lastBytes, list->totalBytes,
- list->firstMsg->size, list->lastMsg->size, list->firstMsg == list->lastMsg);
-
- /* If there is no incoming data, return EAGAIN */
- if (list->totalBytes == 0) {
- errno = EAGAIN;
- return -1;
- }
-
- /* Now try to transfer as much from the list of incoming messages
- * into the buffers.
- */
- while (msg != NULL && buff < buffEnd) {
- DDASSERT(msgStart < msg->size);
- DDASSERT(buffStart < buff->size);
-
- /* Copy data from current message into next buffer.
- * For a given message, first determine the start and end
- * of available data. Then try to see how much of these
- * we can copy to the current buffer.
- */
- size_t msgEnd = msg->size;
-
- if (msg == list->lastMsg) {
- msgEnd = list->lastBytes;
- }
-
- size_t msgAvail = msgEnd - msgStart;
- size_t buffAvail = buff->size - buffStart;
-
- if (msgAvail > buffAvail) {
- msgAvail = buffAvail;
- }
-
- DDASSERT(msgAvail > 0);
-
- D("%s: transfer %d bytes (msgStart=%d msgSize=%d buffStart=%d buffSize=%d)",
- __FUNCTION__, msgAvail, msgStart, msg->size, buffStart, buff->size);
- memcpy(buff->data + buffStart, msg->data + msgStart, msgAvail);
-
- /* Advance cursors */
- msgStart += msgAvail;
- buffStart += msgAvail;
- totalSize += msgAvail;
-
- /* Did we fill up the current buffer? */
- if (buffStart >= buff->size) {
- buffStart = 0;
- buff++;
- }
-
- /* Did we empty the current message? */
- if (msgStart >= msgEnd) {
- msgStart = 0;
- /* If this is the last message, reset the 'first' and 'last'
- * pointers to reuse it for the next recv(). */
- if (msg == list->lastMsg) {
- list->lastBytes = 0;
- msg = NULL;
- } else {
- /* Otherwise, delete the message, and jump to the next one */
- list->firstMsg = msg->next;
- pipeMsg_free(msg);
- msg = list->firstMsg;
- }
- }
-
- }
- list->firstBytes = msgStart;
- list->totalBytes -= totalSize;
-
- D("%s: EXIT list.firstBytes=%d list.lastBytes=%d list.totalBytes=%d list.firstSize=%d list.lastSize=%d list.firstEqualLast=%d",
- __FUNCTION__, list->firstBytes, list->lastBytes, list->totalBytes,
- list->firstMsg->size, list->lastMsg->size, list->firstMsg == list->lastMsg);
-
- return (int)totalSize;
-}
-
-
-/* Try to receive data from non-blocking socket 'fd'.
- * Return 0 on success, or -1 on error, where errno can be:
- *
- * ECONNRESET - connection reset by peer
- * ENOMEM - full message list, no room to receive more data
- */
-static int
-msgList_recv( MsgList* list, int fd )
-{
- int ret = 0;
-
- D("%s: ENTER list.firstBytes=%d list.lastBytes=%d list.totalBytes=%d list.firstSize=%d list.lastSize=%d list.firstEqualLast=%d",
- __FUNCTION__, list->firstBytes, list->lastBytes, list->totalBytes,
- list->firstMsg->size, list->lastMsg->size, list->firstMsg == list->lastMsg);
-
- for (;;) {
- PipeMsg* last = list->lastMsg;
- size_t lastBytes = list->lastBytes;
- size_t availBytes;
-
- /* Compute how many bytes we can receive in the last buffer*/
- DDASSERT(last != NULL);
- DDASSERT(last->size > 0);
- DDASSERT(lastBytes < last->size);
-
- availBytes = last->size - lastBytes;
-
- /* Try to receive the data, act on errors */
- ret = socket_recv(fd, last->data + lastBytes, availBytes);
- if (ret <= 0) {
- goto ERROR;
- }
-
- /* Acknowledge received data */
- list->lastBytes += ret;
- list->totalBytes += ret;
-
- if (list->lastBytes < last->size) {
- continue;
- }
-
- /* We filled-up the last message buffer, allocate a new one */
- last = pipeMsg_alloc( DEFAULT_RECEIVER_SIZE );
- list->lastMsg->next = last;
- list->lastMsg = last;
- list->lastBytes = 0;
- }
-
-ERROR:
- if (ret < 0) { /* EAGAIN/EWOULDBLOCK or disconnection */
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- ret = 0; /* clear error - this is normal */
- } else {
- DD("%s: socket_send() returned %d: %s\n", __FUNCTION__, errno, errno_str);
- errno = ECONNRESET;
- }
- } else /* ret == 0 */ {
-#if DEBUG >= 2
- int err = socket_get_error(fd);
- DD("%s: socket_send() returned 0 (error=%d: %s)", __FUNCTION__,
- err, strerror(err));
-#endif
- errno = ECONNRESET;
- ret = -1;
- }
- D("%s: EXIT list.firstBytes=%d list.lastBytes=%d list.totalBytes=%d list.firstSize=%d list.lastSize=%d list.firstEqualLast=%d",
- __FUNCTION__, list->firstBytes, list->lastBytes, list->totalBytes,
- list->firstMsg->size, list->lastMsg->size, list->firstMsg == list->lastMsg);
-
- return ret;
-}
-
-
-
-/**********************************************************************
- **********************************************************************
- *****
- ***** P I P E H A N D L E R S
- *****
- *****/
-
-/* Technical Note:
- *
- * Each NetPipe object is connected to the following:
- *
- * - a remote rendering process through a normal TCP socket.
- * - a Goldfish pipe (see hw/goldfish_pipe.h) to exchange messages with the guest.
- * - a Qemud client (see android/hw-qemud.h) to signal state changes to the guest.
- *
- * REMOTE <---socket---> PIPE <------> GOLDFISH PIPE
- * PROCESS <--+
- * |
- * +---> QEMUD CHANNEL (android/hw-qemud.h)
- *
- */
-enum {
- STATE_INIT,
- STATE_CONNECTING,
- STATE_CONNECTED,
- STATE_CLOSING_GUEST,
- STATE_CLOSING_SOCKET
-};
-
-#define DEFAULT_INCOMING_SIZE 4000
-
-#define MAX_IN_BUFFERS 4
-
-typedef struct {
- QemudClient* client;
- int state;
- int wakeWanted;
-
- MsgList outList[1];
- MsgList inList[1];
-
- LoopIo io[1];
- AsyncConnector connector[1];
-
- GoldfishPipeBuffer outBuffer[1];
- GoldfishPipeBuffer inBuffers[MAX_IN_BUFFERS];
- int inBufferCount;
-
-} NetPipe;
-
-static void
-netPipe_free( NetPipe* pipe )
-{
- int fd;
-
- /* Removing any pending incoming packet */
- msgList_done(pipe->outList);
- msgList_done(pipe->inList);
-
- /* Close the socket */
- fd = pipe->io->fd;
- loopIo_done(pipe->io);
- socket_close(fd);
-
- /* Release the pipe object */
- AFREE(pipe);
-}
-
-
-static void
-netPipe_resetState( NetPipe* pipe )
-{
- /* If there is a pending outgoing packet, open the valve */
- if (msgList_hasData(pipe->outList)) {
- loopIo_wantWrite(pipe->io);
- } else {
- loopIo_dontWantWrite(pipe->io);
- }
-
- /* Accept incoming data if we are not closing, and our input list isn't full */
- if (pipe->state == STATE_CONNECTED) {
- loopIo_wantRead(pipe->io);
- } else {
- loopIo_dontWantRead(pipe->io);
- }
-}
-
-
-/* This function is only called when the socket is disconnected.
- * See netPipe_closeFromGuest() for the case when the guest requires
- * the disconnection. */
-static void
-netPipe_closeFromSocket( void* opaque )
-{
- NetPipe* pipe = opaque;
-
- /* If the guest already ordered the pipe to be closed, delete immediately */
- if (pipe->state == STATE_CLOSING_GUEST) {
- netPipe_free(pipe);
- return;
- }
-
- /* Force the closure of the QEMUD channel - if a guest is blocked
- * waiting for a wake signal, it will receive an error. */
- if (pipe->client != NULL) {
- qemud_client_close(pipe->client);
- pipe->client = NULL;
- }
-
- /* Remove any outgoing packets - they won't go anywhere */
- msgList_done(pipe->outList);
-
- pipe->state = STATE_CLOSING_SOCKET;
- netPipe_resetState(pipe);
-}
-
-
-/* This is the function that gets called each time there is an asynchronous
- * event on the network pipe.
- */
-static void
-netPipe_io_func( void* opaque, int fd, unsigned events )
-{
- NetPipe* pipe = opaque;
- int wakeFlags = 0;
-
- /* Run the connector if we are in the CONNECTING state */
- /* TODO: Add some sort of time-out, to deal with the case */
- /* where the renderer process is wedged. */
- if (pipe->state == STATE_CONNECTING) {
- AsyncStatus status = asyncConnector_run(pipe->connector);
- if (status == ASYNC_NEED_MORE) {
- return;
- }
- else if (status == ASYNC_ERROR) {
- /* Could not connect, tell our client by closing the channel. */
-
- netPipe_closeFromSocket(pipe);
- return;
- }
- pipe->state = STATE_CONNECTED;
- netPipe_resetState(pipe);
- return;
- }
-
- /* Otherwise, accept incoming data */
- if ((events & LOOP_IO_READ) != 0) {
- int ret;
-
- if ((pipe->wakeWanted & QEMUD_PIPE_WAKE_ON_RECV) != 0) {
- wakeFlags |= QEMUD_PIPE_WAKE_ON_RECV;
- }
-
- ret = msgList_recv(pipe->inList, fd);
- if (ret < 0) {
- wakeFlags &= ~QEMUD_PIPE_WAKE_ON_RECV;
-
- if (errno == ENOMEM) { /* shouldn't happen */
- DD("%s: msgList_recv() return ENOMEM!?\n", __FUNCTION__);
- } else {
- /* errno == ECONNRESET */
- DD("%s: msgList_recv() error, closing pipe\n", __FUNCTION__);
- netPipe_closeFromSocket(pipe);
- return;
- }
- }
- }
-
- if ((events & LOOP_IO_WRITE) != 0) {
- int ret;
-
- DDASSERT(msgList_hasData(pipe->outList));
-
- ret = msgList_send(pipe->outList, fd);
- if (ret < 0) {
- DD("%s: msgList_send() error, closing pipe\n", __FUNCTION__);
- netPipe_closeFromSocket(pipe);
- return;
- }
-
- if ((pipe->wakeWanted & QEMUD_PIPE_WAKE_ON_SEND) != 0) {
- wakeFlags |= QEMUD_PIPE_WAKE_ON_SEND;
- }
- }
-
- /* Send wake signal to the guest if needed */
- if (wakeFlags != 0) {
- uint8_t byte = (uint8_t) wakeFlags;
- DD("%s: Sending wake flags %d (wanted=%d)", __FUNCTION__, byte, pipe->wakeWanted);
- qemud_client_send(pipe->client, &byte, 1);
- pipe->wakeWanted &= ~wakeFlags;
- }
-
- /* Reset state */
- netPipe_resetState(pipe);
-}
-
-
-void*
-netPipe_init( QemudClient* qcl, void* pipeOpaque )
-{
- NetPipe* pipe;
- NetPipeInit* pipeSvc = pipeOpaque;
-
- ANEW0(pipe);
-
- pipe->client = qcl;
- pipe->state = STATE_INIT;
-
- msgList_initSend(pipe->outList);
- msgList_initReceive(pipe->inList);
-
-#define DEFAULT_OPENGLES_PORT 22468
-
- {
- AsyncStatus status;
-
- int fd = socket_create_inet( SOCKET_STREAM );
- if (fd < 0) {
- netPipe_free(pipe);
- return NULL;
- }
-
- loopIo_init(pipe->io, pipeSvc->looper, fd, netPipe_io_func, pipe);
- asyncConnector_init(pipe->connector, pipeSvc->serverAddress, pipe->io);
- pipe->state = STATE_CONNECTING;
-
- status = asyncConnector_run(pipe->connector);
- if (status == ASYNC_ERROR) {
- D("%s: Could not create to renderer process: %s",
- __FUNCTION__, errno_str);
- netPipe_free(pipe);
- return NULL;
- }
- if (status == ASYNC_COMPLETE) {
- pipe->state = STATE_CONNECTED;
- netPipe_resetState(pipe);
- }
- }
-
- return pipe;
-}
-
-/* Called when the guest wants to close the channel. This is different
- * from netPipe_closeFromSocket() which is called when the socket is
- * disconnected. */
-static void
-netPipe_closeFromGuest( void* opaque )
-{
- NetPipe* pipe = opaque;
-
- /* The qemud client is gone when we reach this code */
- pipe->client = NULL;
-
- /* Remove input messages */
- msgList_done(pipe->inList);
-
- /* If the socket is already closed, or if there are no
- * outgoing messages, delete immediately */
- if (pipe->state == STATE_CLOSING_SOCKET ||
- !msgList_hasData(pipe->outList)) {
- netPipe_free(pipe);
- return;
- }
-
- /* Otherwise, mark our pipe as closing, and wait until everything is
- * sent before deleting the object. */
- pipe->state = STATE_CLOSING_GUEST;
- netPipe_resetState(pipe);
-}
-
-
-static int
-netPipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
-{
- NetPipe* pipe = opaque;
- int ret;
-
- ret = msgList_sendBuffers(pipe->outList, buffers, numBuffers);
- netPipe_resetState(pipe);
- return ret;
-}
-
-static int
-netPipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
-{
- NetPipe* pipe = opaque;
- int ret;
-
- ret = msgList_recvBuffers(pipe->inList, buffers, numBuffers);
- netPipe_resetState(pipe);
- return ret;
-}
-
-static void
-netPipe_wakeOn( void* opaque, int flags )
-{
- NetPipe* pipe = opaque;
-
- pipe->wakeWanted |= flags;
-}
-
-/**********************************************************************
- **********************************************************************
- *****
- ***** N E T W O R K P I P E M E S S A G E S
- *****
- *****/
-
-static const QemudPipeHandlerFuncs net_pipe_handler_funcs = {
- netPipe_init,
- netPipe_closeFromGuest,
- netPipe_sendBuffers,
- netPipe_recvBuffers,
- netPipe_wakeOn,
-};
-
-
-static NetPipeInit _netPipeService[1];
-
-/**********************************************************************
- **********************************************************************
- *****
- ***** O P E N G L E S P I P E S E R V I C E
- *****
- *****/
-
-void
-android_hw_opengles_init(void)
-{
- NetPipeInit* svc = _netPipeService;
- int ret;
-
- DD("%s: Registering service\n", __FUNCTION__);
-
- svc->looper = looper_newCore();
-
- ret = sock_address_init_resolve(svc->serverAddress,
- "127.0.0.1",
- DEFAULT_OPENGLES_PORT,
- 0);
- if (ret < 0) {
- APANIC("Could not resolve renderer process address!");
- }
-
- goldfish_pipe_add_type( "opengles", svc, &net_pipe_handler_funcs );
-}