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