Browse Source

gossipd: don't use pwrite, better error messaging on init.

Since we open with O_APPEND, any write() will append as we want it to.

But we want to distinguish a new store creation from a truncation due
to bad version.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
2b8293c9f6
  1. 54
      gossipd/gossip_store.c
  2. 3
      gossipd/test/run-bench-find_route.c
  3. 3
      gossipd/test/run-find_route-specific.c
  4. 3
      gossipd/test/run-find_route.c

54
gossipd/gossip_store.c

@ -16,7 +16,6 @@ static u8 gossip_store_version = 0x01;
struct gossip_store { struct gossip_store {
int fd; int fd;
off_t write_pos;
u8 version; u8 version;
}; };
@ -29,22 +28,29 @@ struct gossip_store *gossip_store_new(const tal_t *ctx)
{ {
struct gossip_store *gs = tal(ctx, struct gossip_store); struct gossip_store *gs = tal(ctx, struct gossip_store);
gs->fd = open(GOSSIP_STORE_FILENAME, O_RDWR|O_APPEND|O_CREAT, 0600); gs->fd = open(GOSSIP_STORE_FILENAME, O_RDWR|O_APPEND|O_CREAT, 0600);
gs->write_pos = lseek(gs->fd, 0, SEEK_END);
tal_add_destructor(gs, gossip_store_destroy);
/* Try to read the version, write it if this is a new file, or truncate /* Try to read the version, write it if this is a new file, or truncate
* if the version doesn't match */ * if the version doesn't match */
if (pread(gs->fd, &gs->version, sizeof(gs->version), 0) != 1 || if (read(gs->fd, &gs->version, sizeof(gs->version))
gs->version != gossip_store_version) { == sizeof(gs->version)) {
status_trace("Truncating gossip_store, either it was empty or " /* Version match? All good */
"the version was not supported."); if (gs->version == gossip_store_version)
gs->version = gossip_store_version; return gs;
gs->write_pos = 1;
pwrite(gs->fd, &gossip_store_version, sizeof(gossip_store_version), 0); status_unusual("Gossip store version %u not %u: removing",
ftruncate(gs->fd, gs->write_pos); gs->version, gossip_store_version);
if (ftruncate(gs->fd, 0) != 0)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Truncating store: %s", strerror(errno));
} }
/* Empty file, write version byte */
tal_add_destructor(gs, gossip_store_destroy); gs->version = gossip_store_version;
if (write(gs->fd, &gs->version, sizeof(gs->version))
!= sizeof(gs->version))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Writing version to store: %s", strerror(errno));
return gs; return gs;
} }
/** /**
@ -59,11 +65,17 @@ static void gossip_store_append(struct gossip_store *gs, const u8 *msg)
u32 msglen = tal_len(msg); u32 msglen = tal_len(msg);
beint32_t belen = cpu_to_be32(msglen); beint32_t belen = cpu_to_be32(msglen);
if (pwrite(gs->fd, &belen, sizeof(belen), gs->write_pos) != sizeof(belen) || /* Only give error message once. */
pwrite(gs->fd, msg, msglen, gs->write_pos + sizeof(belen)) != msglen) { if (gs->fd == -1)
return; return;
} else
gs->write_pos += sizeof(belen) + msglen; /* FORTIFY_SOURCE gets upset if we don't check return. */
if (write(gs->fd, &belen, sizeof(belen)) != sizeof(belen) ||
write(gs->fd, msg, msglen) != msglen) {
status_broken("Failed writing to gossip store: %s",
strerror(errno));
gs->fd = -1;
}
} }
void gossip_store_add_channel_announcement(struct gossip_store *gs, const u8 *gossip_msg, u64 satoshis) void gossip_store_add_channel_announcement(struct gossip_store *gs, const u8 *gossip_msg, u64 satoshis)
@ -107,6 +119,7 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
/* We set/check version byte on creation */ /* We set/check version byte on creation */
off_t known_good = 1; off_t known_good = 1;
const char *bad; const char *bad;
size_t stats[] = {0, 0, 0, 0};
lseek(gs->fd, known_good, SEEK_SET); lseek(gs->fd, known_good, SEEK_SET);
while (read(gs->fd, &belen, sizeof(belen)) == sizeof(belen)) { while (read(gs->fd, &belen, sizeof(belen)) == sizeof(belen)) {
@ -127,18 +140,21 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
bad = "Bad channel_announcement"; bad = "Bad channel_announcement";
goto truncate; goto truncate;
} }
stats[0]++;
} else if (fromwire_gossip_store_channel_update(msg, msg, } else if (fromwire_gossip_store_channel_update(msg, msg,
&gossip_msg)) { &gossip_msg)) {
if (!routing_add_channel_update(rstate, gossip_msg)) { if (!routing_add_channel_update(rstate, gossip_msg)) {
bad = "Bad channel_update"; bad = "Bad channel_update";
goto truncate; goto truncate;
} }
stats[1]++;
} else if (fromwire_gossip_store_node_announcement(msg, msg, } else if (fromwire_gossip_store_node_announcement(msg, msg,
&gossip_msg)) { &gossip_msg)) {
if (!routing_add_node_announcement(rstate, gossip_msg)) { if (!routing_add_node_announcement(rstate, gossip_msg)) {
bad = "Bad node_announcement"; bad = "Bad node_announcement";
goto truncate; goto truncate;
} }
stats[2]++;
} else if (fromwire_gossip_store_channel_delete(msg, &scid)) { } else if (fromwire_gossip_store_channel_delete(msg, &scid)) {
struct chan *c = get_channel(rstate, &scid); struct chan *c = get_channel(rstate, &scid);
if (!c) { if (!c) {
@ -146,6 +162,7 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
goto truncate; goto truncate;
} }
tal_free(c); tal_free(c);
stats[3]++;
} else { } else {
bad = "Unknown message"; bad = "Unknown message";
goto truncate; goto truncate;
@ -153,6 +170,9 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
known_good += sizeof(belen) + msglen; known_good += sizeof(belen) + msglen;
tal_free(msg); tal_free(msg);
} }
status_trace("gossip_store: Read %zu/%zu/%zu/%zu cannounce/cupdate/nannounce/cdelete from store in %"PRIu64" bytes",
stats[0], stats[1], stats[2], stats[3],
(u64)known_good);
return; return;
truncate: truncate:

3
gossipd/test/run-bench-find_route.c

@ -86,6 +86,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */ /* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } { fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for gossip_wire_type_name */
const char *gossip_wire_type_name(int e UNNEEDED)
{ fprintf(stderr, "gossip_wire_type_name called!\n"); abort(); }
/* Generated stub for onion_type_name */ /* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED) const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); } { fprintf(stderr, "onion_type_name called!\n"); abort(); }

3
gossipd/test/run-find_route-specific.c

@ -50,6 +50,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */ /* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } { fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for gossip_wire_type_name */
const char *gossip_wire_type_name(int e UNNEEDED)
{ fprintf(stderr, "gossip_wire_type_name called!\n"); abort(); }
/* Generated stub for onion_type_name */ /* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED) const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); } { fprintf(stderr, "onion_type_name called!\n"); abort(); }

3
gossipd/test/run-find_route.c

@ -48,6 +48,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */ /* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } { fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for gossip_wire_type_name */
const char *gossip_wire_type_name(int e UNNEEDED)
{ fprintf(stderr, "gossip_wire_type_name called!\n"); abort(); }
/* Generated stub for onion_type_name */ /* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED) const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); } { fprintf(stderr, "onion_type_name called!\n"); abort(); }

Loading…
Cancel
Save