1 /* 2 * Copyright (C) 2011 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 "emulator-console.h" 17 #include "sockets.h" 18 #include <stdlib.h> 19 #include <stdio.h> 20 #include <string.h> 21 22 #define DEBUG 0 23 #if DEBUG >= 1 24 # define D(...) printf(__VA_ARGS__), printf("\n") 25 #else 26 # define D(...) ((void)0) 27 #endif 28 #if DEBUG >= 2 29 # define DD(...) printf(__VA_ARGS__), printf("\n") 30 #else 31 # define DD(...) ((void)0) 32 #endif 33 34 #define ANEW0(p) (p) = calloc(sizeof(*(p)), 1) 35 36 enum { 37 STATE_CONNECTING = 0, 38 STATE_CONNECTED, 39 STATE_WAITING, 40 STATE_ERROR = 2 41 }; 42 43 typedef struct Msg { 44 const char* data; // pointer to data 45 int size; // size of data 46 int sent; // already sent (so sent..size remain in buffer). 47 struct Msg* next; // next message in queue. 48 } Msg; 49 50 static Msg* 51 msg_alloc( const char* data, int datalen ) 52 { 53 Msg* msg; 54 55 msg = malloc(sizeof(*msg) + datalen); 56 msg->data = (const char*)(msg + 1); 57 msg->size = datalen; 58 msg->sent = 0; 59 memcpy((char*)msg->data, data, datalen); 60 msg->next = NULL; 61 62 return msg; 63 } 64 65 static void 66 msg_free( Msg* msg ) 67 { 68 free(msg); 69 } 70 71 struct EmulatorConsole { 72 int fd; 73 IoLooper* looper; 74 int state; 75 Msg* out_msg; 76 SockAddress address; 77 int64_t waitUntil; 78 }; 79 80 /* Read as much from the input as possible, ignoring it. 81 */ 82 static int 83 emulatorConsole_eatInput( EmulatorConsole* con ) 84 { 85 for (;;) { 86 char temp[64]; 87 int ret = socket_recv(con->fd, temp, sizeof temp); 88 if (ret < 0) { 89 if (errno == EAGAIN || errno == EWOULDBLOCK) { 90 return 0; 91 } 92 return -1; 93 } 94 if (ret == 0) { 95 return -1; 96 } 97 DD("Console received: '%.*s'", ret, temp); 98 } 99 } 100 101 static int 102 emulatorConsole_sendOutput( EmulatorConsole* con ) 103 { 104 if (con->state != STATE_CONNECTED) { 105 errno = EINVAL; 106 return -1; 107 } 108 109 while (con->out_msg != NULL) { 110 Msg* msg = con->out_msg; 111 int ret; 112 113 ret = socket_send(con->fd, 114 msg->data + msg->sent, 115 msg->size - msg->sent); 116 if (ret > 0) { 117 DD("Console sent: '%.*s'", ret, msg->data + msg->sent); 118 119 msg->sent += ret; 120 if (msg->sent == msg->size) { 121 con->out_msg = msg->next; 122 msg_free(msg); 123 } 124 continue; 125 } 126 if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { 127 return 0; 128 } 129 con->state = STATE_ERROR; 130 D("Console error when sending: %s", strerror(errno)); 131 return -1; 132 } 133 iolooper_del_write(con->looper, con->fd); 134 return 0; 135 } 136 137 static void 138 emulatorConsole_completeConnect(EmulatorConsole* con) 139 { 140 D("Console connected!"); 141 iolooper_add_read(con->looper, con->fd); 142 iolooper_del_write(con->looper, con->fd); 143 con->state = STATE_CONNECTED; 144 if (con->out_msg != NULL) { 145 iolooper_add_write(con->looper, con->fd); 146 emulatorConsole_sendOutput(con); 147 } 148 } 149 150 static void 151 emulatorConsole_retry(EmulatorConsole* con) 152 { 153 /* Not possible yet, wait one second */ 154 D("Could not connect to emulator, waiting 1 second: %s", errno_str); 155 con->state = STATE_WAITING; 156 con->waitUntil = iolooper_now() + 5000; 157 } 158 159 static void 160 emulatorConsole_connect(EmulatorConsole* con) 161 { 162 D("Trying to connect!"); 163 if (con->fd < 0) { 164 con->fd = socket_create_inet( SOCKET_STREAM ); 165 if (con->fd < 0) { 166 D("ERROR: Could not create socket: %s", errno_str); 167 con->state = STATE_ERROR; 168 return; 169 } 170 socket_set_nonblock(con->fd); 171 } 172 con->state = STATE_CONNECTING; 173 if (socket_connect(con->fd, &con->address) < 0) { 174 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { 175 iolooper_add_write(con->looper, con->fd); 176 } else { 177 emulatorConsole_retry(con); 178 } 179 return; 180 } 181 182 emulatorConsole_completeConnect(con); 183 } 184 185 static void 186 emulatorConsole_reset( EmulatorConsole* con ) 187 { 188 D("Resetting console connection"); 189 while (con->out_msg) { 190 Msg* msg = con->out_msg; 191 con->out_msg = msg->next; 192 msg_free(msg); 193 } 194 iolooper_del_read(con->looper, con->fd); 195 iolooper_del_write(con->looper, con->fd); 196 socket_close(con->fd); 197 con->fd = -1; 198 emulatorConsole_connect(con); 199 } 200 201 /* Create a new EmulatorConsole object to connect asynchronously to 202 * a given emulator port. Note that this should always succeeds since 203 * the connection is asynchronous. 204 */ 205 EmulatorConsole* 206 emulatorConsole_new(int port, IoLooper* looper) 207 { 208 EmulatorConsole* con; 209 SockAddress addr; 210 211 ANEW0(con); 212 con->looper = looper; 213 con->fd = -1; 214 sock_address_init_inet(&con->address, SOCK_ADDRESS_INET_LOOPBACK, port); 215 216 emulatorConsole_connect(con); 217 return con; 218 } 219 220 int 221 emulatorConsole_poll( EmulatorConsole* con ) 222 { 223 int ret; 224 225 if (con->state == STATE_WAITING) { 226 if (iolooper_now() >= con->waitUntil) 227 emulatorConsole_connect(con); 228 return 0; 229 } 230 231 if (!iolooper_is_read(con->looper, con->fd) && 232 !iolooper_is_write(con->looper, con->fd)) 233 { 234 return 0; 235 } 236 237 LOOP: 238 switch (con->state) { 239 case STATE_ERROR: 240 return -1; 241 242 case STATE_CONNECTING: 243 // read socket error to determine success / error. 244 if (socket_get_error(con->fd) != 0) { 245 emulatorConsole_retry(con); 246 } else { 247 emulatorConsole_completeConnect(con); 248 } 249 return 0; 250 251 case STATE_CONNECTED: 252 /* ignore input, if any */ 253 if (iolooper_is_read(con->looper, con->fd)) { 254 if (emulatorConsole_eatInput(con) < 0) { 255 goto SET_ERROR; 256 } 257 } 258 /* send outgoing data, if any */ 259 if (iolooper_is_write(con->looper, con->fd)) { 260 if (emulatorConsole_sendOutput(con) < 0) { 261 goto SET_ERROR; 262 } 263 } 264 return 0; 265 266 default: 267 D("UNSUPPORTED STATE!"); 268 break; 269 } 270 271 SET_ERROR: 272 D("Console ERROR!: %s\n", errno_str); 273 con->state = STATE_ERROR; 274 emulatorConsole_reset(con); 275 return -1; 276 } 277 278 /* Send a message to the console asynchronously. Any answer will be 279 * ignored. */ 280 void 281 emulatorConsole_send( EmulatorConsole* con, const char* command ) 282 { 283 int cmdlen = strlen(command); 284 Msg* msg; 285 Msg** plast; 286 287 if (cmdlen == 0) 288 return; 289 290 /* Append new message at end of outgoing list */ 291 msg = msg_alloc(command, cmdlen); 292 plast = &con->out_msg; 293 while (*plast) { 294 plast = &(*plast)->next; 295 } 296 *plast = msg; 297 if (con->out_msg == msg) { 298 iolooper_add_write(con->looper, con->fd); 299 } 300 emulatorConsole_sendOutput(con); 301 } 302 303 304 void 305 emulatorConsole_sendMouseDown( EmulatorConsole* con, int x, int y ) 306 { 307 char temp[128]; 308 309 D("sendMouseDown(%d,%d)", x, y); 310 snprintf(temp, sizeof temp, 311 "event send 3:0:%d 3:1:%d 1:330:1 0:0:0\r\n", 312 x, y); 313 emulatorConsole_send(con, temp); 314 } 315 316 void 317 emulatorConsole_sendMouseMotion( EmulatorConsole* con, int x, int y ) 318 { 319 /* Same as mouse down */ 320 emulatorConsole_sendMouseDown(con, x, y); 321 } 322 323 void 324 emulatorConsole_sendMouseUp( EmulatorConsole* con, int x, int y ) 325 { 326 char temp[128]; 327 328 D("sendMouseUp(%d,%d)", x, y); 329 snprintf(temp, sizeof temp, 330 "event send 3:0:%d 3:1:%d 1:330:0 0:0:0\r\n", 331 x, y); 332 emulatorConsole_send(con, temp); 333 } 334 335 #define EE(x,y) if (keycode == x) return y; 336 337 void 338 emulatorConsole_sendKey( EmulatorConsole* con, int keycode, int down ) 339 { 340 char temp[128]; 341 342 snprintf(temp, sizeof temp, 343 "event send EV_KEY:%d:%d 0:0:0\r\n", keycode, down); 344 emulatorConsole_send(con, temp); 345 } 346