update epan/dissectors/pidl/drsuapi/drsuapi.idl from samba
[wireshark-sm.git] / epan / wslua / wslua_listener.c
blob156ff690b72a57dafaba87eb119e934dee18377f
1 /*
2 * wslua_listener.c
4 * Wireshark's interface to the Lua Programming Language
6 * Implementation of tap Listeners
8 * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include "config.h"
18 #define WS_LOG_DOMAIN LOG_DOMAIN_WSLUA
20 /* WSLUA_MODULE Listener Post-Dissection Packet Analysis */
22 #include "wslua.h"
24 WSLUA_CLASS_DEFINE(Listener,FAIL_ON_NULL("Listener"));
26 A `Listener` is called once for every packet that matches a certain filter or has a certain tap.
27 It can read the tree, the packet's <<lua_class_Tvb,`Tvb`>> buffer as well as the tapped data, but it cannot add elements to the tree.
30 static int tap_packet_cb_error_handler(lua_State* L) {
31 const char* error = lua_tostring(L,1);
32 static char* last_error = NULL;
33 static int repeated = 0;
34 static int next = 2;
35 char* where = (lua_pinfo) ?
36 wmem_strdup_printf(NULL, "Lua: on packet %i Error during execution of Listener packet callback",lua_pinfo->num) :
37 wmem_strdup_printf(NULL, "Lua: Error during execution of Listener packet callback") ;
39 /* show the error the 1st, 3rd, 5th, 9th, 17th, 33th... time it appears to avoid window flooding */
40 /* XXX the last series of identical errors won't be shown (the user however gets at least one message) */
42 if (! last_error) {
43 report_failure("%s:\n%s",where,error);
44 last_error = g_strdup(error);
45 repeated = 0;
46 next = 2;
47 wmem_free(NULL, where);
48 return 0;
51 if (g_str_equal(last_error,error) ) {
52 repeated++;
53 if ( repeated == next ) {
54 report_failure("%s happened %i times:\n %s",where,repeated,error);
55 next *= 2;
57 } else {
58 report_failure("%s happened %i times:\n %s",where,repeated,last_error);
59 g_free(last_error);
60 last_error = g_strdup(error);
61 repeated = 0;
62 next = 2;
63 report_failure("%s:\n %s",where,error);
66 wmem_free(NULL, where);
67 return 0;
71 static tap_packet_status lua_tap_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data, tap_flags_t flags _U_) {
72 Listener tap = (Listener)tapdata;
73 tap_packet_status retval = TAP_PACKET_DONT_REDRAW;
74 TreeItem lua_tree_tap;
76 if (tap->packet_ref == LUA_NOREF) return TAP_PACKET_DONT_REDRAW; /* XXX - report error and return TAP_PACKET_FAILED? */
78 lua_settop(tap->L,0);
79 lua_pushcfunction(tap->L,tap_packet_cb_error_handler);
80 lua_rawgeti(tap->L, LUA_REGISTRYINDEX, tap->packet_ref);
82 push_Pinfo(tap->L, pinfo);
83 push_Tvb(tap->L, edt->tvb);
85 if (tap->extractor) {
86 tap->extractor(tap->L,data);
87 } else {
88 lua_pushnil(tap->L);
91 lua_pinfo = pinfo;
92 lua_tvb = edt->tvb;
93 lua_tree_tap = create_TreeItem(edt->tree, NULL);
94 lua_tree = lua_tree_tap;
96 switch ( lua_pcall(tap->L,3,1,1) ) {
97 case 0:
98 /* XXX - treat 2 as TAP_PACKET_FAILED? */
99 retval = luaL_optinteger(tap->L,-1,1) == 0 ? TAP_PACKET_DONT_REDRAW : TAP_PACKET_REDRAW;
100 break;
101 case LUA_ERRRUN:
102 /* XXX - TAP_PACKET_FAILED? */
103 break;
104 case LUA_ERRMEM:
105 ws_warning("Memory alloc error while calling listener tap callback packet");
106 /* XXX - TAP_PACKET_FAILED? */
107 break;
108 case LUA_ERRERR:
109 ws_warning("Error while running the error handler function for listener tap callback");
110 break;
111 default:
112 ws_assert_not_reached();
113 break;
116 clear_outstanding_Pinfo();
117 clear_outstanding_Tvb();
119 lua_pinfo = NULL;
120 lua_tvb = NULL;
121 lua_tree = NULL;
122 g_free(lua_tree_tap);
124 return retval;
127 static int tap_reset_cb_error_handler(lua_State* L) {
128 const char* error = lua_tostring(L,1);
129 report_failure("Lua: Error during execution of Listener reset callback:\n %s",error);
130 return 0;
133 static void lua_tap_reset(void *tapdata) {
134 Listener tap = (Listener)tapdata;
136 if (tap->reset_ref == LUA_NOREF) return;
138 lua_pushcfunction(tap->L,tap_reset_cb_error_handler);
139 lua_rawgeti(tap->L, LUA_REGISTRYINDEX, tap->reset_ref);
141 switch ( lua_pcall(tap->L,0,0,lua_gettop(tap->L)-1) ) {
142 case 0:
143 break;
144 case LUA_ERRRUN:
145 ws_warning("Runtime error while calling a listener's init()");
146 break;
147 case LUA_ERRMEM:
148 ws_warning("Memory alloc error while calling a listener's init()");
149 break;
150 case LUA_ERRERR:
151 ws_warning("Error while running the error handler function for a listener's init()");
152 break;
153 default:
154 ws_assert_not_reached();
155 break;
159 static int tap_draw_cb_error_handler(lua_State* L) {
160 const char* error = lua_tostring(L,1);
161 report_failure("Lua: Error during execution of Listener draw callback:\n %s",error);
162 return 0;
165 static void lua_tap_draw(void *tapdata) {
166 Listener tap = (Listener)tapdata;
167 const char* error;
169 if (tap->draw_ref == LUA_NOREF) return;
171 lua_pushcfunction(tap->L,tap_draw_cb_error_handler);
172 lua_rawgeti(tap->L, LUA_REGISTRYINDEX, tap->draw_ref);
174 switch ( lua_pcall(tap->L,0,0,lua_gettop(tap->L)-1) ) {
175 case 0:
176 /* OK */
177 break;
178 case LUA_ERRRUN:
179 error = lua_tostring(tap->L,-1);
180 ws_warning("Runtime error while calling a listener's draw(): %s",error);
181 break;
182 case LUA_ERRMEM:
183 ws_warning("Memory alloc error while calling a listener's draw()");
184 break;
185 case LUA_ERRERR:
186 ws_warning("Error while running the error handler function for a listener's draw()");
187 break;
188 default:
189 ws_assert_not_reached();
190 break;
194 /* TODO: we should probably use a Lua table here */
195 static GPtrArray *listeners;
197 static void deregister_Listener (lua_State* L _U_, Listener tap) {
198 if (tap->all_fields) {
199 epan_set_always_visible(false);
200 tap->all_fields = false;
203 remove_tap_listener(tap);
205 g_free(tap->filter);
206 g_free(tap->name);
207 g_free(tap);
210 WSLUA_CONSTRUCTOR Listener_new(lua_State* L) {
211 /* Creates a new `Listener` tap object. */
212 #define WSLUA_OPTARG_Listener_new_TAP 1 /* The name of this tap. See <<lua_fn_Listener_list__,`Listener.list()`>> for a way to print valid listener names. */
213 #define WSLUA_OPTARG_Listener_new_FILTER 2 /*
214 A display filter to apply to the tap.
215 The `tap.packet` function will be called for each matching packet.
216 The default is `nil`, which matches every packet.
217 Example: "m2tp".
219 #define WSLUA_OPTARG_Listener_new_ALLFIELDS 3 /*
220 Whether to generate all fields.
221 The default is `false`.
222 Note: This impacts performance. */
224 const char* tap_type = luaL_optstring(L,WSLUA_OPTARG_Listener_new_TAP,"frame");
225 const char* filter = luaL_optstring(L,WSLUA_OPTARG_Listener_new_FILTER,NULL);
226 const bool all_fields = wslua_optbool(L, WSLUA_OPTARG_Listener_new_ALLFIELDS, false);
227 Listener tap;
228 GString* error;
230 tap = (Listener)g_malloc(sizeof(struct _wslua_tap));
232 tap->name = g_strdup(tap_type);
233 tap->filter = g_strdup(filter);
234 tap->extractor = wslua_get_tap_extractor(tap_type);
235 tap->L = L;
236 tap->packet_ref = LUA_NOREF;
237 tap->draw_ref = LUA_NOREF;
238 tap->reset_ref = LUA_NOREF;
239 tap->all_fields = all_fields;
242 * XXX - do all Lua taps require the protocol tree? If not, it might
243 * be useful to have a way to indicate whether any do.
245 * XXX - do any Lua taps require the columns? If so, we either need
246 * to request them for this tap, or do so if any Lua taps require them.
248 error = register_tap_listener(tap_type, tap, tap->filter, TL_REQUIRES_PROTO_TREE, lua_tap_reset, lua_tap_packet, lua_tap_draw, NULL);
250 if (error) {
251 g_free(tap->filter);
252 g_free(tap->name);
253 g_free(tap);
254 /* WSLUA_ERROR(new_tap,"tap registration error"); */
255 lua_pushfstring(L,"Error while registering tap:\n%s",error->str);
256 g_string_free(error,TRUE);
257 return luaL_error(L,lua_tostring(L,-1));
260 if (all_fields) {
261 epan_set_always_visible(true);
264 g_ptr_array_add(listeners, tap);
266 pushListener(L,tap);
267 WSLUA_RETURN(1); /* The newly created Listener listener object */
270 /* Allow dissector key names to be sorted alphabetically */
271 static int
272 compare_dissector_key_name(const void *dissector_a, const void *dissector_b)
274 return strcmp((const char*)dissector_a, (const char*)dissector_b);
277 WSLUA_CONSTRUCTOR Listener_list (lua_State *L) { /*
278 Gets a Lua array table of all registered `Listener` tap names.
280 Note: This is an expensive operation, and should only be used for troubleshooting.
281 ===== Example
283 [source,lua]
284 ----
285 -- Print a list of tap listeners to stdout.
286 for _,tap_name in pairs(Listener.list()) do
287 print(tap_name)
289 ----
291 GList* list = get_tap_names();
292 GList* elist = NULL;
293 int i = 1;
295 if (!list) return luaL_error(L,"Cannot retrieve tap name list");
297 list = g_list_sort(list, (GCompareFunc)compare_dissector_key_name);
298 elist = g_list_first(list);
300 lua_newtable(L);
301 for (i=1; elist; i++, elist = g_list_next(elist)) {
302 lua_pushstring(L,(const char *) elist->data);
303 lua_rawseti(L,-2,i);
306 g_list_free(list);
307 WSLUA_RETURN(1); /* The array table of registered tap names */
310 WSLUA_METHOD Listener_remove(lua_State* L) {
311 /* Removes a tap `Listener`. */
312 Listener tap = checkListener(L,1);
314 if (listeners && g_ptr_array_remove(listeners, tap)) {
315 deregister_Listener(L, tap);
318 return 0;
321 WSLUA_METAMETHOD Listener__tostring(lua_State* L) {
322 /* Generates a string of debug info for the tap `Listener`. */
323 Listener tap = checkListener(L,1);
325 lua_pushfstring(L,"Listener(%s) filter: %s tapinfo: %s",tap->name, tap->filter ? tap->filter : "NONE", tap->extractor ? "YES": "NO");
327 return 1;
331 /* WSLUA_ATTRIBUTE Listener_packet WO A function that will be called once every packet matches the
332 `Listener` listener filter.
334 When later called by Wireshark, the `packet` function will be given:
335 1. A `Pinfo` object
336 2. A `Tvb` object
337 3. A `tapinfo` table
339 [source,lua]
340 ----
341 function tap.packet(pinfo,tvb,tapinfo) ... end
342 ----
344 [NOTE]
345 ====
346 `tapinfo` is a table of info based on the `Listener` type, or nil.
348 See _epan/wslua/taps_ for `tapinfo` structure definitions.
349 ====
351 WSLUA_ATTRIBUTE_FUNC_SETTER(Listener,packet);
354 /* WSLUA_ATTRIBUTE Listener_draw WO A function that will be called once every few seconds to redraw the GUI objects;
355 in TShark this function is called only at the very end of the capture file.
357 When later called by Wireshark, the `draw` function will not be given any arguments.
359 [source,lua]
360 ----
361 function tap.draw() ... end
362 ----
364 WSLUA_ATTRIBUTE_FUNC_SETTER(Listener,draw);
366 /* WSLUA_ATTRIBUTE Listener_reset WO A function that will be called at the end of the capture run.
368 When later called by Wireshark, the `reset` function will not be given any arguments.
370 [source,lua]
371 ----
372 function tap.reset() ... end
373 ----
375 WSLUA_ATTRIBUTE_FUNC_SETTER(Listener,reset);
378 static int Listener__gc(lua_State* L _U_) {
379 /* do NOT free Listener here, only in deregister_Listener */
380 return 0;
383 /* This table is ultimately registered as a sub-table of the class' metatable,
384 * and if __index/__newindex is invoked then it calls the appropriate function
385 * from this table for getting/setting the members.
387 WSLUA_ATTRIBUTES Listener_attributes[] = {
388 WSLUA_ATTRIBUTE_WOREG(Listener,packet),
389 WSLUA_ATTRIBUTE_WOREG(Listener,draw),
390 WSLUA_ATTRIBUTE_WOREG(Listener,reset),
391 { NULL, NULL, NULL }
394 WSLUA_METHODS Listener_methods[] = {
395 WSLUA_CLASS_FNREG(Listener,new),
396 WSLUA_CLASS_FNREG(Listener,remove),
397 WSLUA_CLASS_FNREG(Listener,list),
398 { NULL, NULL }
401 WSLUA_META Listener_meta[] = {
402 WSLUA_CLASS_MTREG(Listener,tostring),
403 { NULL, NULL }
406 int Listener_register(lua_State* L) {
407 wslua_set_tap_enums(L);
409 listeners = g_ptr_array_new();
411 WSLUA_REGISTER_CLASS_WITH_ATTRS(Listener);
412 return 0;
415 static void deregister_tap_listener (void *data, void *userdata) {
416 lua_State *L = (lua_State *) userdata;
417 Listener tap = (Listener) data;
418 deregister_Listener(L, tap);
421 int wslua_deregister_listeners(lua_State* L) {
422 g_ptr_array_foreach(listeners, deregister_tap_listener, L);
423 g_ptr_array_free(listeners, true);
424 listeners = NULL;
426 return 0;
430 * Editor modelines - https://www.wireshark.org/tools/modelines.html
432 * Local variables:
433 * c-basic-offset: 4
434 * tab-width: 8
435 * indent-tabs-mode: nil
436 * End:
438 * vi: set shiftwidth=4 tabstop=8 expandtab:
439 * :indentSize=4:tabSize=8:noTabs=true: