• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
37 enum {
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 */
47 static AsyncStatus
_acc_prepareLineReader(AsyncConsoleConnector * acc,int newState)48 _acc_prepareLineReader(AsyncConsoleConnector* acc, int newState)
49 {
50     acc->state = newState;
51     asyncLineReader_init(acc->lreader, acc->lbuff, sizeof(acc->lbuff), acc->io);
52     return ASYNC_NEED_MORE;
53 }
54 
55 AsyncStatus
asyncConsoleConnector_connect(AsyncConsoleConnector * acc,const SockAddress * address,LoopIo * io)56 asyncConsoleConnector_connect(AsyncConsoleConnector* acc,
57                               const SockAddress*     address,
58                               LoopIo*                io)
59 {
60     acc->state = STATE_INITIAL;
61     acc->address = address[0];
62     acc->io = io;
63     return asyncConsoleConnector_run(acc);
64 }
65 
66 
67 AsyncStatus
asyncConsoleConnector_run(AsyncConsoleConnector * acc)68 asyncConsoleConnector_run(AsyncConsoleConnector* acc)
69 {
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;
81             status = asyncConnector_init(acc->connector, &acc->address, acc->io);
82             if (status == ASYNC_ERROR)
83                 goto SET_ERROR;
84 
85             if (status == ASYNC_COMPLETE) { /* immediate connection */
86                 _acc_prepareLineReader(acc, STATE_READ_BANNER_1);
87                 continue;
88             }
89             break;
90 
91         case STATE_CONNECTING: /* still trying to connect */
92             status = asyncConnector_run(acc->connector);
93             if (status == ASYNC_ERROR)
94                 goto SET_ERROR;
95 
96             if (status == ASYNC_COMPLETE) {
97                 _acc_prepareLineReader(acc, STATE_READ_BANNER_1);
98                 continue;
99             }
100             break;
101 
102         case STATE_READ_BANNER_1: /* reading the first banner line */
103             status = asyncLineReader_read(acc->lreader);
104             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 */
115                 _acc_prepareLineReader(acc, STATE_READ_BANNER_2);
116                 continue;
117             }
118             break;
119 
120         case STATE_READ_BANNER_2: /* reading the second banner line */
121             status = asyncLineReader_read(acc->lreader);
122             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     }
141 BAD_BANNER:
142     errno = ENOPROTOOPT;
143 SET_ERROR:
144     acc->state = STATE_ERROR;
145     acc->error = errno;
146     return ASYNC_ERROR;
147 }
148