HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-gearman.c
blob5408cfbd78a292aef6a7a706c4500cd63f8f082c
1 /* packet-gearman.c
2 * Routines for Gearman protocol packet disassembly
3 * By Flier Lu <flier.lu@gmail.com>
4 * Copyright 2010 Flier Lu
6 * Gearman Protocol
7 * ----------------
8 * http://gearman.org/index.php?id=protocol
10 * $Id$
12 * Wireshark - Network traffic analyzer
13 * By Gerald Combs <gerald@wireshark.org>
14 * Copyright 1998 Gerald Combs
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include "config.h"
33 #include <epan/packet.h>
34 #include <epan/prefs.h>
35 #include <epan/expert.h>
36 #include "packet-tcp.h"
38 static int proto_gearman = -1;
40 static int hf_gearman_mgr_cmd = -1;
41 static int hf_gearman_magic_code = -1;
42 static int hf_gearman_pkt_type = -1;
43 static int hf_gearman_data_size = -1;
44 static int hf_gearman_data_content = -1;
45 static int hf_gearman_option_name = -1;
46 static int hf_gearman_func_name = -1;
47 static int hf_gearman_func_namez = -1;
48 static int hf_gearman_client_id = -1;
49 static int hf_gearman_uniq_id = -1;
50 static int hf_gearman_argument = -1;
51 static int hf_gearman_job_handle = -1;
52 static int hf_gearman_job_handlez = -1;
53 static int hf_gearman_complete_numerator = -1;
54 static int hf_gearman_complete_denominator = -1;
55 static int hf_gearman_submit_job_sched_minute = -1;
56 static int hf_gearman_submit_job_sched_hour = -1;
57 static int hf_gearman_submit_job_sched_day_of_month = -1;
58 static int hf_gearman_submit_job_sched_month = -1;
59 static int hf_gearman_submit_job_sched_day_of_week = -1;
60 static int hf_gearman_submit_job_epoch_time = -1;
61 static int hf_gearman_result = -1;
62 static int hf_gearman_known_status = -1;
63 static int hf_gearman_running_status = -1;
64 static int hf_gearman_echo_text = -1;
65 static int hf_gearman_err_code = -1;
66 static int hf_gearman_err_text = -1;
68 static gint ett_gearman = -1;
69 static gint ett_gearman_command = -1;
70 static gint ett_gearman_content = -1;
72 static expert_field ei_gearman_pkt_type_unknown = EI_INIT;
74 static gboolean gearman_desegment = TRUE;
76 static const int GEARMAN_COMMAND_HEADER_SIZE = 12;
77 static const int GEARMAN_PORT = 4730;
78 static const gchar *GEARMAN_MAGIC_CODE_REQUEST = "\0REQ";
79 static const gchar *GEARMAN_MAGIC_CODE_RESPONSE = "\0RES";
81 static const gchar *GEARMAN_MGR_CMDS[] = {
82 "workers",
83 "status",
84 "maxqueue",
85 "shutdown",
86 "version"
89 static const int GEARMAN_MGR_CMDS_COUNT = sizeof(GEARMAN_MGR_CMDS)/sizeof(GEARMAN_MGR_CMDS[0]);
91 typedef enum
93 GEARMAN_COMMAND_TEXT,
94 GEARMAN_COMMAND_CAN_DO, /* W->J: FUNC */
95 GEARMAN_COMMAND_CANT_DO, /* W->J: FUNC */
96 GEARMAN_COMMAND_RESET_ABILITIES, /* W->J: -- */
97 GEARMAN_COMMAND_PRE_SLEEP, /* W->J: -- */
98 GEARMAN_COMMAND_UNUSED,
99 GEARMAN_COMMAND_NOOP, /* J->W: -- */
100 GEARMAN_COMMAND_SUBMIT_JOB, /* C->J: FUNC[0]UNIQ[0]ARGS */
101 GEARMAN_COMMAND_JOB_CREATED, /* J->C: HANDLE */
102 GEARMAN_COMMAND_GRAB_JOB, /* W->J: -- */
103 GEARMAN_COMMAND_NO_JOB, /* J->W: -- */
104 GEARMAN_COMMAND_JOB_ASSIGN, /* J->W: HANDLE[0]FUNC[0]ARG */
105 GEARMAN_COMMAND_WORK_STATUS, /* W->J/C: HANDLE[0]NUMERATOR[0]DENOMINATOR */
106 GEARMAN_COMMAND_WORK_COMPLETE, /* W->J/C: HANDLE[0]RES */
107 GEARMAN_COMMAND_WORK_FAIL, /* W->J/C: HANDLE */
108 GEARMAN_COMMAND_GET_STATUS, /* C->J: HANDLE */
109 GEARMAN_COMMAND_ECHO_REQ, /* ?->J: TEXT */
110 GEARMAN_COMMAND_ECHO_RES, /* J->?: TEXT */
111 GEARMAN_COMMAND_SUBMIT_JOB_BG, /* C->J: FUNC[0]UNIQ[0]ARGS */
112 GEARMAN_COMMAND_ERROR, /* J->?: ERRCODE[0]ERR_TEXT */
113 GEARMAN_COMMAND_STATUS_RES, /* C->J: HANDLE[0]KNOWN[0]RUNNING[0]NUM[0]DENOM */
114 GEARMAN_COMMAND_SUBMIT_JOB_HIGH, /* C->J: FUNC[0]UNIQ[0]ARGS */
115 GEARMAN_COMMAND_SET_CLIENT_ID, /* W->J: [RANDOM_STRING_NO_WHITESPACE] */
116 GEARMAN_COMMAND_CAN_DO_TIMEOUT, /* W->J: FUNC[0]TIMEOUT */
117 GEARMAN_COMMAND_ALL_YOURS,
118 GEARMAN_COMMAND_WORK_EXCEPTION,
119 GEARMAN_COMMAND_OPTION_REQ,
120 GEARMAN_COMMAND_OPTION_RES,
121 GEARMAN_COMMAND_WORK_DATA,
122 GEARMAN_COMMAND_WORK_WARNING,
123 GEARMAN_COMMAND_GRAB_JOB_UNIQ,
124 GEARMAN_COMMAND_JOB_ASSIGN_UNIQ,
125 GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG,
126 GEARMAN_COMMAND_SUBMIT_JOB_LOW,
127 GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG,
128 GEARMAN_COMMAND_SUBMIT_JOB_SCHED,
129 GEARMAN_COMMAND_SUBMIT_JOB_EPOCH,
130 GEARMAN_COMMAND_MAX /* Always add new commands before this. */
131 } gearman_command_t;
133 static const value_string gearman_command_names[] = {
134 { GEARMAN_COMMAND_TEXT, "TEXT" },
135 { GEARMAN_COMMAND_CAN_DO, "CAN_DO" }, /* W->J: FUNC */
136 { GEARMAN_COMMAND_CANT_DO, "CANT_DO" }, /* W->J: FUNC */
137 { GEARMAN_COMMAND_RESET_ABILITIES, "RESET_ABILITIES" }, /* W->J: -- */
138 { GEARMAN_COMMAND_PRE_SLEEP, "PRE_SLEEP" }, /* W->J: -- */
139 { GEARMAN_COMMAND_UNUSED, "UNUSED" },
140 { GEARMAN_COMMAND_NOOP, "NOOP" }, /* J->W: -- */
141 { GEARMAN_COMMAND_SUBMIT_JOB, "SUBMIT_JOB" }, /* C->J: FUNC[0]UNIQ[0]ARGS */
142 { GEARMAN_COMMAND_JOB_CREATED, "JOB_CREATED" }, /* J->C: HANDLE */
143 { GEARMAN_COMMAND_GRAB_JOB, "GRAB_JOB" }, /* W->J: -- */
144 { GEARMAN_COMMAND_NO_JOB, "NO_JOB" }, /* J->W: -- */
145 { GEARMAN_COMMAND_JOB_ASSIGN, "JOB_ASSIGN" }, /* J->W: HANDLE[0]FUNC[0]ARG */
146 { GEARMAN_COMMAND_WORK_STATUS, "WORK_STATUS" }, /* W->J/C: HANDLE[0]NUMERATOR[0]DENOMINATOR */
147 { GEARMAN_COMMAND_WORK_COMPLETE, "WORK_COMPLETE" }, /* W->J/C: HANDLE[0]RES */
148 { GEARMAN_COMMAND_WORK_FAIL, "WORK_FAIL" }, /* W->J/C: HANDLE */
149 { GEARMAN_COMMAND_GET_STATUS, "GET_STATUS" }, /* C->J: HANDLE */
150 { GEARMAN_COMMAND_ECHO_REQ, "ECHO_REQ" }, /* ?->J: TEXT */
151 { GEARMAN_COMMAND_ECHO_RES, "ECHO_RES" }, /* J->?: TEXT */
152 { GEARMAN_COMMAND_SUBMIT_JOB_BG, "SUBMIT_JOB_BG" }, /* C->J: FUNC[0]UNIQ[0]ARGS */
153 { GEARMAN_COMMAND_ERROR, "ERROR" }, /* J->?: ERRCODE[0]ERR_TEXT */
154 { GEARMAN_COMMAND_STATUS_RES, "STATUS_RES" }, /* C->J: HANDLE[0]KNOWN[0]RUNNING[0]NUM[0]DENOM */
155 { GEARMAN_COMMAND_SUBMIT_JOB_HIGH, "SUBMIT_JOB_HIGH" }, /* C->J: FUNC[0]UNIQ[0]ARGS */
156 { GEARMAN_COMMAND_SET_CLIENT_ID, "SET_CLIENT_ID" }, /* W->J: [RANDOM_STRING_NO_WHITESPACE] */
157 { GEARMAN_COMMAND_CAN_DO_TIMEOUT, "CAN_DO_TIMEOUT" }, /* W->J: FUNC[0]TIMEOUT */
158 { GEARMAN_COMMAND_ALL_YOURS, "ALL_YOURS" },
159 { GEARMAN_COMMAND_WORK_EXCEPTION, "WORK_EXCEPTION" },
160 { GEARMAN_COMMAND_OPTION_REQ, "OPTION_REQ" },
161 { GEARMAN_COMMAND_OPTION_RES, "OPTION_RES" },
162 { GEARMAN_COMMAND_WORK_DATA, "WORK_DATA" },
163 { GEARMAN_COMMAND_WORK_WARNING, "WORK_WARNING" },
164 { GEARMAN_COMMAND_GRAB_JOB_UNIQ, "GRAB_JOB_UNIQ" },
165 { GEARMAN_COMMAND_JOB_ASSIGN_UNIQ, "JOB_ASSIGN_UNIQ" },
166 { GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG, "SUBMIT_JOB_HIGH_BG" },
167 { GEARMAN_COMMAND_SUBMIT_JOB_LOW, "SUBMIT_JOB_LOW" },
168 { GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG, "SUBMIT_JOB_LOW_BG" },
169 { GEARMAN_COMMAND_SUBMIT_JOB_SCHED, "SUBMIT_JOB_SCHED" },
170 { GEARMAN_COMMAND_SUBMIT_JOB_EPOCH, "SUBMIT_JOB_EPOCH" },
171 { 0, NULL}
174 static guint
175 get_gearman_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
177 return tvb_get_ntohl(tvb, offset+8)+GEARMAN_COMMAND_HEADER_SIZE;
180 static int
181 dissect_binary_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
183 gint offset, start_offset;
184 char *magic_code;
185 guint32 type, size;
186 guint len;
187 proto_item *content_item = NULL;
188 proto_tree *content_tree = NULL;
190 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Gearman");
191 col_clear(pinfo->cinfo,COL_INFO);
193 magic_code = tvb_get_string(wmem_packet_scope(), tvb, 1, 3);
194 type = tvb_get_ntohl(tvb, 4);
195 size = tvb_get_ntohl(tvb, 8);
197 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " , ", "[%s] ", magic_code);
199 col_append_fstr(pinfo->cinfo, COL_INFO, "%s(%d) LEN=%d",
200 val_to_str(type, gearman_command_names, "Unknown (0x%08x)"), type, size);
202 if (tree) {
203 proto_item *ti;
204 proto_tree *command_tree, *gearman_tree;
205 ti = proto_tree_add_item(tree, proto_gearman, tvb, 0, -1, ENC_NA);
206 gearman_tree = proto_item_add_subtree(ti, ett_gearman);
208 ti = proto_tree_add_text(gearman_tree, tvb, 0, GEARMAN_COMMAND_HEADER_SIZE+size,
209 "[%s] %s(%d) LEN=%d", magic_code, val_to_str(type, gearman_command_names, "Unknown (0x%08x)"), type, size);
210 command_tree = proto_item_add_subtree(ti, ett_gearman_command);
212 proto_tree_add_string(command_tree, hf_gearman_magic_code, tvb, 0, 4, magic_code);
213 proto_tree_add_item(command_tree, hf_gearman_pkt_type, tvb, 4, 4, ENC_BIG_ENDIAN);
214 proto_tree_add_item(command_tree, hf_gearman_data_size, tvb, 8, 4, ENC_BIG_ENDIAN);
216 content_item = proto_tree_add_item(command_tree, hf_gearman_data_content, tvb, GEARMAN_COMMAND_HEADER_SIZE, size, ENC_ASCII|ENC_NA);
217 content_tree = proto_item_add_subtree(content_item, ett_gearman_content);
220 offset = GEARMAN_COMMAND_HEADER_SIZE;
222 switch(type)
224 case GEARMAN_COMMAND_ECHO_REQ:
225 case GEARMAN_COMMAND_ECHO_RES:
226 if (!tree) break;
227 proto_tree_add_item(content_tree, hf_gearman_echo_text, tvb,
228 offset, size, ENC_NA|ENC_ASCII);
229 break;
231 case GEARMAN_COMMAND_ERROR:
232 if (!tree) break;
233 len = tvb_strsize(tvb, offset);
234 proto_tree_add_item(content_tree, hf_gearman_err_code, tvb, offset, len, ENC_NA|ENC_ASCII);
235 proto_tree_add_item(content_tree, hf_gearman_err_text, tvb, offset+len, size-len, ENC_NA|ENC_ASCII);
236 break;
238 case GEARMAN_COMMAND_JOB_CREATED:
239 case GEARMAN_COMMAND_WORK_FAIL:
240 if (!tree) break;
241 proto_tree_add_item(content_tree, hf_gearman_job_handle, tvb,
242 offset, size, ENC_NA|ENC_ASCII);
243 break;
245 case GEARMAN_COMMAND_STATUS_RES:
246 if (!tree) break;
247 start_offset = offset;
248 len = tvb_strsize(tvb, start_offset);
249 proto_tree_add_item(content_tree, hf_gearman_job_handlez, tvb, start_offset, len, ENC_NA|ENC_ASCII);
251 start_offset += len;
252 len = tvb_strsize(tvb, start_offset);
253 proto_tree_add_item(content_tree, hf_gearman_known_status, tvb, start_offset, len, ENC_NA|ENC_ASCII);
255 start_offset += len;
256 len = tvb_strsize(tvb, start_offset);
257 proto_tree_add_item(content_tree, hf_gearman_running_status, tvb, start_offset, len, ENC_NA|ENC_ASCII);
259 start_offset += len;
260 len = tvb_strsize(tvb, start_offset);
261 proto_tree_add_item(content_tree, hf_gearman_complete_numerator, tvb, start_offset, len, ENC_NA|ENC_ASCII);
263 proto_tree_add_item(content_tree, hf_gearman_complete_denominator, tvb, start_offset+len, size-start_offset+GEARMAN_COMMAND_HEADER_SIZE, ENC_NA|ENC_ASCII);
264 break;
266 case GEARMAN_COMMAND_OPTION_REQ:
267 case GEARMAN_COMMAND_OPTION_RES:
268 if (!tree) break;
269 proto_tree_add_item(content_tree, hf_gearman_option_name, tvb,
270 offset, size, ENC_NA|ENC_ASCII);
271 break;
273 case GEARMAN_COMMAND_SUBMIT_JOB:
274 case GEARMAN_COMMAND_SUBMIT_JOB_BG:
275 case GEARMAN_COMMAND_SUBMIT_JOB_HIGH:
276 case GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG:
277 case GEARMAN_COMMAND_SUBMIT_JOB_LOW:
278 case GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG:
279 if (!tree) break;
280 start_offset = offset;
281 len = tvb_strsize(tvb, start_offset);
282 proto_tree_add_item(content_tree, hf_gearman_func_name, tvb, start_offset, len, ENC_NA|ENC_ASCII);
284 start_offset += len;
285 len = tvb_strsize(tvb, start_offset);
286 proto_tree_add_item(content_tree, hf_gearman_uniq_id, tvb, start_offset, len, ENC_NA|ENC_ASCII);
288 proto_tree_add_item(content_tree, hf_gearman_argument, tvb, start_offset+len, size-start_offset+GEARMAN_COMMAND_HEADER_SIZE, ENC_NA|ENC_ASCII);
289 break;
291 case GEARMAN_COMMAND_SUBMIT_JOB_SCHED:
292 if (!tree) break;
293 start_offset = offset;
294 len = tvb_strsize(tvb, start_offset);
295 proto_tree_add_item(content_tree, hf_gearman_func_name, tvb, start_offset, len, ENC_NA|ENC_ASCII);
297 start_offset += len;
298 len = tvb_strsize(tvb, start_offset);
299 proto_tree_add_item(content_tree, hf_gearman_uniq_id, tvb, start_offset, len, ENC_NA|ENC_ASCII);
301 start_offset += len;
302 len = tvb_strsize(tvb, start_offset);
303 proto_tree_add_item(content_tree, hf_gearman_submit_job_sched_minute, tvb, start_offset, len, ENC_NA|ENC_ASCII);
305 start_offset += len;
306 len = tvb_strsize(tvb, start_offset);
307 proto_tree_add_item(content_tree, hf_gearman_submit_job_sched_hour, tvb, start_offset, len, ENC_NA|ENC_ASCII);
309 start_offset += len;
310 len = tvb_strsize(tvb, start_offset);
311 proto_tree_add_item(content_tree, hf_gearman_submit_job_sched_day_of_month, tvb, start_offset, len, ENC_NA|ENC_ASCII);
313 start_offset += len;
314 len = tvb_strsize(tvb, start_offset);
315 proto_tree_add_item(content_tree, hf_gearman_submit_job_sched_month, tvb, start_offset, len, ENC_NA|ENC_ASCII);
317 start_offset += len;
318 len = tvb_strsize(tvb, start_offset);
319 proto_tree_add_item(content_tree, hf_gearman_submit_job_sched_day_of_week, tvb, start_offset, len, ENC_NA|ENC_ASCII);
321 proto_tree_add_item(content_tree, hf_gearman_argument, tvb, start_offset+len, size-start_offset+GEARMAN_COMMAND_HEADER_SIZE, ENC_NA|ENC_ASCII);
322 break;
324 case GEARMAN_COMMAND_SUBMIT_JOB_EPOCH:
325 if (!tree) break;
326 start_offset = offset;
327 len = tvb_strsize(tvb, start_offset);
328 proto_tree_add_item(content_tree, hf_gearman_func_name, tvb, start_offset, len, ENC_NA|ENC_ASCII);
330 start_offset += len;
331 len = tvb_strsize(tvb, start_offset);
332 proto_tree_add_item(content_tree, hf_gearman_uniq_id, tvb, start_offset, len, ENC_NA|ENC_ASCII);
334 start_offset += len;
335 len = tvb_strsize(tvb, start_offset);
336 proto_tree_add_item(content_tree, hf_gearman_submit_job_epoch_time, tvb, start_offset, len, ENC_NA|ENC_ASCII);
338 proto_tree_add_item(content_tree, hf_gearman_argument, tvb, start_offset+len, size-start_offset+GEARMAN_COMMAND_HEADER_SIZE, ENC_NA|ENC_ASCII);
339 break;
341 case GEARMAN_COMMAND_JOB_ASSIGN:
342 start_offset = offset;
343 len = tvb_strsize(tvb, start_offset);
344 proto_tree_add_item(content_tree, hf_gearman_job_handlez, tvb, start_offset, len, ENC_NA|ENC_ASCII);
346 start_offset += len;
347 len = tvb_strsize(tvb, start_offset);
348 proto_tree_add_item(content_tree, hf_gearman_func_namez, tvb, start_offset, len, ENC_NA|ENC_ASCII);
350 proto_tree_add_item(content_tree, hf_gearman_argument, tvb, start_offset+len, size-start_offset+GEARMAN_COMMAND_HEADER_SIZE, ENC_NA|ENC_ASCII);
351 break;
353 case GEARMAN_COMMAND_JOB_ASSIGN_UNIQ:
354 start_offset = offset;
355 len = tvb_strsize(tvb, start_offset);
356 proto_tree_add_item(content_tree, hf_gearman_job_handlez, tvb, start_offset, len, ENC_NA|ENC_ASCII);
358 start_offset += len;
359 len = tvb_strsize(tvb, start_offset);
360 proto_tree_add_item(content_tree, hf_gearman_func_namez, tvb, start_offset, len, ENC_NA|ENC_ASCII);
362 start_offset += len;
363 len = tvb_strsize(tvb, start_offset);
364 proto_tree_add_item(content_tree, hf_gearman_uniq_id, tvb, start_offset, len, ENC_NA|ENC_ASCII);
366 proto_tree_add_item(content_tree, hf_gearman_argument, tvb, start_offset+len, size-start_offset+GEARMAN_COMMAND_HEADER_SIZE, ENC_NA|ENC_ASCII);
367 break;
369 case GEARMAN_COMMAND_CAN_DO:
370 case GEARMAN_COMMAND_CANT_DO:
371 if (!tree) break;
372 proto_tree_add_item(content_tree, hf_gearman_func_name, tvb,
373 offset, size, ENC_NA|ENC_ASCII);
374 break;
376 case GEARMAN_COMMAND_CAN_DO_TIMEOUT:
377 if (!tree) break;
378 proto_tree_add_item(content_tree, hf_gearman_func_name, tvb,
379 offset, tvb_strsize(tvb, offset), ENC_NA|ENC_ASCII);
380 break;
382 case GEARMAN_COMMAND_WORK_DATA:
383 case GEARMAN_COMMAND_WORK_WARNING:
384 case GEARMAN_COMMAND_WORK_COMPLETE:
385 case GEARMAN_COMMAND_WORK_EXCEPTION:
386 if (!tree) break;
387 len = tvb_strsize(tvb, offset);
388 proto_tree_add_item(content_tree, hf_gearman_job_handlez, tvb, offset, len, ENC_NA|ENC_ASCII);
389 proto_tree_add_item(content_tree, hf_gearman_result, tvb, offset+len, size-len, ENC_NA|ENC_ASCII);
390 break;
392 case GEARMAN_COMMAND_WORK_STATUS:
393 if (!tree) break;
394 start_offset = offset;
395 len = tvb_strsize(tvb, start_offset);
396 proto_tree_add_item(content_tree, hf_gearman_job_handlez, tvb, start_offset, len, ENC_NA|ENC_ASCII);
398 start_offset += len;
399 len = tvb_strsize(tvb, start_offset);
400 proto_tree_add_item(content_tree, hf_gearman_complete_numerator, tvb, start_offset, len, ENC_NA|ENC_ASCII);
402 proto_tree_add_item(content_tree, hf_gearman_complete_denominator, tvb, start_offset+len, size-start_offset+GEARMAN_COMMAND_HEADER_SIZE, ENC_NA|ENC_ASCII);
403 break;
405 case GEARMAN_COMMAND_SET_CLIENT_ID:
406 if (!tree) break;
407 proto_tree_add_item(content_tree, hf_gearman_client_id, tvb,
408 offset, size, ENC_NA|ENC_ASCII);
409 break;
411 default:
412 if (size > 0)
413 expert_add_info(pinfo, content_item, &ei_gearman_pkt_type_unknown);
416 col_set_fence(pinfo->cinfo, COL_INFO);
417 return tvb_length(tvb);
420 static void
421 dissect_management_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
423 int i, type = 0, cmdlen, linelen, offset = 0, next_offset = 0;
424 proto_item *ti;
425 proto_tree *gearman_tree;
427 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Gearman");
428 col_clear(pinfo->cinfo, COL_INFO);
430 ti = proto_tree_add_item(tree, proto_gearman, tvb, 0, -1, ENC_NA);
431 gearman_tree = proto_item_add_subtree(ti, ett_gearman);
433 while ((linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE)) > 0)
435 for (i=0; i<GEARMAN_MGR_CMDS_COUNT; i++)
437 /* the array is a const and clearly none of the elements are longer than
438 * MAX_SIGNED_INT so this is a safe cast */
439 cmdlen = (int)strlen(GEARMAN_MGR_CMDS[i]);
441 if (cmdlen == linelen && 0 == tvb_strneql(tvb, offset, GEARMAN_MGR_CMDS[i], cmdlen))
443 proto_tree_add_item(gearman_tree, hf_gearman_mgr_cmd, tvb, offset, cmdlen, ENC_ASCII|ENC_NA);
444 col_add_fstr(pinfo->cinfo, COL_INFO, "[MGR] %s", tvb_get_string(wmem_packet_scope(), tvb, offset, linelen));
445 type = 1;
446 break;
450 if (GEARMAN_MGR_CMDS_COUNT == i)
452 proto_tree_add_text(gearman_tree, tvb, offset, next_offset - offset,
453 "%s", tvb_format_text(tvb, offset, next_offset - offset));
455 if (type == 0)
457 col_add_fstr(pinfo->cinfo, COL_INFO, "[MGR] %s", tvb_get_string(wmem_packet_scope(), tvb, offset, linelen));
458 type = -1;
460 else
462 col_append_sep_fstr(pinfo->cinfo, COL_INFO, ",", "%s", tvb_get_string(wmem_packet_scope(), tvb, offset, linelen));
466 offset = next_offset;
470 static int
471 dissect_gearman(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
473 if ((0 == tvb_memeql(tvb, 0, GEARMAN_MAGIC_CODE_REQUEST, 4)) ||
474 (0 == tvb_memeql(tvb, 0, GEARMAN_MAGIC_CODE_RESPONSE, 4)))
476 tcp_dissect_pdus(tvb, pinfo, tree, gearman_desegment, GEARMAN_COMMAND_HEADER_SIZE, get_gearman_pdu_len, dissect_binary_packet, data);
478 else
480 dissect_management_packet(tvb, pinfo, tree);
483 return tvb_length(tvb);
486 void
487 proto_register_gearman(void)
489 static hf_register_info hf[] = {
490 { &hf_gearman_mgr_cmd, { "Management Command", "gearman.mgr_cmd", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
491 { &hf_gearman_magic_code, { "Magic Code", "gearman.magic_code", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
492 { &hf_gearman_pkt_type, { "Packet Type", "gearman.pkt_type", FT_UINT32, BASE_DEC_HEX, VALS(gearman_command_names), 0x0, NULL, HFILL} },
493 { &hf_gearman_data_size, { "Data Length", "gearman.data_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} },
494 { &hf_gearman_data_content, { "Data Content", "gearman.data_content", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
495 { &hf_gearman_option_name, { "Option Name", "gearman.opt.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
496 { &hf_gearman_func_name, { "Function Name", "gearman.func.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
497 { &hf_gearman_func_namez, { "Function Name", "gearman.func.name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL} },
498 { &hf_gearman_client_id, { "Client ID", "gearman.client_id", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
499 { &hf_gearman_uniq_id, { "Unique ID", "gearman.uniq_id", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL} },
500 { &hf_gearman_argument, { "Function Argument", "gearman.func.arg", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
501 { &hf_gearman_job_handle, { "Job Handle", "gearman.job.handle", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
502 { &hf_gearman_job_handlez, { "Job Handle", "gearman.job.handle", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL} },
503 { &hf_gearman_complete_numerator, { "Complete Numerator", "gearman.numerator", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL} },
504 { &hf_gearman_complete_denominator, { "Complete Denominator", "gearman.denominator", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
505 { &hf_gearman_submit_job_sched_minute, { "Minute", "gearman.submit_job_sched.minute", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
506 { &hf_gearman_submit_job_sched_hour, { "Hour", "gearman.submit_job_sched.hour", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
507 { &hf_gearman_submit_job_sched_day_of_month, { "Day of Month", "gearman.submit_job_sched.day_of_month", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
508 { &hf_gearman_submit_job_sched_month, { "Month", "gearman.submit_job_sched.month", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
509 { &hf_gearman_submit_job_sched_day_of_week, { "Day of Week", "gearman.submit_job_sched.day_of_week", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
510 { &hf_gearman_submit_job_epoch_time, { "Epoch Time", "gearman.submit_job.epoch_time", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
511 { &hf_gearman_result, { "Function Result", "gearman.func.result", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
512 { &hf_gearman_known_status, { "Known job", "gearman.job.known", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL} },
513 { &hf_gearman_running_status, { "Running Job", "gearman.job.running", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL} },
514 { &hf_gearman_echo_text, { "Echo Text", "gearman.echo_text", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
515 { &hf_gearman_err_code, { "Error Code", "gearman.err.code", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL} },
516 { &hf_gearman_err_text, { "Error Text", "gearman.err.text", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL} }
519 /* Setup protocol subtree array */
520 static gint *ett[] = {
521 &ett_gearman,
522 &ett_gearman_command,
523 &ett_gearman_content
526 static ei_register_info ei[] = {
527 { &ei_gearman_pkt_type_unknown, { "gearman.pkt_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown command", EXPFILL }},
530 module_t *gearman_module;
531 expert_module_t* expert_gearman;
533 proto_gearman = proto_register_protocol("Gearman Protocol", "Gearman", "gearman");
535 proto_register_field_array(proto_gearman, hf, array_length(hf));
536 proto_register_subtree_array(ett, array_length(ett));
537 expert_gearman = expert_register_protocol(proto_gearman);
538 expert_register_field_array(expert_gearman, ei, array_length(ei));
540 gearman_module = prefs_register_protocol(proto_gearman, NULL);
541 prefs_register_bool_preference(gearman_module, "desegment",
542 "Desegment all Gearman messages spanning multiple TCP segments",
543 "Whether the Gearman dissector should desegment all messages spanning multiple TCP segments",
544 &gearman_desegment);
548 void
549 proto_reg_handoff_gearman(void)
551 dissector_handle_t gearman_handle;
553 gearman_handle = new_create_dissector_handle(dissect_gearman, proto_gearman);
554 dissector_add_uint("tcp.port", GEARMAN_PORT, gearman_handle);
558 * Editor modelines - http://www.wireshark.org/tools/modelines.html
560 * Local variables:
561 * c-basic-offset: 2
562 * tab-width: 8
563 * indent-tabs-mode: nil
564 * End:
566 * vi: set shiftwidth=2 tabstop=8 expandtab:
567 * :indentSize=2:tabSize=8:noTabs=true: