From afedf0e8acc42557e3fea20ddde6ce4845c2be7a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 24 Mar 2016 12:03:44 +1030 Subject: [PATCH] cryptopkt: implement ack callbacks. For the change to asynchronous updates as specified by BOLT #2, we need to know when the other side acknowledged a packet. This creates a simple callback mechanism for it. Signed-off-by: Rusty Russell --- daemon/cryptopkt.c | 44 ++++++++++++++++++++++++++++++++++++++------ daemon/cryptopkt.h | 19 ++++++++++++++----- daemon/peer.c | 2 +- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/daemon/cryptopkt.c b/daemon/cryptopkt.c index fc4c2bf97..6ef7f01c4 100644 --- a/daemon/cryptopkt.c +++ b/daemon/cryptopkt.c @@ -102,6 +102,13 @@ static void setup_crypto(struct dir_state *dir, dir->cpkt = NULL; } +struct ack { + struct list_node list; + u64 pktnum; + void (*ack_cb)(struct peer *peer, void *); + void *ack_arg; +}; + struct io_data { /* Stuff we need to keep around to talk to peer. */ struct dir_state in, out; @@ -114,6 +121,9 @@ struct io_data { /* For negotiation phase. */ struct key_negotiate *neg; + + /* Tracking what needs acks. */ + struct list_head acks; }; static void *proto_tal_alloc(void *allocator_data, size_t size) @@ -239,6 +249,7 @@ static struct crypto_pkt *encrypt_pkt(struct peer *peer, const Pkt *pkt, u64 ack static struct io_plan *decrypt_body(struct io_conn *conn, struct peer *peer) { struct io_data *iod = peer->io_data; + struct ack *ack; /* We have full packet. */ peer->inpkt = decrypt_pkt(peer, iod->in.cpkt, @@ -256,6 +267,15 @@ static struct io_plan *decrypt_body(struct io_conn *conn, struct peer *peer) peer->inpkt->pkt_case == PKT__PKT_AUTH ? "PKT_AUTH" : input_name(peer->inpkt->pkt_case)); + /* Do callbacks for any packets it acknowledged receiving. */ + while ((ack = list_top(&iod->acks, struct ack, list)) != NULL) { + if (le64_to_cpu(iod->hdr_in.acknowledge) < ack->pktnum) + break; + ack->ack_cb(peer, ack->ack_arg); + list_del_from(&iod->acks, &ack->list); + tal_free(ack); + } + return iod->cb(conn, peer); } @@ -305,11 +325,13 @@ struct io_plan *peer_read_packet(struct io_conn *conn, } /* Caller must free data! */ -struct io_plan *peer_write_packet(struct io_conn *conn, - struct peer *peer, - const Pkt *pkt, - struct io_plan *(*next)(struct io_conn *, - struct peer *)) +struct io_plan *peer_write_packet_(struct io_conn *conn, + struct peer *peer, + const Pkt *pkt, + void (*ack_cb)(struct peer *peer, void *), + void *ack_arg, + struct io_plan *(*next)(struct io_conn *, + struct peer *)) { struct io_data *iod = peer->io_data; size_t totlen; @@ -320,6 +342,15 @@ struct io_plan *peer_write_packet(struct io_conn *conn, iod->out.cpkt = encrypt_pkt(peer, pkt, peer->io_data->in.count, &totlen); + /* Set up ack callback if any. */ + if (ack_cb) { + struct ack *ack = tal(peer, struct ack); + ack->pktnum = peer->io_data->out.count; + ack->ack_cb = ack_cb; + ack->ack_arg = ack_arg; + list_add_tail(&iod->acks, &ack->list); + } + /* We don't add to count for authenticate case. */ if (pkt->pkt_case != PKT__PKT_AUTH) peer->io_data->out.count++; @@ -476,7 +507,7 @@ static struct io_plan *keys_exchanged(struct io_conn *conn, struct peer *peer) /* FIXME: Free auth afterwards. */ auth = authenticate_pkt(peer, &peer->dstate->id, &sig); - return peer_write_packet(conn, peer, auth, receive_proof); + return peer_write_packet(conn, peer, auth, NULL, NULL, receive_proof); } /* Read and ignore any extra bytes... */ @@ -564,6 +595,7 @@ struct io_plan *peer_crypto_setup(struct io_conn *conn, struct peer *peer, BUILD_ASSERT(CRYPTO_HDR_LEN == offsetof(struct crypto_pkt, data)); peer->io_data = tal(peer, struct io_data); + list_head_init(&peer->io_data->acks); /* We store negotiation state here. */ neg = peer->io_data->neg = tal(peer->io_data, struct key_negotiate); diff --git a/daemon/cryptopkt.h b/daemon/cryptopkt.h index 06c61672d..82a231c1d 100644 --- a/daemon/cryptopkt.h +++ b/daemon/cryptopkt.h @@ -3,6 +3,7 @@ #include "config.h" #include "lightning.pb-c.h" #include +#include struct peer; @@ -17,10 +18,18 @@ struct io_plan *peer_read_packet(struct io_conn *conn, struct io_plan *(*cb)(struct io_conn *, struct peer *)); -struct io_plan *peer_write_packet(struct io_conn *conn, - struct peer *peer, - const Pkt *pkt, - struct io_plan *(*next)(struct io_conn *, - struct peer *)); +struct io_plan *peer_write_packet_(struct io_conn *conn, + struct peer *peer, + const Pkt *pkt, + void (*ack_cb)(struct peer *peer, void *), + void *ack_arg, + struct io_plan *(*next)(struct io_conn *, + struct peer *)); +#define peer_write_packet(conn, peer, pkt, ack_cb, ack_arg, next) \ + peer_write_packet_((conn), (peer), (pkt), \ + typesafe_cb_preargs(void, void *, \ + (ack_cb), (ack_arg), \ + struct peer *), \ + (ack_arg), (next)) #endif /* LIGHTNING_DAEMON_CRYPTOPKT_H */ diff --git a/daemon/peer.c b/daemon/peer.c index 281d22186..f07665621 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -240,7 +240,7 @@ static struct io_plan *pkt_out(struct io_conn *conn, struct peer *peer) out = peer->outpkt[0]; memmove(peer->outpkt, peer->outpkt + 1, (sizeof(*peer->outpkt)*(n-1))); tal_resize(&peer->outpkt, n-1); - return peer_write_packet(conn, peer, out, pkt_out); + return peer_write_packet(conn, peer, out, NULL, NULL, pkt_out); } static struct io_plan *pkt_in(struct io_conn *conn, struct peer *peer)