aboutsummaryrefslogtreecommitdiffstats
path: root/android/protocol
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2011-02-02 14:05:23 +0100
committerDavid 'Digit' Turner <digit@android.com>2011-02-02 14:05:23 +0100
commite993126c6704029cb1c656922a66a32bd09b6089 (patch)
tree64df4e534e0364cb3d45b4eef564e401932a118e /android/protocol
parent74d7acec6643694132a127feb5ccadda7ea793d6 (diff)
downloadexternal_qemu-e993126c6704029cb1c656922a66a32bd09b6089.zip
external_qemu-e993126c6704029cb1c656922a66a32bd09b6089.tar.gz
external_qemu-e993126c6704029cb1c656922a66a32bd09b6089.tar.bz2
Move core-connection.c from to android/protocol/
Change-Id: I1f04ed1f00fccdea043f4a4fbf5ba745b36bbcc7
Diffstat (limited to 'android/protocol')
-rw-r--r--android/protocol/attach-ui-impl.c2
-rw-r--r--android/protocol/core-commands-proxy.c2
-rw-r--r--android/protocol/core-connection.c363
-rw-r--r--android/protocol/core-connection.h169
-rw-r--r--android/protocol/fb-updates-impl.c1
-rw-r--r--android/protocol/fb-updates-impl.h1
-rw-r--r--android/protocol/ui-commands-impl.c2
-rw-r--r--android/protocol/user-events-proxy.c2
8 files changed, 537 insertions, 5 deletions
diff --git a/android/protocol/attach-ui-impl.c b/android/protocol/attach-ui-impl.c
index 8ca204c..a61e546 100644
--- a/android/protocol/attach-ui-impl.c
+++ b/android/protocol/attach-ui-impl.c
@@ -16,9 +16,9 @@
* from the Core.
*/
-#include "android/core-connection.h"
#include "android/utils/debug.h"
#include "android/utils/panic.h"
+#include "android/protocol/core-connection.h"
#include "android/protocol/attach-ui-impl.h"
/* Descriptor for the UI-side of the "attach-ui" service. */
diff --git a/android/protocol/core-commands-proxy.c b/android/protocol/core-commands-proxy.c
index a52a376..0a50794 100644
--- a/android/protocol/core-commands-proxy.c
+++ b/android/protocol/core-commands-proxy.c
@@ -17,11 +17,11 @@
#include "console.h"
#include "android/looper.h"
-#include "android/core-connection.h"
#include "android/async-utils.h"
#include "android/sync-utils.h"
#include "android/utils/debug.h"
#include "android/utils/panic.h"
+#include "android/protocol/core-connection.h"
#include "android/protocol/core-commands.h"
#include "android/protocol/core-commands-proxy.h"
#include "android/protocol/core-commands-api.h"
diff --git a/android/protocol/core-connection.c b/android/protocol/core-connection.c
new file mode 100644
index 0000000..6de5386
--- /dev/null
+++ b/android/protocol/core-connection.c
@@ -0,0 +1,363 @@
+/* Copyright (C) 2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include <unistd.h>
+
+#include "sockets.h"
+#include "qemu-common.h"
+#include "errno.h"
+#include "iolooper.h"
+#include "android/android.h"
+#include "android/utils/debug.h"
+#include "android/globals.h"
+#include "android/utils/system.h"
+#include "android/protocol/core-connection.h"
+
+/* Descriptor for a client, connected to the core via console port. */
+struct CoreConnection {
+ /* Socket address of the console. */
+ SockAddress console_address;
+
+ // Helper for performing sync I/O on the console socket.
+ SyncSocket* ssocket;
+
+ /* Stream name. Can be:
+ * - NULL for the console itself.
+ * - "attach-UI" for the attached UI client.
+ */
+ char* stream_name;
+};
+
+/*
+ * Zero-terminates string buffer.
+ * Param:
+ * buf - Buffer containing the string.
+ * buf_size - Buffer size.
+ * eos - String size.
+ */
+static inline void
+_zero_terminate(char* buf, size_t buf_size, size_t eos)
+{
+ if (eos < buf_size) {
+ buf[eos] = '\0';
+ } else {
+ buf[buf_size - 1] = '\0';
+ }
+}
+
+/*
+ * Checks if console has replied with "OK"
+ * Param:
+ * reply - String containing console's reply
+ * Return:
+ * boolean: true if reply was "OK", or false otherwise.
+ */
+static int
+_is_reply_ok(const char* reply, int reply_size)
+{
+ return (reply_size < 2) ? 0 : (reply[0] == 'O' && reply[1] == 'K');
+}
+
+/*
+ * Checks if console has replied with "KO"
+ * Param:
+ * reply - String containing console's reply
+ * Return:
+ * boolean: true if reply was "KO", or false otherwise.
+ */
+static int
+_is_reply_ko(const char* reply, int reply_size)
+{
+ return (reply_size < 2) ? 0 : (reply[0] == 'K' && reply[1] == 'O');
+}
+
+SyncSocket*
+core_connection_open_socket(SockAddress* sockaddr)
+{
+ SyncSocket* ssocket;
+ int status;
+ int64_t deadline;
+ char buf[512];
+
+ int fd = socket_create(sock_address_get_family(sockaddr), SOCKET_STREAM);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ socket_set_xreuseaddr(fd);
+
+ // Create sync connection to the console.
+ ssocket = syncsocket_connect(fd, sockaddr, CORE_PORT_TIMEOUT_MS);
+ if (ssocket == NULL) {
+ derror("syncsocket_connect has failed: %s\n", errno_str);
+ socket_close(fd);
+ return NULL;
+ }
+
+ // Upon successful connection the console will reply with two strings:
+ // "Android Console....", and "OK\r\n". Read them and check.
+ status = syncsocket_start_read(ssocket);
+ if (status < 0) {
+ derror("syncsocket_start_read has failed: %s\n", errno_str);
+ syncsocket_free(ssocket);
+ return NULL;
+ }
+
+ deadline = iolooper_now() + CORE_PORT_TIMEOUT_MS;
+ // Read first line.
+ status = syncsocket_read_line_absolute(ssocket, buf, sizeof(buf), deadline);
+ if (status <= 0) {
+ derror("syncsocket_read_line_absolute has failed: %s\n", errno_str);
+ syncsocket_free(ssocket);
+ return NULL;
+ }
+ if (status < 15 || memcmp(buf, "Android Console", 15)) {
+ _zero_terminate(buf, sizeof(buf), status);
+ derror("console has failed the connection: %s\n", buf);
+ syncsocket_free(ssocket);
+ return NULL;
+ }
+ // Read second line
+ status = syncsocket_read_line_absolute(ssocket, buf, sizeof(buf), deadline);
+ syncsocket_stop_read(ssocket);
+ if (status < 2 || !_is_reply_ok(buf, status)) {
+ _zero_terminate(buf, sizeof(buf), status);
+ derror("unexpected reply from the console: %s\n", buf);
+ syncsocket_free(ssocket);
+ return NULL;
+ }
+
+ return ssocket;
+}
+
+CoreConnection*
+core_connection_create(SockAddress* console_address)
+{
+ CoreConnection* desc;
+ ANEW0(desc);
+ desc->console_address = console_address[0];
+ desc->ssocket = NULL;
+ desc->stream_name = NULL;
+
+ return desc;
+}
+
+void
+core_connection_free(CoreConnection* desc)
+{
+ if (desc == NULL) {
+ return;
+ }
+ if (desc->ssocket != NULL) {
+ syncsocket_free(desc->ssocket);
+ }
+ if (desc->stream_name != NULL) {
+ free(desc->stream_name);
+ }
+ free(desc);
+}
+
+int
+core_connection_open(CoreConnection* desc)
+{
+ if (desc == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (desc->ssocket != NULL) {
+ return 0;
+ }
+
+ desc->ssocket = core_connection_open_socket(&desc->console_address);
+
+ return (desc->ssocket != NULL) ? 0 : -1;
+}
+
+void
+core_connection_close(CoreConnection* desc)
+{
+ if (desc == NULL) {
+ return;
+ }
+ if (desc->ssocket != NULL) {
+ syncsocket_close(desc->ssocket);
+ }
+}
+
+int
+core_connection_write(CoreConnection* desc,
+ const void* buffer,
+ size_t to_write,
+ size_t* written_bytes)
+{
+ ssize_t written;
+
+ int status = syncsocket_start_write(desc->ssocket);
+ if (status < 0) {
+ derror("syncsocket_start_write failed: %s\n", errno_str);
+ return status;
+ }
+
+ written =
+ syncsocket_write(desc->ssocket, buffer, to_write, CORE_PORT_TIMEOUT_MS);
+ syncsocket_stop_write(desc->ssocket);
+ if (written <= 0) {
+ derror("syncsocket_write failed: %s\n", errno_str);
+ return -1;
+ }
+ if (written_bytes != NULL) {
+ *written_bytes = written;
+ }
+
+ return 0;
+}
+
+int
+core_connection_read(CoreConnection* desc,
+ void* buffer,
+ size_t to_read,
+ size_t* read_bytes)
+{
+ ssize_t read_size;
+
+ int status = syncsocket_start_read(desc->ssocket);
+ if (status < 0) {
+ derror("syncsocket_start_read failed: %s\n", errno_str);
+ return status;
+ }
+
+ read_size =
+ syncsocket_read(desc->ssocket, buffer, to_read, CORE_PORT_TIMEOUT_MS);
+ syncsocket_stop_read(desc->ssocket);
+ if (read_size <= 0) {
+ derror("syncsocket_read failed: %s\n", errno_str);
+ return -1;
+ }
+
+ if (read_bytes != NULL) {
+ *read_bytes = read_size;
+ }
+ return 0;
+}
+
+int
+core_connection_switch_stream(CoreConnection* desc,
+ const char* stream_name,
+ char** handshake)
+{
+ char buf[4096];
+ int handshake_len;
+ int status;
+ int64_t deadline;
+
+ *handshake = NULL;
+ if (desc == NULL || desc->stream_name != NULL || stream_name == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Prepare and write "switch" command.
+ snprintf(buf, sizeof(buf), "qemu %s\r\n", stream_name);
+ if (core_connection_write(desc, buf, strlen(buf), NULL)) {
+ return -1;
+ }
+
+ // Read result / handshake
+ status = syncsocket_start_read(desc->ssocket);
+ if (status < 0) {
+ return -1;
+ }
+ deadline = iolooper_now() + CORE_PORT_TIMEOUT_MS;
+ handshake_len =
+ syncsocket_read_line_absolute(desc->ssocket, buf, sizeof(buf), deadline);
+ _zero_terminate(buf, sizeof(buf), handshake_len);
+ // Replace terminating "\r\n" with 0
+ if (handshake_len >= 1) {
+ if (buf[handshake_len - 1] == '\r' || buf[handshake_len - 1] == '\n') {
+ buf[handshake_len - 1] = '\0';
+ if (handshake_len >= 2 && (buf[handshake_len - 2] == '\r' ||
+ buf[handshake_len - 2] == '\n')) {
+ buf[handshake_len - 2] = '\0';
+ }
+ }
+ }
+ // Lets see what kind of response we've got here.
+ if (_is_reply_ok(buf, handshake_len)) {
+ *handshake = strdup(buf + 3);
+ desc->stream_name = strdup(stream_name);
+ // We expect an "OK" string here
+ status = syncsocket_read_line_absolute(desc->ssocket, buf, sizeof(buf),
+ deadline);
+ syncsocket_stop_read(desc->ssocket);
+ if (status < 0) {
+ derror("error reading console reply on stream switch: %s\n", errno_str);
+ return -1;
+ } else if (!_is_reply_ok(buf, status)) {
+ _zero_terminate(buf, sizeof(buf), status);
+ derror("unexpected console reply when switching streams: %s\n", buf);
+ return -1;
+ }
+ return 0;
+ } else if (_is_reply_ko(buf, handshake_len)) {
+ derror("console has rejected stream switch: %s\n", buf);
+ syncsocket_stop_read(desc->ssocket);
+ *handshake = strdup(buf + 3);
+ return -1;
+ } else {
+ // No OK, no KO? Should be an error!
+ derror("unexpected console reply when switching streams: %s\n", buf);
+ syncsocket_stop_read(desc->ssocket);
+ *handshake = strdup(buf);
+ return -1;
+ }
+}
+
+CoreConnection*
+core_connection_create_and_switch(SockAddress* console_socket,
+ const char* stream_name,
+ char** handshake)
+{
+ char switch_cmd[256];
+ CoreConnection* connection = NULL;
+
+ // Connect to the console service.
+ connection = core_connection_create(console_socket);
+ if (connection == NULL) {
+ return NULL;
+ }
+ if (core_connection_open(connection)) {
+ core_connection_free(connection);
+ return NULL;
+ }
+
+ // Perform the switch.
+ snprintf(switch_cmd, sizeof(switch_cmd), "%s", stream_name);
+ if (core_connection_switch_stream(connection, switch_cmd, handshake)) {
+ core_connection_close(connection);
+ core_connection_free(connection);
+ return NULL;
+ }
+
+ return connection;
+}
+
+void
+core_connection_detach(CoreConnection* desc)
+{
+ core_connection_write(desc, "\n", 1, NULL);
+}
+
+int
+core_connection_get_socket(CoreConnection* desc)
+{
+ return (desc != NULL) ? syncsocket_get_socket(desc->ssocket) : -1;
+}
diff --git a/android/protocol/core-connection.h b/android/protocol/core-connection.h
new file mode 100644
index 0000000..5701f8c
--- /dev/null
+++ b/android/protocol/core-connection.h
@@ -0,0 +1,169 @@
+/* Copyright (C) 2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+/*
+ * This file contains declaration related to communication between emulator's
+ * UI and core through a console port.
+ */
+
+#ifndef QEMU_ANDROID_CORE_CONNECTION_H
+#define QEMU_ANDROID_CORE_CONNECTION_H
+
+#include "android/sync-utils.h"
+
+// Opaque CoreConnection structure.
+typedef struct CoreConnection CoreConnection;
+
+// Base console port
+#define CORE_BASE_PORT 5554
+
+// Maximum number of core porocesses running simultaneously on a machine.
+#define MAX_CORE_PROCS 16
+
+// Socket timeout in millisec (set to 5 seconds)
+#define CORE_PORT_TIMEOUT_MS 5000
+
+/* Opens core console socket.
+ * Param:
+ * sockaddr Socket address to the core console.
+ * Return:
+ * Sync socket descriptor on success, or -1 on failure, with errno appropriately
+ * set.
+ */
+SyncSocket* core_connection_open_socket(SockAddress* sockaddr);
+
+/* Creates descriptor for a console client.
+ * Param:
+ * console_socket Socket address for the console.
+ * Return:
+ * Allocated and initialized descriptor for the client on success, or NULL
+ * on failure.
+ */
+CoreConnection* core_connection_create(SockAddress* console_socket);
+
+/* Frees descriptor allocated with core_connection_create.
+ * Param:
+ * desc Descriptor to free. Note that this routine will simply free the memory
+ * used by the descriptor.
+ */
+void core_connection_free(CoreConnection* desc);
+
+/* Opens a socket handle to the console.
+ * Param:
+ * desc Console client descriptor. Note that if the descriptor has been already
+ * opened, this routine will simply return with success.
+ * Return:
+ * 0 on success, or -1 on failure with errno properly set. This routine will
+ * return in at most one second.
+ */
+int core_connection_open(CoreConnection* desc);
+
+/* Closes a socket handle to the console opened with core_connection_open.
+ * Param:
+ * desc Console client descriptor opened with core_connection_open.
+ */
+void core_connection_close(CoreConnection* desc);
+
+/* Synchronously writes to the console. See CORE_PORT_TIMEOUT_MS for the timeout
+ * value used to wait for the write operation to complete.
+ * Param:
+ * desc Console client descriptor opened with core_connection_open.
+ * buffer Buffer to write.
+ * to_write Number of bytes to write.
+ * written_bytes Upon success, contains number of bytes written. This parameter
+ * is optional, and can be NULL.
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int core_connection_write(CoreConnection* desc,
+ const void* buffer,
+ size_t to_write,
+ size_t* written_bytes);
+
+/* Synchronously reads from the console. See CORE_PORT_TIMEOUT_MS for the
+ * timeout value used to wait for the read operation to complete.
+ * Param:
+ * desc Console client descriptor opened with core_connection_open.
+ * buffer Buffer to read data to.
+ * to_read Number of bytes to read.
+ * read_bytes Upon success, contains number of bytes that have been actually
+ * read. This parameter is optional, and can be NULL.
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int core_connection_read(CoreConnection* desc,
+ void* buffer,
+ size_t to_read,
+ size_t* read_bytes);
+
+/* Switches opened console client to a given stream.
+ * Param:
+ * desc Console client descriptor opened with core_connection_open. Note
+ * that this descriptor should represent console itself. In other words,
+ * there must have been no previous calls to this routine for that
+ * descriptor.
+ * stream_name Name of the stream to switch to.
+ * handshake Address of a string to allocate for a handshake message on
+ * success, or an error message on failure. If upon return from this
+ * routine that string is not NULL, its buffer must be freed with 'free'.
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int core_connection_switch_stream(CoreConnection* desc,
+ const char* stream_name,
+ char** handshake);
+
+/* Creates a console client, and switches it to a given stream.
+ * console_socket Socket address for the console.
+ * stream_name Name of the stream to switch to.
+ * handshake Address of a string to allocate for a handshake message on
+ * success, or an error message on failure. If upon return from this
+ * routine that string is not NULL, its buffer must be freed with 'free'.
+ * Return:
+ * Allocated and initialized descriptor for the switched client on success, or
+ * NULL on failure.
+ */
+CoreConnection* core_connection_create_and_switch(SockAddress* console_socket,
+ const char* stream_name,
+ char** handshake);
+
+/* Detaches opened console client from the console.
+ * By console protocol, writing "\r\n" string to the console will destroy the
+ * console client.
+ * Param:
+ * desc Console client descriptor opened with core_connection_open.
+ */
+void core_connection_detach(CoreConnection* desc);
+
+/* Gets socket descriptor associated with the core connection.
+ * Param:
+ * desc Console client descriptor opened with core_connection_open.
+ * Return
+ * Socket descriptor associated with the core connection.
+ */
+int core_connection_get_socket(CoreConnection* desc);
+
+/* Calculates timeout for transferring the given number of bytes via core
+ * connection.
+ * Return:
+ * Number of milliseconds during which the entire number of bytes is expected
+ * to be transferred via core connection.
+ */
+static inline int
+core_connection_get_timeout(size_t data_size)
+{
+ // Min 2 seconds + 10 millisec for each transferring byte.
+ // TODO: Come up with a better arithmetics here.
+ return 2000 + data_size * 10;
+}
+
+#endif // QEMU_ANDROID_CORE_CONNECTION_H
diff --git a/android/protocol/fb-updates-impl.c b/android/protocol/fb-updates-impl.c
index ebe7309..170fb47 100644
--- a/android/protocol/fb-updates-impl.c
+++ b/android/protocol/fb-updates-impl.c
@@ -20,6 +20,7 @@
#include "android/utils/debug.h"
#include "android/utils/panic.h"
#include "android/sync-utils.h"
+#include "android/protocol/core-connection.h"
#include "android/protocol/fb-updates.h"
#include "android/protocol/fb-updates-impl.h"
diff --git a/android/protocol/fb-updates-impl.h b/android/protocol/fb-updates-impl.h
index 0c351aa..2572b5e 100644
--- a/android/protocol/fb-updates-impl.h
+++ b/android/protocol/fb-updates-impl.h
@@ -22,7 +22,6 @@
#include "framebuffer.h"
#include "android/looper.h"
#include "android/async-utils.h"
-#include "android/core-connection.h"
/* Creates framebuffer client, and connects it with the core.
* Param:
diff --git a/android/protocol/ui-commands-impl.c b/android/protocol/ui-commands-impl.c
index 30d5277..f265514 100644
--- a/android/protocol/ui-commands-impl.c
+++ b/android/protocol/ui-commands-impl.c
@@ -18,12 +18,12 @@
#include "console.h"
#include "android/looper.h"
-#include "android/core-connection.h"
#include "android/async-utils.h"
#include "android/sync-utils.h"
#include "android/utils/system.h"
#include "android/utils/debug.h"
#include "android/utils/panic.h"
+#include "android/protocol/core-connection.h"
#include "android/protocol/ui-commands-impl.h"
#include "android/protocol/ui-commands-api.h"
diff --git a/android/protocol/user-events-proxy.c b/android/protocol/user-events-proxy.c
index 2049b68..3796ff9 100644
--- a/android/protocol/user-events-proxy.c
+++ b/android/protocol/user-events-proxy.c
@@ -14,8 +14,8 @@
#include "console.h"
#include "android/looper.h"
#include "android/async-utils.h"
-#include "android/core-connection.h"
#include "android/utils/debug.h"
+#include "android/protocol/core-connection.h"
#include "android/protocol/user-events-protocol.h"
#include "android/protocol/user-events-proxy.h"