Line data Source code
1 : #ifndef HEADER_fd_src_waltz_tlsrec_fd_tlsrec_sock_h 2 : #define HEADER_fd_src_waltz_tlsrec_fd_tlsrec_sock_h 3 : 4 : /* fd_tlsrec_sock shuttles TLS records between a non-blocking TCP 5 : socket and an fd_tlsrec_conn. It owns the two buffers every socket 6 : user of fd_tlsrec needs: ciphertext that the socket did not accept 7 : yet, and plaintext that the application did not consume yet. 8 : 9 : The socket is never read while plaintext is still held (it would be 10 : overwritten), and never read while the ciphertext buffer lacks room 11 : for the replies fd_tlsrec_conn_rx may generate (a KeyUpdate). In 12 : both cases the TCP window back-pressures the peer. A send parked on 13 : EAGAIN alone does not stop RX: whatever conn_rx emits is appended 14 : behind the parked bytes. 15 : 16 : All functions use MSG_DONTWAIT|MSG_NOSIGNAL and never block. */ 17 : 18 : #include "fd_tlsrec.h" 19 : 20 : /* FD_TLSREC_SOCK_TX_RESERVE is the ciphertext headroom kept free for 21 : conn_rx output while a record is parked. Post-handshake, one conn_rx 22 : call emits at most one 27 byte KeyUpdate record however many updates 23 : the peer requested. FD_TLSREC_SOCK_RX_MTU is the most ciphertext 24 : read from the socket per call. */ 25 : 26 : #define FD_TLSREC_SOCK_TX_RESERVE (512UL) 27 : #define FD_TLSREC_SOCK_TX_BUF_SZ (FD_TLSREC_PLAINTEXT_MAX+22UL+FD_TLSREC_SOCK_TX_RESERVE) 28 : #define FD_TLSREC_SOCK_RX_MTU (FD_TLSREC_CAP) 29 : #define FD_TLSREC_SOCK_RX_BUF_SZ (FD_TLSREC_CAP+FD_TLSREC_SOCK_RX_MTU) 30 : 31 : struct fd_tlsrec_sock { 32 : uchar tx_buf[ FD_TLSREC_SOCK_TX_BUF_SZ ]; /* ciphertext [tx_off,tx_sz) awaits send(2) */ 33 : ulong tx_off; 34 : ulong tx_sz; 35 : 36 : uchar rx_buf[ FD_TLSREC_SOCK_RX_BUF_SZ ]; /* plaintext [rx_off,rx_sz) awaits the app */ 37 : ulong rx_off; 38 : ulong rx_sz; 39 : }; 40 : 41 : typedef struct fd_tlsrec_sock fd_tlsrec_sock_t; 42 : 43 : /* Error codes. Positive values are FD_TLSREC_ERR_{...}. */ 44 : 45 0 : #define FD_TLSREC_SOCK_ERR_RECV (-1) /* recv(2) failed, errno set */ 46 0 : #define FD_TLSREC_SOCK_ERR_SEND (-2) /* send(2) failed, errno set */ 47 9 : #define FD_TLSREC_SOCK_ERR_EOF (-3) /* peer closed the connection */ 48 : 49 : FD_PROTOTYPES_BEGIN 50 : 51 : static inline void 52 135 : fd_tlsrec_sock_init( fd_tlsrec_sock_t * sock ) { 53 135 : sock->tx_off = 0UL; sock->tx_sz = 0UL; 54 135 : sock->rx_off = 0UL; sock->rx_sz = 0UL; 55 135 : } 56 : 57 : FD_FN_PURE static inline int 58 0 : fd_tlsrec_sock_tx_pending( fd_tlsrec_sock_t const * sock ) { 59 0 : return sock->tx_off!=sock->tx_sz; 60 0 : } 61 : 62 : /* Plaintext accessors: fd_tlsrec_sock_rx_avail is the number of 63 : decrypted bytes held, fd_tlsrec_sock_rx_data points to them, and 64 : fd_tlsrec_sock_rx_consume releases the first sz of them. 65 : fd_tlsrec_sock_rx_pop copies up to dst_max bytes out and returns the 66 : count. */ 67 : 68 : FD_FN_PURE static inline ulong 69 21 : fd_tlsrec_sock_rx_avail( fd_tlsrec_sock_t const * sock ) { 70 21 : return sock->rx_sz - sock->rx_off; 71 21 : } 72 : 73 : FD_FN_PURE static inline uchar const * 74 3 : fd_tlsrec_sock_rx_data( fd_tlsrec_sock_t const * sock ) { 75 3 : return sock->rx_buf + sock->rx_off; 76 3 : } 77 : 78 : static inline void 79 : fd_tlsrec_sock_rx_consume( fd_tlsrec_sock_t * sock, 80 3 : ulong sz ) { 81 3 : sock->rx_off += sz; 82 3 : if( sock->rx_off==sock->rx_sz ) { sock->rx_off = 0UL; sock->rx_sz = 0UL; } 83 3 : } 84 : 85 : static inline ulong 86 : fd_tlsrec_sock_rx_pop( fd_tlsrec_sock_t * sock, 87 : void * dst, 88 0 : ulong dst_max ) { 89 0 : ulong sz = fd_ulong_min( fd_tlsrec_sock_rx_avail( sock ), dst_max ); 90 0 : fd_memcpy( dst, fd_tlsrec_sock_rx_data( sock ), sz ); 91 0 : fd_tlsrec_sock_rx_consume( sock, sz ); 92 0 : return sz; 93 0 : } 94 : 95 : /* fd_tlsrec_sock_flush writes parked ciphertext to fd until the buffer 96 : is empty or send blocks. Returns 0 if the buffer is now empty, 1 if 97 : send would block (bytes remain, wait for POLLOUT), and 98 : FD_TLSREC_SOCK_ERR_SEND on a hard send error. */ 99 : 100 : int 101 : fd_tlsrec_sock_flush( fd_tlsrec_sock_t * sock, 102 : int fd ); 103 : 104 : /* fd_tlsrec_sock_rx reads up to FD_TLSREC_SOCK_RX_MTU bytes of 105 : ciphertext from fd, decrypts them into the plaintext buffer, and 106 : sends whatever conn emitted in response (handshake flights, a 107 : KeyUpdate reply). conn is stepped even if nothing was read, which 108 : is what produces the ClientHello. The read is skipped, and the call 109 : is a no-op, while plaintext is held or the ciphertext buffer lacks 110 : FD_TLSREC_SOCK_TX_RESERVE bytes of headroom. 111 : 112 : Returns 0 on success with *opt_rx_sz set to the number of ciphertext 113 : bytes read (0 on EAGAIN or a skipped read). Otherwise returns 114 : FD_TLSREC_SOCK_ERR_{RECV,SEND,EOF} or a positive FD_TLSREC_ERR code; 115 : the connection should be dropped. ERR_EOF is also returned for a 116 : TLS close_notify, once the plaintext preceding it was consumed. */ 117 : 118 : int 119 : fd_tlsrec_sock_rx( fd_tlsrec_sock_t * sock, 120 : fd_tlsrec_conn_t * conn, 121 : int fd, 122 : ulong * opt_rx_sz ); 123 : 124 : /* fd_tlsrec_sock_close queues a close_notify alert behind any parked 125 : ciphertext and flushes. Returns like fd_tlsrec_sock_flush: 0 when 126 : everything was sent, 1 if bytes remain (wait for POLLOUT, then flush), 127 : FD_TLSREC_SOCK_ERR_SEND, or a positive FD_TLSREC_ERR code (ERR_STATE 128 : if the connection is not established or already closed for writing, 129 : ERR_OOM if the parked bytes leave no room, in which case flush first). */ 130 : 131 : int 132 : fd_tlsrec_sock_close( fd_tlsrec_sock_t * sock, 133 : fd_tlsrec_conn_t * conn, 134 : int fd ); 135 : 136 : /* fd_tlsrec_sock_tx encrypts one record of application data from 137 : [app,app+app_sz) and sends it, parking any tail the socket did not 138 : accept. Does nothing if ciphertext is already parked (flush first). 139 : *opt_consumed is set to the number of application bytes encrypted, 140 : at most FD_TLSREC_PLAINTEXT_MAX. Returns 0 on success, 141 : FD_TLSREC_SOCK_ERR_SEND, or a positive FD_TLSREC_ERR code. */ 142 : 143 : int 144 : fd_tlsrec_sock_tx( fd_tlsrec_sock_t * sock, 145 : fd_tlsrec_conn_t * conn, 146 : int fd, 147 : void const * app, 148 : ulong app_sz, 149 : ulong * opt_consumed ); 150 : 151 : FD_FN_CONST char const * 152 : fd_tlsrec_sock_strerror( int err ); 153 : 154 : FD_PROTOTYPES_END 155 : 156 : #endif /* HEADER_fd_src_waltz_tlsrec_fd_tlsrec_sock_h */