Move the stats.[ch] stuff into epan, so plugins can use it.
[obnox/wireshark/wip.git] / util.c
1 /* util.c
2  * Utility routines
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <glib.h>
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <errno.h>
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 #ifdef HAVE_SYS_STAT_H
41 #include <sys/stat.h>
42 #endif
43
44 #ifdef NEED_MKSTEMP
45 #include "mkstemp.h"
46 #endif
47
48 #ifdef HAVE_IO_H
49 #include <io.h>
50 #ifndef __MINGW32__
51 typedef int mode_t;     /* for win32 */
52 #endif /* __MINGW32__ */
53 #endif /* HAVE_IO_H */
54
55 #include <epan/address.h>
56 #include <epan/addr_resolv.h>
57
58 /*
59  * This has to come after the include of <pcap.h>, as the include of
60  * <pcap.h> might cause <winsock2.h> to be included, and if we've
61  * already included <winsock.h> as a result of including <windows.h>,
62  * we get a bunch of redefinitions.
63  */
64 #ifdef HAVE_WINDOWS_H
65 #include <windows.h>
66 #endif
67
68 #include "util.h"
69
70 /*
71  * Collect command-line arguments as a string consisting of the arguments,
72  * separated by spaces.
73  */
74 char *
75 get_args_as_string(int argc, char **argv, int optind)
76 {
77         int len;
78         int i;
79         char *argstring;
80
81         /*
82          * Find out how long the string will be.
83          */
84         len = 0;
85         for (i = optind; i < argc; i++) {
86                 len += strlen(argv[i]);
87                 len++;  /* space, or '\0' if this is the last argument */
88         }
89
90         /*
91          * Allocate the buffer for the string.
92          */
93         argstring = g_malloc(len);
94
95         /*
96          * Now construct the string.
97          */
98         strcpy(argstring, "");
99         i = optind;
100         for (;;) {
101                 strcat(argstring, argv[i]);
102                 i++;
103                 if (i == argc)
104                         break;
105                 strcat(argstring, " ");
106         }
107         return argstring;
108 }
109
110 static const char *
111 setup_tmpdir(const char *dir)
112 {
113         size_t len = strlen(dir);
114         char *newdir;
115
116         /* Append path separator if necessary */
117         if (len != 0 && dir[len - 1] == G_DIR_SEPARATOR) {
118                 return dir;
119         }
120         else {
121                 newdir = g_malloc(len + 2);
122                 strcpy(newdir, dir);
123                 strcat(newdir, G_DIR_SEPARATOR_S);
124                 return newdir;
125         }
126 }
127
128 static int
129 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
130 {
131         static const char suffix[] = "XXXXXXXXXX";
132         int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
133         mode_t old_umask;
134         int tmp_fd;
135
136         if (namebuflen < namelen) {
137                 /* Stick in a truncated name, so that if this error is
138                    reported with the file name, you at least get
139                    something. */
140                 g_snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
141                 errno = ENAMETOOLONG;
142                 return -1;
143         }
144         strcpy(namebuf, dir);
145         strcat(namebuf, pfx);
146         strcat(namebuf, suffix);
147
148         /* The Single UNIX Specification doesn't say that "mkstemp()"
149            creates the temporary file with mode rw-------, so we
150            won't assume that all UNIXes will do so; instead, we set
151            the umask to 0077 to take away all group and other
152            permissions, attempt to create the file, and then put
153            the umask back. */
154         old_umask = umask(0077);
155         tmp_fd = mkstemp(namebuf);
156         umask(old_umask);
157         return tmp_fd;
158 }
159
160 static const char *tmpdir = NULL;
161 #ifdef _WIN32
162 static char *temp = NULL;
163 #endif
164 static const char *E_tmpdir;
165
166 #ifndef P_tmpdir
167 #define P_tmpdir "/var/tmp"
168 #endif
169
170 int
171 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
172 {
173         char *dir;
174         int fd;
175         static gboolean initialized;
176
177         if (!initialized) {
178                 if ((dir = getenv("TMPDIR")) != NULL)
179                         tmpdir = setup_tmpdir(dir);
180 #ifdef _WIN32
181                 if ((dir = getenv("TEMP")) != NULL)
182                         temp = setup_tmpdir(dir);
183 #endif
184
185                 E_tmpdir = setup_tmpdir(P_tmpdir);
186                 initialized = TRUE;
187         }
188
189         if (tmpdir != NULL) {
190                 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
191                 if (fd != -1)
192                         return fd;
193         }
194
195 #ifdef _WIN32
196         if (temp != NULL) {
197                 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
198                 if (fd != -1)
199                         return fd;
200         }
201 #endif
202
203         fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
204         if (fd != -1)
205                 return fd;
206
207         return try_tempfile(namebuf, namebuflen, G_DIR_SEPARATOR_S "tmp", pfx);
208 }
209
210 /* Compute the difference between two seconds/microseconds time stamps. */
211 void
212 compute_timestamp_diff(gint *diffsec, gint *diffusec,
213         guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
214 {
215   if (sec1 == sec2) {
216     /* The seconds part of the first time is the same as the seconds
217        part of the second time, so if the microseconds part of the first
218        time is less than the microseconds part of the second time, the
219        first time is before the second time.  The microseconds part of
220        the delta should just be the difference between the microseconds
221        part of the first time and the microseconds part of the second
222        time; don't adjust the seconds part of the delta, as it's OK if
223        the microseconds part is negative. */
224
225     *diffsec = sec1 - sec2;
226     *diffusec = usec1 - usec2;
227   } else if (sec1 <= sec2) {
228     /* The seconds part of the first time is less than the seconds part
229        of the second time, so the first time is before the second time.
230
231        Both the "seconds" and "microseconds" value of the delta
232        should have the same sign, so if the difference between the
233        microseconds values would be *positive*, subtract 1,000,000
234        from it, and add one to the seconds value. */
235     *diffsec = sec1 - sec2;
236     if (usec2 >= usec1) {
237       *diffusec = usec1 - usec2;
238     } else {
239       *diffusec = (usec1 - 1000000) - usec2;
240       (*diffsec)++;
241     }
242   } else {
243     /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
244     *diffsec = sec1 - sec2;
245     if (usec2 <= usec1) {
246       *diffusec = usec1 - usec2;
247     } else {
248       *diffusec = (usec1 + 1000000) - usec2;
249       (*diffsec)--;
250     }
251   }
252 }
253
254 /* Try to figure out if we're remotely connected, e.g. via ssh or
255    Terminal Server, and create a capture filter that matches aspects of the
256    connection.  We match the following environment variables:
257
258    SSH_CONNECTION (ssh): <remote IP> <remote port> <local IP> <local port>
259    SSH_CLIENT (ssh): <remote IP> <remote port> <local port>
260    REMOTEHOST (tcsh, others?): <remote name>
261    DISPLAY (x11): [remote name]:<display num>
262    CLIENTNAME (terminal server): <remote name>
263  */
264
265 const gchar *get_conn_cfilter(void) {
266         static GString *filter_str = NULL;
267         gchar *env, **tokens;
268
269         if (filter_str == NULL) {
270                 filter_str = g_string_new("");
271         }
272         if ((env = getenv("SSH_CONNECTION")) != NULL) {
273                 tokens = g_strsplit(env, " ", 4);
274                 if (tokens[3]) {
275                         g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
276                                                          "and tcp port %s and %s host %s)", tokens[1], host_ip_af(tokens[0]), tokens[0],
277                                 tokens[3], host_ip_af(tokens[2]), tokens[2]);
278                         return filter_str->str;
279                 }
280         } else if ((env = getenv("SSH_CLIENT")) != NULL) {
281                 tokens = g_strsplit(env, " ", 3);
282                 g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
283                         "and tcp port %s)", tokens[1], host_ip_af(tokens[0]), tokens[0], tokens[2]);
284                 return filter_str->str;
285         } else if ((env = getenv("REMOTEHOST")) != NULL) {
286                 if (strcasecmp(env, "localhost") == 0 || strcmp(env, "127.0.0.1") == 0) {
287                         return "";
288                 }
289                 g_string_sprintf(filter_str, "not %s host %s", host_ip_af(env), env);
290                 return filter_str->str;
291         } else if ((env = getenv("DISPLAY")) != NULL) {
292                 tokens = g_strsplit(env, ":", 2);
293                 if (tokens[0] && tokens[0][0] != 0) {
294                         if (strcasecmp(tokens[0], "localhost") == 0 ||
295                                         strcmp(tokens[0], "127.0.0.1") == 0) {
296                                 return "";
297                         }
298                         g_string_sprintf(filter_str, "not %s host %s",
299                                 host_ip_af(tokens[0]), tokens[0]);
300                         return filter_str->str;
301                 }
302         } else if ((env = getenv("CLIENTNAME")) != NULL) {
303                 if (g_strcasecmp("console", env) != 0) {
304                         g_string_sprintf(filter_str, "not %s host %s", host_ip_af(env), env);
305                         return filter_str->str;
306                 }
307         }
308         return "";
309 }