mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV: 1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`. 2. Every new peer, gossipd hands up to lightningd, with global/local features and the peer fd and a gossip fd using `gossip_peer_connected` 3. If lightningd doesn't want it, it just hands the peerfd and global/local features back to gossipd using `gossipctl_handle_peer` 4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends it up using `gossip_peer_nongossip`. 5. If lightningd wants to fund a channel, it simply calls `release_channel`. Notes: * There's no more "unique_id": we use the peer id. * For the moment, we don't ask gossipd when we're told to list peers, so connected peers without a channel don't appear in the JSON getpeers API. * We add a `gossipctl_peer_addrhint` for the moment, so you can connect to a specific ip/port, but using other sources is a TODO. * We now (correctly) only give up on reaching a peer after we exchange init messages, which changes the test_disconnect case. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
2273ce783e
commit
474887512d
@ -13,6 +13,7 @@ LIGHTNINGD_GOSSIP_CONTROL_OBJS := $(LIGHTNINGD_GOSSIP_CONTROL_SRC:.c=.o)
|
||||
|
||||
# gossipd needs these:
|
||||
LIGHTNINGD_GOSSIP_HEADERS := gossipd/gen_gossip_wire.h \
|
||||
gossipd/handshake.h \
|
||||
gossipd/routing.h \
|
||||
gossipd/broadcast.h
|
||||
LIGHTNINGD_GOSSIP_SRC := gossipd/gossip.c \
|
||||
@ -48,7 +49,11 @@ GOSSIPD_COMMON_OBJS := \
|
||||
common/type_to_string.o \
|
||||
common/utils.o \
|
||||
common/version.o \
|
||||
lightningd/gossip_msg.o
|
||||
common/wire_error.o \
|
||||
hsmd/client.o \
|
||||
hsmd/gen_hsm_client_wire.o \
|
||||
lightningd/gossip_msg.o \
|
||||
lightningd/netaddr.o
|
||||
|
||||
$(LIGHTNINGD_GOSSIP_OBJS) $(LIGHTNINGD_GOSSIP_CLIENT_OBJS): $(LIGHTNINGD_HEADERS)
|
||||
|
||||
|
981
gossipd/gossip.c
981
gossipd/gossip.c
File diff suppressed because it is too large
Load Diff
@ -1,52 +1,71 @@
|
||||
# Peers can give a bad message, we close their fd, but no harm done.
|
||||
gossipstatus_peer_bad_msg,13000
|
||||
gossipstatus_peer_bad_msg,,unique_id,u64
|
||||
gossipstatus_peer_bad_msg,,len,u16
|
||||
gossipstatus_peer_bad_msg,,err,len*u8
|
||||
|
||||
# Misc problems like opening control fd.
|
||||
gossipstatus_peer_failed,13001
|
||||
gossipstatus_peer_failed,,unique_id,u64
|
||||
gossipstatus_peer_failed,,len,u16
|
||||
gossipstatus_peer_failed,,err,len*u8
|
||||
|
||||
#include <common/cryptomsg.h>
|
||||
|
||||
# Initialize the gossip daemon
|
||||
# Initialize the gossip daemon.
|
||||
gossipctl_init,3000
|
||||
gossipctl_init,,broadcast_interval,u32
|
||||
gossipctl_init,,chain_hash,struct sha256_double
|
||||
gossipctl_init,,id,struct pubkey
|
||||
# If non-zero, port to listen on.
|
||||
gossipctl_init,,port,u16
|
||||
gossipctl_init,,gflen,u16
|
||||
gossipctl_init,,gfeatures,gflen*u8
|
||||
gossipctl_init,,lflen,u16
|
||||
gossipctl_init,,lfeatures,lflen*u8
|
||||
|
||||
# These take an fd, but have no response
|
||||
gossipctl_new_peer,3001
|
||||
gossipctl_new_peer,,unique_id,u64
|
||||
gossipctl_new_peer,,crypto_state,struct crypto_state
|
||||
# Master -> gossipd: Optional hint for where to find peer.
|
||||
gossipctl_peer_addrhint,3014
|
||||
gossipctl_peer_addrhint,,id,struct pubkey
|
||||
gossipctl_peer_addrhint,,addr,struct ipaddr
|
||||
|
||||
# Tell it to release a peer which has initialized.
|
||||
gossipctl_release_peer,3002
|
||||
gossipctl_release_peer,,unique_id,u64
|
||||
# Master -> gossipd: connect to a peer. We may get a peer_connected.
|
||||
gossipctl_reach_peer,3001
|
||||
gossipctl_reach_peer,,id,struct pubkey
|
||||
|
||||
# This releases the peer and returns the cryptostate (followed two fds: peer and gossip)
|
||||
gossipctl_release_peer_reply,3102
|
||||
# Gossipd -> master: we got a peer. Two fds: peer and gossip
|
||||
gossip_peer_connected,3002
|
||||
gossip_peer_connected,,id,struct pubkey
|
||||
gossip_peer_connected,,crypto_state,struct crypto_state
|
||||
gossip_peer_connected,,gflen,u16
|
||||
gossip_peer_connected,,gfeatures,gflen*u8
|
||||
gossip_peer_connected,,lflen,u16
|
||||
gossip_peer_connected,,lfeatures,lflen*u8
|
||||
|
||||
# Gossipd -> master: peer sent non-gossip packet. Two fds: peer and gossip
|
||||
gossip_peer_nongossip,3003
|
||||
gossip_peer_nongossip,,id,struct pubkey
|
||||
gossip_peer_nongossip,,crypto_state,struct crypto_state
|
||||
gossip_peer_nongossip,,gflen,u16
|
||||
gossip_peer_nongossip,,gfeatures,gflen*u8
|
||||
gossip_peer_nongossip,,lflen,u16
|
||||
gossip_peer_nongossip,,lfeatures,lflen*u8
|
||||
gossip_peer_nongossip,,len,u16
|
||||
gossip_peer_nongossip,,msg,len*u8
|
||||
|
||||
# Master -> gossipd: release a peer (so we can open a channel)
|
||||
gossipctl_release_peer,3004
|
||||
gossipctl_release_peer,,id,struct pubkey
|
||||
|
||||
# Gossipd -> master: reply to gossip_release_peer. Two fds: peer and gossip.
|
||||
gossipctl_release_peer_reply,3104
|
||||
gossipctl_release_peer_reply,,crypto_state,struct crypto_state
|
||||
gossipctl_release_peer_reply,,gflen,u16
|
||||
gossipctl_release_peer_reply,,gfeatures,gflen*u8
|
||||
gossipctl_release_peer_reply,,lflen,u16
|
||||
gossipctl_release_peer_reply,,lfeatures,lflen*u8
|
||||
|
||||
# This is if we couldn't find the peer.
|
||||
gossipctl_release_peer_replyfail,3202
|
||||
# Gossipd -> master: reply to gossip_release_peer if we couldn't find the peer.
|
||||
gossipctl_release_peer_replyfail,3204
|
||||
|
||||
# This is where we save a peer's features.
|
||||
#gossipstatus_peer_features,3001
|
||||
#gossipstatus_peer_features,,unique_id,u64
|
||||
#gossipstatus_peer_features,,gflen,u16
|
||||
#gossipstatus_peer_features,,globalfeatures,gflen*u8
|
||||
#gossipstatus_peer_features,,lflen,u16
|
||||
#gossipstatus_peer_features,,localfeatures,lflen*u8
|
||||
|
||||
# Peer can send non-gossip packet (usually an open_channel) (followed two fds: peer and gossip)
|
||||
gossipstatus_peer_nongossip,3004
|
||||
gossipstatus_peer_nongossip,,unique_id,u64
|
||||
gossipstatus_peer_nongossip,,crypto_state,struct crypto_state
|
||||
gossipstatus_peer_nongossip,,len,u16
|
||||
gossipstatus_peer_nongossip,,msg,len*u8
|
||||
# Gossipd -> master: take over peer, with optional msg. (+peer fd)
|
||||
gossipctl_handle_peer,3013
|
||||
gossipctl_handle_peer,,id,struct pubkey
|
||||
gossipctl_handle_peer,,crypto_state,struct crypto_state
|
||||
gossipctl_handle_peer,,gflen,u16
|
||||
gossipctl_handle_peer,,gfeatures,gflen*u8
|
||||
gossipctl_handle_peer,,lflen,u16
|
||||
gossipctl_handle_peer,,lfeatures,lflen*u8
|
||||
gossipctl_handle_peer,,len,u16
|
||||
gossipctl_handle_peer,,msg,len*u8
|
||||
|
||||
# Pass JSON-RPC getnodes call through
|
||||
gossip_getnodes_request,3005
|
||||
@ -73,13 +92,16 @@ gossip_getchannels_reply,3107
|
||||
gossip_getchannels_reply,,num_channels,u16
|
||||
gossip_getchannels_reply,,nodes,num_channels*struct gossip_getchannels_entry
|
||||
|
||||
# Ping/pong test.
|
||||
# Ping/pong test. Waits for a reply if it expects one.
|
||||
gossip_ping,3008
|
||||
gossip_ping,,unique_id,u64
|
||||
gossip_ping,,id,struct pubkey
|
||||
gossip_ping,,num_pong_bytes,u16
|
||||
gossip_ping,,len,u16
|
||||
|
||||
gossip_ping_reply,3108
|
||||
# False if id in gossip_ping was unknown.
|
||||
gossip_ping_reply,,sent,bool
|
||||
# 0 == no pong expected
|
||||
gossip_ping_reply,,totlen,u16
|
||||
|
||||
# Given a short_channel_id, return the endpoints
|
||||
@ -96,25 +118,3 @@ gossip_forwarded_msg,3010
|
||||
gossip_forwarded_msg,,msglen,u16
|
||||
gossip_forwarded_msg,,msg,msglen*u8
|
||||
|
||||
# If peer is still connected, fail it (master does this for reconnect)
|
||||
gossipctl_drop_peer,3011
|
||||
gossipctl_drop_peer,,unique_id,u64
|
||||
|
||||
# Get a gossip fd for this peer (it has reconnected)
|
||||
gossipctl_get_peer_gossipfd,3012
|
||||
gossipctl_get_peer_gossipfd,,unique_id,u64
|
||||
# Does it want a full dump of gossip?
|
||||
gossipctl_get_peer_gossipfd,,sync,bool
|
||||
|
||||
# + fd.
|
||||
gossipctl_get_peer_gossipfd_reply,3112
|
||||
|
||||
# Failure (can't make new socket)
|
||||
gossipctl_get_peer_gossipfd_replyfail,3212
|
||||
|
||||
# Send canned message to peer and fail it.
|
||||
gossipctl_fail_peer,3013
|
||||
gossipctl_fail_peer,,unique_id,u64
|
||||
gossipctl_fail_peer,,crypto_state,struct crypto_state
|
||||
gossipctl_fail_peer,,len,u16
|
||||
gossipctl_fail_peer,,failmsg,len*u8
|
||||
|
|
@ -34,13 +34,13 @@ LIGHTNINGD_COMMON_OBJS := \
|
||||
common/utils.o \
|
||||
common/utxo.o \
|
||||
common/version.o \
|
||||
common/wire_error.o \
|
||||
common/withdraw_tx.o
|
||||
|
||||
LIGHTNINGD_SRC := \
|
||||
lightningd/bitcoind.c \
|
||||
lightningd/build_utxos.c \
|
||||
lightningd/chaintopology.c \
|
||||
lightningd/dns.c \
|
||||
lightningd/gossip_control.c \
|
||||
lightningd/gossip_msg.c \
|
||||
lightningd/hsm_control.c \
|
||||
@ -50,7 +50,6 @@ LIGHTNINGD_SRC := \
|
||||
lightningd/lightningd.c \
|
||||
lightningd/log.c \
|
||||
lightningd/netaddr.c \
|
||||
lightningd/new_connection.c \
|
||||
lightningd/opt_time.c \
|
||||
lightningd/options.c \
|
||||
lightningd/pay.c \
|
||||
|
@ -13,16 +13,18 @@ static bool ping_reply(struct subd *subd, const u8 *msg, const int *fds,
|
||||
struct command *cmd)
|
||||
{
|
||||
u16 totlen;
|
||||
bool ok;
|
||||
bool ok, sent = true;
|
||||
|
||||
log_debug(subd->ld->log, "Got ping reply!");
|
||||
if (streq(subd->name, "lightning_channeld"))
|
||||
ok = fromwire_channel_ping_reply(msg, NULL, &totlen);
|
||||
else
|
||||
ok = fromwire_gossip_ping_reply(msg, NULL, &totlen);
|
||||
ok = fromwire_gossip_ping_reply(msg, NULL, &sent, &totlen);
|
||||
|
||||
if (!ok)
|
||||
command_fail(cmd, "Bad reply message");
|
||||
else if (!sent)
|
||||
command_fail(cmd, "Unknown peer");
|
||||
else {
|
||||
struct json_result *response = new_json_result(cmd);
|
||||
|
||||
@ -41,6 +43,8 @@ static void json_dev_ping(struct command *cmd,
|
||||
u8 *msg;
|
||||
jsmntok_t *peeridtok, *lentok, *pongbytestok;
|
||||
unsigned int len, pongbytes;
|
||||
struct pubkey id;
|
||||
struct subd *owner;
|
||||
|
||||
if (!json_get_params(buffer, params,
|
||||
"peerid", &peeridtok,
|
||||
@ -51,21 +55,8 @@ static void json_dev_ping(struct command *cmd,
|
||||
return;
|
||||
}
|
||||
|
||||
peer = peer_from_json(cmd->ld, buffer, peeridtok);
|
||||
if (!peer) {
|
||||
command_fail(cmd, "Could not find peer with that peerid");
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: These checks are horrible, use a peer flag to say it's
|
||||
* ready to forward! */
|
||||
if (peer->owner && !streq(peer->owner->name, "lightning_channeld")
|
||||
&& !streq(peer->owner->name, "lightning_gossipd")) {
|
||||
command_fail(cmd, "Peer in %s",
|
||||
peer->owner ? peer->owner->name : "unattached");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json_tok_number(buffer, lentok, &len)) {
|
||||
command_fail(cmd, "'%.*s' is not a valid number",
|
||||
(int)(lentok->end - lentok->start),
|
||||
@ -80,13 +71,32 @@ static void json_dev_ping(struct command *cmd,
|
||||
return;
|
||||
}
|
||||
|
||||
if (streq(peer->owner->name, "lightning_channeld"))
|
||||
msg = towire_channel_ping(cmd, pongbytes, len);
|
||||
else
|
||||
msg = towire_gossip_ping(cmd, peer->unique_id, pongbytes, len);
|
||||
if (!json_tok_pubkey(buffer, peeridtok, &id)) {
|
||||
command_fail(cmd, "'%.*s' is not a valid pubkey",
|
||||
(int)(peeridtok->end - peeridtok->start),
|
||||
buffer + peeridtok->start);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: If subdaemon dies? */
|
||||
subd_req(peer->owner, peer->owner, take(msg), -1, 0, ping_reply, cmd);
|
||||
/* First, see if it's in channeld. */
|
||||
peer = peer_by_id(cmd->ld, &id);
|
||||
if (peer) {
|
||||
if (!peer->owner ||
|
||||
!streq(peer->owner->name, "lightning_channeld")) {
|
||||
command_fail(cmd, "Peer in %s",
|
||||
peer->owner
|
||||
? peer->owner->name : "unattached");
|
||||
return;
|
||||
}
|
||||
msg = towire_channel_ping(cmd, pongbytes, len);
|
||||
owner = peer->owner;
|
||||
} else {
|
||||
/* We assume it's in gossipd. */
|
||||
msg = towire_gossip_ping(cmd, &id, pongbytes, len);
|
||||
owner = cmd->ld->gossip;
|
||||
}
|
||||
|
||||
subd_req(owner, owner, take(msg), -1, 0, ping_reply, cmd);
|
||||
}
|
||||
|
||||
static const struct json_command dev_ping_command = {
|
||||
|
247
lightningd/dns.c
247
lightningd/dns.c
@ -1,247 +0,0 @@
|
||||
/* Async dns helper. */
|
||||
#include "dns.h"
|
||||
#include "lightningd.h"
|
||||
#include "log.h"
|
||||
#include "netaddr.h"
|
||||
#include <assert.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
struct dns_async {
|
||||
struct lightningd *ld;
|
||||
struct io_plan *(*init)(struct io_conn *, struct lightningd *,
|
||||
const struct netaddr *,
|
||||
void *);
|
||||
void (*fail)(struct lightningd *, void *arg);
|
||||
const char *name;
|
||||
void *arg;
|
||||
int pid;
|
||||
size_t num_addresses;
|
||||
struct netaddr *addresses;
|
||||
};
|
||||
|
||||
/* This runs in the child */
|
||||
static void lookup_and_write(int fd, const char *name, const char *port)
|
||||
{
|
||||
struct addrinfo *addr, *i;
|
||||
struct netaddr *addresses;
|
||||
size_t num;
|
||||
struct addrinfo hints;
|
||||
|
||||
/* We don't want UDP sockets (yet?) */
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (getaddrinfo(name, port, &hints, &addr) != 0)
|
||||
return;
|
||||
|
||||
num = 0;
|
||||
for (i = addr; i; i = i->ai_next)
|
||||
num++;
|
||||
|
||||
addresses = tal_arr(NULL, struct netaddr, num);
|
||||
num = 0;
|
||||
for (i = addr; i; i = i->ai_next) {
|
||||
addresses[num].type = i->ai_socktype;
|
||||
addresses[num].protocol = i->ai_protocol;
|
||||
addresses[num].addrlen = i->ai_addrlen;
|
||||
memset(&addresses[num].saddr, 0, sizeof(addresses[num].saddr));
|
||||
/* Let parent report this error. */
|
||||
if (i->ai_addrlen <= sizeof(addresses[num].saddr))
|
||||
memcpy(&addresses[num].saddr, i->ai_addr, i->ai_addrlen);
|
||||
num++;
|
||||
}
|
||||
|
||||
if (!num) {
|
||||
tal_free(addresses);
|
||||
return;
|
||||
}
|
||||
|
||||
if (write_all(fd, &num, sizeof(num)))
|
||||
write_all(fd, addresses, num * sizeof(addresses[0]));
|
||||
tal_free(addresses);
|
||||
}
|
||||
|
||||
static struct io_plan *connected(struct io_conn *conn, struct dns_async *d)
|
||||
{
|
||||
struct io_plan *plan;
|
||||
|
||||
/* No longer need to try more connections via connect_failed. */
|
||||
io_set_finish(conn, NULL, NULL);
|
||||
|
||||
plan = d->init(conn, d->ld, &d->addresses[-1], d->arg);
|
||||
tal_free(d);
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
static void try_connect_one(struct dns_async *d);
|
||||
|
||||
/* If this connection failed, try connecting to another address. */
|
||||
static void connect_failed(struct io_conn *conn, struct dns_async *d)
|
||||
{
|
||||
try_connect_one(d);
|
||||
}
|
||||
|
||||
static struct io_plan *init_conn(struct io_conn *conn, struct dns_async *d)
|
||||
{
|
||||
struct addrinfo a;
|
||||
|
||||
netaddr_to_addrinfo(&a, &d->addresses[0]);
|
||||
|
||||
/* Consume that address. */
|
||||
d->addresses++;
|
||||
d->num_addresses--;
|
||||
|
||||
io_set_finish(conn, connect_failed, d);
|
||||
|
||||
/* That new connection owns d */
|
||||
return io_connect(conn, &a, connected, d);
|
||||
}
|
||||
|
||||
static void try_connect_one(struct dns_async *d)
|
||||
{
|
||||
int fd;
|
||||
|
||||
while (d->num_addresses) {
|
||||
const struct netaddr *a = &d->addresses[0];
|
||||
|
||||
/* Now we can warn if it's overlength */
|
||||
if (a->addrlen > sizeof(a->saddr)) {
|
||||
log_broken(d->ld->log,
|
||||
"DNS lookup gave overlength address for %s"
|
||||
" for family %u, len=%u",
|
||||
d->name, a->saddr.s.sa_family, a->addrlen);
|
||||
} else {
|
||||
/* Might not even be able to create eg. IPv6 sockets */
|
||||
fd = socket(a->saddr.s.sa_family, a->type, a->protocol);
|
||||
if (fd >= 0) {
|
||||
io_new_conn(d->ld, fd, init_conn, d);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Consume that address. */
|
||||
d->addresses++;
|
||||
d->num_addresses--;
|
||||
}
|
||||
|
||||
/* We're out of things to try. Fail. */
|
||||
d->fail(d->ld, d->arg);
|
||||
tal_free(d);
|
||||
}
|
||||
|
||||
static struct io_plan *start_connecting(struct io_conn *conn,
|
||||
struct dns_async *d)
|
||||
{
|
||||
assert(d->num_addresses);
|
||||
|
||||
/* OK, we've read all we want, child should exit. */
|
||||
waitpid(d->pid, NULL, 0);
|
||||
|
||||
/* No need to call dns_lookup_failed now. */
|
||||
io_set_finish(conn, NULL, NULL);
|
||||
|
||||
try_connect_one(d);
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
struct dns_async *multiaddress_connect_(struct lightningd *ld,
|
||||
const struct netaddr *addresses,
|
||||
struct io_plan *(*init)(struct io_conn *,
|
||||
struct lightningd *,
|
||||
const struct netaddr *,
|
||||
void *arg),
|
||||
void (*fail)(struct lightningd *, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
struct dns_async *d = tal(ld, struct dns_async);
|
||||
|
||||
d->ld = ld;
|
||||
d->init = init;
|
||||
d->fail = fail;
|
||||
d->arg = arg;
|
||||
d->name = "names from address list";
|
||||
d->num_addresses = tal_count(addresses);
|
||||
d->addresses = tal_dup_arr(d, struct netaddr, addresses,
|
||||
d->num_addresses, 0);
|
||||
try_connect_one(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
static struct io_plan *read_addresses(struct io_conn *conn, struct dns_async *d)
|
||||
{
|
||||
d->addresses = tal_arr(d, struct netaddr, d->num_addresses);
|
||||
return io_read(conn, d->addresses,
|
||||
d->num_addresses * sizeof(d->addresses[0]),
|
||||
start_connecting, d);
|
||||
}
|
||||
|
||||
static struct io_plan *init_dns_conn(struct io_conn *conn, struct dns_async *d)
|
||||
{
|
||||
return io_read(conn, &d->num_addresses, sizeof(d->num_addresses),
|
||||
read_addresses, d);
|
||||
}
|
||||
|
||||
static void dns_lookup_failed(struct io_conn *conn, struct dns_async *d)
|
||||
{
|
||||
waitpid(d->pid, NULL, 0);
|
||||
d->fail(d->ld, d->arg);
|
||||
tal_free(d);
|
||||
}
|
||||
|
||||
struct dns_async *dns_resolve_and_connect_(struct lightningd *ld,
|
||||
const char *name, const char *port,
|
||||
struct io_plan *(*init)(struct io_conn *,
|
||||
struct lightningd *,
|
||||
const struct netaddr *,
|
||||
void *arg),
|
||||
void (*fail)(struct lightningd *, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
int pfds[2];
|
||||
struct dns_async *d = tal(ld, struct dns_async);
|
||||
struct io_conn *conn;
|
||||
|
||||
d->ld = ld;
|
||||
d->init = init;
|
||||
d->fail = fail;
|
||||
d->arg = arg;
|
||||
d->name = tal_fmt(d, "%s:%s", name, port);
|
||||
|
||||
/* First fork child to get addresses. */
|
||||
if (pipe(pfds) != 0) {
|
||||
log_unusual(ld->log,
|
||||
"Creating pipes for dns lookup: %s",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
d->pid = fork();
|
||||
switch (d->pid) {
|
||||
case -1:
|
||||
log_unusual(ld->log, "forking for dns lookup: %s",
|
||||
strerror(errno));
|
||||
close(pfds[0]);
|
||||
close(pfds[1]);
|
||||
return NULL;
|
||||
case 0:
|
||||
close(pfds[0]);
|
||||
lookup_and_write(pfds[1], name, port);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
close(pfds[1]);
|
||||
conn = io_new_conn(ld, pfds[0], init_dns_conn, d);
|
||||
io_set_finish(conn, dns_lookup_failed, d);
|
||||
return d;
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_DNS_H
|
||||
#define LIGHTNING_LIGHTNINGD_DNS_H
|
||||
#include "config.h"
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct lightningd;
|
||||
struct netaddr;
|
||||
|
||||
#define dns_resolve_and_connect(dstate, name, port, initfn, failfn, arg) \
|
||||
dns_resolve_and_connect_((dstate), (name), (port), \
|
||||
typesafe_cb_preargs(struct io_plan *, void *, \
|
||||
(initfn), (arg), \
|
||||
struct io_conn *, \
|
||||
struct lightningd *, \
|
||||
const struct netaddr *), \
|
||||
typesafe_cb_preargs(void, void *, (failfn), (arg), \
|
||||
struct lightningd *), \
|
||||
(arg))
|
||||
|
||||
struct dns_async *dns_resolve_and_connect_(struct lightningd *ld,
|
||||
const char *name, const char *port,
|
||||
struct io_plan *(*init)(struct io_conn *,
|
||||
struct lightningd *,
|
||||
const struct netaddr *,
|
||||
void *arg),
|
||||
void (*fail)(struct lightningd *, void *arg),
|
||||
void *arg);
|
||||
|
||||
/* Don't do lookup, just try to connect to these addresses. */
|
||||
#define multiaddress_connect(dstate, addresses, initfn, failfn, arg) \
|
||||
multiaddress_connect_((dstate), (addresses), \
|
||||
typesafe_cb_preargs(struct io_plan *, void *, \
|
||||
(initfn), (arg), \
|
||||
struct io_conn *, \
|
||||
struct lightningd *, \
|
||||
const struct netaddr *), \
|
||||
typesafe_cb_preargs(void, void *, (failfn), (arg), \
|
||||
struct lightningd *), \
|
||||
(arg))
|
||||
|
||||
struct dns_async *multiaddress_connect_(struct lightningd *ld,
|
||||
const struct netaddr *addresses,
|
||||
struct io_plan *(*init)(struct io_conn *,
|
||||
struct lightningd *,
|
||||
const struct netaddr *,
|
||||
void *arg),
|
||||
void (*fail)(struct lightningd *, void *arg),
|
||||
void *arg);
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_DNS_H */
|
@ -27,69 +27,34 @@ static void gossip_finished(struct subd *gossip, int status)
|
||||
errx(1, "Gossip failed (signal %u), exiting.", WTERMSIG(status));
|
||||
}
|
||||
|
||||
static void peer_bad_message(struct subd *gossip, const u8 *msg)
|
||||
{
|
||||
u64 unique_id;
|
||||
struct peer *peer;
|
||||
u8 *err;
|
||||
|
||||
if (!fromwire_gossipstatus_peer_bad_msg(msg, msg, NULL,
|
||||
&unique_id, &err))
|
||||
fatal("Gossip gave bad PEER_BAD message %s", tal_hex(msg, msg));
|
||||
|
||||
peer = peer_by_unique_id(gossip->ld, unique_id);
|
||||
if (!peer)
|
||||
fatal("Gossip gave bad peerid %"PRIu64, unique_id);
|
||||
|
||||
log_debug(gossip->log, "Peer %s gave bad msg %s",
|
||||
type_to_string(msg, struct pubkey, &peer->id),
|
||||
tal_hex(msg, msg));
|
||||
peer_fail_permanent(peer, msg);
|
||||
}
|
||||
|
||||
static void peer_failed(struct subd *gossip, const u8 *msg)
|
||||
{
|
||||
u64 unique_id;
|
||||
struct peer *peer;
|
||||
u8 *err;
|
||||
|
||||
if (!fromwire_gossipstatus_peer_failed(msg, msg, NULL,
|
||||
&unique_id, &err))
|
||||
fatal("Gossip gave bad PEER_FAILED message %s",
|
||||
tal_hex(msg, msg));
|
||||
|
||||
peer = peer_by_unique_id(gossip->ld, unique_id);
|
||||
if (!peer)
|
||||
fatal("Gossip gave bad peerid %"PRIu64, unique_id);
|
||||
|
||||
peer_fail_permanent(peer, msg);
|
||||
}
|
||||
|
||||
static void peer_nongossip(struct subd *gossip, const u8 *msg,
|
||||
int peer_fd, int gossip_fd)
|
||||
{
|
||||
u64 unique_id;
|
||||
struct peer *peer;
|
||||
u8 *inner;
|
||||
struct pubkey id;
|
||||
struct crypto_state cs;
|
||||
u8 *gfeatures, *lfeatures, *in_pkt;
|
||||
|
||||
if (!fromwire_gossipstatus_peer_nongossip(msg, msg, NULL,
|
||||
&unique_id, &cs, &inner))
|
||||
fatal("Gossip gave bad PEER_NONGOSSIP message %s",
|
||||
if (!fromwire_gossip_peer_nongossip(msg, msg, NULL,
|
||||
&id, &cs,
|
||||
&gfeatures,
|
||||
&lfeatures,
|
||||
&in_pkt))
|
||||
fatal("Gossip gave bad GOSSIP_PEER_NONGOSSIP message %s",
|
||||
tal_hex(msg, msg));
|
||||
|
||||
peer = peer_by_unique_id(gossip->ld, unique_id);
|
||||
if (!peer)
|
||||
fatal("Gossip gave bad peerid %"PRIu64, unique_id);
|
||||
/* We already checked the features when it first connected. */
|
||||
if (unsupported_features(gfeatures, lfeatures)) {
|
||||
log_unusual(gossip->log,
|
||||
"Gossip gave unsupported features %s/%s",
|
||||
tal_hex(msg, gfeatures),
|
||||
tal_hex(msg, lfeatures));
|
||||
close(peer_fd);
|
||||
close(gossip_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (peer->owner != gossip)
|
||||
fatal("Gossip gave bad peerid %"PRIu64" (owner %s)",
|
||||
unique_id, peer->owner ? peer->owner->name : "(none)");
|
||||
|
||||
log_info(peer->log, "Gossip ended up receipt of %s",
|
||||
wire_type_name(fromwire_peektype(inner)));
|
||||
|
||||
peer_fundee_open(peer, inner, &cs, peer_fd, gossip_fd);
|
||||
peer_sent_nongossip(gossip->ld, &id, &cs, gfeatures, lfeatures,
|
||||
peer_fd, gossip_fd, in_pkt);
|
||||
}
|
||||
|
||||
static int gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
|
||||
@ -99,35 +64,31 @@ static int gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
|
||||
switch (t) {
|
||||
/* These are messages we send, not them. */
|
||||
case WIRE_GOSSIPCTL_INIT:
|
||||
case WIRE_GOSSIPCTL_NEW_PEER:
|
||||
case WIRE_GOSSIPCTL_FAIL_PEER:
|
||||
case WIRE_GOSSIPCTL_RELEASE_PEER:
|
||||
case WIRE_GOSSIPCTL_DROP_PEER:
|
||||
case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD:
|
||||
case WIRE_GOSSIP_GETNODES_REQUEST:
|
||||
case WIRE_GOSSIP_GETROUTE_REQUEST:
|
||||
case WIRE_GOSSIP_GETCHANNELS_REQUEST:
|
||||
case WIRE_GOSSIP_PING:
|
||||
case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST:
|
||||
case WIRE_GOSSIP_FORWARDED_MSG:
|
||||
case WIRE_GOSSIPCTL_REACH_PEER:
|
||||
case WIRE_GOSSIPCTL_HANDLE_PEER:
|
||||
case WIRE_GOSSIPCTL_RELEASE_PEER:
|
||||
case WIRE_GOSSIPCTL_PEER_ADDRHINT:
|
||||
/* This is a reply, so never gets through to here. */
|
||||
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY:
|
||||
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLYFAIL:
|
||||
case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD_REPLY:
|
||||
case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD_REPLYFAIL:
|
||||
case WIRE_GOSSIP_GETNODES_REPLY:
|
||||
case WIRE_GOSSIP_GETROUTE_REPLY:
|
||||
case WIRE_GOSSIP_GETCHANNELS_REPLY:
|
||||
case WIRE_GOSSIP_PING_REPLY:
|
||||
case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY:
|
||||
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY:
|
||||
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLYFAIL:
|
||||
break;
|
||||
case WIRE_GOSSIPSTATUS_PEER_BAD_MSG:
|
||||
peer_bad_message(gossip, msg);
|
||||
case WIRE_GOSSIP_PEER_CONNECTED:
|
||||
if (tal_count(fds) != 2)
|
||||
return 2;
|
||||
peer_connected(gossip->ld, msg, fds[0], fds[1]);
|
||||
break;
|
||||
case WIRE_GOSSIPSTATUS_PEER_FAILED:
|
||||
peer_failed(gossip, msg);
|
||||
break;
|
||||
case WIRE_GOSSIPSTATUS_PEER_NONGOSSIP:
|
||||
case WIRE_GOSSIP_PEER_NONGOSSIP:
|
||||
if (tal_count(fds) != 2)
|
||||
return 2;
|
||||
peer_nongossip(gossip, msg, fds[0], fds[1]);
|
||||
@ -164,7 +125,10 @@ void gossip_init(struct lightningd *ld)
|
||||
err(1, "Could not subdaemon gossip");
|
||||
|
||||
msg = towire_gossipctl_init(tmpctx, ld->broadcast_interval,
|
||||
&get_chainparams(ld)->genesis_blockhash);
|
||||
&get_chainparams(ld)->genesis_blockhash,
|
||||
&ld->id, ld->portnum,
|
||||
get_supported_global_features(tmpctx),
|
||||
get_supported_local_features(tmpctx));
|
||||
subd_send_msg(ld->gossip, msg);
|
||||
tal_free(tmpctx);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_GOSSIP_CONTROL_H
|
||||
#define LIGHTNING_LIGHTNINGD_GOSSIP_CONTROL_H
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct lightningd;
|
||||
|
@ -655,5 +655,6 @@ void setup_jsonrpc(struct lightningd *ld, const char *rpc_filename)
|
||||
if (listen(fd, 1) != 0)
|
||||
err(1, "Listening on '%s'", rpc_filename);
|
||||
|
||||
log_debug(ld->log, "Listening on '%s'", rpc_filename);
|
||||
io_new_listener(ld, fd, incoming_jcon_connected, ld);
|
||||
}
|
||||
|
@ -31,16 +31,6 @@
|
||||
|
||||
char *bitcoin_datadir;
|
||||
|
||||
struct peer *find_peer_by_unique_id(struct lightningd *ld, u64 unique_id)
|
||||
{
|
||||
struct peer *peer;
|
||||
list_for_each(&ld->peers, peer, list) {
|
||||
if (peer->unique_id == unique_id)
|
||||
return peer;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void notify_new_block(struct chain_topology *topo, u32 height);
|
||||
void notify_new_block(struct chain_topology *topo, u32 height)
|
||||
{
|
||||
@ -81,7 +71,6 @@ static struct lightningd *new_lightningd(const tal_t *ctx,
|
||||
struct lightningd *ld = tal(ctx, struct lightningd);
|
||||
|
||||
list_head_init(&ld->peers);
|
||||
ld->peer_counter = 0;
|
||||
ld->dev_debug_subdaemon = NULL;
|
||||
htlc_in_map_init(&ld->htlcs_in);
|
||||
htlc_out_map_init(&ld->htlcs_out);
|
||||
@ -90,6 +79,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx,
|
||||
ld->log = new_log(log_book, log_book, "lightningd(%u):", (int)getpid());
|
||||
|
||||
list_head_init(&ld->pay_commands);
|
||||
list_head_init(&ld->connects);
|
||||
ld->portnum = DEFAULT_PORT;
|
||||
timers_init(&ld->timers, time_mono());
|
||||
ld->topology = new_topology(ld, ld->log);
|
||||
@ -260,15 +250,9 @@ int main(int argc, char *argv[])
|
||||
/* Initialize wallet, now that we are in the correct directory */
|
||||
ld->wallet = wallet_new(ld, ld->log);
|
||||
|
||||
/* Mark ourselves live. */
|
||||
log_info(ld->log, "Hello world from %s!", version());
|
||||
|
||||
/* Set up HSM. */
|
||||
hsm_init(ld, newdir);
|
||||
|
||||
/* Set up gossip daemon. */
|
||||
gossip_init(ld);
|
||||
|
||||
/* Initialize block topology. */
|
||||
setup_topology(ld->topology,
|
||||
&ld->timers,
|
||||
@ -281,6 +265,9 @@ int main(int argc, char *argv[])
|
||||
err(1, "Could not load invoices from the database");
|
||||
}
|
||||
|
||||
/* Set up gossip daemon. */
|
||||
gossip_init(ld);
|
||||
|
||||
/* Load peers from database */
|
||||
wallet_channels_load_active(ld->wallet, &ld->peers);
|
||||
|
||||
@ -302,8 +289,8 @@ int main(int argc, char *argv[])
|
||||
/* Create RPC socket (if any) */
|
||||
setup_jsonrpc(ld, ld->rpc_filename);
|
||||
|
||||
/* Ready for connections from peers. */
|
||||
setup_listeners(ld);
|
||||
/* Mark ourselves live. */
|
||||
log_info(ld->log, "Hello world from %s!", version());
|
||||
|
||||
#if 0
|
||||
/* Load peers from database. */
|
||||
|
@ -103,8 +103,9 @@ struct lightningd {
|
||||
struct list_head peers;
|
||||
/* FIXME: This should stay in HSM */
|
||||
struct secret peer_seed;
|
||||
/* Used to give a unique seed to every peer. */
|
||||
u64 peer_counter;
|
||||
|
||||
/* Outstanding connect commands. */
|
||||
struct list_head connects;
|
||||
|
||||
/* Our chain topology. */
|
||||
struct chain_topology *topology;
|
||||
@ -150,7 +151,5 @@ struct lightningd {
|
||||
void derive_peer_seed(struct lightningd *ld, struct privkey *peer_seed,
|
||||
const struct pubkey *peer_id, const u64 channel_id);
|
||||
|
||||
struct peer *find_peer_by_unique_id(struct lightningd *ld, u64 unique_id);
|
||||
|
||||
struct chainparams *get_chainparams(const struct lightningd *ld);
|
||||
#endif /* LIGHTNING_LIGHTNINGD_LIGHTNINGD_H */
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* FIXME: We should deprecate this in favor of BOLT7 address descriptor */
|
||||
#ifndef LIGHTNING_LIGHTNINGD_NETADDR_H
|
||||
#define LIGHTNING_LIGHTNINGD_NETADDR_H
|
||||
#include "config.h"
|
||||
|
@ -1,283 +0,0 @@
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/fdpass/fdpass.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/cryptomsg.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <handshaked/gen_handshake_wire.h>
|
||||
#include <hsmd/gen_hsm_wire.h>
|
||||
#include <lightningd/hsm_control.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/new_connection.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <unistd.h>
|
||||
#include <wire/wire_sync.h>
|
||||
|
||||
const u8 supported_local_features[] = {LOCALFEATURES_INITIAL_ROUTING_SYNC};
|
||||
const u8 supported_global_features[] = {0x00};
|
||||
|
||||
/* Before we have identified the peer, we just have a connection object. */
|
||||
struct connection {
|
||||
/* Lightning daemon, for when we're handed through callbacks. */
|
||||
struct lightningd *ld;
|
||||
|
||||
/* Where we connected to/from. */
|
||||
struct netaddr netaddr;
|
||||
|
||||
/* Unique identifier for handshaked. */
|
||||
u64 unique_id;
|
||||
|
||||
/* Json command which made us connect (if any) */
|
||||
struct command *cmd;
|
||||
|
||||
/* If we are initiating, we known their id. Otherwise NULL. */
|
||||
struct pubkey *known_id;
|
||||
};
|
||||
|
||||
static void connection_destroy(struct connection *c)
|
||||
{
|
||||
/* FIXME: better diagnostics. */
|
||||
if (c->cmd)
|
||||
command_fail(c->cmd, "Failed to connect to peer");
|
||||
}
|
||||
|
||||
static void
|
||||
PRINTF_FMT(3,4) connection_failed(struct connection *c, struct log *log,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
const char *msg;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
msg = tal_vfmt(c, fmt, ap);
|
||||
va_end(ap);
|
||||
log_info(log, "%s", msg);
|
||||
if (c->cmd) {
|
||||
command_fail(c->cmd, "%s", msg);
|
||||
/* Don't fail in destructor, too. */
|
||||
c->cmd = NULL;
|
||||
}
|
||||
tal_free(c);
|
||||
}
|
||||
|
||||
struct connection *new_connection(const tal_t *ctx,
|
||||
struct lightningd *ld,
|
||||
struct command *cmd,
|
||||
const struct pubkey *known_id)
|
||||
{
|
||||
static u64 id_counter = 1;
|
||||
struct connection *c = tal(ctx, struct connection);
|
||||
|
||||
c->ld = ld;
|
||||
c->unique_id = id_counter++;
|
||||
c->cmd = cmd;
|
||||
if (known_id)
|
||||
c->known_id = tal_dup(c, struct pubkey, known_id);
|
||||
else
|
||||
c->known_id = NULL;
|
||||
tal_add_destructor(c, connection_destroy);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* requires_unsupported_features - Check if we support what's being asked
|
||||
*
|
||||
* Given the features vector that the remote connection is expecting
|
||||
* from us, we check to see if we support all even bit features, i.e.,
|
||||
* the required features. We do so by subtracting our own features in
|
||||
* the provided positions and see if even bits remain.
|
||||
*
|
||||
* @bitmap: the features bitmap the peer is asking for
|
||||
* @supportmap: what do we support
|
||||
* @smlen: how long is our supportmap
|
||||
*/
|
||||
static bool requires_unsupported_features(const u8 *bitmap,
|
||||
const u8 *supportmap,
|
||||
size_t smlen)
|
||||
{
|
||||
size_t len = tal_count(bitmap);
|
||||
u8 support;
|
||||
for (size_t i=0; i<len; i++) {
|
||||
/* Find matching bitmap byte in supportmap, 0x00 if none */
|
||||
if (len > smlen) {
|
||||
support = 0x00;
|
||||
} else {
|
||||
support = supportmap[smlen-1];
|
||||
}
|
||||
|
||||
/* Cancel out supported bits, check for even bits */
|
||||
if ((~support & bitmap[i]) & 0x55)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handshake_succeeded(struct subd *handshaked,
|
||||
const u8 *msg, const int *fds,
|
||||
struct connection *c)
|
||||
{
|
||||
struct crypto_state cs;
|
||||
struct pubkey *id;
|
||||
u8 *globalfeatures, *localfeatures;
|
||||
|
||||
assert(tal_count(fds) == 1);
|
||||
|
||||
/* FIXME: Look for peer duplicates! */
|
||||
|
||||
if (!c->known_id) {
|
||||
id = tal(msg, struct pubkey);
|
||||
if (!fromwire_handshake_responder_reply(c, msg, NULL, id, &cs,
|
||||
&globalfeatures,
|
||||
&localfeatures))
|
||||
goto err;
|
||||
log_info(handshaked->log, "Peer in from %s",
|
||||
type_to_string(ltmp, struct pubkey, id));
|
||||
} else {
|
||||
id = c->known_id;
|
||||
if (!fromwire_handshake_initiator_reply(c, msg, NULL, &cs,
|
||||
&globalfeatures,
|
||||
&localfeatures))
|
||||
goto err;
|
||||
log_info(handshaked->log, "Peer out to %s",
|
||||
type_to_string(ltmp, struct pubkey, id));
|
||||
}
|
||||
|
||||
/* BOLT #1:
|
||||
*
|
||||
* For unknown feature bits which are non-zero, the receiver
|
||||
* MUST ignore the bit if the bit number is odd, and MUST fail
|
||||
* the connection if the bit number is even.
|
||||
*/
|
||||
if (requires_unsupported_features(
|
||||
globalfeatures, supported_global_features,
|
||||
ARRAY_SIZE(supported_global_features))) {
|
||||
connection_failed(c, handshaked->log,
|
||||
"peer %s: bad globalfeatures: %s",
|
||||
type_to_string(c, struct pubkey, id),
|
||||
tal_hex(msg, globalfeatures));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (requires_unsupported_features(
|
||||
localfeatures, supported_local_features,
|
||||
ARRAY_SIZE(supported_local_features))) {
|
||||
connection_failed(c, handshaked->log,
|
||||
"peer %s: bad localfeatures: %s",
|
||||
type_to_string(c, struct pubkey, id),
|
||||
tal_hex(msg, localfeatures));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (c->cmd) {
|
||||
struct json_result *response;
|
||||
response = new_json_result(c->cmd);
|
||||
|
||||
json_object_start(response, NULL);
|
||||
json_add_pubkey(response, "id", id);
|
||||
json_object_end(response);
|
||||
command_success(c->cmd, response);
|
||||
c->cmd = NULL;
|
||||
}
|
||||
|
||||
add_peer(handshaked->ld, c->unique_id, fds[0], id, &cs);
|
||||
/* Now shut handshaked down (frees c as well) */
|
||||
return false;
|
||||
|
||||
err:
|
||||
log_broken(handshaked->log, "Malformed resp: %s", tal_hex(c, msg));
|
||||
close(fds[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Same path for connecting in vs connecting out. */
|
||||
static struct io_plan *hsm_then_handshake(struct io_conn *conn,
|
||||
struct lightningd *ld,
|
||||
struct connection *c)
|
||||
{
|
||||
const tal_t *tmpctx = tal_tmpctx(conn);
|
||||
int connfd = io_conn_fd(conn), hsmfd;
|
||||
struct subd *handshaked;
|
||||
u8 *msg;
|
||||
|
||||
/* Get HSM fd for this peer. */
|
||||
msg = towire_hsmctl_hsmfd_ecdh(tmpctx, c->unique_id);
|
||||
if (!wire_sync_write(ld->hsm_fd, msg))
|
||||
fatal("Could not write to HSM: %s", strerror(errno));
|
||||
|
||||
msg = hsm_sync_read(tmpctx, ld);
|
||||
if (!fromwire_hsmctl_hsmfd_ecdh_fd_reply(msg, NULL))
|
||||
fatal("Malformed hsmfd response: %s", tal_hex(msg, msg));
|
||||
|
||||
hsmfd = fdpass_recv(ld->hsm_fd);
|
||||
if (hsmfd < 0)
|
||||
fatal("Could not read fd from HSM: %s", strerror(errno));
|
||||
|
||||
/* Make sure connection fd is blocking */
|
||||
io_fd_block(connfd, true);
|
||||
|
||||
/* Give handshake daemon the hsm fd. */
|
||||
handshaked = new_subd(ld,
|
||||
"lightning_handshaked", NULL,
|
||||
handshake_wire_type_name,
|
||||
NULL, NULL, NULL,
|
||||
take(&hsmfd), take(&connfd), NULL);
|
||||
if (!handshaked) {
|
||||
log_unusual(ld->log, "Could not subdaemon handshake: %s",
|
||||
strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If handshake daemon fails, we just drop connection. */
|
||||
tal_steal(handshaked, c);
|
||||
|
||||
if (c->known_id) {
|
||||
msg = towire_handshake_initiator(tmpctx, &ld->id, c->known_id);
|
||||
} else {
|
||||
msg = towire_handshake_responder(tmpctx, &ld->id);
|
||||
}
|
||||
|
||||
/* Now hand peer request to the handshake daemon: hands it
|
||||
* back on success */
|
||||
subd_req(c, handshaked, take(msg), -1, 1, handshake_succeeded, c);
|
||||
|
||||
tal_free(tmpctx);
|
||||
|
||||
/* We don't need conn, we've passed fd to handshaked. */
|
||||
return io_close_taken_fd(conn);
|
||||
|
||||
error:
|
||||
close(hsmfd);
|
||||
tal_free(tmpctx);
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
struct io_plan *connection_out(struct io_conn *conn,
|
||||
struct lightningd *ld,
|
||||
const struct netaddr *netaddr,
|
||||
struct connection *c)
|
||||
{
|
||||
c->netaddr = *netaddr;
|
||||
return hsm_then_handshake(conn, ld, c);
|
||||
}
|
||||
|
||||
struct io_plan *connection_in(struct io_conn *conn, struct lightningd *ld)
|
||||
{
|
||||
struct connection *c = new_connection(ld, ld, NULL, NULL);
|
||||
|
||||
/* FIXME: Don't assume TCP here. */
|
||||
if (!netaddr_from_fd(io_conn_fd(conn), SOCK_STREAM, IPPROTO_TCP,
|
||||
&c->netaddr)) {
|
||||
log_unusual(ld->log, "Could not get address of incoming fd");
|
||||
return io_close(conn);
|
||||
}
|
||||
return hsm_then_handshake(conn, ld, c);
|
||||
}
|
||||
|
||||
const struct pubkey *connection_known_id(const struct connection *c)
|
||||
{
|
||||
return c->known_id;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_NEW_CONNECTION_H
|
||||
#define LIGHTNING_LIGHTNINGD_NEW_CONNECTION_H
|
||||
#include "config.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
struct command;
|
||||
struct io_conn;
|
||||
struct lightningd;
|
||||
struct netaddr;
|
||||
struct pubkey;
|
||||
|
||||
struct connection *new_connection(const tal_t *ctx,
|
||||
struct lightningd *ld,
|
||||
struct command *cmd,
|
||||
const struct pubkey *known_id);
|
||||
|
||||
struct io_plan *connection_out(struct io_conn *conn,
|
||||
struct lightningd *dstate,
|
||||
const struct netaddr *netaddr,
|
||||
struct connection *c);
|
||||
|
||||
struct io_plan *connection_in(struct io_conn *conn, struct lightningd *ld);
|
||||
|
||||
const struct pubkey *connection_known_id(const struct connection *c);
|
||||
#endif /* LIGHTNING_LIGHTNINGD_NEW_CONNECTION_H */
|
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,9 @@ struct peer {
|
||||
/* ID of peer */
|
||||
struct pubkey id;
|
||||
|
||||
/* Global and local features bitfields. */
|
||||
const u8 *gfeatures, *lfeatures;
|
||||
|
||||
/* Error message (iff in error state) */
|
||||
u8 *error;
|
||||
|
||||
@ -127,6 +130,12 @@ static inline bool peer_on_chain(const struct peer *peer)
|
||||
return peer_state_on_chain(peer->state);
|
||||
}
|
||||
|
||||
static inline bool peer_wants_reconnect(const struct peer *peer)
|
||||
{
|
||||
return peer->state >= CHANNELD_AWAITING_LOCKIN
|
||||
&& peer->state <= CLOSINGD_COMPLETE;
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* On disconnection, the funder MUST remember the channel for
|
||||
@ -142,7 +151,6 @@ static inline bool peer_persists(const struct peer *peer)
|
||||
return peer->state >= CHANNELD_AWAITING_LOCKIN;
|
||||
}
|
||||
|
||||
struct peer *peer_by_unique_id(struct lightningd *ld, u64 unique_id);
|
||||
struct peer *peer_by_id(struct lightningd *ld, const struct pubkey *id);
|
||||
struct peer *peer_from_json(struct lightningd *ld,
|
||||
const char *buffer,
|
||||
@ -151,13 +159,23 @@ struct peer *peer_from_json(struct lightningd *ld,
|
||||
void peer_last_tx(struct peer *peer, struct bitcoin_tx *tx,
|
||||
const secp256k1_ecdsa_signature *sig);
|
||||
|
||||
void peer_fundee_open(struct peer *peer, const u8 *msg,
|
||||
const struct crypto_state *cs,
|
||||
int peer_fd, int gossip_fd);
|
||||
/* The three ways peers enter from the network:
|
||||
*
|
||||
* peer_connected - when it first connects to gossipd (after init exchange).
|
||||
* peer_sent_nongossip - when it tries to fund a channel.
|
||||
* gossip_peer_released - when we tell gossipd to release it so we can fund
|
||||
* a channel.
|
||||
*/
|
||||
void peer_connected(struct lightningd *ld, const u8 *msg,
|
||||
int peer_fd, int gossip_fd);
|
||||
|
||||
void add_peer(struct lightningd *ld, u64 unique_id,
|
||||
int fd, const struct pubkey *id,
|
||||
const struct crypto_state *cs);
|
||||
void peer_sent_nongossip(struct lightningd *ld,
|
||||
const struct pubkey *id,
|
||||
const struct crypto_state *cs,
|
||||
const u8 *gfeatures,
|
||||
const u8 *lfeatures,
|
||||
int peer_fd, int gossip_fd,
|
||||
const u8 *in_msg);
|
||||
|
||||
/**
|
||||
* populate_peer -- Populate daemon fields in a peer
|
||||
@ -171,6 +189,13 @@ void add_peer(struct lightningd *ld, u64 unique_id,
|
||||
*/
|
||||
void populate_peer(struct lightningd *ld, struct peer *peer);
|
||||
|
||||
/* Returns true if these contain any unsupported features. */
|
||||
bool unsupported_features(const u8 *gfeatures, const u8 *lfeatures);
|
||||
|
||||
/* For sending our features: tal_len() returns length. */
|
||||
u8 *get_supported_global_features(const tal_t *ctx);
|
||||
u8 *get_supported_local_features(const tal_t *ctx);
|
||||
|
||||
/* Could be configurable. */
|
||||
#define OUR_CHANNEL_FLAGS CHANNEL_FLAGS_ANNOUNCE_CHANNEL
|
||||
|
||||
|
@ -5,9 +5,6 @@
|
||||
enum peer_state {
|
||||
UNINITIALIZED,
|
||||
|
||||
/* In gossip daemon. */
|
||||
GOSSIPD,
|
||||
|
||||
/* Negotiating channel opening: in opening daemon */
|
||||
OPENINGD,
|
||||
|
||||
|
@ -55,9 +55,6 @@ void register_opts(struct lightningd *ld UNNEEDED)
|
||||
/* Generated stub for setup_jsonrpc */
|
||||
void setup_jsonrpc(struct lightningd *ld UNNEEDED, const char *rpc_filename UNNEEDED)
|
||||
{ fprintf(stderr, "setup_jsonrpc called!\n"); abort(); }
|
||||
/* Generated stub for setup_listeners */
|
||||
void setup_listeners(struct lightningd *ld UNNEEDED)
|
||||
{ fprintf(stderr, "setup_listeners called!\n"); abort(); }
|
||||
/* Generated stub for setup_topology */
|
||||
void setup_topology(struct chain_topology *topology UNNEEDED,
|
||||
struct timers *timers UNNEEDED,
|
||||
|
@ -212,8 +212,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
assert ret['id'] == l2.info['id']
|
||||
|
||||
l1.daemon.wait_for_log('WIRE_GOSSIPCTL_NEW_PEER')
|
||||
l2.daemon.wait_for_log('WIRE_GOSSIPCTL_NEW_PEER')
|
||||
l1.daemon.wait_for_log('WIRE_GOSSIPCTL_HANDLE_PEER')
|
||||
l2.daemon.wait_for_log('WIRE_GOSSIPCTL_HANDLE_PEER')
|
||||
return l1,l2
|
||||
|
||||
def fund_channel(self, l1, l2, amount):
|
||||
@ -267,18 +267,13 @@ class LightningDTests(BaseLightningDTests):
|
||||
def test_connect(self):
|
||||
l1,l2 = self.connect()
|
||||
|
||||
p1 = l1.rpc.getpeer(l2.info['id'], 'info')
|
||||
p2 = l2.rpc.getpeer(l1.info['id'], 'info')
|
||||
# Main daemon has no idea about these peers; they're in gossipd.
|
||||
assert l1.rpc.getpeer(l2.info['id'], 'info') == None
|
||||
assert l2.rpc.getpeer(l1.info['id'], 'info') == None
|
||||
|
||||
assert p1['state'] == 'GOSSIPD'
|
||||
assert p2['state'] == 'GOSSIPD'
|
||||
|
||||
# It should have gone through these steps
|
||||
assert 'state: UNINITIALIZED -> GOSSIPD' in p1['log']
|
||||
|
||||
# Both should still be owned by gossip
|
||||
assert p1['owner'] == 'lightning_gossipd'
|
||||
assert p2['owner'] == 'lightning_gossipd'
|
||||
# Both gossipds will have them as new peers once handed back.
|
||||
l1.daemon.wait_for_log('handle_peer {}: new peer'.format(l2.info['id']))
|
||||
l2.daemon.wait_for_log('handle_peer {}: new peer'.format(l1.info['id']))
|
||||
|
||||
def test_balance(self):
|
||||
l1,l2 = self.connect()
|
||||
@ -403,8 +398,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
assert ret['id'] == l2.info['id']
|
||||
|
||||
l1.daemon.wait_for_log('WIRE_GOSSIPCTL_NEW_PEER')
|
||||
l2.daemon.wait_for_log('WIRE_GOSSIPCTL_NEW_PEER')
|
||||
l1.daemon.wait_for_log('WIRE_GOSSIPCTL_HANDLE_PEER')
|
||||
l2.daemon.wait_for_log('WIRE_GOSSIPCTL_HANDLE_PEER')
|
||||
|
||||
addr = l1.rpc.newaddr()['address']
|
||||
txid = l1.bitcoin.rpc.sendtoaddress(addr, 10**6 / 10**8 + 0.01)
|
||||
@ -1087,7 +1082,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
assert ret['id'] == l3.info['id']
|
||||
|
||||
l3.daemon.wait_for_log('WIRE_GOSSIPCTL_NEW_PEER')
|
||||
l3.daemon.wait_for_log('WIRE_GOSSIPCTL_HANDLE_PEER')
|
||||
self.fund_channel(l1, l2, 10**6)
|
||||
self.fund_channel(l2, l3, 10**6)
|
||||
|
||||
@ -1138,20 +1133,20 @@ class LightningDTests(BaseLightningDTests):
|
||||
l1.rpc.sendpay(to_json(route), rhash)
|
||||
|
||||
def test_disconnect(self):
|
||||
# These should all make us fail.
|
||||
# These should all make us fail, and retry.
|
||||
# FIXME: Configure short timeout for reconnect!
|
||||
disconnects = ['-WIRE_INIT',
|
||||
'@WIRE_INIT',
|
||||
'+WIRE_INIT']
|
||||
l1 = self.node_factory.get_node(disconnect=disconnects)
|
||||
l2 = self.node_factory.get_node()
|
||||
for d in disconnects:
|
||||
self.assertRaises(ValueError, l1.rpc.connect,
|
||||
l2.info['id'], 'localhost:{}'.format(l2.info['port']))
|
||||
assert l1.rpc.getpeer(l2.info['id']) == None
|
||||
|
||||
# Now we should connect normally.
|
||||
l1.rpc.connect(l2.info['id'], 'localhost:{}'.format(l2.info['port']))
|
||||
|
||||
# Should have 3 connect fails.
|
||||
for d in disconnects:
|
||||
l1.daemon.wait_for_log('Failed connected out for {}, will try again'
|
||||
.format(l2.info['id']))
|
||||
|
||||
def test_disconnect_funder(self):
|
||||
# Now error on funder side duringchannel open.
|
||||
disconnects = ['-WIRE_OPEN_CHANNEL',
|
||||
|
Loading…
Reference in New Issue
Block a user