lightningd: add dev-fail command to inject permenant failure.

A couple of double-free bugs founnd doing this, too.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-08-18 14:13:52 +09:30
parent 524e56cf56
commit 8e0c19c76a
3 changed files with 57 additions and 1 deletions

View File

@ -59,6 +59,8 @@ static void reconnect_failed(struct lightningd_state *dstate,
struct lightningd *ld = ld_from_dstate(dstate);
struct peer *peer = peer_by_id(ld, connection_known_id(c));
log_debug(peer->log, "reconnect_failed");
tal_free(c);
peer_reconnect(peer);
}
@ -68,6 +70,8 @@ static void try_reconnect(struct peer *peer)
struct connection *c;
struct netaddr *addrs;
log_debug(peer->log, "try_reconnect: trying to reconnect");
/* We may already be reconnected (another incoming connection) */
if (peer->owner) {
log_debug(peer->log, "try_reconnect: already reconnected (%s)",
@ -109,7 +113,7 @@ void peer_fail_permanent(struct peer *peer, const u8 *msg)
peer_state_name(peer->state),
(int)tal_len(msg), (char *)msg);
peer->error = towire_error(peer, &all_channels, msg);
peer->owner = NULL;
peer->owner = tal_free(peer->owner);
if (taken(msg))
tal_free(msg);
@ -202,6 +206,7 @@ static void peer_start_closingd(struct peer *peer,
static struct io_plan *send_error(struct io_conn *conn,
struct peer_crypto_state *pcs)
{
log_debug(pcs->peer->log, "Sending canned error");
return peer_write_message(conn, pcs, pcs->peer->error, (void *)io_close_cb);
}
@ -720,6 +725,38 @@ static const struct json_command connect_command = {
};
AUTODATA(json_command, &connect_command);
static void json_dev_fail(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
struct lightningd *ld = ld_from_dstate(cmd->dstate);
jsmntok_t *peertok;
struct peer *peer;
if (!json_get_params(buffer, params,
"id", &peertok,
NULL)) {
command_fail(cmd, "Need id");
return;
}
peer = peer_from_json(ld, buffer, peertok);
if (!peer) {
command_fail(cmd, "Could not find peer with that id");
return;
}
peer_internal_error(peer, "Failing due to dev-fail command");
command_success(cmd, null_response(cmd));
}
static const struct json_command dev_fail_command = {
"dev-fail",
json_dev_fail,
"Fail with peer {id}",
"Returns {} on success"
};
AUTODATA(json_command, &dev_fail_command);
struct log_info {
enum log_level level;
struct json_result *response;

View File

@ -371,6 +371,11 @@ static void destroy_subd(struct subd *sd)
status = -1;
break;
}
/* In case we're freed manually, such as peer_fail_permanent */
if (sd->conn)
sd->conn = tal_free(sd->conn);
log_debug(sd->log, "finishing: %p", sd->finished);
if (sd->finished)
sd->finished(sd, status);

View File

@ -336,6 +336,20 @@ class LightningDTests(BaseLightningDTests):
l2.daemon.wait_for_log('sendrawtx exit 0')
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1
def test_permfail(self):
l1,l2 = self.connect()
self.fund_channel(l1, l2, 10**6)
self.pay(l1,l2,200000000)
# We fail l2, so l1 will reconnect to it.
l2.rpc.dev_fail(l1.info['id']);
l2.daemon.wait_for_log('Failing due to dev-fail command')
l2.daemon.wait_for_log('sendrawtx exit 0')
# "Internal error" in hex
l1.daemon.wait_for_log('WIRE_ERROR.*496e7465726e616c206572726f72')
def test_gossip_jsonrpc(self):
l1,l2 = self.connect()