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;
}
Exemplo n.º 3
0
/*
 * 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);
}