THRIFT-5282: Add IPv6 client support to Lua library
Client: lua
Patch: Jeffrey Han

This closes #2243
diff --git a/lib/lua/src/usocket.c b/lib/lua/src/usocket.c
index 7c77651..21c0bac 100644
--- a/lib/lua/src/usocket.c
+++ b/lib/lua/src/usocket.c
@@ -283,6 +283,7 @@
   return strerror(err)
 
 const char * tcp_create(p_socket sock) {
+  // TODO support IPv6
   int err = socket_create(sock, AF_INET, SOCK_STREAM, 0);
   ERRORSTR_RETURN(err);
 }
@@ -293,6 +294,7 @@
 }
 
 const char * tcp_bind(p_socket sock, const char *host, unsigned short port) {
+  // TODO support IPv6
   int err;
   struct hostent *h;
   struct sockaddr_in local;
@@ -327,6 +329,7 @@
                          const char *host,
                          unsigned short port,
                          int timeout) {
+  // TODO support IPv6
   int err;
   struct hostent *h;
   struct sockaddr_in remote;
@@ -346,6 +349,66 @@
   ERRORSTR_RETURN(err);
 }
 
+const char * tcp_create_and_connect(p_socket sock,
+                                    const char *host,
+                                    unsigned short port,
+                                    int timeout) {
+  int err;
+  struct sockaddr_in sa4;
+  struct sockaddr_in6 sa6;
+
+  memset(&sa4, 0, sizeof(sa4));
+  sa4.sin_family = AF_INET;
+  sa4.sin_port = htons(port);
+  memset(&sa6, 0, sizeof(sa6));
+  sa6.sin6_family = AF_INET6;
+  sa6.sin6_port = htons(port);
+
+  if (inet_pton(AF_INET, host, &sa4.sin_addr)) {
+    socket_create(sock, AF_INET, SOCK_STREAM, 0);
+    err = socket_connect(sock, (p_sa) &sa4, sizeof(sa4), timeout);
+    ERRORSTR_RETURN(err);
+  } else if (inet_pton(AF_INET6, host, &sa6.sin6_addr)) {
+    socket_create(sock, AF_INET6, SOCK_STREAM, 0);
+    err = socket_connect(sock, (p_sa) &sa6, sizeof(sa6), timeout);
+    ERRORSTR_RETURN(err);
+  } else {
+    struct addrinfo hints, *servinfo, *rp;
+    char portStr[6];
+    int rv;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+
+    sprintf(portStr, "%u", port);
+
+    if ((rv = getaddrinfo(host, portStr, &hints, &servinfo)) != 0) {
+      return gai_strerror(rv);
+    }
+
+    err = TIMEOUT;
+    for (rp = servinfo; rp != NULL; rp = rp->ai_next) {
+      err = socket_create(sock, rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+      if (err != SUCCESS) {
+        continue;
+      }
+      err = socket_connect(sock, (p_sa) rp->ai_addr, rp->ai_addrlen, timeout);
+      if (err == SUCCESS) {
+        break;
+      }
+      close(*sock);
+    }
+    freeaddrinfo(servinfo);
+    if (rp == NULL) {
+      *sock = -1;
+      return "Failed to connect";
+    } else {
+      ERRORSTR_RETURN(err);
+    }
+  }
+}
+
 #define WRITE_STEP 8192
 const char * tcp_send(
   p_socket sock, const char * data, size_t w_len, int timeout) {