cd92d2b60542b596c83ae423311345ad0c0e0580
[strongswan.git] / src / dumm / irdumm.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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 <stdio.h>
17 #include <signal.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20
21 #include <library.h>
22 #include <dumm.h>
23 #include <debug.h>
24
25 #undef PACKAGE_NAME
26 #undef PACKAGE_TARNAME
27 #undef PACKAGE_VERSION
28 #undef PACKAGE_STRING
29 #include <ruby.h>
30
31 dumm_t *dumm;
32
33 VALUE rbm_dumm;
34 VALUE rbc_guest;
35 VALUE rbc_bridge;
36 VALUE rbc_iface;
37 VALUE rbc_template;
38
39 /**
40 * Guest invocation callback
41 */
42 static pid_t invoke(void *null, guest_t *guest, char *args[], int argc)
43 {
44 pid_t pid;
45
46 args[argc++] = "con0=xterm";
47 args[argc++] = "xterm=gnome-terminal,-t,-x";
48
49 pid = fork();
50 switch (pid)
51 {
52 case 0: /* child */
53 dup2(open("/dev/null", 0), 1);
54 dup2(open("/dev/null", 0), 2);
55 execvp(args[0], args);
56 /* FALL */
57 case -1:
58 return 0;
59 default:
60 return pid;
61 }
62 }
63
64 /**
65 * SIGCHLD signal handler
66 */
67 static void sigchld_handler(int signal, siginfo_t *info, void* ptr)
68 {
69 enumerator_t *enumerator;
70 guest_t *guest;
71
72 enumerator = dumm->create_guest_enumerator(dumm);
73 while (enumerator->enumerate(enumerator, &guest))
74 {
75 if (guest->get_pid(guest) == info->si_pid)
76 {
77 guest->sigchild(guest);
78 break;
79 }
80 }
81 enumerator->destroy(enumerator);
82 }
83
84 /**
85 * SIGINT/SEGV/TERM signal handler
86 */
87 static void sigint_handler(int signal, siginfo_t *info, void* ptr)
88 {
89 struct sigaction action;
90
91 dumm->destroy(dumm);
92
93 action.sa_handler = SIG_DFL;
94 action.sa_flags = 0;
95 sigaction(SIGCHLD, &action, NULL);
96
97 library_deinit();
98 exit(0);
99 }
100
101 /**
102 * Guest bindings
103 */
104 static VALUE guest_get(VALUE class, VALUE key)
105 {
106 enumerator_t *enumerator;
107 guest_t *guest, *found = NULL;
108
109 enumerator = dumm->create_guest_enumerator(dumm);
110 while (enumerator->enumerate(enumerator, &guest))
111 {
112 if (streq(guest->get_name(guest), StringValuePtr(key)))
113 {
114 found = guest;
115 break;
116 }
117 }
118 enumerator->destroy(enumerator);
119 if (!found)
120 {
121 rb_raise(rb_eRuntimeError, "guest not found");
122 }
123 return Data_Wrap_Struct(class, NULL, NULL, found);
124 }
125
126 static VALUE guest_each(int argc, VALUE *argv, VALUE class)
127 {
128 enumerator_t *enumerator;
129 guest_t *guest;
130
131 if (!rb_block_given_p())
132 {
133 rb_raise(rb_eArgError, "must be called with a block");
134 }
135 enumerator = dumm->create_guest_enumerator(dumm);
136 while (enumerator->enumerate(enumerator, &guest))
137 {
138 rb_yield(Data_Wrap_Struct(class, NULL, NULL, guest));
139 }
140 enumerator->destroy(enumerator);
141 return class;
142 }
143
144 static VALUE guest_new(VALUE class, VALUE name, VALUE kernel,
145 VALUE master, VALUE mem)
146 {
147 guest_t *guest;
148
149 guest = dumm->create_guest(dumm, StringValuePtr(name), StringValuePtr(kernel),
150 StringValuePtr(master), FIX2INT(mem));
151 if (!guest)
152 {
153 rb_raise(rb_eRuntimeError, "creating guest failed");
154 }
155 return Data_Wrap_Struct(class, NULL, NULL, guest);
156 }
157
158 static VALUE guest_to_s(VALUE self)
159 {
160 guest_t *guest;
161
162 Data_Get_Struct(self, guest_t, guest);
163 return rb_str_new2(guest->get_name(guest));
164 }
165
166 static VALUE guest_start(VALUE self)
167 {
168 guest_t *guest;
169
170 Data_Get_Struct(self, guest_t, guest);
171
172 if (!guest->start(guest, invoke, NULL, NULL))
173 {
174 rb_raise(rb_eRuntimeError, "starting guest failed");
175 }
176 return self;
177 }
178
179 static VALUE guest_stop(VALUE self)
180 {
181 guest_t *guest;
182
183 Data_Get_Struct(self, guest_t, guest);
184 guest->stop(guest, NULL);
185 return self;
186 }
187
188 static void exec_cb(void *data, char *buf)
189 {
190 rb_yield(rb_str_new2(buf));
191 }
192
193 static VALUE guest_exec(VALUE self, VALUE cmd)
194 {
195 guest_t *guest;
196 bool block;
197
198 block = rb_block_given_p();
199 Data_Get_Struct(self, guest_t, guest);
200 if (guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
201 "%s", StringValuePtr(cmd)) != 0)
202 {
203 rb_raise(rb_eRuntimeError, "executing command failed");
204 }
205 return self;
206 }
207
208 static VALUE guest_add_iface(VALUE self, VALUE name)
209 {
210 guest_t *guest;
211 iface_t *iface;
212
213 Data_Get_Struct(self, guest_t, guest);
214 iface = guest->create_iface(guest, StringValuePtr(name));
215 if (!iface)
216 {
217 rb_raise(rb_eRuntimeError, "adding interface failed");
218 }
219 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
220 }
221
222 static VALUE guest_get_iface(VALUE self, VALUE key)
223 {
224 enumerator_t *enumerator;
225 iface_t *iface, *found = NULL;
226 guest_t *guest;
227
228 Data_Get_Struct(self, guest_t, guest);
229 enumerator = guest->create_iface_enumerator(guest);
230 while (enumerator->enumerate(enumerator, &iface))
231 {
232 if (streq(iface->get_guestif(iface), StringValuePtr(key)))
233 {
234 found = iface;
235 break;
236 }
237 }
238 enumerator->destroy(enumerator);
239 if (!found)
240 {
241 rb_raise(rb_eRuntimeError, "interface not found");
242 }
243 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
244 }
245
246 static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self)
247 {
248 enumerator_t *enumerator;
249 guest_t *guest;
250 iface_t *iface;
251
252 if (!rb_block_given_p())
253 {
254 rb_raise(rb_eArgError, "must be called with a block");
255 }
256 Data_Get_Struct(self, guest_t, guest);
257 enumerator = guest->create_iface_enumerator(guest);
258 while (enumerator->enumerate(enumerator, &iface))
259 {
260 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
261 }
262 enumerator->destroy(enumerator);
263 return self;
264 }
265
266 static VALUE guest_delete(VALUE self)
267 {
268 guest_t *guest;
269
270 Data_Get_Struct(self, guest_t, guest);
271 dumm->delete_guest(dumm, guest);
272 return Qnil;
273 }
274
275 static void guest_init()
276 {
277 rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject);
278 rb_define_singleton_method(rbc_guest, "[]", guest_get, 1);
279 rb_define_singleton_method(rbc_guest, "each", guest_each, -1);
280 rb_define_singleton_method(rbc_guest, "new", guest_new, 4);
281 rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
282 rb_define_method(rbc_guest, "start", guest_start, 0);
283 rb_define_method(rbc_guest, "stop", guest_stop, 0);
284 rb_define_method(rbc_guest, "exec", guest_exec, 1);
285 rb_define_method(rbc_guest, "add", guest_add_iface, 1);
286 rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
287 rb_define_method(rbc_guest, "each", guest_each_iface, -1);
288 rb_define_method(rbc_guest, "delete", guest_delete, 0);
289 rb_include_module(rb_class_of(rbc_guest), rb_mEnumerable);
290 rb_include_module(rbc_guest, rb_mEnumerable);
291 }
292
293 /**
294 * Bridge binding
295 */
296 static VALUE bridge_get(VALUE class, VALUE key)
297 {
298 enumerator_t *enumerator;
299 bridge_t *bridge, *found = NULL;
300
301 enumerator = dumm->create_bridge_enumerator(dumm);
302 while (enumerator->enumerate(enumerator, &bridge))
303 {
304 if (streq(bridge->get_name(bridge), StringValuePtr(key)))
305 {
306 found = bridge;
307 break;
308 }
309 }
310 enumerator->destroy(enumerator);
311 if (!found)
312 {
313 rb_raise(rb_eRuntimeError, "bridge not found");
314 }
315 return Data_Wrap_Struct(class, NULL, NULL, found);
316 }
317
318 static VALUE bridge_each(int argc, VALUE *argv, VALUE class)
319 {
320 enumerator_t *enumerator;
321 bridge_t *bridge;
322
323 if (!rb_block_given_p())
324 {
325 rb_raise(rb_eArgError, "must be called with a block");
326 }
327 enumerator = dumm->create_bridge_enumerator(dumm);
328 while (enumerator->enumerate(enumerator, &bridge))
329 {
330 rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge));
331 }
332 enumerator->destroy(enumerator);
333 return class;
334 }
335
336 static VALUE bridge_new(VALUE class, VALUE name)
337
338 {
339 bridge_t *bridge;
340
341 bridge = dumm->create_bridge(dumm, StringValuePtr(name));
342 if (!bridge)
343 {
344 rb_raise(rb_eRuntimeError, "creating bridge failed");
345 }
346 return Data_Wrap_Struct(class, NULL, NULL, bridge);
347 }
348
349 static VALUE bridge_to_s(VALUE self)
350 {
351 bridge_t *bridge;
352
353 Data_Get_Struct(self, bridge_t, bridge);
354 return rb_str_new2(bridge->get_name(bridge));
355 }
356
357 static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self)
358 {
359 enumerator_t *enumerator;
360 bridge_t *bridge;
361 iface_t *iface;
362
363 if (!rb_block_given_p())
364 {
365 rb_raise(rb_eArgError, "must be called with a block");
366 }
367 Data_Get_Struct(self, bridge_t, bridge);
368 enumerator = bridge->create_iface_enumerator(bridge);
369 while (enumerator->enumerate(enumerator, &iface))
370 {
371 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
372 }
373 enumerator->destroy(enumerator);
374 return self;
375 }
376
377 static VALUE bridge_delete(VALUE self)
378 {
379 bridge_t *bridge;
380
381 Data_Get_Struct(self, bridge_t, bridge);
382 dumm->delete_bridge(dumm, bridge);
383 return Qnil;
384 }
385
386 static void bridge_init()
387 {
388 rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject);
389 rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1);
390 rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1);
391 rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1);
392 rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0);
393 rb_define_method(rbc_bridge, "each", bridge_each_iface, -1);
394 rb_define_method(rbc_bridge, "delete", bridge_delete, 0);
395 rb_include_module(rb_class_of(rbc_bridge), rb_mEnumerable);
396 rb_include_module(rbc_bridge, rb_mEnumerable);
397 }
398
399 /**
400 * Iface wrapper
401 */
402 static VALUE iface_to_s(VALUE self)
403 {
404 iface_t *iface;
405
406 Data_Get_Struct(self, iface_t, iface);
407 return rb_str_new2(iface->get_hostif(iface));
408 }
409
410 static VALUE iface_connect(VALUE self, VALUE vbridge)
411 {
412 iface_t *iface;
413 bridge_t *bridge;
414
415 Data_Get_Struct(self, iface_t, iface);
416 Data_Get_Struct(vbridge, bridge_t, bridge);
417 if (!bridge->connect_iface(bridge, iface))
418 {
419 rb_raise(rb_eRuntimeError, "connecting iface failed");
420 }
421 return self;
422 }
423
424 static VALUE iface_disconnect(VALUE self)
425 {
426 iface_t *iface;
427 bridge_t *bridge;
428
429 Data_Get_Struct(self, iface_t, iface);
430 bridge = iface->get_bridge(iface);
431 if (!bridge || !bridge->disconnect_iface(bridge, iface))
432 {
433 rb_raise(rb_eRuntimeError, "disconnecting iface failed");
434 }
435 return self;
436 }
437
438 static VALUE iface_add_addr(VALUE self, VALUE name)
439 {
440 iface_t *iface;
441 host_t *addr;
442
443 addr = host_create_from_string(StringValuePtr(name), 0);
444 if (!addr)
445 {
446 rb_raise(rb_eRuntimeError, "invalid IP address");
447 }
448 Data_Get_Struct(self, iface_t, iface);
449 if (!iface->add_address(iface, addr))
450 {
451 rb_raise(rb_eRuntimeError, "adding address failed");
452 }
453 return self;
454 }
455
456 static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
457 {
458 enumerator_t *enumerator;
459 iface_t *iface;
460 host_t *addr;
461 char buf[64];
462
463 if (!rb_block_given_p())
464 {
465 rb_raise(rb_eArgError, "must be called with a block");
466 }
467 Data_Get_Struct(self, iface_t, iface);
468 enumerator = iface->create_address_enumerator(iface);
469 while (enumerator->enumerate(enumerator, &addr))
470 {
471 snprintf(buf, sizeof(buf), "%H", addr);
472 rb_yield(rb_str_new2(buf));
473 }
474 enumerator->destroy(enumerator);
475 return self;
476 }
477
478 static VALUE iface_del_addr(VALUE self, VALUE vaddr)
479 {
480 iface_t *iface;
481 host_t *addr;
482
483 addr = host_create_from_string(StringValuePtr(vaddr), 0);
484 Data_Get_Struct(self, iface_t, iface);
485 if (!iface->delete_address(iface, addr))
486 {
487 addr->destroy(addr);
488 rb_raise(rb_eRuntimeError, "address not found");
489 }
490 addr->destroy(addr);
491 return self;
492 }
493
494 static VALUE iface_delete(VALUE self)
495 {
496 guest_t *guest;
497 iface_t *iface;
498
499 Data_Get_Struct(self, iface_t, iface);
500 guest = iface->get_guest(iface);
501 guest->destroy_iface(guest, iface);
502 return Qnil;
503 }
504
505 static void iface_init()
506 {
507 rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject);
508 rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
509 rb_define_method(rbc_iface, "connect", iface_connect, 1);
510 rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
511 rb_define_method(rbc_iface, "add", iface_add_addr, 1);
512 rb_define_method(rbc_iface, "del", iface_del_addr, 1);
513 rb_define_method(rbc_iface, "each", iface_each_addr, -1);
514 rb_define_method(rbc_iface, "delete", iface_delete, 0);
515 rb_include_module(rbc_iface, rb_mEnumerable);
516 }
517
518 static VALUE template_load(VALUE class, VALUE name)
519 {
520 if (!dumm->load_template(dumm, StringValuePtr(name)))
521 {
522 rb_raise(rb_eRuntimeError, "loading template failed");
523 }
524 return class;
525 }
526
527 static VALUE template_unload(VALUE class)
528 {
529 if (!dumm->load_template(dumm, NULL))
530 {
531 rb_raise(rb_eRuntimeError, "unloading template failed");
532 }
533 return class;
534 }
535
536 static void template_init()
537 {
538 rbc_template = rb_define_class_under(rbm_dumm , "Template", rb_cObject);
539 rb_define_singleton_method(rbc_template, "load", template_load, 1);
540 rb_define_singleton_method(rbc_template, "unload", template_unload, 0);
541 }
542
543 /**
544 * main routine, parses args and reads from console
545 */
546 int main(int argc, char *argv[])
547 {
548 int state, i;
549 struct sigaction action;
550 char buf[512];
551
552 ruby_init();
553 ruby_init_loadpath();
554
555 /* there are too many to report, rubyruby... */
556 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
557
558 library_init(NULL);
559
560 dumm = dumm_create(NULL);
561
562 rbm_dumm = rb_define_module("Dumm");
563
564 guest_init();
565 bridge_init();
566 iface_init();
567 template_init();
568
569 sigemptyset(&action.sa_mask);
570 action.sa_flags = SA_SIGINFO;
571 action.sa_sigaction = sigchld_handler;
572 sigaction(SIGCHLD, &action, NULL);
573 action.sa_sigaction = sigint_handler;
574 sigaction(SIGINT, &action, NULL);
575 sigaction(SIGTERM, &action, NULL);
576 sigaction(SIGSEGV, &action, NULL);
577 sigaction(SIGHUP, &action, NULL);
578
579 rb_eval_string_protect("include Dumm", &state);
580 if (state)
581 {
582 rb_p(ruby_errinfo);
583 }
584 for (i = 1; i < argc; i++)
585 {
586 snprintf(buf, sizeof(buf), "load \"%s\"", argv[i]);
587 printf("%s\n", buf);
588 rb_eval_string_protect(buf, &state);
589 if (state)
590 {
591 rb_p(ruby_errinfo);
592 }
593 }
594 rb_require("irb");
595 rb_require("irb/completion");
596 rb_eval_string_protect("IRB.start", &state);
597 if (state)
598 {
599 rb_p(ruby_errinfo);
600 }
601
602 dumm->destroy(dumm);
603
604 action.sa_handler = SIG_DFL;
605 action.sa_flags = 0;
606 sigaction(SIGCHLD, &action, NULL);
607
608 library_deinit();
609 ruby_finalize();
610 return 0;
611 }
612