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