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-08-05 05:04: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. At this moment
     155             :        FD_GOSSIP_UPDATE_MSG is missing the TVU_QUIC */
     156             : 
     157           0 :     if( FD_UNLIKELY( socket_tag >= FD_GOSSIP_UPDATE_MSG_NUM_SOCKETS ) ){
     158           0 :       FD_LOG_DEBUG(( "Unsupported socket tag in update msg %u", socket_tag ));
     159           0 :       continue;
     160           0 :     }
     161           0 :     if( FD_UNLIKELY( !fd_gossip_ip_addr_is_ip4( &ci_v2->addrs[ socket_entry->index ] ))){
     162             :       /* Skip non IPv4 entries */
     163           0 :       continue;
     164           0 :     }
     165             : 
     166           0 :     update->addrs[ socket_tag ].ip   = ci_v2->addrs[ socket_entry->index ].inner.ip4;
     167           0 :     update->addrs[ socket_tag ].port = cur_port ;
     168           0 :   }
     169           0 : }
     170             : 
     171             : int
     172             : fd_contact_info_get_socket_addr( fd_contact_info_t const *  ci_int,
     173             :                                  uchar                      socket_tag,
     174           0 :                                  fd_gossip_socket_addr_t *  out_addr ) {
     175           0 :   if( FD_UNLIKELY( socket_tag >= FD_GOSSIP_SOCKET_TAG_MAX ) ) {
     176           0 :     FD_LOG_ERR(( "Invalid socket tag %u", socket_tag ));
     177           0 :     return -1;
     178           0 :   }
     179           0 :   if( FD_UNLIKELY( ci_int->socket_tag_idx[ socket_tag ]==USHORT_MAX ) ) {
     180           0 :     FD_LOG_WARNING(( "Socket tag %u not found in contact info", socket_tag ));
     181           0 :     return -1;
     182           0 :   }
     183           0 :   ushort socket_idx = ci_int->socket_tag_idx[ socket_tag ];
     184           0 :   fd_gossip_socket_entry_t const * socket_entry = &ci_int->ci_crd.sockets[ socket_idx ];
     185           0 :   fd_gossip_ip_addr_t const * addr = &ci_int->ci_crd.addrs[ socket_entry->index ];
     186           0 :   ushort port = fd_ushort_bswap( ci_int->ports[ socket_idx ] );
     187             : 
     188           0 :   if( FD_LIKELY( fd_gossip_ip_addr_is_ip4( addr ) ) ) {
     189           0 :     fd_gossip_socket_addr_new_disc( out_addr, fd_gossip_socket_addr_enum_ip4 );
     190           0 :     out_addr->inner.ip4.port = port;
     191           0 :     out_addr->inner.ip4.addr = addr->inner.ip4;
     192           0 :   } else {
     193           0 :     fd_gossip_socket_addr_new_disc( out_addr, fd_gossip_socket_addr_enum_ip6 );
     194           0 :     out_addr->inner.ip6.port = port;
     195           0 :     out_addr->inner.ip6.addr = addr->inner.ip6;
     196           0 :   }
     197             : 
     198           0 :   return 0;
     199             : 
     200           0 : }
     201             : 
     202             : static int
     203             : fd_contact_info_remove_socket( fd_contact_info_t *      ci_int,
     204           0 :                                ushort                   socket_tag ) {
     205           0 :   if( FD_UNLIKELY( socket_tag >= FD_GOSSIP_SOCKET_TAG_MAX ) ){
     206           0 :     FD_LOG_ERR(( "Invalid socket tag %u", socket_tag ));
     207           0 :   }
     208             : 
     209           0 :   if( FD_UNLIKELY( ci_int->socket_tag_idx[ socket_tag ]==USHORT_MAX ) ) {
     210           0 :     FD_LOG_WARNING(( "Socket tag %u not found in contact info", socket_tag ));
     211           0 :     return -1;
     212           0 :   }
     213             : 
     214           0 :   ushort socket_idx = ci_int->socket_tag_idx[ socket_tag ];
     215           0 :   ushort addr_idx = ci_int->ci_crd.sockets[ socket_idx ].index;
     216           0 :   memmove( &ci_int->ci_crd.sockets[ socket_idx ],
     217           0 :            &ci_int->ci_crd.sockets[ socket_idx+1 ],
     218           0 :            sizeof(fd_gossip_socket_entry_t)*(ulong)( ci_int->ci_crd.sockets_len - socket_idx - 1 ) );
     219           0 :   ci_int->ci_crd.sockets_len--;
     220             : 
     221             :   /* Remove addr idx if no longer in any socket entry */
     222           0 :   int addr_found = 0;
     223           0 :   for( ulong i = 0UL; i<ci_int->ci_crd.sockets_len; i++ ) {
     224           0 :     if( ci_int->ci_crd.sockets[ i ].index == addr_idx ){
     225           0 :       addr_found = 1;
     226           0 :       break;
     227           0 :     }
     228           0 :   }
     229             : 
     230           0 :   if( !addr_found ){
     231           0 :     memmove( &ci_int->ci_crd.addrs[ addr_idx ],
     232           0 :              &ci_int->ci_crd.addrs[ addr_idx+1 ],
     233           0 :              sizeof(fd_gossip_ip_addr_t)*(ulong)( ci_int->ci_crd.addrs_len - addr_idx - 1 ) );
     234           0 :     ci_int->ci_crd.addrs_len--;
     235           0 :   }
     236             : 
     237           0 :   refresh_metadata( ci_int );
     238             : 
     239           0 :   return 0;
     240           0 : }
     241             : 
     242             : int
     243             : fd_contact_info_insert_socket( fd_contact_info_t *            ci_int,
     244             :                                fd_gossip_peer_addr_t const *  peer,
     245           0 :                                uchar                          socket_tag ) {
     246           0 :   if( FD_UNLIKELY( socket_tag >= FD_GOSSIP_SOCKET_TAG_MAX ) ) {
     247           0 :     FD_LOG_ERR(( "Invalid socket tag %u", socket_tag ));
     248           0 :   }
     249             : 
     250           0 :   if( FD_UNLIKELY( ci_int->socket_tag_idx[ socket_tag ]!=FD_CONTACT_INFO_SOCKET_TAG_NULL ) ) {
     251           0 :     FD_LOG_NOTICE(( "Overwriting socket tag %u", socket_tag ));
     252           0 :     fd_contact_info_remove_socket( ci_int, socket_tag );
     253           0 :   }
     254             : 
     255           0 :   ushort new_port = fd_ushort_bswap( peer->port );
     256           0 :   fd_gossip_socket_entry_t new_socket_entry;
     257           0 :   new_socket_entry.key = socket_tag;
     258             : 
     259             :   /* Find idx to insert in */
     260           0 :   ushort insert_idx = 0;
     261           0 :   ushort cur_port = 0U;
     262           0 :   for( ; insert_idx<ci_int->ci_crd.sockets_len; insert_idx++ ) {
     263           0 :     fd_gossip_socket_entry_t const * socket_entry = &ci_int->sockets[ insert_idx ];
     264           0 :     if( FD_LIKELY( cur_port + socket_entry->offset > new_port ) ) {
     265           0 :       break;
     266           0 :     }
     267           0 :     cur_port = (ushort)( cur_port + socket_entry->offset );
     268           0 :   }
     269             : 
     270           0 :   new_socket_entry.offset = (ushort)( new_port - cur_port );
     271             : 
     272             :   /* Update the offset for the entry currently in insert_idx */
     273           0 :   ci_int->sockets[ insert_idx ].offset = (ushort)( ci_int->sockets[ insert_idx ].offset - new_socket_entry.offset );
     274             : 
     275             :   /* Shift all entries starting from insert_idx down */
     276           0 :   memmove( &ci_int->sockets[ insert_idx+1 ],
     277           0 :            &ci_int->sockets[ insert_idx ],
     278           0 :            sizeof(fd_gossip_socket_entry_t)*(ulong)( ci_int->ci_crd.sockets_len - insert_idx ) );
     279           0 :   ci_int->ci_crd.sockets_len++;
     280             : 
     281             :   /* Find addr idx */
     282           0 :   uchar addr_idx = 0U;
     283           0 :   for( ; addr_idx<ci_int->ci_crd.addrs_len; addr_idx++ ) {
     284           0 :     if( FD_LIKELY( ci_int->ci_crd.addrs[ addr_idx ].inner.ip4==peer->addr ) ) {
     285           0 :       break;
     286           0 :     }
     287           0 :   }
     288             : 
     289           0 :   if(  FD_UNLIKELY( addr_idx==ci_int->ci_crd.addrs_len ) ) {
     290           0 :     FD_LOG_INFO(( "Adding new addr %u", peer->addr ) );
     291           0 :     fd_gossip_ip_addr_new_disc( &ci_int->ci_crd.addrs[ addr_idx ], fd_gossip_ip_addr_enum_ip4 );
     292           0 :     ci_int->ci_crd.addrs[ addr_idx ].inner.ip4 = peer->addr;
     293           0 :     ci_int->ci_crd.addrs_len++;
     294           0 :   }
     295             : 
     296           0 :   new_socket_entry.index = addr_idx;
     297           0 :   ci_int->ci_crd.sockets[ insert_idx ] = new_socket_entry;
     298             : 
     299             :   /* Refresh metadata */
     300           0 :   refresh_metadata( ci_int );
     301           0 :   return 0;
     302           0 : }
     303             : 
     304             : int
     305             : fd_gossip_contact_info_v2_find_proto_ident( fd_gossip_contact_info_v2_t const * contact_info,
     306             :                                             uchar                               proto_ident,
     307           0 :                                             fd_gossip_socket_addr_t *           out_addr ) {
     308           0 :   ushort port = 0;
     309           0 :   for( ulong i = 0UL; i<contact_info->sockets_len; i++ ) {
     310           0 :     fd_gossip_socket_entry_t const * socket_entry = &contact_info->sockets[ i ];
     311           0 :     port = (ushort)( port + socket_entry->offset );
     312           0 :     if( socket_entry->key==proto_ident ) {
     313           0 :       if( socket_entry->index>=contact_info->addrs_len) {
     314           0 :         continue;
     315           0 :       }
     316             : 
     317             :       /* fd_gossip_socket_addr->inner and fd_gossip_ip_addr
     318             :          are slightly different, so we can't just
     319             :          out_addr->ip = contact_info->addrs[ idx ] */
     320           0 :       fd_gossip_ip_addr_t * tmp = &contact_info->addrs[ socket_entry->index ];
     321           0 :       if( FD_LIKELY( tmp->discriminant == fd_gossip_ip_addr_enum_ip4 ) ) {
     322           0 :         out_addr->discriminant = fd_gossip_socket_addr_enum_ip4;
     323           0 :         out_addr->inner.ip4.addr = tmp->inner.ip4;
     324           0 :         out_addr->inner.ip4.port = port;
     325           0 :       } else {
     326           0 :         out_addr->discriminant = fd_gossip_socket_addr_enum_ip6;
     327           0 :         out_addr->inner.ip6.addr = tmp->inner.ip6;
     328           0 :         out_addr->inner.ip6.port = port;
     329           0 :       }
     330           0 :       return 1;
     331           0 :     }
     332           0 :   }
     333             : 
     334           0 :   return 0;
     335           0 : }

Generated by: LCOV version 1.14