diff --git a/gossipd/gossip.c b/gossipd/gossip.c index 2ed07e727..e91478f9a 100644 --- a/gossipd/gossip.c +++ b/gossipd/gossip.c @@ -1554,8 +1554,7 @@ static struct io_plan *gossip_init(struct daemon_conn *master, gossip_refresh_network, daemon); /* Load stored gossip messages */ - while (gossip_store_read_next(daemon->rstate, daemon->rstate->store)) { - } + gossip_store_load(daemon->rstate, daemon->rstate->store); return daemon_conn_read_next(master->conn, master); } diff --git a/gossipd/gossip_store.c b/gossipd/gossip_store.c index aaa89387a..5590e6765 100644 --- a/gossipd/gossip_store.c +++ b/gossipd/gossip_store.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -14,7 +16,7 @@ static u8 gossip_store_version = 0x01; struct gossip_store { int fd; - off_t read_pos, write_pos; + off_t write_pos; u8 version; }; @@ -27,7 +29,6 @@ struct gossip_store *gossip_store_new(const tal_t *ctx) { struct gossip_store *gs = tal(ctx, struct gossip_store); gs->fd = open(GOSSIP_STORE_FILENAME, O_RDWR|O_APPEND|O_CREAT, 0600); - gs->read_pos = 1; gs->write_pos = lseek(gs->fd, 0, SEEK_END); /* Try to read the version, write it if this is a new file, or truncate @@ -96,58 +97,69 @@ void gossip_store_add_channel_delete(struct gossip_store *gs, tal_free(msg); } -bool gossip_store_read_next(struct routing_state *rstate, - struct gossip_store *gs) +void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs) { beint32_t belen; u32 msglen; u8 *msg, *gossip_msg; u64 satoshis; - enum gossip_wire_type type; struct short_channel_id scid; - - /* Did we already reach the end of the gossip_store? */ - if (gs->read_pos == -1) - return NULL; - - /* Can we read one message? */ - if (pread(gs->fd, &belen, sizeof(belen), gs->read_pos) != sizeof(belen)) { - gs->read_pos = -1; - return false; - } - - msglen = be32_to_cpu(belen); - msg = tal_arr(gs, u8, msglen); - - if (!pread(gs->fd, msg, msglen, gs->read_pos + sizeof(belen))) { - status_trace("Short read from gossip-store, expected lenght %d", - msglen); - - /* Reset write_pos to truncate this message and disable future - * reads */ - gs->write_pos = gs->read_pos; - gs->read_pos = -1; - ftruncate(gs->fd, gs->write_pos); + /* We set/check version byte on creation */ + off_t known_good = 1; + const char *bad; + + lseek(gs->fd, known_good, SEEK_SET); + while (read(gs->fd, &belen, sizeof(belen)) == sizeof(belen)) { + msglen = be32_to_cpu(belen); + msg = tal_arr(gs, u8, msglen); + + if (read(gs->fd, msg, msglen) != msglen) { + status_unusual("gossip_store: truncated file?"); + goto truncate_nomsg; + } + + if (fromwire_gossip_store_channel_announcement(msg, msg, + &gossip_msg, + &satoshis)) { + if (!routing_add_channel_announcement(rstate, + gossip_msg, + satoshis)) { + bad = "Bad channel_announcement"; + goto truncate; + } + } else if (fromwire_gossip_store_channel_update(msg, msg, + &gossip_msg)) { + if (!routing_add_channel_update(rstate, gossip_msg)) { + bad = "Bad channel_update"; + goto truncate; + } + } else if (fromwire_gossip_store_node_announcement(msg, msg, + &gossip_msg)) { + if (!routing_add_node_announcement(rstate, gossip_msg)) { + bad = "Bad node_announcement"; + goto truncate; + } + } else if (fromwire_gossip_store_channel_delete(msg, &scid)) { + struct chan *c = get_channel(rstate, &scid); + if (!c) { + bad = "Bad channel_delete"; + goto truncate; + } + tal_free(c); + } else { + bad = "Unknown message"; + goto truncate; + } + known_good += sizeof(belen) + msglen; tal_free(msg); - return false; } - - gs->read_pos += sizeof(belen) + msglen; - type = fromwire_peektype(msg); - - if (type == WIRE_GOSSIP_STORE_CHANNEL_ANNOUNCEMENT) { - fromwire_gossip_store_channel_announcement(msg, msg, &gossip_msg, &satoshis); - routing_add_channel_announcement(rstate, gossip_msg, satoshis); - } else if(type == WIRE_GOSSIP_STORE_CHANNEL_UPDATE) { - fromwire_gossip_store_channel_update(msg, msg, &gossip_msg); - routing_add_channel_update(rstate, gossip_msg); - } else if(type == WIRE_GOSSIP_STORE_NODE_ANNOUNCEMENT) { - fromwire_gossip_store_node_announcement(msg, msg, &gossip_msg); - routing_add_node_announcement(rstate, gossip_msg); - } else if(type == WIRE_GOSSIP_STORE_CHANNEL_DELETE) { - fromwire_gossip_store_channel_delete(msg, &scid); - tal_free(get_channel(rstate, &scid)); - } - tal_free(msg); - return true; + return; + +truncate: + status_unusual("gossip_store: %s (%s) truncating to %"PRIu64, + bad, tal_hex(msg, msg), (u64)known_good); +truncate_nomsg: + if (ftruncate(gs->fd, known_good) != 0) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Truncating store: %s", strerror(errno)); } diff --git a/gossipd/gossip_store.h b/gossipd/gossip_store.h index 34bb205a1..d5e80925c 100644 --- a/gossipd/gossip_store.h +++ b/gossipd/gossip_store.h @@ -17,15 +17,12 @@ struct routing_state; struct gossip_store *gossip_store_new(const tal_t *ctx); /** - * Retrieve the next gossip message if any + * Load the initial gossip store, if any. * - * @param ctx The context to allocate the message from + * @param rstate The routing state to load init. * @param gs The `gossip_store` to read from - * @return whether a message was read from the store. False means that all - * messages have been processed. */ -bool gossip_store_read_next(struct routing_state *rstate, - struct gossip_store *gs); +void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs); /** * Store a channel_announcement with all its extra data