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