diff --git a/common/gossip_store.c b/common/gossip_store.c index cf7aaaae8..361aaed38 100644 --- a/common/gossip_store.c +++ b/common/gossip_store.c @@ -182,25 +182,48 @@ u8 *gossip_store_next(const tal_t *ctx, return msg; } -size_t find_gossip_store_end(int gossip_store_fd, size_t off) +/* We cheat and read first two bytes of message too. */ +struct hdr_and_type { + struct gossip_hdr hdr; + be16 type; +}; +/* Beware padding! */ +#define HDR_AND_TYPE_SIZE (sizeof(struct gossip_hdr) + sizeof(u16)) + +bool gossip_store_readhdr(int gossip_store_fd, size_t off, + size_t *len, + u32 *timestamp, + u16 *flags, + u16 *type) { - /* We cheat and read first two bytes of message too. */ - struct { - struct gossip_hdr hdr; - be16 type; - } buf; + struct hdr_and_type buf; int r; - while ((r = pread(gossip_store_fd, &buf, - sizeof(buf.hdr) + sizeof(buf.type), off)) - == sizeof(buf.hdr) + sizeof(buf.type)) { - u16 msglen = be16_to_cpu(buf.hdr.len); + r = pread(gossip_store_fd, &buf, HDR_AND_TYPE_SIZE, off); + if (r != HDR_AND_TYPE_SIZE) + return false; + *len = be16_to_cpu(buf.hdr.len); + if (flags) + *flags = be16_to_cpu(buf.hdr.flags); + if (timestamp) + *timestamp = be32_to_cpu(buf.hdr.timestamp); + if (type) + *type = be16_to_cpu(buf.type); + return true; +} +size_t find_gossip_store_end(int gossip_store_fd, size_t off) +{ + size_t msglen; + u16 type; + + while (gossip_store_readhdr(gossip_store_fd, off, + &msglen, NULL, NULL, &type)) { /* Don't swallow end marker! */ - if (buf.type == CPU_TO_BE16(WIRE_GOSSIP_STORE_ENDED)) + if (type == WIRE_GOSSIP_STORE_ENDED) break; - off += sizeof(buf.hdr) + msglen; + off += sizeof(struct gossip_hdr) + msglen; } return off; } diff --git a/common/gossip_store.h b/common/gossip_store.h index 6ef02e3c8..2bc3340ae 100644 --- a/common/gossip_store.h +++ b/common/gossip_store.h @@ -69,6 +69,27 @@ u8 *gossip_store_next(const tal_t *ctx, bool with_spam, size_t *off, size_t *end); +/** + * Direct store accessor: read gossip msg hdr from store. + * @gossip_store_fd: the readable file descriptor + * @off: the offset to read + * @len (out): the length of the message (not including header) + * @timestamp (out): if non-NULL, set to the timestamp. + * @flags (out): if non-NULL, set to the flags. + * @type (out): if non-NULL, set to the msg type. + * + * Returns false if there are no more gossip msgs. If you + * want to read the message, use gossip_store_next, if you + * want to skip, simply add sizeof(gossip_hdr) + *len to *off. + * Note: it's possible that entire record isn't there yet, + * so gossip_store_next can fail. + */ +bool gossip_store_readhdr(int gossip_store_fd, size_t off, + size_t *len, + u32 *timestamp, + u16 *flags, + u16 *type); + /** * Gossipd will be writing to this, and it's not atomic! Safest * way to find the "end" is to walk through.