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