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