Line data Source code
1 : #ifndef HEADER_src_ballet_tls_fd_tls_serde_h 2 : #define HEADER_src_ballet_tls_fd_tls_serde_h 3 : 4 : /* fd_tls_serde.h provides branch-minimizing (de-)serializer macros for 5 : internal use. This file specifically exists for fd_tls_proto.c and 6 : should not be included elsewhere. */ 7 : 8 : /* FD_TLS_SERDE_{BEGIN,END} create and terminate a bounds checking 9 : context. Internally, creates a new do/while(0) scope. */ 10 : 11 : #include "fd_tls_proto.h" 12 235056 : #define FD_TLS_SERDE_BEGIN do { \ 13 235056 : int valid = 1; \ 14 : 15 235056 : #define FD_TLS_SERDE_END } while(0); 16 : 17 : /* FD_TLS_SERDE_LOCATE defines a local variable pointing to the would- 18 : be position of the field to be decoded, which may be out-of-bounds. 19 : Also extends the "valid" expression to include a bounds check for 20 : this field. Both the "valid" expression and this local can be fully 21 : constant-propagated if sz is constant. */ 22 : 23 : #define FD_TLS_SERDE_LOCATE( IDX, FIELD, FIELD_TYPE, FIELD_CNT ) \ 24 680820 : ulong _field_##IDX##_laddr = wire_laddr; \ 25 680820 : ulong const _field_##IDX##_cnt = (FIELD_CNT); \ 26 680820 : ulong const _field_##IDX##_sz = sizeof(FIELD_TYPE)*_field_##IDX##_cnt; \ 27 680820 : valid &= (wire_sz >= _field_##IDX##_sz); \ 28 680820 : wire_sz -= _field_##IDX##_sz; \ 29 680820 : wire_laddr += _field_##IDX##_sz; 30 : 31 : /* FD_TLS_SERDE_CHECK performs tbe bounds checks queued by prior 32 : FD_TLS_SERDE_LOCATE ops. */ 33 : 34 : #define FD_TLS_SERDE_CHECK \ 35 271188 : if( FD_UNLIKELY( !valid ) ) return -(long)FD_TLS_ALERT_DECODE_ERROR; 36 : 37 : /* FD_TLS_SERDE_DECODE generates a non-overlapping memory copy for the 38 : given field. Field should be bounds checked at this point. 39 : 40 : Note: We use __extension__ here because ISO C forbids casting a 41 : non-scalar type to itself. (as is the case with tls_u24). */ 42 : 43 : #define FD_TLS_SERDE_DECODE( IDX, FIELD, FIELD_TYPE, FIELD_CNT ) \ 44 313434 : do { \ 45 313434 : memcpy( (FIELD), (void const *)_field_##IDX##_laddr, _field_##IDX##_sz ); \ 46 313434 : FIELD_TYPE * _field_##IDX##_ptr = (FIELD); \ 47 1379865 : for( ulong i=0; i < (FIELD_CNT); i++ ) { \ 48 1066431 : *((_field_##IDX##_ptr)++) = __extension__ \ 49 1066431 : (FIELD_TYPE)fd_##FIELD_TYPE##_bswap( (FIELD)[i] ); \ 50 1066431 : } \ 51 313434 : } while(0); 52 : 53 : #define FD_TLS_SERDE_ENCODE( IDX, FIELD, FIELD_TYPE, FIELD_CNT ) \ 54 331254 : do { \ 55 331254 : uchar * dest = (uchar *)_field_##IDX##_laddr; \ 56 331254 : memcpy( dest, (FIELD), _field_##IDX##_sz ); \ 57 331254 : FIELD_TYPE * ele = fd_type_pun( dest ); \ 58 3956034 : for( ulong i=0; i<(FIELD_CNT); i++ ) { \ 59 3624780 : *ele = fd_##FIELD_TYPE##_bswap( *ele ); \ 60 3624780 : ele++; \ 61 3624780 : } \ 62 331254 : } while(0); 63 : 64 : /* FD_TLS_DECODE_FIELD is a convenience macro for decoding a single 65 : field with known size. */ 66 : 67 : #define FD_TLS_DECODE_FIELD( FIELD, FIELD_TYPE ) \ 68 90459 : FD_TLS_SERDE_BEGIN \ 69 90459 : FD_TLS_SERDE_LOCATE( _, FIELD, FIELD_TYPE, 1 ) \ 70 90459 : FD_TLS_SERDE_CHECK \ 71 90459 : FD_TLS_SERDE_DECODE( _, FIELD, FIELD_TYPE, 1 ) \ 72 90459 : FD_TLS_SERDE_END 73 : 74 : #define FD_TLS_ENCODE_FIELD( FIELD, FIELD_TYPE ) \ 75 0 : FD_TLS_SERDE_BEGIN \ 76 0 : FD_TLS_SERDE_LOCATE( _, FIELD, FIELD_TYPE, 1 ) \ 77 0 : FD_TLS_SERDE_CHECK \ 78 0 : FD_TLS_SERDE_ENCODE( _, FIELD, FIELD_TYPE, 1 ) \ 79 0 : FD_TLS_SERDE_END 80 : 81 : /* FD_TLS_DECODE_STATIC_BATCH is a convenience macro for decoding a 82 : batch of static sized fields in a new decode context. */ 83 : 84 : #define FD_TLS_DECODE_STATIC_BATCH( fields ) \ 85 96423 : FD_TLS_SERDE_BEGIN \ 86 222975 : fields( FD_TLS_SERDE_LOCATE ) \ 87 96423 : FD_TLS_SERDE_CHECK \ 88 222975 : fields( FD_TLS_SERDE_DECODE ) \ 89 96423 : FD_TLS_SERDE_END 90 : 91 : #define FD_TLS_ENCODE_STATIC_BATCH( fields ) \ 92 48174 : FD_TLS_SERDE_BEGIN \ 93 331254 : fields( FD_TLS_SERDE_LOCATE ) \ 94 48174 : FD_TLS_SERDE_CHECK \ 95 331254 : fields( FD_TLS_SERDE_ENCODE ) \ 96 48174 : FD_TLS_SERDE_END 97 : 98 : #define FD_TLS_DECODE_LIST_BEGIN( LIST_SZ_TYPE, ALIGN ) \ 99 48216 : do { \ 100 48216 : LIST_SZ_TYPE list_sz; \ 101 48216 : FD_TLS_DECODE_FIELD( &list_sz, LIST_SZ_TYPE ); \ 102 48216 : if( FD_UNLIKELY( !fd_ulong_is_aligned( list_sz, (ALIGN) ) ) ) \ 103 48216 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \ 104 48216 : if( FD_UNLIKELY( list_sz > wire_sz ) ) \ 105 48216 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \ 106 48216 : ulong const list_start = wire_laddr; \ 107 48216 : ulong const list_stop = list_start + list_sz; \ 108 138690 : while( wire_laddr < list_stop ) \ 109 : 110 : #define FD_TLS_DECODE_LIST_END \ 111 48216 : if( FD_UNLIKELY( wire_laddr != list_stop ) ) \ 112 48216 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \ 113 48216 : } while(0); \ 114 : 115 30111 : #define FD_TLS_SKIP_FIELD( FIELD_TYPE ) (__extension__({ \ 116 30111 : int valid = 1; \ 117 30111 : FD_TLS_SERDE_LOCATE( , , FIELD_TYPE, 1 ) \ 118 30111 : FD_TLS_SERDE_CHECK \ 119 30111 : (FIELD_TYPE *)fd_type_pun( (void *)_field__laddr ); \ 120 30111 : })) 121 : 122 6021 : #define FD_TLS_SKIP_FIELDS( FIELD_TYPE, CNT ) (__extension__({ \ 123 6021 : int valid = 1; \ 124 6021 : FD_TLS_SERDE_LOCATE( , , FIELD_TYPE, (CNT) ) \ 125 6021 : FD_TLS_SERDE_CHECK \ 126 6021 : (FIELD_TYPE *)_field__laddr; \ 127 6021 : })) 128 : 129 6027 : #define FD_TLS_DECODE_SUB( FUNC, OUT ) do { \ 130 6027 : long res = FUNC( (OUT), (void const *)wire_laddr, wire_sz ); \ 131 6027 : if( FD_UNLIKELY( res<0L ) ) return res; \ 132 6027 : wire_laddr += (ulong)res; \ 133 6027 : wire_sz -= (ulong)res; \ 134 6027 : } while(0) 135 : 136 24072 : #define FD_TLS_ENCODE_SUB( FUNC, IN ) (__extension__({ \ 137 24072 : long res = FUNC( (IN), (void *)wire_laddr, wire_sz ); \ 138 24072 : if( FD_UNLIKELY( res<0L ) ) return res; \ 139 24072 : wire_laddr += (ulong)res; \ 140 24072 : wire_sz -= (ulong)res; \ 141 24072 : (ulong)res; \ 142 24072 : })) 143 : 144 : #endif /* HEADER_src_ballet_tls_fd_tls_serde_h */