Implement logging to a network socket.  So it's now possible to do
valgrind ... --logsocket=192.168.0.1:1500 or whatever, to send all
output to that address/port combination.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1272 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_mylibc.c b/coregrind/vg_mylibc.c
index 05f662f..1bcf037 100644
--- a/coregrind/vg_mylibc.c
+++ b/coregrind/vg_mylibc.c
@@ -630,9 +630,14 @@
 static void add_to_myprintf_buf ( Char c )
 {
    if (n_myprintf_buf >= 100-10 /*paranoia*/ ) {
-      if (VG_(clo_logfile_fd) >= 0)
-         VG_(write)
-           (VG_(clo_logfile_fd), myprintf_buf, VG_(strlen)(myprintf_buf));
+      if (VG_(clo_logfile_fd) >= 0) {
+         if (VG_(logging_to_filedes))
+            VG_(write)
+              (VG_(clo_logfile_fd), myprintf_buf, VG_(strlen)(myprintf_buf));
+         else
+            VG_(write_socket)
+              (VG_(clo_logfile_fd), myprintf_buf, VG_(strlen)(myprintf_buf));
+      }
       n_myprintf_buf = 0;
       myprintf_buf[n_myprintf_buf] = 0;      
    }
@@ -650,9 +655,14 @@
    myprintf_buf[n_myprintf_buf] = 0;      
    ret = VG_(vprintf) ( add_to_myprintf_buf, format, vargs );
 
-   if (n_myprintf_buf > 0 && VG_(clo_logfile_fd) >= 0)
-      VG_(write)
-         ( VG_(clo_logfile_fd), myprintf_buf, n_myprintf_buf);
+   if (n_myprintf_buf > 0 && VG_(clo_logfile_fd) >= 0) {
+      if (VG_(logging_to_filedes))
+         VG_(write)
+            ( VG_(clo_logfile_fd), myprintf_buf, n_myprintf_buf);
+      else
+         VG_(write_socket)
+            ( VG_(clo_logfile_fd), myprintf_buf, n_myprintf_buf);
+   }
 
    va_end(vargs);
 
@@ -1422,6 +1432,212 @@
 }
 
 
