Honor uninitialized private key in destructor
[gnutls.git] / lib / gnutls_mbuffers.c
bloba12f640790250420ee2ae561fe6f6bc392588509
1 /*
2 * Copyright (C) 2009 Free Software Foundation
4 * Author: Jonathan Bastien-Filiatrault
6 * This file is part of GNUTLS.
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.
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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * USA
25 #include "gnutls_mbuffers.h"
26 #include "gnutls_errors.h"
28 /* Here be mbuffers */
30 /* A note on terminology:
32 * Variables named bufel designate a single buffer segment (mbuffer_st
33 * type). This type is textually referred to as a "segment" or a
34 * "buffer element".
36 * Variables named buf desigate a chain of buffer segments
37 * (mbuffer_head_st type). This type is textually referred to as a
38 * "buffer head" or simply as "buffer".
40 * Design objectives:
42 * - Make existing code easier to understand.
43 * - Make common operations more efficient by avoiding unnecessary
44 * copying.
45 * - Provide a common datatype with a well-known interface to move
46 * data around and through the multiple protocol layers.
47 * - Enable a future implementation of DTLS, which needs the concept
48 * of record boundaries.
52 /* Initialize a buffer head.
54 * Cost: O(1)
56 void
57 _mbuffer_init (mbuffer_head_st * buf)
59 buf->head = NULL;
60 buf->tail = &buf->head;
62 buf->length = 0;
63 buf->byte_length = 0;
66 /* Deallocate all buffer segments and reset the buffer head.
68 * Cost: O(n)
69 * n: Number of segments currently in the buffer.
71 void
72 _mbuffer_clear (mbuffer_head_st * buf)
74 mbuffer_st *bufel, *next;
76 for (bufel = buf->head; bufel != NULL; bufel = next)
78 next = bufel->next;
79 gnutls_free (bufel);
82 _mbuffer_init (buf);
85 /* Append a segment to the end of this buffer.
87 * Cost: O(1)
89 void
90 _mbuffer_enqueue (mbuffer_head_st * buf, mbuffer_st * bufel)
92 bufel->next = NULL;
94 buf->length++;
95 buf->byte_length += bufel->msg.size - bufel->mark;
97 *(buf->tail) = bufel;
98 buf->tail = &bufel->next;
101 /* Get a reference to the first segment of the buffer and its data.
103 * Used to start iteration or to peek at the data.
105 * Cost: O(1)
107 mbuffer_st *
108 _mbuffer_get_first (mbuffer_head_st * buf, gnutls_datum_t * msg)
110 mbuffer_st *bufel = buf->head;
112 if (bufel)
114 msg->data = bufel->msg.data + bufel->mark;
115 msg->size = bufel->msg.size - bufel->mark;
117 else
119 msg->data = NULL;
120 msg->size = 0;
122 return bufel;
125 /* Get a reference to the next segment of the buffer and its data.
127 * Used to iterate over the buffer segments.
129 * Cost: O(1)
131 mbuffer_st *
132 _mbuffer_get_next (mbuffer_st * cur, gnutls_datum_t * msg)
134 mbuffer_st *bufel = cur->next;
136 if (bufel)
138 msg->data = bufel->msg.data + bufel->mark;
139 msg->size = bufel->msg.size - bufel->mark;
141 else
143 msg->data = NULL;
144 msg->size = 0;
146 return bufel;
149 /* Remove the first segment from the buffer.
151 * Used to dequeue data from the buffer. Not yet exposed in the
152 * internal interface since it is not yet needed outside of this unit.
154 * Cost: O(1)
156 static inline void
157 remove_front (mbuffer_head_st * buf)
159 mbuffer_st *bufel;
161 if (!buf->head)
162 return;
164 bufel = buf->head;
165 buf->head = bufel->next;
167 buf->byte_length -= (bufel->msg.size - bufel->mark);
168 buf->length -= 1;
169 gnutls_free (bufel);
171 if (!buf->head)
172 buf->tail = &buf->head;
175 /* Remove a specified number of bytes from the start of the buffer.
177 * Useful for uses that treat the buffer as a simple array of bytes.
179 * Returns 0 on success or an error code otherwise.
181 * Cost: O(n)
182 * n: Number of segments needed to remove the specified amount of data.
185 _mbuffer_remove_bytes (mbuffer_head_st * buf, size_t bytes)
187 size_t left = bytes;
188 mbuffer_st *bufel, *next;
190 if (bytes > buf->byte_length)
192 gnutls_assert ();
193 return GNUTLS_E_INVALID_REQUEST;
196 for (bufel = buf->head; bufel != NULL && left > 0; bufel = next)
198 next = bufel->next;
200 if (left >= (bufel->msg.size - bufel->mark))
202 left -= (bufel->msg.size - bufel->mark);
203 remove_front (buf);
205 else
207 bufel->mark += left;
208 buf->byte_length -= left;
209 left = 0;
213 return 0;
216 /* Allocate a buffer segment. The segment is not initially "owned" by
217 * any buffer.
219 * maximum_size: Amount of data that this segment can contain.
220 * size: Amount of useful data that is contained in this
221 * buffer. Generally 0, but this is a shortcut when a fixed amount of
222 * data will immediately be added to this segment.
224 * Returns the segment or NULL on error.
226 * Cost: O(1)
228 mbuffer_st *
229 _mbuffer_alloc (size_t payload_size, size_t maximum_size)
231 mbuffer_st *st;
233 st = gnutls_malloc (maximum_size + sizeof (mbuffer_st));
234 if (st == NULL)
236 gnutls_assert ();
237 return NULL;
240 //payload points after the mbuffer_st structure
241 st->msg.data = (opaque *) st + sizeof (mbuffer_st);
242 st->msg.size = payload_size;
243 st->mark = 0;
244 st->user_mark = 0;
245 st->next = NULL;
246 st->maximum_size = maximum_size;
248 return st;
251 /* Copy data into a segment. The segment must not be part of a buffer
252 * head when using this function.
254 * Bounds checking is performed by this function.
256 * Returns 0 on success or an error code otherwise.
258 * Cost: O(n)
259 * n: number of bytes to copy
262 _mbuffer_append_data (mbuffer_st * bufel, void *newdata, size_t newdata_size)
264 if (bufel->msg.size + newdata_size <= bufel->maximum_size)
266 memcpy (&bufel->msg.data[bufel->msg.size], newdata, newdata_size);
267 bufel->msg.size += newdata_size;
269 else
271 gnutls_assert ();
272 return GNUTLS_E_INVALID_REQUEST;
275 return 0;
278 /* Takes a buffer in multiple chunks and puts all the data in a single
279 * contiguous segment.
281 * Returns 0 on success or an error code otherwise.
283 * Cost: O(n)
284 * n: number of segments initially in the buffer
287 _mbuffer_linearize (mbuffer_head_st * buf)
289 mbuffer_st *bufel, *cur;
290 gnutls_datum_t msg;
291 size_t pos = 0;
293 if (buf->length <= 1)
294 /* Nothing to do */
295 return 0;
297 bufel = _mbuffer_alloc (buf->byte_length, buf->byte_length);
298 if (!bufel)
300 gnutls_assert ();
301 return GNUTLS_E_MEMORY_ERROR;
304 for (cur = _mbuffer_get_first (buf, &msg);
305 msg.data != NULL; cur = _mbuffer_get_next (cur, &msg))
307 memcpy (&bufel->msg.data[pos], msg.data, cur->msg.size);
308 pos += cur->msg.size;
311 _mbuffer_clear (buf);
312 _mbuffer_enqueue (buf, bufel);
314 return 0;