LCOV - code coverage report
Current view: top level - discof/restore/utils - fd_ssresolve.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 207 0.0 %
Date: 2025-10-13 04:42:14 Functions: 0 12 0.0 %

          Line data    Source code
       1             : #include "fd_ssresolve.h"
       2             : #include "fd_ssarchive.h"
       3             : 
       4             : #include "../../../waltz/http/picohttpparser.h"
       5             : #include "../../../util/log/fd_log.h"
       6             : 
       7             : #include <unistd.h>
       8             : #include <errno.h>
       9             : #include <stdlib.h>
      10             : #include <strings.h>
      11             : 
      12             : #include <sys/socket.h>
      13             : #include <netinet/tcp.h>
      14             : #include <netinet/in.h>
      15             : 
      16           0 : #define FD_SSRESOLVE_STATE_REQ  (0) /* sending request for snapshot */
      17           0 : #define FD_SSRESOLVE_STATE_RESP (1) /* receiving snapshot response */
      18           0 : #define FD_SSRESOLVE_STATE_DONE (2) /* done */
      19             : 
      20             : struct fd_ssresolve_private {
      21             :   int  state;
      22             :   long deadline;
      23             : 
      24             :   fd_ip4_port_t addr;
      25             :   int           sockfd;
      26             :   int           full;
      27             : 
      28             :   char  request[ 4096UL ];
      29             :   ulong request_sent;
      30             :   ulong request_len;
      31             : 
      32             :   ulong response_len;
      33             :   char  response[ USHORT_MAX ];
      34             : 
      35             :   ulong magic;
      36             : };
      37             : 
      38             : FD_FN_CONST ulong
      39           0 : fd_ssresolve_align( void ) {
      40           0 :   return FD_SSRESOLVE_ALIGN;
      41           0 : }
      42             : 
      43             : FD_FN_CONST ulong
      44           0 : fd_ssresolve_footprint( void ) {
      45           0 :   ulong l;
      46           0 :   l = FD_LAYOUT_INIT;
      47           0 :   l = FD_LAYOUT_APPEND( l, FD_SSRESOLVE_ALIGN, sizeof(fd_ssresolve_t) );
      48           0 :   return FD_LAYOUT_FINI( l, FD_SSRESOLVE_ALIGN );
      49           0 : }
      50             : 
      51             : void *
      52           0 : fd_ssresolve_new( void * shmem ) {
      53           0 :   if( FD_UNLIKELY( !shmem ) ) {
      54           0 :     FD_LOG_WARNING(( "NULL shmem" ));
      55           0 :     return NULL;
      56           0 :   }
      57             : 
      58           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_ssresolve_align() ) ) ) {
      59           0 :     FD_LOG_WARNING(( "unaligned shmem" ));
      60           0 :     return NULL;
      61           0 :   }
      62             : 
      63           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      64           0 :   fd_ssresolve_t * ssresolve = FD_SCRATCH_ALLOC_APPEND( l, FD_SSRESOLVE_ALIGN, sizeof(fd_ssresolve_t) );
      65             : 
      66           0 :   ssresolve->state        = FD_SSRESOLVE_STATE_REQ;
      67           0 :   ssresolve->request_sent = 0UL;
      68           0 :   ssresolve->request_len  = 0UL;
      69           0 :   ssresolve->response_len = 0UL;
      70             : 
      71           0 :   FD_COMPILER_MFENCE();
      72           0 :   FD_VOLATILE( ssresolve->magic ) = FD_SSRESOLVE_MAGIC;
      73           0 :   FD_COMPILER_MFENCE();
      74             : 
      75           0 :   return (void *)ssresolve;
      76           0 : }
      77             : 
      78             : fd_ssresolve_t *
      79           0 : fd_ssresolve_join( void * _ssresolve ) {
      80           0 :   if( FD_UNLIKELY( !_ssresolve ) ) {
      81           0 :     FD_LOG_WARNING(( "NULL ssresolve" ));
      82           0 :     return NULL;
      83           0 :   }
      84             : 
      85           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)_ssresolve, fd_ssresolve_align() ) ) ) {
      86           0 :     FD_LOG_WARNING(( "misaligned ssresolve" ));
      87           0 :     return NULL;
      88           0 :   }
      89             : 
      90           0 :   fd_ssresolve_t * ssresolve = (fd_ssresolve_t *)_ssresolve;
      91             : 
      92           0 :   if( FD_UNLIKELY( ssresolve->magic!=FD_SSRESOLVE_MAGIC ) ) {
      93           0 :     FD_LOG_WARNING(( "bad magic" ));
      94           0 :     return NULL;
      95           0 :   }
      96             : 
      97           0 :   return ssresolve;
      98           0 : }
      99             : 
     100             : void
     101             : fd_ssresolve_init( fd_ssresolve_t * ssresolve,
     102             :                    fd_ip4_port_t    addr,
     103             :                    int              sockfd,
     104           0 :                    int              full ) {
     105           0 :   ssresolve->addr   = addr;
     106           0 :   ssresolve->sockfd = sockfd;
     107           0 :   ssresolve->full   = full;
     108             : 
     109           0 :   ssresolve->state        = FD_SSRESOLVE_STATE_REQ;
     110           0 :   ssresolve->request_sent = 0UL;
     111           0 :   ssresolve->request_len  = 0UL;
     112           0 :   ssresolve->response_len = 0UL;
     113           0 : }
     114             : 
     115             : static void
     116             : fd_ssresolve_render_req( fd_ssresolve_t * ssresolve,
     117           0 :                          fd_ip4_port_t    addr ) {
     118           0 :   if( FD_LIKELY( ssresolve->full ) ) {
     119           0 :     FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
     120           0 :              "GET /snapshot.tar.bz2 HTTP/1.1\r\n"
     121           0 :              "User-Agent: Firedancer\r\n"
     122           0 :              "Accept: */*\r\n"
     123           0 :              "Accept-Encoding: identity\r\n"
     124           0 :              "Host: " FD_IP4_ADDR_FMT "\r\n\r\n",
     125           0 :              FD_IP4_ADDR_FMT_ARGS( addr.addr ) ) );
     126           0 :   } else {
     127           0 :     FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
     128           0 :              "GET /incremental-snapshot.tar.bz2 HTTP/1.1\r\n"
     129           0 :              "User-Agent: Firedancer\r\n"
     130           0 :              "Accept: */*\r\n"
     131           0 :              "Accept-Encoding: identity\r\n"
     132           0 :              "Host: " FD_IP4_ADDR_FMT "\r\n\r\n",
     133           0 :              FD_IP4_ADDR_FMT_ARGS( addr.addr ) ) );
     134           0 :   }
     135           0 : }
     136             : 
     137             : static int
     138           0 : fd_ssresolve_send_request( fd_ssresolve_t * ssresolve ) {
     139           0 :   FD_TEST( ssresolve->state==FD_SSRESOLVE_STATE_REQ );
     140             : 
     141           0 :   if( FD_UNLIKELY( !ssresolve->request_len ) ) {
     142           0 :     fd_ssresolve_render_req( ssresolve, ssresolve->addr );
     143           0 :   }
     144             : 
     145           0 :   long sent = sendto( ssresolve->sockfd, ssresolve->request+ssresolve->request_sent, ssresolve->request_len-ssresolve->request_sent, 0, NULL, 0 );
     146           0 :   if( FD_UNLIKELY( -1==sent && errno==EAGAIN ) ) return FD_SSRESOLVE_ADVANCE_AGAIN;
     147           0 :   else if( FD_UNLIKELY( -1==sent ) ) {
     148           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     149           0 :   }
     150             : 
     151           0 :   ssresolve->request_sent += (ulong)sent;
     152           0 :   if( FD_UNLIKELY( ssresolve->request_sent==ssresolve->request_len ) ) {
     153           0 :     ssresolve->state = FD_SSRESOLVE_STATE_RESP;
     154           0 :     return FD_SSRESOLVE_ADVANCE_SUCCESS;
     155           0 :   }
     156             : 
     157           0 :   return FD_SSRESOLVE_ADVANCE_AGAIN;
     158           0 : }
     159             : 
     160             : static int
     161             : fd_ssresolve_parse_redirect( fd_ssresolve_t *        ssresolve,
     162             :                              struct phr_header *     headers,
     163             :                              ulong                   header_cnt,
     164           0 :                              fd_ssresolve_result_t * result ) {
     165           0 :   ulong        location_len = 0UL;
     166           0 :   char const * location     = NULL;
     167             : 
     168           0 :   for( ulong i=0UL; i<header_cnt; i++ ) {
     169           0 :     if( FD_UNLIKELY( !strncasecmp( headers[ i ].name, "location", headers[ i ].name_len ) ) ) {
     170           0 :       if( FD_UNLIKELY( !headers [ i ].value_len || headers[ i ].value[ 0 ]!='/' ) ) {
     171           0 :         FD_LOG_WARNING(( "invalid location header `%.*s`", (int)headers[ i ].value_len, headers[ i ].value ));
     172           0 :         return FD_SSRESOLVE_ADVANCE_ERROR;
     173           0 :       }
     174             : 
     175           0 :       location_len = headers[ i ].value_len;
     176           0 :       location = headers[ i ].value;
     177           0 :       break;
     178           0 :     }
     179           0 :   }
     180             : 
     181           0 :   if( FD_UNLIKELY( location_len>=PATH_MAX-1UL ) ) return FD_SSRESOLVE_ADVANCE_ERROR;
     182             : 
     183           0 :   char snapshot_name[ PATH_MAX ];
     184           0 :   fd_memcpy( snapshot_name, location+1UL, location_len-1UL );
     185           0 :   snapshot_name[ location_len-1UL ] = '\0';
     186             : 
     187           0 :   ulong full_entry_slot, incremental_entry_slot;
     188           0 :   uchar decoded_hash[ FD_HASH_FOOTPRINT ];
     189           0 :   int err = fd_ssarchive_parse_filename( snapshot_name, &full_entry_slot, &incremental_entry_slot, decoded_hash );
     190             : 
     191           0 :   if( FD_UNLIKELY( err ) ) {
     192           0 :     FD_LOG_WARNING(( "unrecognized snapshot file `%s` in redirect location header", snapshot_name ));
     193           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     194           0 :   }
     195             : 
     196           0 :   if( FD_LIKELY( incremental_entry_slot==ULONG_MAX ) ) {
     197           0 :     result->slot      = full_entry_slot;
     198           0 :     result->base_slot = ULONG_MAX;
     199           0 :   } else {
     200           0 :     result->slot      = incremental_entry_slot;
     201           0 :     result->base_slot = full_entry_slot;
     202           0 :   }
     203             : 
     204           0 :   ssresolve->state = FD_SSRESOLVE_STATE_DONE;
     205           0 :   return FD_SSRESOLVE_ADVANCE_SUCCESS;
     206           0 : }
     207             : 
     208             : static int
     209             : fd_ssresolve_read_response( fd_ssresolve_t *        ssresolve,
     210           0 :                             fd_ssresolve_result_t * result ) {
     211           0 :   FD_TEST( ssresolve->state==FD_SSRESOLVE_STATE_RESP );
     212           0 :   long read = recvfrom( ssresolve->sockfd, ssresolve->response+ssresolve->response_len, sizeof(ssresolve->response)-ssresolve->response_len, 0, NULL, NULL );
     213           0 :   if( FD_UNLIKELY( -1==read && errno==EAGAIN ) ) return FD_SSRESOLVE_ADVANCE_AGAIN;
     214           0 :   else if( FD_UNLIKELY( -1==read ) ) {
     215           0 :     FD_LOG_WARNING(( "recvfrom() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
     216           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     217           0 :   }
     218             : 
     219           0 :   ssresolve->response_len += (ulong)read;
     220             : 
     221           0 :   int               minor_version;
     222           0 :   int               status;
     223           0 :   const char *      message;
     224           0 :   ulong             message_len;
     225           0 :   struct phr_header headers[ 128UL ];
     226           0 :   ulong             header_cnt = 128UL;
     227           0 :   int parsed = phr_parse_response( ssresolve->response,
     228           0 :                                     ssresolve->response_len,
     229           0 :                                     &minor_version,
     230           0 :                                     &status,
     231           0 :                                     &message,
     232           0 :                                     &message_len,
     233           0 :                                     headers,
     234           0 :                                     &header_cnt,
     235           0 :                                     ssresolve->response_len - (ulong)read );
     236           0 :   if( FD_UNLIKELY( parsed==-1 ) ) {
     237           0 :     FD_LOG_WARNING(( "malformed response body" ));
     238           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     239           0 :   } else if( parsed==-2 ) {
     240           0 :     return FD_SSRESOLVE_ADVANCE_AGAIN;
     241           0 :   }
     242             : 
     243           0 :   int is_redirect = (status==301) | (status==302) | (status==303) | (status==304) | (status==307) | (status==308);
     244           0 :   if( FD_UNLIKELY( is_redirect ) ) {
     245           0 :     return fd_ssresolve_parse_redirect( ssresolve, headers, header_cnt, result );
     246           0 :   }
     247             : 
     248           0 :   if( FD_UNLIKELY( status!=200 ) ) {
     249           0 :     FD_LOG_WARNING(( "unexpected response status %d", status ));
     250           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     251           0 :   }
     252             : 
     253           0 :   return FD_SSRESOLVE_ADVANCE_ERROR;
     254           0 : }
     255             : 
     256             : int
     257           0 : fd_ssresolve_advance_poll_out( fd_ssresolve_t * ssresolve ) {
     258           0 :   int res;
     259           0 :   switch( ssresolve->state ) {
     260           0 :     case FD_SSRESOLVE_STATE_REQ: {
     261           0 :       res = fd_ssresolve_send_request( ssresolve );
     262           0 :       break;
     263           0 :     }
     264           0 :     case FD_SSRESOLVE_STATE_RESP: {
     265           0 :       res = FD_SSRESOLVE_ADVANCE_AGAIN;
     266           0 :       break;
     267           0 :     }
     268           0 :     default: {
     269           0 :       FD_LOG_ERR(( "unexpected state %d", ssresolve->state ));
     270           0 :       return FD_SSRESOLVE_ADVANCE_ERROR;
     271           0 :     }
     272           0 :   }
     273           0 :   return res;
     274           0 : }
     275             : 
     276             : int
     277             : fd_ssresolve_advance_poll_in( fd_ssresolve_t *        ssresolve,
     278           0 :                               fd_ssresolve_result_t * result ) {
     279           0 :   int res;
     280           0 :   switch( ssresolve->state ) {
     281           0 :     case FD_SSRESOLVE_STATE_RESP: {
     282           0 :       res = fd_ssresolve_read_response( ssresolve, result );
     283           0 :       break;
     284           0 :     }
     285           0 :     case FD_SSRESOLVE_STATE_REQ: {
     286           0 :       res = FD_SSRESOLVE_ADVANCE_AGAIN;
     287           0 :       break;
     288           0 :     }
     289           0 :     default: {
     290           0 :       FD_LOG_ERR(( "unexpected state %d", ssresolve->state ));
     291           0 :       return FD_SSRESOLVE_ADVANCE_ERROR;
     292           0 :     }
     293           0 :   }
     294             : 
     295           0 :   return res;
     296           0 : }
     297             : 
     298             : int
     299           0 : fd_ssresolve_is_done( fd_ssresolve_t * ssresolve ) {
     300           0 :   return ssresolve->state==FD_SSRESOLVE_STATE_DONE;
     301           0 : }

Generated by: LCOV version 1.14