+/* ---------------------------------------------------------------------
+   Gruesome hackery for connecting to a logging server over the network.
+   This is all very Linux-kernel specific.
+   ------------------------------------------------------------------ */
+
+/* Various needed constants from the kernel iface (2.4),
+   /usr/src/linux-2.4.9-31 */
+
+/* kernel, ./include/linux/net.h */
+#define SYS_SOCKET     1               /* sys_socket(2)        */
+#define SYS_CONNECT    3               /* sys_connect(2)       */
+#define SYS_SEND       9               /* sys_send(2)          */
+
+typedef UInt __u32;
+
+/* Internet address. */
+struct vki_in_addr {
+        __u32   s_addr;
+};
+
+/* kernel, include/linux/socket.h */
+typedef unsigned short  vki_sa_family_t;
+#define AF_INET                2       /* Internet IP Protocol        */
+
+/* kernel, ./include/asm-i386/socket.h */
+#define SOCK_STREAM 1                  /* stream (connection) socket  */
+
+/* kernel, /usr/src/linux-2.4.9-31/linux/include/in.h */
+/* Structure describing an Internet (IP) socket address. */
+#define __SOCK_SIZE__   16              /* sizeof(struct sockaddr)      */
+struct vki_sockaddr_in {
+  vki_sa_family_t       sin_family;     /* Address family               */
+  unsigned short int    sin_port;       /* Port number                  */
+  struct vki_in_addr    sin_addr;       /* Internet address             */
+
+  /* Pad to size of `struct sockaddr'. */
+  unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -
+                        sizeof(unsigned short int) - 
+                        sizeof(struct vki_in_addr)];
+};
+
+
+static
+Int parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port );
+
+static
+Int my_socket ( Int domain, Int type, Int protocol );
+
+static
+Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, 
+                 Int addrlen );
+
+static 
+UInt my_htonl ( UInt x )
+{
+   return
+      (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
+      | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
+}
+
+static
+UShort my_htons ( UShort x )
+{
+   return
+      (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
+}
+
+
+/* The main function. 
+
+   Supplied string contains either an ip address "192.168.0.1" or
+   an ip address and port pair, "192.168.0.1:1500".  Parse these,
+   and return:
+     -1 if there is a parse error
+     -2 if no parse error, but specified host:port cannot be opened
+     the relevant file (socket) descriptor, otherwise.
+   If no socket is specified, VG_CLO_DEFAULT_LOGSOCKET is used.
+*/
+Int VG_(connect_via_socket)( UChar* str )
+{
+   Int sd, res;
+   struct vki_sockaddr_in servAddr;
+   UInt   ip   = 0;
+   UShort port = VG_CLO_DEFAULT_LOGSOCKET;
+   Bool   ok   = parse_inet_addr_and_port(str, &ip, &port);
+   if (!ok) 
+      return -1;
+
+   if (0)
+      VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
+                  (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, 
+                  (ip >> 8) & 0xFF, ip & 0xFF, 
+	          (UInt)port );
+
+   servAddr.sin_family = AF_INET;
+   servAddr.sin_addr.s_addr = my_htonl(ip);
+   servAddr.sin_port = my_htons(port);
+
+   /* create socket */
+   sd = my_socket(AF_INET, SOCK_STREAM, 0 /* IPPROTO_IP ? */);
+   if (sd < 0) {
+     /* this shouldn't happen ... nevertheless */
+     return -2;
+   }
+			
+   /* connect to server */
+   res = my_connect(sd, (struct vki_sockaddr_in *) &servAddr, 
+                        sizeof(servAddr));
+   if (res < 0) {
+     /* connection failed */
+     return -2;
+   }
+
+   return sd;
+}
+
+
+/* Let d = one or more digits.  Accept either:
+   d.d.d.d  or  d.d.d.d:d
+*/
+Int parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port )
+{
+#  define GET_CH ((*str) ? (*str++) : 0)
+   UInt ipa, i, j, c, any;
+   ipa = 0;
+   for (i = 0; i < 4; i++) {
+      j = 0;
+      any = 0;
+      while (1) {
+         c = GET_CH; 
+         if (c < '0' || c > '9') break;
+         j = 10 * j + (int)(c - '0');
+         any = 1;
+      }
+      if (any == 0 || j > 255) goto syntaxerr;
+      ipa = (ipa << 8) + j;
+      if (i <= 2 && c != '.') goto syntaxerr;
+   }
+   if (c == 0 || c == ':') 
+      *ip_addr = ipa;
+   if (c == 0) goto ok;
+   if (c != ':') goto syntaxerr;
+   j = 0;
+   any = 0;
+   while (1) {
+      c = GET_CH; 
+      if (c < '0' || c > '9') break;
+      j = j * 10 + (int)(c - '0');
+      any = 1;
+      if (j > 65535) goto syntaxerr;
+   }
+   if (any == 0 || c != 0) goto syntaxerr;
+   *port = (UShort)j;
+ ok:
+   return 1;
+ syntaxerr:
+   return 0;
+#  undef GET_CH
+}
+
+
+static
+Int my_socket ( Int domain, Int type, Int protocol )
+{
+   Int res;
+   UInt args[3];
+   args[0] = domain;
+   args[1] = type;
+   args[2] = protocol;
+   res = vg_do_syscall2(__NR_socketcall, SYS_SOCKET, (UInt)&args);
+   if (VG_(is_kerror)(res)) 
+      res = -1;
+   return res;
+}
+
+static
+Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, 
+                 Int addrlen )
+{
+   Int res;
+   UInt args[3];
+   args[0] = sockfd;
+   args[1] = (UInt)serv_addr;
+   args[2] = addrlen;
+   res = vg_do_syscall2(__NR_socketcall, SYS_CONNECT, (UInt)&args);
+   if (VG_(is_kerror)(res)) 
+      res = -1;
+   return res;
+}
+
+Int VG_(write_socket)( Int sd, void *msg, Int count )
+{
+   /* This is actually send(). */
+   Int flags = 0;
+   Int res;
+   UInt args[4];
+   args[0] = sd;
+   args[1] = (UInt)msg;
+   args[2] = count;
+   args[3] = flags;
+   res = vg_do_syscall2(__NR_socketcall, SYS_SEND, (UInt)&args);
+   if (VG_(is_kerror)(res)) 
+      res = -1;
+   return res;
+}
+
 
 /*--------------------------------------------------------------------*/
 /*--- end                                              vg_mylibc.c ---*/