LCOV - code coverage report
Current view: top level - discof/restore/utils - fd_ssresolve.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 366 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 18 0.0 %

          Line data    Source code
       1             : #include <linux/limits.h>  /* PATH_MAX — needed before fd_ssarchive.h */
       2             : #include "fd_ssresolve.h"
       3             : #include "fd_ssarchive.h"
       4             : 
       5             : #include "../../../third_party/picohttpparser/picohttpparser.h"
       6             : #include "../../../waltz/tlsrec/fd_tlsrec_sock.h"
       7             : #include "../../../ballet/ed25519/fd_x25519.h"
       8             : #include "../../../util/log/fd_log.h"
       9             : 
      10             : #include <unistd.h>
      11             : #include <errno.h>
      12             : #include <stdlib.h>
      13             : #include <strings.h>
      14             : #include <limits.h>
      15             : 
      16             : #include <sys/socket.h>
      17             : #include <netinet/tcp.h>
      18             : #include <netinet/in.h>
      19             : 
      20           0 : #define FD_SSRESOLVE_CONNECT             (0) /* TLS handshake in progress */
      21           0 : #define FD_SSRESOLVE_STATE_REQ           (1) /* sending request for snapshot */
      22           0 : #define FD_SSRESOLVE_STATE_RESP          (2) /* receiving snapshot response */
      23           0 : #define FD_SSRESOLVE_STATE_DONE          (3) /* done */
      24             : 
      25             : struct fd_ssresolve_private {
      26             :   int  state;
      27             :   long deadline;
      28             : 
      29             :   fd_ip4_port_t addr;
      30             :   int           sockfd;
      31             :   int           full;
      32             :   int           is_https;
      33             :   int           tcp_connected;
      34             :   char const *  hostname;
      35             : 
      36             :   char  request[ 4096UL ];
      37             :   ulong request_sent;
      38             :   ulong request_len;
      39             : 
      40             :   ulong response_len;
      41             :   char  response[ USHORT_MAX ];
      42             : 
      43             :   /* Native TLS state */
      44             :   fd_tlsrec_conn_t tls_conn;
      45             :   fd_tlsrec_sock_t tls_sock[1];
      46             : 
      47             :   ulong magic;
      48             : };
      49             : 
      50             : FD_STATIC_ASSERT( alignof(fd_ssresolve_t)==FD_SSRESOLVE_ALIGN, ssresolve_align );
      51             : 
      52             : FD_FN_CONST ulong
      53           0 : fd_ssresolve_align( void ) {
      54           0 :   return FD_SSRESOLVE_ALIGN;
      55           0 : }
      56             : 
      57             : FD_FN_CONST ulong
      58           0 : fd_ssresolve_footprint( void ) {
      59           0 :   ulong l;
      60           0 :   l = FD_LAYOUT_INIT;
      61           0 :   l = FD_LAYOUT_APPEND( l, FD_SSRESOLVE_ALIGN, sizeof(fd_ssresolve_t) );
      62           0 :   return FD_LAYOUT_FINI( l, FD_SSRESOLVE_ALIGN );
      63           0 : }
      64             : 
      65             : void *
      66           0 : fd_ssresolve_new( void * shmem ) {
      67           0 :   if( FD_UNLIKELY( !shmem ) ) {
      68           0 :     FD_LOG_WARNING(( "NULL shmem" ));
      69           0 :     return NULL;
      70           0 :   }
      71             : 
      72           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_ssresolve_align() ) ) ) {
      73           0 :     FD_LOG_WARNING(( "unaligned shmem" ));
      74           0 :     return NULL;
      75           0 :   }
      76             : 
      77           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      78           0 :   fd_ssresolve_t * ssresolve = FD_SCRATCH_ALLOC_APPEND( l, FD_SSRESOLVE_ALIGN, sizeof(fd_ssresolve_t) );
      79             : 
      80           0 :   ssresolve->state           = FD_SSRESOLVE_STATE_REQ;
      81           0 :   ssresolve->request_sent    = 0UL;
      82           0 :   ssresolve->request_len     = 0UL;
      83           0 :   ssresolve->response_len    = 0UL;
      84           0 :   ssresolve->sockfd          = -1;
      85           0 :   fd_tlsrec_sock_init( ssresolve->tls_sock );
      86             : 
      87           0 :   FD_COMPILER_MFENCE();
      88           0 :   FD_VOLATILE( ssresolve->magic ) = FD_SSRESOLVE_MAGIC;
      89           0 :   FD_COMPILER_MFENCE();
      90             : 
      91           0 :   return (void *)ssresolve;
      92           0 : }
      93             : 
      94             : fd_ssresolve_t *
      95           0 : fd_ssresolve_join( void * _ssresolve ) {
      96           0 :   if( FD_UNLIKELY( !_ssresolve ) ) {
      97           0 :     FD_LOG_WARNING(( "NULL ssresolve" ));
      98           0 :     return NULL;
      99           0 :   }
     100             : 
     101           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)_ssresolve, fd_ssresolve_align() ) ) ) {
     102           0 :     FD_LOG_WARNING(( "misaligned ssresolve" ));
     103           0 :     return NULL;
     104           0 :   }
     105             : 
     106           0 :   fd_ssresolve_t * ssresolve = (fd_ssresolve_t *)_ssresolve;
     107             : 
     108           0 :   if( FD_UNLIKELY( ssresolve->magic!=FD_SSRESOLVE_MAGIC ) ) {
     109           0 :     FD_LOG_WARNING(( "bad magic" ));
     110           0 :     return NULL;
     111           0 :   }
     112             : 
     113           0 :   return ssresolve;
     114           0 : }
     115             : 
     116             : void
     117             : fd_ssresolve_init( fd_ssresolve_t * ssresolve,
     118             :                    fd_ip4_port_t    addr,
     119             :                    int              sockfd,
     120             :                    int              full,
     121           0 :                    char const *     hostname ) {
     122           0 :   ssresolve->addr   = addr;
     123           0 :   ssresolve->sockfd = sockfd;
     124           0 :   ssresolve->full   = full;
     125             : 
     126           0 :   ssresolve->state           = FD_SSRESOLVE_STATE_REQ;
     127           0 :   ssresolve->request_sent    = 0UL;
     128           0 :   ssresolve->request_len     = 0UL;
     129           0 :   ssresolve->response_len    = 0UL;
     130           0 :   ssresolve->is_https        = 0;
     131           0 :   ssresolve->hostname        = hostname;
     132           0 :   fd_tlsrec_sock_init( ssresolve->tls_sock );
     133           0 : }
     134             : 
     135             : void
     136             : fd_ssresolve_init_https( fd_ssresolve_t *           ssresolve,
     137             :                          fd_ip4_port_t              addr,
     138             :                          int                        sockfd,
     139             :                          int                        full,
     140             :                          char const *               hostname,
     141             :                          fd_tls_t const *           tls,
     142           0 :                          fd_x509_ca_store_t const * ca_store ) {
     143           0 :   ssresolve->addr   = addr;
     144           0 :   ssresolve->sockfd = sockfd;
     145           0 :   ssresolve->full   = full;
     146             : 
     147           0 :   ssresolve->state         = FD_SSRESOLVE_CONNECT;
     148           0 :   ssresolve->tcp_connected = 0;
     149           0 :   ssresolve->request_sent  = 0UL;
     150           0 :   ssresolve->request_len  = 0UL;
     151           0 :   ssresolve->response_len = 0UL;
     152           0 :   ssresolve->is_https     = 1;
     153           0 :   ssresolve->hostname     = hostname;
     154             : 
     155             :   /* Copy and configure fd_tls for this connection */
     156           0 :   fd_tlsrec_conn_init( &ssresolve->tls_conn, tls, 0 );
     157             : 
     158           0 :   ulong hostname_len = hostname ? strlen( hostname ) : 0UL;
     159           0 :   if( FD_UNLIKELY( !hostname_len ||
     160           0 :                    hostname_len>=sizeof(ssresolve->tls_conn.tls.server_name) ) ) {
     161           0 :     FD_LOG_ERR(( "Invalid HTTPS snapshot peer hostname (%lu bytes)", hostname_len ));
     162           0 :   }
     163           0 :   fd_memcpy( ssresolve->tls_conn.tls.server_name, hostname, hostname_len );
     164           0 :   ssresolve->tls_conn.tls.server_name[ hostname_len ] = '\0';
     165           0 :   ssresolve->tls_conn.tls.server_name_len = (ushort)hostname_len;
     166             : 
     167           0 :   ssresolve->tls_conn.tls.ca_store = ca_store;
     168             : 
     169             :   /* Generate a fresh ephemeral X25519 key for this handshake */
     170             : 
     171           0 :   if( FD_UNLIKELY( !fd_rng_secure( ssresolve->tls_conn.tls.kex_private_key, 32UL ) ) )
     172           0 :     FD_LOG_CRIT(( "fd_rng_secure failed" ));
     173           0 :   fd_x25519_public( ssresolve->tls_conn.tls.kex_public_key,
     174           0 :                     ssresolve->tls_conn.tls.kex_private_key );
     175             : 
     176           0 :   fd_tlsrec_sock_init( ssresolve->tls_sock );
     177           0 : }
     178             : 
     179             : static void
     180           0 : fd_ssresolve_render_req( fd_ssresolve_t * ssresolve ) {
     181           0 :   char const * path = ssresolve->full ? "/snapshot.tar.bz2" : "/incremental-snapshot.tar.bz2";
     182             : 
     183           0 :   if( FD_LIKELY( ssresolve->hostname && ssresolve->hostname[ 0 ]!='\0' ) ) {
     184           0 :     FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
     185           0 :            "HEAD %s HTTP/1.1\r\n"
     186           0 :            "User-Agent: Firedancer\r\n"
     187           0 :            "Accept: */*\r\n"
     188           0 :            "Accept-Encoding: identity\r\n"
     189           0 :            "Host: %s\r\n\r\n",
     190           0 :            path, ssresolve->hostname ) );
     191           0 :   } else {
     192           0 :     FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
     193           0 :            "HEAD %s HTTP/1.1\r\n"
     194           0 :            "User-Agent: Firedancer\r\n"
     195           0 :            "Accept: */*\r\n"
     196           0 :            "Accept-Encoding: identity\r\n"
     197           0 :            "Host: " FD_IP4_ADDR_FMT "\r\n\r\n",
     198           0 :            path, FD_IP4_ADDR_FMT_ARGS( ssresolve->addr.addr ) ) );
     199           0 :   }
     200           0 : }
     201             : 
     202             : /* Native TLS send/recv helpers */
     203             : 
     204             : /* ssresolve_tls_tx_flush drains retained ciphertext.  Returns 1 if
     205             :    the buffer is now empty, 0 if the socket could not take all of it,
     206             :    and -1 on a hard send error. */
     207             : 
     208             : 
     209             : static long
     210             : ssresolve_send_tls( fd_ssresolve_t * ssresolve,
     211             :                     void *           buf,
     212           0 :                     ulong            bufsz ) {
     213           0 :   int flush = fd_tlsrec_sock_flush( ssresolve->tls_sock, ssresolve->sockfd );
     214           0 :   if( flush<0 ) {
     215           0 :     FD_LOG_WARNING(( "send() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
     216           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     217           0 :   }
     218           0 :   if( flush>0 ) return FD_SSRESOLVE_ADVANCE_AGAIN;
     219             : 
     220           0 :   ulong consumed;
     221           0 :   int err = fd_tlsrec_sock_tx( ssresolve->tls_sock, &ssresolve->tls_conn, ssresolve->sockfd, buf, bufsz, &consumed );
     222           0 :   if( FD_UNLIKELY( err ) ) {
     223           0 :     FD_LOG_WARNING(( "TLS send failed (%d-%s)", err, fd_tlsrec_sock_strerror( err ) ));
     224           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     225           0 :   }
     226           0 :   return (long)consumed;
     227           0 : }
     228             : 
     229             : static long
     230             : ssresolve_recv_tls( fd_ssresolve_t * ssresolve,
     231             :                     void *           buf,
     232           0 :                     ulong            bufsz ) {
     233             :   /* Drain buffered decrypted data */
     234           0 :   ulong n = fd_tlsrec_sock_rx_pop( ssresolve->tls_sock, buf, bufsz );
     235           0 :   if( n ) return (long)n;
     236             : 
     237             :   /* Drain pending ciphertext before generating any new records */
     238             : 
     239           0 :   int flush = fd_tlsrec_sock_flush( ssresolve->tls_sock, ssresolve->sockfd );
     240           0 :   if( flush<0 ) {
     241           0 :     FD_LOG_WARNING(( "send() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
     242           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     243           0 :   }
     244           0 :   if( flush>0 ) return FD_SSRESOLVE_ADVANCE_AGAIN;
     245             : 
     246           0 :   ulong tcp_rx_sz;
     247           0 :   int err = fd_tlsrec_sock_rx( ssresolve->tls_sock, &ssresolve->tls_conn, ssresolve->sockfd, &tcp_rx_sz );
     248           0 :   if( FD_UNLIKELY( err ) ) {
     249           0 :     if( err==FD_TLSREC_SOCK_ERR_EOF ) {
     250           0 :       FD_LOG_WARNING(( "peer closed the connection before sending the full response" ));
     251           0 :     } else if( err==FD_TLSREC_SOCK_ERR_RECV || err==FD_TLSREC_SOCK_ERR_SEND ) {
     252           0 :       FD_LOG_WARNING(( "%s (%d-%s)", fd_tlsrec_sock_strerror( err ), errno, fd_io_strerror( errno ) ));
     253           0 :     } else {
     254           0 :       FD_LOG_WARNING(( "TLS error (%d-%s)", err, fd_tlsrec_sock_strerror( err ) ));
     255           0 :     }
     256           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     257           0 :   }
     258           0 :   if( !tcp_rx_sz ) return FD_SSRESOLVE_ADVANCE_AGAIN;
     259             : 
     260           0 :   n = fd_tlsrec_sock_rx_pop( ssresolve->tls_sock, buf, bufsz );
     261           0 :   if( !n ) return FD_SSRESOLVE_ADVANCE_AGAIN;
     262           0 :   return (long)n;
     263           0 : }
     264             : 
     265             : static int
     266           0 : fd_ssresolve_send_request( fd_ssresolve_t * ssresolve ) {
     267           0 :   FD_TEST( ssresolve->state==FD_SSRESOLVE_STATE_REQ );
     268             : 
     269           0 :   if( FD_UNLIKELY( !ssresolve->request_len ) ) {
     270           0 :     fd_ssresolve_render_req( ssresolve );
     271           0 :   }
     272             : 
     273           0 :   long sent;
     274           0 :   if( FD_LIKELY( ssresolve->is_https ) ) {
     275           0 :     sent = ssresolve_send_tls( ssresolve,
     276           0 :                                ssresolve->request + ssresolve->request_sent,
     277           0 :                                ssresolve->request_len - ssresolve->request_sent );
     278           0 :     if( FD_UNLIKELY( sent <= 0 ) ) return (int)sent;
     279           0 :   } else {
     280           0 :     sent = sendto( ssresolve->sockfd, ssresolve->request+ssresolve->request_sent, ssresolve->request_len-ssresolve->request_sent, MSG_NOSIGNAL, NULL, 0 );
     281           0 :     if( FD_UNLIKELY( -1==sent && errno==EAGAIN ) ) return FD_SSRESOLVE_ADVANCE_AGAIN;
     282           0 :     else if( FD_UNLIKELY( -1==sent ) ) {
     283           0 :       FD_LOG_WARNING(( "send() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
     284           0 :       return FD_SSRESOLVE_ADVANCE_ERROR;
     285           0 :     }
     286           0 :   }
     287             : 
     288           0 :   ssresolve->request_sent += (ulong)sent;
     289           0 :   if( FD_UNLIKELY( ssresolve->request_sent==ssresolve->request_len ) ) {
     290           0 :     ssresolve->state = FD_SSRESOLVE_STATE_RESP;
     291           0 :     return FD_SSRESOLVE_ADVANCE_SUCCESS;
     292           0 :   }
     293             : 
     294           0 :   return FD_SSRESOLVE_ADVANCE_AGAIN;
     295           0 : }
     296             : 
     297             : static int
     298             : fd_ssresolve_parse_redirect( fd_ssresolve_t *        ssresolve,
     299             :                              struct phr_header *     headers,
     300             :                              ulong                   header_cnt,
     301           0 :                              fd_ssresolve_result_t * result ) {
     302           0 :   ulong        location_len = 0UL;
     303           0 :   char const * location     = NULL;
     304             : 
     305           0 :   for( ulong i=0UL; i<header_cnt; i++ ) {
     306           0 :     if( FD_UNLIKELY( headers[ i ].name_len == 8 && !strncasecmp( headers[ i ].name, "location", headers[ i ].name_len ) ) ) {
     307           0 :       if( FD_UNLIKELY( !headers [ i ].value_len || headers[ i ].value[ 0 ]!='/' ) ) {
     308           0 :         FD_LOG_WARNING(( "invalid location header `%.*s`", (int)headers[ i ].value_len, headers[ i ].value ));
     309           0 :         return FD_SSRESOLVE_ADVANCE_ERROR;
     310           0 :       }
     311             : 
     312           0 :       location_len = headers[ i ].value_len;
     313           0 :       location = headers[ i ].value;
     314           0 :       break;
     315           0 :     }
     316           0 :   }
     317             : 
     318           0 :   if( FD_UNLIKELY( !location_len ) ) {
     319           0 :     FD_LOG_WARNING(( "no location header in redirect response" ));
     320           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     321           0 :   }
     322             : 
     323           0 :   if( FD_UNLIKELY( location_len>=PATH_MAX-1UL ) ) {
     324           0 :     FD_LOG_WARNING(( "redirect location header too long (%lu)", location_len ));
     325           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     326           0 :   }
     327             : 
     328           0 :   char snapshot_name[ PATH_MAX ];
     329           0 :   fd_memcpy( snapshot_name, location+1UL, location_len-1UL );
     330           0 :   snapshot_name[ location_len-1UL ] = '\0';
     331             : 
     332           0 :   int is_zstd;
     333           0 :   ulong full_entry_slot, incremental_entry_slot;
     334           0 :   uchar decoded_hash[ FD_HASH_FOOTPRINT ];
     335           0 :   int err = fd_ssarchive_parse_filename( snapshot_name, &full_entry_slot, &incremental_entry_slot, decoded_hash, &is_zstd );
     336             : 
     337           0 :   if( FD_UNLIKELY( err || !is_zstd ) ) {
     338           0 :     FD_LOG_WARNING(( "unrecognized snapshot file `%s` in redirect location header", snapshot_name ));
     339           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     340           0 :   }
     341             : 
     342           0 :   fd_memcpy( result->hash, decoded_hash, FD_HASH_FOOTPRINT );
     343           0 :   if( FD_LIKELY( incremental_entry_slot==ULONG_MAX ) ) {
     344           0 :     result->slot      = full_entry_slot;
     345           0 :     result->base_slot = ULONG_MAX;
     346           0 :   } else {
     347           0 :     result->slot      = incremental_entry_slot;
     348           0 :     result->base_slot = full_entry_slot;
     349           0 :   }
     350             : 
     351           0 :   ssresolve->state = FD_SSRESOLVE_STATE_DONE;
     352           0 :   return FD_SSRESOLVE_ADVANCE_RESULT;
     353           0 : }
     354             : 
     355             : static int
     356             : fd_ssresolve_read_response( fd_ssresolve_t *        ssresolve,
     357           0 :                             fd_ssresolve_result_t * result ) {
     358           0 :   FD_TEST( ssresolve->state==FD_SSRESOLVE_STATE_RESP );
     359             : 
     360           0 :   if( FD_UNLIKELY( ssresolve->response_len>=sizeof(ssresolve->response) ) ) {
     361           0 :     FD_LOG_WARNING(( "response headers too large" ));
     362           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     363           0 :   }
     364             : 
     365           0 :   long read = 0L;
     366           0 :   if( FD_LIKELY( ssresolve->is_https ) ) {
     367           0 :     read = ssresolve_recv_tls( ssresolve,
     368           0 :                                ssresolve->response + ssresolve->response_len,
     369           0 :                                sizeof(ssresolve->response) - ssresolve->response_len );
     370           0 :     if( FD_UNLIKELY( read <= 0 ) ) return (int)read;
     371           0 :   } else {
     372           0 :     read = recvfrom( ssresolve->sockfd, ssresolve->response+ssresolve->response_len, sizeof(ssresolve->response)-ssresolve->response_len, 0, NULL, NULL );
     373           0 :     if( FD_UNLIKELY( -1==read && errno==EAGAIN ) ) return FD_SSRESOLVE_ADVANCE_AGAIN;
     374           0 :     else if( FD_UNLIKELY( -1==read ) ) {
     375           0 :       FD_LOG_WARNING(( "recvfrom() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
     376           0 :       return FD_SSRESOLVE_ADVANCE_ERROR;
     377           0 :     } else if( FD_UNLIKELY( !read ) ) {
     378           0 :       FD_LOG_WARNING(( "peer closed the connection before sending the full response" ));
     379           0 :       return FD_SSRESOLVE_ADVANCE_ERROR;
     380           0 :     }
     381           0 :   }
     382             : 
     383           0 :   ssresolve->response_len += (ulong)read;
     384             : 
     385           0 :   int               minor_version;
     386           0 :   int               status;
     387           0 :   const char *      message;
     388           0 :   ulong             message_len;
     389           0 :   struct phr_header headers[ 128UL ];
     390           0 :   ulong             header_cnt = 128UL;
     391           0 :   int parsed = phr_parse_response( ssresolve->response,
     392           0 :                                     ssresolve->response_len,
     393           0 :                                     &minor_version,
     394           0 :                                     &status,
     395           0 :                                     &message,
     396           0 :                                     &message_len,
     397           0 :                                     headers,
     398           0 :                                     &header_cnt,
     399           0 :                                     ssresolve->response_len - (ulong)read );
     400           0 :   if( FD_UNLIKELY( parsed==-1 ) ) {
     401           0 :     FD_LOG_WARNING(( "malformed response body" ));
     402           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     403           0 :   } else if( parsed==-2 ) {
     404           0 :     return FD_SSRESOLVE_ADVANCE_AGAIN;
     405           0 :   }
     406             : 
     407           0 :   int is_redirect = (status==301) | (status==302) | (status==303) | (status==307) | (status==308);
     408           0 :   if( FD_UNLIKELY( is_redirect ) ) {
     409           0 :     return fd_ssresolve_parse_redirect( ssresolve, headers, header_cnt, result );
     410           0 :   }
     411             : 
     412           0 :   if( FD_UNLIKELY( status!=200 ) ) {
     413           0 :     char req_path[ 4096UL ];
     414           0 :     if( FD_LIKELY( ssresolve->is_https ) ) {
     415           0 :       FD_TEST( fd_cstr_printf_check( req_path, sizeof(req_path), NULL,
     416           0 :                "https://%s:%u%s", ssresolve->hostname, fd_ushort_bswap( ssresolve->addr.port ), ssresolve->full ? "/snapshot.tar.bz2" : "/incremental-snapshot.tar.bz2" ) );
     417           0 :     } else {
     418           0 :       FD_TEST( fd_cstr_printf_check( req_path, sizeof(req_path), NULL,
     419           0 :                "http://%s:%u%s", ssresolve->hostname, fd_ushort_bswap( ssresolve->addr.port ), ssresolve->full ? "/snapshot.tar.bz2" : "/incremental-snapshot.tar.bz2" ) );
     420           0 :     }
     421           0 :     FD_LOG_WARNING(( "unexpected response code %d accessing %s", status, req_path ));
     422           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     423           0 :   }
     424             : 
     425           0 :   return FD_SSRESOLVE_ADVANCE_ERROR;
     426           0 : }
     427             : 
     428             : static int
     429           0 : ssresolve_connect_tls( fd_ssresolve_t * ssresolve ) {
     430             :   /* Drain pending ciphertext before generating any new records */
     431             : 
     432           0 :   int flush = fd_tlsrec_sock_flush( ssresolve->tls_sock, ssresolve->sockfd );
     433           0 :   if( flush<0 ) {
     434           0 :     FD_LOG_WARNING(( "send() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
     435           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     436           0 :   }
     437           0 :   if( flush>0 ) return FD_SSRESOLVE_ADVANCE_AGAIN;
     438             : 
     439             :   /* Drive the TLS handshake */
     440             : 
     441           0 :   int err = fd_tlsrec_sock_rx( ssresolve->tls_sock, &ssresolve->tls_conn, ssresolve->sockfd, NULL );
     442           0 :   if( FD_UNLIKELY( err ) ) {
     443           0 :     if( err==FD_TLSREC_SOCK_ERR_EOF ) {
     444           0 :       FD_LOG_WARNING(( "peer closed the connection during TLS handshake with %s", ssresolve->hostname ));
     445           0 :     } else {
     446           0 :       FD_LOG_WARNING(( "TLS handshake failed (%d-%s) for %s",
     447           0 :                        err, fd_tlsrec_sock_strerror( err ), ssresolve->hostname ));
     448           0 :     }
     449           0 :     return FD_SSRESOLVE_ADVANCE_ERROR;
     450           0 :   }
     451             : 
     452           0 :   if( fd_tlsrec_conn_is_ready( &ssresolve->tls_conn ) ) {
     453           0 :     ssresolve->state = FD_SSRESOLVE_STATE_REQ;
     454           0 :     return FD_SSRESOLVE_ADVANCE_AGAIN;
     455           0 :   }
     456             : 
     457           0 :   if( fd_tlsrec_conn_is_failed( &ssresolve->tls_conn ) ) return FD_SSRESOLVE_ADVANCE_ERROR;
     458           0 :   return FD_SSRESOLVE_ADVANCE_AGAIN;
     459           0 : }
     460             : 
     461             : int
     462           0 : fd_ssresolve_advance_poll_out( fd_ssresolve_t * ssresolve ) {
     463           0 :   int res;
     464           0 :   switch( ssresolve->state ) {
     465           0 :     case FD_SSRESOLVE_CONNECT:
     466           0 :       ssresolve->tcp_connected = 1;
     467           0 :       res = ssresolve_connect_tls( ssresolve );
     468           0 :       break;
     469           0 :     case FD_SSRESOLVE_STATE_REQ:
     470           0 :       res = fd_ssresolve_send_request( ssresolve );
     471           0 :       break;
     472           0 :     case FD_SSRESOLVE_STATE_RESP:
     473           0 :       res = FD_SSRESOLVE_ADVANCE_AGAIN;
     474           0 :       if( ssresolve->is_https && fd_tlsrec_sock_flush( ssresolve->tls_sock, ssresolve->sockfd )<0 ) {
     475           0 :         res = FD_SSRESOLVE_ADVANCE_ERROR;
     476           0 :       }
     477           0 :       break;
     478           0 :     default:
     479           0 :       FD_LOG_ERR(( "unexpected state %d", ssresolve->state ));
     480           0 :       return FD_SSRESOLVE_ADVANCE_ERROR;
     481           0 :   }
     482           0 :   return res;
     483           0 : }
     484             : 
     485             : int
     486             : fd_ssresolve_advance_poll_in( fd_ssresolve_t *        ssresolve,
     487           0 :                               fd_ssresolve_result_t * result ) {
     488           0 :   int res;
     489           0 :   switch( ssresolve->state ) {
     490           0 :     case FD_SSRESOLVE_CONNECT:
     491           0 :       res = ssresolve_connect_tls( ssresolve );
     492           0 :       break;
     493           0 :     case FD_SSRESOLVE_STATE_RESP:
     494           0 :       res = fd_ssresolve_read_response( ssresolve, result );
     495           0 :       break;
     496           0 :     case FD_SSRESOLVE_STATE_REQ:
     497           0 :       res = FD_SSRESOLVE_ADVANCE_AGAIN;
     498           0 :       break;
     499           0 :     case FD_SSRESOLVE_STATE_DONE:
     500           0 :       res = FD_SSRESOLVE_ADVANCE_SUCCESS;
     501           0 :       break;
     502           0 :     default:
     503           0 :       FD_LOG_ERR(( "unexpected state %d", ssresolve->state ));
     504           0 :       return FD_SSRESOLVE_ADVANCE_ERROR;
     505           0 :   }
     506             : 
     507           0 :   return res;
     508           0 : }
     509             : 
     510             : int
     511           0 : fd_ssresolve_is_done( fd_ssresolve_t * ssresolve ) {
     512           0 :   return ssresolve->state==FD_SSRESOLVE_STATE_DONE;
     513           0 : }
     514             : 
     515             : int
     516           0 : fd_ssresolve_wants_pollout( fd_ssresolve_t const * ssresolve ) {
     517           0 :   return (ssresolve->state==FD_SSRESOLVE_CONNECT && !ssresolve->tcp_connected) ||
     518           0 :          ssresolve->state==FD_SSRESOLVE_STATE_REQ ||
     519           0 :          (ssresolve->is_https && fd_tlsrec_sock_tx_pending( ssresolve->tls_sock ));
     520           0 : }
     521             : 
     522             : void
     523           0 : fd_ssresolve_cancel( fd_ssresolve_t * ssresolve ) {
     524           0 :   if( FD_LIKELY( ssresolve->sockfd!=-1 ) ) {
     525           0 :     if( FD_UNLIKELY( -1==close( ssresolve->sockfd ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     526           0 :     ssresolve->sockfd = -1;
     527           0 :   }
     528           0 :   fd_tlsrec_sock_init( ssresolve->tls_sock );
     529           0 : }

Generated by: LCOV version 1.14