LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_contact_info.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 233 0.0 %
Date: 2025-07-01 05:00:49 Functions: 0 12 0.0 %

          Line data    Source code
       1             : #include "fd_contact_info.h"
       2             : #include <string.h>
       3             : 
       4             : static void
       5           0 : reset_socket_tag_idx( ushort * socket_tag_idx ) {
       6           0 :   for( ulong i = 0UL; i<FD_GOSSIP_SOCKET_TAG_MAX; i++ ) {
       7           0 :     socket_tag_idx[ i ] = USHORT_MAX;
       8           0 :   }
       9           0 : }
      10             : 
      11             : static void
      12           0 : refresh_metadata( fd_contact_info_t * ci_int ) {
      13           0 :   ushort cur_port = 0U;
      14           0 :   reset_socket_tag_idx( ci_int->socket_tag_idx );
      15           0 :   for( ushort i = 0UL; i<ci_int->ci_crd.sockets_len; i++ ) {
      16           0 :     cur_port = (ushort)( cur_port + ci_int->sockets[ i ].offset );
      17             : 
      18           0 :     ci_int->socket_tag_idx[ ci_int->sockets[ i ].key ] = i;
      19           0 :     ci_int->ports[ i ] = cur_port;
      20           0 :   }
      21           0 : }
      22             : 
      23             : ushort
      24           0 : fd_contact_info_get_shred_version( fd_contact_info_t const * contact_info ) {
      25           0 :   return contact_info->ci_crd.shred_version;
      26           0 : }
      27             : 
      28             : void
      29             : fd_contact_info_set_shred_version( fd_contact_info_t * contact_info,
      30           0 :                                    ushort              shred_version ) {
      31           0 :   contact_info->ci_crd.shred_version = shred_version;
      32           0 : }
      33             : 
      34             : 
      35             : void
      36           0 : fd_contact_info_init( fd_contact_info_t * contact_info ) {
      37           0 :   memset( contact_info, 0, sizeof(fd_contact_info_t) );
      38             : 
      39           0 :   contact_info->ci_crd.addrs    = contact_info->addrs;
      40           0 :   contact_info->ci_crd.sockets  = contact_info->sockets;
      41             : 
      42           0 :   reset_socket_tag_idx( contact_info->socket_tag_idx );
      43           0 : }
      44             : 
      45             : void
      46             : fd_contact_info_from_ci_v2( fd_gossip_contact_info_v2_t const * ci_v2,
      47           0 :                             fd_contact_info_t *                 contact_info ) {
      48           0 :   fd_gossip_contact_info_v2_t * ci_int = &contact_info->ci_crd;
      49           0 :   *ci_int = *ci_v2;
      50             : 
      51           0 :   ci_int->addrs           = contact_info->addrs;
      52           0 :   ci_int->addrs_len       = 0U;
      53           0 :   ci_int->sockets         = contact_info->sockets;
      54           0 :   ci_int->sockets_len     = 0U;
      55           0 :   ci_int->extensions      = NULL; /* unsupported */
      56           0 :   ci_int->extensions_len  = 0U;   /* unsupported */
      57             : 
      58           0 :   reset_socket_tag_idx( contact_info->socket_tag_idx );
      59             : 
      60             : 
      61             :   /* For sockets, validate individual entries and keep track of offsets */
      62           0 :   ushort cur_offset = 0U;
      63           0 :   ushort cur_port   = 0U;
      64           0 :   for( ulong i = 0UL; i<ci_v2->sockets_len; i++ ) {
      65           0 :     fd_gossip_socket_entry_t const * socket_entry = &ci_v2->sockets[ i ];
      66           0 :     cur_offset = (ushort)( cur_offset + socket_entry->offset );
      67           0 :     cur_port   = (ushort)( cur_port   + socket_entry->offset );
      68             : 
      69           0 :     if( FD_UNLIKELY( socket_entry->key >= FD_GOSSIP_SOCKET_TAG_MAX ) ){
      70             :       /* We seem to receive quite a few of these in testnet, so commented out logging
      71             :          TODO: Check with Anza about why this is the case */
      72             :       // FD_LOG_WARNING(( "Invalid socket entry key %u", socket_entry->key ));
      73           0 :       continue;
      74           0 :     }
      75             : 
      76           0 :     if( FD_UNLIKELY( contact_info->socket_tag_idx[ socket_entry->key ]!=USHORT_MAX ) ){
      77           0 :       FD_LOG_WARNING(( "Duplicate socket tag %u", socket_entry->key ));
      78           0 :       continue;
      79           0 :     }
      80             : 
      81             :     /* Find addr index
      82             :        TODO: can avoid nested for loop with a simple mapping of (ci_v2 addr_idx, ci_int addr_idx) */
      83           0 :     uchar addr_index = UCHAR_MAX;
      84           0 :     for( ulong j = 0UL; j < ci_int->addrs_len; j++ ) {
      85           0 :       if( FD_LIKELY( memcmp(&ci_int->addrs[j], &ci_v2->addrs[socket_entry->index], sizeof(fd_gossip_ip_addr_t)) == 0 ) ) {
      86           0 :         addr_index = (uchar)j;
      87           0 :         break;
      88           0 :       }
      89           0 :     }
      90             : 
      91             :     /* Add entry to end of addrs if does not exist */
      92           0 :     if( FD_UNLIKELY( addr_index == UCHAR_MAX ) ) {
      93           0 :       if( FD_UNLIKELY( socket_entry->index >= ci_v2->addrs_len ) ) {
      94           0 :         FD_LOG_WARNING(( "addr index %u out of bounds for addrs_len %u", socket_entry->index, ci_v2->addrs_len ));
      95           0 :         continue;
      96           0 :       }
      97           0 :       if( FD_UNLIKELY( ci_int->addrs_len >= FD_GOSSIP_SOCKET_TAG_MAX ) ) {
      98           0 :         FD_LOG_ERR(( "Too many unique addresses (%u) in contact info, possible broken implementation of fd_contact_info_from_ci_v2", ci_int->addrs_len ));
      99           0 :         continue;
     100           0 :       }
     101           0 :       ci_int->addrs[ ci_int->addrs_len ] = ci_v2->addrs[ socket_entry->index ];
     102           0 :       addr_index = (uchar)ci_int->addrs_len;
     103           0 :       ci_int->addrs_len++;
     104           0 :     }
     105             : 
     106           0 :     ci_int->sockets[ ci_int->sockets_len ].index            = addr_index;
     107           0 :     ci_int->sockets[ ci_int->sockets_len ].key              = socket_entry->key;
     108           0 :     ci_int->sockets[ ci_int->sockets_len ].offset           = cur_offset;
     109             : 
     110             :     /* Metadata updates */
     111           0 :     contact_info->socket_tag_idx[ socket_entry->key ]       = ci_int->sockets_len;
     112           0 :     contact_info->ports[ ci_int->sockets_len ]              = cur_port;
     113             : 
     114           0 :     ci_int->sockets_len++;
     115           0 :     cur_offset = 0U;
     116           0 :   }
     117             : 
     118           0 :   if( FD_UNLIKELY( ci_int->sockets_len > FD_GOSSIP_SOCKET_TAG_MAX ) ){
     119           0 :     FD_LOG_ERR(( "Too many sockets (%u) in contact info, possible broken implementation of fd_contact_info_from_ci_v2", ci_int->sockets_len ));
     120           0 :   }
     121           0 : }
     122             : 
     123             : void
     124             : fd_contact_info_to_ci_v2( fd_contact_info_t const *     ci_int,
     125           0 :                           fd_gossip_contact_info_v2_t * ci_v2 ){
     126           0 :   *ci_v2 = ci_int->ci_crd;
     127           0 : }
     128             : 
     129             : void
     130             : fd_contact_info_to_update_msg( fd_contact_info_t const * contact_info,
     131           0 :                                fd_gossip_update_msg_t *  update ) {
     132           0 :   fd_gossip_contact_info_v2_t const * ci_v2 = &contact_info->ci_crd;
     133           0 :   fd_memcpy( update->pubkey, &ci_v2->from, sizeof(fd_pubkey_t) );
     134             : 
     135           0 :   update->wallclock           = ci_v2->wallclock;
     136           0 :   update->shred_version       = ci_v2->shred_version;
     137           0 :   update->version_major       = ci_v2->version.major;
     138           0 :   update->version_minor       = ci_v2->version.minor;
     139           0 :   update->version_patch       = ci_v2->version.patch;
     140           0 :   update->version_commit      = ci_v2->version.commit;
     141           0 :   update->version_feature_set = ci_v2->version.feature_set;
     142             : 
     143             :   /* TODO: missing version_commit_type and version_type */
     144           0 :   update->version_commit_type = 0U;
     145           0 :   update->version_type        = 0U;
     146             : 
     147           0 :   ushort cur_port = 0U;
     148           0 :   for( ulong i = 0UL; i<FD_GOSSIP_SOCKET_TAG_MAX; i++ ) {
     149           0 :     fd_gossip_socket_entry_t const * socket_entry = &ci_v2->sockets[ i ];
     150           0 :     cur_port = (ushort)( cur_port + socket_entry->offset );
     151           0 :     ushort socket_tag = socket_entry->key;
     152             : 
     153             :     /* NOTE: We use FD_GOSSIP_UPDATE_MSG_NUM_SOCKETS instead of FD_GOSSIP_SOCKET_TAG_MAX
     154             :        since they aren't strictly the same. */
     155             : 
     156           0 :     if( FD_UNLIKELY( socket_tag >= FD_GOSSIP_UPDATE_MSG_NUM_SOCKETS ) ){
     157           0 :       FD_LOG_WARNING(( "Unsupported socket tag in update msg %u", socket_tag ));
     158           0 :       continue;
     159           0 :     }
     160           0 :     if( FD_UNLIKELY( !fd_gossip_ip_addr_is_ip4( &ci_v2->addrs[ socket_entry->index ] ))){
     161             :       /* Skip non IPv4 entries */
     162           0 :       continue;
     163           0 :     }
     164             : 
     165           0 :     update->addrs[ socket_tag ].ip   = ci_v2->addrs[ socket_entry->index ].inner.ip4;
     166           0 :     update->addrs[ socket_tag ].port = cur_port ;
     167           0 :   }
     168           0 : }
     169             : 
     170             : int
     171             : fd_contact_info_get_socket_addr( fd_contact_info_t const *  ci_int,
     172             :                                  uchar                      socket_tag,
     173           0 :                                  fd_gossip_socket_addr_t *  out_addr ) {
     174           0 :   if( FD_UNLIKELY( socket_tag >= FD_GOSSIP_SOCKET_TAG_MAX ) ) {
     175           0 :     FD_LOG_ERR(( "Invalid socket tag %u", socket_tag ));
     176           0 :     return -1;
     177           0 :   }
     178           0 :   if( FD_UNLIKELY( ci_int->socket_tag_idx[ socket_tag ]==USHORT_MAX ) ) {
     179           0 :     FD_LOG_WARNING(( "Socket tag %u not found in contact info", socket_tag ));
     180           0 :     return -1;
     181           0 :   }
     182           0 :   ushort socket_idx = ci_int->socket_tag_idx[ socket_tag ];
     183           0 :   fd_gossip_socket_entry_t const * socket_entry = &ci_int->ci_crd.sockets[ socket_idx ];
     184           0 :   fd_gossip_ip_addr_t const * addr = &ci_int->ci_crd.addrs[ socket_entry->index ];
     185           0 :   ushort port = fd_ushort_bswap( ci_int->ports[ socket_idx ] );
     186             : 
     187           0 :   if( FD_LIKELY( fd_gossip_ip_addr_is_ip4( addr ) ) ) {
     188           0 :     fd_gossip_socket_addr_new_disc( out_addr, fd_gossip_socket_addr_enum_ip4 );
     189           0 :     out_addr->inner.ip4.port = port;
     190           0 :     out_addr->inner.ip4.addr = addr->inner.ip4;
     191           0 :   } else {
     192           0 :     fd_gossip_socket_addr_new_disc( out_addr, fd_gossip_socket_addr_enum_ip6 );
     193           0 :     out_addr->inner.ip6.port = port;
     194           0 :     out_addr->inner.ip6.addr = addr->inner.ip6;
     195           0 :   }
     196             : 
     197           0 :   return 0;
     198             : 
     199           0 : }
     200             : 
     201             : static int
     202             : fd_contact_info_remove_socket( fd_contact_info_t *      ci_int,
     203           0 :                                ushort                   socket_tag ) {
     204           0 :   if( FD_UNLIKELY( socket_tag >= FD_GOSSIP_SOCKET_TAG_MAX ) ){
     205           0 :     FD_LOG_ERR(( "Invalid socket tag %u", socket_tag ));
     206           0 :   }
     207             : 
     208           0 :   if( FD_UNLIKELY( ci_int->socket_tag_idx[ socket_tag ]==USHORT_MAX ) ) {
     209           0 :     FD_LOG_WARNING(( "Socket tag %u not found in contact info", socket_tag ));
     210           0 :     return -1;
     211           0 :   }
     212             : 
     213           0 :   ushort socket_idx = ci_int->socket_tag_idx[ socket_tag ];
     214           0 :   ushort addr_idx = ci_int->ci_crd.sockets[ socket_idx ].index;
     215           0 :   memmove( &ci_int->ci_crd.sockets[ socket_idx ],
     216           0 :            &ci_int->ci_crd.sockets[ socket_idx+1 ],
     217           0 :            sizeof(fd_gossip_socket_entry_t)*(ulong)( ci_int->ci_crd.sockets_len - socket_idx - 1 ) );
     218           0 :   ci_int->ci_crd.sockets_len--;
     219             : 
     220             :   /* Remove addr idx if no longer in any socket entry */
     221           0 :   int addr_found = 0;
     222           0 :   for( ulong i = 0UL; i<ci_int->ci_crd.sockets_len; i++ ) {
     223           0 :     if( ci_int->ci_crd.sockets[ i ].index == addr_idx ){
     224           0 :       addr_found = 1;
     225           0 :       break;
     226           0 :     }
     227           0 :   }
     228             : 
     229           0 :   if( !addr_found ){
     230           0 :     memmove( &ci_int->ci_crd.addrs[ addr_idx ],
     231           0 :              &ci_int->ci_crd.addrs[ addr_idx+1 ],
     232           0 :              sizeof(fd_gossip_ip_addr_t)*(ulong)( ci_int->ci_crd.addrs_len - addr_idx - 1 ) );
     233           0 :     ci_int->ci_crd.addrs_len--;
     234           0 :   }
     235             : 
     236           0 :   refresh_metadata( ci_int );
     237             : 
     238           0 :   return 0;
     239           0 : }
     240             : 
     241             : int
     242             : fd_contact_info_insert_socket( fd_contact_info_t *            ci_int,
     243             :                                fd_gossip_peer_addr_t const *  peer,
     244           0 :                                uchar                          socket_tag ) {
     245           0 :   if( FD_UNLIKELY( socket_tag >= FD_GOSSIP_SOCKET_TAG_MAX ) ) {
     246           0 :     FD_LOG_ERR(( "Invalid socket tag %u", socket_tag ));
     247           0 :   }
     248             : 
     249           0 :   if( FD_UNLIKELY( ci_int->socket_tag_idx[ socket_tag ]!=FD_CONTACT_INFO_SOCKET_TAG_NULL ) ) {
     250           0 :     FD_LOG_NOTICE(( "Overwriting socket tag %u", socket_tag ));
     251           0 :     fd_contact_info_remove_socket( ci_int, socket_tag );
     252           0 :   }
     253             : 
     254           0 :   ushort new_port = fd_ushort_bswap( peer->port );
     255           0 :   fd_gossip_socket_entry_t new_socket_entry;
     256           0 :   new_socket_entry.key = socket_tag;
     257             : 
     258             :   /* Find idx to insert in */
     259           0 :   ushort insert_idx = 0;
     260           0 :   ushort cur_port = 0U;
     261           0 :   for( ; insert_idx<ci_int->ci_crd.sockets_len; insert_idx++ ) {
     262           0 :     fd_gossip_socket_entry_t const * socket_entry = &ci_int->sockets[ insert_idx ];
     263           0 :     if( FD_LIKELY( cur_port + socket_entry->offset > new_port ) ) {
     264           0 :       break;
     265           0 :     }
     266           0 :     cur_port = (ushort)( cur_port + socket_entry->offset );
     267           0 :   }
     268             : 
     269           0 :   new_socket_entry.offset = (ushort)( new_port - cur_port );
     270             : 
     271             :   /* Update the offset for the entry currently in insert_idx */
     272           0 :   ci_int->sockets[ insert_idx ].offset = (ushort)( ci_int->sockets[ insert_idx ].offset - new_socket_entry.offset );
     273             : 
     274             :   /* Shift all entries starting from insert_idx down */
     275           0 :   memmove( &ci_int->sockets[ insert_idx+1 ],
     276           0 :            &ci_int->sockets[ insert_idx ],
     277           0 :            sizeof(fd_gossip_socket_entry_t)*(ulong)( ci_int->ci_crd.sockets_len - insert_idx ) );
     278           0 :   ci_int->ci_crd.sockets_len++;
     279             : 
     280             :   /* Find addr idx */
     281           0 :   uchar addr_idx = 0U;
     282           0 :   for( ; addr_idx<ci_int->ci_crd.addrs_len; addr_idx++ ) {
     283           0 :     if( FD_LIKELY( ci_int->ci_crd.addrs[ addr_idx ].inner.ip4==peer->addr ) ) {
     284           0 :       break;
     285           0 :     }
     286           0 :   }
     287             : 
     288           0 :   if(  FD_UNLIKELY( addr_idx==ci_int->ci_crd.addrs_len ) ) {
     289           0 :     FD_LOG_INFO(( "Adding new addr %u", peer->addr ) );
     290           0 :     fd_gossip_ip_addr_new_disc( &ci_int->ci_crd.addrs[ addr_idx ], fd_gossip_ip_addr_enum_ip4 );
     291           0 :     ci_int->ci_crd.addrs[ addr_idx ].inner.ip4 = peer->addr;
     292           0 :     ci_int->ci_crd.addrs_len++;
     293           0 :   }
     294             : 
     295           0 :   new_socket_entry.index = addr_idx;
     296           0 :   ci_int->ci_crd.sockets[ insert_idx ] = new_socket_entry;
     297             : 
     298             :   /* Refresh metadata */
     299           0 :   refresh_metadata( ci_int );
     300           0 :   return 0;
     301           0 : }
     302             : 
     303             : int
     304             : fd_gossip_contact_info_v2_find_proto_ident( fd_gossip_contact_info_v2_t const * contact_info,
     305             :                                             uchar                               proto_ident,
     306           0 :                                             fd_gossip_socket_addr_t *           out_addr ) {
     307           0 :   ushort port = 0;
     308           0 :   for( ulong i = 0UL; i<contact_info->sockets_len; i++ ) {
     309           0 :     fd_gossip_socket_entry_t const * socket_entry = &contact_info->sockets[ i ];
     310           0 :     port = (ushort)( port + socket_entry->offset );
     311           0 :     if( socket_entry->key==proto_ident ) {
     312           0 :       if( socket_entry->index>=contact_info->addrs_len) {
     313           0 :         continue;
     314           0 :       }
     315             : 
     316             :       /* fd_gossip_socket_addr->inner and fd_gossip_ip_addr
     317             :          are slightly different, so we can't just
     318             :          out_addr->ip = contact_info->addrs[ idx ] */
     319           0 :       fd_gossip_ip_addr_t * tmp = &contact_info->addrs[ socket_entry->index ];
     320           0 :       if( FD_LIKELY( tmp->discriminant == fd_gossip_ip_addr_enum_ip4 ) ) {
     321           0 :         out_addr->discriminant = fd_gossip_socket_addr_enum_ip4;
     322           0 :         out_addr->inner.ip4.addr = tmp->inner.ip4;
     323           0 :         out_addr->inner.ip4.port = port;
     324           0 :       } else {
     325           0 :         out_addr->discriminant = fd_gossip_socket_addr_enum_ip6;
     326           0 :         out_addr->inner.ip6.addr = tmp->inner.ip6;
     327           0 :         out_addr->inner.ip6.port = port;
     328           0 :       }
     329           0 :       return 1;
     330           0 :     }
     331           0 :   }
     332             : 
     333           0 :   return 0;
     334           0 : }

Generated by: LCOV version 1.14