diff --git a/tools/emulator/system/libqemu/Android.mk b/tools/emulator/system/libqemu/Android.mk new file mode 100644 index 000000000..a0f0e5473 --- /dev/null +++ b/tools/emulator/system/libqemu/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH := $(call my-dir) + +# The main libqemud library +include $(CLEAR_VARS) +LOCAL_MODULE := libqemu +LOCAL_SRC_FILES := libqemu.c +LOCAL_MODULE_TAGS := debug +include $(BUILD_STATIC_LIBRARY) + +# Define BUILD_LIBQEMUD_TESTS to 'true' in your environment +# to generate the following test programs. You must be on Linux! +# +ifeq (true-linux,$(strip $(BUILD_LIBQEMU_TESTS)-$(HOST_OS))) +include $(LOCAL_PATH)/tests.mk +endif # BUILD_LIBQEMUD_TESTS == true diff --git a/tools/emulator/system/libqemu/libqemu.c b/tools/emulator/system/libqemu/libqemu.c new file mode 100644 index 000000000..be2ca76ad --- /dev/null +++ b/tools/emulator/system/libqemu/libqemu.c @@ -0,0 +1,81 @@ +/* + * 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. + */ + +/* Set to 1 to enable debugging */ +#define DEBUG 0 + +#if DEBUG >= 1 +# define D(...) fprintf(stderr,"libqemud:" __VA_ARGS__), fprintf(stderr, "\n") +#endif + +#include +#include +#include +#include +#include +#include /* for pthread_once() */ +#include +#include + +/* Used for debugging */ + +#ifndef D +# define D(...) do{}while(0) +#endif + +/* Try to open a qemud pipe, 'pipeName' must be a generic pipe service + * name (e.g. "opengles" or "camera"). The emulator will be in charge of + * connecting the corresponding pipe/client to an internal service or an + * external socket, these details are hidden from the caller. + * + * Return a new QemuPipe pointer, or NULL in case of error + */ +int +qemu_pipe_open(const char* pipeName) +{ + char buff[256]; + int buffLen; + int fd, ret; + + if (pipeName == NULL || pipeName[0] == '\0') { + errno = EINVAL; + return -1; + } + + snprintf(buff, sizeof buff, "pipe:%s", pipeName); + + fd = open("/dev/qemu_pipe", O_RDWR); + if (fd < 0) { + D("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__, strerror(errno)); + errno = ENOSYS; + return -1; + } + + buffLen = strlen(buff); + + ret = TEMP_FAILURE_RETRY(write(fd, buff, buffLen+1)); + if (ret != buffLen+1) { + D("%s: Could not connect to %s pipe service: %s", __FUNCTION__, pipeName, strerror(errno)); + if (ret == 0) { + errno = ECONNRESET; + } else if (ret > 0) { + errno = EINVAL; + } + return -1; + } + + return fd; +} diff --git a/tools/emulator/system/libqemu/test_guest_1.c b/tools/emulator/system/libqemu/test_guest_1.c new file mode 100644 index 000000000..1a8100053 --- /dev/null +++ b/tools/emulator/system/libqemu/test_guest_1.c @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/* This program uses a QEMUD pipe to exchange data with a test + * server. It's very simple: + * + * for count in range(0,100): + * msg = "Hello Word " + count + * qemud_pipe_send(msg) + * qemud_pipe_recv(msg2) + * if (msg != msg2): + * error() + * + * + * See test_host_1.c for the corresponding server code, which simply + * sends back anything it receives from the client. + */ +#include "test_util.h" +#include +#include +#include +#include + +#define PIPE_NAME "pingpong" + + +int main(void) +{ + Pipe pipe[1]; + const int maxCount = 100; + int port = 8012; + +#if 0 + if (pipe_openSocket(pipe, port) < 0) { + fprintf(stderr, "Could not open tcp socket!\n"); + return 1; + } + printf("Connected to tcp:host:%d\n", port); +#else + if (pipe_openQemuPipe(pipe, PIPE_NAME) < 0) { + fprintf(stderr, "Could not open '%s' pipe: %s\n", PIPE_NAME, strerror(errno)); + return 1; + } + printf("Connected to '%s' pipe\n", PIPE_NAME); +#endif + + char buff[64]; + char buff2[64]; + int count; + double time0 = now_secs(); + size_t total = 0; + + for (count = 0; count < maxCount; count++) { + /* First, send a small message */ + int len = snprintf(buff, sizeof(buff), "Hello World %d\n", count); + printf("%4d: Sending %d bytes\n", count, len); + int ret = pipe_send(pipe, buff, len); + if (ret < 0) { + fprintf(stderr,"Sending %d bytes failed: %s\n", len, strerror(errno)); + return 1; + } + + total += len; + + /* The server is supposed to send the message back */ + ret = pipe_recv(pipe, buff2, len); + if (ret < 0) { + fprintf(stderr, "Receiving failed (ret=%d): %s\n", ret, strerror(errno)); + return 3; + } + printf("%4d: Received %d bytes\n", count, ret); + /* Check the message's content */ + if (ret != len) { + fprintf(stderr, "Message size mismatch sent=%d received=%d\n", len, ret); + return 5; + } + if (memcmp(buff, buff2, len) != 0) { + fprintf(stderr, "Message content mismatch!\n"); + return 6; + } + } + + double time1 = now_secs(); + + printf("Closing pipe\n"); + pipe_close(pipe); + + printf("Bandwidth: %g MB/s, %g bytes in %g seconds.\n", + total*1.0 / (1024.*1024.*(time1-time0)), 1.0*total, time1-time0); + + return 0; +} diff --git a/tools/emulator/system/libqemu/test_guest_2.c b/tools/emulator/system/libqemu/test_guest_2.c new file mode 100644 index 000000000..c834098fb --- /dev/null +++ b/tools/emulator/system/libqemu/test_guest_2.c @@ -0,0 +1,240 @@ +/* + * 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. + */ + +/* This program benchmarks a QEMUD pipe to exchange data with a test + * server. + * + * See test_host_1.c for the corresponding server code, which simply + * sends back anything it receives from the client. + */ +#include +#include +#include +#include +#include +#include "test_util.h" + +#define PIPE_NAME "pingpong" + +char* progname; + +static void usage(int code) +{ + printf("Usage: %s [options]\n\n", progname); + printf( + "Valid options are:\n\n" + " -? -h --help Print this message\n" + " -pipe Use pipe name (default: " PIPE_NAME ")\n" + " -tcp Use local tcp port\n" + " -size Specify packet size\n" + "\n" + ); + exit(code); +} + +int main(int argc, char** argv) +{ + Pipe pipe[1]; + const char* tcpPort = NULL; + int localPort = 0; + const char* pipeName = NULL; + const char* packetSize = NULL; + int port = 8012; + int maxCount = 1000; + int bufferSize = 16384; + uint8_t* buffer; + uint8_t* buffer2; + int nn, count; + double time0, time1; + + /* Extract program name */ + { + char* p = strrchr(argv[0], '/'); + if (p == NULL) + progname = argv[0]; + else + progname = p+1; + } + + /* Parse options */ + while (argc > 1 && argv[1][0] == '-') { + char* arg = argv[1]; + if (!strcmp(arg, "-?") || !strcmp(arg, "-h") || !strcmp(arg, "--help")) { + usage(0); + } else if (!strcmp(arg, "-pipe")) { + if (argc < 3) { + fprintf(stderr, "-pipe option needs an argument! See --help for details.\n"); + exit(1); + } + argc--; + argv++; + pipeName = argv[1]; + } else if (!strcmp(arg, "-tcp")) { + if (argc < 3) { + fprintf(stderr, "-tcp option needs an argument! See --help for details.\n"); + exit(1); + } + argc--; + argv++; + tcpPort = argv[1]; + } else if (!strcmp(arg, "-size")) { + if (argc < 3) { + fprintf(stderr, "-tcp option needs an argument! See --help for details.\n"); + exit(1); + } + argc--; + argv++; + packetSize = argv[1]; + } else { + fprintf(stderr, "UNKNOWN OPTION: %s\n\n", arg); + usage(1); + } + argc--; + argv++; + } + + /* Check arguments */ + if (tcpPort && pipeName) { + fprintf(stderr, "You can't use both -pipe and -tcp at the same time\n"); + exit(2); + } + + if (tcpPort != NULL) { + localPort = atoi(tcpPort); + if (localPort <= 0 || localPort > 65535) { + fprintf(stderr, "Invalid port number: %s\n", tcpPort); + exit(2); + } + } else if (pipeName == NULL) { + /* Use default pipe name */ + pipeName = PIPE_NAME; + } + + if (packetSize != NULL) { + int size = atoi(packetSize); + if (size <= 0) { + fprintf(stderr, "Invalid byte size: %s\n", packetSize); + exit(3); + } + bufferSize = size; + } + + /* Open the pipe */ + if (tcpPort != NULL) { + if (pipe_openSocket(pipe, localPort) < 0) { + fprintf(stderr, "Could not open tcp socket!\n"); + return 1; + } + printf("Connected to tcp:localhost:%d\n", port); + } + else { + if (pipe_openQemuPipe(pipe, pipeName) < 0) { + fprintf(stderr, "Could not open '%s' pipe: %s\n", pipeName, strerror(errno)); + return 1; + } + printf("Connected to '%s' pipe\n", pipeName); + } + + /* Allocate buffers, setup their data */ + buffer = malloc(bufferSize); + buffer2 = malloc(bufferSize); + + for (nn = 0; nn < bufferSize; nn++) { + buffer[nn] = (uint8_t)nn; + } + + /* Do the work! */ + time0 = now_secs(); + + for (count = 0; count < maxCount; count++) { + int ret = pipe_send(pipe, buffer, bufferSize); + int pos, len; + + if (ret < 0) { + fprintf(stderr,"%d: Sending %d bytes failed: %s\n", count, bufferSize, strerror(errno)); + return 1; + } + +#if 1 + /* The server is supposed to send the message back */ + pos = 0; + len = bufferSize; + while (len > 0) { + ret = pipe_recv(pipe, buffer2 + pos, len); + if (ret < 0) { + fprintf(stderr, "Receiving failed (ret=%d): %s\n", ret, strerror(errno)); + return 3; + } + if (ret == 0) { + fprintf(stderr, "Disconnection while receiving!\n"); + return 4; + } + pos += ret; + len -= ret; + } + + if (memcmp(buffer, buffer2, bufferSize) != 0) { + fprintf(stderr, "Message content mismatch!\n"); + const int maxAvail = 16; + const int maxLines = 12; + int numLines = 0; + for (nn = 0; nn < bufferSize; ) { + int avail = bufferSize - nn; + int mm; + if (avail > maxAvail) + avail = maxAvail; + + if (memcmp(buffer+nn, buffer2+nn, avail) != 0) { + if (++numLines >= maxLines) { + printf(".... to be continued ...\n"); + break; + } + printf("%04x:", nn); + + for (mm = 0; mm < avail; mm++) + printf(" %02x", buffer[nn+mm]); + for ( ; mm < maxAvail; mm++ ) + printf(" "); + + printf( " -- " ); + + for (mm = 0; mm < avail; mm++) + printf(" %02x", buffer2[nn+mm]); + + printf ("\n"); + } + nn += avail; + } + return 6; + } + +#endif + + if (count > 0 && (count % 200) == 0) { + printf("... %d\n", count); + } + } + + time1 = now_secs(); + + printf("Closing pipe\n"); + pipe_close(pipe); + + printf("Total time: %g seconds\n", time1 - time0); + printf("Total bytes: %g bytes\n", 1.0*maxCount*bufferSize); + printf("Bandwidth: %g MB/s\n", (maxCount*bufferSize/(1024.0*1024.0))/(time1 - time0) ); + return 0; +} diff --git a/tools/emulator/system/libqemu/test_host_1.c b/tools/emulator/system/libqemu/test_host_1.c new file mode 100644 index 000000000..8e32bf23e --- /dev/null +++ b/tools/emulator/system/libqemu/test_host_1.c @@ -0,0 +1,244 @@ +/* + * 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. + */ + +/* This program is used to test the QEMUD fast pipes. + * See external/qemu/docs/ANDROID-QEMUD-PIPES.TXT for details. + * + * The program acts as a simple TCP server that accepts data and sends + * them back to the client as is. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Default port number */ +#define DEFAULT_PORT 8012 +#define DEFAULT_PATH "/tmp/libqemu-socket" + +/* Try to execute x, looping around EINTR errors. */ +#undef TEMP_FAILURE_RETRY +#define TEMP_FAILURE_RETRY(exp) ({ \ + typeof (exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; }) + +#define TFR TEMP_FAILURE_RETRY + +/* Close a socket, preserving the value of errno */ +static void +socket_close(int sock) +{ + int old_errno = errno; + close(sock); + errno = old_errno; +} + +/* Create a server socket bound to a loopback port */ +static int +socket_loopback_server( int port, int type ) +{ + struct sockaddr_in addr; + + int sock = socket(AF_INET, type, 0); + if (sock < 0) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + int n = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); + + if (TFR(bind(sock, (struct sockaddr*)&addr, sizeof(addr))) < 0) { + socket_close(sock); + return -1; + } + + if (type == SOCK_STREAM) { + if (TFR(listen(sock, 4)) < 0) { + socket_close(sock); + return -1; + } + } + + return sock; +} + +static int +socket_unix_server( const char* path, int type ) +{ + struct sockaddr_un addr; + + int sock = socket(AF_UNIX, type, 0); + if (sock < 0) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path); + + unlink(addr.sun_path); + + printf("Unix path: '%s'\n", addr.sun_path); + + int n = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); + + if (TFR(bind(sock, (struct sockaddr*)&addr, sizeof(addr))) < 0) { + socket_close(sock); + return -1; + } + + if (type == SOCK_STREAM) { + if (TFR(listen(sock, 4)) < 0) { + socket_close(sock); + return -1; + } + } + + return sock; +} + +char* progname; + +static void usage(int code) +{ + printf("Usage: %s [options]\n\n", progname); + printf( + "Valid options are:\n\n" + " -? -h --help Print this message\n" + " -unix Use unix server socket\n" + " -tcp Use local tcp port (default %d)\n" + "\n", DEFAULT_PORT + ); + exit(code); +} + +/* Main program */ +int main(int argc, char** argv) +{ + int sock, client; + int port = DEFAULT_PORT; + const char* path = NULL; + const char* tcpPort = NULL; + + /* Extract program name */ + { + char* p = strrchr(argv[0], '/'); + if (p == NULL) + progname = argv[0]; + else + progname = p+1; + } + + /* Parse options */ + while (argc > 1 && argv[1][0] == '-') { + char* arg = argv[1]; + if (!strcmp(arg, "-?") || !strcmp(arg, "-h") || !strcmp(arg, "--help")) { + usage(0); + } else if (!strcmp(arg, "-unix")) { + if (argc < 3) { + fprintf(stderr, "-unix option needs an argument! See --help for details.\n"); + exit(1); + } + argc--; + argv++; + path = argv[1]; + } else if (!strcmp(arg, "-tcp")) { + if (argc < 3) { + fprintf(stderr, "-tcp option needs an argument! See --help for details.\n"); + exit(1); + } + argc--; + argv++; + tcpPort = argv[1]; + } else { + fprintf(stderr, "UNKNOWN OPTION: %s\n\n", arg); + usage(1); + } + argc--; + argv++; + } + + if (path != NULL) { + printf("Starting pipe test server on unix path: %s\n", path); + sock = socket_unix_server( path, SOCK_STREAM ); + } else { + printf("Starting pipe test server on local port %d\n", port); + sock = socket_loopback_server( port, SOCK_STREAM ); + } + if (sock < 0) { + fprintf(stderr, "Could not start server: %s\n", strerror(errno)); + return 1; + } + printf("Server ready!\n"); + +RESTART: + client = TFR(accept(sock, NULL, NULL)); + if (client < 0) { + fprintf(stderr, "Server error: %s\n", strerror(errno)); + return 2; + } + printf("Client connected!\n"); + + /* Now, accept any incoming data, and send it back */ + for (;;) { + char buff[32768], *p; + int ret, count; + + ret = TFR(read(client, buff, sizeof(buff))); + if (ret < 0) { + fprintf(stderr, "Client read error: %s\n", strerror(errno)); + socket_close(client); + return 3; + } + if (ret == 0) { + break; + } + count = ret; + p = buff; + //printf(" received: %d bytes\n", count); + + while (count > 0) { + ret = TFR(write(client, p, count)); + if (ret < 0) { + fprintf(stderr, "Client write error: %s\n", strerror(errno)); + socket_close(client); + return 4; + } + //printf(" sent: %d bytes\n", ret); + + p += ret; + count -= ret; + } + } + printf("Client closed connection\n"); + socket_close(client); + goto RESTART; + + return 0; +} diff --git a/tools/emulator/system/libqemu/test_host_2.c b/tools/emulator/system/libqemu/test_host_2.c new file mode 100644 index 000000000..46a9e8dfb --- /dev/null +++ b/tools/emulator/system/libqemu/test_host_2.c @@ -0,0 +1,129 @@ +/* + * 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. + */ + +/* This program is used to test the QEMUD fast pipes. + * See external/qemu/docs/ANDROID-QEMUD-PIPES.TXT for details. + * + * The program acts as a simple TCP server that accepts any data and + * discards it immediately. + */ +#include +#include +#include +#include +#include +#include +#include + +/* Default port number */ +#define DEFAULT_PORT 8012 + +/* Try to execute x, looping around EINTR errors. */ +#undef TEMP_FAILURE_RETRY +#define TEMP_FAILURE_RETRY(exp) ({ \ + typeof (exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; }) + +#define TFR TEMP_FAILURE_RETRY + +/* Close a socket, preserving the value of errno */ +static void +socket_close(int sock) +{ + int old_errno = errno; + close(sock); + errno = old_errno; +} + +/* Create a server socket bound to a loopback port */ +static int +socket_loopback_server( int port, int type ) +{ + struct sockaddr_in addr; + + int sock = socket(AF_INET, type, 0); + if (sock < 0) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + int n = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); + + if (TFR(bind(sock, (struct sockaddr*)&addr, sizeof(addr))) < 0) { + socket_close(sock); + return -1; + } + + if (type == SOCK_STREAM) { + if (TFR(listen(sock, 4)) < 0) { + socket_close(sock); + return -1; + } + } + + return sock; +} + +/* Main program */ +int main(void) +{ + int sock, client; + int port = DEFAULT_PORT; + + printf("Starting pipe test server on local port %d\n", port); + sock = socket_loopback_server( port, SOCK_STREAM ); + if (sock < 0) { + fprintf(stderr, "Could not start server: %s\n", strerror(errno)); + return 1; + } + +RESTART: + client = TFR(accept(sock, NULL, NULL)); + if (client < 0) { + fprintf(stderr, "Server error: %s\n", strerror(errno)); + return 2; + } + printf("Client connected!\n"); + + /* Now, accept any incoming data, and send it back */ + for (;;) { + char buff[8192], *p; + int ret, count; + + ret = TFR(read(client, buff, sizeof(buff))); + if (ret < 0) { + fprintf(stderr, "Client read error: %s\n", strerror(errno)); + socket_close(client); + return 3; + } + if (ret == 0) { + break; + } + } + printf("Client closed connection\n"); + socket_close(client); + goto RESTART; + + return 0; +} diff --git a/tools/emulator/system/libqemu/test_util.c b/tools/emulator/system/libqemu/test_util.c new file mode 100644 index 000000000..169679626 --- /dev/null +++ b/tools/emulator/system/libqemu/test_util.c @@ -0,0 +1,137 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include "test_util.h" + +#ifdef __linux__ +#include +double now_secs(void) +{ + struct timespec tm; + clock_gettime(CLOCK_MONOTONIC, &tm); + return (double)tm.tv_sec + (double)tm.tv_nsec/1e9; +} +#else +#include +double now_secs(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.sec + (double)tv.usec/1e6; +} +#endif + +int +pipe_openSocket( Pipe* pipe, int port ) +{ + static int fd; + struct sockaddr_in addr; + + pipe->socket = -1; + + fd = socket( AF_INET, SOCK_STREAM, 0 ); + if (fd < 0) { + fprintf(stderr, "%s: Can't create socket!!\n", __FUNCTION__); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(0x0a000202); + + if ( connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0 ) { + fprintf(stderr, "%s: Can't connect to tcp:local:%d: %s\n", + __FUNCTION__, port, strerror(errno)); + close(fd); + return -1; + } + + pipe->socket = fd; + return 0; +} + +int +pipe_openQemuPipe( Pipe* pipe, const char* pipename ) +{ + pipe->socket = qemu_pipe_open(pipename); + if (pipe->socket < 0) { + fprintf(stderr, "%s: Could not open '%s' pipe: %s\n", __FUNCTION__, pipename, strerror(errno)); + return -1; + } + return 0; +} + +int +pipe_send( Pipe* pipe, const void* buff, size_t bufflen ) +{ + int ret; + const uint8_t* ptr = buff; + while (bufflen > 0) { + ret = write(pipe->socket, ptr, bufflen); + if (ret < 0) { + if (errno == EINTR) + continue; + fprintf(stderr, "%s: error: %s\n", __FUNCTION__, strerror(errno)); + return -1; + } + if (ret == 0) { + fprintf(stderr, "%s: disconnection!\n", __FUNCTION__); + return -1; + } + ptr += ret; + bufflen -= ret; + } + return 0; +} + +int +pipe_recv( Pipe* pipe, void* buff, size_t bufflen ) +{ + int ret; + + for (;;) { + ret = read(pipe->socket, buff, bufflen); + if (ret < 0) { + if (errno == EINTR) + continue; + fprintf(stderr, "%s: error: %s\n", __FUNCTION__, strerror(errno)); + return -1; + } + if (ret == 0) { + fprintf(stderr, "%s: disconnection!\n", __FUNCTION__); + return -1; + } + break; + } + return ret; +} + +void +pipe_close( Pipe* pipe ) +{ + if (pipe->socket >= 0) { + close(pipe->socket); + pipe->socket = -1; + } +} diff --git a/tools/emulator/system/libqemu/test_util.h b/tools/emulator/system/libqemu/test_util.h new file mode 100644 index 000000000..28e5115c0 --- /dev/null +++ b/tools/emulator/system/libqemu/test_util.h @@ -0,0 +1,35 @@ +/* + * 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 TEST_UTIL_H +#define TEST_UTIL_H + +#include +#include + + +double now_secs(void); + +typedef struct { + int socket; +} Pipe; + +int pipe_openSocket( Pipe* pipe, int port ); +int pipe_openQemuPipe( Pipe* pipe, const char* pipename ); +int pipe_send( Pipe* pipe, const void* buff, size_t bufflen ); +int pipe_recv( Pipe* pipe, void* buff, size_t bufflen ); +void pipe_close( Pipe* pipe ); + +#endif /* TEST_UTIL_H */ diff --git a/tools/emulator/system/libqemu/tests.mk b/tools/emulator/system/libqemu/tests.mk new file mode 100644 index 000000000..66d402b73 --- /dev/null +++ b/tools/emulator/system/libqemu/tests.mk @@ -0,0 +1,30 @@ +# Build libqemu tests, included from main Android.mk + +# The first test program is a simple TCP server that will send back +# anything it receives from the client. +# +include $(CLEAR_VARS) +LOCAL_MODULE := test-libqemu-1 +LOCAL_SRC_FILES := test_host_1.c +LOCAL_MODULE_TAGS := debug +include $(BUILD_HOST_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := test-libqemu-2 +LOCAL_SRC_FILES := test_host_2.c +LOCAL_MODULE_TAGS := debug +include $(BUILD_HOST_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := test-libqemu-1 +LOCAL_SRC_FILES := test_guest_1.c test_util.c +LOCAL_MODULE_TAGS := debug +LOCAL_STATIC_LIBRARIES := libqemu libcutils +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := test-libqemu-2 +LOCAL_SRC_FILES := test_guest_2.c test_util.c +LOCAL_MODULE_TAGS := debug +LOCAL_STATIC_LIBRARIES := libqemu libcutils +include $(BUILD_EXECUTABLE)