From e993126c6704029cb1c656922a66a32bd09b6089 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Wed, 2 Feb 2011 14:05:23 +0100 Subject: Move core-connection.c from to android/protocol/ Change-Id: I1f04ed1f00fccdea043f4a4fbf5ba745b36bbcc7 --- Makefile.android | 2 +- android/core-connection.c | 363 --------------------------------- android/core-connection.h | 169 --------------- android/main-ui.c | 2 +- android/protocol/attach-ui-impl.c | 2 +- android/protocol/core-commands-proxy.c | 2 +- android/protocol/core-connection.c | 363 +++++++++++++++++++++++++++++++++ android/protocol/core-connection.h | 169 +++++++++++++++ android/protocol/fb-updates-impl.c | 1 + android/protocol/fb-updates-impl.h | 1 - android/protocol/ui-commands-impl.c | 2 +- android/protocol/user-events-proxy.c | 2 +- vl-android-ui.c | 2 +- 13 files changed, 540 insertions(+), 540 deletions(-) delete mode 100644 android/core-connection.c delete mode 100644 android/core-connection.h create mode 100644 android/protocol/core-connection.c create mode 100644 android/protocol/core-connection.h diff --git a/Makefile.android b/Makefile.android index 5faab57..1896cf0 100644 --- a/Makefile.android +++ b/Makefile.android @@ -1212,13 +1212,13 @@ VL_SOURCES := framebuffer.c \ android/display.c \ android/looper-generic.c \ android/snapshot.c \ - android/core-connection.c \ android/main-common.c \ android/main-ui.c \ qemu-timer-ui.c \ vl-android-ui.c \ console-ui.c \ iolooper-select.c \ + android/protocol/core-connection.c \ android/protocol/attach-ui-impl.c \ android/protocol/fb-updates-impl.c \ android/protocol/ui-commands-impl.c \ diff --git a/android/core-connection.c b/android/core-connection.c deleted file mode 100644 index 1099291..0000000 --- a/android/core-connection.c +++ /dev/null @@ -1,363 +0,0 @@ -/* 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 - -#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/core-connection.h" -#include "android/utils/system.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/core-connection.h b/android/core-connection.h deleted file mode 100644 index 5701f8c..0000000 --- a/android/core-connection.h +++ /dev/null @@ -1,169 +0,0 @@ -/* 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/main-ui.c b/android/main-ui.c index 0486ac1..051f3e8 100644 --- a/android/main-ui.c +++ b/android/main-ui.c @@ -52,7 +52,7 @@ #include "android/display.h" #include "android/snapshot.h" -#include "android/core-connection.h" +#include "android/protocol/core-connection.h" #include "android/protocol/fb-updates-impl.h" #include "android/protocol/user-events-proxy.h" #include "android/protocol/core-commands-proxy.h" 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 + +#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" diff --git a/vl-android-ui.c b/vl-android-ui.c index e818159..c4a396c 100644 --- a/vl-android-ui.c +++ b/vl-android-ui.c @@ -41,7 +41,7 @@ #include "android/globals.h" #include "android/utils/bufprint.h" #include "android/utils/system.h" -#include "android/core-connection.h" +#include "android/protocol/core-connection.h" #include "android/protocol/attach-ui-impl.h" #include "android/protocol/fb-updates-impl.h" #include "android/protocol/user-events-proxy.h" -- cgit v1.1