aboutsummaryrefslogtreecommitdiffstats
path: root/android/async-console.c
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2010-11-18 16:14:03 +0100
committerDavid 'Digit' Turner <digit@android.com>2010-11-19 15:01:21 +0100
commit6d448806a80bcc2557ae0a38e7fd206967cf844e (patch)
tree08c567d36949bbc4263eb7a84b67936ce7789f6d /android/async-console.c
parent1bb627cd086588d3f9650fac04f4034961caf9f1 (diff)
downloadexternal_qemu-6d448806a80bcc2557ae0a38e7fd206967cf844e.zip
external_qemu-6d448806a80bcc2557ae0a38e7fd206967cf844e.tar.gz
external_qemu-6d448806a80bcc2557ae0a38e7fd206967cf844e.tar.bz2
Introduce asynchronous operation helpers.
<android/async-utils.h> contains generic helpers to read, write and connect to sockets. <android/async-console.h> contains a helper class to connect to Android console port asynchronously. Change-Id: I5d0a49a770ad974c5d4382438d75e9eb624368d1
Diffstat (limited to 'android/async-console.c')
-rw-r--r--android/async-console.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/android/async-console.c b/android/async-console.c
new file mode 100644
index 0000000..f486df0
--- /dev/null
+++ b/android/async-console.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 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 "android/async-console.h"
+#include <string.h>
+
+/*
+ * State diagram, ommitting the ERROR state
+ *
+ * INITIAL -->--+
+ * | |
+ * | CONNECTING
+ * | |
+ * |<-----+
+ * v
+ * READ_BANNER_1
+ * |
+ * v
+ * READ_BANNER_2
+ * |
+ * v
+ * COMPLETE
+ */
+
+enum {
+ STATE_INITIAL,
+ STATE_CONNECTING,
+ STATE_ERROR,
+ STATE_READ_BANNER_1,
+ STATE_READ_BANNER_2,
+ STATE_COMPLETE
+};
+
+/* A helper function to prepare the line reader and switch to a new state */
+static AsyncStatus
+_acc_prepareLineReader(AsyncConsoleConnector* acc, LoopIo* io, int newState)
+{
+ acc->state = newState;
+ asyncLineReader_init(acc->lreader, acc->lbuff, sizeof(acc->lbuff), io);
+ return ASYNC_NEED_MORE;
+}
+
+AsyncStatus
+asyncConsoleConnector_connect(AsyncConsoleConnector* acc,
+ const SockAddress* address,
+ LoopIo* io)
+{
+ acc->state = STATE_INITIAL;
+ acc->address = address[0];
+ return asyncConsoleConnector_run(acc, io);
+}
+
+
+AsyncStatus
+asyncConsoleConnector_run(AsyncConsoleConnector* acc,
+ LoopIo* io)
+{
+ AsyncStatus status = ASYNC_NEED_MORE;
+
+ for (;;) {
+ switch (acc->state)
+ {
+ case STATE_ERROR: /* reporting previous error */
+ errno = acc->error;
+ return ASYNC_ERROR;
+
+ case STATE_INITIAL: /* initial connection attempt */
+ acc->state = STATE_CONNECTING;
+ status = asyncConnector_init(acc->connector, &acc->address, io);
+ if (status == ASYNC_ERROR)
+ goto SET_ERROR;
+
+ if (status == ASYNC_COMPLETE) { /* immediate connection */
+ _acc_prepareLineReader(acc, io, STATE_READ_BANNER_1);
+ continue;
+ }
+ break;
+
+ case STATE_CONNECTING: /* still trying to connect */
+ status = asyncConnector_run(acc->connector, io);
+ if (status == ASYNC_ERROR)
+ goto SET_ERROR;
+
+ if (status == ASYNC_COMPLETE) {
+ _acc_prepareLineReader(acc, io, STATE_READ_BANNER_1);
+ continue;
+ }
+ break;
+
+ case STATE_READ_BANNER_1: /* reading the first banner line */
+ status = asyncLineReader_read(acc->lreader, io);
+ if (status == ASYNC_ERROR)
+ goto SET_ERROR;
+
+ if (status == ASYNC_COMPLETE) {
+ /* Check that first line starts with "Android Console:",
+ * otherwise we're not talking to the right program. */
+ const char* line = asyncLineReader_getLine(acc->lreader);
+ if (line == NULL || memcmp(line, "Android Console:", 16)) {
+ goto BAD_BANNER;
+ }
+ /* ok, fine, prepare for the next banner line then */
+ _acc_prepareLineReader(acc, io, STATE_READ_BANNER_2);
+ continue;
+ }
+ break;
+
+ case STATE_READ_BANNER_2: /* reading the second banner line */
+ status = asyncLineReader_read(acc->lreader, io);
+ if (status == ASYNC_ERROR)
+ goto SET_ERROR;
+
+ if (status == ASYNC_COMPLETE) {
+ const char* line = asyncLineReader_getLine(acc->lreader);
+ if (line == NULL) {
+ goto BAD_BANNER;
+ }
+ /* ok, we're done !*/
+ acc->state = STATE_COMPLETE;
+ return ASYNC_COMPLETE;
+ }
+ break;
+
+ case STATE_COMPLETE:
+ status = ASYNC_COMPLETE;
+ }
+ return status;
+ }
+BAD_BANNER:
+ errno = ENOPROTOOPT;
+SET_ERROR:
+ acc->state = STATE_ERROR;
+ acc->error = errno;
+ return ASYNC_ERROR;
+}