Give the code that computes protocol statistics a progress dialog box,
[obnox/wireshark/wip.git] / util.c
diff --git a/util.c b/util.c
index 2fe999b83f480a8457956b36f863e32fe9280b85..4f3bd2ebc7721ccc44659478de6ad95400c62279 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,7 +1,7 @@
 /* util.c
  * Utility routines
  *
- * $Id: util.c,v 1.33 2000/01/29 19:08:12 guy Exp $
+ * $Id: util.c,v 1.50 2001/03/22 06:14:27 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
 #endif
 
 #ifdef NEED_SNPRINTF_H
-# ifdef HAVE_STDARG_H
-#  include <stdarg.h>
-# else
-#  include <varargs.h>
-# endif
 # include "snprintf.h"
 #endif
 
@@ -80,7 +75,9 @@ typedef int mode_t;   /* for win32 */
 #include <sys/ioctl.h>
 #endif
 
-#ifdef HAVE_NET_IF_H
+#include <pcap.h>
+
+#ifndef WIN32
 #include <net/if.h>
 #endif
 
@@ -92,12 +89,57 @@ typedef int mode_t; /* for win32 */
 
 #endif
 
+/*
+ * Given a pathname, return:
+ *
+ *     the errno, if an attempt to "stat()" the file fails;
+ *
+ *     EISDIR, if the attempt succeeded and the file turned out
+ *     to be a directory;
+ *
+ *     0, if the attempt succeeded and the file turned out not
+ *     to be a directory.
+ */
+
+/*
+ * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
+ * define them either.)
+ *
+ * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
+ */
+#ifndef S_ISREG
+#define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
+#endif
+#ifndef S_IFIFO
+#define S_IFIFO        _S_IFIFO
+#endif
+#ifndef S_ISFIFO
+#define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
+#endif
+
+int
+test_for_directory(const char *path)
+{
+       struct stat statb;
+
+       if (stat(path, &statb) < 0)
+               return errno;
+
+       if (S_ISDIR(statb.st_mode))
+               return EISDIR;
+       else
+               return 0;
+}
+
 /*
  * Given a pathname, return a pointer to the last pathname separator
  * character in the pathname, or NULL if the pathname contains no
  * separators.
  */
-static char *
+char *
 find_last_pathname_separator(char *path)
 {
        char *separator;
@@ -183,6 +225,46 @@ get_dirname(char *path)
        return path;
 }
 
