@ -16,7 +16,6 @@ static u8 gossip_store_version = 0x01;
struct gossip_store {
int fd ;
off_t write_pos ;
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 ) ;
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
* if the version doesn ' t match */
if ( pread ( gs - > fd , & gs - > version , sizeof ( gs - > version ) , 0 ) ! = 1 | |
gs - > version ! = gossip_store_version ) {
status_trace ( " Truncating gossip_store, either it was empty or "
" the version was not supported. " ) ;
gs - > version = gossip_store_version ;
gs - > write_pos = 1 ;
pwrite ( gs - > fd , & gossip_store_version , sizeof ( gossip_store_version ) , 0 ) ;
ftruncate ( gs - > fd , gs - > write_pos ) ;
if ( read ( gs - > fd , & gs - > version , sizeof ( gs - > version ) )
= = sizeof ( gs - > version ) ) {
/* Version match? All good */
if ( gs - > version = = gossip_store_version )
return gs ;
status_unusual ( " Gossip store version %u not %u: removing " ,
gs - > version , gossip_store_version ) ;
if ( ftruncate ( gs - > fd , 0 ) ! = 0 )
status_failed ( STATUS_FAIL_INTERNAL_ERROR ,
" Truncating store: %s " , strerror ( errno ) ) ;
}
tal_add_destructor ( gs , gossip_store_destroy ) ;
/* Empty file, write version byte */
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 ;
}
/**
@ -59,11 +65,17 @@ static void gossip_store_append(struct gossip_store *gs, const u8 *msg)
u32 msglen = tal_len ( msg ) ;
beint32_t belen = cpu_to_be32 ( msglen ) ;
if ( pwrite ( gs - > fd , & belen , sizeof ( belen ) , gs - > write_pos ) ! = sizeof ( belen ) | |
pwrite ( gs - > fd , msg , msglen , gs - > write_pos + sizeof ( belen ) ) ! = msglen ) {
/* Only give error message once. */
if ( gs - > fd = = - 1 )
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 )
@ -107,6 +119,7 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
/* We set/check version byte on creation */
off_t known_good = 1 ;
const char * bad ;
size_t stats [ ] = { 0 , 0 , 0 , 0 } ;
lseek ( gs - > fd , known_good , SEEK_SET ) ;
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 " ;
goto truncate ;
}
stats [ 0 ] + + ;
} 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 ;
}
stats [ 1 ] + + ;
} 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 ;
}
stats [ 2 ] + + ;
} else if ( fromwire_gossip_store_channel_delete ( msg , & scid ) ) {
struct chan * c = get_channel ( rstate , & scid ) ;
if ( ! c ) {
@ -146,6 +162,7 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
goto truncate ;
}
tal_free ( c ) ;
stats [ 3 ] + + ;
} else {
bad = " Unknown message " ;
goto truncate ;
@ -153,6 +170,9 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
known_good + = sizeof ( belen ) + msglen ;
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 ;
truncate :