Browse Source
connectd is the only user of the cryptomsg async APIs; better to open-code it here. We need to expose a little from cryptomsg(), but we remove the 'struct peer' entirely from connectd. One trick is that we still need to defer telling lightningd when a peer reconnects (until it tells us the old one is disconnected). So now we generate the message for lightningd and send it once we're woken. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>fee-tracking2
Rusty Russell
6 years ago
7 changed files with 289 additions and 145 deletions
@ -1,10 +1,22 @@ |
|||||
#ifndef LIGHTNING_CONNECTD_CONNECTD_H |
#ifndef LIGHTNING_CONNECTD_CONNECTD_H |
||||
#define LIGHTNING_CONNECTD_CONNECTD_H |
#define LIGHTNING_CONNECTD_CONNECTD_H |
||||
#include "config.h" |
#include "config.h" |
||||
|
#include <bitcoin/pubkey.h> |
||||
|
#include <common/crypto_state.h> |
||||
|
|
||||
struct io_conn; |
struct io_conn; |
||||
|
struct peer; |
||||
struct reaching; |
struct reaching; |
||||
|
struct daemon; |
||||
|
|
||||
|
/* Called by io_tor_connect once it has a connection out. */ |
||||
struct io_plan *connection_out(struct io_conn *conn, struct reaching *reach); |
struct io_plan *connection_out(struct io_conn *conn, struct reaching *reach); |
||||
|
|
||||
|
/* Called by peer_exchange_initmsg if successful. */ |
||||
|
struct io_plan *peer_connected(struct io_conn *conn, |
||||
|
struct daemon *daemon, |
||||
|
const struct pubkey *id TAKES, |
||||
|
const u8 *peer_connected_msg TAKES, |
||||
|
const u8 *lfeatures TAKES); |
||||
|
|
||||
#endif /* LIGHTNING_CONNECTD_CONNECTD_H */ |
#endif /* LIGHTNING_CONNECTD_CONNECTD_H */ |
||||
|
@ -0,0 +1,177 @@ |
|||||
|
#include <ccan/io/io.h> |
||||
|
#include <common/cryptomsg.h> |
||||
|
#include <common/dev_disconnect.h> |
||||
|
#include <common/features.h> |
||||
|
#include <common/status.h> |
||||
|
#include <common/wire_error.h> |
||||
|
#include <connectd/connectd.h> |
||||
|
#include <connectd/gen_connect_wire.h> |
||||
|
#include <connectd/peer_exchange_initmsg.h> |
||||
|
#include <wire/peer_wire.h> |
||||
|
|
||||
|
/* Temporary structure for us to read peer message in */ |
||||
|
struct peer { |
||||
|
struct daemon *daemon; |
||||
|
|
||||
|
/* The ID of the peer */ |
||||
|
struct pubkey id; |
||||
|
|
||||
|
/* Where it's connected to/from. */ |
||||
|
struct wireaddr_internal addr; |
||||
|
|
||||
|
/* Crypto state for writing/reading peer initmsg */ |
||||
|
struct crypto_state cs; |
||||
|
|
||||
|
/* Buffer for reading/writing message. */ |
||||
|
u8 *msg; |
||||
|
}; |
||||
|
|
||||
|
/* Here in case we need to read another message. */ |
||||
|
static struct io_plan *read_init(struct io_conn *conn, struct peer *peer); |
||||
|
|
||||
|
static struct io_plan *peer_init_received(struct io_conn *conn, |
||||
|
struct peer *peer) |
||||
|
{ |
||||
|
u8 *msg = cryptomsg_decrypt_body(peer, &peer->cs, peer->msg); |
||||
|
u8 *gfeatures, *lfeatures; |
||||
|
|
||||
|
if (!msg) |
||||
|
return io_close(conn); |
||||
|
|
||||
|
status_peer_io(LOG_IO_IN, msg); |
||||
|
|
||||
|
/* BOLT #1:
|
||||
|
* |
||||
|
* A receiving node: |
||||
|
* - upon receiving a message of _odd_, unknown type: |
||||
|
* - MUST ignore the received message. |
||||
|
*/ |
||||
|
if (unlikely(is_unknown_msg_discardable(msg))) |
||||
|
return read_init(conn, peer); |
||||
|
|
||||
|
if (!fromwire_init(peer, msg, &gfeatures, &lfeatures)) { |
||||
|
status_trace("peer %s bad fromwire_init '%s', closing", |
||||
|
type_to_string(tmpctx, struct pubkey, &peer->id), |
||||
|
tal_hex(tmpctx, msg)); |
||||
|
return io_close(conn); |
||||
|
} |
||||
|
|
||||
|
/* BOLT #1:
|
||||
|
* |
||||
|
* The receiving node: |
||||
|
* ... |
||||
|
* - upon receiving unknown _odd_ feature bits that are non-zero: |
||||
|
* - MUST ignore the bit. |
||||
|
* - upon receiving unknown _even_ feature bits that are non-zero: |
||||
|
* - MUST fail the connection. |
||||
|
*/ |
||||
|
if (!features_supported(gfeatures, lfeatures)) { |
||||
|
const u8 *global_features = get_offered_global_features(msg); |
||||
|
const u8 *local_features = get_offered_local_features(msg); |
||||
|
msg = towire_errorfmt(NULL, NULL, "Unsupported features %s/%s:" |
||||
|
" we only offer globalfeatures %s" |
||||
|
" and localfeatures %s", |
||||
|
tal_hex(msg, gfeatures), |
||||
|
tal_hex(msg, lfeatures), |
||||
|
tal_hex(msg, global_features), |
||||
|
tal_hex(msg, local_features)); |
||||
|
msg = cryptomsg_encrypt_msg(NULL, &peer->cs, take(msg)); |
||||
|
return io_write(conn, msg, tal_count(msg), io_close_cb, NULL); |
||||
|
} |
||||
|
|
||||
|
/* Create message to tell master peer has connected. */ |
||||
|
msg = towire_connect_peer_connected(NULL, &peer->id, &peer->addr, |
||||
|
&peer->cs, gfeatures, lfeatures); |
||||
|
|
||||
|
/* Usually return io_close_taken_fd, but may wait for old peer to
|
||||
|
* be disconnected if it's a reconnect. */ |
||||
|
return peer_connected(conn, peer->daemon, &peer->id, |
||||
|
take(msg), take(lfeatures)); |
||||
|
} |
||||
|
|
||||
|
static struct io_plan *peer_init_hdr_received(struct io_conn *conn, |
||||
|
struct peer *peer) |
||||
|
{ |
||||
|
u16 len; |
||||
|
|
||||
|
if (!cryptomsg_decrypt_header(&peer->cs, peer->msg, &len)) |
||||
|
return io_close(conn); |
||||
|
|
||||
|
tal_free(peer->msg); |
||||
|
peer->msg = tal_arr(peer, u8, (u32)len + CRYPTOMSG_BODY_OVERHEAD); |
||||
|
return io_read(conn, peer->msg, tal_count(peer->msg), |
||||
|
peer_init_received, peer); |
||||
|
} |
||||
|
|
||||
|
static struct io_plan *read_init(struct io_conn *conn, struct peer *peer) |
||||
|
{ |
||||
|
/* Free our sent init msg. */ |
||||
|
tal_free(peer->msg); |
||||
|
|
||||
|
/* BOLT #1:
|
||||
|
* |
||||
|
* The receiving node: |
||||
|
* - MUST wait to receive `init` before sending any other messages. |
||||
|
*/ |
||||
|
peer->msg = tal_arr(peer, u8, CRYPTOMSG_HDR_SIZE); |
||||
|
return io_read(conn, peer->msg, tal_bytelen(peer->msg), |
||||
|
peer_init_hdr_received, peer); |
||||
|
} |
||||
|
|
||||
|
#if DEVELOPER |
||||
|
static struct io_plan *peer_write_postclose(struct io_conn *conn, |
||||
|
struct peer *peer) |
||||
|
{ |
||||
|
dev_sabotage_fd(io_conn_fd(conn)); |
||||
|
return read_init(conn, peer); |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
struct io_plan *peer_exchange_initmsg(struct io_conn *conn, |
||||
|
struct daemon *daemon, |
||||
|
const struct crypto_state *cs, |
||||
|
const struct pubkey *id, |
||||
|
const struct wireaddr_internal *addr) |
||||
|
{ |
||||
|
/* If conn is closed, forget peer */ |
||||
|
struct peer *peer = tal(conn, struct peer); |
||||
|
struct io_plan *(*next)(struct io_conn *, struct peer *); |
||||
|
|
||||
|
peer->daemon = daemon; |
||||
|
peer->id = *id; |
||||
|
peer->addr = *addr; |
||||
|
peer->cs = *cs; |
||||
|
|
||||
|
/* BOLT #1:
|
||||
|
* |
||||
|
* The sending node: |
||||
|
* - MUST send `init` as the first Lightning message for any |
||||
|
* connection. |
||||
|
*/ |
||||
|
peer->msg = towire_init(NULL, |
||||
|
get_offered_global_features(tmpctx), |
||||
|
get_offered_local_features(tmpctx)); |
||||
|
status_peer_io(LOG_IO_OUT, peer->msg); |
||||
|
peer->msg = cryptomsg_encrypt_msg(peer, &peer->cs, take(peer->msg)); |
||||
|
|
||||
|
next = read_init; |
||||
|
#if DEVELOPER |
||||
|
switch (dev_disconnect(WIRE_INIT)) { |
||||
|
case DEV_DISCONNECT_BEFORE: |
||||
|
dev_sabotage_fd(io_conn_fd(conn)); |
||||
|
break; |
||||
|
case DEV_DISCONNECT_DROPPKT: |
||||
|
peer->msg = tal_free(peer->msg); /* FALL THRU */ |
||||
|
case DEV_DISCONNECT_AFTER: |
||||
|
next = peer_write_postclose; |
||||
|
break; |
||||
|
case DEV_DISCONNECT_BLACKHOLE: |
||||
|
dev_blackhole_fd(io_conn_fd(conn)); |
||||
|
break; |
||||
|
case DEV_DISCONNECT_NORMAL: |
||||
|
break; |
||||
|
} |
||||
|
#endif /* DEVELOPER */ |
||||
|
|
||||
|
return io_write(conn, peer->msg, tal_bytelen(peer->msg), next, peer); |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
#ifndef LIGHTNING_CONNECTD_PEER_EXCHANGE_INITMSG_H |
||||
|
#define LIGHTNING_CONNECTD_PEER_EXCHANGE_INITMSG_H |
||||
|
#include "config.h" |
||||
|
|
||||
|
struct crypto_state; |
||||
|
struct daemon; |
||||
|
struct io_conn; |
||||
|
struct pubkey; |
||||
|
struct wireaddr_internal; |
||||
|
|
||||
|
/* If successful, calls peer_connected() */ |
||||
|
struct io_plan *peer_exchange_initmsg(struct io_conn *conn, |
||||
|
struct daemon *daemon, |
||||
|
const struct crypto_state *cs, |
||||
|
const struct pubkey *id, |
||||
|
const struct wireaddr_internal *addr); |
||||
|
|
||||
|
#endif /* LIGHTNING_CONNECTD_PEER_EXCHANGE_INITMSG_H */ |
Loading…
Reference in new issue