Change the -z args for expert item. You can now give the minimum severity level...
[obnox/wireshark/wip.git] / tap-expert.c
1 /* tap-expert.c
2  * Copyright 2011 Martin Mathieson
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
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
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <stdio.h>
31
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
34 #endif
35
36 #include <string.h>
37 #include <epan/packet.h>
38 #include <epan/packet_info.h>
39 #include <epan/tap.h>
40 #include <epan/stat_cmd_args.h>
41 #include <epan/expert.h>
42
43 /* Tap data */
44 typedef enum severity_level_t {
45     chat_level=0,
46     note_level,
47     warn_level,
48     error_level,
49     max_level
50 } severity_level_t;
51
52 /* This variable stores the lowest level that will be displayed.
53    May be changed from the command line */
54 static severity_level_t lowest_report_level = chat_level;
55
56 typedef struct expert_entry
57 {
58     int group;
59     const gchar *protocol;
60     gchar *summary;
61     int frequency;
62 } expert_entry;
63
64
65 /* Overall struct for storing all data seen */
66 typedef struct expert_tapdata_t {
67     GArray         *ei_array[max_level];   /* expert info items */
68     GStringChunk*  text;    /* for efficient storage of summary strings */
69 } expert_tapdata_t;
70
71
72 /* Reset expert stats */
73 static void
74 expert_stat_reset(void *tapdata)
75 {
76     gint n;
77     expert_tapdata_t *etd = tapdata;
78
79     /* Free & reallocate chunk of strings */
80     g_string_chunk_free(etd->text);
81     etd->text = g_string_chunk_new(100);
82
83     /* Empty each of the arrays */
84     for (n=0; n < max_level; n++) {
85         g_array_set_size(etd->ei_array[n], 0);
86     }
87 }
88
89 /* Process stat struct for an expert frame */
90 static int
91 expert_stat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_,
92                    const void *pointer)
93 {
94     expert_info_t    *ei = (expert_info_t *)pointer;
95     expert_tapdata_t *data = tapdata;
96     severity_level_t severity_level;
97     expert_entry     tmp_entry;
98     expert_entry     *entry;
99     guint            n;
100
101     switch (ei->severity) {
102         case PI_CHAT:
103             severity_level = chat_level;
104             break;
105         case PI_NOTE:
106             severity_level = note_level;
107             break;
108         case PI_WARN:
109             severity_level = warn_level;
110             break;
111         case PI_ERROR:
112             severity_level = error_level;
113             break;
114         default:
115             g_assert_not_reached();
116             return 0;
117     }
118
119     /* Don't store details at a lesser severity than we are interested in */
120     if (severity_level < lowest_report_level) {
121         return 1;
122     }
123
124     /* If a duplicate just bump up frequency.
125        TODO: could make more efficient by avoiding linear search...*/
126     for (n=0; n < data->ei_array[severity_level]->len; n++) {
127         entry = &g_array_index(data->ei_array[severity_level], expert_entry, n);
128         if ((strcmp(ei->protocol, entry->protocol) == 0) &&
129             (strcmp(ei->summary, entry->summary) == 0)) {
130             entry->frequency++;
131             return 1;
132         }
133     }
134
135     /* Else Add new item to end of list for severity level */
136     g_array_append_val(data->ei_array[severity_level], tmp_entry);
137
138     /* Get pointer to newly-allocated item */
139     entry = &g_array_index(data->ei_array[severity_level], expert_entry,
140                            data->ei_array[severity_level]->len - 1); /* ugly */
141     /* Copy/Store protocol and summary strings efficiently using GStringChunk */
142     entry->protocol = g_string_chunk_insert_const(data->text, ei->protocol);
143     entry->summary = g_string_chunk_insert_const(data->text, ei->summary);
144     entry->frequency = 1;
145
146     return 1;
147 }
148
149 /* Output for all of the items of one severity */
150 static void draw_items_for_severity(GArray *items, const gchar *label)
151 {
152     guint n;
153     expert_entry *ei;
154     int total = 0;
155
156     /* Don't print title if no items */
157     if (items->len == 0) {
158         return;
159     }
160
161     /* Add frequencies together to get total */
162     for (n=0; n < items->len; n++) {
163         ei = &g_array_index(items, expert_entry, n);
164         total += ei->frequency;
165     }
166
167     /* Title */
168     printf("\n%s (%u)\n", label, total);
169     printf("=============\n");
170
171     /* Column headings */
172     printf("   Frequency      Group            Protocol\n");
173
174     /* Items */
175     for (n=0; n < items->len; n++) {
176         ei = &g_array_index(items, expert_entry, n);
177         printf("%12u %10s %18s  %s\n", ei->frequency,
178               val_to_str(ei->group, expert_group_vals, "Unknown"),
179               ei->protocol, ei->summary);
180     }
181 }
182
183 /* (Re)draw expert stats */
184 static void
185 expert_stat_draw(void *phs _U_)
186 {
187     /* Look up the statistics struct */
188     expert_tapdata_t *hs = (expert_tapdata_t *)phs;
189
190     draw_items_for_severity(hs->ei_array[error_level], "Errors");
191     draw_items_for_severity(hs->ei_array[warn_level],  "Warns");
192     draw_items_for_severity(hs->ei_array[note_level],  "Notes");
193     draw_items_for_severity(hs->ei_array[chat_level],  "Chats");
194 }
195
196 /* Create a new expert stats struct */
197 static void expert_stat_init(const char *optarg, void *userdata _U_)
198 {
199     const char        *args = NULL;
200     const char        *filter = NULL;
201     GString           *error_string;
202     expert_tapdata_t  *hs;
203     int n;
204
205     /* Check for args. */
206     if (strncmp(optarg, "expert", 6) == 0) {
207         /* Skip those characters */
208         args = optarg + 6;
209     }
210     else {
211         /* No args. Will show all reports, with no filter */
212         lowest_report_level = max_level;
213     }
214
215     /* First (optional) arg is Error|Warn|Note|Chat */
216     if (args != NULL) {
217         if (strncasecmp(args, ",error", 6) == 0) {
218             lowest_report_level = error_level;
219             args += 6;
220         }
221         else if (strncasecmp(args, ",warn", 5) == 0) {
222             lowest_report_level = warn_level;
223             args += 5;
224         } else if (strncasecmp(args, ",note", 5) == 0) {
225             lowest_report_level = note_level;
226             args += 5;
227         } else if (strncasecmp(args, ",chat", 5) == 0) {
228             lowest_report_level = chat_level;
229             args += 5;
230         }
231     }
232
233     /* Second (optional) arg is a filter string */
234     if (args != NULL) {
235         if (args[0] == ',') {
236             filter = args+1;
237         }
238     }
239
240
241     /* Create top-level struct */
242     hs = g_malloc(sizeof(expert_tapdata_t));
243     memset(hs, 0,  sizeof(expert_tapdata_t));
244
245     /* Allocate chunk of strings */
246     hs->text = g_string_chunk_new(100);
247
248     /* Allocate GArray for each severity level */
249     for (n=0; n < max_level; n++) {
250         hs->ei_array[n] = g_array_sized_new(FALSE, FALSE, sizeof(expert_info_t), 1000);
251     }
252
253     /**********************************************/
254     /* Register the tap listener                  */
255     /**********************************************/
256
257     error_string = register_tap_listener("expert", hs,
258                                          filter, 0,
259                                          expert_stat_reset,
260                                          expert_stat_packet,
261                                          expert_stat_draw);
262     if (error_string) {
263         printf("Expert tap error (%s)!\n", error_string->str);
264         g_string_free(error_string, TRUE);
265         g_free(hs);
266         exit(1);
267     }
268 }
269
270
271 /* Register this tap listener (need void on own so line register function found) */
272 void
273 register_tap_listener_expert_info(void)
274 {
275     register_stat_cmd_arg("expert", expert_stat_init, NULL);
276 }
277