1 /*
2 * Copyright (C) 2009-2012 Free Software Foundation, Inc.
3 *
4 * Author: Jonathan Bastien-Filiatrault
5 *
6 * This file is part of GNUTLS.
7 *
8 * The GNUTLS library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>
20 *
21 */
22
23 #ifndef GNUTLS_LIB_MBUFFERS_H
24 #define GNUTLS_LIB_MBUFFERS_H
25
26 #include "gnutls_int.h"
27 #include "errors.h"
28 #include <assert.h>
29
30 void _mbuffer_head_init(mbuffer_head_st * buf);
31 void _mbuffer_head_clear(mbuffer_head_st * buf);
32 void _mbuffer_enqueue(mbuffer_head_st * buf, mbuffer_st * bufel);
33 mbuffer_st *_mbuffer_dequeue(mbuffer_head_st * buf, mbuffer_st * bufel);
34 int _mbuffer_head_remove_bytes(mbuffer_head_st * buf, size_t bytes);
35 mbuffer_st *_mbuffer_alloc(size_t maximum_size);
36 int _mbuffer_linearize(mbuffer_head_st * buf);
37
38 mbuffer_st *_mbuffer_head_get_first(mbuffer_head_st * buf,
39 gnutls_datum_t * msg);
40 mbuffer_st *_mbuffer_head_get_next(mbuffer_st * cur, gnutls_datum_t * msg);
41
42 void _mbuffer_head_push_first(mbuffer_head_st * buf, mbuffer_st * bufel);
43
44 mbuffer_st *_mbuffer_head_pop_first(mbuffer_head_st * buf);
45
46 /* This is dangerous since it will replace bufel with a new
47 * one.
48 */
49 int _mbuffer_append_data(mbuffer_st * bufel, void *newdata,
50 size_t newdata_size);
51
52
53 /* For "user" use. One can have buffer data and header.
54 */
55
_mbuffer_get_uhead_ptr(mbuffer_st * bufel)56 inline static void *_mbuffer_get_uhead_ptr(mbuffer_st * bufel)
57 {
58 return bufel->msg.data + bufel->mark;
59 }
60
_mbuffer_get_udata_ptr(mbuffer_st * bufel)61 inline static void *_mbuffer_get_udata_ptr(mbuffer_st * bufel)
62 {
63 return bufel->msg.data + bufel->uhead_mark + bufel->mark;
64 }
65
_mbuffer_set_udata_size(mbuffer_st * bufel,size_t size)66 inline static void _mbuffer_set_udata_size(mbuffer_st * bufel, size_t size)
67 {
68 bufel->msg.size = size + bufel->uhead_mark + bufel->mark;
69 }
70
71 inline static void
_mbuffer_set_udata(mbuffer_st * bufel,void * data,size_t data_size)72 _mbuffer_set_udata(mbuffer_st * bufel, void *data, size_t data_size)
73 {
74 memcpy(_mbuffer_get_udata_ptr(bufel), data,
75 data_size);
76 _mbuffer_set_udata_size(bufel, data_size);
77 }
78
_mbuffer_get_udata_size(mbuffer_st * bufel)79 inline static size_t _mbuffer_get_udata_size(mbuffer_st * bufel)
80 {
81 return bufel->msg.size - bufel->uhead_mark - bufel->mark;
82 }
83
84 /* discards size bytes from the begging of the buffer */
85 inline static void
_mbuffer_consume(mbuffer_head_st * buf,mbuffer_st * bufel,size_t size)86 _mbuffer_consume(mbuffer_head_st * buf, mbuffer_st * bufel, size_t size)
87 {
88 bufel->uhead_mark = 0;
89 if (bufel->mark + size < bufel->msg.size)
90 bufel->mark += size;
91 else
92 bufel->mark = bufel->msg.size;
93
94 buf->byte_length -= size;
95 }
96
_mbuffer_get_uhead_size(mbuffer_st * bufel)97 inline static size_t _mbuffer_get_uhead_size(mbuffer_st * bufel)
98 {
99 return bufel->uhead_mark;
100 }
101
_mbuffer_set_uhead_size(mbuffer_st * bufel,size_t size)102 inline static void _mbuffer_set_uhead_size(mbuffer_st * bufel, size_t size)
103 {
104 bufel->uhead_mark = size;
105 }
106
_mbuffer_init(mbuffer_st * bufel,size_t max)107 inline static void _mbuffer_init(mbuffer_st *bufel, size_t max)
108 {
109 memset(bufel, 0, sizeof(*bufel));
110 bufel->maximum_size = max;
111
112 /* payload points after the mbuffer_st structure */
113 bufel->msg.data = (uint8_t *) bufel + sizeof(mbuffer_st);
114 }
115
116 /* Helper functions to utilize a gnutls_buffer_st in order
117 * to generate a gnutls_mbuffer_st, without multiple allocations.
118 */
_gnutls_buffer_init_mbuffer(gnutls_buffer_st * buf,size_t header_size)119 inline static int _gnutls_buffer_init_mbuffer(gnutls_buffer_st * buf, size_t header_size)
120 {
121 int ret;
122 mbuffer_st *bufel;
123
124 _gnutls_buffer_init(buf);
125
126 ret = _gnutls_buffer_resize(buf, sizeof(mbuffer_st)+header_size);
127 if (ret < 0)
128 return gnutls_assert_val(ret);
129
130 /* we store the uhead size on the uninitialized bufel, only to read
131 * it back on _gnutls_buffer_to_mbuffer(). */
132 bufel = (void*)buf->data;
133 _mbuffer_set_uhead_size(bufel, header_size);
134
135 buf->length = sizeof(mbuffer_st)+header_size;
136
137 return 0;
138 }
139
140 #define _gnutls_buffer_init_handshake_mbuffer(b) _gnutls_buffer_init_mbuffer(b, HANDSHAKE_HEADER_SIZE(session))
141
142
143 /* Cannot fail */
_gnutls_buffer_to_mbuffer(gnutls_buffer_st * buf)144 inline static mbuffer_st *_gnutls_buffer_to_mbuffer(gnutls_buffer_st * buf)
145 {
146 mbuffer_st *bufel;
147 unsigned header_size;
148
149 bufel = (void*)buf->data;
150
151 header_size = _mbuffer_get_uhead_size(bufel);
152 assert(buf->length >= sizeof(mbuffer_st)+header_size);
153
154 _mbuffer_init(bufel, buf->length - sizeof(mbuffer_st));
155
156 _mbuffer_set_udata_size(bufel, buf->length - sizeof(mbuffer_st));
157 _mbuffer_set_uhead_size(bufel, header_size);
158
159 _gnutls_buffer_init(buf); /* avoid double frees */
160
161 return bufel;
162 }
163
_gnutls_handshake_alloc(gnutls_session_t session,size_t maximum)164 inline static mbuffer_st *_gnutls_handshake_alloc(gnutls_session_t session,
165 size_t maximum)
166 {
167 mbuffer_st *bufel =
168 _mbuffer_alloc(HANDSHAKE_HEADER_SIZE(session) + maximum);
169
170 if (!bufel)
171 return NULL;
172
173 _mbuffer_set_uhead_size(bufel, HANDSHAKE_HEADER_SIZE(session));
174 _mbuffer_set_udata_size(bufel, maximum);
175
176 return bufel;
177 }
178
179 /* Free a segment, if the pointer is not NULL
180 *
181 * We take a ** to detect and fix double free bugs (the dangling
182 * pointer case). It also makes sure the pointer has a known value
183 * after freeing.
184 */
_mbuffer_xfree(mbuffer_st ** bufel)185 inline static void _mbuffer_xfree(mbuffer_st ** bufel)
186 {
187 if (*bufel)
188 gnutls_free(*bufel);
189
190 *bufel = NULL;
191 }
192
193 #ifdef ENABLE_ALIGN16
194 mbuffer_st *_mbuffer_alloc_align16(size_t maximum_size, unsigned align_pos);
195 int _mbuffer_linearize_align16(mbuffer_head_st * buf, unsigned align_pos);
196 #else
197 # define _mbuffer_alloc_align16(x,y) _mbuffer_alloc(x)
198 # define _mbuffer_linearize_align16(x,y) _mbuffer_linearize(x)
199 #endif
200
201 #endif /* GNUTLS_LIB_MBUFFERS_H */
202