BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file NCDUdevMonitorParser.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <stdlib.h>
31 #include <string.h>
32  
33 #include <misc/string_begins_with.h>
34 #include <misc/balloc.h>
35 #include <base/BLog.h>
36  
37 #include <udevmonitor/NCDUdevMonitorParser.h>
38  
39 #include <generated/blog_channel_NCDUdevMonitorParser.h>
40  
41 #define PROPERTY_REGEX "^([^=]+)=(.*)$"
42  
43 static uint8_t * find_end (uint8_t *buf, size_t len)
44 {
45 while (len >= 2) {
46 if (buf[0] == '\n' && buf[1] == '\n') {
47 return (buf + 2);
48 }
49 buf++;
50 len--;
51 }
52  
53 return NULL;
54 }
55  
56 static int parse_property (NCDUdevMonitorParser *o, char *data)
57 {
58 ASSERT(o->ready_num_properties >= 0)
59 ASSERT(o->ready_num_properties <= o->max_properties)
60  
61 if (o->ready_num_properties == o->max_properties) {
62 BLog(BLOG_ERROR, "too many properties");
63 return 0;
64 }
65 struct NCDUdevMonitorParser_property *prop = &o->ready_properties[o->ready_num_properties];
66  
67 // execute property regex
68 regmatch_t matches[3];
69 if (regexec(&o->property_regex, data, 3, matches, 0) != 0) {
70 BLog(BLOG_ERROR, "failed to parse property");
71 return 0;
72 }
73  
74 // extract components
75 prop->name = data + matches[1].rm_so;
76 *(data + matches[1].rm_eo) = '\0';
77 prop->value = data + matches[2].rm_so;
78 *(data + matches[2].rm_eo) = '\0';
79  
80 // register property
81 o->ready_num_properties++;
82  
83 return 1;
84 }
85  
86 static int parse_message (NCDUdevMonitorParser *o)
87 {
88 ASSERT(!o->is_ready)
89 ASSERT(o->ready_len >= 2)
90 ASSERT(o->buf[o->ready_len - 2] == '\n')
91 ASSERT(o->buf[o->ready_len - 1] == '\n')
92  
93 // zero terminate message (replacing the second newline)
94 o->buf[o->ready_len - 1] = '\0';
95  
96 // start parsing
97 char *line = (char *)o->buf;
98 int first_line = 1;
99  
100 // set is not ready event
101 o->ready_is_ready_event = 0;
102  
103 // init properties
104 o->ready_num_properties = 0;
105  
106 do {
107 // find end of line
108 char *line_end = strchr(line, '\n');
109 ASSERT(line_end)
110  
111 // zero terminate line
112 *line_end = '\0';
113  
114 if (o->is_info_mode) {
115 // ignore W: entries with missing space
116 if (string_begins_with(line, "W:")) {
117 goto nextline;
118 }
119  
120 // parse prefix
121 if (strlen(line) < 3 || line[1] != ':' || line[2] != ' ') {
122 BLog(BLOG_ERROR, "failed to parse head");
123 return 0;
124 }
125 char line_type = line[0];
126 char *line_value = line + 3;
127  
128 if (first_line) {
129 if (line_type != 'P') {
130 BLog(BLOG_ERROR, "wrong first line type");
131 return 0;
132 }
133 } else {
134 if (line_type == 'E') {
135 if (!parse_property(o, line_value)) {
136 return 0;
137 }
138 }
139 }
140 } else {
141 if (first_line) {
142 // is this the initial informational message?
143 if (string_begins_with(line, "monitor")) {
144 o->ready_is_ready_event = 1;
145 break;
146 }
147  
148 // check first line
149 if (!string_begins_with(line, "UDEV ") && !string_begins_with(line, "KERNEL")) {
150 BLog(BLOG_ERROR, "failed to parse head");
151 return 0;
152 }
153 } else {
154 if (!parse_property(o, line)) {
155 return 0;
156 }
157 }
158 }
159 nextline:
160  
161 first_line = 0;
162 line = line_end + 1;
163 } while (*line);
164  
165 // set ready
166 o->is_ready = 1;
167  
168 return 1;
169 }
170  
171 static void process_data (NCDUdevMonitorParser *o)
172 {
173 ASSERT(!o->is_ready)
174  
175 while (1) {
176 // look for end of event
177 uint8_t *c = find_end(o->buf, o->buf_used);
178 if (!c) {
179 // check for out of buffer condition
180 if (o->buf_used == o->buf_size) {
181 BLog(BLOG_ERROR, "out of buffer");
182 o->buf_used = 0;
183 }
184  
185 // receive more data
186 StreamRecvInterface_Receiver_Recv(o->input, o->buf + o->buf_used, o->buf_size - o->buf_used);
187 return;
188 }
189  
190 // remember message length
191 o->ready_len = c - o->buf;
192  
193 // parse message
194 if (parse_message(o)) {
195 break;
196 }
197  
198 // shift buffer
199 memmove(o->buf, o->buf + o->ready_len, o->buf_used - o->ready_len);
200 o->buf_used -= o->ready_len;
201 }
202  
203 // call handler
204 o->handler(o->user);
205 return;
206 }
207  
208 static void input_handler_done (NCDUdevMonitorParser *o, int data_len)
209 {
210 DebugObject_Access(&o->d_obj);
211 ASSERT(!o->is_ready)
212 ASSERT(data_len > 0)
213 ASSERT(data_len <= o->buf_size - o->buf_used)
214  
215 // increment buffer position
216 o->buf_used += data_len;
217  
218 // process data
219 process_data(o);
220 return;
221 }
222  
223 static void done_job_handler (NCDUdevMonitorParser *o)
224 {
225 DebugObject_Access(&o->d_obj);
226 ASSERT(o->is_ready)
227  
228 // shift buffer
229 memmove(o->buf, o->buf + o->ready_len, o->buf_used - o->ready_len);
230 o->buf_used -= o->ready_len;
231  
232 // set not ready
233 o->is_ready = 0;
234  
235 // process data
236 process_data(o);
237 return;
238 }
239  
240 int NCDUdevMonitorParser_Init (NCDUdevMonitorParser *o, StreamRecvInterface *input, int buf_size, int max_properties,
241 int is_info_mode, BPendingGroup *pg, void *user,
242 NCDUdevMonitorParser_handler handler)
243 {
244 ASSERT(buf_size > 0)
245 ASSERT(max_properties >= 0)
246 ASSERT(is_info_mode == 0 || is_info_mode == 1)
247  
248 // init arguments
249 o->input = input;
250 o->buf_size = buf_size;
251 o->max_properties = max_properties;
252 o->is_info_mode = is_info_mode;
253 o->user = user;
254 o->handler = handler;
255  
256 // init input
257 StreamRecvInterface_Receiver_Init(o->input, (StreamRecvInterface_handler_done)input_handler_done, o);
258  
259 // init property regex
260 if (regcomp(&o->property_regex, PROPERTY_REGEX, REG_EXTENDED) != 0) {
261 BLog(BLOG_ERROR, "regcomp failed");
262 goto fail1;
263 }
264  
265 // init done job
266 BPending_Init(&o->done_job, pg, (BPending_handler)done_job_handler, o);
267  
268 // allocate buffer
269 if (!(o->buf = malloc(o->buf_size))) {
270 BLog(BLOG_ERROR, "malloc failed");
271 goto fail2;
272 }
273  
274 // set buffer position
275 o->buf_used = 0;
276  
277 // set not ready
278 o->is_ready = 0;
279  
280 // allocate properties
281 if (!(o->ready_properties = BAllocArray(o->max_properties, sizeof(o->ready_properties[0])))) {
282 BLog(BLOG_ERROR, "BAllocArray failed");
283 goto fail3;
284 }
285  
286 // start receiving
287 StreamRecvInterface_Receiver_Recv(o->input, o->buf, o->buf_size);
288  
289 DebugObject_Init(&o->d_obj);
290 return 1;
291  
292 fail3:
293 free(o->buf);
294 fail2:
295 BPending_Free(&o->done_job);
296 regfree(&o->property_regex);
297 fail1:
298 return 0;
299 }
300  
301 void NCDUdevMonitorParser_Free (NCDUdevMonitorParser *o)
302 {
303 DebugObject_Free(&o->d_obj);
304  
305 // free properties
306 BFree(o->ready_properties);
307  
308 // free buffer
309 free(o->buf);
310  
311 // free done job
312 BPending_Free(&o->done_job);
313  
314 // free property regex
315 regfree(&o->property_regex);
316 }
317  
318 void NCDUdevMonitorParser_AssertReady (NCDUdevMonitorParser *o)
319 {
320 DebugObject_Access(&o->d_obj);
321 ASSERT(o->is_ready)
322 }
323  
324 void NCDUdevMonitorParser_Done (NCDUdevMonitorParser *o)
325 {
326 DebugObject_Access(&o->d_obj);
327 ASSERT(o->is_ready)
328  
329 // schedule done job
330 BPending_Set(&o->done_job);
331 }
332  
333 int NCDUdevMonitorParser_IsReadyEvent (NCDUdevMonitorParser *o)
334 {
335 DebugObject_Access(&o->d_obj);
336 ASSERT(o->is_ready)
337  
338 return o->ready_is_ready_event;
339 }
340  
341 int NCDUdevMonitorParser_GetNumProperties (NCDUdevMonitorParser *o)
342 {
343 DebugObject_Access(&o->d_obj);
344 ASSERT(o->is_ready)
345  
346 return o->ready_num_properties;
347 }
348  
349 void NCDUdevMonitorParser_GetProperty (NCDUdevMonitorParser *o, int index, const char **name, const char **value)
350 {
351 DebugObject_Access(&o->d_obj);
352 ASSERT(o->is_ready)
353 ASSERT(index >= 0)
354 ASSERT(index < o->ready_num_properties)
355  
356 *name = o->ready_properties[index].name;
357 *value = o->ready_properties[index].value;
358 }