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