Пример #1
0
jsmntok_t *json_parse_input(const char *input, int len, bool *valid)
{
	jsmn_parser parser;
	jsmntok_t *toks;
	jsmnerr_t ret;

	toks = tal_arr(input, jsmntok_t, 10);

again:	
	jsmn_init(&parser);
	ret = jsmn_parse(&parser, input, len, toks, tal_count(toks) - 1);

	switch (ret) {
	case JSMN_ERROR_INVAL:
		*valid = false;
		return tal_free(toks);
	case JSMN_ERROR_PART:
		*valid = true;
		return tal_free(toks);
	case JSMN_ERROR_NOMEM:
		tal_resize(&toks, tal_count(toks) * 2);
		goto again;
	}

	/* Cut to length and return. */
	*valid = true;
	tal_resize(&toks, ret + 1);
	/* Make sure last one is always referencable. */
	toks[ret].type = -1;
	toks[ret].start = toks[ret].end = toks[ret].size = 0;
	
	return toks;
}
Пример #2
0
static void result_append(struct json_result *res, const char *str)
{
	size_t len = tal_count(res->s) - 1;

	tal_resize(&res->s, len + strlen(str) + 1);
	strcpy(res->s + len, str);
}
Пример #3
0
static void add_token(struct token **toks, const char *p, size_t len)
{
	size_t n = tal_count(*toks);
	tal_resize(toks, n+1);
	(*toks)[n].p = p;
	(*toks)[n].len = len;
}
Пример #4
0
static struct io_plan *read_done(struct io_conn *conn, struct data *d)
{
	tal_resize(&d->pattern, tal_count(d->pattern) + 1 + strlen(d->buf));
	strcat(d->pattern, "<");
	strcat(d->pattern, d->buf);
	return read_more(conn, d);
}
Пример #5
0
static char *read_from(const tal_t *ctx, int fd)
{
	size_t max = 128, done = 0;
	int r;
	char *p = tal_arr(ctx, char, max);

	while ((r = read(fd, p + done, max - done)) > 0) {
		done += r;
		if (done == max)
			tal_resize(&p, max *= 2);
	}
	tal_resize(&p, done + 1);
	p[done] = '\0';

	return p;
}
Пример #6
0
/* Make copy of src, replacing "from" with "to". */
static char *replace(const void *ctx, const char *src,
		     const char *from, const char *to)
{
	char *ret = tal_strdup(ctx, "");
	unsigned int rlen, len, add;

	rlen = len = 0;
	for (;;) {
		const char *next = strstr(src+len, from);
		if (!next)
			add = strlen(src+len) + 1;
		else
			add = next - (src+len);

		tal_resize(&ret, rlen + add + strlen(to)+1);
		memcpy(ret+rlen, src+len, add);
		if (!next)
			return ret;
		len += add;
		rlen += add;
		strcpy(ret+rlen, to);
		rlen += strlen(to);
		len += strlen(from);
	}
}
Пример #7
0
static void add_linearize(const void *data, size_t len, void *pptr_)
{
	u8 **pptr = pptr_;
	size_t oldsize = tal_count(*pptr);

	tal_resize(pptr, oldsize + len);
	memcpy(*pptr + oldsize, memcheck(data, len), len);
}
Пример #8
0
jsmntok_t *json_parse_input(const tal_t *ctx,
			    const char *input, int len, bool *valid)
{
	jsmn_parser parser;
	jsmntok_t *toks;
	int ret;

	toks = tal_arr(ctx, jsmntok_t, 10);
	toks[0].type = JSMN_UNDEFINED;

	jsmn_init(&parser);
again:
	ret = jsmn_parse(&parser, input, len, toks, tal_count(toks) - 1);

	switch (ret) {
	case JSMN_ERROR_INVAL:
		*valid = false;
		return tal_free(toks);
	case JSMN_ERROR_NOMEM:
		tal_resize(&toks, tal_count(toks) * 2);
		goto again;
	}

	/* Check whether we read at least one full root element, i.e., root
	 * element has its end set. */
	if (toks[0].type == JSMN_UNDEFINED || toks[0].end == -1) {
		*valid = true;
		return tal_free(toks);
	}

	/* If we read a partial element at the end of the stream we'll get a
	 * ret=JSMN_ERROR_PART, but due to the previous check we know we read at
	 * least one full element, so count tokens that are part of this root
	 * element. */
	ret = json_next(toks) - toks;

	/* Cut to length and return. */
	*valid = true;
	tal_resize(&toks, ret + 1);
	/* Make sure last one is always referenceable. */
	toks[ret].type = -1;
	toks[ret].start = toks[ret].end = toks[ret].size = 0;

	return toks;
}
Пример #9
0
/* enum ... */
static bool tok_take_enum(struct parse_state *ps)
{
	size_t n = 0;
	struct cdump_type *e;
	const char *name;

	name = tok_take_ident(ps->defs, &ps->toks);
	if (!name) {
		complain(ps, "Expected enum name");
		return false;
	}

	e = get_type(ps->defs, CDUMP_ENUM, name);

	/* Duplicate name? */
	if (type_defined(e)) {
		complain(ps, "enum already defined");
		return false;
	}

	if (!tok_take_if(&ps->toks, "{")) {
		complain(ps, "Expected { after enum name");
		return false;
	}

	e->u.enum_vals = tal_arr(e, struct cdump_enum_val, n);
	do {
		struct cdump_enum_val *v;

		/* GCC extension: comma and end of enum */
		if (tok_is(&ps->toks, "}"))
			break;

		tal_resize(&e->u.enum_vals, n+1);
		v = &e->u.enum_vals[n++];

		v->name = tok_take_ident(e, &ps->toks);
		if (!v->name) {
			complain(ps, "Expected enum value name");
			return false;
		}
		if (tok_take_if(&ps->toks, "=")) {
			v->value = tok_take_until(e, &ps->toks, ",}");
			if (!v->value) {
				complain(ps, "Expected , or } to end value");
				return false;
			}
		} else
			v->value = NULL;
	} while (tok_take_if(&ps->toks, ","));

	if (tok_take_if(&ps->toks, "}") && tok_take_if(&ps->toks, ";"))
		return true;

	complain(ps, "Expected }; at end of enum");
	return false;
}
Пример #10
0
static struct io_plan *read_json(struct io_conn *conn,
				 struct json_connection *jcon)
{
	jsmntok_t *toks;
	bool valid;

