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