peer: keep addresses separately from peers.

This makes more sense eventually: we may know the network addresses of
many peers, not just those we're connecting to.  So keep a mapping, and
update it when we successfully connect outwards.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2016-08-18 14:25:14 +09:30
parent f68607d10b
commit 319c2ec5fc
8 changed files with 153 additions and 107 deletions

View File

@@ -203,48 +203,6 @@ void db_add_wallet_privkey(struct lightningd_state *dstate,
fatal("db_add_wallet_privkey:%s", err);
}
static void load_peer_address(struct peer *peer)
{
int err;
sqlite3_stmt *stmt;
sqlite3 *sql = peer->dstate->db->sql;
char *ctx = tal(peer, char);
const char *select;
bool addr_set = false;
select = tal_fmt(ctx,
"SELECT * FROM peer_address WHERE peer = x'%s';",
pubkey_to_hexstr(ctx, peer->dstate->secpctx, peer->id));
err = sqlite3_prepare_v2(sql, select, -1, &stmt, NULL);
if (err != SQLITE_OK)
fatal("load_peer_address:prepare gave %s:%s",
sqlite3_errstr(err), sqlite3_errmsg(sql));
while ((err = sqlite3_step(stmt)) != SQLITE_DONE) {
if (err != SQLITE_ROW)
fatal("load_peer_address:step gave %s:%s",
sqlite3_errstr(err), sqlite3_errmsg(sql));
if (addr_set)
fatal("load_peer_address: two addresses for '%s'",
select);
if (!netaddr_from_blob(sqlite3_column_blob(stmt, 1),
sqlite3_column_bytes(stmt, 1),
&peer->addr))
fatal("load_peer_address: unparsable addresses for '%s'",
select);
addr_set = true;
peer->log = new_log(peer, peer->dstate->log_record, "%s%s:",
log_prefix(peer->dstate->base_log),
netaddr_name(peer, &peer->addr));
}
if (!addr_set)
fatal("load_peer_address: no addresses for '%s'", select);
tal_free(ctx);
}
static void load_peer_secrets(struct peer *peer)
{
int err;
@@ -928,7 +886,6 @@ static void db_load_peers(struct lightningd_state *dstate)
sqlite3_errmsg(dstate->db->sql));
list_for_each(&dstate->peers, peer, list) {
load_peer_address(peer);
load_peer_secrets(peer);
load_peer_closing(peer);
peer->anchor.min_depth = 0;
@@ -946,10 +903,45 @@ static void db_load_peers(struct lightningd_state *dstate)
connect_htlc_src(dstate);
}
static void db_load_addresses(struct lightningd_state *dstate)
{
int err;
sqlite3_stmt *stmt;
sqlite3 *sql = dstate->db->sql;
char *ctx = tal(dstate, char);
const char *select;
select = tal_fmt(ctx, "SELECT * FROM peer_address;");
err = sqlite3_prepare_v2(sql, select, -1, &stmt, NULL);
if (err != SQLITE_OK)
fatal("load_peer_addresses:prepare gave %s:%s",
sqlite3_errstr(err), sqlite3_errmsg(sql));
while ((err = sqlite3_step(stmt)) != SQLITE_DONE) {
struct peer_address *addr;
if (err != SQLITE_ROW)
fatal("load_peer_addresses:step gave %s:%s",
sqlite3_errstr(err), sqlite3_errmsg(sql));
addr = tal(dstate, struct peer_address);
pubkey_from_sql(dstate->secpctx, stmt, 0, &addr->id);
if (!netaddr_from_blob(sqlite3_column_blob(stmt, 1),
sqlite3_column_bytes(stmt, 1),
&addr->addr))
fatal("load_peer_addresses: unparsable addresses for '%s'",
select);
list_add_tail(&dstate->addresses, &addr->list);
log_debug(dstate->base_log, "load_peer_addresses:%s",
pubkey_to_hexstr(ctx, dstate->secpctx, &addr->id));
}
tal_free(ctx);
}
static void db_load(struct lightningd_state *dstate)
{
db_load_wallet(dstate);
db_load_addresses(dstate);
db_load_peers(dstate);
}
@@ -1152,14 +1144,6 @@ bool db_create_peer(struct peer *peer)
if (errmsg)
goto out;
errmsg = db_exec(ctx, peer->dstate,
"INSERT INTO peer_address VALUES (x'%s', x'%s');",
peerid,
netaddr_to_hex(ctx, &peer->addr));
if (errmsg)
goto out;
if (!db_commit_transaction(peer))
errmsg = "Commit failed";
@@ -1413,6 +1397,26 @@ bool db_add_commit_map(struct peer *peer,
return !errmsg;
}
/* FIXME: Clean out old ones! */
bool db_add_peer_address(struct lightningd_state *dstate,
const struct peer_address *addr)
{
const char *errmsg, *ctx = tal(dstate, char);
log_debug(dstate->base_log, "%s", __func__);
assert(!dstate->db->in_transaction);
errmsg = db_exec(ctx, dstate,
"INSERT OR REPLACE INTO peer_address VALUES (x'%s', x'%s');",
pubkey_to_hexstr(ctx, dstate->secpctx, &addr->id),
netaddr_to_hex(ctx, &addr->addr));
if (errmsg)
log_broken(dstate->base_log, "%s:%s", __func__, errmsg);
tal_free(ctx);
return !errmsg;
}
void db_forget_peer(struct peer *peer)
{
const char *ctx = tal(peer, char);

View File

@@ -17,6 +17,9 @@ bool db_commit_transaction(struct peer *peer);
void db_add_wallet_privkey(struct lightningd_state *dstate,
const struct privkey *privkey);
bool db_add_peer_address(struct lightningd_state *dstate,
const struct peer_address *addr);
/* Must NOT be inside transaction. */
bool db_htlc_fulfilled(struct peer *peer, const struct htlc *htlc);
bool db_set_our_closing_script(struct peer *peer);

View File

@@ -251,6 +251,7 @@ static struct lightningd_state *lightningd_state(void)
list_head_init(&dstate->bitcoin_req);
list_head_init(&dstate->wallet);
list_head_init(&dstate->payments);
list_head_init(&dstate->addresses);
dstate->dev_never_routefail = false;
dstate->bitcoin_req_running = false;
dstate->nodes = empty_node_map(dstate);

View File

@@ -84,6 +84,9 @@ struct lightningd_state {
/* Our peers. */
struct list_head peers;
/* Addresses to contact peers. */
struct list_head addresses;
/* Crypto tables for global use. */
secp256k1_context *secpctx;

View File

@@ -77,3 +77,12 @@ bool netaddr_from_blob(const void *linear, size_t len, struct netaddr *a)
pull(&p, &len, &a->saddr, a->addrlen);
return p != NULL && len == 0;
}
bool netaddr_from_fd(int fd, int type, int protocol, struct netaddr *a)
{
a->type = type;
a->protocol = protocol;
a->addrlen = sizeof(a->saddr);
return getpeername(fd, &a->saddr.s, &a->addrlen) == 0;
}

View File

@@ -26,6 +26,8 @@ char *netaddr_name(const tal_t *ctx, const struct netaddr *a);
/* Create a addrinfo (as wanted by io_connect) for this address. */
void netaddr_to_addrinfo(struct addrinfo *ai, const struct netaddr *a);
bool netaddr_from_fd(int fd, int type, int protocol, struct netaddr *a);
bool netaddr_from_blob(const void *linear, size_t len, struct netaddr *a);
char *netaddr_to_hex(const tal_t *ctx, const struct netaddr *a);

View File

@@ -2101,21 +2101,6 @@ struct commit_info *new_commit_info(const tal_t *ctx, u64 commit_num)
return ci;
}
static bool peer_getaddr(struct peer *peer,
int fd, int addr_type, int addr_protocol)
{
peer->addr.type = addr_type;
peer->addr.protocol = addr_protocol;
peer->addr.addrlen = sizeof(peer->addr.saddr);
if (getpeername(fd, &peer->addr.saddr.s, &peer->addr.addrlen) != 0) {
log_broken(peer->dstate->base_log,
"Could not get address for peer: %s",
strerror(errno));
return false;
}
return true;
}
static bool peer_reconnected(struct peer *peer,
struct io_conn *conn,
int addr_type, int addr_protocol,
@@ -2123,13 +2108,15 @@ static bool peer_reconnected(struct peer *peer,
const struct pubkey *id,
bool we_connected)
{
char *prefix;
char *name;
struct netaddr addr;
assert(structeq(peer->id, id));
peer->io_data = tal_steal(peer, iod);
/* FIXME: Attach IO logging for this peer. */
if (!peer_getaddr(peer, io_conn_fd(conn), addr_type, addr_protocol))
if (!netaddr_from_fd(io_conn_fd(conn), addr_type, addr_protocol, &addr))
return false;
/* If we free peer, conn should be closed, but can't be freed
@@ -2137,18 +2124,10 @@ static bool peer_reconnected(struct peer *peer,
peer->conn = conn;
io_set_finish(conn, peer_disconnect, peer);
prefix = tal_fmt(peer, "%s%s:%s:",
log_prefix(peer->dstate->base_log),
we_connected ? "out" : "in",
netaddr_name(peer, &peer->addr));
if (peer->log) {
log_info(peer->log, "Reconnected as %s", prefix);
set_log_prefix(peer->log, prefix);
} else {
peer->log = new_log(peer, peer->dstate->log_record,
"%s", prefix);
}
tal_free(prefix);
name = netaddr_name(peer, &addr);
log_info(peer->log, "Reconnected %s %s",
we_connected ? "out to" : "in from", name);
tal_free(name);
return true;
}
@@ -2202,6 +2181,8 @@ struct peer *new_peer(struct lightningd_state *dstate,
peer->local.mindepth = dstate->config.anchor_confirms;
peer->local.commit = peer->remote.commit = NULL;
peer->local.staging_cstate = peer->remote.staging_cstate = NULL;
peer->log = new_log(peer, peer->dstate->log_record, "%s:peer %p:",
log_prefix(peer->dstate->base_log), peer);
htlc_map_init(&peer->htlcs);
shachain_init(&peer->their_preimages);
@@ -2211,6 +2192,34 @@ struct peer *new_peer(struct lightningd_state *dstate,
return peer;
}
static struct peer_address *find_address(struct lightningd_state *dstate,
const struct pubkey *id)
{
struct peer_address *i;
list_for_each(&dstate->addresses, i, list) {
if (structeq(&id->pubkey, &i->id.pubkey))
return i;
}
return NULL;
}
static bool add_peer_address(struct lightningd_state *dstate,
const struct pubkey *id,
const struct netaddr *addr)
{
struct peer_address *a = find_address(dstate, id);
if (a) {
a->addr = *addr;
} else {
a = tal(dstate, struct peer_address);
a->addr = *addr;
a->id = *id;
list_add_tail(&dstate->addresses, &a->list);
}
return db_add_peer_address(dstate, a);
}
static bool peer_first_connected(struct peer *peer,
struct io_conn *conn,
int addr_type, int addr_protocol,
@@ -2218,6 +2227,9 @@ static bool peer_first_connected(struct peer *peer,
const struct pubkey *id,
bool we_connected)
{
char *name;
struct netaddr addr;
peer->io_data = tal_steal(peer, iod);
peer->id = tal_dup(peer, struct pubkey, id);
/* FIXME: Make this dynamic! */
@@ -2234,28 +2246,25 @@ static bool peer_first_connected(struct peer *peer,
peer->conn = conn;
io_set_finish(conn, peer_disconnect, peer);
/* FIXME: Attach IO logging for this peer. */
peer->addr.type = addr_type;
peer->addr.protocol = addr_protocol;
peer->addr.addrlen = sizeof(peer->addr.saddr);
if (getpeername(io_conn_fd(conn), &peer->addr.saddr.s,
&peer->addr.addrlen) != 0) {
log_unusual(peer->dstate->base_log,
"Could not get address for peer: %s",
strerror(errno));
return tal_free(peer);
}
peer->anchor.min_depth = get_block_height(peer->dstate);
peer->log = new_log(peer, peer->dstate->log_record, "%s%s:%s:",
log_prefix(peer->dstate->base_log),
we_connected ? "out" : "in",
netaddr_name(peer, &peer->addr));
/* FIXME: Attach IO logging for this peer. */
if (!netaddr_from_fd(io_conn_fd(conn), addr_type, addr_protocol, &addr))
return false;
/* Save/update address if we connected to them. */
if (we_connected && !add_peer_address(peer->dstate, peer->id, &addr))
return false;
name = netaddr_name(peer, &addr);
log_info(peer->log, "Connected %s %s id %s",
we_connected ? "out to" : "in from", name,
pubkey_to_hexstr(name, peer->dstate->secpctx, peer->id));
tal_free(name);
log_debug(peer->log, "Using fee rate %"PRIu64,
peer->local.commit_fee_rate);
return peer;
return true;
}
static u64 peer_commitsigs_received(struct peer *peer)
@@ -2372,8 +2381,8 @@ static struct io_plan *crypto_on_reconnect(struct io_conn *conn,
u64 sigs, revokes, shutdown, closing;
/* Setup peer->conn and peer->io_data */
if (!peer_reconnected(peer, conn, peer->addr.type,
peer->addr.protocol, iod, id, we_connected))
if (!peer_reconnected(peer, conn, SOCK_STREAM, IPPROTO_TCP,
iod, id, we_connected))
return io_close(conn);
sigs = peer_commitsigs_received(peer);
@@ -3849,14 +3858,17 @@ static void reconnect_failed(struct io_conn *conn, struct peer *peer)
static struct io_plan *init_conn(struct io_conn *conn, struct peer *peer)
{
struct addrinfo a;
struct peer_address *addr = find_address(peer->dstate, peer->id);
netaddr_to_addrinfo(&a, &peer->addr);
netaddr_to_addrinfo(&a, &addr->addr);
return io_connect(conn, &a, peer_reconnect, peer);
}
static void try_reconnect(struct peer *peer)
{
struct io_conn *conn;
struct peer_address *addr;
char *name;
int fd;
/* Already reconnected? */
@@ -3865,8 +3877,14 @@ static void try_reconnect(struct peer *peer)
return;
}
fd = socket(peer->addr.saddr.s.sa_family, peer->addr.type,
peer->addr.protocol);
addr = find_address(peer->dstate, peer->id);
if (!addr) {
log_debug(peer->log, "try_reconnect: no known address");
return;
}
fd = socket(addr->addr.saddr.s.sa_family, addr->addr.type,
addr->addr.protocol);
if (fd < 0) {
log_broken(peer->log, "do_reconnect: failed to create socket: %s",
strerror(errno));
@@ -3877,7 +3895,9 @@ static void try_reconnect(struct peer *peer)
assert(!peer->conn);
conn = io_new_conn(peer->dstate, fd, init_conn, peer);
log_debug(peer->log, "Trying to reconnect...");
name = netaddr_name(peer, &addr->addr);
log_debug(peer->log, "Trying to reconnect to %s", name);
tal_free(name);
io_set_finish(conn, reconnect_failed, peer);
}

View File

@@ -103,9 +103,6 @@ struct peer {
/* Global state. */
struct lightningd_state *dstate;
/* The other end's address. */
struct netaddr addr;
/* Their ID. */
struct pubkey *id;
@@ -228,6 +225,13 @@ struct peer {
struct shachain their_preimages;
};
/* Mapping for id -> network address. */
struct peer_address {
struct list_node list;
struct pubkey id;
struct netaddr addr;
};
void setup_listeners(struct lightningd_state *dstate, unsigned int portnum);
struct peer *find_peer(struct lightningd_state *dstate, const struct pubkey *id);