static jsmntok_t *json_skip(jsmntok_t *t) { int i; jsmntok_t *s; switch (t->type) { case JSMN_PRIMITIVE: case JSMN_STRING: t++; break; case JSMN_OBJECT: case JSMN_ARRAY: s = t; t++; // move onto first key for (i = 0; i < s->size; i++) { t = json_skip(t); if (s->type == JSMN_OBJECT) { t = json_skip(t); } } } return t; }
static int process_json(bgpstream_broker_datasource_t *broker_ds, bgpstream_input_mgr_t *input_mgr, const char *js, jsmntok_t *root_tok, size_t count) { int i, j, k; jsmntok_t *t = root_tok + 1; int arr_len, obj_len; int time_set = 0; int num_results = 0; // per-file info char *url = NULL; size_t url_len = 0; int url_set = 0; char collector[BGPSTREAM_UTILS_STR_NAME_LEN] = ""; int collector_set = 0; char project[BGPSTREAM_UTILS_STR_NAME_LEN] = ""; int project_set = 0; char type[BGPSTREAM_UTILS_STR_NAME_LEN] = ""; int type_set = 0; uint32_t initial_time = 0; int initial_time_set = 0; uint32_t duration = 0; int duration_set = 0; if (count == 0) { fprintf(stderr, "ERROR: Empty JSON response from broker\n"); goto retry; } if (root_tok->type != JSMN_OBJECT) { fprintf(stderr, "ERROR: Root object is not JSON\n"); fprintf(stderr, "INFO: JSON: %s\n", js); goto err; } // iterate over the children of the root object for (i = 0; i < root_tok->size; i++) { // all keys must be strings if (t->type != JSMN_STRING) { fprintf(stderr, "ERROR: Encountered non-string key: '%.*s'\n", t->end - t->start, js + t->start); goto err; } if (json_strcmp(js, t, "time") == 0) { NEXT_TOK; json_type_assert(t, JSMN_PRIMITIVE); json_strtoul(broker_ds->last_response_time, t); time_set = 1; NEXT_TOK; } else if (json_strcmp(js, t, "type") == 0) { NEXT_TOK; json_str_assert(js, t, "data"); NEXT_TOK; } else if (json_strcmp(js, t, "error") == 0) { NEXT_TOK; if (json_isnull(js, t) == 0) { // i.e. there is an error set fprintf(stderr, "ERROR: Broker reported an error: %.*s\n", t->end - t->start, js + t->start); goto err; } NEXT_TOK; } else if (json_strcmp(js, t, "queryParameters") == 0) { NEXT_TOK; json_type_assert(t, JSMN_OBJECT); // skip over this object t = json_skip(t); } else if (json_strcmp(js, t, "data") == 0) { NEXT_TOK; json_type_assert(t, JSMN_OBJECT); NEXT_TOK; json_str_assert(js, t, "dumpFiles"); NEXT_TOK; json_type_assert(t, JSMN_ARRAY); arr_len = t->size; // number of dump files NEXT_TOK; // first elem in array for (j = 0; j < arr_len; j++) { json_type_assert(t, JSMN_OBJECT); obj_len = t->size; NEXT_TOK; url_set = 0; project_set = 0; collector_set = 0; type_set = 0; initial_time_set = 0; duration_set = 0; for (k = 0; k < obj_len; k++) { if (json_strcmp(js, t, "urlType") == 0) { NEXT_TOK; if (json_strcmp(js, t, "simple") != 0) { // not yet supported? fprintf(stderr, "ERROR: Unsupported URL type '%.*s'\n", t->end - t->start, js + t->start); goto err; } NEXT_TOK; } else if (json_strcmp(js, t, "url") == 0) { NEXT_TOK; json_type_assert(t, JSMN_STRING); if (url_len < (t->end - t->start + 1)) { url_len = t->end - t->start + 1; if ((url = realloc(url, url_len)) == NULL) { fprintf(stderr, "ERROR: Could not realloc URL string\n"); goto err; } } json_strcpy(url, t, js); unescape_url(url); url_set = 1; NEXT_TOK; } else if (json_strcmp(js, t, "project") == 0) { NEXT_TOK; json_type_assert(t, JSMN_STRING); json_strcpy(project, t, js); project_set = 1; NEXT_TOK; } else if (json_strcmp(js, t, "collector") == 0) { NEXT_TOK; json_type_assert(t, JSMN_STRING); json_strcpy(collector, t, js); collector_set = 1; NEXT_TOK; } else if (json_strcmp(js, t, "type") == 0) { NEXT_TOK; json_type_assert(t, JSMN_STRING); json_strcpy(type, t, js); type_set = 1; NEXT_TOK; } else if (json_strcmp(js, t, "initialTime") == 0) { NEXT_TOK; json_type_assert(t, JSMN_PRIMITIVE); json_strtoul(initial_time, t); initial_time_set = 1; NEXT_TOK; } else if (json_strcmp(js, t, "duration") == 0) { NEXT_TOK; json_type_assert(t, JSMN_PRIMITIVE); json_strtoul(duration, t); duration_set = 1; NEXT_TOK; } else { fprintf(stderr, "ERROR: Unknown field '%.*s'\n", t->end - t->start, js + t->start); goto err; } } // file obj has been completely read if (url_set == 0 || project_set == 0 || collector_set == 0 || type_set == 0 || initial_time_set == 0 || duration_set == 0) { fprintf(stderr, "ERROR: Invalid dumpFile record\n"); goto retry; } #ifdef WITH_BROKER_DEBUG fprintf(stderr, "----------\n"); fprintf(stderr, "URL: %s\n", url); fprintf(stderr, "Project: %s\n", project); fprintf(stderr, "Collector: %s\n", collector); fprintf(stderr, "Type: %s\n", type); fprintf(stderr, "InitialTime: %" PRIu32 "\n", initial_time); fprintf(stderr, "Duration: %" PRIu32 "\n", duration); #endif // do we need to update our current_window_end? if (initial_time + duration > broker_ds->current_window_end) { broker_ds->current_window_end = (initial_time + duration); } if (bgpstream_input_mgr_push_sorted_input( input_mgr, strdup(url), strdup(project), strdup(collector), strdup(type), initial_time, duration) <= 0) { goto err; } num_results++; } } // TODO: handle unknown tokens } if (time_set == 0) { goto err; } free(url); return num_results; retry: free(url); return ERR_RETRY; err: fprintf(stderr, "ERROR: Invalid JSON response received from broker\n"); free(url); return ERR_RETRY; }
/* * json_top_level -- * Parse the top level JSON input. */ static int json_top_level(WT_SESSION *session, JSON_INPUT_STATE *ins, uint32_t flags) { CONFIG_LIST cl; WT_DECL_RET; char *config, *tableuri; int toktype; static const char *json_markers[] = { "\"config\"", "\"colgroups\"", "\"indices\"", "\"data\"", NULL }; memset(&cl, 0, sizeof(cl)); tableuri = NULL; JSON_EXPECT(session, ins, '{'); while (json_peek(session, ins) == 's') { JSON_EXPECT(session, ins, 's'); tableuri = realloc(tableuri, ins->toklen); snprintf(tableuri, ins->toklen, "%.*s", (int)(ins->toklen - 2), ins->tokstart + 1); JSON_EXPECT(session, ins, ':'); /* * Allow any ordering of 'config', 'colgroups', * 'indices' before 'data', which must appear last. * The non-'data' items build up a list of entries * that created in our session before the data is * inserted. */ for (;;) { if (json_skip(session, ins, json_markers) != 0) goto err; JSON_EXPECT(session, ins, 's'); if (JSON_STRING_MATCH(ins, "config")) { JSON_EXPECT(session, ins, ':'); JSON_EXPECT(session, ins, 's'); if ((ret = json_strdup(ins, &config)) != 0) { ret = util_err(ret, NULL); goto err; } if ((ret = config_list_add(&cl, tableuri)) != 0) goto err; if ((ret = config_list_add(&cl, config)) != 0) goto err; tableuri = NULL; } else if (JSON_STRING_MATCH(ins, "colgroups")) { JSON_EXPECT(session, ins, ':'); JSON_EXPECT(session, ins, '['); if ((ret = json_column_group_index( session, ins, &cl, 0)) != 0) goto err; JSON_EXPECT(session, ins, ']'); } else if (JSON_STRING_MATCH(ins, "indices")) { JSON_EXPECT(session, ins, ':'); JSON_EXPECT(session, ins, '['); if ((ret = json_column_group_index( session, ins, &cl, 1)) != 0) goto err; JSON_EXPECT(session, ins, ']'); } else if (JSON_STRING_MATCH(ins, "data")) { JSON_EXPECT(session, ins, ':'); JSON_EXPECT(session, ins, '['); if ((ret = json_data(session, ins, &cl, flags)) != 0) goto err; config_list_free(&cl); break; } else goto err; } while ((toktype = json_peek(session, ins)) == '}' || toktype == ']') JSON_EXPECT(session, ins, toktype); if (toktype == 0) /* Check EOF. */ break; if (toktype == ',') { JSON_EXPECT(session, ins, ','); if (json_peek(session, ins) != 's') goto err; continue; } } JSON_EXPECT(session, ins, 0); if (0) { err: if (ret == 0) ret = EINVAL; } config_list_free(&cl); if (tableuri != NULL) free(tableuri); return (ret); }