1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12 /*
13 * Android emulator control console
14 *
15 * this console is enabled automatically at emulator startup, on port 5554 by default,
16 * unless some other emulator is already running. See (android_emulation_start in android_sdl.c
17 * for details)
18 *
19 * you can telnet to the console, then use commands like 'help' or others to dynamically
20 * change emulator settings.
21 *
22 */
23
24 #include "sockets.h"
25 #include "qemu-char.h"
26 #include "sysemu.h"
27 #include "android/android.h"
28 #include "sockets.h"
29 #include "cpu.h"
30 #include "hw/goldfish_device.h"
31 #include "hw/power_supply.h"
32 #include "shaper.h"
33 #include "modem_driver.h"
34 #include "android/gps.h"
35 #include "android/globals.h"
36 #include "android/utils/bufprint.h"
37 #include "android/utils/debug.h"
38 #include "android/utils/stralloc.h"
39 #include "tcpdump.h"
40 #include "net.h"
41
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include "android/hw-events.h"
49 #include "android/skin/keyboard.h"
50
51 #if defined(CONFIG_SLIRP)
52 #include "libslirp.h"
53 #endif
54
55 /* set to 1 to use the i/o and event functions
56 * defined in "telephony/sysdeps.h"
57 */
58 #define USE_SYSDEPS 0
59
60 #include "sysdeps.h"
61
62 #define DEBUG 1
63
64 #if 1
65 # define D_ACTIVE VERBOSE_CHECK(console)
66 #else
67 # define D_ACTIVE DEBUG
68 #endif
69
70 #if DEBUG
71 # define D(x) do { if (D_ACTIVE) ( printf x , fflush(stdout) ); } while (0)
72 #else
73 # define D(x) do{}while(0)
74 #endif
75
76 typedef struct ControlGlobalRec_* ControlGlobal;
77
78 typedef struct ControlClientRec_* ControlClient;
79
80 typedef struct {
81 int host_port;
82 int host_udp;
83 unsigned int guest_ip;
84 int guest_port;
85 } RedirRec, *Redir;
86
87
88 #if USE_SYSDEPS
89 typedef SysChannel Socket;
90 #else /* !USE_SYSDEPS */
91 typedef int Socket;
92 #endif /* !USE_SYSDEPS */
93
94
95 typedef struct ControlClientRec_
96 {
97 struct ControlClientRec_* next; /* next client in list */
98 Socket sock; /* socket used for communication */
99 ControlGlobal global;
100 char finished;
101 char buff[ 4096 ];
102 int buff_len;
103
104 } ControlClientRec;
105
106
107 typedef struct ControlGlobalRec_
108 {
109 /* listening socket */
110 Socket listen_fd;
111
112 /* the list of current clients */
113 ControlClient clients;
114
115 /* the list of redirections currently active */
116 Redir redirs;
117 int num_redirs;
118 int max_redirs;
119
120 } ControlGlobalRec;
121
122
123 static int
control_global_add_redir(ControlGlobal global,int host_port,int host_udp,unsigned int guest_ip,int guest_port)124 control_global_add_redir( ControlGlobal global,
125 int host_port,
126 int host_udp,
127 unsigned int guest_ip,
128 int guest_port )
129 {
130 Redir redir;
131
132 if (global->num_redirs >= global->max_redirs)
133 {
134 int old_max = global->max_redirs;
135 int new_max = old_max + (old_max >> 1) + 4;
136
137 Redir new_redirs = realloc( global->redirs, new_max*sizeof(global->redirs[0]) );
138 if (new_redirs == NULL)
139 return -1;
140
141 global->redirs = new_redirs;
142 global->max_redirs = new_max;
143 }
144
145 redir = &global->redirs[ global->num_redirs++ ];
146
147 redir->host_port = host_port;
148 redir->host_udp = host_udp;
149 redir->guest_ip = guest_ip;
150 redir->guest_port = guest_port;
151
152 return 0;
153 }
154
155 static int
control_global_del_redir(ControlGlobal global,int host_port,int host_udp)156 control_global_del_redir( ControlGlobal global,
157 int host_port,
158 int host_udp )
159 {
160 int nn;
161
162 for (nn = 0; nn < global->num_redirs; nn++)
163 {
164 Redir redir = &global->redirs[nn];
165
166 if ( redir->host_port == host_port &&
167 redir->host_udp == host_udp )
168 {
169 memmove( redir, redir + 1, ((global->num_redirs - nn)-1)*sizeof(*redir) );
170 global->num_redirs -= 1;
171 return 0;
172 }
173 }
174 /* we didn't find it */
175 return -1;
176 }
177
178 static void
control_client_destroy(ControlClient client)179 control_client_destroy( ControlClient client )
180 {
181 ControlGlobal global = client->global;
182 ControlClient *pnode = &global->clients;
183
184 D(( "destroying control client %p\n", client ));
185
186 #if USE_SYSDEPS
187 sys_channel_on( client->sock, 0, NULL, NULL );
188 #else
189 qemu_set_fd_handler( client->sock, NULL, NULL, NULL );
190 #endif
191
192 for ( ;; ) {
193 ControlClient node = *pnode;
194 if ( node == NULL )
195 break;
196 if ( node == client ) {
197 *pnode = node->next;
198 node->next = NULL;
199 break;
200 }
201 pnode = &node->next;
202 }
203
204 #if USE_SYSDEPS
205 sys_channel_close( client->sock );
206 client->sock = NULL;
207 #else
208 socket_close( client->sock );
209 client->sock = -1;
210 #endif
211
212 free( client );
213 }
214
215 static void control_client_read( void* _client ); /* forward */
216
217
control_control_write(ControlClient client,const char * buff,int len)218 static void control_control_write( ControlClient client, const char* buff, int len )
219 {
220 int ret;
221
222 if (len < 0)
223 len = strlen(buff);
224
225 while (len > 0) {
226 #if USE_SYSDEPS
227 ret = sys_channel_write( client->sock, buff, len );
228 #else
229 ret = socket_send( client->sock, buff, len);
230 #endif
231 if (ret < 0) {
232 if (errno != EINTR && errno != EWOULDBLOCK)
233 return;
234 } else {
235 buff += ret;
236 len -= ret;
237 }
238 }
239 }
240
control_write(ControlClient client,const char * format,...)241 static void control_write( ControlClient client, const char* format, ... )
242 {
243 static char temp[1024];
244 va_list args;
245
246 va_start(args, format);
247 vsnprintf( temp, sizeof(temp), format, args );
248 va_end(args);
249
250 temp[ sizeof(temp)-1 ] = 0;
251
252 control_control_write( client, temp, -1 );
253 }
254
255
256 static ControlClient
control_client_create(Socket socket,ControlGlobal global)257 control_client_create( Socket socket,
258 ControlGlobal global )
259 {
260 ControlClient client = calloc( sizeof(*client), 1 );
261
262 if (client) {
263 #if !USE_SYSDEPS
264 socket_set_nodelay( socket );
265 socket_set_nonblock( socket );
266 #endif
267 client->finished = 0;
268 client->global = global;
269 client->sock = socket;
270 client->next = global->clients;
271 global->clients = client;
272
273 #if USE_SYSDEPS
274 sys_channel_on( socket, SYS_EVENT_READ,
275 (SysChannelCallback) control_client_read,
276 client );
277 #else
278 qemu_set_fd_handler( socket, control_client_read, NULL, client );
279 #endif
280 }
281 return client;
282 }
283
284 typedef const struct CommandDefRec_ *CommandDef;
285
286 typedef struct CommandDefRec_ {
287 const char* names;
288 const char* abstract;
289 const char* description;
290 void (*descriptor)( ControlClient client );
291 int (*handler)( ControlClient client, char* args );
292 CommandDef subcommands; /* if handler is NULL */
293
294 } CommandDefRec;
295
296 static const CommandDefRec main_commands[]; /* forward */
297
298 static CommandDef
find_command(char * input,CommandDef commands,char ** pend,char ** pargs)299 find_command( char* input, CommandDef commands, char* *pend, char* *pargs )
300 {
301 int nn;
302 char* args = strchr(input, ' ');
303
304 if (args != NULL) {
305 while (*args == ' ')
306 args++;
307
308 if (args[0] == 0)
309 args = NULL;
310 }
311
312 for (nn = 0; commands[nn].names != NULL; nn++)
313 {
314 const char* name = commands[nn].names;
315 const char* sep;
316
317 do {
318 int len, c;
319
320 sep = strchr( name, '|' );
321 if (sep)
322 len = sep - name;
323 else
324 len = strlen(name);
325
326 c = input[len];
327 if ( !memcmp( name, input, len ) && (c == ' ' || c == 0) ) {
328 *pend = input + len;
329 *pargs = args;
330 return &commands[nn];
331 }
332
333 if (sep)
334 name = sep + 1;
335
336 } while (sep != NULL && *name);
337 }
338 /* NOTE: don't touch *pend and *pargs if no command is found */
339 return NULL;
340 }
341
342 static void
dump_help(ControlClient client,CommandDef cmd,const char * prefix)343 dump_help( ControlClient client,
344 CommandDef cmd,
345 const char* prefix )
346 {
347 if (cmd->description) {
348 control_write( client, "%s", cmd->description );
349 } else if (cmd->descriptor) {
350 cmd->descriptor( client );
351 } else
352 control_write( client, "%s\r\n", cmd->abstract );
353
354 if (cmd->subcommands) {
355 cmd = cmd->subcommands;
356 control_write( client, "\r\navailable sub-commands:\r\n" );
357 for ( ; cmd->names != NULL; cmd++ ) {
358 control_write( client, " %s %-15s %s\r\n", prefix, cmd->names, cmd->abstract );
359 }
360 control_write( client, "\r\n" );
361 }
362 }
363
364 static void
control_client_do_command(ControlClient client)365 control_client_do_command( ControlClient client )
366 {
367 char* line = client->buff;
368 char* args = NULL;
369 CommandDef commands = main_commands;
370 char* cmdend = client->buff;
371 CommandDef cmd = find_command( line, commands, &cmdend, &args );
372
373 if (cmd == NULL) {
374 control_write( client, "KO: unknown command, try 'help'\r\n" );
375 return;
376 }
377
378 for (;;) {
379 CommandDef subcmd;
380
381 if (cmd->handler) {
382 if ( !cmd->handler( client, args ) )
383 control_write( client, "OK\r\n" );
384 break;
385 }
386
387 /* no handler means we should have sub-commands */
388 if (cmd->subcommands == NULL) {
389 control_write( client, "KO: internal error: buggy command table for '%.*s'\r\n",
390 cmdend - client->buff, client->buff );
391 break;
392 }
393
394 /* we need a sub-command here */
395 if ( !args ) {
396 dump_help( client, cmd, "" );
397 control_write( client, "KO: missing sub-command\r\n" );
398 break;
399 }
400
401 line = args;
402 commands = cmd->subcommands;
403 subcmd = find_command( line, commands, &cmdend, &args );
404 if (subcmd == NULL) {
405 dump_help( client, cmd, "" );
406 control_write( client, "KO: bad sub-command\r\n" );
407 break;
408 }
409 cmd = subcmd;
410 }
411 }
412
413 /* implement the 'help' command */
414 static int
do_help(ControlClient client,char * args)415 do_help( ControlClient client, char* args )
416 {
417 char* line;
418 char* start = args;
419 char* end = start;
420 CommandDef cmd = main_commands;
421
422 /* without arguments, simply dump all commands */
423 if (args == NULL) {
424 control_write( client, "Android console command help:\r\n\r\n" );
425 for ( ; cmd->names != NULL; cmd++ ) {
426 control_write( client, " %-15s %s\r\n", cmd->names, cmd->abstract );
427 }
428 control_write( client, "\r\ntry 'help <command>' for command-specific help\r\n" );
429 return 0;
430 }
431
432 /* with an argument, find the corresponding command */
433 for (;;) {
434 CommandDef subcmd;
435
436 line = args;
437 subcmd = find_command( line, cmd, &end, &args );
438 if (subcmd == NULL) {
439 control_write( client, "try one of these instead:\r\n\r\n" );
440 for ( ; cmd->names != NULL; cmd++ ) {
441 control_write( client, " %.*s %s\r\n",
442 end - start, start, cmd->names );
443 }
444 control_write( client, "\r\nKO: unknown command\r\n" );
445 return -1;
446 }
447
448 if ( !args || !subcmd->subcommands ) {
449 dump_help( client, subcmd, start );
450 return 0;
451 }
452 cmd = subcmd->subcommands;
453 }
454 }
455
456
457 static void
control_client_read_byte(ControlClient client,unsigned char ch)458 control_client_read_byte( ControlClient client, unsigned char ch )
459 {
460 if (ch == '\r')
461 {
462 /* filter them out */
463 }
464 else if (ch == '\n')
465 {
466 client->buff[ client->buff_len ] = 0;
467 control_client_do_command( client );
468 if (client->finished)
469 return;
470
471 client->buff_len = 0;
472 }
473 else
474 {
475 if (client->buff_len >= sizeof(client->buff)-1)
476 client->buff_len = 0;
477
478 client->buff[ client->buff_len++ ] = ch;
479 }
480 }
481
482 static void
control_client_read(void * _client)483 control_client_read( void* _client )
484 {
485 ControlClient client = _client;
486 unsigned char buf[4096];
487 int size;
488
489 D(( "in control_client read: " ));
490 #if USE_SYSDEPS
491 size = sys_channel_read( client->sock, buf, sizeof(buf) );
492 #else
493 size = socket_recv( client->sock, buf, sizeof(buf) );
494 #endif
495 if (size < 0) {
496 D(( "size < 0, exiting with %d: %s\n", errno, errno_str ));
497 if (errno != EWOULDBLOCK && errno != EINTR)
498 control_client_destroy( client );
499 return;
500 }
501
502 if (size == 0) {
503 /* end of connection */
504 D(( "end of connection detected !!\n" ));
505 control_client_destroy( client );
506 }
507 else {
508 int nn;
509 #ifdef _WIN32
510 # if DEBUG
511 char temp[16];
512 int count = size > sizeof(temp)-1 ? sizeof(temp)-1 : size;
513 for (nn = 0; nn < count; nn++) {
514 int c = buf[nn];
515 if (c == '\n')
516 temp[nn] = '!';
517 else if (c < 32)
518 temp[nn] = '.';
519 else
520 temp[nn] = (char)c;
521 }
522 temp[nn] = 0;
523 D(( "received %d bytes: %s\n", size, temp ));
524 # endif
525 #else
526 D(( "received %.*s\n", size, buf ));
527 #endif
528 for (nn = 0; nn < size; nn++) {
529 control_client_read_byte( client, buf[nn] );
530 if (client->finished) {
531 control_client_destroy(client);
532 return;
533 }
534 }
535 }
536 }
537
538
539 /* this function is called on each new client connection */
540 static void
control_global_accept(void * _global)541 control_global_accept( void* _global )
542 {
543 ControlGlobal global = _global;
544 ControlClient client;
545 Socket fd;
546
547 D(( "control_global_accept: just in (fd=%p)\n", (void*)global->listen_fd ));
548
549 #if USE_SYSDEPS
550 fd = sys_channel_create_tcp_handler( global->listen_fd );
551 if (fd == NULL) {
552 perror("accept");
553 return;
554 }
555 #else
556 for(;;) {
557 fd = socket_accept( global->listen_fd, NULL );
558 if (fd < 0 && errno != EINTR) {
559 D(( "problem in accept: %d: %s\n", errno, errno_str ));
560 perror("accept");
561 return;
562 } else if (fd >= 0) {
563 break;
564 }
565 D(( "relooping in accept()\n" ));
566 }
567
568 socket_set_xreuseaddr( fd );
569 #endif
570
571 D(( "control_global_accept: creating new client\n" ));
572 client = control_client_create( fd, global );
573 if (client) {
574 D(( "control_global_accept: new client %p\n", client ));
575 control_write( client, "Android Console: type 'help' for a list of commands\r\n" );
576 control_write( client, "OK\r\n" );
577 }
578 }
579
580
581 static int
control_global_init(ControlGlobal global,int control_port)582 control_global_init( ControlGlobal global,
583 int control_port )
584 {
585 Socket fd;
586 #if !USE_SYSDEPS
587 int ret;
588 SockAddress sockaddr;
589 #endif
590
591 memset( global, 0, sizeof(*global) );
592
593 sys_main_init();
594
595 #if USE_SYSDEPS
596 fd = sys_channel_create_tcp_server( control_port );
597 if (fd == NULL) {
598 return -1;
599 }
600
601 D(("global fd=%p\n", fd));
602
603 global->listen_fd = fd;
604 sys_channel_on( fd, SYS_EVENT_READ,
605 (SysChannelCallback) control_global_accept,
606 global );
607 #else
608 fd = socket_create_inet( SOCKET_STREAM );
609 if (fd < 0) {
610 perror("socket");
611 return -1;
612 }
613
614 socket_set_xreuseaddr( fd );
615
616 sock_address_init_inet( &sockaddr, SOCK_ADDRESS_INET_LOOPBACK, control_port );
617
618 ret = socket_bind(fd, &sockaddr );
619 if (ret < 0) {
620 perror("bind");
621 socket_close( fd );
622 return -1;
623 }
624
625 ret = socket_listen(fd, 0);
626 if (ret < 0) {
627 perror("listen");
628 socket_close( fd );
629 return -1;
630 }
631
632 socket_set_nonblock(fd);
633
634 global->listen_fd = fd;
635
636 qemu_set_fd_handler( fd, control_global_accept, NULL, global );
637 #endif
638 return 0;
639 }
640
641
642
643 static int
do_quit(ControlClient client,char * args)644 do_quit( ControlClient client, char* args )
645 {
646 client->finished = 1;
647 return -1;
648 }
649
650 /********************************************************************************************/
651 /********************************************************************************************/
652 /***** ******/
653 /***** N E T W O R K S E T T I N G S ******/
654 /***** ******/
655 /********************************************************************************************/
656 /********************************************************************************************/
657
658 static int
do_network_status(ControlClient client,char * args)659 do_network_status( ControlClient client, char* args )
660 {
661 control_write( client, "Current network status:\r\n" );
662
663 control_write( client, " download speed: %8d bits/s (%.1f KB/s)\r\n",
664 (long)qemu_net_download_speed, qemu_net_download_speed/8192. );
665
666 control_write( client, " upload speed: %8d bits/s (%.1f KB/s)\r\n",
667 (long)qemu_net_upload_speed, qemu_net_upload_speed/8192. );
668
669 control_write( client, " minimum latency: %ld ms\r\n", qemu_net_min_latency );
670 control_write( client, " maximum latency: %ld ms\r\n", qemu_net_max_latency );
671 return 0;
672 }
673
674 static void
dump_network_speeds(ControlClient client)675 dump_network_speeds( ControlClient client )
676 {
677 const NetworkSpeed* speed = android_netspeeds;
678 const char* const format = " %-8s %s\r\n";
679 for ( ; speed->name; speed++ ) {
680 control_write( client, format, speed->name, speed->display );
681 }
682 control_write( client, format, "<num>", "selects both upload and download speed" );
683 control_write( client, format, "<up>:<down>", "select individual upload/download speeds" );
684 }
685
686
687 static int
do_network_speed(ControlClient client,char * args)688 do_network_speed( ControlClient client, char* args )
689 {
690 if ( !args ) {
691 control_write( client, "KO: missing <speed> argument, see 'help network speed'\r\n" );
692 return -1;
693 }
694 if ( android_parse_network_speed( args ) < 0 ) {
695 control_write( client, "KO: invalid <speed> argument, see 'help network speed' for valid values\r\n" );
696 return -1;
697 }
698
699 netshaper_set_rate( slirp_shaper_in, qemu_net_download_speed );
700 netshaper_set_rate( slirp_shaper_out, qemu_net_upload_speed );
701
702 if (android_modem) {
703 amodem_set_data_network_type( android_modem,
704 android_parse_network_type( args ) );
705 }
706 return 0;
707 }
708
709 static void
describe_network_speed(ControlClient client)710 describe_network_speed( ControlClient client )
711 {
712 control_write( client,
713 "'network speed <speed>' allows you to dynamically change the speed of the emulated\r\n"
714 "network on the device, where <speed> is one of the following:\r\n\r\n" );
715 dump_network_speeds( client );
716 }
717
718 static int
do_network_delay(ControlClient client,char * args)719 do_network_delay( ControlClient client, char* args )
720 {
721 if ( !args ) {
722 control_write( client, "KO: missing <delay> argument, see 'help network delay'\r\n" );
723 return -1;
724 }
725 if ( android_parse_network_latency( args ) < 0 ) {
726 control_write( client, "KO: invalid <delay> argument, see 'help network delay' for valid values\r\n" );
727 return -1;
728 }
729 netdelay_set_latency( slirp_delay_in, qemu_net_min_latency, qemu_net_max_latency );
730 return 0;
731 }
732
733 static void
describe_network_delay(ControlClient client)734 describe_network_delay( ControlClient client )
735 {
736 control_write( client,
737 "'network delay <latency>' allows you to dynamically change the latency of the emulated\r\n"
738 "network on the device, where <latency> is one of the following:\r\n\r\n" );
739 /* XXX: TODO */
740 }
741
742 static int
do_network_capture_start(ControlClient client,char * args)743 do_network_capture_start( ControlClient client, char* args )
744 {
745 if ( !args ) {
746 control_write( client, "KO: missing <file> argument, see 'help network capture start'\r\n" );
747 return -1;
748 }
749 if ( qemu_tcpdump_start(args) < 0) {
750 control_write( client, "KO: could not start capture: %s", strerror(errno) );
751 return -1;
752 }
753 return 0;
754 }
755
756 static int
do_network_capture_stop(ControlClient client,char * args)757 do_network_capture_stop( ControlClient client, char* args )
758 {
759 /* no need to return an error here */
760 qemu_tcpdump_stop();
761 return 0;
762 }
763
764 static const CommandDefRec network_capture_commands[] =
765 {
766 { "start", "start network capture",
767 "'network capture start <file>' starts a new capture of network packets\r\n"
768 "into a specific <file>. This will stop any capture already in progress.\r\n"
769 "the capture file can later be analyzed by tools like WireShark. It uses\r\n"
770 "the libpcap file format.\r\n\r\n"
771 "you can stop the capture anytime with 'network capture stop'\r\n", NULL,
772 do_network_capture_start, NULL },
773
774 { "stop", "stop network capture",
775 "'network capture stop' stops a currently running packet capture, if any.\r\n"
776 "you can start one with 'network capture start <file>'\r\n", NULL,
777 do_network_capture_stop, NULL },
778
779 { NULL, NULL, NULL, NULL, NULL, NULL }
780 };
781
782 static const CommandDefRec network_commands[] =
783 {
784 { "status", "dump network status", NULL, NULL,
785 do_network_status, NULL },
786
787 { "speed", "change network speed", NULL, describe_network_speed,
788 do_network_speed, NULL },
789
790 { "delay", "change network latency", NULL, describe_network_delay,
791 do_network_delay, NULL },
792
793 { "capture", "dump network packets to file",
794 "allows to start/stop capture of network packets to a file for later analysis\r\n", NULL,
795 NULL, network_capture_commands },
796
797 { NULL, NULL, NULL, NULL, NULL, NULL }
798 };
799
800 /********************************************************************************************/
801 /********************************************************************************************/
802 /***** ******/
803 /***** P O R T R E D I R E C T I O N S ******/
804 /***** ******/
805 /********************************************************************************************/
806 /********************************************************************************************/
807
808 static int
do_redir_list(ControlClient client,char * args)809 do_redir_list( ControlClient client, char* args )
810 {
811 ControlGlobal global = client->global;
812
813 if (global->num_redirs == 0)
814 control_write( client, "no active redirections\r\n" );
815 else {
816 int nn;
817 for (nn = 0; nn < global->num_redirs; nn++) {
818 Redir redir = &global->redirs[nn];
819 control_write( client, "%s:%-5d => %-5d\r\n",
820 redir->host_udp ? "udp" : "tcp",
821 redir->host_port,
822 redir->guest_port );
823 }
824 }
825 return 0;
826 }
827
828 /* parse a protocol:port specification */
829 static int
redir_parse_proto_port(char * args,int * pport,int * pproto)830 redir_parse_proto_port( char* args, int *pport, int *pproto )
831 {
832 int proto = -1;
833 int len = 0;
834 char* end;
835
836 if ( !memcmp( args, "tcp:", 4 ) ) {
837 proto = 0;
838 len = 4;
839 }
840 else if ( !memcmp( args, "udp:", 4 ) ) {
841 proto = 1;
842 len = 4;
843 }
844 else
845 return 0;
846
847 args += len;
848 *pproto = proto;
849 *pport = strtol( args, &end, 10 );
850 if (end == args)
851 return 0;
852
853 len += end - args;
854 return len;
855 }
856
857 static int
redir_parse_guest_port(char * arg,int * pport)858 redir_parse_guest_port( char* arg, int *pport )
859 {
860 char* end;
861
862 *pport = strtoul( arg, &end, 10 );
863 if (end == arg)
864 return 0;
865
866 return end - arg;
867 }
868
869 static Redir
redir_find(ControlGlobal global,int port,int isudp)870 redir_find( ControlGlobal global, int port, int isudp )
871 {
872 int nn;
873
874 for (nn = 0; nn < global->num_redirs; nn++) {
875 Redir redir = &global->redirs[nn];
876
877 if (redir->host_port == port && redir->host_udp == isudp)
878 return redir;
879 }
880 return NULL;
881 }
882
883
884 static int
do_redir_add(ControlClient client,char * args)885 do_redir_add( ControlClient client, char* args )
886 {
887 int len, host_proto, host_port, guest_port;
888 uint32_t guest_ip;
889 Redir redir;
890
891 if ( !args )
892 goto BadFormat;
893
894 if (!slirp_is_inited()) {
895 control_write( client, "KO: network emulation disabled\r\n");
896 return -1;
897 }
898
899 len = redir_parse_proto_port( args, &host_port, &host_proto );
900 if (len == 0 || args[len] != ':')
901 goto BadFormat;
902
903 args += len + 1;
904 len = redir_parse_guest_port( args, &guest_port );
905 if (len == 0 || args[len] != 0)
906 goto BadFormat;
907
908 redir = redir_find( client->global, host_port, host_proto );
909 if ( redir != NULL ) {
910 control_write( client, "KO: host port already active, use 'redir del' to remove first\r\n" );
911 return -1;
912 }
913
914 if (inet_strtoip("10.0.2.15", &guest_ip) < 0) {
915 control_write( client, "KO: unexpected internal failure when resolving 10.0.2.15\r\n" );
916 return -1;
917 }
918
919 D(("pattern hport=%d gport=%d proto=%d\n", host_port, guest_port, host_proto ));
920 if ( control_global_add_redir( client->global, host_port, host_proto,
921 guest_ip, guest_port ) < 0 )
922 {
923 control_write( client, "KO: not enough memory to allocate redirection\r\n" );
924 return -1;
925 }
926
927 if (slirp_redir(host_proto, host_port, guest_ip, guest_port) < 0) {
928 control_write( client, "KO: can't setup redirection, port probably used by another program on host\r\n" );
929 control_global_del_redir( client->global, host_port, host_proto );
930 return -1;
931 }
932
933 return 0;
934
935 BadFormat:
936 control_write( client, "KO: bad redirection format, try (tcp|udp):hostport:guestport\r\n", -1 );
937 return -1;
938 }
939
940
941 static int
do_redir_del(ControlClient client,char * args)942 do_redir_del( ControlClient client, char* args )
943 {
944 int len, proto, port;
945 Redir redir;
946
947 if ( !args )
948 goto BadFormat;
949 len = redir_parse_proto_port( args, &port, &proto );
950 if ( len == 0 || args[len] != 0 )
951 goto BadFormat;
952
953 redir = redir_find( client->global, port, proto );
954 if (redir == NULL) {
955 control_write( client, "KO: can't remove unknown redirection (%s:%d)\r\n",
956 proto ? "udp" : "tcp", port );
957 return -1;
958 }
959
960 slirp_unredir( redir->host_udp, redir->host_port );
961 control_global_del_redir( client->global, port, proto );\
962
963 return 0;
964
965 BadFormat:
966 control_write( client, "KO: bad redirection format, try (tcp|udp):hostport\r\n" );
967 return -1;
968 }
969
970 static const CommandDefRec redir_commands[] =
971 {
972 { "list", "list current redirections",
973 "list current port redirections. use 'redir add' and 'redir del' to add and remove them\r\n", NULL,
974 do_redir_list, NULL },
975
976 { "add", "add new redirection",
977 "add a new port redirection, arguments must be:\r\n\r\n"
978 " redir add <protocol>:<host-port>:<guest-port>\r\n\r\n"
979 "where: <protocol> is either 'tcp' or 'udp'\r\n"
980 " <host-port> a number indicating which port on the host to open\r\n"
981 " <guest-port> a number indicating which port to route to on the device\r\n"
982 "\r\nas an example, 'redir tcp:5000:6000' will allow any packets sent to\r\n"
983 "the host's TCP port 5000 to be routed to TCP port 6000 of the emulated device\r\n", NULL,
984 do_redir_add, NULL },
985
986 { "del", "remove existing redirection",
987 "remove a port redirecion that was created with 'redir add', arguments must be:\r\n\r\n"
988 " redir del <protocol>:<host-port>\r\n\r\n"
989 "see the 'help redir add' for the meaning of <protocol> and <host-port>\r\n", NULL,
990 do_redir_del, NULL },
991
992 { NULL, NULL, NULL, NULL, NULL, NULL }
993 };
994
995
996
997 /********************************************************************************************/
998 /********************************************************************************************/
999 /***** ******/
1000 /***** G S M M O D E M ******/
1001 /***** ******/
1002 /********************************************************************************************/
1003 /********************************************************************************************/
1004
1005 static const struct {
1006 const char* name;
1007 const char* display;
1008 ARegistrationState state;
1009 } _gsm_states[] = {
1010 { "unregistered", "no network available", A_REGISTRATION_UNREGISTERED },
1011 { "home", "on local network, non-roaming", A_REGISTRATION_HOME },
1012 { "roaming", "on roaming network", A_REGISTRATION_ROAMING },
1013 { "searching", "searching networks", A_REGISTRATION_SEARCHING },
1014 { "denied", "emergency calls only", A_REGISTRATION_DENIED },
1015 { "off", "same as 'unregistered'", A_REGISTRATION_UNREGISTERED },
1016 { "on", "same as 'home'", A_REGISTRATION_HOME },
1017 { NULL, NULL, A_REGISTRATION_UNREGISTERED }
1018 };
1019
1020 static const char*
gsm_state_to_string(ARegistrationState state)1021 gsm_state_to_string( ARegistrationState state )
1022 {
1023 int nn;
1024 for (nn = 0; _gsm_states[nn].name != NULL; nn++) {
1025 if (state == _gsm_states[nn].state)
1026 return _gsm_states[nn].name;
1027 }
1028 return "<unknown>";
1029 }
1030
1031 static int
do_gsm_status(ControlClient client,char * args)1032 do_gsm_status( ControlClient client, char* args )
1033 {
1034 if (args) {
1035 control_write( client, "KO: no argument required\r\n" );
1036 return -1;
1037 }
1038 if (!android_modem) {
1039 control_write( client, "KO: modem emulation not running\r\n" );
1040 return -1;
1041 }
1042 control_write( client, "gsm voice state: %s\r\n",
1043 gsm_state_to_string(
1044 amodem_get_voice_registration(android_modem) ) );
1045 control_write( client, "gsm data state: %s\r\n",
1046 gsm_state_to_string(
1047 amodem_get_data_registration(android_modem) ) );
1048 return 0;
1049 }
1050
1051
1052 static void
help_gsm_data(ControlClient client)1053 help_gsm_data( ControlClient client )
1054 {
1055 int nn;
1056 control_write( client,
1057 "the 'gsm data <state>' allows you to change the state of your GPRS connection\r\n"
1058 "valid values for <state> are the following:\r\n\r\n" );
1059 for (nn = 0; ; nn++) {
1060 const char* name = _gsm_states[nn].name;
1061 const char* display = _gsm_states[nn].display;
1062
1063 if (!name)
1064 break;
1065
1066 control_write( client, " %-15s %s\r\n", name, display );
1067 }
1068 control_write( client, "\r\n" );
1069 }
1070
1071
1072 static int
do_gsm_data(ControlClient client,char * args)1073 do_gsm_data( ControlClient client, char* args )
1074 {
1075 int nn;
1076
1077 if (!args) {
1078 control_write( client, "KO: missing argument, try 'gsm data <state>'\r\n" );
1079 return -1;
1080 }
1081
1082 for (nn = 0; ; nn++) {
1083 const char* name = _gsm_states[nn].name;
1084 ARegistrationState state = _gsm_states[nn].state;
1085
1086 if (!name)
1087 break;
1088
1089 if ( !strcmp( args, name ) ) {
1090 if (!android_modem) {
1091 control_write( client, "KO: modem emulation not running\r\n" );
1092 return -1;
1093 }
1094 amodem_set_data_registration( android_modem, state );
1095 qemu_net_disable = (state != A_REGISTRATION_HOME &&
1096 state != A_REGISTRATION_ROAMING );
1097 return 0;
1098 }
1099 }
1100 control_write( client, "KO: bad GSM data state name, try 'help gsm data' for list of valid values\r\n" );
1101 return -1;
1102 }
1103
1104 static void
help_gsm_voice(ControlClient client)1105 help_gsm_voice( ControlClient client )
1106 {
1107 int nn;
1108 control_write( client,
1109 "the 'gsm voice <state>' allows you to change the state of your GPRS connection\r\n"
1110 "valid values for <state> are the following:\r\n\r\n" );
1111 for (nn = 0; ; nn++) {
1112 const char* name = _gsm_states[nn].name;
1113 const char* display = _gsm_states[nn].display;
1114
1115 if (!name)
1116 break;
1117
1118 control_write( client, " %-15s %s\r\n", name, display );
1119 }
1120 control_write( client, "\r\n" );
1121 }
1122
1123
1124 static int
do_gsm_voice(ControlClient client,char * args)1125 do_gsm_voice( ControlClient client, char* args )
1126 {
1127 int nn;
1128
1129 if (!args) {
1130 control_write( client, "KO: missing argument, try 'gsm voice <state>'\r\n" );
1131 return -1;
1132 }
1133
1134 for (nn = 0; ; nn++) {
1135 const char* name = _gsm_states[nn].name;
1136 ARegistrationState state = _gsm_states[nn].state;
1137
1138 if (!name)
1139 break;
1140
1141 if ( !strcmp( args, name ) ) {
1142 if (!android_modem) {
1143 control_write( client, "KO: modem emulation not running\r\n" );
1144 return -1;
1145 }
1146 amodem_set_voice_registration( android_modem, state );
1147 return 0;
1148 }
1149 }
1150 control_write( client, "KO: bad GSM data state name, try 'help gsm voice' for list of valid values\r\n" );
1151 return -1;
1152 }
1153
1154
1155 static int
gsm_check_number(char * args)1156 gsm_check_number( char* args )
1157 {
1158 int nn;
1159
1160 for (nn = 0; args[nn] != 0; nn++) {
1161 int c = args[nn];
1162 if ( !isdigit(c) && c != '+' && c != '#' ) {
1163 return -1;
1164 }
1165 }
1166 if (nn == 0)
1167 return -1;
1168
1169 return 0;
1170 }
1171
1172 static int
do_gsm_call(ControlClient client,char * args)1173 do_gsm_call( ControlClient client, char* args )
1174 {
1175 /* check that we have a phone number made of digits */
1176 if (!args) {
1177 control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" );
1178 return -1;
1179 }
1180
1181 if (gsm_check_number(args)) {
1182 control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" );
1183 return -1;
1184 }
1185
1186 if (!android_modem) {
1187 control_write( client, "KO: modem emulation not running\r\n" );
1188 return -1;
1189 }
1190 amodem_add_inbound_call( android_modem, args );
1191 return 0;
1192 }
1193
1194 static int
do_gsm_cancel(ControlClient client,char * args)1195 do_gsm_cancel( ControlClient client, char* args )
1196 {
1197 if (!args) {
1198 control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" );
1199 return -1;
1200 }
1201 if (gsm_check_number(args)) {
1202 control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" );
1203 return -1;
1204 }
1205 if (!android_modem) {
1206 control_write( client, "KO: modem emulation not running\r\n" );
1207 return -1;
1208 }
1209 if ( amodem_disconnect_call( android_modem, args ) < 0 ) {
1210 control_write( client, "KO: could not cancel this number\r\n" );
1211 return -1;
1212 }
1213 return 0;
1214 }
1215
1216
1217 static const char*
call_state_to_string(ACallState state)1218 call_state_to_string( ACallState state )
1219 {
1220 switch (state) {
1221 case A_CALL_ACTIVE: return "active";
1222 case A_CALL_HELD: return "held";
1223 case A_CALL_ALERTING: return "ringing";
1224 case A_CALL_WAITING: return "waiting";
1225 case A_CALL_INCOMING: return "incoming";
1226 default: return "unknown";
1227 }
1228 }
1229
1230 static int
do_gsm_list(ControlClient client,char * args)1231 do_gsm_list( ControlClient client, char* args )
1232 {
1233 /* check that we have a phone number made of digits */
1234 int count = amodem_get_call_count( android_modem );
1235 int nn;
1236 for (nn = 0; nn < count; nn++) {
1237 ACall call = amodem_get_call( android_modem, nn );
1238 const char* dir;
1239
1240 if (call == NULL)
1241 continue;
1242
1243 if (call->dir == A_CALL_OUTBOUND)
1244 dir = "outbound to ";
1245 else
1246 dir = "inbound from";
1247
1248 control_write( client, "%s %-10s : %s\r\n", dir,
1249 call->number, call_state_to_string(call->state) );
1250 }
1251 return 0;
1252 }
1253
1254 static int
do_gsm_busy(ControlClient client,char * args)1255 do_gsm_busy( ControlClient client, char* args )
1256 {
1257 ACall call;
1258
1259 if (!args) {
1260 control_write( client, "KO: missing argument, try 'gsm busy <phonenumber>'\r\n" );
1261 return -1;
1262 }
1263 call = amodem_find_call_by_number( android_modem, args );
1264 if (call == NULL || call->dir != A_CALL_OUTBOUND) {
1265 control_write( client, "KO: no current outbound call to number '%s' (call %p)\r\n", args, call );
1266 return -1;
1267 }
1268 if ( amodem_disconnect_call( android_modem, args ) < 0 ) {
1269 control_write( client, "KO: could not cancel this number\r\n" );
1270 return -1;
1271 }
1272 return 0;
1273 }
1274
1275 static int
do_gsm_hold(ControlClient client,char * args)1276 do_gsm_hold( ControlClient client, char* args )
1277 {
1278 ACall call;
1279
1280 if (!args) {
1281 control_write( client, "KO: missing argument, try 'gsm out hold <phonenumber>'\r\n" );
1282 return -1;
1283 }
1284 call = amodem_find_call_by_number( android_modem, args );
1285 if (call == NULL) {
1286 control_write( client, "KO: no current call to/from number '%s'\r\n", args );
1287 return -1;
1288 }
1289 if ( amodem_update_call( android_modem, args, A_CALL_HELD ) < 0 ) {
1290 control_write( client, "KO: could put this call on hold\r\n" );
1291 return -1;
1292 }
1293 return 0;
1294 }
1295
1296
1297 static int
do_gsm_accept(ControlClient client,char * args)1298 do_gsm_accept( ControlClient client, char* args )
1299 {
1300 ACall call;
1301
1302 if (!args) {
1303 control_write( client, "KO: missing argument, try 'gsm accept <phonenumber>'\r\n" );
1304 return -1;
1305 }
1306 call = amodem_find_call_by_number( android_modem, args );
1307 if (call == NULL) {
1308 control_write( client, "KO: no current call to/from number '%s'\r\n", args );
1309 return -1;
1310 }
1311 if ( amodem_update_call( android_modem, args, A_CALL_ACTIVE ) < 0 ) {
1312 control_write( client, "KO: could not activate this call\r\n" );
1313 return -1;
1314 }
1315 return 0;
1316 }
1317
1318
1319 #if 0
1320 static const CommandDefRec gsm_in_commands[] =
1321 {
1322 { "new", "create a new 'waiting' inbound call",
1323 "'gsm in create <phonenumber>' creates a new inbound phone call, placed in\r\n"
1324 "the 'waiting' state by default, until the system answers/holds/closes it\r\n", NULL
1325 do_gsm_in_create, NULL },
1326
1327 { "hold", "change the state of an oubtound call to 'held'",
1328 "change the state of an outbound call to 'held'. this is only possible\r\n"
1329 "if the call in the 'waiting' or 'active' state\r\n", NULL,
1330 do_gsm_out_hold, NULL },
1331
1332 { "accept", "change the state of an outbound call to 'active'",
1333 "change the state of an outbound call to 'active'. this is only possible\r\n"
1334 "if the call is in the 'waiting' or 'held' state\r\n", NULL,
1335 do_gsm_out_accept, NULL },
1336
1337 { NULL, NULL, NULL, NULL, NULL, NULL }
1338 };
1339 #endif
1340
1341
1342 static const CommandDefRec gsm_commands[] =
1343 {
1344 { "list", "list current phone calls",
1345 "'gsm list' lists all inbound and outbound calls and their state\r\n", NULL,
1346 do_gsm_list, NULL },
1347
1348 { "call", "create inbound phone call",
1349 "'gsm call <phonenumber>' allows you to simulate a new inbound call\r\n", NULL,
1350 do_gsm_call, NULL },
1351
1352 { "busy", "close waiting outbound call as busy",
1353 "'gsm busy <remoteNumber>' closes an outbound call, reporting\r\n"
1354 "the remote phone as busy. only possible if the call is 'waiting'.\r\n", NULL,
1355 do_gsm_busy, NULL },
1356
1357 { "hold", "change the state of an oubtound call to 'held'",
1358 "'gsm hold <remoteNumber>' change the state of a call to 'held'. this is only possible\r\n"
1359 "if the call in the 'waiting' or 'active' state\r\n", NULL,
1360 do_gsm_hold, NULL },
1361
1362 { "accept", "change the state of an outbound call to 'active'",
1363 "'gsm accept <remoteNumber>' change the state of a call to 'active'. this is only possible\r\n"
1364 "if the call is in the 'waiting' or 'held' state\r\n", NULL,
1365 do_gsm_accept, NULL },
1366
1367 { "cancel", "disconnect an inbound or outbound phone call",
1368 "'gsm cancel <phonenumber>' allows you to simulate the end of an inbound or outbound call\r\n", NULL,
1369 do_gsm_cancel, NULL },
1370
1371 { "data", "modify data connection state", NULL, help_gsm_data,
1372 do_gsm_data, NULL },
1373
1374 { "voice", "modify voice connection state", NULL, help_gsm_voice,
1375 do_gsm_voice, NULL },
1376
1377 { "status", "display GSM status",
1378 "'gsm status' displays the current state of the GSM emulation\r\n", NULL,
1379 do_gsm_status, NULL },
1380
1381 { NULL, NULL, NULL, NULL, NULL, NULL }
1382 };
1383
1384 /********************************************************************************************/
1385 /********************************************************************************************/
1386 /***** ******/
1387 /***** S M S C O M M A N D ******/
1388 /***** ******/
1389 /********************************************************************************************/
1390 /********************************************************************************************/
1391
1392 static int
do_sms_send(ControlClient client,char * args)1393 do_sms_send( ControlClient client, char* args )
1394 {
1395 char* p;
1396 int textlen;
1397 SmsAddressRec sender;
1398 SmsPDU* pdus;
1399 int nn;
1400
1401 /* check that we have a phone number made of digits */
1402 if (!args) {
1403 MissingArgument:
1404 control_write( client, "KO: missing argument, try 'sms send <phonenumber> <text message>'\r\n" );
1405 return -1;
1406 }
1407 p = strchr( args, ' ' );
1408 if (!p) {
1409 goto MissingArgument;
1410 }
1411
1412 if ( sms_address_from_str( &sender, args, p - args ) < 0 ) {
1413 control_write( client, "KO: bad phone number format, must be [+](0-9)*\r\n" );
1414 return -1;
1415 }
1416
1417
1418 /* un-secape message text into proper utf-8 (conversion happens in-site) */
1419 p += 1;
1420 textlen = strlen(p);
1421 textlen = sms_utf8_from_message_str( p, textlen, (unsigned char*)p, textlen );
1422 if (textlen < 0) {
1423 control_write( client, "message must be utf8 and can use the following escapes:\r\n"
1424 " \\n for a newline\r\n"
1425 " \\xNN where NN are two hexadecimal numbers\r\n"
1426 " \\uNNNN where NNNN are four hexadecimal numbers\r\n"
1427 " \\\\ to send a '\\' character\r\n\r\n"
1428 " anything else is an error\r\n"
1429 "KO: badly formatted text\r\n" );
1430 return -1;
1431 }
1432
1433 if (!android_modem) {
1434 control_write( client, "KO: modem emulation not running\r\n" );
1435 return -1;
1436 }
1437
1438 /* create a list of SMS PDUs, then send them */
1439 pdus = smspdu_create_deliver_utf8( (cbytes_t)p, textlen, &sender, NULL );
1440 if (pdus == NULL) {
1441 control_write( client, "KO: internal error when creating SMS-DELIVER PDUs\n" );
1442 return -1;
1443 }
1444
1445 for (nn = 0; pdus[nn] != NULL; nn++)
1446 amodem_receive_sms( android_modem, pdus[nn] );
1447
1448 smspdu_free_list( pdus );
1449 return 0;
1450 }
1451
1452 static int
do_sms_sendpdu(ControlClient client,char * args)1453 do_sms_sendpdu( ControlClient client, char* args )
1454 {
1455 SmsPDU pdu;
1456
1457 /* check that we have a phone number made of digits */
1458 if (!args) {
1459 control_write( client, "KO: missing argument, try 'sms sendpdu <hexstring>'\r\n" );
1460 return -1;
1461 }
1462
1463 if (!android_modem) {
1464 control_write( client, "KO: modem emulation not running\r\n" );
1465 return -1;
1466 }
1467
1468 pdu = smspdu_create_from_hex( args, strlen(args) );
1469 if (pdu == NULL) {
1470 control_write( client, "KO: badly formatted <hexstring>\r\n" );
1471 return -1;
1472 }
1473
1474 amodem_receive_sms( android_modem, pdu );
1475 smspdu_free( pdu );
1476 return 0;
1477 }
1478
1479 static const CommandDefRec sms_commands[] =
1480 {
1481 { "send", "send inbound SMS text message",
1482 "'sms send <phonenumber> <message>' allows you to simulate a new inbound sms message\r\n", NULL,
1483 do_sms_send, NULL },
1484
1485 { "pdu", "send inbound SMS PDU",
1486 "'sms pdu <hexstring>' allows you to simulate a new inbound sms PDU\r\n"
1487 "(used internally when one emulator sends SMS messages to another instance).\r\n"
1488 "you probably don't want to play with this at all\r\n", NULL,
1489 do_sms_sendpdu, NULL },
1490
1491 { NULL, NULL, NULL, NULL, NULL, NULL }
1492 };
1493
1494 static void
do_control_write(void * data,const char * string)1495 do_control_write(void* data, const char* string)
1496 {
1497 control_write((ControlClient)data, string);
1498 }
1499
1500 static int
do_power_display(ControlClient client,char * args)1501 do_power_display( ControlClient client, char* args )
1502 {
1503 goldfish_battery_display(do_control_write, client);
1504 return 0;
1505 }
1506
1507 static int
do_ac_state(ControlClient client,char * args)1508 do_ac_state( ControlClient client, char* args )
1509 {
1510 if (args) {
1511 if (strcasecmp(args, "on") == 0) {
1512 goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 1);
1513 return 0;
1514 }
1515 if (strcasecmp(args, "off") == 0) {
1516 goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 0);
1517 return 0;
1518 }
1519 }
1520
1521 control_write( client, "KO: Usage: \"ac on\" or \"ac off\"\n" );
1522 return -1;
1523 }
1524
1525 static int
do_battery_status(ControlClient client,char * args)1526 do_battery_status( ControlClient client, char* args )
1527 {
1528 if (args) {
1529 if (strcasecmp(args, "unknown") == 0) {
1530 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_UNKNOWN);
1531 return 0;
1532 }
1533 if (strcasecmp(args, "charging") == 0) {
1534 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_CHARGING);
1535 return 0;
1536 }
1537 if (strcasecmp(args, "discharging") == 0) {
1538 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_DISCHARGING);
1539 return 0;
1540 }
1541 if (strcasecmp(args, "not-charging") == 0) {
1542 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_NOT_CHARGING);
1543 return 0;
1544 }
1545 if (strcasecmp(args, "full") == 0) {
1546 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_FULL);
1547 return 0;
1548 }
1549 }
1550
1551 control_write( client, "KO: Usage: \"status unknown|charging|discharging|not-charging|full\"\n" );
1552 return -1;
1553 }
1554
1555 static int
do_battery_present(ControlClient client,char * args)1556 do_battery_present( ControlClient client, char* args )
1557 {
1558 if (args) {
1559 if (strcasecmp(args, "true") == 0) {
1560 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 1);
1561 return 0;
1562 }
1563 if (strcasecmp(args, "false") == 0) {
1564 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 0);
1565 return 0;
1566 }
1567 }
1568
1569 control_write( client, "KO: Usage: \"present true\" or \"present false\"\n" );
1570 return -1;
1571 }
1572
1573 static int
do_battery_health(ControlClient client,char * args)1574 do_battery_health( ControlClient client, char* args )
1575 {
1576 if (args) {
1577 if (strcasecmp(args, "unknown") == 0) {
1578 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNKNOWN);
1579 return 0;
1580 }
1581 if (strcasecmp(args, "good") == 0) {
1582 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_GOOD);
1583 return 0;
1584 }
1585 if (strcasecmp(args, "overheat") == 0) {
1586 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERHEAT);
1587 return 0;
1588 }
1589 if (strcasecmp(args, "dead") == 0) {
1590 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_DEAD);
1591 return 0;
1592 }
1593 if (strcasecmp(args, "overvoltage") == 0) {
1594 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERVOLTAGE);
1595 return 0;
1596 }
1597 if (strcasecmp(args, "failure") == 0) {
1598 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNSPEC_FAILURE);
1599 return 0;
1600 }
1601 }
1602
1603 control_write( client, "KO: Usage: \"health unknown|good|overheat|dead|overvoltage|failure\"\n" );
1604 return -1;
1605 }
1606
1607 static int
do_battery_capacity(ControlClient client,char * args)1608 do_battery_capacity( ControlClient client, char* args )
1609 {
1610 if (args) {
1611 int capacity;
1612
1613 if (sscanf(args, "%d", &capacity) == 1 && capacity >= 0 && capacity <= 100) {
1614 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_CAPACITY, capacity);
1615 return 0;
1616 }
1617 }
1618
1619 control_write( client, "KO: Usage: \"capacity <percentage>\"\n" );
1620 return -1;
1621 }
1622
1623
1624 static const CommandDefRec power_commands[] =
1625 {
1626 { "display", "display battery and charger state",
1627 "display battery and charger state\r\n", NULL,
1628 do_power_display, NULL },
1629
1630 { "ac", "set AC charging state",
1631 "'ac on|off' allows you to set the AC charging state to on or off\r\n", NULL,
1632 do_ac_state, NULL },
1633
1634 { "status", "set battery status",
1635 "'status unknown|charging|discharging|not-charging|full' allows you to set battery status\r\n", NULL,
1636 do_battery_status, NULL },
1637
1638 { "present", "set battery present state",
1639 "'present true|false' allows you to set battery present state to true or false\r\n", NULL,
1640 do_battery_present, NULL },
1641
1642 { "health", "set battery health state",
1643 "'health unknown|good|overheat|dead|overvoltage|failure' allows you to set battery health state\r\n", NULL,
1644 do_battery_health, NULL },
1645
1646 { "capacity", "set battery capacity state",
1647 "'capacity <percentage>' allows you to set battery capacity to a value 0 - 100\r\n", NULL,
1648 do_battery_capacity, NULL },
1649
1650 { NULL, NULL, NULL, NULL, NULL, NULL }
1651 };
1652
1653 /********************************************************************************************/
1654 /********************************************************************************************/
1655 /***** ******/
1656 /***** E V E N T C O M M A N D S ******/
1657 /***** ******/
1658 /********************************************************************************************/
1659 /********************************************************************************************/
1660
1661
1662 static int
do_event_send(ControlClient client,char * args)1663 do_event_send( ControlClient client, char* args )
1664 {
1665 char* p;
1666
1667 if (!args) {
1668 control_write( client, "KO: Usage: event send <type>:<code>:<value> ...\r\n" );
1669 return -1;
1670 }
1671
1672 p = args;
1673 while (*p) {
1674 char* q;
1675 int type, code, value, ret;
1676
1677 p += strspn( args, " \t" ); /* skip spaces */
1678 if (*p == 0)
1679 break;
1680
1681 q = p + strcspn( p, " \t" );
1682
1683 if (q == p)
1684 break;
1685
1686 ret = android_event_from_str( p, &type, &code, &value );
1687 if (ret < 0) {
1688 if (ret == -1) {
1689 control_write( client,
1690 "KO: invalid event type in '%.*s', try 'event list types' for valid values\r\n",
1691 q-p, p );
1692 } else if (ret == -2) {
1693 control_write( client,
1694 "KO: invalid event code in '%.*s', try 'event list codes <type>' for valid values\r\n",
1695 q-p, p );
1696 } else {
1697 control_write( client,
1698 "KO: invalid event value in '%.*s', must be an integer\r\n",
1699 q-p, p);
1700 }
1701 return -1;
1702 }
1703
1704 kbd_generic_event( type, code, value );
1705 p = q;
1706 }
1707 return 0;
1708 }
1709
1710 static int
do_event_types(ControlClient client,char * args)1711 do_event_types( ControlClient client, char* args )
1712 {
1713 int count = android_event_get_type_count();
1714 int nn;
1715
1716 control_write( client, "event <type> can be an integer or one of the following aliases\r\n" );
1717 for (nn = 0; nn < count; nn++) {
1718 char tmp[16];
1719 char* p = tmp;
1720 char* end = p + sizeof(tmp);
1721 int count2 = android_event_get_code_count( nn );;
1722
1723 p = android_event_bufprint_type_str( p, end, nn );
1724
1725 control_write( client, " %-8s", tmp );
1726 if (count2 > 0)
1727 control_write( client, " (%d code aliases)", count2 );
1728
1729 control_write( client, "\r\n" );
1730 }
1731 return 0;
1732 }
1733
1734 static int
do_event_codes(ControlClient client,char * args)1735 do_event_codes( ControlClient client, char* args )
1736 {
1737 int count;
1738 int nn, type, dummy;
1739
1740 if (!args) {
1741 control_write( client, "KO: argument missing, try 'event codes <type>'\r\n" );
1742 return -1;
1743 }
1744
1745 if ( android_event_from_str( args, &type, &dummy, &dummy ) < 0 ) {
1746 control_write( client, "KO: bad argument, see 'event types' for valid values\r\n" );
1747 return -1;
1748 }
1749
1750 count = android_event_get_code_count( type );
1751 if (count == 0) {
1752 control_write( client, "no code aliases defined for this type\r\n" );
1753 } else {
1754 control_write( client, "type '%s' accepts the following <code> aliases:\r\n",
1755 args );
1756 for (nn = 0; nn < count; nn++) {
1757 char temp[20], *p = temp, *end = p + sizeof(temp);
1758 android_event_bufprint_code_str( p, end, type, nn );
1759 control_write( client, " %-12s\r\n", temp );
1760 }
1761 }
1762
1763 return 0;
1764 }
1765
1766 static __inline__ int
utf8_next(unsigned char ** pp,unsigned char * end)1767 utf8_next( unsigned char* *pp, unsigned char* end )
1768 {
1769 unsigned char* p = *pp;
1770 int result = -1;
1771
1772 if (p < end) {
1773 int c= *p++;
1774 if (c >= 128) {
1775 if ((c & 0xe0) == 0xc0)
1776 c &= 0x1f;
1777 else if ((c & 0xf0) == 0xe0)
1778 c &= 0x0f;
1779 else
1780 c &= 0x07;
1781
1782 while (p < end && (p[0] & 0xc0) == 0x80) {
1783 c = (c << 6) | (p[0] & 0x3f);
1784 }
1785 }
1786 result = c;
1787 *pp = p;
1788 }
1789 return result;
1790 }
1791
1792 static int
do_event_text(ControlClient client,char * args)1793 do_event_text( ControlClient client, char* args )
1794 {
1795 SkinKeyboard* keyboard;
1796 unsigned char* p = (unsigned char*) args;
1797 unsigned char* end = p + strlen(args);
1798 int textlen;
1799
1800 if (!args) {
1801 control_write( client, "KO: argument missing, try 'event text <message>'\r\n" );
1802 return -1;
1803 }
1804 keyboard = android_emulator_get_keyboard();
1805 if (keyboard == NULL) {
1806 control_write( client, "KO: no keyboard active in current device layout/config\r\n" );
1807 return -1;
1808 }
1809
1810 /* un-secape message text into proper utf-8 (conversion happens in-site) */
1811 textlen = strlen((char*)p);
1812 textlen = sms_utf8_from_message_str( args, textlen, (unsigned char*)p, textlen );
1813 if (textlen < 0) {
1814 control_write( client, "message must be utf8 and can use the following escapes:\r\n"
1815 " \\n for a newline\r\n"
1816 " \\xNN where NN are two hexadecimal numbers\r\n"
1817 " \\uNNNN where NNNN are four hexadecimal numbers\r\n"
1818 " \\\\ to send a '\\' character\r\n\r\n"
1819 " anything else is an error\r\n"
1820 "KO: badly formatted text\r\n" );
1821 return -1;
1822 }
1823
1824 end = p + textlen;
1825 while (p < end) {
1826 int c = utf8_next( &p, end );
1827 if (c <= 0)
1828 break;
1829
1830 skin_keyboard_process_unicode_event( keyboard, (unsigned)c, 1 );
1831 skin_keyboard_process_unicode_event( keyboard, (unsigned)c, 0 );
1832 skin_keyboard_flush( keyboard );
1833 }
1834
1835 return 0;
1836 }
1837
1838 static const CommandDefRec event_commands[] =
1839 {
1840 { "send", "send a series of events to the kernel",
1841 "'event send <type>:<code>:<value> ...' allows your to send one or more hardware events\r\n"
1842 "to the Android kernel. you can use text names or integers for <type> and <code>\r\n", NULL,
1843 do_event_send, NULL },
1844
1845 { "types", "list all <type> aliases",
1846 "'event types' list all <type> string aliases supported by the 'event' subcommands\r\n",
1847 NULL, do_event_types, NULL },
1848
1849 { "codes", "list all <code> aliases for a given <type>",
1850 "'event codes <type>' lists all <code> string aliases for a given event <type>\r\n",
1851 NULL, do_event_codes, NULL },
1852
1853 { "text", "simulate keystrokes from a given text",
1854 "'event text <message>' allows you to simulate keypresses to generate a given text\r\n"
1855 "message. <message> must be an utf-8 string. Unicode points will be reverse-mapped\r\n"
1856 "according to the current device keyboard. unsupported characters will be discarded\r\n"
1857 "silently\r\n", NULL, do_event_text, NULL },
1858
1859 { NULL, NULL, NULL, NULL, NULL, NULL }
1860 };
1861
1862
1863 /********************************************************************************************/
1864 /********************************************************************************************/
1865 /***** ******/
1866 /***** V M C O M M A N D S ******/
1867 /***** ******/
1868 /********************************************************************************************/
1869 /********************************************************************************************/
1870
1871 static int
do_avd_stop(ControlClient client,char * args)1872 do_avd_stop( ControlClient client, char* args )
1873 {
1874 if (!vm_running) {
1875 control_write( client, "KO: virtual device already stopped\r\n" );
1876 return -1;
1877 }
1878 vm_stop(EXCP_INTERRUPT);
1879 return 0;
1880 }
1881
1882 static int
do_avd_start(ControlClient client,char * args)1883 do_avd_start( ControlClient client, char* args )
1884 {
1885 if (vm_running) {
1886 control_write( client, "KO: virtual device already running\r\n" );
1887 return -1;
1888 }
1889 vm_start();
1890 return 0;
1891 }
1892
1893 static int
do_avd_status(ControlClient client,char * args)1894 do_avd_status( ControlClient client, char* args )
1895 {
1896 control_write( client, "virtual device is %s\r\n", vm_running ? "running" : "stopped" );
1897 return 0;
1898 }
1899
1900 static int
do_avd_name(ControlClient client,char * args)1901 do_avd_name( ControlClient client, char* args )
1902 {
1903 control_write( client, "%s\r\n", avdInfo_getName(android_avdInfo) );
1904 return 0;
1905 }
1906
1907 static const CommandDefRec vm_commands[] =
1908 {
1909 { "stop", "stop the virtual device",
1910 "'avd stop' stops the virtual device immediately, use 'avd start' to continue execution\r\n",
1911 NULL, do_avd_stop, NULL },
1912
1913 { "start", "start/restart the virtual device",
1914 "'avd start' will start or continue the virtual device, use 'avd stop' to stop it\r\n",
1915 NULL, do_avd_start, NULL },
1916
1917 { "status", "query virtual device status",
1918 "'avd status' will indicate wether the virtual device is running or not\r\n",
1919 NULL, do_avd_status, NULL },
1920
1921 { "name", "query virtual device name",
1922 "'avd name' will return the name of this virtual device\r\n",
1923 NULL, do_avd_name, NULL },
1924
1925 { NULL, NULL, NULL, NULL, NULL, NULL }
1926 };
1927
1928 /********************************************************************************************/
1929 /********************************************************************************************/
1930 /***** ******/
1931 /***** G E O C O M M A N D S ******/
1932 /***** ******/
1933 /********************************************************************************************/
1934 /********************************************************************************************/
1935
1936 static int
do_geo_nmea(ControlClient client,char * args)1937 do_geo_nmea( ControlClient client, char* args )
1938 {
1939 if (!args) {
1940 control_write( client, "KO: NMEA sentence missing, try 'help geo nmea'\r\n" );
1941 return -1;
1942 }
1943 if (!android_gps_cs) {
1944 control_write( client, "KO: no GPS emulation in this virtual device\r\n" );
1945 return -1;
1946 }
1947 android_gps_send_nmea( args );
1948 return 0;
1949 }
1950
1951 static int
do_geo_fix(ControlClient client,char * args)1952 do_geo_fix( ControlClient client, char* args )
1953 {
1954 #define MAX_GEO_PARAMS 3
1955 char* p = args;
1956 int n_params = 0;
1957 double params[ MAX_GEO_PARAMS ];
1958
1959 static int last_time = 0;
1960 static double last_altitude = 0.;
1961
1962 if (!p)
1963 p = "";
1964
1965 /* tokenize */
1966 while (*p) {
1967 char* end;
1968 double val = strtod( p, &end );
1969
1970 if (end == p) {
1971 control_write( client, "KO: argument '%s' is not a number\n", p );
1972 return -1;
1973 }
1974
1975 params[n_params++] = val;
1976 if (n_params >= MAX_GEO_PARAMS)
1977 break;
1978
1979 p = end;
1980 while (*p && (p[0] == ' ' || p[0] == '\t'))
1981 p += 1;
1982 }
1983
1984 /* sanity check */
1985 if (n_params < 2) {
1986 control_write( client, "KO: not enough arguments: see 'help geo fix' for details\r\n" );
1987 return -1;
1988 }
1989
1990 /* generate an NMEA sentence for this fix */
1991 {
1992 STRALLOC_DEFINE(s);
1993 double val;
1994 int deg, min;
1995 char hemi;
1996
1997 /* first, the time */
1998 stralloc_add_format( s, "$GPGGA,%06d", last_time );
1999 last_time ++;
2000
2001 /* then the latitude */
2002 hemi = 'N';
2003 val = params[1];
2004 if (val < 0) {
2005 hemi = 'S';
2006 val = -val;
2007 }
2008 deg = (int) val;
2009 min = 60*(val - deg);
2010 val = val - min/60.;
2011 stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)(val * 10000), hemi );
2012
2013 /* the longitude */
2014 hemi = 'E';
2015 val = params[0];
2016 if (val < 0) {
2017 hemi = 'W';
2018 val = -val;
2019 }
2020 deg = (int) val;
2021 min = 60*(val - deg);
2022 val = val - min/60.;
2023 stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)(val * 10000), hemi );
2024
2025 /* bogus fix quality, empty satellite count and dilutions */
2026 stralloc_add_str( s, ",1,,,," );
2027
2028 /* optional altitude */
2029 if (n_params >= 3) {
2030 stralloc_add_format( s, "%.1g", params[2] );
2031 last_altitude = params[2];
2032 } else {
2033 stralloc_add_str( s, "," );
2034 }
2035 /* bogus rest and checksum */
2036 stralloc_add_str( s, ",,,*47" );
2037
2038 /* send it, then free */
2039 android_gps_send_nmea( stralloc_cstr(s) );
2040 stralloc_reset( s );
2041 }
2042 return 0;
2043 }
2044
2045 static const CommandDefRec geo_commands[] =
2046 {
2047 { "nmea", "send an GPS NMEA sentence",
2048 "'geo nema <sentence>' sends a NMEA 0183 sentence to the emulated device, as\r\n"
2049 "if it came from an emulated GPS modem. <sentence> must begin with '$GP'. only\r\n"
2050 "'$GPGGA' and '$GPRCM' sentences are supported at the moment.\r\n",
2051 NULL, do_geo_nmea, NULL },
2052
2053 { "fix", "send a simple GPS fix",
2054 "'geo fix <longitude> <latitude> [<altitude>]' allows you to send a\r\n"
2055 "simple GPS fix to the emulated system. the parameters are:\r\n\r\n"
2056 " <longitude> longitude, in decimal degrees\r\n"
2057 " <latitude> latitude, in decimal degrees\r\n"
2058 " <altitude> optional altitude in meters\r\n"
2059 "\r\n",
2060 NULL, do_geo_fix, NULL },
2061
2062 { NULL, NULL, NULL, NULL, NULL, NULL }
2063 };
2064
2065
2066 /********************************************************************************************/
2067 /********************************************************************************************/
2068 /***** ******/
2069 /***** M A I N C O M M A N D S ******/
2070 /***** ******/
2071 /********************************************************************************************/
2072 /********************************************************************************************/
2073
2074 extern void android_emulator_set_window_scale( double, int );
2075
2076 static int
do_window_scale(ControlClient client,char * args)2077 do_window_scale( ControlClient client, char* args )
2078 {
2079 double scale;
2080 int is_dpi = 0;
2081 char* end;
2082
2083 if (!args) {
2084 control_write( client, "KO: argument missing, try 'window scale <scale>'\r\n" );
2085 return -1;
2086 }
2087
2088 scale = strtol( args, &end, 10 );
2089 if (end > args && !memcmp( end, "dpi", 4 )) {
2090 is_dpi = 1;
2091 }
2092 else {
2093 scale = strtod( args, &end );
2094 if (end == args || end[0]) {
2095 control_write( client, "KO: argument <scale> must be a real number, or an integer followed by 'dpi'\r\n" );
2096 return -1;
2097 }
2098 }
2099
2100 android_emulator_set_window_scale( scale, is_dpi );
2101 return 0;
2102 }
2103
2104 static const CommandDefRec window_commands[] =
2105 {
2106 { "scale", "change the window scale",
2107 "'window scale <scale>' allows you to change the scale of the emulator window at runtime\r\n"
2108 "<scale> must be either a real number between 0.1 and 3.0, or an integer followed by\r\n"
2109 "the 'dpi' prefix (as in '120dpi')\r\n",
2110 NULL, do_window_scale, NULL },
2111
2112 { NULL, NULL, NULL, NULL, NULL, NULL }
2113 };
2114
2115 /********************************************************************************************/
2116 /********************************************************************************************/
2117 /***** ******/
2118 /***** M A I N C O M M A N D S ******/
2119 /***** ******/
2120 /********************************************************************************************/
2121 /********************************************************************************************/
2122
2123 static int
do_kill(ControlClient client,char * args)2124 do_kill( ControlClient client, char* args )
2125 {
2126 control_write( client, "OK: killing emulator, bye bye\r\n" );
2127 exit(0);
2128 }
2129
2130 static const CommandDefRec main_commands[] =
2131 {
2132 { "help|h|?", "print a list of commands", NULL, NULL, do_help, NULL },
2133
2134 { "event", "simulate hardware events",
2135 "allows you to send fake hardware events to the kernel\r\n", NULL,
2136 NULL, event_commands },
2137
2138 { "geo", "Geo-location commands",
2139 "allows you to change Geo-related settings, or to send GPS NMEA sentences\r\n", NULL,
2140 NULL, geo_commands },
2141
2142 { "gsm", "GSM related commands",
2143 "allows you to change GSM-related settings, or to make a new inbound phone call\r\n", NULL,
2144 NULL, gsm_commands },
2145
2146 { "kill", "kill the emulator instance", NULL, NULL,
2147 do_kill, NULL },
2148
2149 { "network", "manage network settings",
2150 "allows you to manage the settings related to the network data connection of the\r\n"
2151 "emulated device.\r\n", NULL,
2152 NULL, network_commands },
2153
2154 { "power", "power related commands",
2155 "allows to change battery and AC power status\r\n", NULL,
2156 NULL, power_commands },
2157
2158 { "quit|exit", "quit control session", NULL, NULL,
2159 do_quit, NULL },
2160
2161 { "redir", "manage port redirections",
2162 "allows you to add, list and remove UDP and/or PORT redirection from the host to the device\r\n"
2163 "as an example, 'redir tcp:5000:6000' will route any packet sent to the host's TCP port 5000\r\n"
2164 "to TCP port 6000 of the emulated device\r\n", NULL,
2165 NULL, redir_commands },
2166
2167 { "sms", "SMS related commands",
2168 "allows you to simulate an inbound SMS\r\n", NULL,
2169 NULL, sms_commands },
2170
2171 { "avd", "manager virtual device state",
2172 "allows to change (e.g. start/stop) the virtual device state\r\n", NULL,
2173 NULL, vm_commands },
2174
2175 { "window", "manage emulator window",
2176 "allows you to modify the emulator window\r\n", NULL,
2177 NULL, window_commands },
2178
2179 { NULL, NULL, NULL, NULL, NULL, NULL }
2180 };
2181
2182
2183 static ControlGlobalRec _g_global;
2184
2185 int
control_console_start(int port)2186 control_console_start( int port )
2187 {
2188 return control_global_init( &_g_global, port );
2189 }
2190