]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/bio/bio_writer.c
Ensure buffer in bio_writer_t is properly increased
[people/ms/strongswan.git] / src / libstrongswan / bio / bio_writer.c
1 /*
2 * Copyright (C) 2012-2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2010 Martin Willi
6 * Copyright (C) 2010 revosec AG
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include "bio_writer.h"
20
21 typedef struct private_bio_writer_t private_bio_writer_t;
22
23 /**
24 * Private data of an bio_writer_t object.
25 */
26 struct private_bio_writer_t {
27
28 /**
29 * Public bio_writer_t interface.
30 */
31 bio_writer_t public;
32
33 /**
34 * Allocated buffer
35 */
36 chunk_t buf;
37
38 /**
39 * Used bytes in buffer
40 */
41 size_t used;
42
43 /**
44 * Number of bytes to increase buffer size
45 */
46 size_t increase;
47 };
48
49 /**
50 * Increase buffer size, if required
51 */
52 static inline void increase(private_bio_writer_t *this, size_t required)
53 {
54 bool inc = FALSE;
55
56 while (this->used + required > this->buf.len)
57 {
58 this->buf.len += this->increase;
59 inc = TRUE;
60 }
61 if (inc)
62 {
63 this->buf.ptr = realloc(this->buf.ptr, this->buf.len);
64 }
65 }
66
67 METHOD(bio_writer_t, write_uint8, void,
68 private_bio_writer_t *this, u_int8_t value)
69 {
70 increase(this, 1);
71 this->buf.ptr[this->used] = value;
72 this->used += 1;
73 }
74
75 METHOD(bio_writer_t, write_uint16, void,
76 private_bio_writer_t *this, u_int16_t value)
77 {
78 increase(this, 2);
79 htoun16(this->buf.ptr + this->used, value);
80 this->used += 2;
81 }
82
83 METHOD(bio_writer_t, write_uint24, void,
84 private_bio_writer_t *this, u_int32_t value)
85 {
86 increase(this, 3);
87 value = htonl(value);
88 memcpy(this->buf.ptr + this->used, ((char*)&value) + 1, 3);
89 this->used += 3;
90 }
91
92 METHOD(bio_writer_t, write_uint32, void,
93 private_bio_writer_t *this, u_int32_t value)
94 {
95 increase(this, 4);
96 htoun32(this->buf.ptr + this->used, value);
97 this->used += 4;
98 }
99
100 METHOD(bio_writer_t, write_uint64, void,
101 private_bio_writer_t *this, u_int64_t value)
102 {
103 increase(this, 8);
104 htoun64(this->buf.ptr + this->used, value);
105 this->used += 8;
106 }
107
108 METHOD(bio_writer_t, write_data, void,
109 private_bio_writer_t *this, chunk_t value)
110 {
111 increase(this, value.len);
112 memcpy(this->buf.ptr + this->used, value.ptr, value.len);
113 this->used += value.len;
114 }
115
116 METHOD(bio_writer_t, write_data8, void,
117 private_bio_writer_t *this, chunk_t value)
118 {
119 increase(this, 1 + value.len);
120 write_uint8(this, value.len);
121 write_data(this, value);
122 }
123
124 METHOD(bio_writer_t, write_data16, void,
125 private_bio_writer_t *this, chunk_t value)
126 {
127 increase(this, 2 + value.len);
128 write_uint16(this, value.len);
129 write_data(this, value);
130 }
131
132 METHOD(bio_writer_t, write_data24, void,
133 private_bio_writer_t *this, chunk_t value)
134 {
135 increase(this, 3 + value.len);
136 write_uint24(this, value.len);
137 write_data(this, value);
138 }
139
140 METHOD(bio_writer_t, write_data32, void,
141 private_bio_writer_t *this, chunk_t value)
142 {
143 increase(this, 4 + value.len);
144 write_uint32(this, value.len);
145 write_data(this, value);
146 }
147
148 METHOD(bio_writer_t, wrap8, void,
149 private_bio_writer_t *this)
150 {
151 increase(this, 1);
152 memmove(this->buf.ptr + 1, this->buf.ptr, this->used);
153 this->buf.ptr[0] = this->used;
154 this->used += 1;
155 }
156
157 METHOD(bio_writer_t, wrap16, void,
158 private_bio_writer_t *this)
159 {
160 increase(this, 2);
161 memmove(this->buf.ptr + 2, this->buf.ptr, this->used);
162 htoun16(this->buf.ptr, this->used);
163 this->used += 2;
164 }
165
166 METHOD(bio_writer_t, wrap24, void,
167 private_bio_writer_t *this)
168 {
169 u_int32_t len;
170
171 increase(this, 3);
172 memmove(this->buf.ptr + 3, this->buf.ptr, this->used);
173
174 len = htonl(this->used);
175 memcpy(this->buf.ptr, ((char*)&len) + 1, 3);
176 this->used += 3;
177 }
178
179 METHOD(bio_writer_t, wrap32, void,
180 private_bio_writer_t *this)
181 {
182 increase(this, 4);
183 memmove(this->buf.ptr + 4, this->buf.ptr, this->used);
184 htoun32(this->buf.ptr, this->used);
185 this->used += 4;
186 }
187
188 METHOD(bio_writer_t, skip, chunk_t,
189 private_bio_writer_t *this, size_t len)
190 {
191 chunk_t skipped;
192
193 increase(this, len);
194 skipped = chunk_create(this->buf.ptr + this->used, len);
195 this->used += len;
196 return skipped;
197 }
198
199 METHOD(bio_writer_t, get_buf, chunk_t,
200 private_bio_writer_t *this)
201 {
202 return chunk_create(this->buf.ptr, this->used);
203 }
204
205 METHOD(bio_writer_t, extract_buf, chunk_t,
206 private_bio_writer_t *this)
207 {
208 chunk_t buf = get_buf(this);
209 this->buf = chunk_empty;
210 this->used = 0;
211 return buf;
212 }
213
214 METHOD(bio_writer_t, destroy, void,
215 private_bio_writer_t *this)
216 {
217 free(this->buf.ptr);
218 free(this);
219 }
220
221 /**
222 * See header
223 */
224 bio_writer_t *bio_writer_create(u_int32_t bufsize)
225 {
226 private_bio_writer_t *this;
227
228 INIT(this,
229 .public = {
230 .write_uint8 = _write_uint8,
231 .write_uint16 = _write_uint16,
232 .write_uint24 = _write_uint24,
233 .write_uint32 = _write_uint32,
234 .write_uint64 = _write_uint64,
235 .write_data = _write_data,
236 .write_data8 = _write_data8,
237 .write_data16 = _write_data16,
238 .write_data24 = _write_data24,
239 .write_data32 = _write_data32,
240 .wrap8 = _wrap8,
241 .wrap16 = _wrap16,
242 .wrap24 = _wrap24,
243 .wrap32 = _wrap32,
244 .skip = _skip,
245 .get_buf = _get_buf,
246 .extract_buf = _extract_buf,
247 .destroy = _destroy,
248 },
249 .increase = bufsize ? max(bufsize, 4) : 32,
250 );
251 if (bufsize)
252 {
253 this->buf = chunk_alloc(bufsize);
254 }
255
256 return &this->public;
257 }