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