Enable interconnection of emulators

This patch adds a -shared-net-id option to the emulator which
joins the emulator in a shared network.
If the option is given the emulator is started with an additional
network interface bound to a multicast socket. This multicast socket
emulates a network hub, interconnecting emulators.
If the -shared-net-id option is not given, nothing changes.

Change-Id: I0ea70a073cdbd34f804161300240fafca34080d0
diff --git a/CHANGES.TXT b/CHANGES.TXT
index c110833..8338250 100644
--- a/CHANGES.TXT
+++ b/CHANGES.TXT
@@ -35,6 +35,10 @@
 
 - Removed audio stack SDL dependency.
 
+- Add a '-shared-net-id' option which allows emulators to join a shared network.
+  This allows testing situations where emulators need to communicate directly
+  with each other. See '-help-shared-net-id' for more details.
+
 ==============================================================================
 Changes between 6.0 and 5.0
 
diff --git a/android/cmdline-options.h b/android/cmdline-options.h
index 7a1a70f..a311912 100644
--- a/android/cmdline-options.h
+++ b/android/cmdline-options.h
@@ -135,6 +135,8 @@
 
 OPT_LIST(  prop, "<name>=<value>", "set system property on boot")
 
+OPT_PARAM( shared_net_id, "<number>", "join the shared network, using IP address 10.1.2.<number>")
+
 #ifdef CONFIG_NAND_LIMITS
 OPT_PARAM( nand_limits, "<nlimits>", "enforce NAND/Flash read/write thresholds" )
 #endif
diff --git a/android/help.c b/android/help.c
index e8737f5..23a94dd 100644
--- a/android/help.c
+++ b/android/help.c
@@ -1348,6 +1348,23 @@
     );
 }
 
+static void
+help_shared_net_id(stralloc_t*  out)
+{
+    PRINTF(
+    "  Normally, Android instances running in the emulator cannot talk to each other\n"
+    "  directly, because each instance is behind a virtual router. However, sometimes\n"
+    "  it is necessary to test the behaviour of applications if they are directly\n"
+    "  exposed to the network.\n\n"
+
+    "  This option instructs the emulator to join a virtual network shared with\n"
+    "  emulators also using this option. The number given is used to construct\n"
+    "  the IP address 10.1.2.<number>, which is bound to a second interface on\n"
+    "  the emulator. Each emulator must use a different number.\n\n"
+    );
+}
+
+
 #define  help_no_skin   NULL
 #define  help_netspeed  help_shaper
 #define  help_netdelay  help_shaper
diff --git a/android/main.c b/android/main.c
index 3aa89d0..bf3feec 100644
--- a/android/main.c
+++ b/android/main.c
@@ -1758,6 +1758,19 @@
         qemu_cpu_delay = (int) delay;
     }
 
+    if (opts->shared_net_id) {
+        char*  end;
+        long   shared_net_id = strtol(opts->shared_net_id, &end, 0);
+        if (end == NULL || *end || shared_net_id < 1 || shared_net_id > 255) {
+            fprintf(stderr, "option -shared-net-id must be an integer between 1 and 255\n");
+            exit(1);
+        }
+        char ip[11];
+        snprintf(ip, 11, "10.1.2.%ld", shared_net_id);
+        boot_property_add("net.shared_net_ip",ip);
+    }
+
+
     emulator_config_init();
     init_skinned_ui(opts->skindir, opts->skin, opts);
 
@@ -2271,6 +2284,22 @@
     args[n++] = "unix";
 #endif
 
+    /* Set up the interfaces for inter-emulator networking */
+    if (opts->shared_net_id) {
+        unsigned int shared_net_id = atoi(opts->shared_net_id);
+        char nic[37];
+        args[n++] = "-net";
+        snprintf(nic, 37, "nic,vlan=1,macaddr=52:54:00:12:34:%02x", shared_net_id);
+        args[n++] = strdup(nic);
+        args[n++] = "-net";
+        args[n++] = "socket,vlan=1,mcast=230.0.0.10:1234";
+
+        args[n++] = "-net";
+        args[n++] = "nic,vlan=0";
+        args[n++] = "-net";
+        args[n++] = "user,vlan=0";
+    }
+
     while(argc-- > 0) {
         args[n++] = *argv++;
     }