From ef0dd6c916ea4a17b0e389a47f0588f23e05e452 Mon Sep 17 00:00:00 2001
From: Robert Ricci <ricci@cs.utah.edu>
Date: Mon, 8 Jan 2007 22:50:25 +0000
Subject: [PATCH] Some code hygiene - created a new logpacket() function to do
 most of the logging. This cleans up a lot of code, and lets me (mostly)
 encapsulate information about which log messages contain what information in
 what version in a single place.

---
 pelab/libnetmon/libnetmon.c | 349 ++++++++++++++++++++++--------------
 pelab/libnetmon/libnetmon.h |  44 +++++
 2 files changed, 258 insertions(+), 135 deletions(-)

diff --git a/pelab/libnetmon/libnetmon.c b/pelab/libnetmon/libnetmon.c
index c711c7601c..e973adf2a5 100644
--- a/pelab/libnetmon/libnetmon.c
+++ b/pelab/libnetmon/libnetmon.c
@@ -107,10 +107,9 @@ void lnm_init() {
          */
 #define FIND_REAL_FUN(FUN) \
           real_##FUN = (FUN##_proto_t*)dlsym(RTLD_NEXT,#FUN); \
-          if (!real_##FUN) { \
+          if (!real_##FUN) \
               croak("Unable to get the address of " #FUN "(): %s\n", \
                     dlerror()); \
-          }
 
         FIND_REAL_FUN(socket);
         FIND_REAL_FUN(close);
@@ -126,7 +125,7 @@ void lnm_init() {
 
         /*
          * Connect to netmond if we've been asked to
-         */
+         */ 
 
         /*
          * If this is set at all, use the standard data and control sockets for
@@ -351,7 +350,8 @@ void lnm_control_wait() {
 }
 
 /*
- * Get the unique identifier for a connection
+ * 'Name' a file descriptor by getting a unique identifier for it - port
+ * numbers, IP addresses, etc.
  */
 void nameFD(int fd, const struct sockaddr *localname,
         const struct sockaddr *remotename) {
@@ -381,7 +381,6 @@ void nameFD(int fd, const struct sockaddr *localname,
      * later
      */
     monitorFDs[fd].remote_port = ntohs(remoteaddr->sin_port);
-    /* XXX Error checking */
     monitorFDs[fd].remote_hostname = inet_ntoa(remoteaddr->sin_addr);
 
     /*
@@ -402,10 +401,6 @@ void nameFD(int fd, const struct sockaddr *localname,
 
     monitorFDs[fd].local_port = ntohs(localaddr->sin_port);
 
-    monitorFDs[fd].connected = true;
-    if (report_connect) {
-        informConnect(fd);
-    }
 }
 
 /*
@@ -485,19 +480,7 @@ void startFD(int fd) {
      * reported in informConnect()
      */
     if (output_version >= 3) {
-        fprintf(outstream,"New: ");
-        fprintID(outstream,fd);
-        fprintf(outstream," ");
-        fprintTime(outstream);
-        fprintf(outstream," ");
-        if (socktype == SOCK_STREAM) {
-            fprintf(outstream,"TCP");
-        } else if (socktype == SOCK_DGRAM) {
-            fprintf(outstream,"UDP");
-        } else {
-            fprintf(outstream,"UNKNOWN");
-        }
-        fprintf(outstream,"\n");
+        printlog(LOG_NEW,fd,(socktype == SOCK_STREAM)?"TCP":"UDP");
     }
 
     monitorFDs[fd].monitoring = true;
@@ -521,13 +504,11 @@ void stopFD(int fd) {
     /*
      * Let the monitor know we're done with it
      */
-    if (output_version >= 2 && report_connect) {
-        fprintf(outstream,"Closed: ");
-        fprintID(outstream,fd);
-        fprintf(outstream,"\n");
-    }
+    printlog(LOG_CLOSED,fd);
 
     monitorFDs[fd].monitoring = false;
+
+    // XXX: Possible memory leak?
     if (monitorFDs[fd].remote_hostname != NULL) {
         monitorFDs[fd].remote_hostname = NULL;
     }
@@ -545,6 +526,158 @@ void stopWatchingAll() {
     }
 }
 
+void printlog(logmsg_t type, int fd, ...) {
+    /*
+     * A set of variables that turns on and off specific parts of the output
+     * string
+     */
+    bool print_name = true;
+    bool print_id = true;
+    bool print_timestamp = true;
+    bool print_value = true;
+
+    /*
+     * If this is set to false, we bypass logging completely.
+     */
+    bool print = true;
+
+    DEBUG(printf("printlog(%i,%i,...) called\n");)
+
+    /*
+     * Decide what to print based on the type of the log message and the output
+     * version
+     */
+    switch (type) {
+        case LOG_NEW:
+            // Old versions didn't print a timestamp or socket type
+            if (output_version < 3) { print_timestamp = print_value = false; }
+            break;
+        case LOG_REMOTEIP:
+            // This message only showed up in version 3
+            if (output_version < 3) { print = false; }
+            break;
+        case LOG_REMOTEPORT:
+            // This message only showed up in version 3
+            if (output_version < 3) { print = false; }
+            break;
+        case LOG_LOCALPORT:
+            // This message only showed up in version 1
+            if (output_version < 1) { print = false; }
+            // Old version didn't include a timestamp
+            if (output_version < 3) { print_timestamp = false; }
+            // Only report if we're also reporting connection info
+            if (!report_connect) { print = false; }
+            break;
+        case LOG_TCP_NODELAY:
+            // Old version didn't include a timestamp
+            if (output_version < 3) { print_timestamp = false; }
+            // This message only showed up in version 2
+            if (output_version < 2) { print = false; }
+            // Allow global turning on/off of this message type
+            if (!report_sockopt) { print = false; }
+            break;
+        case LOG_TCP_MAXSEG:
+            // Old version didn't include a timestamp
+            if (output_version < 3) { print_timestamp = false; }
+            // This message only showed up in version 2
+            if (output_version < 2) { print = false; }
+            // Allow global turning on/off of this message type
+            if (!report_sockopt) { print = false; }
+            break;
+        case LOG_SO_RCVBUF:
+            // Old version didn't include a timestamp
+            if (output_version < 3) { print_timestamp = false; }
+            // This message only showed up in version 2
+            if (output_version < 2) { print = false; }
+            // Allow global turning on/off of this message type
+            if (!report_sockopt) { print = false; }
+            break;
+        case LOG_SO_SNDBUF:
+            // Old version didn't include a timestamp
+            if (output_version < 3) { print_timestamp = false; }
+            // This message only showed up in version 2
+            if (output_version < 2) { print = false; }
+            // Allow global turning on/off of this message type
+            if (!report_sockopt) { print = false; }
+            break;
+        case LOG_CONNECTED:
+            // No Value
+            print_value = false;
+            // Old version didn't include a timestamp
+            if (output_version < 3) { print_timestamp = false; }
+            // This message only showed up in version 2
+            if (output_version < 2) { print = false; }
+            // Allow global turning on/off of this message type
+            if (!report_connect) { print = false; }
+            break;
+        case LOG_SEND:
+            // This should be handled by calling log_packet()
+            croak("LOG_SEND passed to printlog()");
+            break;
+        case LOG_SENDTO:
+            // This should be handled by calling log_packet()
+            croak("LOG_SENDTO passed to printlog()");
+            break;
+        case LOG_CLOSED:
+            // No Value
+            print_value = false;
+            // Old version didn't include a timestamp
+            if (output_version < 3) { print_timestamp = false; }
+            // This message only showed up in version 2
+            if (output_version < 2) { print = false; }
+            // Allow global turning on/off of this message type
+            if (!report_connect) { print = false; }
+            break;
+        default:
+            croak("Invalid type (%) passed to printlog()\n",type);
+    }
+
+    /*
+     * If we've decided not to print anything at all, bail now
+     */
+    if (!print) {
+        return;
+    }
+
+    /*
+     * Print out the name of the command
+     */
+    if (print_name) {
+        char *logname = log_type_names[type];
+        fprintf(outstream,"%s: ",logname);
+    }
+
+    /*
+     * Print out the ID of the socket the action is for
+     */
+    if (print_id) {
+        fprintID(outstream,fd);
+        fprintf(outstream," ");
+    }
+
+    /*
+     * Print out a timestamp
+     */
+    if (print_timestamp) {
+        fprintTime(outstream);
+        fprintf(outstream," ");
+    }
+
+    va_list ap;
+    va_start(ap,fd);
+    if (print_value) {
+        /*
+         * First variadic argument is the format string, which must be passed
+         * specially to vfprintf;
+         */
+        char *fmt = va_arg(ap,char*);
+        vfprintf(outstream,fmt,ap);
+    }
+    va_end(ap);
+
+    fprintf(outstream,"\n");
+}
+
 /*
  * Print the unique identifier for a connection to the given filestream
  */
@@ -791,7 +924,9 @@ bool connectedFD_p(int whichFD) {
 }
 
 /*
- * Let the user know that a packet has been sent.
+ * Let the user know that a packet has been sent. This function is, for now,
+ * seperate from printlog() because it prints out very different messages for
+ * early versions of the output format
  */
 void log_packet(int fd, size_t len, const struct sockaddr *srvaddr) {
     if (!report_io) {
@@ -874,106 +1009,57 @@ void log_packet(int fd, size_t len, const struct sockaddr *srvaddr) {
  * Inform the user that the nodelay flag has been changed
  */
 void informNodelay(int fd) {
-    if (monitorFDs[fd].socktype == SOCK_STREAM && output_version >= 2) {
-	fprintf(outstream,"TCP_NODELAY: ");
-	fprintID(outstream,fd);
-        if (output_version >= 3) {
-            fprintf(outstream," ");
-            fprintTime(outstream);
-        }
-	fprintf(outstream," %i\n",monitorFDs[fd].tcp_nodelay);
+    if (monitorFDs[fd].socktype == SOCK_STREAM) {
+        printlog(LOG_TCP_NODELAY, fd, "%i",monitorFDs[fd].tcp_nodelay);
     }
 }
 
 void informMaxseg(int fd) {
-    if (monitorFDs[fd].socktype == SOCK_STREAM && output_version >= 2) {
-	fprintf(outstream,"TCP_MAXSEG: ");
-	fprintID(outstream,fd);
-        if (output_version >= 3) {
-            fprintf(outstream," ");
-            fprintTime(outstream);
-        }
-	fprintf(outstream," %i\n",monitorFDs[fd].tcp_maxseg);
+    if (monitorFDs[fd].socktype == SOCK_STREAM) {
+        printlog(LOG_TCP_MAXSEG, fd, "%i",monitorFDs[fd].tcp_maxseg);
     }
 }
 
 void informBufsize(int fd, int which) {
-    int bufsize;
-    if (output_version >= 2) {
-	/* TODO: Handle bad which parameter */
-	if (which == SO_SNDBUF) {
-	    bufsize = monitorFDs[fd].sndbuf;
-	} else {
-	    bufsize = monitorFDs[fd].rcvbuf;
-	}
+    /* TODO: Handle bad which parameter */
+    printlog((which == SO_SNDBUF) ? LOG_SO_SNDBUF : LOG_SO_RCVBUF,
+             fd, "%i",
+             (which == SO_SNDBUF) ? monitorFDs[fd].sndbuf :
+                                    monitorFDs[fd].rcvbuf);
 
-	fprintf(outstream,"%s: ", (which == SO_SNDBUF) ?
-		"SO_SNDBUF" : "SO_RCVBUF");
-	fprintID(outstream,fd);
-        if (output_version >= 3) {
-            fprintf(outstream," ");
-            fprintTime(outstream);
-        }
-	fprintf(outstream," %i\n", bufsize);
-
-    }
 }
 
 void informConnect(int fd) {
-    if (output_version >= 2) {
-	/*
-         * Let the monitor know about it - note: if it's a UDP socket, we've
-         * already reported on it in startFD. Note that, for version 3, we
-         * report the existence of the socket earler, in startFD
-	 */
-        if ((output_version < 3) && monitorFDs[fd].socktype == SOCK_STREAM) {
-            fprintf(outstream,"New: ");
-            fprintID(outstream,fd);
-            fprintf(outstream," ");
-            fprintTime(outstream);
-            fprintf(outstream,"\n");
-        }
-
-        /*
-         * New versions of the output no longer include port numbers in the
-         * identifier. So, report those now. Note that we only do this for TCP
-         * sockets - UDP sockets will get this information reported with each
-         * sendto()
-         */
-        if (output_version >= 3 && monitorFDs[fd].socktype == SOCK_STREAM){
-            fprintf(outstream,"RemoteIP: ");
-            fprintID(outstream,fd);
-            fprintf(outstream," ");
-            fprintTime(outstream);
-            fprintf(outstream," %s",monitorFDs[fd].remote_hostname);
-            fprintf(outstream,"\n");
+    /*
+     * Let the monitor know about it - note: if it's a UDP socket, we've
+     * already reported on it in startFD. Note that, for version 3, we
+     * report the existence of the socket earler, in startFD
+     */
+    if ((output_version < 3) && monitorFDs[fd].socktype == SOCK_STREAM) {
+        printlog(LOG_NEW, fd,
+                 (monitorFDs[fd].socktype == SOCK_STREAM)?"TCP":"UDP");
+    }
 
-            fprintf(outstream,"RemotePort: ");
-            fprintID(outstream,fd);
-            fprintf(outstream," ");
-            fprintTime(outstream);
-            fprintf(outstream," %i",monitorFDs[fd].remote_port);
-            fprintf(outstream,"\n");
-        }
+    /*
+     * New versions of the output no longer include port numbers in the
+     * identifier. So, report those now. Note that we only do this for TCP
+     * sockets - UDP sockets will get this information reported with each
+     * sendto()
+     */
+    if (monitorFDs[fd].socktype == SOCK_STREAM){
+        printlog(LOG_REMOTEIP,fd,"%s",monitorFDs[fd].remote_hostname);
+        printlog(LOG_REMOTEPORT,fd,"%i",monitorFDs[fd].remote_port);
+    }
 
-	/*
-	 * Some things we report on for every connection
-	 */
-        if (report_sockopt) {
-            informNodelay(fd);
-            informMaxseg(fd);
-            informBufsize(fd, SO_RCVBUF);
-            informBufsize(fd, SO_SNDBUF);
-        }
+    /*
+     * Some things we report on for every connection
+     */
+    informNodelay(fd);
+    informMaxseg(fd);
+    informBufsize(fd, SO_RCVBUF);
+    informBufsize(fd, SO_SNDBUF);
 
-        if (report_connect) {
-            fprintf(outstream,"Connected: ");
-            fprintID(outstream,fd);
-            fprintf(outstream," ");
-            fprintTime(outstream);
-            fprintf(outstream,"\n");
-        }
-    }
+    printlog(LOG_CONNECTED,fd);
 }
 
 int getNewSockbuf(int fd, int which) {
@@ -998,7 +1084,6 @@ int getNewSockbuf(int fd, int which) {
 /*
  * Library function wrappers
  */
-
 int socket(int domain, int type, int protocol) {
     int returnedFD;
     lnm_init();
@@ -1041,6 +1126,7 @@ int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {
      */
     if (monitorFD_p(sockfd)) {
         nameFD(sockfd,NULL,serv_addr);
+        informConnect(sockfd);
     }
 
     rv = real_connect(sockfd, serv_addr, addrlen);
@@ -1069,6 +1155,7 @@ int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {
          * if they don't, and just write to it, we won't find out. So, for
          * now, just assume that the connect() will succeed.
          */
+        monitorFDs[sockfd].connected = true;
 
         /*
          * Get the local port number so that we can monitor it
@@ -1081,14 +1168,11 @@ int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {
         int local_port = ntohs(localaddr.sin_port);
         monitorFDs[sockfd].local_port = local_port;
 
-        if (report_connect && monitorFDs[sockfd].socktype == SOCK_STREAM) {
-            fprintf(outstream,"LocalPort: ");
-            fprintID(outstream,sockfd);
-            if (output_version >= 3) {
-                fprintf(outstream," ");
-                fprintTime(outstream);
-            }
-            fprintf(outstream," %i\n",local_port);
+        /*
+         * Report on the local port number
+         */
+        if (monitorFDs[sockfd].socktype == SOCK_STREAM) {
+            printlog(LOG_LOCALPORT,sockfd,"%i",local_port);
         }
     } else {
         /*
@@ -1124,16 +1208,12 @@ int accept(int s, struct sockaddr * addr,
          */
         startFD(rv);
         nameFD(rv,addr,NULL);
-        if (report_connect) {
-            fprintf(outstream,"LocalPort: ");
-            fprintID(outstream,rv);
-            if (output_version >= 3) {
-                fprintf(outstream," ");
-                fprintTime(outstream);
-            }
-            fprintf(outstream," %i\n",ntohs(((struct sockaddr_in*)addr)->sin_port));
-        }
+        informConnect(rv);
+        // XXX Accessors
+        monitorFDs[s].connected = 1;
         monitorFDs[s].local_port = ntohs(((struct sockaddr_in*)addr)->sin_port);
+        printlog(LOG_CONNECTED,rv);
+        printlog(LOG_LOCALPORT,rv,"%i",monitorFDs[s].local_port);
     }
 
     return rv;
@@ -1261,7 +1341,6 @@ ssize_t sendto(int fd, const void *buf, size_t count, int flags,
 
 }
 
-
 int setsockopt (int s, int level, int optname, const void *optval,
                  socklen_t optlen) {
     int rv;
@@ -1317,7 +1396,7 @@ int setsockopt (int s, int level, int optname, const void *optval,
 	     * not be exactly what the user asked for
 	     */
 	    getNewSockbuf(s,optname);
-	    if (connectedFD_p(s) && report_sockopt) {
+	    if (connectedFD_p(s)) {
 		informBufsize(s,optname);
 	    }
 	}
@@ -1329,7 +1408,7 @@ int setsockopt (int s, int level, int optname, const void *optval,
 	    if (optname == TCP_NODELAY) {
 		monitorFDs[s].tcp_nodelay = *((int *)optval);
 
-		if (connectedFD_p(s) && report_sockopt) {
+		if (connectedFD_p(s)) {
 		     /* If connected, inform user of this call */
 		    informNodelay(s);
 		}
@@ -1337,7 +1416,7 @@ int setsockopt (int s, int level, int optname, const void *optval,
 	    if (optname == TCP_MAXSEG) {
 		monitorFDs[s].tcp_maxseg = *((int *)optval);
 
-		if (connectedFD_p(s) && report_sockopt) {
+		if (connectedFD_p(s)) {
 		    /* If connected, inform user of this call */
 		    informMaxseg(s);
 		}
diff --git a/pelab/libnetmon/libnetmon.h b/pelab/libnetmon/libnetmon.h
index fea9d07bd1..fe434a26be 100644
--- a/pelab/libnetmon/libnetmon.h
+++ b/pelab/libnetmon/libnetmon.h
@@ -88,6 +88,50 @@ static bool monitorFD_p(int);
  */
 static bool connectedFD_p(int);
 
+/*
+ * Logging messages
+ */
+
+/*
+ * The types of log messages which are currently defined, and the associated
+ * ASCII strings
+ */
+typedef enum { LOG_NEW = 0,
+               LOG_REMOTEIP, 
+               LOG_REMOTEPORT,
+               LOG_LOCALPORT,
+               LOG_TCP_NODELAY,
+               LOG_TCP_MAXSEG,
+               LOG_SO_RCVBUF,
+               LOG_SO_SNDBUF,
+               LOG_CONNECTED,
+               LOG_SEND,
+               LOG_SENDTO,
+               LOG_CLOSED
+} logmsg_t;
+static char *log_type_names[] = {
+    "New",
+    "RemoteIP",
+    "RemotePort",
+    "LocalPort",
+    "TCP_NODELAY",
+    "TCP_MAXSEG",
+    "SO_RCVBUF",
+    "SO_SNDBUF",
+    "Connected",
+    "Send",
+    "SendTo",
+    "Closed"
+};
+
+/*
+ * Print out a log message. First argument is the type of the log mesage, the
+ * second is the file descriptor number, and the remaining arguments are
+ * processed like arguments to printf() (ie. a format string, then zero or more
+ * arguments to be interpolated into the format string)
+ */
+static void printlog(logmsg_t,int, ... );
+
 /*
  * Log that a packet has been sent to the kernel on a given FD with a given
  * size. If the final argument is non-NULL, then we are logging a packet from
-- 
GitLab