qemu-sockets-android.c: Add inet_dgram_opts

Change-Id: I30b3905332925d369481612a571342e21a5a7ed9
diff --git a/qemu-sockets-android.c b/qemu-sockets-android.c
index e7d5e18..b07129b 100644
--- a/qemu-sockets-android.c
+++ b/qemu-sockets-android.c
@@ -26,6 +26,10 @@
 # define AI_ADDRCONFIG 0
 #endif
 
+#ifndef INET6_ADDRSTRLEN
+# define INET6_ADDRSTRLEN  46
+#endif
+
 static int sockets_debug = 0;
 static const int on=1, off=0;
 
@@ -252,6 +256,114 @@
     return sock;
 }
 
+int inet_dgram_opts(QemuOpts *opts)
+{
+    SockAddress**  peer_list = NULL;
+    SockAddress**  local_list = NULL;
+    SockAddress*   e;
+    unsigned       flags = 0;
+    const char *addr;
+    const char *port;
+    char uaddr[INET6_ADDRSTRLEN+1];
+    char uport[33];
+    int sock = -1;
+    int nn;
+
+    /* lookup peer addr */
+    addr = qemu_opt_get(opts, "host");
+    port = qemu_opt_get(opts, "port");
+    if (addr == NULL || strlen(addr) == 0) {
+        addr = "localhost";
+    }
+    if (port == NULL || strlen(port) == 0) {
+        fprintf(stderr, "inet_dgram: port not specified\n");
+        return -1;
+    }
+
+    flags = SOCKET_LIST_DGRAM;
+    if (qemu_opt_get_bool(opts, "ipv4", 0)) {
+        flags &= SOCKET_LIST_FORCE_IN6;
+        flags |= SOCKET_LIST_FORCE_INET;
+    }
+    if (qemu_opt_get_bool(opts, "ipv6", 0)) {
+        flags &= SOCKET_LIST_FORCE_INET;
+        flags |= SOCKET_LIST_FORCE_IN6;
+    }
+
+    peer_list = sock_address_list_create(addr, port, flags);
+    if (peer_list == NULL) {
+        fprintf(stderr,"getaddrinfo(%s,%s): %s\n",
+                addr, port, errno_str);
+        return -1;
+    }
+
+    /* lookup local addr */
+    addr = qemu_opt_get(opts, "localaddr");
+    port = qemu_opt_get(opts, "localport");
+    if (addr == NULL || strlen(addr) == 0) {
+        addr = NULL;
+    }
+    if (!port || strlen(port) == 0)
+        port = "0";
+
+    flags = SOCKET_LIST_DGRAM | SOCKET_LIST_PASSIVE;
+    local_list = sock_address_list_create(addr, port, flags);
+    if (local_list == NULL) {
+        fprintf(stderr,"getaddrinfo(%s,%s): %s\n",
+                addr, port, errno_str);
+        goto EXIT;
+    }
+
+    if (sock_address_get_numeric_info(local_list[0],
+                                       uaddr, INET6_ADDRSTRLEN,
+                                       uport, 32)) {
+        fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
+        goto EXIT;
+    }
+
+    for (nn = 0; peer_list[nn] != NULL; nn++) {
+        SockAddress *local = local_list[0];
+        e    = peer_list[nn];
+        sock = socket_create(sock_address_get_family(e), SOCKET_DGRAM);
+        if (sock < 0) {
+            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+            sock_address_strfamily(e), errno_str);
+            continue;
+        }
+        socket_set_xreuseaddr(sock);
+
+        /* bind socket */
+        if (socket_bind(sock, local) < 0) {
+            fprintf(stderr,"%s: bind(%s,%s,%s): OK\n", __FUNCTION__,
+                sock_address_strfamily(local), addr, port);
+            socket_close(sock);
+            continue;
+        }
+
+        /* connect to peer */
+        if (socket_connect(sock,e) < 0) {
+            if (sockets_debug)
+                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
+                        sock_address_strfamily(e),
+                        sock_address_to_string(e), addr, port, strerror(errno));
+            socket_close(sock);
+            continue;
+        }
+        if (sockets_debug)
+            fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
+                        sock_address_strfamily(e),
+                        sock_address_to_string(e), addr, port);
+
+        goto EXIT;
+    }
+    sock = -1;
+EXIT:
+    if (local_list)
+        sock_address_list_free(local_list);
+    if (peer_list)
+        sock_address_list_free(peer_list);
+    return sock;
+}
 
 /* compatibility wrapper */
 static int inet_parse(QemuOpts *opts, const char *str)