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*
msg_alloc(const char * data,int datalen)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
msg_free(Msg * msg)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
emulatorConsole_eatInput(EmulatorConsole * con)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
emulatorConsole_sendOutput(EmulatorConsole * con)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
emulatorConsole_completeConnect(EmulatorConsole * con)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
emulatorConsole_retry(EmulatorConsole * con)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
emulatorConsole_connect(EmulatorConsole * con)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
emulatorConsole_reset(EmulatorConsole * con)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*
emulatorConsole_new(int port,IoLooper * looper)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
emulatorConsole_poll(EmulatorConsole * con)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
emulatorConsole_send(EmulatorConsole * con,const char * command)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
emulatorConsole_sendMouseDown(EmulatorConsole * con,int x,int y)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
emulatorConsole_sendMouseMotion(EmulatorConsole * con,int x,int y)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
emulatorConsole_sendMouseUp(EmulatorConsole * con,int x,int y)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
emulatorConsole_sendKey(EmulatorConsole * con,int keycode,int down)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