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 : }
|