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