diff options
author | David 'Digit' Turner <digit@android.com> | 2010-11-18 16:14:03 +0100 |
---|---|---|
committer | David 'Digit' Turner <digit@android.com> | 2010-11-19 15:01:21 +0100 |
commit | 6d448806a80bcc2557ae0a38e7fd206967cf844e (patch) | |
tree | 08c567d36949bbc4263eb7a84b67936ce7789f6d /android/async-console.c | |
parent | 1bb627cd086588d3f9650fac04f4034961caf9f1 (diff) | |
download | external_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.c | 147 |
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; +} |