diff options
author | Paul Offord <paul.offord58@gmail.com> | 2021-06-20 17:07:28 +0100 |
---|---|---|
committer | Wireshark GitLab Utility <gerald+gitlab-utility@wireshark.org> | 2021-06-21 12:49:47 +0000 |
commit | 647205177179a6e9ef6c08f08c33a2b405efffbc (patch) | |
tree | d110c72a3b76dc20eb36ce2cf69d62aaffe6ec58 /sharkd_session.c | |
parent | 553e9e83d2d3985c53700ca56ba051698d4b6257 (diff) |
solved code conflicts pre rebase
Diffstat (limited to 'sharkd_session.c')
-rw-r--r-- | sharkd_session.c | 1100 |
1 files changed, 871 insertions, 229 deletions
diff --git a/sharkd_session.c b/sharkd_session.c index 486e45ffdd..81fc577691 100644 --- a/sharkd_session.c +++ b/sharkd_session.c @@ -20,6 +20,7 @@ #include <glib.h> #include <wsutil/wsjson.h> +#include <wsutil/ws_printf.h> #include <wsutil/json_dumper.h> #include <wsutil/ws_assert.h> @@ -81,10 +82,11 @@ struct sharkd_filter_item static GHashTable *filter_table = NULL; static int mode; -gboolean extended_log = FALSE; +static guint32 rpcid; static json_dumper dumper = {0}; + static const char * json_find_attr(const char *buf, const jsmntok_t *tokens, int count, const char *attr) { @@ -172,15 +174,532 @@ sharkd_json_array_close(void) } static void -sharkd_json_simple_reply(int err, const char *errmsg) +sharkd_json_response_open(guint32 id) +{ + json_dumper_begin_object(&dumper); // start the message + sharkd_json_value_string("jsonrpc", "2.0"); + sharkd_json_value_anyf("id", "%d", id); +} + +static void +sharkd_json_response_close(void) +{ + json_dumper_finish(&dumper); + + /* + * We do an explicit fflush after every line, because + * we want output to be written to the socket as soon + * as the line is complete. + * + * The stream is fully-buffered by default, so it's + * only flushed when the buffer fills or the FILE * + * is closed. On UN*X, we could set it to be line + * buffered, but the MSVC standard I/O routines don't + * support line buffering - they only support *byte* + * buffering, doing a write for every byte written, + * which is too inefficient, and full buffering, + * which is what you get if you request line buffering. + */ + fflush(stdout); +} + +static void +sharkd_json_result_prologue(guint32 id) +{ + sharkd_json_response_open(id); + sharkd_json_value_anyf("result", NULL); + json_dumper_begin_object(&dumper); // start the result object +} + +static void +sharkd_json_result_epilogue() +{ + json_dumper_end_object(&dumper); // end the result object + json_dumper_end_object(&dumper); // end the message + sharkd_json_response_close(); +} + +static void +sharkd_json_result_array_prologue(guint32 id) +{ + sharkd_json_response_open(id); + sharkd_json_array_open("result"); // start the result array +} + +static void +sharkd_json_result_array_epilogue() +{ + sharkd_json_array_close(); // end of result array + json_dumper_end_object(&dumper); // end the message + sharkd_json_response_close(); +} + +static void +sharkd_json_simple_ok(guint32 id) +{ + sharkd_json_result_prologue(id); + sharkd_json_value_string("status", "OK"); + sharkd_json_result_epilogue(); +} + +static void +sharkd_json_warning(guint32 id, char *warning) +{ + sharkd_json_result_prologue(id); + sharkd_json_value_string("status", "Warning"); + sharkd_json_value_string("warning", warning); + sharkd_json_result_epilogue(); +} + +static void G_GNUC_PRINTF(4, 5) +sharkd_json_error(guint32 id, int code, char* data, char* format, ...) { + sharkd_json_response_open(id); + sharkd_json_value_anyf("error", NULL); json_dumper_begin_object(&dumper); - sharkd_json_value_anyf("err", "%d", err); - if (errmsg) - sharkd_json_value_string("errmsg", errmsg); + sharkd_json_value_anyf("code", "%d", code); + + if (format) + { + // format the text message + va_list args; + + va_start(args, format); + char *error_msg = g_strdup_vprintf(format, args); + va_end(args); + + sharkd_json_value_string("message", error_msg); + + g_free(error_msg); + } json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + + if (data) + sharkd_json_value_string("data", data); + + json_dumper_end_object(&dumper); + sharkd_json_response_close(); +} + +static gboolean +is_param_match(char *param_in, char *valid_param) +{ + char* ptr; + + if (ptr = g_strrstr(valid_param, "*")) + { + int prefix_len = ptr - valid_param; + return !strncmp(param_in, valid_param, prefix_len); + } + else + return !strcmp(param_in, valid_param); +} + +/* +* json_prep does four things: +* +* 1. check the syntax of the root and parameter members +* 2. tokenize the names and values by zero terminating them +* 3. unescape the names and values +* 4. extracts and saves the rpcid +* - we have to do it here as it's needed for the error messages +* +* The objective is to minimise the validation work in the functions +* that process each called method. +* +* This gets a little messy as the JSON parser creates a flat list +* of all members rather than create a tree. +*/ +static gboolean +json_prep(char* buf, const jsmntok_t* tokens, int count) +{ + int i; + char* method = NULL; + char* attr_name = NULL; + char* attr_value = NULL; + +#define SHARKD_JSON_ANY 0 +#define SHARKD_JSON_STRING 1 +#define SHARKD_JSON_INTEGER 2 +#define SHARKD_JSON_UINTEGER 3 +#define SHARKD_JSON_FLOAT 4 +#define SHARKD_JSON_OBJECT 5 +#define SHARKD_JSON_ARRAY 6 +#define SHARKD_JSON_BOOLEAN 7 +#define SHARKD_ARRAY_END 99 + + struct member_attribute { + const char* parent_ctx; + const char* name; + int level; + jsmntype_t type; + int value_type; + gboolean is_mandatory; + }; + +#define MANDATORY TRUE +#define OPTIONAL FALSE + + /* + * The member attribute structure is key to the syntax checking. The + * array contains all of the root level (1) member names, the data + * types permissable for the value and a boolean that indicates whether + * or not the member is mandatory. + * + * Once we get into the next layer (2) of the json tree, we need to check + * params member names and data types dependent in the context of the method + * (parent_ctx). + */ + + struct member_attribute name_array[] = { + // Root members + {NULL, "jsonrpc", 1, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY}, + {NULL, "userid", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {NULL, "id", 1, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, MANDATORY}, + {NULL, "method", 1, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY}, + {NULL, "params", 1, JSMN_OBJECT, SHARKD_JSON_OBJECT, OPTIONAL}, + + // Valid methods + {"method", "analyse", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "bye", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "check", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "complete", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "download", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "dumpconf", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "follow", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "frame", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "frames", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "info", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "intervals", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "iograph", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "load", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "setcomment", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "setconf", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "status", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"method", "tap", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + + // Parameters and their method context + {"check", "field", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"check", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"complete", "field", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"complete", "pref", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"download", "token", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"dumpconf", "pref", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"follow", "follow", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY}, + {"follow", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY}, + {"frame", "frame", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, MANDATORY}, + {"frame", "proto", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL}, + {"frame", "ref_frame", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL}, + {"frame", "prev_frame", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL}, + {"frame", "columns", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL}, + {"frame", "color", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL}, + {"frame", "bytes", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL}, + {"frame", "hidden", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL}, + {"frames", "column*", 2, JSMN_UNDEFINED, SHARKD_JSON_ANY, OPTIONAL}, + {"frames", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"frames", "skip", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, OPTIONAL}, + {"frames", "limit", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, OPTIONAL}, + {"frames", "refs", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"intervals", "interval", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, OPTIONAL}, + {"intervals", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "interval", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, OPTIONAL}, + {"iograph", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "graph0", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY}, + {"iograph", "graph1", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "graph2", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "graph3", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "graph4", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "graph5", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "graph6", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "graph7", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "graph8", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "graph9", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter0", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter1", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter2", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter3", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter4", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter5", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter6", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter7", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter8", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"iograph", "filter9", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"load", "file", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY}, + {"setcomment", "frame", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, MANDATORY}, + {"setcomment", "comment", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"setconf", "name", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY}, + {"setconf", "value", 2, JSMN_UNDEFINED, SHARKD_JSON_ANY, MANDATORY}, + {"tap", "tap0", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY}, + {"tap", "tap1", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap2", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap3", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap4", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap5", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap6", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap7", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap8", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap9", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap10", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap11", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap12", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap13", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap14", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + {"tap", "tap15", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL}, + + // End of the name_array + {NULL, NULL, 0, JSMN_STRING, SHARKD_ARRAY_END, OPTIONAL}, + }; + + rpcid = 0; + + /* sanity check, and split strings */ + if (count < 1 || tokens[0].type != JSMN_OBJECT) + { + sharkd_json_error( + rpcid, -32600, NULL, + "The request must an object" + ); + goto fail; + } + + /* don't need [0] token */ + tokens++; + count--; + + if (count & 1) + { + sharkd_json_error( + rpcid, -32600, NULL, + "The request must contain name/value pairs" + ); + goto fail; + } + + for (i = 0; i < count; i += 2) + { + if (tokens[i].type != JSMN_STRING) + { + sharkd_json_error( + rpcid, -32600, NULL, + "Member names must be a string - member %d is not string", (i / 2) + 1 + ); + goto fail; + } + + buf[tokens[i + 0].end] = '\0'; + buf[tokens[i + 1].end] = '\0'; + + attr_name = &buf[tokens[i + 0].start]; + attr_value = &buf[tokens[i + 1].start]; + + // we must get the id as soon as possible so that it's available in all future error messages + if (!strcmp(attr_name, "id")) + { + if (!ws_strtou32(attr_value, NULL, &rpcid)) + { + sharkd_json_error( + rpcid, -32600, NULL, + "The id value must be a positive integer" + ); + goto fail; + } + } + + if (!strcmp(attr_name, "jsonrpc")) + { + if (strcmp(&buf[tokens[i + 1].start], "2.0")) + { + sharkd_json_error( + rpcid, -32600, NULL, + "Only JSON %s is supported", "2.0" + ); + goto fail; + } + } + + /* unescape only value, as keys are simple strings */ + if (tokens[i + 1].type == JSMN_STRING && !json_decode_string_inplace(attr_value)) + { + sharkd_json_error( + rpcid, -32600, NULL, + "Cannot unescape the value string of member %d", (i / 2) + 1 + ); + goto fail; + } + + /* Confirm that the member is valid */ + gboolean match = FALSE; + + // We need to check root members (level 1) and parameters (level 2), hence the for loop. + + for (int level = 1; level < 3; level++) + { + size_t j = 0; + + while (name_array[j].value_type != SHARKD_ARRAY_END) // iterate through the array until we hit the end + { + if (is_param_match(attr_name, name_array[j].name) && name_array[j].level == level) + { + // We need to be sure the match is in the correct context + // i.e. is this a match for a root member (level 1) or for a parameter (level 2). + + if (level == 1) + { + // need to guard against a parameter name matching a method name + if (method) + { + if (name_array[j].parent_ctx) + { + j++; + continue; + } + + if (!strcmp(method, &buf[tokens[i + 0].start])) + { + j++; + continue; + } + } + + match = TRUE; + } + else if (method) + { + if (level == 2 && !strcmp(name_array[j].parent_ctx, method)) + match = TRUE; + else + { + j++; + continue; + } + } + else + { + j++; + continue; + } + + // The match looks good, let's now check the data types + + if (tokens[i + 1].type != name_array[j].type && name_array[j].type != SHARKD_JSON_ANY) + { + sharkd_json_error( + rpcid, -32600, NULL, + "The data type for member %s is not a valid", attr_name + ); + goto fail; + } + else if (name_array[j].type == JSMN_PRIMITIVE && name_array[j].value_type == SHARKD_JSON_UINTEGER) + { + guint32 temp; + if (!ws_strtou32(attr_value, NULL, &temp) || temp <= 0) + { + sharkd_json_error( + rpcid, -32600, NULL, + "The value for %s must be a positive integer", name_array[j].name + ); + goto fail; + } + } + else if (name_array[j].type == JSMN_PRIMITIVE && name_array[j].value_type == SHARKD_JSON_BOOLEAN) + { + if (!strcmp(attr_value, "true") && !strcmp(attr_value, "false")) + { + sharkd_json_error( + rpcid, -32600, NULL, + "The value for %s must be a boolean (true or false)", name_array[j].name + ); + goto fail; + } + + } + break; // looks like a valid match + } + j++; + } + + if (!strcmp(attr_name, "method")) + { + int k = 0; // name array index + // check that the request method is good + while (name_array[k].value_type != SHARKD_ARRAY_END) + { + if (name_array[k].parent_ctx) + { + if (!strcmp(attr_value, name_array[k].name) && !strcmp(name_array[k].parent_ctx, "method")) + method = attr_value; // the method is valid + } + + k++; + } + + if (!method) + { + sharkd_json_error( + rpcid, -32601, NULL, + "The method %s is not supported", attr_value + ); + goto fail; + } + } + } + + if (!match) + { + sharkd_json_error( + rpcid, -32600, NULL, + "%s is not a valid member name", attr_name + ); + goto fail; + } + } + + /* check for mandatory members */ + size_t j = 0; + + while (name_array[j].value_type != SHARKD_ARRAY_END) + { + if (name_array[j].is_mandatory && name_array[j].level == 1) + { + if (!json_find_attr(buf, tokens, count, name_array[j].name)) + { + sharkd_json_error( + rpcid, -32600, NULL, + "Mandatory member %s is missing", name_array[j].name + ); + goto fail; + } + } + j++; + } + + // check that the current request contains the mandatory parameters + j = 0; + + while (name_array[j].value_type != SHARKD_ARRAY_END) + { + if (name_array[j].is_mandatory && name_array[j].level == 2 && !strcmp(method, name_array[j].parent_ctx)) + { + if (!json_find_attr(buf, tokens, count, name_array[j].name)) + { + sharkd_json_error( + rpcid, -32600, NULL, + "Mandatory parameter %s is missing", name_array[j].name + ); + goto fail; + } + } + j++; + } + + + // check that the parameters for the current request are valid for the method and that the data type for the value is valid + + return TRUE; + +fail: + return FALSE; } static void @@ -433,7 +952,7 @@ sharkd_session_process_info(void) { int i; - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_array_open("columns"); for (i = 0; i < NUM_COL_FMTS; i++) @@ -523,8 +1042,7 @@ sharkd_session_process_info(void) follow_iterate_followers(sharkd_follower_visit_cb, &i); sharkd_json_array_close(); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); } /** @@ -551,7 +1069,10 @@ sharkd_session_process_load(const char *buf, const jsmntok_t *tokens, int count) if (sharkd_cf_open(tok_file, WTAP_TYPE_AUTO, FALSE, &err) != CF_OK) { - sharkd_json_simple_reply(err, NULL); + sharkd_json_error( + rpcid, -2001, NULL, + "Unable to open the file" + ); return; } @@ -561,12 +1082,17 @@ sharkd_session_process_load(const char *buf, const jsmntok_t *tokens, int count) } CATCH(OutOfMemoryError) { + sharkd_json_error( + rpcid, -32603, NULL, + "Load failed, out of memory" + ); fprintf(stderr, "load: OutOfMemoryError\n"); err = ENOMEM; } ENDTRY; - sharkd_json_simple_reply(err, NULL); + if (err == 0) + sharkd_json_simple_ok(rpcid); } /** @@ -583,7 +1109,7 @@ sharkd_session_process_load(const char *buf, const jsmntok_t *tokens, int count) static void sharkd_session_process_status(void) { - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_value_anyf("frames", "%u", cfile.count); sharkd_json_value_anyf("duration", "%.9f", nstime_to_sec(&cfile.elapsed_time)); @@ -604,8 +1130,7 @@ sharkd_session_process_status(void) sharkd_json_value_anyf("filesize", "%" G_GINT64_FORMAT, file_size); } - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); } struct sharkd_analyse_data @@ -671,7 +1196,7 @@ sharkd_session_process_analyse(void) analyser.last_time = NULL; analyser.protocols_set = g_hash_table_new(NULL /* g_direct_hash() */, NULL /* g_direct_equal */); - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_value_anyf("frames", "%u", cfile.count); @@ -686,8 +1211,7 @@ sharkd_session_process_analyse(void) if (analyser.last_time) sharkd_json_value_anyf("last", "%.9f", nstime_to_sec(analyser.last_time)); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); g_hash_table_destroy(analyser.protocols_set); } @@ -812,7 +1336,13 @@ sharkd_session_process_frames(const char *buf, const jsmntok_t *tokens, int coun memset(&user_cinfo, 0, sizeof(user_cinfo)); cinfo = sharkd_session_create_columns(&user_cinfo, buf, tokens, count); if (!cinfo) + { + sharkd_json_error( + rpcid, -13001, NULL, + "Column definition invalid - note column 6 requires a custom definition" + ); return; + } } if (tok_filter) @@ -821,7 +1351,14 @@ sharkd_session_process_frames(const char *buf, const jsmntok_t *tokens, int coun filter_item = sharkd_session_filter_data(tok_filter); if (!filter_item) + { + sharkd_json_error( + rpcid, -13002, NULL, + "Filter expression invalid" + ); return; + } + filter_data = filter_item->filtered; } @@ -845,7 +1382,8 @@ sharkd_session_process_frames(const char *buf, const jsmntok_t *tokens, int coun return; } - sharkd_json_array_open(NULL); + sharkd_json_result_array_prologue(rpcid); + for (framenum = 1; framenum <= cfile.count; framenum++) { frame_data *fdata; @@ -932,8 +1470,7 @@ sharkd_session_process_frames(const char *buf, const jsmntok_t *tokens, int coun if (limit && --limit == 0) break; } - sharkd_json_array_close(); - json_dumper_finish(&dumper); + sharkd_json_result_array_epilogue(); if (cinfo != &cfile.cinfo) col_cleanup(cinfo); @@ -2209,8 +2746,11 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) if (!cfg) { - fprintf(stderr, "sharkd_session_process_tap() stat %s not found\n", tok_tap + 5); - continue; + sharkd_json_error( + rpcid, -11001, NULL, + "sharkd_session_process_tap() stat %s not found", tok_tap + 5 + ); + return; } st = stats_tree_new(cfg, NULL, tap_filter); @@ -2246,8 +2786,11 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) analysis = sequence_analysis_find_by_name(tok_tap + 5); if (!analysis) { - fprintf(stderr, "sharkd_session_process_tap() seq analysis %s not found\n", tok_tap + 5); - continue; + sharkd_json_error( + rpcid, -11002, NULL, + "sharkd_session_process_tap() seq analysis %s not found", tok_tap + 5 + ); + return; } graph_analysis = sequence_analysis_info_new(); @@ -2277,8 +2820,11 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) if (!ct || !(tap_func = get_conversation_packet_func(ct))) { - fprintf(stderr, "sharkd_session_process_tap() conv %s not found\n", tok_tap + 5); - continue; + sharkd_json_error( + rpcid, -11003, NULL, + "sharkd_session_process_tap() conv %s not found", tok_tap + 5 + ); + return; } } else if (!strncmp(tok_tap, "endpt:", 6)) @@ -2287,14 +2833,20 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) if (!ct || !(tap_func = get_hostlist_packet_func(ct))) { - fprintf(stderr, "sharkd_session_process_tap() endpt %s not found\n", tok_tap + 6); - continue; + sharkd_json_error( + rpcid, -11004, NULL, + "sharkd_session_process_tap() endpt %s not found", tok_tap + 6 + ); + return; } } else { - fprintf(stderr, "sharkd_session_process_tap() conv/endpt(?): %s not found\n", tok_tap); - continue; + sharkd_json_error( + rpcid, -11005, NULL, + "sharkd_session_process_tap() conv/endpt(?): %s not found", tok_tap + ); + return; } ct_tapname = proto_get_protocol_filter_name(get_conversation_proto_id(ct)); @@ -2319,8 +2871,11 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) if (!stat_tap) { - fprintf(stderr, "sharkd_session_process_tap() nstat=%s not found\n", tok_tap + 6); - continue; + sharkd_json_error( + rpcid, -11006, NULL, + "sharkd_session_process_tap() nstat=%s not found", tok_tap + 6 + ); + return; } stat_tap->stat_tap_init_cb(stat_tap); @@ -2342,16 +2897,22 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) if (!rtd) { - fprintf(stderr, "sharkd_session_process_tap() rtd=%s not found\n", tok_tap + 4); - continue; + sharkd_json_error( + rpcid, -11007, NULL, + "sharkd_session_process_tap() rtd=%s not found", tok_tap + 4 + ); + return; } rtd_table_get_filter(rtd, "", &tap_filter, &err); if (err != NULL) { - fprintf(stderr, "sharkd_session_process_tap() rtd=%s err=%s\n", tok_tap + 4, err); + sharkd_json_error( + rpcid, -11008, NULL, + "sharkd_session_process_tap() rtd=%s err=%s", tok_tap + 4, err + ); g_free(err); - continue; + return; } rtd_data = g_new0(rtd_data_t, 1); @@ -2371,16 +2932,22 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) if (!srt) { - fprintf(stderr, "sharkd_session_process_tap() srt=%s not found\n", tok_tap + 4); - continue; + sharkd_json_error( + rpcid, -11009, NULL, + "sharkd_session_process_tap() srt=%s not found", tok_tap + 4 + ); + return; } srt_table_get_filter(srt, "", &tap_filter, &err); if (err != NULL) { - fprintf(stderr, "sharkd_session_process_tap() srt=%s err=%s\n", tok_tap + 4, err); + sharkd_json_error( + rpcid, -11010, NULL, + "sharkd_session_process_tap() srt=%s err=%s", tok_tap + 4, err + ); g_free(err); - continue; + return; } srt_data = g_new0(srt_data_t, 1); @@ -2401,8 +2968,11 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) if (!eo) { - fprintf(stderr, "sharkd_session_process_tap() eo=%s not found\n", tok_tap + 3); - continue; + sharkd_json_error( + rpcid, -11011, NULL, + "sharkd_session_process_tap() eo=%s not found", tok_tap + 3 + ); + return; } for (object_list = sharkd_eo_list; object_list; object_list = object_list->next) @@ -2465,17 +3035,23 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) } else { - fprintf(stderr, "sharkd_session_process_tap() %s not recognized\n", tok_tap); - continue; + sharkd_json_error( + rpcid, -11012, NULL, + "sharkd_session_process_tap() %s not recognized", tok_tap + ); + return; } if (tap_error) { - fprintf(stderr, "sharkd_session_process_tap() name=%s error=%s", tok_tap, tap_error->str); + sharkd_json_error( + rpcid, -11013, NULL, + "sharkd_session_process_tap() name=%s error=%s", tok_tap, tap_error->str + ); g_string_free(tap_error, TRUE); if (tap_free) tap_free(tap_data); - continue; + return; } taps_data[taps_count] = tap_data; @@ -2485,18 +3061,19 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) fprintf(stderr, "sharkd_session_process_tap() count=%d\n", taps_count); if (taps_count == 0) + { + sharkd_json_result_prologue(rpcid); + sharkd_json_array_open("taps"); + sharkd_json_array_close(); + sharkd_json_result_epilogue(); return; + } - json_dumper_begin_object(&dumper); - + sharkd_json_result_prologue(rpcid); sharkd_json_array_open("taps"); sharkd_retap(); sharkd_json_array_close(); - - sharkd_json_value_anyf("err", "0"); - - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); for (i = 0; i < taps_count; i++) { @@ -2544,13 +3121,13 @@ sharkd_session_process_follow(char *buf, const jsmntok_t *tokens, int count) const char *host; char *port; - if (!tok_follow || !tok_filter) - return; - follower = get_follow_by_name(tok_follow); if (!follower) { - fprintf(stderr, "sharkd_session_process_follow() follower=%s not found\n", tok_follow); + sharkd_json_error( + rpcid, -12001, NULL, + "sharkd_session_process_follow() follower=%s not found", tok_follow + ); return; } @@ -2561,7 +3138,10 @@ sharkd_session_process_follow(char *buf, const jsmntok_t *tokens, int count) tap_error = register_tap_listener(get_follow_tap_string(follower), follow_info, tok_filter, 0, NULL, get_follow_tap_handler(follower), NULL, NULL); if (tap_error) { - fprintf(stderr, "sharkd_session_process_follow() name=%s error=%s", tok_follow, tap_error->str); + sharkd_json_error( + rpcid, -12002, NULL, + "sharkd_session_process_follow() name=%s error=%s", tok_follow, tap_error->str + ); g_string_free(tap_error, TRUE); g_free(follow_info); return; @@ -2569,9 +3149,7 @@ sharkd_session_process_follow(char *buf, const jsmntok_t *tokens, int count) sharkd_retap(); - json_dumper_begin_object(&dumper); - - sharkd_json_value_anyf("err", "0"); + sharkd_json_result_prologue(rpcid); /* Server information: hostname, port, bytes sent */ host = address_to_name(&follow_info->server_ip); @@ -2616,8 +3194,7 @@ sharkd_session_process_follow(char *buf, const jsmntok_t *tokens, int count) sharkd_json_array_close(); } - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); remove_tap_listener(follow_info); follow_info_free(follow_info); @@ -2778,9 +3355,7 @@ sharkd_session_process_frame_cb(epan_dissect_t *edt, proto_tree *tree, struct ep const struct sharkd_frame_request_data * const req_data = (const struct sharkd_frame_request_data * const) data; const gboolean display_hidden = (req_data) ? req_data->display_hidden : FALSE; - json_dumper_begin_object(&dumper); - - sharkd_json_value_anyf("err", "0"); + sharkd_json_result_prologue(rpcid); if (fdata->has_user_comment) pkt_comment = sharkd_get_user_comment(fdata); @@ -2916,8 +3491,7 @@ sharkd_session_process_frame_cb(epan_dissect_t *edt, proto_tree *tree, struct ep follow_iterate_followers(sharkd_follower_visit_layers_cb, pi); sharkd_json_array_close(); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); } #define SHARKD_IOGRAPH_MAX_ITEMS 250000 /* 250k limit of items is taken from wireshark-qt, on x86_64 sizeof(io_graph_item_t) is 152, so single graph can take max 36 MB */ @@ -3004,13 +3578,7 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count) int i; if (tok_interval) - { - if (!ws_strtou32(tok_interval, NULL, &interval_ms) || interval_ms == 0) - { - fprintf(stderr, "Invalid interval parameter: %s.\n", tok_interval); - return; - } - } + ws_strtou32(tok_interval, NULL, &interval_ms); for (i = graph_count = 0; i < (int) G_N_ELEMENTS(graphs); i++) { @@ -3070,6 +3638,16 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count) graph_count++; + if (graph->error) + { + sharkd_json_error( + rpcid, -6001, NULL, + "%s", graph->error->str + ); + g_string_free(graph->error, TRUE); + return; + } + if (graph->error == NULL) is_any_ok = TRUE; } @@ -3078,7 +3656,7 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count) if (is_any_ok) sharkd_retap(); - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_array_open("iograph"); for (i = 0; i < graph_count; i++) @@ -3089,8 +3667,9 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count) if (graph->error) { - sharkd_json_value_string("errmsg", graph->error->str); + fprintf(stderr, "SNAP 6002 - we should never get to here.\n"); g_string_free(graph->error, TRUE); + exit(-1); } else { @@ -3124,8 +3703,7 @@ sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count) } sharkd_json_array_close(); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); } /** @@ -3172,13 +3750,7 @@ sharkd_session_process_intervals(char *buf, const jsmntok_t *tokens, int count) gint64 max_idx = 0; if (tok_interval) - { - if (!ws_strtou32(tok_interval, NULL, &interval_ms) || interval_ms == 0) - { - fprintf(stderr, "Invalid interval parameter: %s.\n", tok_interval); - return; - } - } + ws_strtou32(tok_interval, NULL, &interval_ms); // already validated if (tok_filter) { @@ -3186,7 +3758,13 @@ sharkd_session_process_intervals(char *buf, const jsmntok_t *tokens, int count) filter_item = sharkd_session_filter_data(tok_filter); if (!filter_item) + { + sharkd_json_error( + rpcid, -7001, NULL, + "Invalid filter parameter: %s", tok_filter + ); return; + } filter_data = filter_item->filtered; } @@ -3198,7 +3776,7 @@ sharkd_session_process_intervals(char *buf, const jsmntok_t *tokens, int count) idx = 0; - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_array_open("intervals"); start_ts = (cfile.count >= 1) ? &(sharkd_get_frame(1)->abs_ts) : NULL; @@ -3249,8 +3827,7 @@ sharkd_session_process_intervals(char *buf, const jsmntok_t *tokens, int count) sharkd_json_value_anyf("frames", "%u", st_total.frames); sharkd_json_value_anyf("bytes", "%" G_GUINT64_FORMAT, st_total.bytes); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); } /** @@ -3309,16 +3886,35 @@ sharkd_session_process_frame(char *buf, const jsmntok_t *tokens, int count) guint32 dissect_flags = SHARKD_DISSECT_FLAG_NULL; struct sharkd_frame_request_data req_data; - if (!tok_frame || !ws_strtou32(tok_frame, NULL, &framenum) || framenum == 0) - return; + ws_strtou32(tok_frame, NULL, &framenum); // we have already validated this ref_frame_num = (framenum != 1) ? 1 : 0; - if (tok_ref_frame && (!ws_strtou32(tok_ref_frame, NULL, &ref_frame_num) || ref_frame_num > framenum)) - return; + if (tok_ref_frame) + { + ws_strtou32(tok_ref_frame, NULL, &ref_frame_num); + if (ref_frame_num > framenum) + { + sharkd_json_error( + rpcid, -8001, NULL, + "Invalid ref_frame - The ref_frame occurs after the frame specified" + ); + return; + } + } prev_dis_num = framenum - 1; - if (tok_prev_frame && (!ws_strtou32(tok_prev_frame, NULL, &prev_dis_num) || prev_dis_num >= framenum)) - return; + if (tok_prev_frame) + { + ws_strtou32(tok_prev_frame, NULL, &prev_dis_num); + if (prev_dis_num >= framenum) + { + sharkd_json_error( + rpcid, -8002, NULL, + "Invalid prev_frame - The prev_frame occurs on or after the frame specified" + ); + return; + } + } if (json_find_attr(buf, tokens, count, "proto") != NULL) dissect_flags |= SHARKD_DISSECT_FLAG_PROTO_TREE; @@ -3331,7 +3927,14 @@ sharkd_session_process_frame(char *buf, const jsmntok_t *tokens, int count) req_data.display_hidden = (json_find_attr(buf, tokens, count, "v") != NULL); - sharkd_dissect_request(framenum, ref_frame_num, prev_dis_num, &sharkd_session_process_frame_cb, dissect_flags, &req_data); + if (sharkd_dissect_request(framenum, ref_frame_num, prev_dis_num, &sharkd_session_process_frame_cb, dissect_flags, &req_data)) + { + sharkd_json_error( + rpcid, -8003, NULL, + "Invalid frame - The frame number requested is out of range" + ); + return; + } } /** @@ -3354,9 +3957,6 @@ sharkd_session_process_check(char *buf, const jsmntok_t *tokens, int count) const char *tok_filter = json_find_attr(buf, tokens, count, "filter"); const char *tok_field = json_find_attr(buf, tokens, count, "field"); - json_dumper_begin_object(&dumper); - sharkd_json_value_anyf("err", "0"); - if (tok_filter != NULL) { char *err_msg = NULL; @@ -3364,18 +3964,22 @@ sharkd_session_process_check(char *buf, const jsmntok_t *tokens, int count) if (dfilter_compile(tok_filter, &dfp, &err_msg)) { - const char *s = "ok"; - if (dfp && dfilter_deprecated_tokens(dfp)) - s = "warn"; + sharkd_json_warning(rpcid, err_msg); + else + sharkd_json_simple_ok(rpcid); - sharkd_json_value_string("filter", s); dfilter_free(dfp); + g_free(err_msg); + return 0; } else { - sharkd_json_value_string("filter", err_msg); - g_free(err_msg); + sharkd_json_error( + rpcid, -5001, NULL, + "Filter invalid - %s", err_msg + ); + return -5001; } } @@ -3383,12 +3987,22 @@ sharkd_session_process_check(char *buf, const jsmntok_t *tokens, int count) { header_field_info *hfi = proto_registrar_get_byname(tok_field); - sharkd_json_value_string("field", (hfi) ? "ok" : "notfound"); + if (!hfi) + { + sharkd_json_error( + rpcid, -5002, NULL, + "Field %s not found", tok_field + ); + return -5002; + } + else + { + sharkd_json_simple_ok(rpcid); + return 0; + } } - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); - + sharkd_json_simple_ok(rpcid); return 0; } @@ -3457,8 +4071,7 @@ sharkd_session_process_complete(char *buf, const jsmntok_t *tokens, int count) const char *tok_field = json_find_attr(buf, tokens, count, "field"); const char *tok_pref = json_find_attr(buf, tokens, count, "pref"); - json_dumper_begin_object(&dumper); - sharkd_json_value_anyf("err", "0"); + sharkd_json_result_prologue(rpcid); if (tok_field != NULL && tok_field[0]) { @@ -3553,8 +4166,7 @@ sharkd_session_process_complete(char *buf, const jsmntok_t *tokens, int count) sharkd_json_array_close(); } - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); return 0; } @@ -3582,15 +4194,34 @@ sharkd_session_process_setcomment(char *buf, const jsmntok_t *tokens, int count) int ret; if (!tok_frame || !ws_strtou32(tok_frame, NULL, &framenum) || framenum == 0) + { + sharkd_json_error( + rpcid, -3001, NULL, + "Frame number must be a positive integer" + ); return; + } - fdata = sharkd_get_frame(framenum); + fdata = sharkd_get_frame(framenum); // BUG HERE - If no file loaded you get a crash if (!fdata) + { + sharkd_json_error( + rpcid, -3002, NULL, + "Frame number is out of range" + ); return; + } ret = sharkd_set_user_comment(fdata, tok_comment); - sharkd_json_simple_reply(ret, NULL); + if (ret) + sharkd_json_error( + rpcid, -3003, NULL, + "Unable to set the comment" + ); + else + sharkd_json_simple_ok(rpcid); + } /** @@ -3615,14 +4246,55 @@ sharkd_session_process_setconf(char *buf, const jsmntok_t *tokens, int count) prefs_set_pref_e ret; - if (!tok_name || tok_name[0] == '\0' || !tok_value) + if (!tok_name || tok_name[0] == '\0') + { + sharkd_json_error( + rpcid, -4001, NULL, + "Preference name missing" + ); + return; + } + + if (!tok_value) + { + sharkd_json_error( + rpcid, -4002, NULL, + "Preference value missing" + ); return; + } snprintf(pref, sizeof(pref), "%s:%s", tok_name, tok_value); ret = prefs_set_pref(pref, &errmsg); - sharkd_json_simple_reply(ret, errmsg); + switch (ret) + { + case PREFS_SET_OK: + sharkd_json_simple_ok(rpcid); + break; + + case PREFS_SET_OBSOLETE: + sharkd_json_error( + rpcid, -4003, NULL, + "The preference specified is obsolete" + ); + break; + + case PREFS_SET_NO_SUCH_PREF: + sharkd_json_error( + rpcid, -4004, NULL, + "No such preference exists" + ); + break; + + default: + sharkd_json_error( + rpcid, -4005, NULL, + "Unable to set the preference" + ); + } + g_free(errmsg); } @@ -3781,15 +4453,14 @@ sharkd_session_process_dumpconf(char *buf, const jsmntok_t *tokens, int count) data.module = NULL; - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_value_anyf("prefs", NULL); json_dumper_begin_object(&dumper); prefs_modules_foreach(sharkd_session_process_dumpconf_mod_cb, &data); json_dumper_end_object(&dumper); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); return; } @@ -3809,18 +4480,25 @@ sharkd_session_process_dumpconf(char *buf, const jsmntok_t *tokens, int count) data.module = pref_mod; - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_value_anyf("prefs", NULL); json_dumper_begin_object(&dumper); sharkd_session_process_dumpconf_cb(pref, &data); json_dumper_end_object(&dumper); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); + return; + } + else + { + sharkd_json_error( + rpcid, -9001, NULL, + "Invalid pref %s.", tok_pref + ); + return; } - return; } pref_mod = prefs_find_module(tok_pref); @@ -3830,15 +4508,21 @@ sharkd_session_process_dumpconf(char *buf, const jsmntok_t *tokens, int count) data.module = pref_mod; - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_value_anyf("prefs", NULL); json_dumper_begin_object(&dumper); prefs_pref_foreach(pref_mod, sharkd_session_process_dumpconf_cb, &data); json_dumper_end_object(&dumper); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); + } + else + { + sharkd_json_error( + rpcid, -9002, NULL, + "Invalid pref %s.", tok_pref + ); } } @@ -4068,12 +4752,16 @@ sharkd_session_process_download(char *buf, const jsmntok_t *tokens, int count) const char *mime = (eo_entry->content_type) ? eo_entry->content_type : "application/octet-stream"; const char *filename = (eo_entry->filename) ? eo_entry->filename : tok_token; - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_value_string("file", filename); sharkd_json_value_string("mime", mime); sharkd_json_value_base64("data", eo_entry->payload_data, eo_entry->payload_len); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); + } + else + { + sharkd_json_result_prologue(rpcid); + sharkd_json_result_epilogue(); } } else if (!strcmp(tok_token, "ssl-secrets")) @@ -4086,12 +4774,11 @@ sharkd_session_process_download(char *buf, const jsmntok_t *tokens, int count) const char *mime = "text/plain"; const char *filename = "keylog.txt"; - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_value_string("file", filename); sharkd_json_value_string("mime", mime); sharkd_json_value_base64("data", str, str_len); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); } g_free(str); } @@ -4103,14 +4790,20 @@ sharkd_session_process_download(char *buf, const jsmntok_t *tokens, int count) memset(&rtp_req, 0, sizeof(rtp_req)); if (!sharkd_rtp_match_init(&rtp_req.id, tok_token + 4)) { - fprintf(stderr, "sharkd_session_process_download() rtp tokenizing error %s\n", tok_token); + sharkd_json_error( + rpcid, -10001, NULL, + "sharkd_session_process_download() rtp tokenizing error %s", tok_token + ); return; } tap_error = register_tap_listener("rtp", &rtp_req, NULL, 0, NULL, sharkd_session_packet_download_tap_rtp_cb, NULL, NULL); if (tap_error) { - fprintf(stderr, "sharkd_session_process_download() rtp error=%s", tap_error->str); + sharkd_json_error( + rpcid, -10002, NULL, + "sharkd_session_process_download() rtp error %s", tap_error->str + ); g_string_free(tap_error, TRUE); return; } @@ -4123,7 +4816,7 @@ sharkd_session_process_download(char *buf, const jsmntok_t *tokens, int count) const char *mime = "audio/x-wav"; const char *filename = tok_token; - json_dumper_begin_object(&dumper); + sharkd_json_result_prologue(rpcid); sharkd_json_value_string("file", filename); sharkd_json_value_string("mime", mime); @@ -4132,8 +4825,7 @@ sharkd_session_process_download(char *buf, const jsmntok_t *tokens, int count) sharkd_rtp_download_decode(&rtp_req); json_dumper_end_base64(&dumper); - json_dumper_end_object(&dumper); - json_dumper_finish(&dumper); + sharkd_json_result_epilogue(); g_slist_free_full(rtp_req.packets, sharkd_rtp_download_free_items); } @@ -4143,114 +4835,58 @@ sharkd_session_process_download(char *buf, const jsmntok_t *tokens, int count) static void sharkd_session_process(char *buf, const jsmntok_t *tokens, int count) { - int i; - - /* sanity check, and split strings */ - if (count < 1 || tokens[0].type != JSMN_OBJECT) + if (json_prep(buf, tokens, count)) { - fprintf(stderr, "sanity check(1): [0] not object\n"); - return; - } + /* don't need [0] token */ + tokens++; + count--; - /* don't need [0] token */ - tokens++; - count--; + const char* tok_method = json_find_attr(buf, tokens, count, "method"); - if (count & 1) - { - fprintf(stderr, "sanity check(2): %d not even\n", count); - return; - } - - for (i = 0; i < count; i += 2) - { - if (tokens[i].type != JSMN_STRING) - { - fprintf(stderr, "sanity check(3): [%d] not string\n", i); - return; - } - - if (tokens[i + 1].type != JSMN_STRING && tokens[i + 1].type != JSMN_PRIMITIVE) - { - fprintf(stderr, "sanity check(3a): [%d] wrong type\n", i + 1); - return; - } - - buf[tokens[i + 0].end] = '\0'; - buf[tokens[i + 1].end] = '\0'; - - /* unescape only value, as keys are simple strings */ - if (tokens[i + 1].type == JSMN_STRING && !json_decode_string_inplace(&buf[tokens[i + 1].start])) - { - fprintf(stderr, "sanity check(3b): [%d] cannot unescape string\n", i + 1); - return; - } - } - - { - const char *tok_req = json_find_attr(buf, tokens, count, "req"); - - if (!tok_req) - { - fprintf(stderr, "sanity check(4): no \"req\".\n"); - return; - } - - if (!strcmp(tok_req, "load")) + if (!strcmp(tok_method, "load")) sharkd_session_process_load(buf, tokens, count); - else if (!strcmp(tok_req, "status")) + else if (!strcmp(tok_method, "status")) sharkd_session_process_status(); - else if (!strcmp(tok_req, "analyse")) + else if (!strcmp(tok_method, "analyse")) sharkd_session_process_analyse(); - else if (!strcmp(tok_req, "info")) + else if (!strcmp(tok_method, "info")) sharkd_session_process_info(); - else if (!strcmp(tok_req, "check")) + else if (!strcmp(tok_method, "check")) sharkd_session_process_check(buf, tokens, count); - else if (!strcmp(tok_req, "complete")) + else if (!strcmp(tok_method, "complete")) sharkd_session_process_complete(buf, tokens, count); - else if (!strcmp(tok_req, "frames")) + else if (!strcmp(tok_method, "frames")) sharkd_session_process_frames(buf, tokens, count); - else if (!strcmp(tok_req, "tap")) + else if (!strcmp(tok_method, "tap")) sharkd_session_process_tap(buf, tokens, count); - else if (!strcmp(tok_req, "follow")) + else if (!strcmp(tok_method, "follow")) sharkd_session_process_follow(buf, tokens, count); - else if (!strcmp(tok_req, "iograph")) + else if (!strcmp(tok_method, "iograph")) sharkd_session_process_iograph(buf, tokens, count); - else if (!strcmp(tok_req, "intervals")) + else if (!strcmp(tok_method, "intervals")) sharkd_session_process_intervals(buf, tokens, count); - else if (!strcmp(tok_req, "frame")) + else if (!strcmp(tok_method, "frame")) sharkd_session_process_frame(buf, tokens, count); - else if (!strcmp(tok_req, "setcomment")) + else if (!strcmp(tok_method, "setcomment")) sharkd_session_process_setcomment(buf, tokens, count); - else if (!strcmp(tok_req, "setconf")) + else if (!strcmp(tok_method, "setconf")) sharkd_session_process_setconf(buf, tokens, count); - else if (!strcmp(tok_req, "dumpconf")) + else if (!strcmp(tok_method, "dumpconf")) sharkd_session_process_dumpconf(buf, tokens, count); - else if (!strcmp(tok_req, "download")) + else if (!strcmp(tok_method, "download")) sharkd_session_process_download(buf, tokens, count); - else if (!strcmp(tok_req, "bye")) + else if (!strcmp(tok_method, "bye")) + { + sharkd_json_simple_ok(rpcid); exit(0); + } else - fprintf(stderr, "::: req = %s\n", tok_req); - - /* reply for every command are 0+ lines of JSON reply (outputed above), finished by empty new line */ - json_dumper_finish(&dumper); - - /* - * We do an explicit fflush after every line, because - * we want output to be written to the socket as soon - * as the line is complete. - * - * The stream is fully-buffered by default, so it's - * only flushed when the buffer fills or the FILE * - * is closed. On UN*X, we could set it to be line - * buffered, but the MSVC standard I/O routines don't - * support line buffering - they only support *byte* - * buffering, doing a write for every byte written, - * which is too inefficient, and full buffering, - * which is what you get if you request line buffering. - */ - fflush(stdout); + { + sharkd_json_error( + rpcid, -32601, NULL, + "The method \"%s\" is unknown", tok_method + ); + } } } @@ -4282,8 +4918,11 @@ sharkd_session_main(int mode_setting) ret = json_parse(buf, NULL, 0); if (ret <= 0) { - fprintf(stderr, "invalid JSON -> closing\n"); - return 1; + sharkd_json_error( + rpcid, -32600, NULL, + "Invalid JSON(1)" + ); + continue; } /* fprintf(stderr, "JSON: %d tokens\n", ret); */ @@ -4300,8 +4939,11 @@ sharkd_session_main(int mode_setting) ret = json_parse(buf, tokens, ret); if (ret <= 0) { - fprintf(stderr, "invalid JSON(2) -> closing\n"); - return 2; + sharkd_json_error( + rpcid, -32600, NULL, + "Invalid JSON(2)" + ); + continue; } host_name_lookup_process(); |