@ -11,6 +11,77 @@
# include <wire/peer_wire.h>
# include <wire/peer_wire.h>
# include <wire/wire_sync.h>
# include <wire/wire_sync.h>
u8 * peer_or_gossip_sync_read ( const tal_t * ctx ,
int peer_fd , int gossip_fd ,
struct crypto_state * cs ,
bool * from_gossipd )
{
fd_set readfds ;
u8 * msg ;
FD_ZERO ( & readfds ) ;
FD_SET ( peer_fd , & readfds ) ;
FD_SET ( gossip_fd , & readfds ) ;
select ( peer_fd > gossip_fd ? peer_fd + 1 : gossip_fd + 1 ,
& readfds , NULL , NULL , NULL ) ;
if ( FD_ISSET ( gossip_fd , & readfds ) ) {
msg = wire_sync_read ( ctx , gossip_fd ) ;
if ( ! msg )
status_failed ( STATUS_FAIL_GOSSIP_IO ,
" Error reading gossip msg: %s " ,
strerror ( errno ) ) ;
* from_gossipd = true ;
return msg ;
}
msg = sync_crypto_read ( ctx , cs , peer_fd ) ;
if ( ! msg )
peer_failed_connection_lost ( ) ;
* from_gossipd = false ;
return msg ;
}
bool is_peer_error ( const tal_t * ctx , const u8 * msg ,
const struct channel_id * channel_id ,
char * * desc , bool * all_channels )
{
struct channel_id err_chanid ;
if ( fromwire_peektype ( msg ) ! = WIRE_ERROR )
return false ;
* desc = sanitize_error ( ctx , msg , & err_chanid ) ;
/* BOLT #1:
*
* The channel is referred to by ` channel_id ` , unless ` channel_id ` is
* 0 ( i . e . all bytes are 0 ) , in which case it refers to all channels .
* . . .
* The receiving node :
* - upon receiving ` error ` :
* - MUST fail the channel referred to by the error message , if that
* channel is with the sending node .
* - if no existing channel is referred to by the message :
* - MUST ignore the message .
*/
* all_channels = channel_id_is_all ( & err_chanid ) ;
if ( ! * all_channels & & ! channel_id_eq ( & err_chanid , channel_id ) )
* desc = tal_free ( * desc ) ;
return true ;
}
bool is_wrong_channel ( const u8 * msg , const struct channel_id * expected ,
struct channel_id * actual )
{
if ( ! extract_channel_id ( msg , actual ) )
return false ;
return ! channel_id_eq ( expected , actual ) ;
}
void handle_gossip_msg_ ( const u8 * msg TAKES , int peer_fd ,
void handle_gossip_msg_ ( const u8 * msg TAKES , int peer_fd ,
struct crypto_state * cs ,
struct crypto_state * cs ,
bool ( * send_msg ) ( struct crypto_state * cs , int fd ,
bool ( * send_msg ) ( struct crypto_state * cs , int fd ,
@ -42,6 +113,53 @@ void handle_gossip_msg_(const u8 *msg TAKES, int peer_fd,
tal_free ( msg ) ;
tal_free ( msg ) ;
}
}
bool handle_peer_gossip_or_error ( int peer_fd , int gossip_fd ,
struct crypto_state * cs ,
const struct channel_id * channel_id ,
const u8 * msg TAKES )
{
char * err ;
bool all_channels ;
struct channel_id actual ;
if ( is_msg_for_gossipd ( msg ) ) {
wire_sync_write ( gossip_fd , msg ) ;
/* wire_sync_write takes, so don't take again. */
return true ;
}
if ( is_peer_error ( tmpctx , msg , channel_id , & err , & all_channels ) ) {
if ( err )
peer_failed_received_errmsg ( peer_fd , gossip_fd ,
cs , err ,
all_channels
? NULL : channel_id ) ;
/* Ignore unknown channel errors. */
goto handled ;
}
/* They're talking about a different channel? */
if ( is_wrong_channel ( msg , channel_id , & actual ) ) {
status_trace ( " Rejecting %s for unknown channel_id %s " ,
wire_type_name ( fromwire_peektype ( msg ) ) ,
type_to_string ( tmpctx , struct channel_id , & actual ) ) ;
if ( ! sync_crypto_write ( cs , peer_fd ,
take ( towire_errorfmt ( NULL , & actual ,
" Multiple channels "
" unsupported " ) ) ) )
peer_failed_connection_lost ( ) ;
goto handled ;
}
return false ;
handled :
if ( taken ( msg ) )
tal_free ( msg ) ;
return true ;
}
u8 * read_peer_msg_ ( const tal_t * ctx ,
u8 * read_peer_msg_ ( const tal_t * ctx ,
int peer_fd , int gossip_fd ,
int peer_fd , int gossip_fd ,
struct crypto_state * cs ,
struct crypto_state * cs ,
@ -51,73 +169,49 @@ u8 *read_peer_msg_(const tal_t *ctx,
void * arg )
void * arg )
{
{
u8 * msg ;
u8 * msg ;
struct channel_id chanid ;
bool from_gossipd , all_channels ;
fd_set readfds ;
struct channel_id actual ;
char * err ;
FD_ZERO ( & readfds ) ;
if ( gossip_fd > 0 ) {
FD_SET ( peer_fd , & readfds ) ;
msg = peer_or_gossip_sync_read ( ctx , peer_fd , gossip_fd ,
if ( gossip_fd > = 0 )
cs , & from_gossipd ) ;
FD_SET ( gossip_fd , & readfds ) ;
} else {
msg = sync_crypto_read ( ctx , cs , peer_fd ) ;
select ( peer_fd > gossip_fd ? peer_fd + 1 : gossip_fd + 1 ,
& readfds , NULL , NULL , NULL ) ;
if ( gossip_fd > = 0 & & FD_ISSET ( gossip_fd , & readfds ) ) {
msg = wire_sync_read ( NULL , gossip_fd ) ;
if ( ! msg )
if ( ! msg )
status_failed ( STATUS_FAIL_GOSSIP_IO ,
peer_failed_connection_lost ( ) ;
" Error reading gossip msg: %s " ,
from_gossipd = false ;
strerror ( errno ) ) ;
}
handle_gossip_msg_ ( msg , peer_fd , cs , send_reply , arg ) ;
if ( from_gossipd ) {
handle_gossip_msg_ ( take ( msg ) , peer_fd , cs , send_reply , arg ) ;
return NULL ;
return NULL ;
}
}
msg = sync_crypto_read ( ctx , cs , peer_fd ) ;
if ( ! msg )
peer_failed_connection_lost ( ) ;
if ( is_msg_for_gossipd ( msg ) ) {
if ( is_msg_for_gossipd ( msg ) ) {
/* Forward to gossip daemon */
/* Forward to gossip daemon */
wire_sync_write ( gossip_fd , take ( msg ) ) ;
wire_sync_write ( gossip_fd , take ( msg ) ) ;
return NULL ;
return NULL ;
}
}
if ( fromwire_peektype ( msg ) = = WIRE_ERROR ) {
if ( is_peer_error ( tmpctx , msg , channel , & err , & all_channels ) ) {
char * err = sanitize_error ( msg , msg , & chanid ) ;
if ( err )
/* BOLT #1:
*
* The channel is referred to by ` channel_id ` , unless
* ` channel_id ` is 0 ( i . e . all bytes are 0 ) , in which
* case it refers to all channels .
* . . .
* The receiving node :
* - upon receiving ` error ` :
* - MUST fail the channel referred to by the error
* message , if that channel is with the sending node .
* - if no existing channel is referred to by the
* message :
* - MUST ignore the message .
*/
if ( channel_id_eq ( & chanid , channel )
| | channel_id_is_all ( & chanid ) ) {
peer_failed_received_errmsg ( peer_fd , gossip_fd ,
peer_failed_received_errmsg ( peer_fd , gossip_fd ,
cs , err , & chanid ) ;
cs , err ,
}
all_channels
? NULL : channel ) ;
/* Ignore unknown channel errors. */
return tal_free ( msg ) ;
return tal_free ( msg ) ;
}
}
/* They're talking about a different channel? */
/* They're talking about a different channel? */
if ( extract_channel_id ( msg , & chanid )
if ( is_wrong_channel ( msg , channel , & actual ) ) {
& & ! channel_id_eq ( & chanid , channel ) ) {
status_trace ( " Rejecting %s for unknown channel_id %s " ,
status_trace ( " Rejecting %s for unknown channel_id %s " ,
wire_type_name ( fromwire_peektype ( msg ) ) ,
wire_type_name ( fromwire_peektype ( msg ) ) ,
type_to_string ( tmpctx , struct channel_id , & chanid ) ) ;
type_to_string ( tmpctx , struct channel_id , & actual ) ) ;
if ( ! send_reply ( cs , peer_fd ,
if ( ! send_reply ( cs , peer_fd ,
take ( towire_errorfmt ( NULL , & chanid ,
take ( towire_errorfmt ( NULL , & actual ,
" Multiple channels "
" Multiple channels "
" unsupported " ) ) ,
" unsupported " ) ) ,
arg ) )
arg ) )