Home | History | Annotate | Download | only in android
      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
     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
     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
     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