Debug: socket details
[exim.git] / src / src / debug.c
index 2ddf22907a083e6a9c31b091898e3d11c098b738..806573f1cc8917e42372c3579b21cba7b26cfde7 100644 (file)
@@ -14,6 +14,26 @@ static int     debug_prefix_length = 0;
 
 
 
+const uschar * rc_names[] = {          /* Mostly for debug output */
+  [OK] =               US"OK",
+  [DEFER] =            US"DEFER",
+  [FAIL] =             US"FAIL",
+  [ERROR] =            US"ERROR",
+  [FAIL_FORCED] =      US"FAIL_FORCED",
+  [DECLINE] =          US"DECLINE",
+  [PASS] =             US"PASS",
+  [DISCARD] =          US"DISCARD",
+  [SKIP] =             US"SKIP",
+  [REROUTED] =         US"REROUTED",
+  [PANIC] =            US"PANIC",
+  [BAD64] =            US"BAD64",
+  [UNEXPECTED] =       US"UNEXPECTED",
+  [CANCELLED] =                US"CANCELLED",
+  [FAIL_SEND] =                US"FAIL_SEND",
+  [FAIL_DROP] =                US"FAIL_DROP"
+};
+
+
 /*************************************************
 *               Print tree                       *
 *************************************************/
@@ -127,6 +147,17 @@ debug_printf("%s uid=%ld gid=%ld euid=%ld egid=%ld\n", s,
   (long int)getegid());
 }
 
+/************************************************/
+
+/* Give a string for a return-code */
+
+const uschar *
+rc_to_string(int rc)
+{
+return rc < 0 || rc >= nelem(rc_names) ? US"?" : rc_names[rc];
+}
+
+
 
 
 
@@ -199,7 +230,7 @@ if (debug_ptr == debug_buffer)
 
   if (host_checking && debug_selector == 0)
     {
-    Ustrcpy(debug_ptr, ">>> ");
+    Ustrcpy(debug_ptr, US">>> ");
     debug_ptr += 4;
     }
 
@@ -211,30 +242,33 @@ if (indent > 0)
   for (int i = indent >> 2; i > 0; i--)
     DEBUG(D_noutf8)
       {
-      Ustrcpy(debug_ptr, "   !");
+      Ustrcpy(debug_ptr, US"   !");
       debug_ptr += 4;  /* 3 spaces + shriek */
       debug_prefix_length += 4;
       }
     else
       {
-      Ustrcpy(debug_ptr, "   " UTF8_VERT_2DASH);
+      Ustrcpy(debug_ptr, US"   " UTF8_VERT_2DASH);
       debug_ptr += 6;  /* 3 spaces + 3 UTF-8 octets */
       debug_prefix_length += 6;
       }
 
-  Ustrncpy(debug_ptr, "   ", indent &= 3);
+  Ustrncpy(debug_ptr, US"   ", indent &= 3);
   debug_ptr += indent;
   debug_prefix_length += indent;
   }
 
-/* Use the checked formatting routine to ensure that the buffer
-does not overflow. Ensure there's space for a newline at the end. */
+/* Use the lengthchecked formatting routine to ensure that the buffer
+does not overflow. Ensure there's space for a newline at the end.
+However, use taint-unchecked routines for writing into the buffer
+so that we can write tainted info into the static debug_buffer -
+we trust that we will never expand the results. */
 
   {
   gstring gs = { .size = (int)sizeof(debug_buffer) - 1,
                .ptr = debug_ptr - debug_buffer,
                .s = debug_buffer };
-  if (!string_vformat(&gs, FALSE, format, ap))
+  if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, format, ap))
     {
     uschar * s = US"**** debug string too long - truncated ****\n";
     uschar * p = gs.s + gs.ptr;
@@ -281,4 +315,82 @@ if (debug_ptr[-1] == '\n')
 errno = save_errno;
 }
 
+
+
+/* Output the details of a socket */
+
+void
+debug_print_socket(int fd)
+{
+struct stat s;
+if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK)
+  {
+  gstring * g = NULL;
+  int val;
+  socklen_t vlen = sizeof(val);
+  struct sockaddr a;
+  socklen_t alen = sizeof(a);
+  struct sockaddr_in * sinp = (struct sockaddr_in *)&a;
+  struct sockaddr_in6 * sin6p = (struct sockaddr_in6 *)&a;
+  struct sockaddr_un * sa_unp ; (struct sockaddr_un *)&a;
+
+  if (getsockname(fd, &a, &alen) == 0)
+    switch (sinp->sin_family)
+      {
+      case AF_INET:
+       g = string_cat(g, US" domain AF_INET");
+       g = string_fmt_append(g, " lcl [%s]:%u",
+         inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
+       if (getpeername(fd, &a, &alen) == 0)
+         g = string_fmt_append(g, " rmt [%s]:%u",
+           inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
+       break;
+      case AF_INET6:
+       {
+       uschar buf[46];
+       g = string_cat(g, US" domain AF_INET6");
+       g = string_fmt_append(g, " lcl [%s]:%u",
+         inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
+         ntohs(sin6p->sin6_port));
+       if (getpeername(fd, &a, &alen) == 0)
+         g = string_fmt_append(g, " rmt [%s]:%u",
+           inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
+           ntohs(sin6p->sin6_port));
+       break;
+       }
+      case AF_UNIX:
+       g = string_cat(g, US" domain AF_UNIX");
+       g = string_fmt_append(g, " lcl %s%s",
+         sa_unp->sun_path[0] ? US"" : US"@",
+         sa_unp->sun_path[0] ? sa_unp->sun_path : sa_unp->sun_path+1);
+       if (getpeername(fd, &a, &alen) == 0)
+         g = string_fmt_append(g, " rmt %s%s",
+           sa_unp->sun_path[0] ? US"" : US"@",
+           sa_unp->sun_path[0] ? sa_unp->sun_path : sa_unp->sun_path+1);
+       break;
+      default:
+       g = string_fmt_append(g, " domain %u", sinp->sin_family);
+       break;
+      }
+  if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &val, &vlen) == 0)
+    switch (val)
+      {
+      case SOCK_STREAM:        g = string_cat(g, US" type SOCK_STREAM"); break;
+      case SOCK_DGRAM: g = string_cat(g, US" type SOCK_DGRAM"); break;
+      default: g = string_fmt_append(g, " type %d", val); break;
+      }
+  if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &val, &vlen) == 0)
+    {
+    struct protoent * p = getprotobynumber(val);
+    g = p
+      ? string_fmt_append(g, " proto %s\n", p->p_name)
+      : string_fmt_append(g, " proto %d", val);
+    }
+  debug_printf_indent(" socket: %s\n", string_from_gstring(g));
+  }
+else
+  debug_printf_indent(" fd st_mode 0%o\n", s.st_mode);
+}
+
+
 /* End of debug.c */