/src/wireshark/epan/register.c
Line | Count | Source |
1 | | /* register.c |
2 | | * Definitions for protocol registration |
3 | | * |
4 | | * Wireshark - Network traffic analyzer |
5 | | * By Gerald Combs <gerald@wireshark.org> |
6 | | * Copyright 1998 Gerald Combs |
7 | | * |
8 | | * SPDX-License-Identifier: GPL-2.0-or-later |
9 | | */ |
10 | | |
11 | | #include "register.h" |
12 | | #include "ws_attributes.h" |
13 | | |
14 | | #include <glib.h> |
15 | | |
16 | | #include <epan/exceptions.h> |
17 | | |
18 | | #include "epan/dissectors/dissectors.h" |
19 | | #include "epan/dissectors/event-dissectors.h" |
20 | | |
21 | | static const char *cur_cb_name; |
22 | | // We could use g_atomic_pointer_set/get instead of a mutex, but that causes |
23 | | // a false positive with Clang and TSAN for GLib < 2.64.0 (Issue #17753): |
24 | | // https://gitlab.gnome.org/GNOME/glib/-/issues/1843 |
25 | | static GMutex cur_cb_name_mtx; |
26 | | static GAsyncQueue *register_cb_done_q; |
27 | | |
28 | 0 | #define CB_WAIT_TIME (150 * 1000) // microseconds |
29 | | |
30 | 0 | static void set_cb_name(const char *proto) { |
31 | 0 | g_mutex_lock(&cur_cb_name_mtx); |
32 | 0 | cur_cb_name = proto; |
33 | 0 | g_mutex_unlock(&cur_cb_name_mtx); |
34 | 0 | } |
35 | | |
36 | | static void * |
37 | | register_all_protocols_worker(void *arg _U_) |
38 | 0 | { |
39 | 0 | void *volatile error_message = NULL; |
40 | |
|
41 | 0 | TRY { |
42 | 0 | for (unsigned long i = 0; i < dissector_reg_proto_count; i++) { |
43 | 0 | set_cb_name(dissector_reg_proto[i].cb_name); |
44 | 0 | dissector_reg_proto[i].cb_func(); |
45 | 0 | } |
46 | 0 | } |
47 | 0 | CATCH(DissectorError) { |
48 | | /* |
49 | | * This is probably a dissector, or something it calls, |
50 | | * calling REPORT_DISSECTOR_ERROR() in a registration |
51 | | * routine or something else outside the normal dissection |
52 | | * code path. |
53 | | * |
54 | | * The message gets freed by ENDTRY, so we must make a copy |
55 | | * of it. |
56 | | */ |
57 | 0 | error_message = g_strdup(GET_MESSAGE); |
58 | 0 | } |
59 | 0 | ENDTRY; |
60 | |
|
61 | 0 | g_async_queue_push(register_cb_done_q, GINT_TO_POINTER(true)); |
62 | 0 | return (void *) error_message; |
63 | 0 | } |
64 | | |
65 | | static void |
66 | | common_register_all_entities(dissector_reg_t const reg_proto[], unsigned long proto_count, GThreadFunc worker_func, register_cb cb, void* cb_data) |
67 | 14 | { |
68 | 14 | bool called_back = false; |
69 | 14 | if (!cb) { |
70 | 25.6k | for (unsigned long i = 0; i < proto_count; i++) { |
71 | 25.6k | reg_proto[i].cb_func(); |
72 | 25.6k | } |
73 | 14 | } |
74 | 0 | else { |
75 | 0 | const char* error_message; /* XXX - This isn't const, and should be freed. */ |
76 | 0 | const char* cb_name; |
77 | 0 | GThread* rapw_thread; |
78 | |
|
79 | 0 | register_cb_done_q = g_async_queue_new(); |
80 | 0 | rapw_thread = g_thread_new("register_all_protocols_worker", worker_func, NULL); |
81 | 0 | while (!g_async_queue_timeout_pop(register_cb_done_q, CB_WAIT_TIME)) { |
82 | 0 | g_mutex_lock(&cur_cb_name_mtx); |
83 | 0 | cb_name = cur_cb_name; |
84 | 0 | g_mutex_unlock(&cur_cb_name_mtx); |
85 | 0 | if (cb_name) { |
86 | 0 | cb(RA_REGISTER, cb_name, cb_data); |
87 | 0 | called_back = true; |
88 | 0 | } |
89 | 0 | } |
90 | 0 | error_message = (const char*)g_thread_join(rapw_thread); |
91 | 0 | if (error_message != NULL) |
92 | 0 | THROW_MESSAGE(DissectorError, error_message); |
93 | 0 | if (!called_back) { |
94 | 0 | cb(RA_REGISTER, "finished", cb_data); |
95 | 0 | } |
96 | 0 | } |
97 | 14 | } |
98 | | |
99 | | void |
100 | | register_all_protocols(register_cb cb, void *cb_data) |
101 | 14 | { |
102 | 14 | common_register_all_entities(dissector_reg_proto, dissector_reg_proto_count, ®ister_all_protocols_worker, cb, cb_data); |
103 | 14 | } |
104 | | |
105 | | static void * |
106 | | register_all_protocol_handoffs_worker(void *arg _U_) |
107 | 0 | { |
108 | 0 | void *volatile error_message = NULL; |
109 | |
|
110 | 0 | TRY { |
111 | 0 | for (unsigned long i = 0; i < dissector_reg_handoff_count; i++) { |
112 | 0 | set_cb_name(dissector_reg_handoff[i].cb_name); |
113 | 0 | dissector_reg_handoff[i].cb_func(); |
114 | 0 | } |
115 | 0 | } |
116 | 0 | CATCH(DissectorError) { |
117 | | /* |
118 | | * This is probably a dissector, or something it calls, |
119 | | * calling REPORT_DISSECTOR_ERROR() in a registration |
120 | | * routine or something else outside the normal dissection |
121 | | * code path. |
122 | | * |
123 | | * The message gets freed by ENDTRY, so we must make a copy |
124 | | * of it. |
125 | | */ |
126 | 0 | error_message = g_strdup(GET_MESSAGE); |
127 | 0 | } |
128 | 0 | ENDTRY; |
129 | |
|
130 | 0 | g_async_queue_push(register_cb_done_q, GINT_TO_POINTER(true)); |
131 | 0 | return (void *) error_message; |
132 | 0 | } |
133 | | |
134 | | static void |
135 | | common_register_all_handoffs(dissector_reg_t const reg_handoff[], unsigned long handoff_count, GThreadFunc worker_func, register_cb cb, void *cb_data) |
136 | 14 | { |
137 | 14 | if (!cb) { |
138 | 23.8k | for (unsigned long i = 0; i < handoff_count; i++) { |
139 | 23.8k | reg_handoff[i].cb_func(); |
140 | 23.8k | } |
141 | 14 | } |
142 | 0 | else { |
143 | 0 | bool called_back = false; |
144 | 0 | const char* error_message; /* XXX - This isn't const, and should be freed */ |
145 | 0 | const char* cb_name; |
146 | 0 | GThread* raphw_thread; |
147 | 0 | if (register_cb_done_q == NULL) { |
148 | 0 | register_cb_done_q = g_async_queue_new(); |
149 | 0 | } |
150 | 0 | set_cb_name(NULL); |
151 | 0 | raphw_thread = g_thread_new("register_all_protocol_handoffs_worker", worker_func, NULL); |
152 | 0 | while (!g_async_queue_timeout_pop(register_cb_done_q, CB_WAIT_TIME)) { |
153 | 0 | g_mutex_lock(&cur_cb_name_mtx); |
154 | 0 | cb_name = cur_cb_name; |
155 | 0 | g_mutex_unlock(&cur_cb_name_mtx); |
156 | 0 | if (cb_name) { |
157 | 0 | cb(RA_HANDOFF, cb_name, cb_data); |
158 | 0 | called_back = true; |
159 | 0 | } |
160 | 0 | } |
161 | 0 | error_message = (const char*)g_thread_join(raphw_thread); |
162 | 0 | if (error_message != NULL) |
163 | 0 | THROW_MESSAGE(DissectorError, error_message); |
164 | 0 | if (!called_back) { |
165 | 0 | cb(RA_HANDOFF, "finished", cb_data); |
166 | 0 | } |
167 | 0 | } |
168 | 14 | if (register_cb_done_q) { |
169 | 0 | g_async_queue_unref(register_cb_done_q); |
170 | 0 | } |
171 | 14 | } |
172 | | |
173 | | void |
174 | | register_all_protocol_handoffs(register_cb cb, void *cb_data) |
175 | 14 | { |
176 | 14 | common_register_all_handoffs(dissector_reg_handoff, dissector_reg_handoff_count, ®ister_all_protocol_handoffs_worker, cb, cb_data); |
177 | 14 | } |
178 | | |
179 | | unsigned long register_count(void) |
180 | 0 | { |
181 | 0 | return dissector_reg_proto_count + dissector_reg_handoff_count; |
182 | 0 | } |
183 | | |
184 | | static void* |
185 | | register_all_events_worker(void* arg _U_) |
186 | 0 | { |
187 | 0 | void* volatile error_message = NULL; |
188 | |
|
189 | 0 | TRY{ |
190 | 0 | for (unsigned long i = 0; i < event_dissector_reg_proto_count; i++) { |
191 | 0 | set_cb_name(event_dissector_reg_proto[i].cb_name); |
192 | 0 | event_dissector_reg_proto[i].cb_func(); |
193 | 0 | } |
194 | 0 | } |
195 | 0 | CATCH(DissectorError) { |
196 | | /* |
197 | | * This is probably a dissector, or something it calls, |
198 | | * calling REPORT_DISSECTOR_ERROR() in a registration |
199 | | * routine or something else outside the normal dissection |
200 | | * code path. |
201 | | * |
202 | | * The message gets freed by ENDTRY, so we must make a copy |
203 | | * of it. |
204 | | */ |
205 | 0 | error_message = g_strdup(GET_MESSAGE); |
206 | 0 | } |
207 | 0 | ENDTRY; |
208 | |
|
209 | 0 | g_async_queue_push(register_cb_done_q, GINT_TO_POINTER(true)); |
210 | 0 | return (void*)error_message; |
211 | 0 | } |
212 | | |
213 | | static void* |
214 | | register_all_event_handoffs_worker(void* arg _U_) |
215 | 0 | { |
216 | 0 | void* volatile error_message = NULL; |
217 | |
|
218 | 0 | TRY{ |
219 | 0 | for (unsigned long i = 0; i < event_dissector_reg_handoff_count; i++) { |
220 | 0 | set_cb_name(event_dissector_reg_handoff[i].cb_name); |
221 | 0 | event_dissector_reg_handoff[i].cb_func(); |
222 | 0 | } |
223 | 0 | } |
224 | 0 | CATCH(DissectorError) { |
225 | | /* |
226 | | * This is probably a dissector, or something it calls, |
227 | | * calling REPORT_DISSECTOR_ERROR() in a registration |
228 | | * routine or something else outside the normal dissection |
229 | | * code path. |
230 | | * |
231 | | * The message gets freed by ENDTRY, so we must make a copy |
232 | | * of it. |
233 | | */ |
234 | 0 | error_message = g_strdup(GET_MESSAGE); |
235 | 0 | } |
236 | 0 | ENDTRY; |
237 | |
|
238 | 0 | g_async_queue_push(register_cb_done_q, GINT_TO_POINTER(true)); |
239 | 0 | return (void*)error_message; |
240 | 0 | } |
241 | | |
242 | | void register_all_event_dissectors(register_cb cb, void* cb_data) |
243 | 0 | { |
244 | 0 | common_register_all_entities(event_dissector_reg_proto, event_dissector_reg_proto_count, ®ister_all_events_worker, cb, cb_data); |
245 | 0 | } |
246 | | |
247 | | void register_all_event_dissectors_handoffs(register_cb cb, void* cb_data) |
248 | 0 | { |
249 | 0 | common_register_all_handoffs(event_dissector_reg_handoff, event_dissector_reg_handoff_count, ®ister_all_event_handoffs_worker, cb, cb_data); |
250 | 0 | } |
251 | | |
252 | | /* |
253 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
254 | | * |
255 | | * Local Variables: |
256 | | * c-basic-offset: 4 |
257 | | * tab-width: 8 |
258 | | * indent-tabs-mode: nil |
259 | | * End: |
260 | | * |
261 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
262 | | * :indentSize=4:tabSize=8:noTabs=true: |
263 | | */ |