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