Line data Source code
1 : #ifndef HEADER_fd_src_waltz_tls_fd_tls_serde_h
2 : #define HEADER_fd_src_waltz_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 0 : #define FD_TLS_SERDE_BEGIN do { \
13 0 : int valid = 1; \
14 :
15 0 : #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 0 : ulong _field_##IDX##_laddr = wire_laddr; \
25 0 : ulong const _field_##IDX##_cnt = (FIELD_CNT); \
26 0 : ulong const _field_##IDX##_sz = sizeof(FIELD_TYPE)*_field_##IDX##_cnt; \
27 0 : valid &= (wire_sz >= _field_##IDX##_sz); \
28 0 : wire_sz -= _field_##IDX##_sz; \
29 0 : wire_laddr += _field_##IDX##_sz;
30 :
31 : /* FD_TLS_SERDE_CHECK performs the bounds checks queued by prior
32 : FD_TLS_SERDE_LOCATE ops. */
33 :
34 : #define FD_TLS_SERDE_CHECK \
35 0 : 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 0 : do { \
45 0 : if( _field_##IDX##_sz ) \
46 0 : memcpy( (FIELD), (void const *)_field_##IDX##_laddr, _field_##IDX##_sz ); \
47 0 : FIELD_TYPE * _field_##IDX##_ptr = (FIELD); \
48 0 : for( ulong i=0; i < (FIELD_CNT); i++ ) { \
49 0 : *((_field_##IDX##_ptr)++) = __extension__ \
50 0 : (FIELD_TYPE)fd_##FIELD_TYPE##_bswap( (FIELD)[i] ); \
51 0 : } \
52 0 : } while(0);
53 :
54 : #define FD_TLS_SERDE_ENCODE( IDX, FIELD, FIELD_TYPE, FIELD_CNT ) \
55 0 : do { \
56 0 : uchar * dest = (uchar *)_field_##IDX##_laddr; \
57 0 : if( _field_##IDX##_sz ) \
58 0 : memcpy( dest, (FIELD), _field_##IDX##_sz ); \
59 0 : for( ulong i=0; i<(FIELD_CNT); i++ ) { \
60 0 : FIELD_TYPE temp; \
61 0 : memcpy( &temp, dest, sizeof(FIELD_TYPE) ); \
62 0 : temp = fd_##FIELD_TYPE##_bswap( temp ); \
63 0 : memcpy( dest, &temp, sizeof(FIELD_TYPE) ); \
64 0 : dest += sizeof(FIELD_TYPE); \
65 0 : } \
66 0 : } while(0);
67 :
68 : /* FD_TLS_DECODE_FIELD is a convenience macro for decoding a single
69 : field with known size. */
70 :
71 : #define FD_TLS_DECODE_FIELD( FIELD, FIELD_TYPE ) \
72 0 : FD_TLS_SERDE_BEGIN \
73 0 : FD_TLS_SERDE_LOCATE( _, FIELD, FIELD_TYPE, 1 ) \
74 0 : FD_TLS_SERDE_CHECK \
75 0 : FD_TLS_SERDE_DECODE( _, FIELD, FIELD_TYPE, 1 ) \
76 0 : FD_TLS_SERDE_END
77 :
78 : #define FD_TLS_ENCODE_FIELD( FIELD, FIELD_TYPE ) \
79 : FD_TLS_SERDE_BEGIN \
80 : FD_TLS_SERDE_LOCATE( _, FIELD, FIELD_TYPE, 1 ) \
81 : FD_TLS_SERDE_CHECK \
82 : FD_TLS_SERDE_ENCODE( _, FIELD, FIELD_TYPE, 1 ) \
83 : FD_TLS_SERDE_END
84 :
85 : /* FD_TLS_DECODE_STATIC_BATCH is a convenience macro for decoding a
86 : batch of static sized fields in a new decode context. */
87 :
88 : #define FD_TLS_DECODE_STATIC_BATCH( fields ) \
89 0 : FD_TLS_SERDE_BEGIN \
90 0 : fields( FD_TLS_SERDE_LOCATE ) \
91 0 : FD_TLS_SERDE_CHECK \
92 0 : fields( FD_TLS_SERDE_DECODE ) \
93 0 : FD_TLS_SERDE_END
94 :
95 : #define FD_TLS_ENCODE_STATIC_BATCH( fields ) \
96 0 : FD_TLS_SERDE_BEGIN \
97 0 : fields( FD_TLS_SERDE_LOCATE ) \
98 0 : FD_TLS_SERDE_CHECK \
99 0 : fields( FD_TLS_SERDE_ENCODE ) \
100 0 : FD_TLS_SERDE_END
101 :
102 : #define FD_TLS_DECODE_LIST_BEGIN( LIST_SZ_TYPE, ALIGN ) \
103 0 : do { \
104 0 : LIST_SZ_TYPE list_sz; \
105 0 : FD_TLS_DECODE_FIELD( &list_sz, LIST_SZ_TYPE ); \
106 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( list_sz, (ALIGN) ) ) ) \
107 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \
108 0 : if( FD_UNLIKELY( list_sz > wire_sz ) ) \
109 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \
110 0 : ulong const list_start = wire_laddr; \
111 0 : ulong const list_stop = list_start + list_sz; \
112 0 : while( wire_laddr < list_stop ) \
113 :
114 : #define FD_TLS_DECODE_LIST_END \
115 0 : if( FD_UNLIKELY( wire_laddr != list_stop ) ) \
116 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \
117 0 : } while(0); \
118 :
119 0 : #define FD_TLS_SKIP_FIELD( FIELD_TYPE ) (__extension__({ \
120 0 : int valid = 1; \
121 0 : FD_TLS_SERDE_LOCATE( , , FIELD_TYPE, 1 ) \
122 0 : FD_TLS_SERDE_CHECK \
123 0 : (FIELD_TYPE *)fd_type_pun( (void *)_field__laddr ); \
124 0 : }))
125 :
126 : #define FD_TLS_SKIP_FIELDS( FIELD_TYPE, CNT ) (__extension__({ \
127 : int valid = 1; \
128 : FD_TLS_SERDE_LOCATE( , , FIELD_TYPE, (CNT) ) \
129 : FD_TLS_SERDE_CHECK \
130 : (FIELD_TYPE *)_field__laddr; \
131 : }))
132 :
133 0 : #define FD_TLS_DECODE_SUB( FUNC, OUT ) do { \
134 0 : long res = FUNC( (OUT), (void const *)wire_laddr, wire_sz ); \
135 0 : if( FD_UNLIKELY( res<0L ) ) return res; \
136 0 : wire_laddr += (ulong)res; \
137 0 : wire_sz -= (ulong)res; \
138 0 : } while(0)
139 :
140 0 : #define FD_TLS_ENCODE_SUB( FUNC, IN ) (__extension__({ \
141 0 : long res = FUNC( (IN), (void *)wire_laddr, wire_sz ); \
142 0 : if( FD_UNLIKELY( res<0L ) ) return res; \
143 0 : wire_laddr += (ulong)res; \
144 0 : wire_sz -= (ulong)res; \
145 0 : (ulong)res; \
146 0 : }))
147 :
148 : #endif /* HEADER_fd_src_waltz_tls_fd_tls_serde_h */
|