Add Socket::Get[Remote/Local]IpAddress and unit tests

Differential Revision: http://reviews.llvm.org/D6917

llvm-svn: 226234
diff --git a/lldb/source/Host/common/Socket.cpp b/lldb/source/Host/common/Socket.cpp
index c12fa07..f93ad7e 100644
--- a/lldb/source/Host/common/Socket.cpp
+++ b/lldb/source/Host/common/Socket.cpp
@@ -222,7 +222,7 @@
         // as port zero is a special code for "find an open port
         // for me".
         if (port == 0)
-            port = listen_socket->GetPortNumber();
+            port = listen_socket->GetLocalPortNumber();
 
         // Set the port predicate since when doing a listen://<host>:<port>
         // it often needs to accept the incoming connection which is a blocking
@@ -230,7 +230,7 @@
         // us to wait for the port predicate to be set to a non-zero value from
         // another thread in an efficient manor.
         if (predicate)
-            predicate->SetValue(port, eBroadcastAlways);
+            predicate->SetValue (port, eBroadcastAlways);
 
         socket = listen_socket.release();
     }
@@ -533,13 +533,18 @@
         if (regex_match.GetMatchAtIndex (host_and_port.data(), 1, host_str) &&
             regex_match.GetMatchAtIndex (host_and_port.data(), 2, port_str))
         {
-            port = StringConvert::ToSInt32 (port_str.c_str(), INT32_MIN);
-            if (port != INT32_MIN)
+            bool ok = false;
+            port = StringConvert::ToUInt32 (port_str.c_str(), UINT32_MAX, 10, &ok);
+            if (ok && port < UINT16_MAX)
             {
                 if (error_ptr)
                     error_ptr->Clear();
                 return true;
             }
+            // port is too large
+            if (error_ptr)
+                error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port.data());
+            return false;
         }
     }
 
@@ -547,10 +552,13 @@
     // a port with an empty host.
     host_str.clear();
     port_str.clear();
-    port = StringConvert::ToSInt32(host_and_port.data(), INT32_MIN);
-    if (port != INT32_MIN)
+    bool ok = false;
+    port = StringConvert::ToUInt32 (host_and_port.data(), UINT32_MAX, 10, &ok);
+    if (ok && port < UINT16_MAX)
     {
         port_str = host_and_port;
+        if (error_ptr)
+            error_ptr->Clear();
         return true;
     }
 
@@ -688,7 +696,7 @@
 	return ::setsockopt(m_socket, level, option_name, option_value_p, sizeof(option_value));
 }
 
-uint16_t Socket::GetPortNumber(const NativeSocket& socket)
+uint16_t Socket::GetLocalPortNumber(const NativeSocket& socket)
 {
     // We bound to port zero, so we need to figure out which port we actually bound to
     if (socket >= 0)
@@ -702,7 +710,47 @@
 }
 
 // Return the port number that is being used by the socket.
-uint16_t Socket::GetPortNumber() const
+uint16_t Socket::GetLocalPortNumber() const
 {
-    return GetPortNumber(m_socket);
+    return GetLocalPortNumber (m_socket);
 }
+
+std::string  Socket::GetLocalIPAddress () const
+{
+    // We bound to port zero, so we need to figure out which port we actually bound to
+    if (m_socket >= 0)
+    {
+        SocketAddress sock_addr;
+        socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+        if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0)
+            return sock_addr.GetIPAddress ();
+    }
+    return "";
+}
+
+uint16_t Socket::GetRemotePortNumber () const
+{
+    if (m_socket >= 0)
+    {
+        SocketAddress sock_addr;
+        socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+        if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0)
+            return sock_addr.GetPort ();
+    }
+    return 0;
+}
+
+std::string Socket::GetRemoteIPAddress () const
+{
+    // We bound to port zero, so we need to figure out which port we actually bound to
+    if (m_socket >= 0)
+    {
+        SocketAddress sock_addr;
+        socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+        if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0)
+            return sock_addr.GetIPAddress ();
+    }
+    return "";
+}
+
+
diff --git a/lldb/source/Host/common/SocketAddress.cpp b/lldb/source/Host/common/SocketAddress.cpp
index 6231631..3b5d7f8 100644
--- a/lldb/source/Host/common/SocketAddress.cpp
+++ b/lldb/source/Host/common/SocketAddress.cpp
@@ -21,6 +21,56 @@
 // Other libraries and framework includes
 // Project includes
 
+// WindowsXP needs an inet_ntop implementation
+#ifdef _WIN32
+
+#ifndef INET6_ADDRSTRLEN // might not be defined in older Windows SDKs
+#define INET6_ADDRSTRLEN 46
+#endif
+
+// TODO: implement shortened form "::" for runs of zeros
+const char* inet_ntop(int af, const void * src,
+                      char * dst, socklen_t size)
+{
+    if (size==0)
+    {
+        return nullptr;
+    }
+    
+    switch (af)
+    {
+        case AF_INET:
+        {
+            const char* formatted = inet_ntoa(*static_cast<const in_addr*>(src));
+            if (formatted && strlen(formatted) < size)
+            {
+                strncpy(dst, formatted, size);
+                return dst;
+            }
+            return nullptr;
+        case AF_INET6:
+            {
+                char tmp[INET6_ADDRSTRLEN] = {0};
+                const uint16_t* src16 = static_cast<const uint16_t*>(src);
+                int full_size = _snprintf(tmp, sizeof(tmp),
+                                          "%x:%x:%x:%x:%x:%x:%x:%x",
+                                          ntohs(src16[0]), ntohs(src16[1]), ntohs(src16[2]), ntohs(src16[3]),
+                                          ntohs(src16[4]), ntohs(src16[5]), ntohs(src16[6]), ntohs(src16[7])
+                                          );
+                if (full_size < size)
+                {
+                    strncpy(dst,tmp,size);
+                    return dst;
+                }
+                return nullptr;
+            }
+        }
+        return nullptr;
+    }
+    
+#endif
+    
+
 using namespace lldb_private;
 
 //----------------------------------------------------------------------
@@ -124,6 +174,26 @@
 #endif
 }
 
+std::string
+SocketAddress::GetIPAddress () const
+{
+    char str[INET6_ADDRSTRLEN] = {0};
+    switch (GetFamily())
+    {
+        case AF_INET:
+            if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv4.sin_addr, str, sizeof(str)))
+            {
+                return str;
+            }
+        case AF_INET6:
+            if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv6.sin6_addr, str, sizeof(str)))
+            {
+                return str;
+            }
+    }
+    return "";
+}
+
 uint16_t
 SocketAddress::GetPort () const
 {