+/*
+ * Collect command-line arguments as a string consisting of the arguments,
+ * separated by spaces.
+ */
+char *
+get_args_as_string(int argc, char **argv, int optind)
+{
+       int len;
+       int i;
+       char *argstring;
+
+       /*
+        * Find out how long the string will be.
+        */
+       len = 0;
+       for (i = optind; i < argc; i++) {
+               len += strlen(argv[i]);
+               len++;  /* space, or '\0' if this is the last argument */
+       }
+
+       /*
+        * Allocate the buffer for the string.
+        */
+       argstring = g_malloc(len);
+
+       /*
+        * Now construct the string.
+        */
+       strcpy(argstring, "");
+       i = optind;
+       for (;;) {
+               strcat(argstring, argv[i]);
+               i++;
+               if (i == argc)
+                       break;
+               strcat(argstring, " ");
+       }
+       return argstring;
+}
+
 static char *
 setup_tmpdir(char *dir)
 {
@@ -416,6 +498,7 @@ search_for_if_cb(gpointer data, gpointer user_data);
 static void
 free_if_cb(gpointer data, gpointer user_data);
 
+#ifndef WIN32
 GList *
 get_interface_list(int *err, char *err_str)
 {
@@ -427,6 +510,8 @@ get_interface_list(int *err, char *err_str)
        int     sock = socket(AF_INET, SOCK_DGRAM, 0);
        struct search_user_data user_data;
        pcap_t *pch;
+       int len, lastlen;
+       char *buf;
 
        if (sock < 0) {
                sprintf(err_str, "Error opening socket: %s",
@@ -435,19 +520,36 @@ get_interface_list(int *err, char *err_str)
        }
 
        /*
-        * Since we have to grab the interface list all at once, we'll
-        * make plenty of room.
+        * This code came from: W. Richard Stevens: "UNIX Network Programming",
+        * Networking APIs: Sockets and XTI, Vol 1, page 434.
         */
-       ifc.ifc_len = 1024 * sizeof(struct ifreq);
-       ifc.ifc_buf = malloc(ifc.ifc_len);
-
-       if (ioctl(sock, SIOCGIFCONF, &ifc) < 0 ||
-           ifc.ifc_len < sizeof(struct ifreq)) {
-               sprintf(err_str, "SIOCGIFCONF error getting list of interfaces: %s",
-                   strerror(errno));
-               goto fail;
-        }
-
+       lastlen = 0;
+       len = 100 * sizeof(struct ifreq);
+       for ( ; ; ) {
+               buf = g_malloc(len);
+               ifc.ifc_len = len;
+               ifc.ifc_buf = buf;
+               memset (buf, 0, len);
+               if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+                       if (errno != EINVAL || lastlen != 0) {
+                               sprintf(err_str,
+                                       "SIOCGIFCONF ioctl error getting list of interfaces: %s",
+                                       strerror(errno));
+                               goto fail;
+                       }
+               } else {
+                       if (ifc.ifc_len < sizeof(struct ifreq)) {
+                               sprintf(err_str,
+                                       "SIOCGIFCONF ioctl gave too small return buffer");
+                               goto fail;
+                       }
+                       if (ifc.ifc_len == lastlen)
+                               break;                  /* success, len has not changed */
+                       lastlen = ifc.ifc_len;
+               }
+               len += 10 * sizeof(struct ifreq);       /* increment */
+               g_free(buf);
+       }
        ifr = (struct ifreq *) ifc.ifc_req;
        last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
        while (ifr < last) {
@@ -532,7 +634,24 @@ get_interface_list(int *err, char *err_str)
 #endif
        }
 
-       free(ifc.ifc_buf);
+#ifdef linux
+       /*
+        * OK, maybe we have support for the "any" device, to do a cooked
+        * capture on all interfaces at once.
+        * Try opening it and, if that succeeds, add it to the end of
+        * the list of interfaces.
+        */
+       pch = pcap_open_live("any", MIN_PACKET_SIZE, 0, 0, err_str);
+       if (pch != NULL) {
+               /*
+                * It worked; we can use the "any" device.
+                */
+               il = g_list_insert(il, g_strdup("any"), -1);
+               pcap_close(pch);
+       }
+#endif
+
+       g_free(ifc.ifc_buf);
        close(sock);
 
        if (il == NULL) {
@@ -548,7 +667,7 @@ fail:
                g_list_foreach(il, free_if_cb, NULL);
                g_list_free(il);
        }
-       free(ifc.ifc_buf);
+       g_free(ifc.ifc_buf);
        close(sock);
        *err = CANT_GET_INTERFACE_LIST;
        return NULL;
@@ -562,6 +681,54 @@ search_for_if_cb(gpointer data, gpointer user_data)
        if (strcmp((char *)data, search_user_data->name) == 0)
                search_user_data->found = TRUE;
 }
+#else
+GList *
+get_interface_list(int *err, char *err_str) {
+  GList  *il = NULL;
+  wchar_t *names;
+  char *win95names; 
+  char newname[255];
+  int i, j, done;
+  
+  names = (wchar_t *)pcap_lookupdev(err_str);
+  i = done = 0;
+
+  if (names) {
+         if (names[0]<256) { 
+                 /* If names[0] is less than 256 it means the first byte is 0
+                    This implies that we are using unicode characters */
+                 do 
+                 { 
+                         j = 0; 
+                         while (names[i] != 0) 
+                                 newname[j++] = names[i++]; 
+                         i++; 
+                         if (names[i] == 0) 
+                                 done = 1; 
+                         newname[j++] = 0; 
+                         il = g_list_append(il, g_strdup(newname)); 
+                 } while (!done); 
+         } 
+         else { 
+                 /* Otherwise we are in Windows 95/98 and using ascii(8 bit)
+                    characters */
+                 do 
+                 { 
+                         win95names=(char *)names; 
+                         j = 0; 
+                         while (win95names[i] != 0) 
+                                 newname[j++] = win95names[i++]; 
+                         i++; 
+                         if (win95names[i] == 0) 
+                                 done = 1; 
+                         newname[j++] = 0; 
+                         il = g_list_append(il, g_strdup(newname)); 
+                 } while (!done); 
+         } 
+  }
+  return(il);
+}
+#endif
 
 static void
 free_if_cb(gpointer data, gpointer user_data)
@@ -580,43 +747,47 @@ free_interface_list(GList *if_list)
 
 #endif /* HAVE_LIBPCAP */
 
-const char*
-get_home_dir(void)
-{
-       char *env_value;
-       static const char *home = NULL;
-#ifndef WIN32
-       uid_t uid;
-       struct passwd *pwd;
-#endif
-
-       /* Return the cached value, if available */
-       if (home)
-               return home;
-
-       env_value = getenv("HOME");
-
-       if (env_value) {
-               home = env_value;
-       }
-       else {
-#ifdef WIN32
-               /* XXX - on NT, get the user name and append it to
-                  "C:\winnt\profiles\"?
-                  What about Windows 9x? */
-               home = "C:"
-#else
-               uid = getuid();
-               pwd = getpwuid(uid);
-               if (pwd != NULL) {
-                       /* This is cached, so we don't need to worry
-                          about allocating multiple ones of them. */
-                       home = g_strdup(pwd->pw_dir);
-               }
-               else
-                       home = "/tmp";
-#endif
-       }
 
-       return home;
+/* Compute the difference between two seconds/microseconds time stamps. */
+void
+compute_timestamp_diff(gint *diffsec, gint *diffusec,
+       guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
+{
+  if (sec1 == sec2) {
+    /* The seconds part of the first time is the same as the seconds
+       part of the second time, so if the microseconds part of the first
+       time is less than the microseconds part of the second time, the
+       first time is before the second time.  The microseconds part of
+       the delta should just be the difference between the microseconds
+       part of the first time and the microseconds part of the second
+       time; don't adjust the seconds part of the delta, as it's OK if
+       the microseconds part is negative. */
+
+    *diffsec = sec1 - sec2;
+    *diffusec = usec1 - usec2;
+  } else if (sec1 <= sec2) {
+    /* The seconds part of the first time is less than the seconds part
+       of the second time, so the first time is before the second time.
+
+       Both the "seconds" and "microseconds" value of the delta
+       should have the same sign, so if the difference between the
+       microseconds values would be *positive*, subtract 1,000,000
+       from it, and add one to the seconds value. */
+    *diffsec = sec1 - sec2;
+    if (usec2 >= usec1) {
+      *diffusec = usec1 - usec2;
+    } else {
+      *diffusec = (usec1 - 1000000) - usec2;
+      (*diffsec)++;
+    }
+  } else {
+    /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
+    *diffsec = sec1 - sec2;
+    if (usec2 <= usec1) {
+      *diffusec = usec1 - usec2;
+    } else {
+      *diffusec = (usec1 + 1000000) - usec2;
+      (*diffsec)--;
+    }
+  }
 }