BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file NCDUdevManager.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/offset.h>
34 #include <base/BLog.h>
35  
36 #include <udevmonitor/NCDUdevManager.h>
37  
38 #include <generated/blog_channel_NCDUdevManager.h>
39  
40 #define RESTART_TIMER_TIME 5000
41  
42 static int event_to_map (NCDUdevMonitor *monitor, BStringMap *out_map);
43 static void free_event (NCDUdevClient *o, struct NCDUdevClient_event *e);
44 static void queue_event (NCDUdevManager *o, NCDUdevMonitor *monitor, NCDUdevClient *client);
45 static void queue_mapless_event (NCDUdevManager *o, const char *devpath, NCDUdevClient *client);
46 static void process_event (NCDUdevManager *o, NCDUdevMonitor *monitor);
47 static void try_monitor (NCDUdevManager *o);
48 static void reset_monitor (NCDUdevManager *o);
49 static void timer_handler (NCDUdevManager *o);
50 static void monitor_handler_event (NCDUdevManager *o);
51 static void monitor_handler_error (NCDUdevManager *o, int is_error);
52 static void info_monitor_handler_event (NCDUdevManager *o);
53 static void info_monitor_handler_error (NCDUdevManager *o, int is_error);
54 static void next_job_handler (NCDUdevClient *o);
55  
56 static int event_to_map (NCDUdevMonitor *monitor, BStringMap *out_map)
57 {
58 NCDUdevMonitor_AssertReady(monitor);
59  
60 // init map
61 BStringMap_Init(out_map);
62  
63 // insert properties to map
64 int num_properties = NCDUdevMonitor_GetNumProperties(monitor);
65 for (int i = 0; i < num_properties; i++) {
66 const char *name;
67 const char *value;
68 NCDUdevMonitor_GetProperty(monitor, i, &name, &value);
69  
70 if (!BStringMap_Set(out_map, name, value)) {
71 BLog(BLOG_ERROR, "BStringMap_Set failed");
72 goto fail1;
73 }
74 }
75  
76 return 1;
77  
78 fail1:
79 BStringMap_Free(out_map);
80 return 0;
81 }
82  
83 static void free_event (NCDUdevClient *o, struct NCDUdevClient_event *e)
84 {
85 // remove from events list
86 LinkedList1_Remove(&o->events_list, &e->events_list_node);
87  
88 // free map
89 if (e->have_map) {
90 BStringMap_Free(&e->map);
91 }
92  
93 // free devpath
94 free(e->devpath);
95  
96 // free structure
97 free(e);
98 }
99  
100 static void queue_event (NCDUdevManager *o, NCDUdevMonitor *monitor, NCDUdevClient *client)
101 {
102 NCDUdevMonitor_AssertReady(monitor);
103  
104 // alloc event
105 struct NCDUdevClient_event *e = malloc(sizeof(*e));
106 if (!e) {
107 BLog(BLOG_ERROR, "malloc failed");
108 goto fail0;
109 }
110  
111 // build map
112 if (!event_to_map(monitor, &e->map)) {
113 goto fail1;
114 }
115  
116 // set have map
117 e->have_map = 1;
118  
119 // get devpath
120 const char *devpath = BStringMap_Get(&e->map, "DEVPATH");
121 if (!devpath) {
122 BLog(BLOG_ERROR, "DEVPATH missing");
123 goto fail2;
124 }
125  
126 // copy devpath
127 if (!(e->devpath = strdup(devpath))) {
128 BLog(BLOG_ERROR, "strdup failed");
129 goto fail2;
130 }
131  
132 // insert to client's events list
133 LinkedList1_Append(&client->events_list, &e->events_list_node);
134  
135 // if client is running, set next job
136 if (client->running) {
137 BPending_Set(&client->next_job);
138 }
139  
140 return;
141  
142 fail2:
143 BStringMap_Free(&e->map);
144 fail1:
145 free(e);
146 fail0:
147 return;
148 }
149  
150 static void queue_mapless_event (NCDUdevManager *o, const char *devpath, NCDUdevClient *client)
151 {
152 // alloc event
153 struct NCDUdevClient_event *e = malloc(sizeof(*e));
154 if (!e) {
155 BLog(BLOG_ERROR, "malloc failed");
156 goto fail0;
157 }
158  
159 // set have no map
160 e->have_map = 0;
161  
162 // copy devpath
163 if (!(e->devpath = strdup(devpath))) {
164 BLog(BLOG_ERROR, "strdup failed");
165 goto fail1;
166 }
167  
168 // insert to client's events list
169 LinkedList1_Append(&client->events_list, &e->events_list_node);
170  
171 // if client is running, set next job
172 if (client->running) {
173 BPending_Set(&client->next_job);
174 }
175  
176 return;
177  
178 fail1:
179 free(e);
180 fail0:
181 return;
182 }
183  
184 static void process_event (NCDUdevManager *o, NCDUdevMonitor *monitor)
185 {
186 NCDUdevMonitor_AssertReady(monitor);
187  
188 // build map from event
189 BStringMap map;
190 if (!event_to_map(monitor, &map)) {
191 BLog(BLOG_ERROR, "failed to build map");
192 return;
193 }
194  
195 // pass event to cache
196 if (!NCDUdevCache_Event(&o->cache, map)) {
197 BLog(BLOG_ERROR, "failed to cache");
198 BStringMap_Free(&map);
199 return;
200 }
201  
202 // queue event to clients
203 LinkedList1Node *list_node = LinkedList1_GetFirst(&o->clients_list);
204 while (list_node) {
205 NCDUdevClient *client = UPPER_OBJECT(list_node, NCDUdevClient, clients_list_node);
206 queue_event(o, monitor, client);
207 list_node = LinkedList1Node_Next(list_node);
208 }
209 }
210  
211 static void try_monitor (NCDUdevManager *o)
212 {
213 ASSERT(!o->have_monitor)
214 ASSERT(!BTimer_IsRunning(&o->restart_timer))
215  
216 int mode = (o->no_udev ? NCDUDEVMONITOR_MODE_MONITOR_KERNEL : NCDUDEVMONITOR_MODE_MONITOR_UDEV);
217  
218 // init monitor
219 if (!NCDUdevMonitor_Init(&o->monitor, o->reactor, o->manager, mode, o,
220 (NCDUdevMonitor_handler_event)monitor_handler_event,
221 (NCDUdevMonitor_handler_error)monitor_handler_error
222 )) {
223 BLog(BLOG_ERROR, "NCDUdevMonitor_Init failed");
224  
225 // set restart timer
226 BReactor_SetTimer(o->reactor, &o->restart_timer);
227 return;
228 }
229  
230 // set have monitor
231 o->have_monitor = 1;
232  
233 // set not have info monitor
234 o->have_info_monitor = 0;
235 }
236  
237 static void reset_monitor (NCDUdevManager *o)
238 {
239 ASSERT(o->have_monitor)
240 ASSERT(!o->have_info_monitor)
241 ASSERT(!BTimer_IsRunning(&o->restart_timer))
242  
243 // free monitor
244 NCDUdevMonitor_Free(&o->monitor);
245  
246 // set have no monitor
247 o->have_monitor = 0;
248  
249 // set restart timer
250 BReactor_SetTimer(o->reactor, &o->restart_timer);
251 }
252  
253 static void timer_handler (NCDUdevManager *o)
254 {
255 DebugObject_Access(&o->d_obj);
256 ASSERT(!o->have_monitor)
257  
258 // try again
259 try_monitor(o);
260 }
261  
262 static void monitor_handler_event (NCDUdevManager *o)
263 {
264 DebugObject_Access(&o->d_obj);
265 ASSERT(o->have_monitor)
266 ASSERT(!o->have_info_monitor)
267 ASSERT(!BTimer_IsRunning(&o->restart_timer))
268  
269 if (NCDUdevMonitor_IsReadyEvent(&o->monitor)) {
270 BLog(BLOG_INFO, "monitor ready");
271  
272 // init info monitor
273 if (!NCDUdevMonitor_Init(&o->info_monitor, o->reactor, o->manager, NCDUDEVMONITOR_MODE_INFO, o,
274 (NCDUdevMonitor_handler_event)info_monitor_handler_event,
275 (NCDUdevMonitor_handler_error)info_monitor_handler_error
276 )) {
277 BLog(BLOG_ERROR, "NCDUdevMonitor_Init failed");
278 reset_monitor(o);
279 return;
280 }
281  
282 // set have info monitor
283 o->have_info_monitor = 1;
284  
285 // start cache cleanup
286 NCDUdevCache_StartClean(&o->cache);
287  
288 // hold processing monitor events until info monitor is done
289 return;
290 }
291  
292 // accept event
293 NCDUdevMonitor_Done(&o->monitor);
294  
295 // process event
296 process_event(o, &o->monitor);
297 }
298  
299 static void monitor_handler_error (NCDUdevManager *o, int is_error)
300 {
301 DebugObject_Access(&o->d_obj);
302 ASSERT(o->have_monitor)
303 ASSERT(!BTimer_IsRunning(&o->restart_timer))
304  
305 BLog(BLOG_ERROR, "monitor error");
306  
307 if (o->have_info_monitor) {
308 // free info monitor
309 NCDUdevMonitor_Free(&o->info_monitor);
310  
311 // set have no info monitor
312 o->have_info_monitor = 0;
313 }
314  
315 // reset monitor
316 reset_monitor(o);
317 }
318  
319 static void info_monitor_handler_event (NCDUdevManager *o)
320 {
321 DebugObject_Access(&o->d_obj);
322 ASSERT(o->have_monitor)
323 ASSERT(o->have_info_monitor)
324 ASSERT(!BTimer_IsRunning(&o->restart_timer))
325  
326 // accept event
327 NCDUdevMonitor_Done(&o->info_monitor);
328  
329 // process event
330 process_event(o, &o->info_monitor);
331 }
332  
333 static void info_monitor_handler_error (NCDUdevManager *o, int is_error)
334 {
335 DebugObject_Access(&o->d_obj);
336 ASSERT(o->have_monitor)
337 ASSERT(o->have_info_monitor)
338 ASSERT(!BTimer_IsRunning(&o->restart_timer))
339  
340 if (is_error) {
341 BLog(BLOG_ERROR, "info monitor error");
342 } else {
343 BLog(BLOG_INFO, "info monitor finished");
344 }
345  
346 // free info monitor
347 NCDUdevMonitor_Free(&o->info_monitor);
348  
349 // set have no info monitor
350 o->have_info_monitor = 0;
351  
352 if (is_error) {
353 // reset monitor
354 reset_monitor(o);
355 } else {
356 // continue processing monitor events
357 NCDUdevMonitor_Done(&o->monitor);
358  
359 // finish cache cleanup
360 NCDUdevCache_FinishClean(&o->cache);
361  
362 // collect cleaned devices
363 BStringMap map;
364 while (NCDUdevCache_GetCleanedDevice(&o->cache, &map)) {
365 // get devpath
366 const char *devpath = BStringMap_Get(&map, "DEVPATH");
367 ASSERT(devpath)
368  
369 // queue mapless event to clients
370 LinkedList1Node *list_node = LinkedList1_GetFirst(&o->clients_list);
371 while (list_node) {
372 NCDUdevClient *client = UPPER_OBJECT(list_node, NCDUdevClient, clients_list_node);
373 queue_mapless_event(o, devpath, client);
374 list_node = LinkedList1Node_Next(list_node);
375 }
376  
377 BStringMap_Free(&map);
378 }
379 }
380 }
381  
382 static void next_job_handler (NCDUdevClient *o)
383 {
384 DebugObject_Access(&o->d_obj);
385 ASSERT(!LinkedList1_IsEmpty(&o->events_list))
386 ASSERT(o->running)
387  
388 // get event
389 struct NCDUdevClient_event *e = UPPER_OBJECT(LinkedList1_GetFirst(&o->events_list), struct NCDUdevClient_event, events_list_node);
390  
391 // grab map from event
392 int have_map = e->have_map;
393 BStringMap map = e->map;
394  
395 // grab devpath from event
396 char *devpath = e->devpath;
397  
398 // remove from events list
399 LinkedList1_Remove(&o->events_list, &e->events_list_node);
400  
401 // free structure
402 free(e);
403  
404 // schedule next event if needed
405 if (!LinkedList1_IsEmpty(&o->events_list)) {
406 BPending_Set(&o->next_job);
407 }
408  
409 // give map to handler
410 o->handler(o->user, devpath, have_map, map);
411 return;
412 }
413  
414 void NCDUdevManager_Init (NCDUdevManager *o, int no_udev, BReactor *reactor, BProcessManager *manager)
415 {
416 ASSERT(no_udev == 0 || no_udev == 1)
417  
418 // init arguments
419 o->no_udev = no_udev;
420 o->reactor = reactor;
421 o->manager = manager;
422  
423 // init clients list
424 LinkedList1_Init(&o->clients_list);
425  
426 // init cache
427 NCDUdevCache_Init(&o->cache);
428  
429 // init restart timer
430 BTimer_Init(&o->restart_timer, RESTART_TIMER_TIME, (BTimer_handler)timer_handler, o);
431  
432 // set have no monitor
433 o->have_monitor = 0;
434  
435 DebugObject_Init(&o->d_obj);
436 }
437  
438 void NCDUdevManager_Free (NCDUdevManager *o)
439 {
440 DebugObject_Free(&o->d_obj);
441 ASSERT(LinkedList1_IsEmpty(&o->clients_list))
442  
443 if (o->have_monitor) {
444 // free info monitor
445 if (o->have_info_monitor) {
446 NCDUdevMonitor_Free(&o->info_monitor);
447 }
448  
449 // free monitor
450 NCDUdevMonitor_Free(&o->monitor);
451 }
452  
453 // free restart timer
454 BReactor_RemoveTimer(o->reactor, &o->restart_timer);
455  
456 // free cache
457 NCDUdevCache_Free(&o->cache);
458 }
459  
460 const BStringMap * NCDUdevManager_Query (NCDUdevManager *o, const char *devpath)
461 {
462 DebugObject_Access(&o->d_obj);
463  
464 return NCDUdevCache_Query(&o->cache, devpath);
465 }
466  
467 void NCDUdevClient_Init (NCDUdevClient *o, NCDUdevManager *m, void *user,
468 NCDUdevClient_handler handler)
469 {
470 DebugObject_Access(&m->d_obj);
471  
472 // init arguments
473 o->m = m;
474 o->user = user;
475 o->handler = handler;
476  
477 // insert to manager's list
478 LinkedList1_Append(&m->clients_list, &o->clients_list_node);
479  
480 // init events list
481 LinkedList1_Init(&o->events_list);
482  
483 // init next job
484 BPending_Init(&o->next_job, BReactor_PendingGroup(m->reactor), (BPending_handler)next_job_handler, o);
485  
486 // set running
487 o->running = 1;
488  
489 // queue all devices from cache
490 const char *devpath = NCDUdevCache_First(&m->cache);
491 while (devpath) {
492 queue_mapless_event(m, devpath, o);
493 devpath = NCDUdevCache_Next(&m->cache, devpath);
494 }
495  
496 // if this is the first client, init monitor
497 if (!m->have_monitor && !BTimer_IsRunning(&m->restart_timer)) {
498 try_monitor(m);
499 }
500  
501 DebugObject_Init(&o->d_obj);
502 }
503  
504 void NCDUdevClient_Free (NCDUdevClient *o)
505 {
506 DebugObject_Free(&o->d_obj);
507 NCDUdevManager *m = o->m;
508  
509 // free events
510 LinkedList1Node *list_node;
511 while (list_node = LinkedList1_GetFirst(&o->events_list)) {
512 struct NCDUdevClient_event *e = UPPER_OBJECT(list_node, struct NCDUdevClient_event, events_list_node);
513 free_event(o, e);
514 }
515  
516 // free next job
517 BPending_Free(&o->next_job);
518  
519 // remove from manager's list
520 LinkedList1_Remove(&m->clients_list, &o->clients_list_node);
521 }
522  
523 void NCDUdevClient_Pause (NCDUdevClient *o)
524 {
525 DebugObject_Access(&o->d_obj);
526 ASSERT(o->running)
527  
528 // set not running
529 o->running = 0;
530  
531 // unset next job to avoid reporting queued events
532 BPending_Unset(&o->next_job);
533 }
534  
535 void NCDUdevClient_Continue (NCDUdevClient *o)
536 {
537 DebugObject_Access(&o->d_obj);
538 ASSERT(!o->running)
539  
540 // set running
541 o->running = 1;
542  
543 // set next job if we have events queued
544 if (!LinkedList1_IsEmpty(&o->events_list)) {
545 BPending_Set(&o->next_job);
546 }
547 }