aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/opengl/tests/event_injector
diff options
context:
space:
mode:
Diffstat (limited to 'emulator/opengl/tests/event_injector')
-rw-r--r--emulator/opengl/tests/event_injector/Android.mk13
-rw-r--r--emulator/opengl/tests/event_injector/EventInjector.cpp76
-rw-r--r--emulator/opengl/tests/event_injector/EventInjector.h59
-rw-r--r--emulator/opengl/tests/event_injector/emulator-console.c345
-rw-r--r--emulator/opengl/tests/event_injector/emulator-console.h55
-rw-r--r--emulator/opengl/tests/event_injector/iolooper-select.c274
-rw-r--r--emulator/opengl/tests/event_injector/iolooper.h91
-rw-r--r--emulator/opengl/tests/event_injector/sockets.c1554
-rw-r--r--emulator/opengl/tests/event_injector/sockets.h432
9 files changed, 2899 insertions, 0 deletions
diff --git a/emulator/opengl/tests/event_injector/Android.mk b/emulator/opengl/tests/event_injector/Android.mk
new file mode 100644
index 000000000..26eb47691
--- /dev/null
+++ b/emulator/opengl/tests/event_injector/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+
+$(call emugl-begin-host-static-library,event_injector)
+
+LOCAL_SRC_FILES := \
+ EventInjector.cpp \
+ sockets.c \
+ emulator-console.c \
+ iolooper-select.c
+
+$(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
+
+$(call emugl-end-module)
diff --git a/emulator/opengl/tests/event_injector/EventInjector.cpp b/emulator/opengl/tests/event_injector/EventInjector.cpp
new file mode 100644
index 000000000..6dade6e49
--- /dev/null
+++ b/emulator/opengl/tests/event_injector/EventInjector.cpp
@@ -0,0 +1,76 @@
+/*
+* 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 "EventInjector.h"
+#include "emulator-console.h"
+
+#define PRIVATE EventInjectorPrivate
+
+class PRIVATE
+{
+public:
+ IoLooper* mLooper;
+ EmulatorConsole* mConsole;
+
+ EventInjectorPrivate(int port) {
+ mLooper = iolooper_new();
+ mConsole = emulatorConsole_new(port, mLooper);
+ }
+};
+
+EventInjector::EventInjector(int consolePort)
+{
+ mPrivate = new PRIVATE(consolePort);
+}
+
+EventInjector::~EventInjector()
+{
+ delete mPrivate;
+}
+
+void EventInjector::wait(int timeout_ms)
+{
+ iolooper_wait(mPrivate->mLooper, timeout_ms);
+}
+
+void EventInjector::poll(void)
+{
+ emulatorConsole_poll(mPrivate->mConsole);
+}
+
+void EventInjector::sendMouseDown( int x, int y )
+{
+ emulatorConsole_sendMouseDown(mPrivate->mConsole, x, y);
+}
+
+void EventInjector::sendMouseUp( int x, int y )
+{
+ emulatorConsole_sendMouseUp(mPrivate->mConsole, x, y);
+}
+
+void EventInjector::sendMouseMotion( int x, int y )
+{
+ emulatorConsole_sendMouseMotion(mPrivate->mConsole, x, y);
+}
+
+void EventInjector::sendKeyDown( int keycode )
+{
+ emulatorConsole_sendKey(mPrivate->mConsole, keycode, 1);
+}
+
+void EventInjector::sendKeyUp( int keycode )
+{
+ emulatorConsole_sendKey(mPrivate->mConsole, keycode, 0);
+}
diff --git a/emulator/opengl/tests/event_injector/EventInjector.h b/emulator/opengl/tests/event_injector/EventInjector.h
new file mode 100644
index 000000000..a8fded701
--- /dev/null
+++ b/emulator/opengl/tests/event_injector/EventInjector.h
@@ -0,0 +1,59 @@
+/*
+* 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.
+*/
+/* Event redirector is used to inject user events from a GL window
+ * into the emulated program.
+ */
+#ifndef EVENT_INJECTOR_H
+#define EVENT_INJECTOR_H
+
+class EventInjectorPrivate;
+
+class EventInjector
+{
+public:
+ EventInjector(int consolePort);
+ virtual ~EventInjector();
+
+ void wait( int timeout_ms );
+ void poll( void );
+
+ void sendMouseDown( int x, int y );
+ void sendMouseUp( int x, int y );
+ void sendMouseMotion( int x, int y );
+ void sendKeyDown( int keycode );
+ void sendKeyUp( int keycode );
+
+ /* Keycode values expected by the Linux kernel, and the emulator */
+ enum {
+ KEY_BACK = 158,
+ KEY_HOME = 102,
+ KEY_SOFT1 = 229,
+ KEY_LEFT = 105,
+ KEY_UP = 103,
+ KEY_DOWN = 108,
+ KEY_RIGHT = 106,
+ KEY_VOLUMEUP = 115,
+ KEY_VOLUMEDOWN = 114,
+ KEY_SEND = 231,
+ KEY_END = 107,
+ KEY_ENTER = 28,
+ };
+
+private:
+ EventInjectorPrivate* mPrivate;
+};
+
+#endif /* EVENT_INJECTOR_H */
diff --git a/emulator/opengl/tests/event_injector/emulator-console.c b/emulator/opengl/tests/event_injector/emulator-console.c
new file mode 100644
index 000000000..a8c49b291
--- /dev/null
+++ b/emulator/opengl/tests/event_injector/emulator-console.c
@@ -0,0 +1,345 @@
+/*
+* 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 "emulator-console.h"
+#include "sockets.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#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")
+#else
+# define DD(...) ((void)0)
+#endif
+
+#define ANEW0(p) (p) = calloc(sizeof(*(p)), 1)
+
+enum {
+ STATE_CONNECTING = 0,
+ STATE_CONNECTED,
+ STATE_WAITING,
+ STATE_ERROR = 2
+};
+
+typedef struct Msg {
+ const char* data; // pointer to data
+ int size; // size of data
+ int sent; // already sent (so sent..size remain in buffer).
+ struct Msg* next; // next message in queue.
+} Msg;
+
+static Msg*
+msg_alloc( const char* data, int datalen )
+{
+ Msg* msg;
+
+ msg = malloc(sizeof(*msg) + datalen);
+ msg->data = (const char*)(msg + 1);
+ msg->size = datalen;
+ msg->sent = 0;
+ memcpy((char*)msg->data, data, datalen);
+ msg->next = NULL;
+
+ return msg;
+}
+
+static void
+msg_free( Msg* msg )
+{
+ free(msg);
+}
+
+struct EmulatorConsole {
+ int fd;
+ IoLooper* looper;
+ int state;
+ Msg* out_msg;
+ SockAddress address;
+ int64_t waitUntil;
+};
+
+/* Read as much from the input as possible, ignoring it.
+ */
+static int
+emulatorConsole_eatInput( EmulatorConsole* con )
+{
+ for (;;) {
+ char temp[64];
+ int ret = socket_recv(con->fd, temp, sizeof temp);
+ if (ret < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return 0;
+ }
+ return -1;
+ }
+ if (ret == 0) {
+ return -1;
+ }
+ DD("Console received: '%.*s'", ret, temp);
+ }
+}
+
+static int
+emulatorConsole_sendOutput( EmulatorConsole* con )
+{
+ if (con->state != STATE_CONNECTED) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ while (con->out_msg != NULL) {
+ Msg* msg = con->out_msg;
+ int ret;
+
+ ret = socket_send(con->fd,
+ msg->data + msg->sent,
+ msg->size - msg->sent);
+ if (ret > 0) {
+ DD("Console sent: '%.*s'", ret, msg->data + msg->sent);
+
+ msg->sent += ret;
+ if (msg->sent == msg->size) {
+ con->out_msg = msg->next;
+ msg_free(msg);
+ }
+ continue;
+ }
+ if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ return 0;
+ }
+ con->state = STATE_ERROR;
+ D("Console error when sending: %s", strerror(errno));
+ return -1;
+ }
+ iolooper_del_write(con->looper, con->fd);
+ return 0;
+}
+
+static void
+emulatorConsole_completeConnect(EmulatorConsole* con)
+{
+ D("Console connected!");
+ iolooper_add_read(con->looper, con->fd);
+ iolooper_del_write(con->looper, con->fd);
+ con->state = STATE_CONNECTED;
+ if (con->out_msg != NULL) {
+ iolooper_add_write(con->looper, con->fd);
+ emulatorConsole_sendOutput(con);
+ }
+}
+
+static void
+emulatorConsole_retry(EmulatorConsole* con)
+{
+ /* Not possible yet, wait one second */
+ D("Could not connect to emulator, waiting 1 second: %s", errno_str);
+ con->state = STATE_WAITING;
+ con->waitUntil = iolooper_now() + 5000;
+}
+
+static void
+emulatorConsole_connect(EmulatorConsole* con)
+{
+ D("Trying to connect!");
+ if (con->fd < 0) {
+ con->fd = socket_create_inet( SOCKET_STREAM );
+ if (con->fd < 0) {
+ D("ERROR: Could not create socket: %s", errno_str);
+ con->state = STATE_ERROR;
+ return;
+ }
+ socket_set_nonblock(con->fd);
+ }
+ con->state = STATE_CONNECTING;
+ if (socket_connect(con->fd, &con->address) < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
+ iolooper_add_write(con->looper, con->fd);
+ } else {
+ emulatorConsole_retry(con);
+ }
+ return;
+ }
+
+ emulatorConsole_completeConnect(con);
+}
+
+static void
+emulatorConsole_reset( EmulatorConsole* con )
+{
+ D("Resetting console connection");
+ while (con->out_msg) {
+ Msg* msg = con->out_msg;
+ con->out_msg = msg->next;
+ msg_free(msg);
+ }
+ iolooper_del_read(con->looper, con->fd);
+ iolooper_del_write(con->looper, con->fd);
+ socket_close(con->fd);
+ con->fd = -1;
+ emulatorConsole_connect(con);
+}
+
+/* Create a new EmulatorConsole object to connect asynchronously to
+ * a given emulator port. Note that this should always succeeds since
+ * the connection is asynchronous.
+ */
+EmulatorConsole*
+emulatorConsole_new(int port, IoLooper* looper)
+{
+ EmulatorConsole* con;
+ SockAddress addr;
+
+ ANEW0(con);
+ con->looper = looper;
+ con->fd = -1;
+ sock_address_init_inet(&con->address, SOCK_ADDRESS_INET_LOOPBACK, port);
+
+ emulatorConsole_connect(con);
+ return con;
+}
+
+int
+emulatorConsole_poll( EmulatorConsole* con )
+{
+ int ret;
+
+ if (con->state == STATE_WAITING) {
+ if (iolooper_now() >= con->waitUntil)
+ emulatorConsole_connect(con);
+ return 0;
+ }
+
+ if (!iolooper_is_read(con->looper, con->fd) &&
+ !iolooper_is_write(con->looper, con->fd))
+ {
+ return 0;
+ }
+
+LOOP:
+ switch (con->state) {
+ case STATE_ERROR:
+ return -1;
+
+ case STATE_CONNECTING:
+ // read socket error to determine success / error.
+ if (socket_get_error(con->fd) != 0) {
+ emulatorConsole_retry(con);
+ } else {
+ emulatorConsole_completeConnect(con);
+ }
+ return 0;
+
+ case STATE_CONNECTED:
+ /* ignore input, if any */
+ if (iolooper_is_read(con->looper, con->fd)) {
+ if (emulatorConsole_eatInput(con) < 0) {
+ goto SET_ERROR;
+ }
+ }
+ /* send outgoing data, if any */
+ if (iolooper_is_write(con->looper, con->fd)) {
+ if (emulatorConsole_sendOutput(con) < 0) {
+ goto SET_ERROR;
+ }
+ }
+ return 0;
+
+ default:
+ D("UNSUPPORTED STATE!");
+ break;
+ }
+
+SET_ERROR:
+ D("Console ERROR!: %s\n", errno_str);
+ con->state = STATE_ERROR;
+ emulatorConsole_reset(con);
+ return -1;
+}
+
+/* Send a message to the console asynchronously. Any answer will be
+ * ignored. */
+void
+emulatorConsole_send( EmulatorConsole* con, const char* command )
+{
+ int cmdlen = strlen(command);
+ Msg* msg;
+ Msg** plast;
+
+ if (cmdlen == 0)
+ return;
+
+ /* Append new message at end of outgoing list */
+ msg = msg_alloc(command, cmdlen);
+ plast = &con->out_msg;
+ while (*plast) {
+ plast = &(*plast)->next;
+ }
+ *plast = msg;
+ if (con->out_msg == msg) {
+ iolooper_add_write(con->looper, con->fd);
+ }
+ emulatorConsole_sendOutput(con);
+}
+
+
+void
+emulatorConsole_sendMouseDown( EmulatorConsole* con, int x, int y )
+{
+ char temp[128];
+
+ D("sendMouseDown(%d,%d)", x, y);
+ snprintf(temp, sizeof temp,
+ "event send 3:0:%d 3:1:%d 1:330:1 0:0:0\r\n",
+ x, y);
+ emulatorConsole_send(con, temp);
+}
+
+void
+emulatorConsole_sendMouseMotion( EmulatorConsole* con, int x, int y )
+{
+ /* Same as mouse down */
+ emulatorConsole_sendMouseDown(con, x, y);
+}
+
+void
+emulatorConsole_sendMouseUp( EmulatorConsole* con, int x, int y )
+{
+ char temp[128];
+
+ D("sendMouseUp(%d,%d)", x, y);
+ snprintf(temp, sizeof temp,
+ "event send 3:0:%d 3:1:%d 1:330:0 0:0:0\r\n",
+ x, y);
+ emulatorConsole_send(con, temp);
+}
+
+#define EE(x,y) if (keycode == x) return y;
+
+void
+emulatorConsole_sendKey( EmulatorConsole* con, int keycode, int down )
+{
+ char temp[128];
+
+ snprintf(temp, sizeof temp,
+ "event send EV_KEY:%d:%d 0:0:0\r\n", keycode, down);
+ emulatorConsole_send(con, temp);
+}
diff --git a/emulator/opengl/tests/event_injector/emulator-console.h b/emulator/opengl/tests/event_injector/emulator-console.h
new file mode 100644
index 000000000..19e9687d5
--- /dev/null
+++ b/emulator/opengl/tests/event_injector/emulator-console.h
@@ -0,0 +1,55 @@
+/*
+* 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.
+*/
+#ifndef ANDROID_EMULATOR_CONSOLE_H
+#define ANDROID_EMULATOR_CONSOLE_H
+
+#include "iolooper.h"
+#include "sockets.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct EmulatorConsole EmulatorConsole;
+
+/* Create a new EmulatorConsole object to connect asynchronously to
+ * a given emulator port. Note that this always succeeds since the
+ * connection is asynchronous.
+ */
+EmulatorConsole* emulatorConsole_new(int port, IoLooper* looper);
+
+/* Call this after an iolooper_poll() or iolooper_wait() to check
+ * the status of the console's socket and act upon it.
+ *
+ * Returns 0 on success, or -1 on error (which indicates disconnection!)
+ */
+int emulatorConsole_poll( EmulatorConsole* console );
+
+/* Send a message to the console asynchronously. Any answer will be
+ * ignored. */
+void emulatorConsole_send( EmulatorConsole* console, const char* command );
+
+void emulatorConsole_sendMouseDown( EmulatorConsole* con, int x, int y );
+void emulatorConsole_sendMouseMotion( EmulatorConsole* con, int x, int y );
+void emulatorConsole_sendMouseUp( EmulatorConsole* con, int x, int y );
+
+void emulatorConsole_sendKey( EmulatorConsole* con, int keycode, int down );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_EMULATOR_CONSOLE_H */
diff --git a/emulator/opengl/tests/event_injector/iolooper-select.c b/emulator/opengl/tests/event_injector/iolooper-select.c
new file mode 100644
index 000000000..c5fc7c22b
--- /dev/null
+++ b/emulator/opengl/tests/event_injector/iolooper-select.c
@@ -0,0 +1,274 @@
+/*
+* 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 <errno.h>
+#include <stdlib.h>
+#include "iolooper.h"
+#include "sockets.h"
+
+/* An implementation of iolooper.h based on Unix select() */
+#ifdef _WIN32
+# include <winsock2.h>
+# include <time.h>
+#else
+# include <sys/types.h>
+# include <sys/select.h>
+# include <sys/time.h>
+#endif
+
+struct IoLooper {
+ fd_set reads[1];
+ fd_set writes[1];
+ fd_set reads_result[1];
+ fd_set writes_result[1];
+ int max_fd;
+ int max_fd_valid;
+};
+
+IoLooper*
+iolooper_new(void)
+{
+ IoLooper* iol = malloc(sizeof(*iol));
+ iolooper_reset(iol);
+ return iol;
+}
+
+void
+iolooper_free( IoLooper* iol )
+{
+ free(iol);
+}
+
+void
+iolooper_reset( IoLooper* iol )
+{
+ FD_ZERO(iol->reads);
+ FD_ZERO(iol->writes);
+ iol->max_fd = -1;
+ iol->max_fd_valid = 1;
+}
+
+static void
+iolooper_add_fd( IoLooper* iol, int fd )
+{
+ if (iol->max_fd_valid && fd > iol->max_fd) {
+ iol->max_fd = fd;
+ }
+}
+
+static void
+iolooper_del_fd( IoLooper* iol, int fd )
+{
+ if (iol->max_fd_valid && fd == iol->max_fd)
+ iol->max_fd_valid = 0;
+}
+
+void
+iolooper_modify( IoLooper* iol, int fd, int oldflags, int newflags )
+{
+ if (fd < 0)
+ return;
+
+ int changed = oldflags ^ newflags;
+
+ if ((changed & IOLOOPER_READ) != 0) {
+ if ((newflags & IOLOOPER_READ) != 0)
+ iolooper_add_read(iol, fd);
+ else
+ iolooper_del_read(iol, fd);
+ }
+ if ((changed & IOLOOPER_WRITE) != 0) {
+ if ((newflags & IOLOOPER_WRITE) != 0)
+ iolooper_add_write(iol, fd);
+ else
+ iolooper_del_write(iol, fd);
+ }
+}
+
+
+static int
+iolooper_fd_count( IoLooper* iol )
+{
+ int max_fd = iol->max_fd;
+ int fd;
+
+ if (iol->max_fd_valid)
+ return max_fd + 1;
+
+ /* recompute max fd */
+ for (fd = 0; fd < FD_SETSIZE; fd++) {
+ if (!FD_ISSET(fd, iol->reads) && !FD_ISSET(fd, iol->writes))
+ continue;
+
+ max_fd = fd;
+ }
+ iol->max_fd = max_fd;
+ iol->max_fd_valid = 1;
+
+ return max_fd + 1;
+}
+
+void
+iolooper_add_read( IoLooper* iol, int fd )
+{
+ if (fd >= 0) {
+ iolooper_add_fd(iol, fd);
+ FD_SET(fd, iol->reads);
+ }
+}
+
+void
+iolooper_add_write( IoLooper* iol, int fd )
+{
+ if (fd >= 0) {
+ iolooper_add_fd(iol, fd);
+ FD_SET(fd, iol->writes);
+ }
+}
+
+void
+iolooper_del_read( IoLooper* iol, int fd )
+{
+ if (fd >= 0) {
+ iolooper_del_fd(iol, fd);
+ FD_CLR(fd, iol->reads);
+ }
+}
+
+void
+iolooper_del_write( IoLooper* iol, int fd )
+{
+ if (fd >= 0) {
+ iolooper_del_fd(iol, fd);
+ FD_CLR(fd, iol->writes);
+ }
+}
+
+int
+iolooper_poll( IoLooper* iol )
+{
+ int count = iolooper_fd_count(iol);
+ int ret;
+ fd_set errs;
+
+ if (count == 0)
+ return 0;
+
+ FD_ZERO(&errs);
+
+ do {
+ struct timeval tv;
+
+ tv.tv_sec = tv.tv_usec = 0;
+
+ iol->reads_result[0] = iol->reads[0];
+ iol->writes_result[0] = iol->writes[0];
+
+ ret = select( count, iol->reads_result, iol->writes_result, &errs, &tv);
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+int
+iolooper_wait( IoLooper* iol, int64_t duration )
+{
+ int count = iolooper_fd_count(iol);
+ int ret;
+ fd_set errs;
+ struct timeval tm0, *tm = NULL;
+
+ if (count == 0)
+ return 0;
+
+ if (duration < 0)
+ tm = NULL;
+ else {
+ tm = &tm0;
+ tm->tv_sec = duration / 1000;
+ tm->tv_usec = (duration - 1000*tm->tv_sec) * 1000;
+ }
+
+ FD_ZERO(&errs);
+
+ do {
+ iol->reads_result[0] = iol->reads[0];
+ iol->writes_result[0] = iol->writes[0];
+
+ ret = select( count, iol->reads_result, iol->writes_result, &errs, tm);
+ if (ret == 0) {
+ // Indicates timeout
+ errno = ETIMEDOUT;
+ }
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+
+int
+iolooper_is_read( IoLooper* iol, int fd )
+{
+ return FD_ISSET(fd, iol->reads_result);
+}
+
+int
+iolooper_is_write( IoLooper* iol, int fd )
+{
+ return FD_ISSET(fd, iol->writes_result);
+}
+
+int
+iolooper_has_operations( IoLooper* iol )
+{
+ return iolooper_fd_count(iol) > 0;
+}
+
+int64_t
+iolooper_now(void)
+{
+#ifdef _WIN32
+ FILETIME now;
+ int64_t now_100ns;
+
+ GetSystemTimeAsFileTime(&now);
+
+ /* Get the time as hundreds of nanosecond intervals since
+ 12:00 AM January 1t 1601 UTC. We don't really need
+ to compute the value relative to the Posix epoch */
+ now_100ns = ((int64_t)now.dwHighDateTime << 32) | now.dwLowDateTime;
+
+ /* 100 ns == 0.1 us == 0.0001 ms */
+ return now_100ns / 10000LL;
+
+#else /* !_WIN32 */
+ struct timeval time_now;
+ return gettimeofday(&time_now, NULL) ? -1 : (int64_t)time_now.tv_sec * 1000LL +
+ time_now.tv_usec / 1000;
+#endif /* !_WIN32 */
+}
+
+int
+iolooper_wait_absolute(IoLooper* iol, int64_t deadline)
+{
+ int64_t timeout = deadline - iolooper_now();
+
+ /* If the deadline has passed, set the timeout to 0, this allows us
+ * to poll the file descriptor nonetheless */
+ if (timeout < 0)
+ timeout = 0;
+
+ return iolooper_wait(iol, timeout);
+}
diff --git a/emulator/opengl/tests/event_injector/iolooper.h b/emulator/opengl/tests/event_injector/iolooper.h
new file mode 100644
index 000000000..4aa3db728
--- /dev/null
+++ b/emulator/opengl/tests/event_injector/iolooper.h
@@ -0,0 +1,91 @@
+/*
+* 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.
+*/
+#ifndef IOLOOPER_H
+#define IOLOOPER_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* An IOLooper is an abstraction for select() */
+
+typedef struct IoLooper IoLooper;
+
+IoLooper* iolooper_new(void);
+void iolooper_free( IoLooper* iol );
+void iolooper_reset( IoLooper* iol );
+
+void iolooper_add_read( IoLooper* iol, int fd );
+void iolooper_add_write( IoLooper* iol, int fd );
+void iolooper_del_read( IoLooper* iol, int fd );
+void iolooper_del_write( IoLooper* iol, int fd );
+
+enum {
+ IOLOOPER_READ = (1<<0),
+ IOLOOPER_WRITE = (1<<1),
+};
+void iolooper_modify( IoLooper* iol, int fd, int oldflags, int newflags);
+
+int iolooper_poll( IoLooper* iol );
+/* Wrapper around select()
+ * Return:
+ * > 0 in case an I/O has occurred, or < 0 on error, or 0 on timeout with
+ * errno set to ETIMEDOUT.
+ */
+int iolooper_wait( IoLooper* iol, int64_t duration );
+
+int iolooper_is_read( IoLooper* iol, int fd );
+int iolooper_is_write( IoLooper* iol, int fd );
+/* Returns 1 if this IoLooper has one or more file descriptor to interact with */
+int iolooper_has_operations( IoLooper* iol );
+/* Gets current time in milliseconds.
+ * Return:
+ * Number of milliseconds corresponded to the current time on success, or -1
+ * on failure.
+ */
+int64_t iolooper_now(void);
+/* Waits for an I/O to occur before specific absolute time.
+ * This routine should be used (instead of iolooper_wait) in cases when multiple
+ * sequential I/O should be completed within given time interval. For instance,
+ * consider the scenario, when "server" does two sequential writes, and "client"
+ * now has to read data transferred with these two distinct writes. It might be
+ * wasteful to do two reads, each with the same (large) timeout. Instead, it
+ * would be better to assign a deadline for both reads before the first read,
+ * and call iolooper_wait_absoulte with the same deadline value:
+ * int64_t deadline = iolooper_now() + TIMEOUT;
+ * if (iolooper_wait_absoulte(iol, deadline)) {
+ * // Process first buffer.
+ * (iolooper_wait_absoulte(iol, deadline)) {
+ * // Process second read
+ * }
+ * }
+ * Param:
+ * iol IoLooper instance for an I/O.
+ * deadline Deadline (absoulte time in milliseconds) before which an I/O should
+ * occur.
+ * Return:
+ * Number of I/O descriptors set in iol, if an I/O has occurred, 0 if no I/O
+ * occurred before the deadline, or -1 on error.
+ */
+int iolooper_wait_absolute(IoLooper* iol, int64_t deadline);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IOLOOPER_H */
diff --git a/emulator/opengl/tests/event_injector/sockets.c b/emulator/opengl/tests/event_injector/sockets.c
new file mode 100644
index 000000000..a2cc334a5
--- /dev/null
+++ b/emulator/opengl/tests/event_injector/sockets.c
@@ -0,0 +1,1554 @@
+/*
+* 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.
+*/
+#ifdef __linux__ /* Recent versions of glibc only define EAI_NODATA, which is an
+ extension to the POSIX standard, if _GNU_SOURCE is defined. */
+# define _GNU_SOURCE 1
+#endif
+
+#include "sockets.h"
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+//#include "android/utils/path.h"
+//#include "android/utils/debug.h"
+//#include "android/utils/misc.h"
+//#include "android/utils/system.h"
+
+#define D(...) ((void)0)
+
+#ifdef _WIN32
+# define xxWIN32_LEAN_AND_MEAN
+# define _WIN32_WINNT 0x501
+# include <windows.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else /* !_WIN32 */
+# include <sys/ioctl.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# include <netdb.h>
+# if HAVE_UNIX_SOCKETS
+# include <sys/un.h>
+# ifndef UNIX_PATH_MAX
+# define UNIX_PATH_MAX (sizeof(((struct sockaddr_un*)0)->sun_path)-1)
+# endif
+# endif
+#endif /* !_WIN32 */
+
+#define MIN(x,y) ({ typeof(x) _x = (x); typeof(y) _y = (y); _x <= _y ? _x : _y; })
+#define AFREE(p) free(p)
+#define AARRAY_NEW(p,count) (p) = malloc(sizeof(*(p))*(count))
+#define AARRAY_NEW0(p,count) (p) = calloc(sizeof(*(p)),(count))
+
+/* QSOCKET_CALL is used to deal with the fact that EINTR happens pretty
+ * easily in QEMU since we use SIGALRM to implement periodic timers
+ */
+#ifdef _WIN32
+# define QSOCKET_CALL(_ret,_cmd) \
+ do { _ret = (_cmd); } while ( _ret < 0 && WSAGetLastError() == WSAEINTR )
+#else
+# define QSOCKET_CALL(_ret,_cmd) \
+ do { \
+ errno = 0; \
+ do { _ret = (_cmd); } while ( _ret < 0 && errno == EINTR ); \
+ } while (0);
+#endif
+
+#ifdef _WIN32
+
+#include <errno.h>
+
+static int winsock_error;
+
+#define WINSOCK_ERRORS_LIST \
+ EE(WSA_INVALID_HANDLE,EINVAL,"invalid handle") \
+ EE(WSA_NOT_ENOUGH_MEMORY,ENOMEM,"not enough memory") \
+ EE(WSA_INVALID_PARAMETER,EINVAL,"invalid parameter") \
+ EE(WSAEINTR,EINTR,"interrupted function call") \
+ EE(WSAEALREADY,EALREADY,"operation already in progress") \
+ EE(WSAEBADF,EBADF,"bad file descriptor") \
+ EE(WSAEACCES,EACCES,"permission denied") \
+ EE(WSAEFAULT,EFAULT,"bad address") \
+ EE(WSAEINVAL,EINVAL,"invalid argument") \
+ EE(WSAEMFILE,EMFILE,"too many opened files") \
+ EE(WSAEWOULDBLOCK,EWOULDBLOCK,"resource temporarily unavailable") \
+ EE(WSAEINPROGRESS,EINPROGRESS,"operation now in progress") \
+ EE(WSAEALREADY,EAGAIN,"operation already in progress") \
+ EE(WSAENOTSOCK,EBADF,"socket operation not on socket") \
+ EE(WSAEDESTADDRREQ,EDESTADDRREQ,"destination address required") \
+ EE(WSAEMSGSIZE,EMSGSIZE,"message too long") \
+ EE(WSAEPROTOTYPE,EPROTOTYPE,"wrong protocol type for socket") \
+ EE(WSAENOPROTOOPT,ENOPROTOOPT,"bad protocol option") \
+ EE(WSAEADDRINUSE,EADDRINUSE,"address already in use") \
+ EE(WSAEADDRNOTAVAIL,EADDRNOTAVAIL,"cannot assign requested address") \
+ EE(WSAENETDOWN,ENETDOWN,"network is down") \
+ EE(WSAENETUNREACH,ENETUNREACH,"network unreachable") \
+ EE(WSAENETRESET,ENETRESET,"network dropped connection on reset") \
+ EE(WSAECONNABORTED,ECONNABORTED,"software caused connection abort") \
+ EE(WSAECONNRESET,ECONNRESET,"connection reset by peer") \
+ EE(WSAENOBUFS,ENOBUFS,"no buffer space available") \
+ EE(WSAEISCONN,EISCONN,"socket is already connected") \
+ EE(WSAENOTCONN,ENOTCONN,"socket is not connected") \
+ EE(WSAESHUTDOWN,ESHUTDOWN,"cannot send after socket shutdown") \
+ EE(WSAETOOMANYREFS,ETOOMANYREFS,"too many references") \
+ EE(WSAETIMEDOUT,ETIMEDOUT,"connection timed out") \
+ EE(WSAECONNREFUSED,ECONNREFUSED,"connection refused") \
+ EE(WSAELOOP,ELOOP,"cannot translate name") \
+ EE(WSAENAMETOOLONG,ENAMETOOLONG,"name too long") \
+ EE(WSAEHOSTDOWN,EHOSTDOWN,"host is down") \
+ EE(WSAEHOSTUNREACH,EHOSTUNREACH,"no route to host") \
+
+typedef struct {
+ int winsock;
+ int unix;
+ const char* string;
+} WinsockError;
+
+static const WinsockError _winsock_errors[] = {
+#define EE(w,u,s) { w, u, s },
+ WINSOCK_ERRORS_LIST
+#undef EE
+ { -1, -1, NULL }
+};
+
+/* this function reads the latest winsock error code and updates
+ * errno to a matching value. It also returns the new value of
+ * errno.
+ */
+static int
+_fix_errno( void )
+{
+ const WinsockError* werr = _winsock_errors;
+ int unix = EINVAL; /* generic error code */
+
+ winsock_error = WSAGetLastError();
+
+ for ( ; werr->string != NULL; werr++ ) {
+ if (werr->winsock == winsock_error) {
+ unix = werr->unix;
+ break;
+ }
+ }
+ errno = unix;
+ return -1;
+}
+
+static int
+_set_errno( int code )
+{
+ winsock_error = -1;
+ errno = code;
+ return -1;
+}
+
+/* this function returns a string describing the latest Winsock error */
+const char*
+_errno_str(void)
+{
+ const WinsockError* werr = _winsock_errors;
+ const char* result = NULL;
+
+ for ( ; werr->string; werr++ ) {
+ if (werr->winsock == winsock_error) {
+ result = werr->string;
+ break;
+ }
+ }
+
+ if (result == NULL) {
+ result = "Unknown socket error";
+ }
+ return result;
+}
+#else
+static int
+_fix_errno( void )
+{
+ return -1;
+}
+
+static int
+_set_errno( int code )
+{
+ errno = code;
+ return -1;
+}
+#endif
+
+/* socket types */
+
+static int
+socket_family_to_bsd( SocketFamily family )
+{
+ switch (family) {
+ case SOCKET_INET: return AF_INET;
+ case SOCKET_IN6: return AF_INET6;
+#if HAVE_UNIX_SOCKETS
+ case SOCKET_UNIX: return AF_LOCAL;
+#endif
+ default: return -1;
+ }
+}
+
+static int
+socket_type_to_bsd( SocketType type )
+{
+ switch (type) {
+ case SOCKET_DGRAM: return SOCK_DGRAM;
+ case SOCKET_STREAM: return SOCK_STREAM;
+ default: return 0;
+ }
+}
+
+static SocketType
+socket_type_from_bsd( int type )
+{
+ switch (type) {
+ case SOCK_DGRAM: return SOCKET_DGRAM;
+ case SOCK_STREAM: return SOCKET_STREAM;
+ default: return (SocketType) SOCKET_UNSPEC;
+ }
+}
+
+#if 0
+static int
+socket_type_check( SocketType type )
+{
+ return (type == SOCKET_DGRAM || type == SOCKET_STREAM);
+}
+#endif
+
+typedef union {
+ struct sockaddr sa[1];
+ struct sockaddr_in in[1];
+#if HAVE_IN6_SOCKETS
+ struct sockaddr_in6 in6[1];
+#endif
+#if HAVE_UNIX_SOCKETS
+ struct sockaddr_un un[1];
+#endif
+} sockaddr_storage;
+
+/* socket addresses */
+
+void
+sock_address_init_inet( SockAddress* a, uint32_t ip, uint16_t port )
+{
+ a->family = SOCKET_INET;
+ a->u.inet.port = port;
+ a->u.inet.address = ip;
+}
+
+void
+sock_address_init_in6 ( SockAddress* a, const uint8_t* ip6[16], uint16_t port )
+{
+ a->family = SOCKET_IN6;
+ a->u.in6.port = port;
+ memcpy( a->u.in6.address, ip6, sizeof(a->u.in6.address) );
+}
+
+void
+sock_address_init_unix( SockAddress* a, const char* path )
+{
+ a->family = SOCKET_UNIX;
+ a->u._unix.path = strdup(path ? path : "");
+ a->u._unix.owner = 1;
+}
+
+void sock_address_done( SockAddress* a )
+{
+ if (a->family == SOCKET_UNIX && a->u._unix.owner) {
+ a->u._unix.owner = 0;
+ free((char*)a->u._unix.path);
+ }
+}
+
+static char*
+format_char( char* buf, char* end, int c )
+{
+ if (buf < end) {
+ if (buf+1 == end) {
+ *buf++ = 0;
+ } else {
+ *buf++ = (char) c;
+ *buf = 0;
+ }
+ }
+ return buf;
+}
+
+static char*
+format_str( char* buf, char* end, const char* str )
+{
+ int len = strlen(str);
+ int avail = end - buf;
+
+ if (len > avail)
+ len = avail;
+
+ memcpy( buf, str, len );
+ buf += len;
+
+ if (buf == end)
+ buf[-1] = 0;
+ else
+ buf[0] = 0;
+
+ return buf;
+}
+
+static char*
+format_unsigned( char* buf, char* end, unsigned val )
+{
+ char temp[16];
+ int nn;
+
+ for ( nn = 0; val != 0; nn++ ) {
+ int rem = val % 10;
+ temp[nn] = '0'+rem;
+ val /= 10;
+ }
+
+ if (nn == 0)
+ temp[nn++] = '0';
+
+ while (nn > 0)
+ buf = format_char(buf, end, temp[--nn]);
+
+ return buf;
+}
+
+static char*
+format_hex( char* buf, char* end, unsigned val, int ndigits )
+{
+ int shift = 4*ndigits;
+ static const char hex[16] = "0123456789abcdef";
+
+ while (shift >= 0) {
+ buf = format_char(buf, end, hex[(val >> shift) & 15]);
+ shift -= 4;
+ }
+ return buf;
+}
+
+static char*
+format_ip4( char* buf, char* end, uint32_t ip )
+{
+ buf = format_unsigned( buf, end, (unsigned)(ip >> 24) );
+ buf = format_char( buf, end, '.');
+ buf = format_unsigned( buf, end, (unsigned)((ip >> 16) & 255));
+ buf = format_char( buf, end, '.');
+ buf = format_unsigned( buf, end, (unsigned)((ip >> 8) & 255));
+ buf = format_char( buf, end, '.');
+ buf = format_unsigned( buf, end, (unsigned)(ip & 255));
+ return buf;
+}
+
+static char*
+format_ip6( char* buf, char* end, const uint8_t* ip6 )
+{
+ int nn;
+ for (nn = 0; nn < 8; nn++) {
+ int val = (ip6[0] << 16) | ip6[1];
+ ip6 += 2;
+ if (nn > 0)
+ buf = format_char(buf, end, ':');
+ if (val == 0)
+ continue;
+ buf = format_hex(buf, end, val, 4);
+ }
+ return buf;
+}
+
+const char*
+sock_address_to_string( const SockAddress* a )
+{
+ static char buf0[PATH_MAX];
+ char *buf = buf0, *end = buf + sizeof(buf0);
+
+ switch (a->family) {
+ case SOCKET_INET:
+ buf = format_ip4( buf, end, a->u.inet.address );
+ buf = format_char( buf, end, ':' );
+ buf = format_unsigned( buf, end, (unsigned) a->u.inet.port );
+ break;
+
+ case SOCKET_IN6:
+ buf = format_ip6( buf, end, a->u.in6.address );
+ buf = format_char( buf, end, ':' );
+ buf = format_unsigned( buf, end, (unsigned) a->u.in6.port );
+ break;
+
+ case SOCKET_UNIX:
+ buf = format_str( buf, end, a->u._unix.path );
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return buf0;
+}
+
+int
+sock_address_equal( const SockAddress* a, const SockAddress* b )
+{
+ if (a->family != b->family)
+ return 0;
+
+ switch (a->family) {
+ case SOCKET_INET:
+ return (a->u.inet.address == b->u.inet.address &&
+ a->u.inet.port == b->u.inet.port);
+
+ case SOCKET_IN6:
+ return (!memcmp(a->u.in6.address, b->u.in6.address, 16) &&
+ a->u.in6.port == b->u.in6.port);
+
+ case SOCKET_UNIX:
+ return (!strcmp(a->u._unix.path, b->u._unix.path));
+
+ default:
+ return 0;
+ }
+}
+
+int
+sock_address_get_port( const SockAddress* a )
+{
+ switch (a->family) {
+ case SOCKET_INET:
+ return a->u.inet.port;
+ case SOCKET_IN6:
+ return a->u.in6.port;
+ default:
+ return -1;
+ }
+}
+
+void
+sock_address_set_port( SockAddress* a, uint16_t port )
+{
+ switch (a->family) {
+ case SOCKET_INET:
+ a->u.inet.port = port;
+ break;
+ case SOCKET_IN6:
+ a->u.in6.port = port;
+ break;
+ default:
+ ;
+ }
+}
+
+const char*
+sock_address_get_path( const SockAddress* a )
+{
+ if (a->family == SOCKET_UNIX)
+ return a->u._unix.path;
+ else
+ return NULL;
+}
+
+int
+sock_address_get_ip( const SockAddress* a )
+{
+ if (a->family == SOCKET_INET)
+ return a->u.inet.address;
+
+ return -1;
+}
+
+#if 0
+char*
+bufprint_sock_address( char* p, char* end, const SockAddress* a )
+{
+ switch (a->family) {
+ case SOCKET_INET:
+ {
+ uint32_t ip = a->u.inet.address;
+
+ return bufprint( p, end, "%d.%d.%d.%d:%d",
+ (ip >> 24) & 255, (ip >> 16) & 255,
+ (ip >> 8) & 255, ip & 255,
+ a->u.inet.port );
+ }
+ case SOCKET_IN6:
+ {
+ int nn = 0;
+ const char* column = "";
+ const uint8_t* tab = a->u.in6.address;
+ for (nn = 0; nn < 16; nn += 2) {
+ p = bufprint(p, end, "%s%04x", column, (tab[n] << 8) | tab[n+1]);
+ column = ":";
+ }
+ return bufprint(p, end, ":%d", a->u.in6.port);
+ }
+ case SOCKET_UNIX:
+ {
+ return bufprint(p, end, "%s", a->u._unix.path);
+ }
+ default:
+ return p;
+ }
+}
+#endif
+
+static int
+sock_address_to_bsd( const SockAddress* a, sockaddr_storage* paddress, socklen_t *psize )
+{
+ switch (a->family) {
+ case SOCKET_INET:
+ {
+ struct sockaddr_in* dst = paddress->in;
+
+ *psize = sizeof(*dst);
+
+ memset( paddress, 0, *psize );
+
+ dst->sin_family = AF_INET;
+ dst->sin_port = htons(a->u.inet.port);
+ dst->sin_addr.s_addr = htonl(a->u.inet.address);
+ }
+ break;
+
+#if HAVE_IN6_SOCKETS
+ case SOCKET_IN6:
+ {
+ struct sockaddr_in6* dst = paddress->in6;
+
+ *psize = sizeof(*dst);
+
+ memset( paddress, 0, *psize );
+
+ dst->sin6_family = AF_INET6;
+ dst->sin6_port = htons(a->u.in6.port);
+ memcpy( dst->sin6_addr.s6_addr, a->u.in6.address, 16 );
+ }
+ break;
+#endif /* HAVE_IN6_SOCKETS */
+
+#if HAVE_UNIX_SOCKETS
+ case SOCKET_UNIX:
+ {
+ int slen = strlen(a->u._unix.path);
+ struct sockaddr_un* dst = paddress->un;
+
+ if (slen >= (int)UNIX_PATH_MAX)
+ return -1;
+
+ memset( dst, 0, sizeof(*dst) );
+
+ dst->sun_family = AF_LOCAL;
+ memcpy( dst->sun_path, a->u._unix.path, slen );
+ dst->sun_path[slen] = 0;
+
+ *psize = (char*)&dst->sun_path[slen+1] - (char*)dst;
+ }
+ break;
+#endif /* HAVE_UNIX_SOCKETS */
+
+ default:
+ return _set_errno(EINVAL);
+ }
+
+ return 0;
+}
+
+static int
+sock_address_from_bsd( SockAddress* a, const void* from, size_t fromlen )
+{
+ switch (((struct sockaddr *)from)->sa_family) {
+ case AF_INET:
+ {
+ const struct sockaddr_in* src = from;
+
+ if (fromlen < sizeof(*src))
+ return _set_errno(EINVAL);
+
+ a->family = SOCKET_INET;
+ a->u.inet.port = ntohs(src->sin_port);
+ a->u.inet.address = ntohl(src->sin_addr.s_addr);
+ }
+ break;
+
+#ifdef HAVE_IN6_SOCKETS
+ case AF_INET6:
+ {
+ const struct sockaddr_in6* src = from;
+
+ if (fromlen < sizeof(*src))
+ return _set_errno(EINVAL);
+
+ a->family = SOCKET_IN6;
+ a->u.in6.port = ntohs(src->sin6_port);
+ memcpy(a->u.in6.address, src->sin6_addr.s6_addr, 16);
+ }
+ break;
+#endif
+
+#ifdef HAVE_UNIX_SOCKETS
+ case AF_LOCAL:
+ {
+ const struct sockaddr_un* src = from;
+ char* end;
+
+ if (fromlen < sizeof(*src))
+ return _set_errno(EINVAL);
+
+ /* check that the path is zero-terminated */
+ end = memchr(src->sun_path, 0, UNIX_PATH_MAX);
+ if (end == NULL)
+ return _set_errno(EINVAL);
+
+ a->family = SOCKET_UNIX;
+ a->u._unix.owner = 1;
+ a->u._unix.path = strdup(src->sun_path);
+ }
+ break;
+#endif
+
+ default:
+ return _set_errno(EINVAL);
+ }
+ return 0;
+}
+
+
+int
+sock_address_init_resolve( SockAddress* a, const char* hostname, uint16_t port, int preferIn6 )
+{
+ struct addrinfo hints[1];
+ struct addrinfo* res;
+ int ret;
+
+ memset(hints, 0, sizeof(hints));
+ hints->ai_family = preferIn6 ? AF_INET6 : AF_UNSPEC;
+
+ ret = getaddrinfo(hostname, NULL, hints, &res);
+ if (ret != 0) {
+ int err;
+
+ switch (ret) {
+ case EAI_AGAIN: /* server is down */
+ case EAI_FAIL: /* server is sick */
+ err = EHOSTDOWN;
+ break;
+
+#ifdef EAI_NODATA
+ case EAI_NODATA:
+#endif
+ case EAI_NONAME:
+ err = ENOENT;
+ break;
+
+ case EAI_MEMORY:
+ err = ENOMEM;
+ break;
+
+ default:
+ err = EINVAL;
+ }
+ return _set_errno(err);
+ }
+
+ /* Parse the returned list of addresses. */
+ {
+ struct addrinfo* res_ipv4 = NULL;
+ struct addrinfo* res_ipv6 = NULL;
+ struct addrinfo* r;
+
+ /* If preferIn6 is false, we stop on the first IPv4 address,
+ * otherwise, we stop on the first IPv6 one
+ */
+ for (r = res; r != NULL; r = r->ai_next) {
+ if (r->ai_family == AF_INET && res_ipv4 == NULL) {
+ res_ipv4 = r;
+ if (!preferIn6)
+ break;
+ }
+ else if (r->ai_family == AF_INET6 && res_ipv6 == NULL) {
+ res_ipv6 = r;
+ if (preferIn6)
+ break;
+ }
+ }
+
+ /* Select the best address in 'r', which will be NULL
+ * if there is no corresponding address.
+ */
+ if (preferIn6) {
+ r = res_ipv6;
+ if (r == NULL)
+ r = res_ipv4;
+ } else {
+ r = res_ipv4;
+ if (r == NULL)
+ r = res_ipv6;
+ }
+
+ if (r == NULL) {
+ ret = _set_errno(ENOENT);
+ goto Exit;
+ }
+
+ /* Convert to a SockAddress */
+ ret = sock_address_from_bsd( a, r->ai_addr, r->ai_addrlen );
+ if (ret < 0)
+ goto Exit;
+ }
+
+ /* need to set the port */
+ switch (a->family) {
+ case SOCKET_INET: a->u.inet.port = port; break;
+ case SOCKET_IN6: a->u.in6.port = port; break;
+ default: ;
+ }
+
+Exit:
+ freeaddrinfo(res);
+ return ret;
+}
+
+/* The Winsock headers for mingw lack some definitions */
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+
+SockAddress**
+sock_address_list_create( const char* hostname,
+ const char* port,
+ unsigned flags )
+{
+ SockAddress** list = NULL;
+ SockAddress* addr;
+ int nn, count, ret;
+ struct addrinfo ai, *res, *e;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_flags |= AI_ADDRCONFIG;
+ ai.ai_family = PF_UNSPEC;
+
+ if (flags & SOCKET_LIST_FORCE_INET)
+ ai.ai_family = PF_INET;
+ else if (flags & SOCKET_LIST_FORCE_IN6)
+ ai.ai_family = PF_INET6;
+
+ if (flags & SOCKET_LIST_PASSIVE)
+ ai.ai_flags |= AI_PASSIVE;
+ else
+ ai.ai_flags |= AI_CANONNAME;
+
+ if (flags & SOCKET_LIST_DGRAM)
+ ai.ai_socktype = SOCK_DGRAM;
+
+ while (1) {
+ struct addrinfo hints = ai;
+
+ ret = getaddrinfo(hostname, port, &hints, &res);
+ if (ret == 0)
+ break;
+
+ switch (ret) {
+#ifdef EAI_ADDRFAMILY
+ case EAI_ADDRFAMILY:
+#endif
+ case EAI_NODATA:
+ _set_errno(ENOENT);
+ break;
+ case EAI_FAMILY:
+ _set_errno(EAFNOSUPPORT);
+ break;
+ case EAI_AGAIN:
+ _set_errno(EAGAIN);
+ break;
+#ifdef EAI_SYSTEM
+ case EAI_SYSTEM:
+ if (errno == EINTR)
+ continue;
+ break;
+#endif
+ default:
+ _set_errno(EINVAL);
+ }
+ return NULL;
+ }
+
+ /* allocate result list */
+ for (count = 0, e = res; e != NULL; e = e->ai_next)
+ count += 1;
+
+ AARRAY_NEW(list, count+1);
+ AARRAY_NEW(addr, count);
+
+ for (nn = 0, e = res; e != NULL; e = e->ai_next) {
+
+ ret = sock_address_from_bsd(addr, e->ai_addr, e->ai_addrlen);
+ if (ret < 0)
+ continue;
+
+ list[nn++] = addr++;
+ }
+ list[nn] = NULL;
+ freeaddrinfo(res);
+ return list;
+}
+
+SockAddress**
+sock_address_list_create2(const char* host_and_port, unsigned flags )
+{
+ char host_name[512];
+ const char* actual_host_name = "localhost";
+ // Parse host and port name.
+ const char* port_name = strchr(host_and_port, ':');
+ if (port_name != NULL) {
+ int to_copy = MIN((int)sizeof(host_name)-1, port_name - host_and_port);
+ if (to_copy != 0) {
+ memcpy(host_name, host_and_port, to_copy);
+ host_name[to_copy] = '\0';
+ actual_host_name = host_name;
+ port_name++;
+ } else {
+ return NULL;
+ }
+ } else {
+ port_name = host_and_port;
+ }
+ // Make sure that port_name is not empty.
+ if (port_name[0] == '\0') {
+ return NULL;
+ }
+ return sock_address_list_create(actual_host_name, port_name, flags);
+}
+
+void
+sock_address_list_free( SockAddress** list )
+{
+ int nn;
+ SockAddress* addr;
+
+ if (list == NULL)
+ return;
+
+ addr = list[0];
+ for (nn = 0; list[nn] != NULL; nn++) {
+ sock_address_done(list[nn]);
+ list[nn] = NULL;
+ }
+ AFREE(addr);
+ AFREE(list);
+}
+
+int
+sock_address_get_numeric_info( SockAddress* a,
+ char* host,
+ size_t hostlen,
+ char* serv,
+ size_t servlen )
+{
+ struct sockaddr* saddr;
+ socklen_t slen;
+ int ret;
+
+ switch (a->family) {
+ case SOCKET_INET:
+ saddr = (struct sockaddr*) &a->u.inet.address;
+ slen = sizeof(a->u.inet.address);
+ break;
+
+#if HAVE_IN6_SOCKET
+ case SOCKET_IN6:
+ saddr = (struct sockaddr*) &a->u.in6.address;
+ slen = sizeof(a->u.in6.address);
+ break;
+#endif
+ default:
+ return _set_errno(EINVAL);
+ }
+
+ ret = getnameinfo( saddr, slen, host, hostlen, serv, servlen,
+ NI_NUMERICHOST | NI_NUMERICSERV );
+
+ switch (ret) {
+ case 0:
+ break;
+ case EAI_AGAIN:
+ ret = EAGAIN;
+ break;
+ default:
+ ret = EINVAL;
+ }
+ return ret;
+}
+
+int
+socket_create( SocketFamily family, SocketType type )
+{
+ int ret;
+ int sfamily = socket_family_to_bsd(family);
+ int stype = socket_type_to_bsd(type);
+
+ if (sfamily < 0 || stype < 0) {
+ return _set_errno(EINVAL);
+ }
+
+ QSOCKET_CALL(ret, socket(sfamily, stype, 0));
+ if (ret < 0)
+ return _fix_errno();
+
+ return ret;
+}
+
+
+int
+socket_create_inet( SocketType type )
+{
+ return socket_create( SOCKET_INET, type );
+}
+
+#if HAVE_IN6_SOCKETS
+int
+socket_create_in6 ( SocketType type )
+{
+ return socket_create( SOCKET_IN6, type );
+}
+#endif
+
+#if HAVE_UNIX_SOCKETS
+int
+socket_create_unix( SocketType type )
+{
+ return socket_create( SOCKET_UNIX, type );
+}
+#endif
+
+int socket_can_read(int fd)
+{
+#ifdef _WIN32
+ unsigned long opt;
+
+ if (ioctlsocket(fd, FIONREAD, &opt) < 0)
+ return 0;
+
+ return opt;
+#else
+ int opt;
+
+ if (ioctl(fd, FIONREAD, &opt) < 0)
+ return 0;
+
+ return opt;
+#endif
+}
+
+#define SOCKET_CALL(cmd) \
+ int ret; \
+ QSOCKET_CALL(ret, (cmd)); \
+ if (ret < 0) \
+ return _fix_errno(); \
+ return ret; \
+
+int
+socket_send(int fd, const void* buf, int buflen)
+{
+ SOCKET_CALL(send(fd, buf, buflen, 0))
+}
+
+int
+socket_send_oob( int fd, const void* buf, int buflen )
+{
+ SOCKET_CALL(send(fd, buf, buflen, MSG_OOB));
+}
+
+int
+socket_sendto(int fd, const void* buf, int buflen, const SockAddress* to)
+{
+ sockaddr_storage sa;
+ socklen_t salen;
+
+ if (sock_address_to_bsd(to, &sa, &salen) < 0)
+ return -1;
+
+ SOCKET_CALL(sendto(fd, buf, buflen, 0, sa.sa, salen));
+}
+
+int
+socket_recv(int fd, void* buf, int len)
+{
+ SOCKET_CALL(recv(fd, buf, len, 0));
+}
+
+int
+socket_recvfrom(int fd, void* buf, int len, SockAddress* from)
+{
+ sockaddr_storage sa;
+ socklen_t salen = sizeof(sa);
+ int ret;
+
+ QSOCKET_CALL(ret,recvfrom(fd,buf,len,0,sa.sa,&salen));
+ if (ret < 0)
+ return _fix_errno();
+
+ if (sock_address_from_bsd(from, &sa, salen) < 0)
+ return -1;
+
+ return ret;
+}
+
+int
+socket_connect( int fd, const SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen;
+
+ if (sock_address_to_bsd(address, &addr, &addrlen) < 0)
+ return -1;
+
+ SOCKET_CALL(connect(fd,addr.sa,addrlen));
+}
+
+int
+socket_bind( int fd, const SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen;
+
+ if (sock_address_to_bsd(address, &addr, &addrlen) < 0)
+ return -1;
+
+ SOCKET_CALL(bind(fd, addr.sa, addrlen));
+}
+
+int
+socket_get_address( int fd, SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ int ret;
+
+ QSOCKET_CALL(ret, getsockname(fd, addr.sa, &addrlen));
+ if (ret < 0)
+ return _fix_errno();
+
+ return sock_address_from_bsd(address, &addr, addrlen);
+}
+
+int
+socket_get_peer_address( int fd, SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ int ret;
+
+ QSOCKET_CALL(ret, getpeername(fd, addr.sa, &addrlen));
+ if (ret < 0)
+ return _fix_errno();
+
+ return sock_address_from_bsd(address, &addr, addrlen);
+}
+
+int
+socket_listen( int fd, int backlog )
+{
+ SOCKET_CALL(listen(fd, backlog));
+}
+
+int
+socket_accept( int fd, SockAddress* address )
+{
+ sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ int ret;
+
+ QSOCKET_CALL(ret, accept(fd, addr.sa, &addrlen));
+ if (ret < 0)
+ return _fix_errno();
+
+ if (address) {
+ if (sock_address_from_bsd(address, &addr, addrlen) < 0) {
+ socket_close(ret);
+ return -1;
+ }
+ }
+ return ret;
+}
+
+static int
+socket_getoption(int fd, int domain, int option, int defaut)
+{
+ int ret;
+ while (1) {
+#ifdef _WIN32
+ DWORD opt = (DWORD)-1;
+#else
+ int opt = -1;
+#endif
+ socklen_t optlen = sizeof(opt);
+ ret = getsockopt(fd, domain, option, (char*)&opt, &optlen);
+ if (ret == 0)
+ return (int)opt;
+ if (errno != EINTR)
+ return defaut;
+ }
+#undef OPT_CAST
+}
+
+
+SocketType socket_get_type(int fd)
+{
+ int so_type = socket_getoption(fd, SOL_SOCKET, SO_TYPE, -1);
+ return socket_type_from_bsd(so_type);
+}
+
+int socket_set_nonblock(int fd)
+{
+#ifdef _WIN32
+ unsigned long opt = 1;
+ return ioctlsocket(fd, FIONBIO, &opt);
+#else
+ int flags = fcntl(fd, F_GETFL);
+ return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+#endif
+}
+
+int socket_set_blocking(int fd)
+{
+#ifdef _WIN32
+ unsigned long opt = 0;
+ return ioctlsocket(fd, FIONBIO, &opt);
+#else
+ int flags = fcntl(fd, F_GETFL);
+ return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+#endif
+}
+
+static int
+socket_setoption(int fd, int domain, int option, int _flag)
+{
+#ifdef _WIN32
+ DWORD flag = (DWORD) _flag;
+#else
+ int flag = _flag;
+#endif
+ return setsockopt( fd, domain, option, (const char*)&flag, sizeof(flag) );
+}
+
+int socket_set_xreuseaddr(int fd)
+{
+#ifdef _WIN32
+ /* on Windows, SO_REUSEADDR is used to indicate that several programs can
+ * bind to the same port. this is completely different from the Unix
+ * semantics. instead of SO_EXCLUSIVEADDR to ensure that explicitely prevent
+ * this.
+ */
+ return socket_setoption(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 1);
+#else
+ return socket_setoption(fd, SOL_SOCKET, SO_REUSEADDR, 1);
+#endif
+}
+
+
+int socket_set_oobinline(int fd)
+{
+ return socket_setoption(fd, SOL_SOCKET, SO_OOBINLINE, 1);
+}
+
+
+int socket_set_nodelay(int fd)
+{
+ return socket_setoption(fd, IPPROTO_TCP, TCP_NODELAY, 1);
+}
+
+int socket_set_ipv6only(int fd)
+{
+/* IPV6_ONLY is only supported since Vista on Windows,
+ * and the Mingw headers lack its definition anyway.
+ */
+#if defined(_WIN32) && !defined(IPV6_V6ONLY)
+ return 0;
+#else
+ return socket_setoption(fd, IPPROTO_IPV6, IPV6_V6ONLY, 1);
+#endif
+}
+
+
+int socket_get_error(int fd)
+{
+ return socket_getoption(fd, SOL_SOCKET, SO_ERROR, -1);
+}
+
+#ifdef _WIN32
+#include <stdlib.h>
+
+static void socket_cleanup(void)
+{
+ WSACleanup();
+}
+
+int socket_init(void)
+{
+ WSADATA Data;
+ int ret, err;
+
+ ret = WSAStartup(MAKEWORD(2,2), &Data);
+ if (ret != 0) {
+ err = WSAGetLastError();
+ return -1;
+ }
+ atexit(socket_cleanup);
+ return 0;
+}
+
+#else /* !_WIN32 */
+
+int socket_init(void)
+{
+ return 0; /* nothing to do on Unix */
+}
+
+#endif /* !_WIN32 */
+
+#ifdef _WIN32
+
+void
+socket_close( int fd )
+{
+ int old_errno = errno;
+
+ shutdown( fd, SD_BOTH );
+ /* we want to drain the socket before closing it */
+ //qemu_set_fd_handler( fd, socket_close_handler, NULL, (void*)fd );
+ closesocket(fd);
+
+ errno = old_errno;
+}
+
+#else /* !_WIN32 */
+
+#include <unistd.h>
+
+void
+socket_close( int fd )
+{
+ int old_errno = errno;
+
+ shutdown( fd, SHUT_RDWR );
+ close( fd );
+
+ errno = old_errno;
+}
+
+#endif /* !_WIN32 */
+
+
+static int
+socket_bind_server( int s, const SockAddress* to, SocketType type )
+{
+ socket_set_xreuseaddr(s);
+
+ if (socket_bind(s, to) < 0) {
+ D("could not bind server socket address %s: %s",
+ sock_address_to_string(to), errno_str);
+ goto FAIL;
+ }
+
+ if (type == SOCKET_STREAM) {
+ if (socket_listen(s, 4) < 0) {
+ D("could not listen server socket %s: %s",
+ sock_address_to_string(to), errno_str);
+ goto FAIL;
+ }
+ }
+ return s;
+
+FAIL:
+ socket_close(s);
+ return -1;
+}
+
+
+static int
+socket_connect_client( int s, const SockAddress* to )
+{
+ if (socket_connect(s, to) < 0) {
+ D( "could not connect client socket to %s: %s\n",
+ sock_address_to_string(to), errno_str );
+ socket_close(s);
+ return -1;
+ }
+
+ socket_set_nonblock( s );
+ return s;
+}
+
+
+static int
+socket_in_server( int address, int port, SocketType type )
+{
+ SockAddress addr;
+ int s;
+
+ sock_address_init_inet( &addr, address, port );
+ s = socket_create_inet( type );
+ if (s < 0)
+ return -1;
+
+ return socket_bind_server( s, &addr, type );
+}
+
+
+static int
+socket_in_client( SockAddress* to, SocketType type )
+{
+ int s;
+
+ s = socket_create_inet( type );
+ if (s < 0) return -1;
+
+ return socket_connect_client( s, to );
+}
+
+
+int
+socket_loopback_server( int port, SocketType type )
+{
+ return socket_in_server( SOCK_ADDRESS_INET_LOOPBACK, port, type );
+}
+
+int
+socket_loopback_client( int port, SocketType type )
+{
+ SockAddress addr;
+
+ sock_address_init_inet( &addr, SOCK_ADDRESS_INET_LOOPBACK, port );
+ return socket_in_client( &addr, type );
+}
+
+
+int
+socket_network_client( const char* host, int port, SocketType type )
+{
+ SockAddress addr;
+
+ if (sock_address_init_resolve( &addr, host, port, 0) < 0)
+ return -1;
+
+ return socket_in_client( &addr, type );
+}
+
+
+int
+socket_anyaddr_server( int port, SocketType type )
+{
+ return socket_in_server( SOCK_ADDRESS_INET_ANY, port, type );
+}
+
+int
+socket_accept_any( int server_fd )
+{
+ int fd;
+
+ QSOCKET_CALL(fd, accept( server_fd, NULL, 0 ));
+ if (fd < 0) {
+ D( "could not accept client connection from fd %d: %s",
+ server_fd, errno_str );
+ return -1;
+ }
+
+ /* set to non-blocking */
+ socket_set_nonblock( fd );
+ return fd;
+}
+
+
+#if HAVE_UNIX_SOCKETS
+
+int
+socket_unix_server( const char* name, SocketType type )
+{
+ SockAddress addr;
+ int s, ret;
+
+ s = socket_create_unix( type );
+ if (s < 0)
+ return -1;
+
+ sock_address_init_unix( &addr, name );
+
+ do {
+ ret = unlink( name );
+ } while (ret < 0 && errno == EINTR);
+
+ ret = socket_bind_server( s, &addr, type );
+
+ sock_address_done( &addr );
+ return ret;
+}
+
+int
+socket_unix_client( const char* name, SocketType type )
+{
+ SockAddress addr;
+ int s, ret;
+
+ s = socket_create_unix(type);
+ if (s < 0)
+ return -1;
+
+ sock_address_init_unix( &addr, name );
+
+ ret = socket_connect_client( s, &addr );
+
+ sock_address_done( &addr );
+ return ret;
+}
+
+#endif /* HAVE_UNIX_SOCKETS */
+
+
+
+int
+socket_pair(int *fd1, int *fd2)
+{
+#ifndef _WIN32
+ int fds[2];
+ int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+
+ if (!ret) {
+ socket_set_nonblock(fds[0]);
+ socket_set_nonblock(fds[1]);
+ *fd1 = fds[0];
+ *fd2 = fds[1];
+ }
+ return ret;
+#else /* _WIN32 */
+ /* on Windows, select() only works with network sockets, which
+ * means we absolutely cannot use Win32 PIPEs to implement
+ * socket pairs with the current event loop implementation.
+ * We're going to do like Cygwin: create a random pair
+ * of localhost TCP sockets and connect them together
+ */
+ int s0, s1, s2, port;
+ struct sockaddr_in sockin;
+ socklen_t len;
+
+ /* first, create the 'server' socket.
+ * a port number of 0 means 'any port between 1024 and 5000.
+ * see Winsock bind() documentation for details */
+ s0 = socket_loopback_server( 0, SOCK_STREAM );
+ if (s0 < 0)
+ return -1;
+
+ /* now connect a client socket to it, we first need to
+ * extract the server socket's port number */
+ len = sizeof sockin;
+ if (getsockname(s0, (struct sockaddr*) &sockin, &len) < 0) {
+ closesocket (s0);
+ return -1;
+ }
+
+ port = ntohs(sockin.sin_port);
+ s2 = socket_loopback_client( port, SOCK_STREAM );
+ if (s2 < 0) {
+ closesocket(s0);
+ return -1;
+ }
+
+ /* we need to accept the connection on the server socket
+ * this will create the second socket for the pair
+ */
+ len = sizeof sockin;
+ s1 = accept(s0, (struct sockaddr*) &sockin, &len);
+ if (s1 == INVALID_SOCKET) {
+ closesocket (s0);
+ closesocket (s2);
+ return -1;
+ }
+ socket_set_nonblock(s1);
+
+ /* close server socket */
+ closesocket(s0);
+ *fd1 = s1;
+ *fd2 = s2;
+ return 0;
+#endif /* _WIN32 */
+}
+
+
+
+int
+socket_mcast_inet_add_membership( int s, uint32_t ip )
+{
+ struct ip_mreq imr;
+
+ imr.imr_multiaddr.s_addr = htonl(ip);
+ imr.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ if ( setsockopt( s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (const char *)&imr,
+ sizeof(struct ip_mreq)) < 0 )
+ {
+ return _fix_errno();
+ }
+ return 0;
+}
+
+int
+socket_mcast_inet_drop_membership( int s, uint32_t ip )
+{
+ struct ip_mreq imr;
+
+ imr.imr_multiaddr.s_addr = htonl(ip);
+ imr.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ if ( setsockopt( s, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ (const char *)&imr,
+ sizeof(struct ip_mreq)) < 0 )
+ {
+ return _fix_errno();
+ }
+ return 0;
+}
+
+int
+socket_mcast_inet_set_loop( int s, int enabled )
+{
+ return socket_setoption( s, IPPROTO_IP, IP_MULTICAST_LOOP, !!enabled );
+}
+
+int
+socket_mcast_inet_set_ttl( int s, int ttl )
+{
+ return socket_setoption( s, IPPROTO_IP, IP_MULTICAST_TTL, ttl );
+}
+
+
+char*
+host_name( void )
+{
+ static char buf[256]; /* 255 is the max host name length supported by DNS */
+ int ret;
+
+ QSOCKET_CALL(ret, gethostname(buf, sizeof(buf)));
+
+ if (ret < 0)
+ return "localhost";
+ else
+ return buf;
+}
diff --git a/emulator/opengl/tests/event_injector/sockets.h b/emulator/opengl/tests/event_injector/sockets.h
new file mode 100644
index 000000000..ea48c5f16
--- /dev/null
+++ b/emulator/opengl/tests/event_injector/sockets.h
@@ -0,0 +1,432 @@
+/*
+* 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.
+*/
+/* headers to use the BSD sockets */
+#ifndef ANDROID_SOCKET_H
+#define ANDROID_SOCKET_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* we're going to hide the implementation details of sockets behind
+ * a simple wrapper interface declared here.
+ *
+ * all socket operations set the global 'errno' variable on error.
+ * this is unlike Winsock which instead modifies another internal
+ * variable accessed through WSAGetLastError() and WSASetLastError()
+ */
+
+/* the wrapper will convert any Winsock error message into an errno
+ * code for you. There are however a few standard Unix error codes
+ * that are not defined by the MS C library headers, so we add them
+ * here. We use the official Winsock error codes, which are documented
+ * even though we don't want to include the Winsock headers
+ */
+#ifdef _WIN32
+# ifndef EINTR
+# define EINTR 10004
+# endif
+# ifndef EAGAIN
+# define EAGAIN 10035
+# endif
+# ifndef EWOULDBLOCK
+# define EWOULDBLOCK EAGAIN
+# endif
+# ifndef EINPROGRESS
+# define EINPROGRESS 10036
+# endif
+# ifndef EALREADY
+# define EALREADY 10037
+# endif
+# ifndef EDESTADDRREQ
+# define EDESTADDRREQ 10039
+# endif
+# ifndef EMSGSIZE
+# define EMSGSIZE 10040
+# endif
+# ifndef EPROTOTYPE
+# define EPROTOTYPE 10041
+# endif
+# ifndef ENOPROTOOPT
+# define ENOPROTOOPT 10042
+# endif
+# ifndef EAFNOSUPPORT
+# define EAFNOSUPPORT 10047
+# endif
+# ifndef EADDRINUSE
+# define EADDRINUSE 10048
+# endif
+# ifndef EADDRNOTAVAIL
+# define EADDRNOTAVAIL 10049
+# endif
+# ifndef ENETDOWN
+# define ENETDOWN 10050
+# endif
+# ifndef ENETUNREACH
+# define ENETUNREACH 10051
+# endif
+# ifndef ENETRESET
+# define ENETRESET 10052
+# endif
+# ifndef ECONNABORTED
+# define ECONNABORTED 10053
+# endif
+# ifndef ECONNRESET
+# define ECONNRESET 10054
+# endif
+# ifndef ENOBUFS
+# define ENOBUFS 10055
+# endif
+# ifndef EISCONN
+# define EISCONN 10056
+# endif
+# ifndef ENOTCONN
+# define ENOTCONN 10057
+# endif
+# ifndef ESHUTDOWN
+# define ESHUTDOWN 10058
+# endif
+# ifndef ETOOMANYREFS
+# define ETOOMANYREFS 10059
+# endif
+# ifndef ETIMEDOUT
+# define ETIMEDOUT 10060
+# endif
+# ifndef ECONNREFUSED
+# define ECONNREFUSED 10061
+# endif
+# ifndef ELOOP
+# define ELOOP 10062
+# endif
+# ifndef EHOSTDOWN
+# define EHOSTDOWN 10064
+# endif
+# ifndef EHOSTUNREACH
+# define EHOSTUNREACH 10065
+# endif
+#endif /* _WIN32 */
+
+/* Define 'errno_str' as a handy macro to return the string
+ * corresponding to a given errno code. On Unix, this is
+ * equivalent to strerror(errno), but on Windows, this will
+ * take care of Winsock-originated errors as well.
+ */
+#ifdef _WIN32
+ extern const char* _errno_str(void);
+# define errno_str _errno_str()
+#else
+# define errno_str strerror(errno)
+#endif
+
+/* always enable IPv6 sockets for now.
+ * the QEMU internal router is not capable of
+ * supporting them, but we plan to replace it
+ * with something better in the future.
+ */
+#define HAVE_IN6_SOCKETS 1
+
+/* Unix sockets are not available on Win32 */
+#ifndef _WIN32
+# define HAVE_UNIX_SOCKETS 1
+#endif
+
+/* initialize the socket sub-system. this must be called before
+ * using any of the declarations below.
+ */
+int socket_init( void );
+
+/* return the name of the current host */
+char* host_name( void );
+
+/* supported socket types */
+typedef enum {
+ SOCKET_DGRAM = 0,
+ SOCKET_STREAM
+} SocketType;
+
+/* supported socket families */
+typedef enum {
+ SOCKET_UNSPEC,
+ SOCKET_INET,
+ SOCKET_IN6,
+ SOCKET_UNIX
+} SocketFamily;
+
+/* Generic socket address structure. Note that for Unix
+ * sockets, the path is stored in a heap-allocated block,
+ * unless the 'owner' field is cleared. If this is the case,
+ */
+typedef struct {
+ SocketFamily family;
+ union {
+ struct {
+ uint16_t port;
+ uint32_t address;
+ } inet;
+ struct {
+ uint16_t port;
+ uint8_t address[16];
+ } in6;
+ struct {
+ int owner;
+ const char* path;
+ } _unix;
+ } u;
+} SockAddress;
+
+#define SOCK_ADDRESS_INET_ANY 0x00000000
+#define SOCK_ADDRESS_INET_LOOPBACK 0x7f000001
+
+/* initialize a new IPv4 socket address, the IP address and port are
+ * in host endianess.
+ */
+void sock_address_init_inet( SockAddress* a, uint32_t ip, uint16_t port );
+
+/* Initialize an IPv6 socket address, the address is in network order
+ * and the port in host endianess.
+ */
+#if HAVE_IN6_SOCKETS
+void sock_address_init_in6 ( SockAddress* a, const uint8_t* ip6[16], uint16_t port );
+#endif
+
+/* Intialize a Unix socket address, this will copy the 'path' string into the
+ * heap. You need to call sock_address_done() to release the copy
+ */
+#if HAVE_UNIX_SOCKETS
+void sock_address_init_unix( SockAddress* a, const char* path );
+#endif
+
+/* Finalize a socket address, only needed for now for Unix addresses */
+void sock_address_done( SockAddress* a );
+
+int sock_address_equal( const SockAddress* a, const SockAddress* b );
+
+/* return a static string describing the address */
+const char* sock_address_to_string( const SockAddress* a );
+
+static __inline__
+SocketFamily sock_address_get_family( const SockAddress* a )
+{
+ return a->family;
+}
+
+/* return the port number of a given socket address, or -1 if it's a Unix one */
+int sock_address_get_port( const SockAddress* a );
+
+/* set the port number of a given socket address, don't do anything for Unix ones */
+void sock_address_set_port( SockAddress* a, uint16_t port );
+
+/* return the path of a given Unix socket, returns NULL for non-Unix ones */
+const char* sock_address_get_path( const SockAddress* a );
+
+/* return the inet address, or -1 if it's not SOCKET_INET */
+int sock_address_get_ip( const SockAddress* a );
+
+/* bufprint a socket address into a human-readable string */
+char* bufprint_sock_address( char* p, char* end, const SockAddress* a );
+
+/* resolve a hostname or decimal IPv4/IPv6 address into a socket address.
+ * returns 0 on success, or -1 on failure. Note that the values or errno
+ * set by this function are the following:
+ *
+ * EINVAL : invalid argument
+ * EHOSTDOWN : could not reach DNS server
+ * ENOENT : no host with this name, or host doesn't have any IP address
+ * ENOMEM : not enough memory to perform request
+ */
+int sock_address_init_resolve( SockAddress* a,
+ const char* hostname,
+ uint16_t port,
+ int preferIn6 );
+
+int sock_address_get_numeric_info( SockAddress* a,
+ char* host,
+ size_t hostlen,
+ char* serv,
+ size_t servlen );
+
+/* Support for listing all socket addresses of a given host */
+enum {
+ SOCKET_LIST_PASSIVE = (1 << 0),
+ SOCKET_LIST_FORCE_INET = (1 << 1),
+ SOCKET_LIST_FORCE_IN6 = (1 << 2),
+ SOCKET_LIST_DGRAM = (1 << 3),
+};
+
+/* resolve a host and service/port name into a list of SockAddress objects.
+ * returns a NULL-terminated array of SockAddress pointers on success,
+ * or NULL in case of failure, with the value of errno set to one of the
+ * following:
+ *
+ * EINVAL : invalid argument
+ * EHOSTDOWN : could not reach DNS server
+ * ENOENT : no host with this name, or host doesn't have IP address
+ * ENOMEM : not enough memory to perform request
+ *
+ * other system-level errors can also be set depending on the host sockets
+ * implementation.
+ *
+ * This function loops on EINTR so the caller shouldn't have to check for it.
+ */
+SockAddress** sock_address_list_create( const char* hostname,
+ const char* port,
+ unsigned flags );
+
+/* resolve a string containing host and port name into a list of SockAddress
+ * objects. Parameter host_and_port should be in format [host:]port, where
+ * 'host' addresses the machine and must be resolvable into an IP address, and
+ * 'port' is a decimal numeric value for the port. 'host' is optional, and if
+ * ommited, localhost will be used.
+ * returns a NULL-terminated array of SockAddress pointers on success,
+ * or NULL in case of failure, with the value of errno set to one of the
+ * following:
+ *
+ * EINVAL : invalid argument
+ * EHOSTDOWN : could not reach DNS server
+ * ENOENT : no host with this name, or host doesn't have IP address
+ * ENOMEM : not enough memory to perform request
+ *
+ * other system-level errors can also be set depending on the host sockets
+ * implementation.
+ *
+ * This function loops on EINTR so the caller shouldn't have to check for it.
+ */
+SockAddress** sock_address_list_create2(const char* host_and_port,
+ unsigned flags );
+
+void sock_address_list_free( SockAddress** list );
+
+/* create a new socket, return the socket number of -1 on failure */
+int socket_create( SocketFamily family, SocketType type );
+
+/* create a new socket intended for IPv4 communication. returns the socket number,
+ * or -1 on failure.
+ */
+int socket_create_inet( SocketType type );
+
+/* create a new socket intended for IPv6 communication. returns the socket number,
+ * or -1 on failure.
+ */
+#if HAVE_IN6_SOCKETS
+int socket_create_in6 ( SocketType type );
+#endif
+
+/* create a unix/local domain socket. returns the socket number,
+ * or -1 on failure.
+ */
+#if HAVE_UNIX_SOCKETS
+int socket_create_unix( SocketType type );
+#endif
+
+/* return the type of a given socket */
+SocketType socket_get_type(int fd);
+
+/* set SO_REUSEADDR on Unix, SO_EXCLUSIVEADDR on Windows */
+int socket_set_xreuseaddr(int fd);
+
+/* set socket in non-blocking mode */
+int socket_set_nonblock(int fd);
+
+/* set socket in blocking mode */
+int socket_set_blocking(int fd);
+
+/* disable the TCP Nagle algorithm for lower latency */
+int socket_set_nodelay(int fd);
+
+/* send OOB data inline for this socket */
+int socket_set_oobinline(int fd);
+
+/* force listening to IPv6 interfaces only */
+int socket_set_ipv6only(int fd);
+
+/* retrieve last socket error code */
+int socket_get_error(int fd);
+
+/* close an opened socket. Note that this is unlike the Unix 'close' because:
+ * - it will properly shutdown the socket in the background
+ * - it does not modify errno
+ */
+void socket_close( int fd );
+
+/* the following functions are equivalent to the BSD sockets ones
+ */
+int socket_recv ( int fd, void* buf, int buflen );
+int socket_recvfrom( int fd, void* buf, int buflen, SockAddress* from );
+
+int socket_send ( int fd, const void* buf, int buflen );
+int socket_send_oob( int fd, const void* buf, int buflen );
+int socket_sendto( int fd, const void* buf, int buflen, const SockAddress* to );
+
+int socket_connect( int fd, const SockAddress* address );
+int socket_bind( int fd, const SockAddress* address );
+int socket_get_address( int fd, SockAddress* address );
+int socket_get_peer_address( int fd, SockAddress* address );
+int socket_listen( int fd, int backlog );
+int socket_accept( int fd, SockAddress* address );
+
+/* returns the number of bytes that can be read from a socket */
+int socket_can_read( int fd );
+
+/* this call creates a pair of non-blocking sockets connected
+ * to each other. this is equivalent to calling the Unix function:
+ * socketpair(AF_LOCAL,SOCK_STREAM,0,&fds)
+ *
+ * on Windows, this will use a pair of TCP loopback sockets instead
+ * returns 0 on success, -1 on error.
+ */
+int socket_pair(int *fd1, int *fd2);
+
+/* create a server socket listening on the host's loopback interface */
+int socket_loopback_server( int port, SocketType type );
+
+/* connect to a port on the host's loopback interface */
+int socket_loopback_client( int port, SocketType type );
+
+/* create a server socket listening to a Unix domain path */
+#if HAVE_UNIX_SOCKETS
+int socket_unix_server( const char* name, SocketType type );
+#endif
+
+/* create a Unix sockets and connects it to a Unix server */
+#if HAVE_UNIX_SOCKETS
+int socket_unix_client( const char* name, SocketType type );
+#endif
+
+/* create an IPv4 client socket and connect it to a given host */
+int socket_network_client( const char* host, int port, SocketType type );
+
+/* create an IPv4 socket and binds it to a given port of the host's interface */
+int socket_anyaddr_server( int port, SocketType type );
+
+/* accept a connection from the host's any interface, return the new socket
+ * descriptor or -1 */
+int socket_accept_any( int server_fd );
+
+
+int socket_mcast_inet_add_membership( int s, uint32_t ip );
+int socket_mcast_inet_drop_membership( int s, uint32_t ip );
+int socket_mcast_inet_set_loop( int s, int enabled );
+int socket_mcast_inet_set_ttl( int s, int ttl );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_SOCKET_H */