blob: 523c2b2f1d80f7684809be08c1af5c338e9ffac9 [file] [log] [blame]
David 'Digit' Turner6d448802010-11-18 16:14:03 +01001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "android/async-console.h"
17#include <string.h>
18
19/*
20 * State diagram, ommitting the ERROR state
21 *
22 * INITIAL -->--+
23 * | |
24 * | CONNECTING
25 * | |
26 * |<-----+
27 * v
28 * READ_BANNER_1
29 * |
30 * v
31 * READ_BANNER_2
32 * |
33 * v
34 * COMPLETE
35 */
36
37enum {
38 STATE_INITIAL,
39 STATE_CONNECTING,
40 STATE_ERROR,
41 STATE_READ_BANNER_1,
42 STATE_READ_BANNER_2,
43 STATE_COMPLETE
44};
45
46/* A helper function to prepare the line reader and switch to a new state */
47static AsyncStatus
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +010048_acc_prepareLineReader(AsyncConsoleConnector* acc, int newState)
David 'Digit' Turner6d448802010-11-18 16:14:03 +010049{
50 acc->state = newState;
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +010051 asyncLineReader_init(acc->lreader, acc->lbuff, sizeof(acc->lbuff), acc->io);
David 'Digit' Turner6d448802010-11-18 16:14:03 +010052 return ASYNC_NEED_MORE;
53}
54
55AsyncStatus
56asyncConsoleConnector_connect(AsyncConsoleConnector* acc,
57 const SockAddress* address,
58 LoopIo* io)
59{
60 acc->state = STATE_INITIAL;
61 acc->address = address[0];
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +010062 acc->io = io;
63 return asyncConsoleConnector_run(acc);
David 'Digit' Turner6d448802010-11-18 16:14:03 +010064}
65
66
67AsyncStatus
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +010068asyncConsoleConnector_run(AsyncConsoleConnector* acc)
David 'Digit' Turner6d448802010-11-18 16:14:03 +010069{
70 AsyncStatus status = ASYNC_NEED_MORE;
71
72 for (;;) {
73 switch (acc->state)
74 {
75 case STATE_ERROR: /* reporting previous error */
76 errno = acc->error;
77 return ASYNC_ERROR;
78
79 case STATE_INITIAL: /* initial connection attempt */
80 acc->state = STATE_CONNECTING;
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +010081 status = asyncConnector_init(acc->connector, &acc->address, acc->io);
David 'Digit' Turner6d448802010-11-18 16:14:03 +010082 if (status == ASYNC_ERROR)
83 goto SET_ERROR;
84
85 if (status == ASYNC_COMPLETE) { /* immediate connection */
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +010086 _acc_prepareLineReader(acc, STATE_READ_BANNER_1);
David 'Digit' Turner6d448802010-11-18 16:14:03 +010087 continue;
88 }
89 break;
90
91 case STATE_CONNECTING: /* still trying to connect */
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +010092 status = asyncConnector_run(acc->connector);
David 'Digit' Turner6d448802010-11-18 16:14:03 +010093 if (status == ASYNC_ERROR)
94 goto SET_ERROR;
95
96 if (status == ASYNC_COMPLETE) {
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +010097 _acc_prepareLineReader(acc, STATE_READ_BANNER_1);
David 'Digit' Turner6d448802010-11-18 16:14:03 +010098 continue;
99 }
100 break;
101
102 case STATE_READ_BANNER_1: /* reading the first banner line */
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +0100103 status = asyncLineReader_read(acc->lreader);
David 'Digit' Turner6d448802010-11-18 16:14:03 +0100104 if (status == ASYNC_ERROR)
105 goto SET_ERROR;
106
107 if (status == ASYNC_COMPLETE) {
108 /* Check that first line starts with "Android Console:",
109 * otherwise we're not talking to the right program. */
110 const char* line = asyncLineReader_getLine(acc->lreader);
111 if (line == NULL || memcmp(line, "Android Console:", 16)) {
112 goto BAD_BANNER;
113 }
114 /* ok, fine, prepare for the next banner line then */
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +0100115 _acc_prepareLineReader(acc, STATE_READ_BANNER_2);
David 'Digit' Turner6d448802010-11-18 16:14:03 +0100116 continue;
117 }
118 break;
119
120 case STATE_READ_BANNER_2: /* reading the second banner line */
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +0100121 status = asyncLineReader_read(acc->lreader);
David 'Digit' Turner6d448802010-11-18 16:14:03 +0100122 if (status == ASYNC_ERROR)
123 goto SET_ERROR;
124
125 if (status == ASYNC_COMPLETE) {
126 const char* line = asyncLineReader_getLine(acc->lreader);
127 if (line == NULL) {
128 goto BAD_BANNER;
129 }
130 /* ok, we're done !*/
131 acc->state = STATE_COMPLETE;
132 return ASYNC_COMPLETE;
133 }
134 break;
135
136 case STATE_COMPLETE:
137 status = ASYNC_COMPLETE;
138 }
139 return status;
140 }
141BAD_BANNER:
142 errno = ENOPROTOOPT;
143SET_ERROR:
144 acc->state = STATE_ERROR;
145 acc->error = errno;
146 return ASYNC_ERROR;
147}