mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 14:42:40 +01:00
channeld: it's OK to block on writing to peer.
In fact, it's good. We don't want to queue up infinite gossip. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
c05bc7c8ab
commit
74d428109a
1 changed files with 39 additions and 144 deletions
|
@ -103,13 +103,6 @@ struct peer {
|
|||
struct channel_id channel_id;
|
||||
struct channel *channel;
|
||||
|
||||
/* Pending msgs to send (not encrypted) */
|
||||
struct msg_queue peer_out;
|
||||
|
||||
/* Current msg to send, and offset (encrypted) */
|
||||
const u8 *peer_outmsg;
|
||||
size_t peer_outoff;
|
||||
|
||||
/* Messages from master / gossipd: we queue them since we
|
||||
* might be waiting for a specific reply. */
|
||||
struct msg_queue from_master, from_gossipd;
|
||||
|
@ -220,84 +213,6 @@ static void *tal_arr_append_(void **p, size_t size)
|
|||
}
|
||||
#define tal_arr_append(p) tal_arr_append_((void **)(p), sizeof(**(p)))
|
||||
|
||||
static void do_peer_write(struct peer *peer)
|
||||
{
|
||||
int r;
|
||||
size_t len = tal_count(peer->peer_outmsg);
|
||||
|
||||
r = write(PEER_FD, peer->peer_outmsg + peer->peer_outoff,
|
||||
len - peer->peer_outoff);
|
||||
if (r < 0)
|
||||
peer_failed_connection_lost();
|
||||
|
||||
peer->peer_outoff += r;
|
||||
if (peer->peer_outoff == len)
|
||||
peer->peer_outmsg = tal_free(peer->peer_outmsg);
|
||||
}
|
||||
|
||||
static bool peer_write_pending(struct peer *peer)
|
||||
{
|
||||
const u8 *msg;
|
||||
|
||||
if (peer->peer_outmsg)
|
||||
return true;
|
||||
|
||||
msg = msg_dequeue(&peer->peer_out);
|
||||
if (!msg)
|
||||
return false;
|
||||
|
||||
status_peer_io(LOG_IO_OUT, msg);
|
||||
peer->peer_outmsg = cryptomsg_encrypt_msg(peer, &peer->cs, take(msg));
|
||||
peer->peer_outoff = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Synchronous flush of all pending packets. */
|
||||
static void flush_peer_out(struct peer *peer)
|
||||
{
|
||||
while (peer_write_pending(peer))
|
||||
do_peer_write(peer);
|
||||
}
|
||||
|
||||
static void enqueue_peer_msg(struct peer *peer, const u8 *msg TAKES)
|
||||
{
|
||||
#if DEVELOPER
|
||||
enum dev_disconnect d = dev_disconnect(fromwire_peektype(msg));
|
||||
|
||||
/* We want to effect this exact packet, so flush any pending. */
|
||||
if (d != DEV_DISCONNECT_NORMAL)
|
||||
flush_peer_out(peer);
|
||||
|
||||
switch (d) {
|
||||
case DEV_DISCONNECT_BEFORE:
|
||||
/* Fail immediately. */
|
||||
dev_sabotage_fd(PEER_FD);
|
||||
msg_enqueue(&peer->peer_out, msg);
|
||||
flush_peer_out(peer);
|
||||
/* Should not return */
|
||||
abort();
|
||||
case DEV_DISCONNECT_DROPPKT:
|
||||
if (taken(msg))
|
||||
tal_free(msg);
|
||||
/* Fail next time we try to do something. */
|
||||
dev_sabotage_fd(PEER_FD);
|
||||
return;
|
||||
case DEV_DISCONNECT_AFTER:
|
||||
msg_enqueue(&peer->peer_out, msg);
|
||||
flush_peer_out(peer);
|
||||
dev_sabotage_fd(PEER_FD);
|
||||
return;
|
||||
case DEV_DISCONNECT_BLACKHOLE:
|
||||
msg_enqueue(&peer->peer_out, msg);
|
||||
dev_blackhole_fd(PEER_FD);
|
||||
return;
|
||||
case DEV_DISCONNECT_NORMAL:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
msg_enqueue(&peer->peer_out, msg);
|
||||
}
|
||||
|
||||
static const u8 *hsm_req(const tal_t *ctx, const u8 *req TAKES)
|
||||
{
|
||||
u8 *msg;
|
||||
|
@ -411,7 +326,8 @@ static void send_announcement_signatures(struct peer *peer)
|
|||
NULL, &peer->channel_id, &peer->short_channel_ids[LOCAL],
|
||||
&peer->announcement_node_sigs[LOCAL],
|
||||
&peer->announcement_bitcoin_sigs[LOCAL]);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
}
|
||||
|
||||
/* Tentatively create a channel_announcement, possibly with invalid
|
||||
|
@ -755,7 +671,8 @@ static void maybe_send_shutdown(struct peer *peer)
|
|||
send_channel_update(peer, ROUTING_FLAGS_DISABLED);
|
||||
|
||||
msg = towire_shutdown(NULL, &peer->channel_id, peer->final_scriptpubkey);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
peer->send_shutdown = false;
|
||||
peer->shutdown_sent[LOCAL] = true;
|
||||
billboard_update(peer);
|
||||
|
@ -1075,7 +992,8 @@ static void send_commit(struct peer *peer)
|
|||
feerate, max);
|
||||
|
||||
msg = towire_update_fee(NULL, &peer->channel_id, feerate);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
|
@ -1117,7 +1035,8 @@ static void send_commit(struct peer *peer)
|
|||
msg = towire_commitment_signed(NULL, &peer->channel_id,
|
||||
&peer->next_commit_sigs->commit_sig,
|
||||
peer->next_commit_sigs->htlc_sigs);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
peer->next_commit_sigs = tal_free(peer->next_commit_sigs);
|
||||
|
||||
maybe_send_shutdown(peer);
|
||||
|
@ -1181,7 +1100,8 @@ static void send_revocation(struct peer *peer)
|
|||
start_commit_timer(peer);
|
||||
}
|
||||
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
}
|
||||
|
||||
static u8 *got_commitsig_msg(const tal_t *ctx,
|
||||
|
@ -1738,7 +1658,8 @@ static void resend_revoke(struct peer *peer)
|
|||
struct pubkey point;
|
||||
/* Current commit is peer->next_index[LOCAL]-1, revoke prior */
|
||||
u8 *msg = make_revocation_msg(peer, peer->next_index[LOCAL]-2, &point);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
}
|
||||
|
||||
static void send_fail_or_fulfill(struct peer *peer, const struct htlc *h)
|
||||
|
@ -1777,7 +1698,8 @@ static void send_fail_or_fulfill(struct peer *peer, const struct htlc *h)
|
|||
&peer->channel_id,
|
||||
"HTLC %"PRIu64" state %s not failed/fulfilled",
|
||||
h->id, htlc_state_name(h->state));
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
}
|
||||
|
||||
static void resend_commitment(struct peer *peer, const struct changed_htlc *last)
|
||||
|
@ -1812,13 +1734,14 @@ static void resend_commitment(struct peer *peer, const struct changed_htlc *last
|
|||
last[i].id);
|
||||
|
||||
if (h->state == SENT_ADD_COMMIT) {
|
||||
u8 *msg = towire_update_add_htlc(peer, &peer->channel_id,
|
||||
u8 *msg = towire_update_add_htlc(NULL, &peer->channel_id,
|
||||
h->id, h->msatoshi,
|
||||
&h->rhash,
|
||||
abs_locktime_to_blocks(
|
||||
&h->expiry),
|
||||
h->routing);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
} else if (h->state == SENT_REMOVE_COMMIT) {
|
||||
send_fail_or_fulfill(peer, h);
|
||||
}
|
||||
|
@ -1828,7 +1751,8 @@ static void resend_commitment(struct peer *peer, const struct changed_htlc *last
|
|||
if (peer->channel->funder == LOCAL) {
|
||||
msg = towire_update_fee(NULL, &peer->channel_id,
|
||||
channel_feerate(peer->channel, REMOTE));
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
}
|
||||
|
||||
/* Re-send the commitment_signed itself. */
|
||||
|
@ -1836,7 +1760,8 @@ static void resend_commitment(struct peer *peer, const struct changed_htlc *last
|
|||
msg = towire_commitment_signed(NULL, &peer->channel_id,
|
||||
&commit_sigs->commit_sig,
|
||||
commit_sigs->htlc_sigs);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
tal_free(commit_sigs);
|
||||
|
||||
/* If we have already received the revocation for the previous, the
|
||||
|
@ -1848,21 +1773,12 @@ static void resend_commitment(struct peer *peer, const struct changed_htlc *last
|
|||
peer->revocations_received);
|
||||
}
|
||||
|
||||
static bool channeld_send_reply(struct crypto_state *cs UNUSED,
|
||||
int peer_fd UNUSED,
|
||||
const u8 *msg,
|
||||
struct peer *peer)
|
||||
{
|
||||
enqueue_peer_msg(peer, msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
static u8 *channeld_read_peer_msg(struct peer *peer)
|
||||
{
|
||||
return read_peer_msg(peer, &peer->cs,
|
||||
&peer->channel_id,
|
||||
channeld_send_reply,
|
||||
peer);
|
||||
sync_crypto_write_arg,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void peer_reconnect(struct peer *peer)
|
||||
|
@ -1905,7 +1821,7 @@ static void peer_reconnect(struct peer *peer)
|
|||
* before we've reestablished channel). */
|
||||
while ((msg = read_peer_msg_nogossip(peer, &peer->cs,
|
||||
&peer->channel_id,
|
||||
channeld_send_reply,
|
||||
sync_crypto_write_arg,
|
||||
peer)) == NULL)
|
||||
clean_tmpctx();
|
||||
|
||||
|
@ -1940,7 +1856,8 @@ static void peer_reconnect(struct peer *peer)
|
|||
msg = towire_funding_locked(NULL,
|
||||
&peer->channel_id,
|
||||
&peer->next_local_per_commit);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
}
|
||||
|
||||
/* Note: next_index is the index of the current commit we're working
|
||||
|
@ -2082,7 +1999,8 @@ static void handle_funding_locked(struct peer *peer, const u8 *msg)
|
|||
msg = towire_funding_locked(NULL,
|
||||
&peer->channel_id,
|
||||
&peer->next_local_per_commit);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
peer->funding_locked[LOCAL] = true;
|
||||
}
|
||||
|
||||
|
@ -2129,7 +2047,8 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
|
|||
peer->htlc_id, amount_msat,
|
||||
&payment_hash, cltv_expiry,
|
||||
onion_routing_packet);
|
||||
enqueue_peer_msg(peer, take(msg));
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(msg)))
|
||||
peer_failed_connection_lost();
|
||||
start_commit_timer(peer);
|
||||
/* Tell the master. */
|
||||
msg = towire_channel_offer_htlc_reply(NULL, peer->htlc_id,
|
||||
|
@ -2493,8 +2412,10 @@ static void init_channel(struct peer *peer)
|
|||
peer_reconnect(peer);
|
||||
|
||||
/* If we have a funding_signed message, send that immediately */
|
||||
if (funding_signed)
|
||||
enqueue_peer_msg(peer, take(funding_signed));
|
||||
if (funding_signed) {
|
||||
if (!sync_crypto_write(&peer->cs, PEER_FD, take(funding_signed)))
|
||||
peer_failed_connection_lost();
|
||||
}
|
||||
|
||||
/* Reenable channel */
|
||||
channel_announcement_negotiate(peer);
|
||||
|
@ -2504,9 +2425,6 @@ static void init_channel(struct peer *peer)
|
|||
|
||||
static void send_shutdown_complete(struct peer *peer)
|
||||
{
|
||||
/* Push out any incomplete messages to peer. */
|
||||
flush_peer_out(peer);
|
||||
|
||||
/* Now we can tell master shutdown is complete. */
|
||||
wire_sync_write(MASTER_FD,
|
||||
take(towire_channel_shutdown_complete(NULL, &peer->cs)));
|
||||
|
@ -2534,9 +2452,6 @@ int main(int argc, char *argv[])
|
|||
peer->channel_local_active = false;
|
||||
msg_queue_init(&peer->from_master, peer);
|
||||
msg_queue_init(&peer->from_gossipd, peer);
|
||||
msg_queue_init(&peer->peer_out, peer);
|
||||
peer->peer_outmsg = NULL;
|
||||
peer->peer_outoff = 0;
|
||||
peer->next_commit_sigs = NULL;
|
||||
peer->shutdown_sent[LOCAL] = false;
|
||||
peer->last_update_timestamp = 0;
|
||||
|
@ -2564,7 +2479,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
while (!shutdown_complete(peer)) {
|
||||
struct timemono first;
|
||||
fd_set rfds = fds_in, wfds, *wptr;
|
||||
fd_set rfds = fds_in;
|
||||
struct timeval timeout, *tptr;
|
||||
struct timer *expired;
|
||||
const u8 *msg;
|
||||
|
@ -2595,8 +2510,8 @@ int main(int argc, char *argv[])
|
|||
status_trace("Now dealing with deferred gossip %u",
|
||||
fromwire_peektype(msg));
|
||||
handle_gossip_msg(take(msg), &peer->cs,
|
||||
channeld_send_reply,
|
||||
peer);
|
||||
sync_crypto_write_arg,
|
||||
NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2607,13 +2522,7 @@ int main(int argc, char *argv[])
|
|||
} else
|
||||
tptr = NULL;
|
||||
|
||||
if (peer_write_pending(peer)) {
|
||||
wfds = fds_out;
|
||||
wptr = &wfds;
|
||||
} else
|
||||
wptr = NULL;
|
||||
|
||||
if (select(nfds, &rfds, wptr, NULL, tptr) < 0) {
|
||||
if (select(nfds, &rfds, NULL, NULL, tptr) < 0) {
|
||||
/* Signals OK, eg. SIGUSR1 */
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
@ -2621,20 +2530,6 @@ int main(int argc, char *argv[])
|
|||
"select failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* Try writing out encrypted packet if any (don't block!) */
|
||||
if (wptr && FD_ISSET(PEER_FD, wptr)) {
|
||||
if (!io_fd_block(PEER_FD, false))
|
||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||
"NONBLOCK failed: %s",
|
||||
strerror(errno));
|
||||
do_peer_write(peer);
|
||||
if (!io_fd_block(PEER_FD, true))
|
||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||
"NONBLOCK unset failed: %s",
|
||||
strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FD_ISSET(MASTER_FD, &rfds)) {
|
||||
msg = wire_sync_read(tmpctx, MASTER_FD);
|
||||
|
||||
|
@ -2650,7 +2545,7 @@ int main(int argc, char *argv[])
|
|||
if (!msg)
|
||||
peer_failed_connection_lost();
|
||||
handle_gossip_msg(msg, &peer->cs,
|
||||
channeld_send_reply,
|
||||
sync_crypto_write_arg,
|
||||
peer);
|
||||
} else if (FD_ISSET(PEER_FD, &rfds)) {
|
||||
/* This could take forever, but who cares? */
|
||||
|
|
Loading…
Add table
Reference in a new issue