Merge "emulator:opengl: input event redirection"
This commit is contained in:
@@ -85,6 +85,7 @@ include $(EMUGL_PATH)/host/renderer/Android.mk
|
||||
|
||||
# Host unit-test for the renderer. this one uses its own small
|
||||
# EGL host wrapper.
|
||||
include $(EMUGL_PATH)/tests/event_injector/Android.mk
|
||||
include $(EMUGL_PATH)/tests/EGL_host_wrapper/Android.mk
|
||||
include $(EMUGL_PATH)/tests/emulator_test_renderer/Android.mk
|
||||
include $(EMUGL_PATH)/tests/ut_renderer/Android.mk
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
LOCAL_PATH:=$(call my-dir)
|
||||
|
||||
$(call emugl-begin-host-executable,emulator_test_renderer)
|
||||
$(call emugl-import,libOpenglRender)
|
||||
$(call emugl-import,libOpenglRender event_injector)
|
||||
|
||||
LOCAL_SRC_FILES := main.cpp
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "libOpenglRender/render_api.h"
|
||||
#include <EventInjector.h>
|
||||
|
||||
static int convert_keysym(int sym); // forward
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
@@ -31,8 +34,11 @@ int main(int argc, char *argv[])
|
||||
int winWidth = 320;
|
||||
int winHeight = 480;
|
||||
int width, height;
|
||||
int mouseDown = 0;
|
||||
const char* env = getenv("ANDROID_WINDOW_SIZE");
|
||||
FBNativeWindowType windowId = NULL;
|
||||
EventInjector* injector;
|
||||
int consolePort = 5554;
|
||||
|
||||
if (env && sscanf(env, "%dx%d", &width, &height) == 2) {
|
||||
winWidth = width;
|
||||
@@ -81,14 +87,53 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
printf("renderer process started\n");
|
||||
|
||||
injector = new EventInjector(consolePort);
|
||||
|
||||
// Just wait until the window is closed
|
||||
SDL_Event ev;
|
||||
while( SDL_WaitEvent(&ev) ) {
|
||||
if (ev.type == SDL_QUIT) {
|
||||
break;
|
||||
|
||||
for (;;) {
|
||||
injector->wait(1000/15);
|
||||
injector->poll();
|
||||
|
||||
while (SDL_PollEvent(&ev)) {
|
||||
switch (ev.type) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (!mouseDown) {
|
||||
injector->sendMouseDown(ev.button.x, ev.button.y);
|
||||
mouseDown = 1;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (mouseDown) {
|
||||
injector->sendMouseUp(ev.button.x,ev.button.y);
|
||||
mouseDown = 0;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (mouseDown)
|
||||
injector->sendMouseMotion(ev.button.x,ev.button.y);
|
||||
break;
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
#ifdef __APPLE__
|
||||
/* special code to deal with Command-Q properly */
|
||||
if (ev.key.keysym.sym == SDLK_q &&
|
||||
ev.key.keysym.mod & KMOD_META) {
|
||||
goto EXIT;
|
||||
}
|
||||
#endif
|
||||
injector->sendKeyDown(convert_keysym(ev.key.keysym.sym));
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
injector->sendKeyUp(convert_keysym(ev.key.keysym.sym));
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXIT:
|
||||
//
|
||||
// stop the renderer
|
||||
//
|
||||
@@ -97,3 +142,26 @@ int main(int argc, char *argv[])
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int convert_keysym(int sym)
|
||||
{
|
||||
#define EE(x,y) SDLK_##x, EventInjector::KEY_##y,
|
||||
static const int keymap[] = {
|
||||
EE(LEFT,LEFT)
|
||||
EE(RIGHT,RIGHT)
|
||||
EE(DOWN,DOWN)
|
||||
EE(UP,UP)
|
||||
EE(RETURN,ENTER)
|
||||
EE(F1,SOFT1)
|
||||
EE(ESCAPE,BACK)
|
||||
EE(HOME,HOME)
|
||||
-1
|
||||
};
|
||||
int nn;
|
||||
for (nn = 0; keymap[nn] >= 0; nn += 2) {
|
||||
if (keymap[nn] == sym)
|
||||
return keymap[nn+1];
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
13
tools/emulator/opengl/tests/event_injector/Android.mk
Normal file
13
tools/emulator/opengl/tests/event_injector/Android.mk
Normal file
@@ -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)
|
||||
76
tools/emulator/opengl/tests/event_injector/EventInjector.cpp
Normal file
76
tools/emulator/opengl/tests/event_injector/EventInjector.cpp
Normal file
@@ -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);
|
||||
}
|
||||
59
tools/emulator/opengl/tests/event_injector/EventInjector.h
Normal file
59
tools/emulator/opengl/tests/event_injector/EventInjector.h
Normal file
@@ -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 */
|
||||
345
tools/emulator/opengl/tests/event_injector/emulator-console.c
Normal file
345
tools/emulator/opengl/tests/event_injector/emulator-console.c
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
257
tools/emulator/opengl/tests/event_injector/iolooper-select.c
Normal file
257
tools/emulator/opengl/tests/event_injector/iolooper-select.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct timeval time_now;
|
||||
return gettimeofday(&time_now, NULL) ? -1 : (int64_t)time_now.tv_sec * 1000LL +
|
||||
time_now.tv_usec / 1000;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
91
tools/emulator/opengl/tests/event_injector/iolooper.h
Normal file
91
tools/emulator/opengl/tests/event_injector/iolooper.h
Normal file
@@ -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 */
|
||||
1573
tools/emulator/opengl/tests/event_injector/sockets.c
Normal file
1573
tools/emulator/opengl/tests/event_injector/sockets.c
Normal file
File diff suppressed because it is too large
Load Diff
432
tools/emulator/opengl/tests/event_injector/sockets.h
Normal file
432
tools/emulator/opengl/tests/event_injector/sockets.h
Normal file
@@ -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 */
|
||||
Reference in New Issue
Block a user