LCOV - code coverage report
Current view: top level - discof/restore/utils - fd_ssresolve.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 9 359 2.5 %
Date: 2026-09-17 04:28:31 Functions: 2 17 11.8 %

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

Generated by: LCOV version 1.14