Initial Contribution
diff --git a/simulator/app/LocalBiChannel.cpp b/simulator/app/LocalBiChannel.cpp
new file mode 100644
index 0000000..93a997d
--- /dev/null
+++ b/simulator/app/LocalBiChannel.cpp
@@ -0,0 +1,444 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+// Local named bi-directional communication channel.
+//
+#include "LocalBiChannel.h"
+#include "utils/Log.h"
+
+#if defined(HAVE_WIN32_IPC)
+# define _WIN32_WINNT 0x0500
+# include <windows.h>
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/stat.h>
+# include <sys/un.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifndef SUN_LEN
+/*
+ * Our current set of ARM header files don't define this.
+ */
+# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ + strlen ((ptr)->sun_path))
+#endif
+
+using namespace android;
+
+const unsigned long kInvalidHandle = (unsigned long) -1;
+
+/*
+ * Initialize data fields.
+ */
+LocalBiChannel::LocalBiChannel(void)
+ : mFileName(NULL), mIsListener(false), mHandle(kInvalidHandle)
+{
+}
+
+#if defined(HAVE_WIN32_IPC)
+/*
+ * Implementation for Win32, using named pipes.
+ *
+ * Cygwin actually supports UNIX-domain sockets, but we want to stuff
+ * the file handles into a Pipe, which uses HANDLE under Win32.
+ */
+
+const int kPipeSize = 4096;
+
+/*
+ * Destructor. If we're the server side, we may need to clean up after
+ * ourselves.
+ */
+LocalBiChannel::~LocalBiChannel(void)
+{
+ if (mHandle != kInvalidHandle)
+ CloseHandle((HANDLE)mHandle);
+
+ delete[] mFileName;
+}
+
+/*
+ * Construct the full path. The caller must delete[] the return value.
+ */
+static char* makeFilename(const char* name)
+{
+ static const char* kBasePath = "\\\\.\\pipe\\android-";
+ char* fileName;
+
+ assert(name != NULL && name[0] != '\0');
+
+ fileName = new char[strlen(kBasePath) + strlen(name) + 1];
+ strcpy(fileName, kBasePath);
+ strcat(fileName, name);
+
+ return fileName;
+}
+
+/*
+ * Create a named pipe, so the client has something to connect to.
+ */
+bool LocalBiChannel::create(const char* name)
+{
+ delete[] mFileName;
+ mFileName = makeFilename(name);
+
+#if 0
+ HANDLE hPipe;
+
+ hPipe = CreateNamedPipe(
+ mFileName, // unique pipe name
+ PIPE_ACCESS_DUPLEX | // open mode
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
+ 0, // pipe mode (byte, blocking)
+ 1, // max instances
+ kPipeSize, // output buffer
+ kPipeSize, // input buffer
+ NMPWAIT_USE_DEFAULT_WAIT, // client time-out
+ NULL); // security
+
+ if (hPipe == 0) {
+ LOG(LOG_ERROR, "lbicomm",
+ "CreateNamedPipe failed (err=%ld)\n", GetLastError());
+ return false;
+ }
+
+ mHandle = (unsigned long) hPipe;
+#endif
+
+ return true;
+}
+
+/*
+ * Attach to an existing named pipe.
+ */
+bool LocalBiChannel::attach(const char* name, Pipe** ppReadPipe,
+ Pipe** ppWritePipe)
+{
+ HANDLE hPipe, dupHandle;
+
+ delete[] mFileName;
+ mFileName = makeFilename(name);
+
+ hPipe = CreateFile(
+ mFileName, // filename
+ GENERIC_READ | GENERIC_WRITE, // access
+ 0, // no sharing
+ NULL, // security
+ OPEN_EXISTING, // don't create
+ 0, // attributes
+ NULL); // template
+ if (hPipe == INVALID_HANDLE_VALUE) {
+ LOG(LOG_ERROR, "lbicomm",
+ "CreateFile on pipe '%s' failed (err=%ld)\n", name, GetLastError());
+ return false;
+ }
+
+ assert(mHandle == kInvalidHandle);
+
+ /*
+ * Set up the pipes. Use the new handle for one, and a duplicate
+ * of it for the other, in case we decide to only close one side.
+ */
+ *ppReadPipe = new Pipe();
+ (*ppReadPipe)->createReader((unsigned long) hPipe);
+
+ DuplicateHandle(
+ GetCurrentProcess(),
+ hPipe,
+ GetCurrentProcess(),
+ &dupHandle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ *ppWritePipe = new Pipe();
+ (*ppWritePipe)->createWriter((unsigned long) dupHandle);
+
+ return true;
+}
+
+/*
+ * Listen for a new connection, discarding any existing connection.
+ */
+bool LocalBiChannel::listen(Pipe** ppReadPipe, Pipe** ppWritePipe)
+{
+ BOOL connected;
+ HANDLE hPipe;
+
+ /*
+ * Create up to 3 instances of the named pipe:
+ * - currently active connection
+ * - connection currently being rejected because one is already active
+ * - a new listener to wait for the next round
+ */
+ hPipe = CreateNamedPipe(
+ mFileName, // unique pipe name
+ PIPE_ACCESS_DUPLEX // open mode
+ /*| FILE_FLAG_FIRST_PIPE_INSTANCE*/,
+ 0, // pipe mode (byte, blocking)
+ 3, // max instances
+ kPipeSize, // output buffer
+ kPipeSize, // input buffer
+ NMPWAIT_USE_DEFAULT_WAIT, // client time-out
+ NULL); // security
+
+ if (hPipe == 0) {
+ LOG(LOG_ERROR, "lbicomm",
+ "CreateNamedPipe failed (err=%ld)\n", GetLastError());
+ return false;
+ }
+
+ /*
+ * If a client is already connected to us, this fails with
+ * ERROR_PIPE_CONNECTED. It returns success if we had to wait
+ * a little bit before the connection happens.
+ */
+ connected = ConnectNamedPipe(hPipe, NULL) ?
+ TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+
+ if (connected) {
+ /*
+ * Create the pipes. Give one a duplicated handle so that,
+ * when one closes, we don't lose both.
+ */
+ HANDLE dupHandle;
+
+ *ppReadPipe = new Pipe();
+ (*ppReadPipe)->createReader((unsigned long) hPipe);
+
+ DuplicateHandle(
+ GetCurrentProcess(),
+ hPipe,
+ GetCurrentProcess(),
+ &dupHandle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ *ppWritePipe = new Pipe();
+ (*ppWritePipe)->createWriter((unsigned long) dupHandle);
+
+ return true;
+ } else {
+ LOG(LOG_WARN, "lbicomm",
+ "ConnectNamedPipe failed (err=%ld)\n", GetLastError());
+#ifdef HAVE_WIN32_THREADS
+ Sleep(500); /* 500 ms */
+#else
+ usleep(500000); // DEBUG DEBUG
+#endif
+ return false;
+ }
+}
+
+#else
+
+/*
+ * Implementation for Linux and Darwin, using UNIX-domain sockets.
+ */
+
+/*
+ * Destructor. If we're the server side, blow away the socket file.
+ */
+LocalBiChannel::~LocalBiChannel(void)
+{
+ if (mHandle != kInvalidHandle)
+ close((int) mHandle);
+
+ if (mIsListener && mFileName != NULL) {
+ LOG(LOG_DEBUG, "lbicomm", "Removing '%s'\n", mFileName);
+ (void) unlink(mFileName);
+ }
+ delete[] mFileName;
+}
+
+/*
+ * Construct the full path. The caller must delete[] the return value.
+ */
+static char* makeFilename(const char* name)
+{
+ static const char* kBasePath = "/tmp/android-";
+ char* fileName;
+
+ assert(name != NULL && name[0] != '\0');
+
+ fileName = new char[strlen(kBasePath) + strlen(name) + 1];
+ strcpy(fileName, kBasePath);
+ strcat(fileName, name);
+
+ return fileName;
+}
+
+/*
+ * Create a UNIX domain socket, carefully removing it if it already
+ * exists.
+ */
+bool LocalBiChannel::create(const char* name)
+{
+ struct stat sb;
+ bool result = false;
+ int sock = -1;
+ int cc;
+
+ delete[] mFileName;
+ mFileName = makeFilename(name);
+
+ cc = stat(mFileName, &sb);
+ if (cc < 0) {
+ if (errno != ENOENT) {
+ LOG(LOG_ERROR, "lbicomm",
+ "Unable to stat '%s' (errno=%d)\n", mFileName, errno);
+ goto bail;
+ }
+ } else {
+ /* don't touch it if it's not a socket */
+ if (!(S_ISSOCK(sb.st_mode))) {
+ LOG(LOG_ERROR, "lbicomm",
+ "File '%s' exists and is not a socket\n", mFileName);
+ goto bail;
+ }
+
+ /* remove the cruft */
+ if (unlink(mFileName) < 0) {
+ LOG(LOG_ERROR, "lbicomm",
+ "Unable to remove '%s' (errno=%d)\n", mFileName, errno);
+ goto bail;
+ }
+ }
+
+ struct sockaddr_un addr;
+
+ sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ LOG(LOG_ERROR, "lbicomm",
+ "UNIX domain socket create failed (errno=%d)\n", errno);
+ goto bail;
+ }
+
+ /* bind the socket; this creates the file on disk */
+ strcpy(addr.sun_path, mFileName); // max 108 bytes
+ addr.sun_family = AF_UNIX;
+ cc = ::bind(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
+ if (cc < 0) {
+ LOG(LOG_ERROR, "lbicomm",
+ "AF_UNIX bind failed for '%s' (errno=%d)\n", mFileName, errno);
+ goto bail;
+ }
+
+ mHandle = (unsigned long) sock;
+ sock = -1;
+ mIsListener = true;
+ result = true;
+
+bail:
+ if (sock >= 0)
+ close(sock);
+ return result;
+}
+
+/*
+ * Attach to an existing UNIX domain socket.
+ */
+bool LocalBiChannel::attach(const char* name, Pipe** ppReadPipe,
+ Pipe** ppWritePipe)
+{
+ bool result = false;
+ int sock = -1;
+ int cc;
+
+ assert(ppReadPipe != NULL);
+ assert(ppWritePipe != NULL);
+
+ delete[] mFileName;
+ mFileName = makeFilename(name);
+
+ struct sockaddr_un addr;
+
+ sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ LOG(LOG_ERROR, "lbicomm",
+ "UNIX domain socket create failed (errno=%d)\n", errno);
+ goto bail;
+ }
+
+ /* connect to socket; fails if file doesn't exist */
+ strcpy(addr.sun_path, mFileName); // max 108 bytes
+ addr.sun_family = AF_UNIX;
+ cc = ::connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
+ if (cc < 0) {
+ // ENOENT means socket file doesn't exist
+ // ECONNREFUSED means socket exists but nobody is listening
+ LOG(LOG_ERROR, "lbicomm",
+ "AF_UNIX connect failed for '%s': %s\n", mFileName,strerror(errno));
+ goto bail;
+ }
+
+ /*
+ * Create the two halves. We dup() the sock so that closing one side
+ * does not hose the other.
+ */
+ *ppReadPipe = new Pipe();
+ (*ppReadPipe)->createReader(sock);
+ *ppWritePipe = new Pipe();
+ (*ppWritePipe)->createWriter(dup(sock));
+
+ assert(mHandle == kInvalidHandle);
+ sock = -1;
+ mIsListener = false;
+
+ result = true;
+
+bail:
+ if (sock >= 0)
+ close(sock);
+ return result;
+}
+
+/*
+ * Listen for a new connection.
+ */
+bool LocalBiChannel::listen(Pipe** ppReadPipe, Pipe** ppWritePipe)
+{
+ bool result = false;
+ struct sockaddr_un from;
+ socklen_t fromlen;
+ int sock, lsock;
+ int cc;
+
+ assert(mHandle != kInvalidHandle);
+ lsock = (int) mHandle;
+
+ LOG(LOG_DEBUG, "lbicomm", "AF_UNIX listening\n");
+ cc = ::listen(lsock, 5);
+ if (cc < 0) {
+ LOG(LOG_ERROR, "lbicomm", "AF_UNIX listen failed (errno=%d)\n", errno);
+ goto bail;
+ }
+
+ fromlen = sizeof(from); // not SUN_LEN()
+ sock = ::accept(lsock, (struct sockaddr*) &from, &fromlen);
+ if (sock < 0) {
+ LOG(LOG_WARN, "lbicomm", "AF_UNIX accept failed (errno=%d)\n", errno);
+ goto bail;
+ }
+
+ /*
+ * Create the two halves. We dup() the sock so that closing one side
+ * does not hose the other.
+ */
+ *ppReadPipe = new Pipe();
+ (*ppReadPipe)->createReader(sock);
+ *ppWritePipe = new Pipe();
+ (*ppWritePipe)->createWriter(dup(sock));
+ result = true;
+
+bail:
+ return result;
+}
+
+#endif