Handle IPv6 addresses when reporting open file descriptors.

Based on a patch from Roger Light on BZ#175819.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13836 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/NEWS b/NEWS
index f1aa78c..cdd7827 100644
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,7 @@
   https://bugs.kde.org/show_bug.cgi?id=XXXXXX
 where XXXXXX is the bug number as listed below.
 
+175819  Support for ipv6 socket reporting with --track-fds
 308729  vex x86->IR: unhandled instruction bytes 0xf 0x5 (syscall) 
 325714  Empty vgcore but RLIMIT_CORE is big enough (too big) 
 325856  Make SGCheck fail gracefully on unsupported platforms
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 6587a0e..cdf64ea 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -608,7 +608,7 @@
 }
 
 static
-HChar *unix2name(struct vki_sockaddr_un *sa, UInt len, HChar *name)
+HChar *unix_to_name(struct vki_sockaddr_un *sa, UInt len, HChar *name)
 {
    if (sa == NULL || len == 0 || sa->sun_path[0] == '\0') {
       VG_(sprintf)(name, "<unknown>");
@@ -620,20 +620,80 @@
 }
 
 static
-HChar *inet2name(struct vki_sockaddr_in *sa, UInt len, HChar *name)
+HChar *inet_to_name(struct vki_sockaddr_in *sa, UInt len, HChar *name)
 {
    if (sa == NULL || len == 0) {
       VG_(sprintf)(name, "<unknown>");
+   } else if (sa->sin_port == 0) {
+      VG_(sprintf)(name, "<unbound>");
    } else {
       UInt addr = VG_(ntohl)(sa->sin_addr.s_addr);
-      if (addr == 0) {
-         VG_(sprintf)(name, "<unbound>");
-      } else {
-         VG_(sprintf)(name, "%u.%u.%u.%u:%u",
-                      (addr>>24) & 0xFF, (addr>>16) & 0xFF,
-                      (addr>>8) & 0xFF, addr & 0xFF,
-                      VG_(ntohs)(sa->sin_port));
+      VG_(sprintf)(name, "%u.%u.%u.%u:%u",
+                   (addr>>24) & 0xFF, (addr>>16) & 0xFF,
+                   (addr>>8) & 0xFF, addr & 0xFF,
+                   VG_(ntohs)(sa->sin_port));
+   }
+
+   return name;
+}
+
+static
+void inet6_format(HChar *s, const UChar ip[16])
+{
+   static const unsigned char V4mappedprefix[12] = {0,0,0,0,0,0,0,0,0,0,0xff,0xff};
+
+   if (!VG_(memcmp)(ip, V4mappedprefix, 12)) {
+      struct vki_in_addr *sin_addr = (struct vki_in_addr *)(ip + 12);
+      UInt addr = VG_(ntohl)(sin_addr->s_addr);
+
+      VG_(sprintf)(s, "::ffff:%u.%u.%u.%u",
+                   (addr>>24) & 0xFF, (addr>>16) & 0xFF,
+                   (addr>>8) & 0xFF, addr & 0xFF);
+   } else {
+      Bool compressing = False;
+      Bool compressed = False;
+      Int len = 0;
+      Int i;
+
+      for (i = 0; i < 16; i += 2) {
+         UInt word = ((UInt)ip[i] << 8) | (UInt)ip[i+1];
+         if (word == 0 && !compressed) {
+            compressing = True;
+         } else {
+            if (compressing) {
+               compressing = False;
+               compressed = True;
+               s[len++] = ':';
+            }
+            if (i > 0) {
+               s[len++] = ':';
+            }
+            len += VG_(sprintf)(s + len, "%x", word);
+         }
       }
+
+      if (compressing) {
+         s[len++] = ':';
+         s[len++] = ':';
+      }
+
+      s[len++] = 0;
+   }
+
+   return;
+}
+
+static
+HChar *inet6_to_name(struct vki_sockaddr_in6 *sa, UInt len, HChar *name)
+{
+   if (sa == NULL || len == 0) {
+      VG_(sprintf)(name, "<unknown>");
+   } else if (sa->sin6_port == 0) {
+      VG_(sprintf)(name, "<unbound>");
+   } else {
+      char addr[128];
+      inet6_format(addr, (void *)&(sa->sin6_addr));
+      VG_(sprintf)(name, "[%s]:%u", addr, VG_(ntohs)(sa->sin6_port));
    }
 
    return name;
@@ -648,6 +708,7 @@
    union u {
       struct vki_sockaddr a;
       struct vki_sockaddr_in in;
+      struct vki_sockaddr_in6 in6;
       struct vki_sockaddr_un un;
    } laddr;
    Int llen;
@@ -665,18 +726,34 @@
 
          if (VG_(getpeername)(fd, (struct vki_sockaddr *)&paddr, &plen) != -1) {
             VG_(message)(Vg_UserMsg, "Open AF_INET socket %d: %s <-> %s\n", fd,
-                         inet2name(&(laddr.in), llen, lname),
-                         inet2name(&paddr, plen, pname));
+                         inet_to_name(&(laddr.in), llen, lname),
+                         inet_to_name(&paddr, plen, pname));
          } else {
             VG_(message)(Vg_UserMsg, "Open AF_INET socket %d: %s <-> unbound\n",
-                         fd, inet2name(&(laddr.in), llen, lname));
+                         fd, inet_to_name(&(laddr.in), llen, lname));
+         }
+         return;
+         }
+      case VKI_AF_INET6: {
+         static char lname[128];
+         static char pname[128];
+         struct vki_sockaddr_in6 paddr;
+         Int plen = sizeof(struct vki_sockaddr_in6);
+
+         if (VG_(getpeername)(fd, (struct vki_sockaddr *)&paddr, &plen) != -1) {
+            VG_(message)(Vg_UserMsg, "Open AF_INET6 socket %d: %s <-> %s\n", fd,
+                         inet6_to_name(&(laddr.in6), llen, lname),
+                         inet6_to_name(&paddr, plen, pname));
+         } else {
+            VG_(message)(Vg_UserMsg, "Open AF_INET6 socket %d: %s <-> unbound\n",
+                         fd, inet6_to_name(&(laddr.in6), llen, lname));
          }
          return;
          }
       case VKI_AF_UNIX: {
          static char lname[256];
          VG_(message)(Vg_UserMsg, "Open AF_UNIX socket %d: %s\n", fd,
-                      unix2name(&(laddr.un), llen, lname));
+                      unix_to_name(&(laddr.un), llen, lname));
          return;
          }
       default: