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