62d17632b39358f0626ac23d264896ce2efbbeca
[strongswan.git] / src / libcharon / plugins / vici / vici_builder.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "vici_builder.h"
17
18 #include <bio/bio_writer.h>
19
20 typedef struct private_vici_builder_t private_vici_builder_t;
21
22 /**
23 * Private data of an vici_builder_t object.
24 */
25 struct private_vici_builder_t {
26
27 /**
28 * Public vici_builder_t interface.
29 */
30 vici_builder_t public;
31
32 /**
33 * Writer for elements
34 */
35 bio_writer_t *writer;
36
37 /**
38 * Errors encountered
39 */
40 u_int error;
41
42 /**
43 * Section nesting level
44 */
45 u_int section;
46
47 /**
48 * In list element?
49 */
50 bool list;
51 };
52
53 METHOD(vici_builder_t, add, void,
54 private_vici_builder_t *this, vici_type_t type, ...)
55 {
56 va_list args;
57 char *name = NULL;
58 chunk_t value = chunk_empty;
59
60 va_start(args, type);
61 switch (type)
62 {
63 case VICI_SECTION_END:
64 case VICI_LIST_END:
65 case VICI_END:
66 break;
67 case VICI_LIST_START:
68 case VICI_SECTION_START:
69 name = va_arg(args, char*);
70 break;
71 case VICI_KEY_VALUE:
72 name = va_arg(args, char*);
73 value = va_arg(args, chunk_t);
74 break;
75 case VICI_LIST_ITEM:
76 value = va_arg(args, chunk_t);
77 break;
78 default:
79 va_end(args);
80 this->error++;
81 return;
82 }
83 va_end(args);
84
85 if (value.len > 0xffff)
86 {
87 this->error++;
88 return;
89 }
90 if (!vici_verify_type(type, this->section, this->list))
91 {
92 this->error++;
93 return;
94 }
95 if (type != VICI_END)
96 {
97 this->writer->write_uint8(this->writer, type);
98 }
99 switch (type)
100 {
101 case VICI_SECTION_START:
102 this->writer->write_data8(this->writer, chunk_from_str(name));
103 this->section++;
104 break;
105 case VICI_SECTION_END:
106 this->section--;
107 break;
108 case VICI_KEY_VALUE:
109 this->writer->write_data8(this->writer, chunk_from_str(name));
110 this->writer->write_data16(this->writer, value);
111 break;
112 case VICI_LIST_START:
113 this->writer->write_data8(this->writer, chunk_from_str(name));
114 this->list = TRUE;
115 break;
116 case VICI_LIST_ITEM:
117 this->writer->write_data16(this->writer, value);
118 break;
119 case VICI_LIST_END:
120 this->list = FALSE;
121 break;
122 default:
123 this->error++;
124 break;
125 }
126 }
127
128 METHOD(vici_builder_t, vadd_kv, void,
129 private_vici_builder_t *this, char *key, char *fmt, va_list args)
130 {
131 char buf[2048];
132 ssize_t len;
133
134 len = vsnprintf(buf, sizeof(buf), fmt, args);
135 if (len < 0 || len >= sizeof(buf))
136 {
137 DBG1(DBG_ENC, "vici builder format buffer exceeds limit");
138 this->error++;
139 }
140 else
141 {
142 add(this, VICI_KEY_VALUE, key, chunk_create(buf, len));
143 }
144 }
145
146 METHOD(vici_builder_t, add_kv, void,
147 private_vici_builder_t *this, char *key, char *fmt, ...)
148 {
149 va_list args;
150
151 va_start(args, fmt);
152 vadd_kv(this, key, fmt, args);
153 va_end(args);
154 }
155
156
157 METHOD(vici_builder_t, vadd_li, void,
158 private_vici_builder_t *this, char *fmt, va_list args)
159 {
160 char buf[2048];
161 ssize_t len;
162
163 len = vsnprintf(buf, sizeof(buf), fmt, args);
164 if (len < 0 || len >= sizeof(buf))
165 {
166 DBG1(DBG_ENC, "vici builder format buffer exceeds limit");
167 this->error++;
168 }
169 else
170 {
171 add(this, VICI_LIST_ITEM, chunk_create(buf, len));
172 }
173 }
174
175 METHOD(vici_builder_t, add_li, void,
176 private_vici_builder_t *this, char *fmt, ...)
177 {
178 va_list args;
179
180 va_start(args, fmt);
181 vadd_li(this, fmt, args);
182 va_end(args);
183 }
184
185 METHOD(vici_builder_t, begin_section, void,
186 private_vici_builder_t *this, char *name)
187 {
188 add(this, VICI_SECTION_START, name);
189 }
190
191 METHOD(vici_builder_t, end_section, void,
192 private_vici_builder_t *this)
193 {
194 add(this, VICI_SECTION_END);
195 }
196
197 METHOD(vici_builder_t, begin_list, void,
198 private_vici_builder_t *this, char *name)
199 {
200 add(this, VICI_LIST_START, name);
201 }
202
203 METHOD(vici_builder_t, end_list, void,
204 private_vici_builder_t *this)
205 {
206 add(this, VICI_LIST_END);
207 }
208
209 METHOD(vici_builder_t, destroy, void,
210 private_vici_builder_t *this)
211 {
212 this->writer->destroy(this->writer);
213 free(this);
214 }
215
216 METHOD(vici_builder_t, finalize, vici_message_t*,
217 private_vici_builder_t *this)
218 {
219 vici_message_t *product;
220
221 if (this->error || this->section || this->list)
222 {
223 DBG1(DBG_ENC, "vici builder error: %u errors (section: %u, list %u)",
224 this->error, this->section, this->list);
225 destroy(this);
226 return NULL;
227 }
228 product = vici_message_create_from_data(
229 this->writer->extract_buf(this->writer), TRUE);
230 destroy(this);
231 return product;
232 }
233
234 /**
235 * See header
236 */
237 vici_builder_t *vici_builder_create()
238 {
239 private_vici_builder_t *this;
240
241 INIT(this,
242 .public = {
243 .add = _add,
244 .add_kv = _add_kv,
245 .vadd_kv = _vadd_kv,
246 .add_li = _add_li,
247 .vadd_li = _vadd_li,
248 .begin_section = _begin_section,
249 .end_section = _end_section,
250 .begin_list = _begin_list,
251 .end_list = _end_list,
252 .finalize = _finalize,
253 .destroy = _destroy,
254 },
255 .writer = bio_writer_create(0),
256 );
257
258 return &this->public;
259 }