|
|
@ -5,12 +5,15 @@ |
|
|
|
#include <ccan/tal/str/str.h> |
|
|
|
#include <common/daemon.h> |
|
|
|
#include <common/memleak.h> |
|
|
|
#include <common/timeout.h> |
|
|
|
#include <gossipd/gen_gossip_wire.h> |
|
|
|
#include <lightningd/chaintopology.h> |
|
|
|
#include <lightningd/jsonrpc.h> |
|
|
|
#include <lightningd/jsonrpc_errors.h> |
|
|
|
#include <lightningd/lightningd.h> |
|
|
|
#include <lightningd/log.h> |
|
|
|
#include <lightningd/param.h> |
|
|
|
#include <lightningd/subd.h> |
|
|
|
#include <stdio.h> |
|
|
|
|
|
|
|
static void json_add_ptr(struct json_stream *response, const char *name, |
|
|
@ -111,7 +114,8 @@ static void json_add_backtrace(struct json_stream *response, |
|
|
|
|
|
|
|
static void scan_mem(struct command *cmd, |
|
|
|
struct json_stream *response, |
|
|
|
struct lightningd *ld) |
|
|
|
struct lightningd *ld, |
|
|
|
const struct subd *leaking_subd) |
|
|
|
{ |
|
|
|
struct htable *memtable; |
|
|
|
const tal_t *i; |
|
|
@ -147,14 +151,64 @@ static void scan_mem(struct command *cmd, |
|
|
|
json_array_end(response); |
|
|
|
json_object_end(response); |
|
|
|
} |
|
|
|
|
|
|
|
if (leaking_subd) { |
|
|
|
json_object_start(response, NULL); |
|
|
|
json_add_string(response, "subdaemon", leaking_subd->name); |
|
|
|
json_object_end(response); |
|
|
|
} |
|
|
|
json_array_end(response); |
|
|
|
} |
|
|
|
|
|
|
|
struct leak_info { |
|
|
|
struct command *cmd; |
|
|
|
struct subd *leaker; |
|
|
|
}; |
|
|
|
|
|
|
|
static void report_leak_info2(struct leak_info *leak_info) |
|
|
|
{ |
|
|
|
struct json_stream *response = json_stream_success(leak_info->cmd); |
|
|
|
|
|
|
|
json_object_start(response, NULL); |
|
|
|
scan_mem(leak_info->cmd, response, leak_info->cmd->ld, leak_info->leaker); |
|
|
|
json_object_end(response); |
|
|
|
|
|
|
|
command_success(leak_info->cmd, response); |
|
|
|
} |
|
|
|
|
|
|
|
static void report_leak_info(struct command *cmd, struct subd *leaker) |
|
|
|
{ |
|
|
|
struct leak_info *leak_info = tal(cmd, struct leak_info); |
|
|
|
|
|
|
|
leak_info->cmd = cmd; |
|
|
|
leak_info->leaker = leaker; |
|
|
|
|
|
|
|
/* Leak detection in a reply handler thinks we're leaking conn. */ |
|
|
|
notleak(new_reltimer(&leak_info->cmd->ld->timers, leak_info->cmd, |
|
|
|
time_from_sec(0), |
|
|
|
report_leak_info2, leak_info)); |
|
|
|
} |
|
|
|
|
|
|
|
static void gossip_dev_memleak_done(struct subd *gossipd, |
|
|
|
const u8 *reply, |
|
|
|
const int *fds UNUSED, |
|
|
|
struct command *cmd) |
|
|
|
{ |
|
|
|
bool found_leak; |
|
|
|
|
|
|
|
if (!fromwire_gossip_dev_memleak_reply(reply, &found_leak)) { |
|
|
|
command_fail(cmd, LIGHTNINGD, "Bad gossip_dev_memleak"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
report_leak_info(cmd, found_leak ? gossipd : NULL); |
|
|
|
} |
|
|
|
|
|
|
|
static void json_memleak(struct command *cmd, |
|
|
|
const char *buffer UNNEEDED, |
|
|
|
const jsmntok_t *params UNNEEDED) |
|
|
|
{ |
|
|
|
struct json_stream *response; |
|
|
|
struct lightningd *ld = cmd->ld; |
|
|
|
|
|
|
|
if (!param(cmd, buffer, params, NULL)) |
|
|
|
return; |
|
|
@ -165,12 +219,9 @@ static void json_memleak(struct command *cmd, |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
response = json_stream_success(cmd); |
|
|
|
json_object_start(response, NULL); |
|
|
|
scan_mem(cmd, response, cmd->ld); |
|
|
|
json_object_end(response); |
|
|
|
|
|
|
|
command_success(cmd, response); |
|
|
|
subd_req(ld->gossip, ld->gossip, take(towire_gossip_dev_memleak(NULL)), |
|
|
|
-1, 0, gossip_dev_memleak_done, cmd); |
|
|
|
command_still_pending(cmd); |
|
|
|
} |
|
|
|
|
|
|
|
static const struct json_command dev_memleak_command = { |
|
|
|