f468e7c79872f6024520ff965d47bba51a1e4f32
[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_eArgError, "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 addr->destroy(addr);
454 return self;
455 }
456
457 static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
458 {
459 enumerator_t *enumerator;
460 iface_t *iface;
461 host_t *addr;
462 char buf[64];
463
464 if (!rb_block_given_p())
465 {
466 rb_raise(rb_eArgError, "must be called with a block");
467 }
468 Data_Get_Struct(self, iface_t, iface);
469 enumerator = iface->create_address_enumerator(iface);
470 while (enumerator->enumerate(enumerator, &addr))
471 {
472 snprintf(buf, sizeof(buf), "%H", addr);
473 rb_yield(rb_str_new2(buf));
474 }
475 enumerator->destroy(enumerator);
476 return self;
477 }
478
479 static VALUE iface_del_addr(VALUE self, VALUE vaddr)
480 {
481 iface_t *iface;
482 host_t *addr;
483
484 addr = host_create_from_string(StringValuePtr(vaddr), 0);
485 if (!addr)
486 {
487 rb_raise(rb_eArgError, "invalid IP address");
488 }
489 Data_Get_Struct(self, iface_t, iface);
490 if (!iface->delete_address(iface, addr))
491 {
492 addr->destroy(addr);
493 rb_raise(rb_eRuntimeError, "address not found");
494 }
495 addr->destroy(addr);
496 return self;
497 }
498
499 static VALUE iface_delete(VALUE self)
500 {
501 guest_t *guest;
502 iface_t *iface;
503
504 Data_Get_Struct(self, iface_t, iface);
505 guest = iface->get_guest(iface);
506 guest->destroy_iface(guest, iface);
507 return Qnil;
508 }
509
510 static void iface_init()
511 {
512 rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject);
513 rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
514 rb_define_method(rbc_iface, "connect", iface_connect, 1);
515 rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
516 rb_define_method(rbc_iface, "add", iface_add_addr, 1);
517 rb_define_method(rbc_iface, "del", iface_del_addr, 1);
518 rb_define_method(rbc_iface, "each", iface_each_addr, -1);
519 rb_define_method(rbc_iface, "delete", iface_delete, 0);
520 rb_include_module(rbc_iface, rb_mEnumerable);
521 }
522
523 static VALUE template_load(VALUE class, VALUE name)
524 {
525 if (!dumm->load_template(dumm, StringValuePtr(name)))
526 {
527 rb_raise(rb_eRuntimeError, "loading template failed");
528 }
529 return class;
530 }
531
532 static VALUE template_unload(VALUE class)
533 {
534 if (!dumm->load_template(dumm, NULL))
535 {
536 rb_raise(rb_eRuntimeError, "unloading template failed");
537 }
538 return class;
539 }
540
541 static void template_init()
542 {
543 rbc_template = rb_define_class_under(rbm_dumm , "Template", rb_cObject);
544 rb_define_singleton_method(rbc_template, "load", template_load, 1);
545 rb_define_singleton_method(rbc_template, "unload", template_unload, 0);
546 }
547
548 /**
549 * main routine, parses args and reads from console
550 */
551 int main(int argc, char *argv[])
552 {
553 int state, i;
554 struct sigaction action;
555 char buf[512];
556
557 ruby_init();
558 ruby_init_loadpath();
559
560 /* there are too many to report, rubyruby... */
561 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
562
563 library_init(NULL);
564
565 dumm = dumm_create(NULL);
566
567 rbm_dumm = rb_define_module("Dumm");
568
569 guest_init();
570 bridge_init();
571 iface_init();
572 template_init();
573
574 sigemptyset(&action.sa_mask);
575 action.sa_flags = SA_SIGINFO;
576 action.sa_sigaction = sigchld_handler;
577 sigaction(SIGCHLD, &action, NULL);
578 action.sa_sigaction = sigint_handler;
579 sigaction(SIGINT, &action, NULL);
580 sigaction(SIGTERM, &action, NULL);
581 sigaction(SIGSEGV, &action, NULL);
582 sigaction(SIGHUP, &action, NULL);
583
584 rb_eval_string_protect("include Dumm", &state);
585 if (state)
586 {
587 rb_p(ruby_errinfo);
588 }
589 for (i = 1; i < argc; i++)
590 {
591 snprintf(buf, sizeof(buf), "load \"%s\"", argv[i]);
592 printf("%s\n", buf);
593 rb_eval_string_protect(buf, &state);
594 if (state)
595 {
596 rb_p(ruby_errinfo);
597 }
598 }
599 rb_require("irb");
600 rb_require("irb/completion");
601 rb_eval_string_protect("IRB.start", &state);
602 if (state)
603 {
604 rb_p(ruby_errinfo);
605 }
606
607 dumm->destroy(dumm);
608
609 action.sa_handler = SIG_DFL;
610 action.sa_flags = 0;
611 sigaction(SIGCHLD, &action, NULL);
612
613 library_deinit();
614 ruby_finalize();
615 return 0;
616 }
617