Use tcp_dissect_pdus().
[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_SNPRINTF_H
45 # include "snprintf.h"
46 #endif
47
48 #ifdef NEED_MKSTEMP
49 #include "mkstemp.h"
50 #endif
51
52 #ifdef HAVE_IO_H
53 #include <io.h>
54 #ifndef __MINGW32__
55 typedef int mode_t;     /* for win32 */
56 #endif /* __MINGW32__ */
57 #endif /* HAVE_IO_H */
58
59 #include <epan/address.h>
60 #include <epan/addr_resolv.h>
61
62 /*
63  * This has to come after the include of <pcap.h>, as the include of
64  * <pcap.h> might cause <winsock2.h> to be included, and if we've
65  * already included <winsock.h> as a result of including <windows.h>,
66  * we get a bunch of redefinitions.
67  */
68 #ifdef HAVE_WINDOWS_H
69 #include <windows.h>
70 #endif
71
72 #include "util.h"
73
74 /*
75  * Collect command-line arguments as a string consisting of the arguments,
76  * separated by spaces.
77  */
78 char *
79 get_args_as_string(int argc, char **argv, int optind)
80 {
81         int len;
82         int i;
83         char *argstring;
84
85         /*
86          * Find out how long the string will be.
87          */
88         len = 0;
89         for (i = optind; i < argc; i++) {
90                 len += strlen(argv[i]);
91                 len++;  /* space, or '\0' if this is the last argument */
92         }
93
94         /*
95          * Allocate the buffer for the string.
96          */
97         argstring = g_malloc(len);
98
99         /*
100          * Now construct the string.
101          */
102         strcpy(argstring, "");
103         i = optind;
104         for (;;) {
105                 strcat(argstring, argv[i]);
106                 i++;
107                 if (i == argc)
108                         break;
109                 strcat(argstring, " ");
110         }
111         return argstring;
112 }
113
114 static char *
115 setup_tmpdir(char *dir)
116 {
117         int len = strlen(dir);
118         char *newdir;
119
120         /* Append path separator if necessary */
121         if (dir[len - 1] == G_DIR_SEPARATOR) {
122                 newdir = dir;
123         }
124         else {
125                 newdir = g_malloc(len + 2);
126                 strcpy(newdir, dir);
127                 strcat(newdir, G_DIR_SEPARATOR_S);
128         }
129         return newdir;
130 }
131
132 static int
133 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
134 {
135         static const char suffix[] = "XXXXXXXXXX";
136         int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
137         mode_t old_umask;
138         int tmp_fd;
139
140         if (namebuflen < namelen) {
141                 /* Stick in a truncated name, so that if this error is
142                    reported with the file name, you at least get
143                    something. */
144                 snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
145                 errno = ENAMETOOLONG;
146                 return -1;
147         }
148         strcpy(namebuf, dir);
149         strcat(namebuf, pfx);
150         strcat(namebuf, suffix);
151
152         /* The Single UNIX Specification doesn't say that "mkstemp()"
153            creates the temporary file with mode rw-------, so we
154            won't assume that all UNIXes will do so; instead, we set
155            the umask to 0077 to take away all group and other
156            permissions, attempt to create the file, and then put
157            the umask back. */
158         old_umask = umask(0077);
159         tmp_fd = mkstemp(namebuf);
160         umask(old_umask);
161         return tmp_fd;
162 }
163
164 static char *tmpdir = NULL;
165 #ifdef _WIN32
166 static char *temp = NULL;
167 #endif
168 static char *E_tmpdir;
169
170 #ifndef P_tmpdir
171 #define P_tmpdir "/var/tmp"
172 #endif
173
174 int
175 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
176 {
177         char *dir;
178         int fd;
179         static gboolean initialized;
180
181         if (!initialized) {
182                 if ((dir = getenv("TMPDIR")) != NULL)
183                         tmpdir = setup_tmpdir(dir);
184 #ifdef _WIN32
185                 if ((dir = getenv("TEMP")) != NULL)
186                         temp = setup_tmpdir(dir);
187 #endif
188
189                 E_tmpdir = setup_tmpdir(P_tmpdir);
190                 initialized = TRUE;
191         }
192
193         if (tmpdir != NULL) {
194                 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
195                 if (fd != -1)
196                         return fd;
197         }
198
199 #ifdef _WIN32
200         if (temp != NULL) {
201                 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
202                 if (fd != -1)
203                         return fd;
204         }
205 #endif
206
207         fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
208         if (fd != -1)
209                 return fd;
210
211         return try_tempfile(namebuf, namebuflen, G_DIR_SEPARATOR_S "tmp", pfx);
212 }
213
214 /* Compute the difference between two seconds/microseconds time stamps. */
215 void
216 compute_timestamp_diff(gint *diffsec, gint *diffusec,
217         guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
218 {
219   if (sec1 == sec2) {
220     /* The seconds part of the first time is the same as the seconds
221        part of the second time, so if the microseconds part of the first
222        time is less than the microseconds part of the second time, the
223        first time is before the second time.  The microseconds part of
224        the delta should just be the difference between the microseconds
225        part of the first time and the microseconds part of the second
226        time; don't adjust the seconds part of the delta, as it's OK if
227        the microseconds part is negative. */
228
229     *diffsec = sec1 - sec2;
230     *diffusec = usec1 - usec2;
231   } else if (sec1 <= sec2) {
232     /* The seconds part of the first time is less than the seconds part
233        of the second time, so the first time is before the second time.
234
235        Both the "seconds" and "microseconds" value of the delta
236        should have the same sign, so if the difference between the
237        microseconds values would be *positive*, subtract 1,000,000
238        from it, and add one to the seconds value. */
239     *diffsec = sec1 - sec2;
240     if (usec2 >= usec1) {
241       *diffusec = usec1 - usec2;
242     } else {
243       *diffusec = (usec1 - 1000000) - usec2;
244       (*diffsec)++;
245     }
246   } else {
247     /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
248     *diffsec = sec1 - sec2;
249     if (usec2 <= usec1) {
250       *diffusec = usec1 - usec2;
251     } else {
252       *diffusec = (usec1 + 1000000) - usec2;
253       (*diffsec)--;
254     }
255   }
256 }
257
258 /* Try to figure out if we're remotely connected, e.g. via ssh or
259    Terminal Server, and create a capture filter that matches aspects of the
260    connection.  We match the following environment variables:
261
262    SSH_CONNECTION (ssh): <remote IP> <remote port> <local IP> <local port>
263    SSH_CLIENT (ssh): <remote IP> <remote port> <local port>
264    REMOTEHOST (tcsh, others?): <remote name>
265    DISPLAY (x11): [remote name]:<display num>
266    CLIENTNAME (terminal server): <remote name>
267  */
268
269 gchar *get_conn_cfilter(void) {
270         static GString *filter_str = NULL;
271         gchar *env, **tokens;
272
273         if (filter_str == NULL) {
274                 filter_str = g_string_new("");
275         }
276         if ((env = getenv("SSH_CONNECTION")) != NULL) {
277                 tokens = g_strsplit(env, " ", 4);
278                 if (tokens[3]) {
279                         g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
280                                                          "and tcp port %s and %s host %s)", tokens[1], host_ip_af(tokens[0]), tokens[0],
281                                 tokens[3], host_ip_af(tokens[2]), tokens[2]);
282                         return filter_str->str;
283                 }
284         } else if ((env = getenv("SSH_CLIENT")) != NULL) {
285                 tokens = g_strsplit(env, " ", 3);
286                 g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
287                         "and tcp port %s)", tokens[1], host_ip_af(tokens[0]), tokens[0], tokens[2]);
288                 return filter_str->str;
289         } else if ((env = getenv("REMOTEHOST")) != NULL) {
290                 if (strcasecmp(env, "localhost") == 0 || strcmp(env, "127.0.0.1") == 0) {
291                         return "";
292                 }
293                 g_string_sprintf(filter_str, "not %s host %s", host_ip_af(env), env);
294                 return filter_str->str;
295         } else if ((env = getenv("DISPLAY")) != NULL) {
296                 tokens = g_strsplit(env, ":", 2);
297                 if (tokens[0] && tokens[0][0] != 0) {
298                         if (strcasecmp(tokens[0], "localhost") == 0 ||
299                                         strcmp(tokens[0], "127.0.0.1") == 0) {
300                                 return "";
301                         }
302                         g_string_sprintf(filter_str, "not %s host %s",
303                                 host_ip_af(tokens[0]), tokens[0]);
304                         return filter_str->str;
305                 }
306         } else if ((env = getenv("CLIENTNAME")) != NULL) {
307                 if (g_strcasecmp("console", env) != 0) {
308                         g_string_sprintf(filter_str, "not %s host %s", host_ip_af(env), env);
309                         return filter_str->str;
310                 }
311         }
312         return "";
313 }