	log_io(jcon->log, true, jcon->buffer + jcon->used, jcon->len_read);

	/* Resize larger if we're full. */
	jcon->used += jcon->len_read;
	if (jcon->used == tal_count(jcon->buffer))
		tal_resize(&jcon->buffer, jcon->used * 2);

again:
	toks = json_parse_input(jcon->buffer, jcon->used, &valid);
	if (!toks) {
		if (!valid) {
			log_unusual(jcon->dstate->base_log,
				    "Invalid token in json input: '%.*s'",
				    (int)jcon->used, jcon->buffer);
			return io_close(conn);
		}
		/* We need more. */
		goto read_more;
	}

	/* Empty buffer? (eg. just whitespace). */
	if (tal_count(toks) == 1) {
		jcon->used = 0;
		goto read_more;
	}

	parse_request(jcon, toks);

	/* Remove first {}. */
	memmove(jcon->buffer, jcon->buffer + toks[0].end,
		tal_count(jcon->buffer) - toks[0].end);
	jcon->used -= toks[0].end;
	tal_free(toks);

	/* Need to wait for command to finish? */
	if (jcon->current) {
		jcon->len_read = 0;
		return io_wait(conn, jcon, read_json, jcon);
	}

	/* See if we can parse the rest. */
	goto again;

read_more:
	tal_free(toks);
	return io_read_partial(conn, jcon->buffer + jcon->used,
			       tal_count(jcon->buffer) - jcon->used,
			       &jcon->len_read, read_json, jcon);
}
Пример #11
0
static void queue_raw_pkt(struct peer *peer, Pkt *pkt)
{
	size_t n = tal_count(peer->outpkt);
	tal_resize(&peer->outpkt, n+1);
	peer->outpkt[n] = pkt;

	log_debug(peer->log, "Queued pkt %s", pkt_name(pkt->pkt_case));

	/* In case it was waiting for output. */
	io_wake(peer);
}
Пример #12
0
static void remove_htlc(struct channel_oneside *oneside, size_t n)
{
    size_t num = tal_count(oneside->htlcs);

    assert(n < num);

    /* Remove. */
    if (num > 0)
        oneside->htlcs[n] = oneside->htlcs[num-1];
    tal_resize(&oneside->htlcs, num - 1);
}
Пример #13
0
static void add_htlc(struct channel_oneside *oneside, UpdateAddHtlc *ah,
                     const char *file)
{
    size_t num = tal_count(oneside->htlcs);

    if (find_htlc(oneside, ah->r_hash) != num)
        errx(1, "Duplicate R hash in %s", file);

    tal_resize(&oneside->htlcs, num+1);
    oneside->htlcs[num] = ah;
}
Пример #14
0
static void queue_raw_pkt(struct peer *peer, Pkt *pkt,
			  void (*ack_cb)(struct peer *peer, void *arg),
			  void *ack_arg)
{
	size_t n = tal_count(peer->outpkt);
	tal_resize(&peer->outpkt, n+1);
	peer->outpkt[n].pkt = pkt;
	peer->outpkt[n].ack_cb = ack_cb;
	peer->outpkt[n].ack_arg = ack_arg;

	/* In case it was waiting for output. */
	io_wake(peer);
}
Пример #15
0
result_append_fmt(struct json_result *res, const char *fmt, ...)
{
	size_t len = tal_count(res->s) - 1, fmtlen;
	va_list ap;

	va_start(ap, fmt);
	fmtlen = vsnprintf(NULL, 0, fmt, ap);
	va_end(ap);

	tal_resize(&res->s, len + fmtlen + 1);
	va_start(ap, fmt);
	vsprintf(res->s + len, fmt, ap);
	va_end(ap);
}
Пример #16
0
void json_tok_remove(jsmntok_t **tokens, jsmntok_t *tok, size_t num)
{
	assert(*tokens);
	assert((*tokens)->type == JSMN_ARRAY || (*tokens)->type == JSMN_OBJECT);
	const jsmntok_t *src = tok;
	const jsmntok_t *end = json_next(*tokens);
	jsmntok_t *dest = tok;
	int remove_count;

	for (int i = 0; i < num; i++)
		src = json_next(src);

	remove_count = src - tok;

	memmove(dest, src, sizeof(jsmntok_t) * (end - src));

	tal_resize(tokens, tal_count(*tokens) - remove_count);
	(*tokens)->size -= num;
}
Пример #17
0
int main(void)
{
	char *parent, *c[4];
	int i;

	plan_tests(11);

	parent = tal(NULL, char);
	ok1(parent);

	/* Zeroing allocations. */
	for (i = 0; i < 4; i++) {
		c[i] = talz(parent, char);
		ok1(*c[i] == '\0');
		tal_free(c[i]);
	}

	/* Array allocation. */
	for (i = 0; i < 4; i++) {
		c[i] = tal_arr(parent, char, 4);
		strcpy(c[i], "abc");
		tal_free(c[i]);
	}

	/* Zeroing array allocation. */
	for (i = 0; i < 4; i++) {
		c[i] = tal_arrz(parent, char, 4);
		ok1(!c[i][0] && !c[i][1] && !c[i][2] && !c[i][3]);
		strcpy(c[i], "abc");
		tal_free(c[i]);
	}

	/* Resizing. */
	c[0] = tal_arrz(parent, char, 4);
	ok1(tal_resize(&c[0], 6));
	strcpy(c[0], "hello");
	tal_free(c[0]);
	ok1(talloc_total_blocks(parent) == 1);
	tal_free(parent);

	return exit_status();
}
Пример #18
0
static void add_files(struct manifest *m, const char *base, const char *subdir)
{
	DIR *d;
	struct dirent *ent;
	char **subs = tal_arr(m, char *, 0);
	const char *thisdir;

	if (!subdir)
		thisdir = base;
	else
		thisdir = path_join(subs, base, subdir);

	d = opendir(thisdir);
	if (!d)
		err(1, "Opening directory %s", thisdir);

	while ((ent = readdir(d)) != NULL) {
		struct stat st;
		struct ccan_file *f;
		struct list_head *dest;
		bool is_c_src;

		if (ent->d_name[0] == '.')
			continue;

		f = new_ccan_file(m, m->dir,
				  subdir ? path_join(m, subdir, ent->d_name)
				  : ent->d_name);
		if (lstat(f->fullname, &st) != 0)
			err(1, "lstat %s", f->fullname);

		if (S_ISDIR(st.st_mode)) {
			size_t len = tal_count(subs);
			tal_resize(&subs, len+1);
			subs[len] = tal_strcat(subs, f->name, "/");
			continue;
		}
		if (!S_ISREG(st.st_mode)) {
			tal_free(f);
			continue;
		}

		if (streq(f->name, "_info")) {
			m->info_file = f;
			continue;
		}

		is_c_src = strends(f->name, ".c");
		if (!is_c_src && !strends(f->name, ".h")) {
			dest = &m->other_files;
		} else if (!strchr(f->name, '/')) {
			if (is_c_src)
				dest = &m->c_files;
			else
				dest = &m->h_files;
		} else if (strstarts(f->name, "test/")) {
			if (is_c_src) {
				if (strstarts(f->name, "test/api"))
					dest = &m->api_tests;
				else if (strstarts(f->name, "test/run"))
					dest = &m->run_tests;
				else if (strstarts(f->name, "test/compile_ok"))
					dest = &m->compile_ok_tests;
				else if (strstarts(f->name, "test/compile_fail"))
					dest = &m->compile_fail_tests;
				else
					dest = &m->other_test_c_files;
			} else
				dest = &m->other_test_files;
		} else
			dest = &m->other_files;

		list_add(dest, &f->list);
	}
	closedir(d);

	/* Before we recurse, sanity check this is a ccan module. */
	if (!subdir) {
		size_t i;

		if (!m->info_file
		    && list_empty(&m->c_files)
		    && list_empty(&m->h_files))
			errx(1, "No _info, C or H files found here!");

		for (i = 0; i < tal_count(subs); i++)
			add_files(m, base, subs[i]);
	}
	tal_free(subs);
}
Пример #19
0
/* struct|union ... */
static bool tok_take_conglom(struct parse_state *ps,
			     enum cdump_type_kind conglom_kind)
{
	struct cdump_type *e;
	const char *name;
	size_t n;

