Browse Source
We currently create a peer struct, then complete handshake to find out who it is. This means we have a half-formed peer, and worse: if it's a reconnect we get two peers the same. Add an explicit 'struct connection' for the handshake phase, and construct a 'struct peer' once that's done. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
8 years ago
8 changed files with 256 additions and 195 deletions
@ -0,0 +1,179 @@ |
|||||
|
#include <daemon/jsonrpc.h> |
||||
|
#include <daemon/log.h> |
||||
|
#include <errno.h> |
||||
|
#include <lightningd/cryptomsg.h> |
||||
|
#include <lightningd/handshake/gen_handshake_wire.h> |
||||
|
#include <lightningd/hsm/gen_hsm_wire.h> |
||||
|
#include <lightningd/lightningd.h> |
||||
|
#include <lightningd/new_connection.h> |
||||
|
#include <lightningd/peer_control.h> |
||||
|
#include <lightningd/subd.h> |
||||
|
|
||||
|
/* 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; |
||||
|
|
||||
|
/* Unique identifier for handshaked. */ |
||||
|
u64 unique_id; |
||||
|
|
||||
|
/* Socket */ |
||||
|
int fd; |
||||
|
|
||||
|
/* 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"); |
||||
|
} |
||||
|
|
||||
|
struct connection *new_connection(const tal_t *ctx, |
||||
|
struct lightningd *ld, |
||||
|
struct command *cmd, |
||||
|
const struct pubkey *known_id) |
||||
|
{ |
||||
|
static u64 id_counter; |
||||
|
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; |
||||
|
c->fd = -1; |
||||
|
tal_add_destructor(c, connection_destroy); |
||||
|
|
||||
|
return c; |
||||
|
} |
||||
|
|
||||
|
static bool handshake_succeeded(struct subd *handshaked, |
||||
|
const u8 *msg, const int *fds, |
||||
|
struct connection *c) |
||||
|
{ |
||||
|
struct crypto_state cs; |
||||
|
struct pubkey *id; |
||||
|
|
||||
|
assert(tal_count(fds) == 1); |
||||
|
|
||||
|
/* FIXME: Look for peer duplicates! */ |
||||
|
|
||||
|
if (!c->known_id) { |
||||
|
id = tal(msg, struct pubkey); |
||||
|
if (!fromwire_handshake_responder_reply(msg, NULL, id, &cs)) |
||||
|
goto err; |
||||
|
log_info_struct(handshaked->log, "Peer in from %s", |
||||
|
struct pubkey, id); |
||||
|
} else { |
||||
|
id = c->known_id; |
||||
|
if (!fromwire_handshake_initiator_reply(msg, NULL, &cs)) |
||||
|
goto err; |
||||
|
log_info_struct(handshaked->log, "Peer out to %s", |
||||
|
struct pubkey, id); |
||||
|
} |
||||
|
|
||||
|
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; |
||||
|
} |
||||
|
|
||||
|
static bool got_handshake_hsmfd(struct subd *hsm, const u8 *msg, |
||||
|
const int *fds, |
||||
|
struct connection *c) |
||||
|
{ |
||||
|
struct lightningd *ld = hsm->ld; |
||||
|
const u8 *req; |
||||
|
struct subd *handshaked; |
||||
|
|
||||
|
assert(tal_count(fds) == 1); |
||||
|
if (!fromwire_hsmctl_hsmfd_ecdh_fd_reply(msg, NULL)) |
||||
|
fatal("Malformed hsmfd response: %s", tal_hex(msg, msg)); |
||||
|
|
||||
|
/* Give handshake daemon the hsm fd. */ |
||||
|
handshaked = new_subd(ld, ld, |
||||
|
"lightningd_handshake", NULL, |
||||
|
handshake_wire_type_name, |
||||
|
NULL, NULL, |
||||
|
fds[0], c->fd, -1); |
||||
|
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); |
||||
|
|
||||
|
/* We no longer own fd (closed; handshaked has copy). */ |
||||
|
c->fd = -1; |
||||
|
if (c->known_id) { |
||||
|
req = towire_handshake_initiator(c, &ld->dstate.id, |
||||
|
c->known_id); |
||||
|
} else { |
||||
|
req = towire_handshake_responder(c, &ld->dstate.id); |
||||
|
} |
||||
|
|
||||
|
/* Now hand peer request to the handshake daemon: hands it
|
||||
|
* back on success */ |
||||
|
subd_req(c, handshaked, take(req), -1, 1, handshake_succeeded, c); |
||||
|
return true; |
||||
|
|
||||
|
error: |
||||
|
close(fds[0]); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/* 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) |
||||
|
{ |
||||
|
|
||||
|
/* Get HSM fd for this peer. */ |
||||
|
subd_req(c, ld->hsm, |
||||
|
take(towire_hsmctl_hsmfd_ecdh(ld, c->unique_id)), |
||||
|
-1, 1, got_handshake_hsmfd, c); |
||||
|
|
||||
|
c->fd = io_conn_fd(conn); |
||||
|
|
||||
|
/* We don't need conn, we'll pass fd to handshaked. */ |
||||
|
return io_close_taken_fd(conn); |
||||
|
} |
||||
|
|
||||
|
struct io_plan *connection_out(struct io_conn *conn, |
||||
|
struct lightningd_state *dstate, |
||||
|
struct connection *c) |
||||
|
{ |
||||
|
return hsm_then_handshake(conn, ld_from_dstate(dstate), c); |
||||
|
} |
||||
|
|
||||
|
struct io_plan *connection_in(struct io_conn *conn, struct lightningd *ld) |
||||
|
{ |
||||
|
struct connection *c = new_connection(ld, ld, NULL, NULL); |
||||
|
|
||||
|
return hsm_then_handshake(conn, ld, c); |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
#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 lightningd_state; |
||||
|
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_state *dstate, |
||||
|
struct connection *c); |
||||
|
|
||||
|
struct io_plan *connection_in(struct io_conn *conn, struct lightningd *ld); |
||||
|
|
||||
|
#endif /* LIGHTNING_LIGHTNINGD_NEW_CONNECTION_H */ |
Loading…
Reference in new issue