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