	assert(conglom_kind == CDUMP_STRUCT || conglom_kind == CDUMP_UNION);

	name = tok_take_ident(ps->defs, &ps->toks);
	if (!name) {
		complain(ps, "Invalid struct/union name");
		return false;
	}

	e = get_type(ps->defs, conglom_kind, name);
	if (type_defined(e)) {
		complain(ps, "Type already defined");
		return false;
	}

	if (!tok_take_if(&ps->toks, "{")) {
		complain(ps, "Expected { for struct/union");
		return false;
	}

	e->u.members = tal_arr(e, struct cdump_member, n = 0);
	while (!tok_is(&ps->toks, "}")) {
		struct cdump_type *basetype;
		const struct token *quals;
		unsigned int num_quals = 0;

		/* Anything can have these prepended. */
		quals = ps->toks;
		while (tok_take_if(&ps->toks, "const")
		       || tok_take_if(&ps->toks, "volatile"))
			num_quals++;

		/* eg. "struct foo" or "varint_t" */
		if (!tok_take_type(ps, &basetype)) {
			complain(ps, "Expected typename inside struct/union");
			return false;
		}

		do {
			struct cdump_member *m;

			tal_resize(&e->u.members, n+1);
			m = &e->u.members[n++];
			m->type = basetype;
			if (num_quals) {
				m->qualifiers
					= string_of_toks(e, quals,
							 quals + num_quals);
			} else
				m->qualifiers = NULL;

			/* May have multiple asterisks. */
			while (tok_take_if(&ps->toks, "*"))
				m->type = ptr_of(ps, m->type);

			m->name = tok_take_ident(e, &ps->toks);
			if (!m->name) {
				complain(ps, "Expected name for member");
				return false;
			}

			/* May be an array. */
			while (tok_take_if(&ps->toks, "[")) {
				if (!tok_take_array(ps, &m->type))
					return false;
			}
		} while (tok_take_if(&ps->toks, ","));

		if (!tok_take_if(&ps->toks, ";")) {
			complain(ps, "Expected ; at end of member");
			return false;
		}
	}

	if (tok_take_if(&ps->toks, "}") && tok_take_if(&ps->toks, ";"))
		return true;
	complain(ps, "Expected }; at end of struct/union");
	return false;
}
Пример #20
0
static struct io_plan *write_done(struct io_conn *conn, struct data *d)
{
	tal_resize(&d->pattern, tal_count(d->pattern) + 1);
	strcat(d->pattern, ">");
	return write_more(conn, d);
}
Пример #21
0
/* Simple test code to create a gateway transaction */
int main(int argc, char *argv[])
{
	int fd, i, off;
	const char *method;
	char *cmd, *resp, *idstr, *rpc_filename;
	char *result_end;
	struct sockaddr_un addr;
	jsmntok_t *toks;
	const jsmntok_t *result, *error, *id;
	char *pettycoin_dir;
	const tal_t *ctx = tal(NULL, char);
	size_t num_opens, num_closes;
	bool valid;

	err_set_progname(argv[0]);

	opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn);
	pettycoin_dir_register_opts(ctx, &pettycoin_dir, &rpc_filename);

	opt_register_noarg("--help|-h", opt_usage_and_exit,
			   "<command> [<params>...]", "Show this message");
	opt_register_noarg("--version|-V", opt_version_and_exit, VERSION,
			   "Display version and exit");

	opt_early_parse(argc, argv, opt_log_stderr_exit);
	opt_parse(&argc, argv, opt_log_stderr_exit);

	method = argv[1];
	if (!method)
		errx(ERROR_USAGE, "Need at least one argument\n%s",
		     opt_usage(argv[0], NULL));

	if (chdir(pettycoin_dir) != 0)
		err(ERROR_TALKING_TO_PETTYCOIN, "Moving into '%s'",
		    pettycoin_dir);

	fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (strlen(rpc_filename) + 1 > sizeof(addr.sun_path))
		errx(ERROR_USAGE, "rpc filename '%s' too long", rpc_filename);
	strcpy(addr.sun_path, rpc_filename);
	addr.sun_family = AF_UNIX;

	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
		err(ERROR_TALKING_TO_PETTYCOIN,
		    "Connecting to '%s'", rpc_filename);

	idstr = tal_fmt(ctx, "pettycoin_query-%i", getpid());
	cmd = tal_fmt(ctx,
		      "{ \"method\" : \"%s\", \"id\" : \"%s\", \"params\" : [ ",
		      method, idstr);

	for (i = 2; i < argc; i++) {
		/* Numbers are left unquoted, and quoted things left alone. */
		if (strspn(argv[i], "0123456789") == strlen(argv[i])
		    || argv[i][0] == '"')
			tal_append_fmt(&cmd, "%s", argv[i]);
		else
			tal_append_fmt(&cmd, "\"%s\"", argv[i]);
		if (i != argc - 1)
			tal_append_fmt(&cmd, ", ");
	}
	tal_append_fmt(&cmd, "] }");

	if (!write_all(fd, cmd, strlen(cmd)))
		err(ERROR_TALKING_TO_PETTYCOIN, "Writing command");

	resp = tal_arr(cmd, char, 100);
	off = 0;
	num_opens = num_closes = 0;
	while ((i = read(fd, resp + off, tal_count(resp) - 1 - off)) > 0) {
		resp[off + i] = '\0';
		num_opens += strcount(resp + off, "{");
		num_closes += strcount(resp + off, "}");

		off += i;
		if (off == tal_count(resp) - 1)
			tal_resize(&resp, tal_count(resp) * 2);

		/* parsing huge outputs is slow: do quick check first. */
		if (num_opens == num_closes && strstr(resp, "\"result\""))
			break;
	}
	if (i < 0)
		err(ERROR_TALKING_TO_PETTYCOIN, "reading response");

	/* Parsing huge results is too slow, so hack fastpath common case */
	result_end = tal_fmt(ctx, ", \"error\" : null, \"id\" : \"%s\" }\n",
			     idstr);

	if (strstarts(resp, "{ \"result\" : ") && strends(resp, result_end)) {
		/* Result is OK, so dump it */
		resp += strlen("{ \"result\" : ");
		printf("%.*s\n", (int)(strlen(resp) - strlen(result_end)), resp);
		tal_free(ctx);
		return 0;
	}

	toks = json_parse_input(resp, off, &valid);
	if (!toks || !valid)
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Malformed response '%s'", resp);

	result = json_get_member(resp, toks, "result");
	if (!result)
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Missing 'result' in response '%s'", resp);
	error = json_get_member(resp, toks, "error");
	if (!error)
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Missing 'error' in response '%s'", resp);
	id = json_get_member(resp, toks, "id");
	if (!id)
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Missing 'id' in response '%s'", resp);
	if (!json_tok_streq(resp, id, idstr))
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Incorrect 'id' in response: %.*s",
		     json_tok_len(id), json_tok_contents(resp, id));

	if (json_tok_is_null(resp, error)) {
		printf("%.*s\n",
		       json_tok_len(result),
		       json_tok_contents(resp, result));
		tal_free(ctx);
		return 0;
	}

	printf("%.*s\n",
	       json_tok_len(error), json_tok_contents(resp, error));
	tal_free(ctx);
	return 1;
}
Пример #22
0
static void add_mod(struct manifest ***deps, struct manifest *m)
{
	unsigned int num = tal_count(*deps);
	tal_resize(deps, num + 1);
	(*deps)[num] = m;
}
Пример #23
0
static void add(u8 **scriptp, const void *mem, size_t len)
{
	size_t oldlen = tal_count(*scriptp);
	tal_resize(scriptp, oldlen + len);
	memcpy(*scriptp + oldlen, mem, len);
}