diff options
author | Martin Willi <martin@strongswan.org> | 2008-07-04 14:21:41 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2008-07-04 14:21:41 +0000 |
commit | ca275ae2ca58fd645fb5e26684ee1df2f8770a19 (patch) | |
tree | f888bc294d5369a38dfaaaef9bff77133bd594a9 /src | |
parent | 4302d4f0120cebe54c90ae7ecf55a90f641eb105 (diff) | |
download | strongswan-ca275ae2ca58fd645fb5e26684ee1df2f8770a19.tar.bz2 strongswan-ca275ae2ca58fd645fb5e26684ee1df2f8770a19.tar.xz |
prototype of irdumm - interactive ruby shell for dumm
Diffstat (limited to 'src')
-rw-r--r-- | src/dumm/Makefile.am | 12 | ||||
-rw-r--r-- | src/dumm/dumm.c | 11 | ||||
-rw-r--r-- | src/dumm/guest.c | 2 | ||||
-rw-r--r-- | src/dumm/guest.h | 4 | ||||
-rw-r--r-- | src/dumm/iface.c | 32 | ||||
-rw-r--r-- | src/dumm/iface.h | 24 | ||||
-rw-r--r-- | src/dumm/irdumm.c | 465 |
7 files changed, 525 insertions, 25 deletions
diff --git a/src/dumm/Makefile.am b/src/dumm/Makefile.am index 1e47e8907..815f38d1b 100644 --- a/src/dumm/Makefile.am +++ b/src/dumm/Makefile.am @@ -1,14 +1,18 @@ lib_LTLIBRARIES = libdumm.la -ipsec_PROGRAMS = dumm testing +ipsec_PROGRAMS = dumm testing irdumm libdumm_la_SOURCES = dumm.c dumm.h guest.c guest.h iface.c iface.h \ bridge.c bridge.h mconsole.c mconsole.h cowfs.h cowfs.c dumm_SOURCES = main.c testing_SOURCES = testing.c +irdumm_SOURCES = irdumm.c -libdumm_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lbridge -lfuse -lutil -dumm_LDADD = -ldumm ${gtk_LIBS} +libdumm_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \ + -lbridge -lfuse -lutil +dumm_LDADD = -ldumm ${gtk_LIBS} testing_LDADD = -ldumm +irdumm_LDADD = -ldumm -lruby1.8 -INCLUDES = -I$(top_srcdir)/src/libstrongswan ${gtk_CFLAGS} +INCLUDES = -I$(top_srcdir)/src/libstrongswan ${gtk_CFLAGS} \ + -I/usr/lib/ruby/1.8/i486-linux/ AM_CFLAGS = -D_FILE_OFFSET_BITS=64 diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c index 5db8eaee0..0bb74e886 100644 --- a/src/dumm/dumm.c +++ b/src/dumm/dumm.c @@ -49,8 +49,6 @@ struct private_dumm_t { linked_list_t *guests; /** list of managed bridges */ linked_list_t *bridges; - /** do not catch signals if we are destroying */ - bool destroying; }; /** @@ -219,8 +217,11 @@ static void destroy(private_dumm_t *this) } enumerator->destroy(enumerator); - this->destroying = TRUE; - this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy)); + while (this->guests->remove_last(this->guests, (void**)&guest) == SUCCESS) + { + guest->destroy(guest); + } + this->guests->destroy(this->guests); free(this->guest_dir); free(this->template_dir); free(this->template); @@ -279,8 +280,6 @@ dumm_t *dumm_create(char *dir) this->public.load_template = (bool(*)(dumm_t*, char *name))load_template; this->public.destroy = (void(*)(dumm_t*))destroy; - this->destroying = FALSE; - if (dir && *dir == '/') { this->dir = strdup(dir); diff --git a/src/dumm/guest.c b/src/dumm/guest.c index d43f46d99..75d0245d8 100644 --- a/src/dumm/guest.c +++ b/src/dumm/guest.c @@ -114,7 +114,7 @@ static iface_t* create_iface(private_guest_t *this, char *name) } enumerator->destroy(enumerator); - iface = iface_create(this->name, name, this->mconsole); + iface = iface_create(name, &this->public, this->mconsole); if (iface) { this->ifaces->insert_last(this->ifaces, iface); diff --git a/src/dumm/guest.h b/src/dumm/guest.h index 79a47fa62..919726d0c 100644 --- a/src/dumm/guest.h +++ b/src/dumm/guest.h @@ -19,11 +19,11 @@ #include <library.h> #include <utils/enumerator.h> -#include "iface.h" - typedef enum guest_state_t guest_state_t; typedef struct guest_t guest_t; +#include "iface.h" + /** * @brief State of a guest (started, stopped, ...) */ diff --git a/src/dumm/iface.c b/src/dumm/iface.c index b1fc641d0..a7d62ffe0 100644 --- a/src/dumm/iface.c +++ b/src/dumm/iface.c @@ -39,6 +39,8 @@ struct private_iface_t { char *hostif; /** bridge this interface is attached to */ bridge_t *bridge; + /** guest this interface is attached to */ + guest_t *guest; /** mconsole for guest */ mconsole_t *mconsole; }; @@ -104,6 +106,22 @@ static void set_bridge(private_iface_t *this, bridge_t *bridge) } /** + * Implementation of iface_t.get_bridge + */ +static bridge_t *get_bridge(private_iface_t *this) +{ + return this->bridge; +} + +/** + * Implementation of iface_t.get_guest + */ +static guest_t* get_guest(private_iface_t *this) +{ + return this->guest; +} + +/** * destroy the tap device */ static bool destroy_tap(private_iface_t *this) @@ -139,14 +157,15 @@ static bool destroy_tap(private_iface_t *this) /** * create the tap device */ -static char* create_tap(private_iface_t *this, char *guest) +static char* create_tap(private_iface_t *this) { struct ifreq ifr; int tap; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s-%s", guest, this->guestif); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s-%s", + this->guest->get_name(this->guest), this->guestif); tap = open(TAP_DEVICE, O_RDWR); if (tap < 0) @@ -185,18 +204,21 @@ static void destroy(private_iface_t *this) /** * create the iface instance */ -iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole) +iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole) { private_iface_t *this = malloc_thing(private_iface_t); this->public.get_hostif = (char*(*)(iface_t*))get_hostif; this->public.get_guestif = (char*(*)(iface_t*))get_guestif; this->public.set_bridge = (void(*)(iface_t*, bridge_t*))set_bridge; + this->public.get_bridge = (bridge_t*(*)(iface_t*))get_bridge; + this->public.get_guest = (guest_t*(*)(iface_t*))get_guest; this->public.destroy = (void*)destroy; this->mconsole = mconsole; - this->guestif = strdup(guestif); - this->hostif = create_tap(this, guest); + this->guestif = strdup(name); + this->guest = guest; + this->hostif = create_tap(this); this->bridge = NULL; if (this->hostif == NULL) { diff --git a/src/dumm/iface.h b/src/dumm/iface.h index e04fe4ed1..e646724f0 100644 --- a/src/dumm/iface.h +++ b/src/dumm/iface.h @@ -25,6 +25,7 @@ typedef struct iface_t iface_t; #include "mconsole.h" #include "bridge.h" +#include "guest.h" /** * @brief Interface in a guest, connected to a tap device on the host. @@ -52,10 +53,19 @@ struct iface_t { */ void (*set_bridge)(iface_t *this, bridge_t *bridge); - /* - bool (*add_addr) (iface_t *this, host_t *addr); - enumerator_t* (*create_addr_enumerator) (iface_t *this); - */ + /** + * @brief Get the bridge this iface is connected, or NULL. + * + * @return connected bridge, or NULL + */ + bridge_t* (*get_bridge)(iface_t *this); + + /** + * @brief Get the guest this iface belongs to. + * + * @return guest of this iface + */ + guest_t* (*get_guest)(iface_t *this); /** * @brief Destroy an interface @@ -66,12 +76,12 @@ struct iface_t { /** * @brief Create a new interface for a guest * - * @param guest name of the guest for this interface - * @param guestif name of the interface in the guest + * @param name name of the interface in the guest + * @param guest guest this iface is connecting * @param mconsole mconsole of guest * @return interface descriptor, or NULL if failed */ -iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole); +iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole); #endif /* IFACE_H */ diff --git a/src/dumm/irdumm.c b/src/dumm/irdumm.c new file mode 100644 index 000000000..598908327 --- /dev/null +++ b/src/dumm/irdumm.c @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> + +#include <library.h> +#include <dumm.h> + +#undef PACKAGE_NAME +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef PACKAGE_STRING +#include <ruby.h> + +dumm_t *dumm; + +VALUE rbm_dumm; +VALUE rbc_guest; +VALUE rbc_bridge; +VALUE rbc_iface; + +/** + * Guest invocation callback + */ +static pid_t invoke(void *null, guest_t *guest, char *args[], int argc) +{ + pid_t pid; + + args[argc] = "con0=xterm"; + + pid = fork(); + switch (pid) + { + case 0: /* child */ + dup2(open("/dev/null", 0), 1); + dup2(open("/dev/null", 0), 2); + execvp(args[0], args); + /* FALL */ + case -1: + rb_raise(rb_eException, "starting guest failed"); + return 0; + default: + return pid; + } +} + +/** + * SIGCHLD signal handler + */ +static void sigchld_handler(int signal, siginfo_t *info, void* ptr) +{ + enumerator_t *enumerator; + guest_t *guest; + + enumerator = dumm->create_guest_enumerator(dumm); + while (enumerator->enumerate(enumerator, &guest)) + { + if (guest->get_pid(guest) == info->si_pid) + { + guest->sigchild(guest); + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Guest bindings + */ +static VALUE guest_get(VALUE class, VALUE key) +{ + enumerator_t *enumerator; + guest_t *guest, *found = NULL; + + enumerator = dumm->create_guest_enumerator(dumm); + while (enumerator->enumerate(enumerator, &guest)) + { + if (streq(guest->get_name(guest), StringValuePtr(key))) + { + found = guest; + break; + } + } + enumerator->destroy(enumerator); + if (!found) + { + return Qnil; + } + return Data_Wrap_Struct(class, NULL, NULL, found); +} + +static VALUE guest_each(int argc, VALUE *argv, VALUE class) +{ + enumerator_t *enumerator; + guest_t *guest; + + if (!rb_block_given_p()) + { + rb_raise(rb_eArgError, "must be called with a block"); + } + enumerator = dumm->create_guest_enumerator(dumm); + while (enumerator->enumerate(enumerator, &guest)) + { + rb_yield(Data_Wrap_Struct(class, NULL, NULL, guest)); + } + enumerator->destroy(enumerator); + return Qnil; +} + +static VALUE guest_new(VALUE class, VALUE name, VALUE kernel, + VALUE master, VALUE mem) + +{ + guest_t *guest; + + guest = dumm->create_guest(dumm, StringValuePtr(name), StringValuePtr(kernel), + StringValuePtr(master), FIX2INT(mem)); + if (!guest) + { + return Qnil; + } + return Data_Wrap_Struct(class, NULL, NULL, guest); +} + +static VALUE guest_to_s(VALUE self) +{ + guest_t *guest; + + Data_Get_Struct(self, guest_t, guest); + return rb_str_new2(guest->get_name(guest)); +} + +static VALUE guest_start(VALUE self) +{ + guest_t *guest; + + Data_Get_Struct(self, guest_t, guest); + + if (guest->start(guest, invoke, NULL, NULL)) + { + return Qtrue; + } + return Qfalse; +} + +static VALUE guest_stop(VALUE self) +{ + guest_t *guest; + + Data_Get_Struct(self, guest_t, guest); + + if (guest->stop(guest, NULL)) + { + return Qtrue; + } + return Qfalse; +} + +static VALUE guest_add_iface(VALUE self, VALUE name) +{ + guest_t *guest; + iface_t *iface; + + Data_Get_Struct(self, guest_t, guest); + iface = guest->create_iface(guest, StringValuePtr(name)); + if (iface) + { + return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface); + } + return Qnil; +} + +static VALUE guest_get_iface(VALUE self, VALUE key) +{ + enumerator_t *enumerator; + iface_t *iface, *found = NULL; + guest_t *guest; + + Data_Get_Struct(self, guest_t, guest); + enumerator = guest->create_iface_enumerator(guest); + while (enumerator->enumerate(enumerator, &iface)) + { + if (streq(iface->get_guestif(iface), StringValuePtr(key))) + { + found = iface; + break; + } + } + enumerator->destroy(enumerator); + if (!found) + { + return Qnil; + } + return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface); +} + +static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self) +{ + enumerator_t *enumerator; + guest_t *guest; + iface_t *iface; + + if (!rb_block_given_p()) + { + rb_raise(rb_eArgError, "must be called with a block"); + } + Data_Get_Struct(self, guest_t, guest); + enumerator = guest->create_iface_enumerator(guest); + while (enumerator->enumerate(enumerator, &iface)) + { + rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface)); + } + enumerator->destroy(enumerator); + return Qnil; +} + +static VALUE guest_delete(VALUE self) +{ + guest_t *guest; + + Data_Get_Struct(self, guest_t, guest); + dumm->delete_guest(dumm, guest); + return Qnil; +} + +static void guest_init() +{ + rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject); + rb_define_singleton_method(rbc_guest, "[]", guest_get, 1); + rb_define_singleton_method(rbc_guest, "each", guest_each, -1); + rb_define_singleton_method(rbc_guest, "new", guest_new, 4); + rb_define_method(rbc_guest, "to_s", guest_to_s, 0); + rb_define_method(rbc_guest, "start", guest_start, 0); + rb_define_method(rbc_guest, "stop", guest_stop, 0); + rb_define_method(rbc_guest, "add", guest_add_iface, 1); + rb_define_method(rbc_guest, "[]", guest_get_iface, 1); + rb_define_method(rbc_guest, "each", guest_each_iface, -1); + rb_define_method(rbc_guest, "delete", guest_delete, 0); +} + +/** + * Bridge binding + */ +static VALUE bridge_get(VALUE class, VALUE key) +{ + enumerator_t *enumerator; + bridge_t *bridge, *found = NULL; + + enumerator = dumm->create_bridge_enumerator(dumm); + while (enumerator->enumerate(enumerator, &bridge)) + { + if (streq(bridge->get_name(bridge), StringValuePtr(key))) + { + found = bridge; + break; + } + } + enumerator->destroy(enumerator); + if (!found) + { + return Qnil; + } + return Data_Wrap_Struct(class, NULL, NULL, found); +} + +static VALUE bridge_each(int argc, VALUE *argv, VALUE class) +{ + enumerator_t *enumerator; + bridge_t *bridge; + + if (!rb_block_given_p()) + { + rb_raise(rb_eArgError, "must be called with a block"); + } + enumerator = dumm->create_bridge_enumerator(dumm); + while (enumerator->enumerate(enumerator, &bridge)) + { + rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge)); + } + enumerator->destroy(enumerator); + return Qnil; +} + +static VALUE bridge_new(VALUE class, VALUE name) + +{ + bridge_t *bridge; + + bridge = dumm->create_bridge(dumm, StringValuePtr(name)); + if (!bridge) + { + return Qnil; + } + return Data_Wrap_Struct(class, NULL, NULL, bridge); +} + +static VALUE bridge_to_s(VALUE self) +{ + bridge_t *bridge; + + Data_Get_Struct(self, bridge_t, bridge); + return rb_str_new2(bridge->get_name(bridge)); +} + +static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self) +{ + enumerator_t *enumerator; + bridge_t *bridge; + iface_t *iface; + + if (!rb_block_given_p()) + { + rb_raise(rb_eArgError, "must be called with a block"); + } + Data_Get_Struct(self, bridge_t, bridge); + enumerator = bridge->create_iface_enumerator(bridge); + while (enumerator->enumerate(enumerator, &iface)) + { + rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface)); + } + enumerator->destroy(enumerator); + return Qnil; +} + +static VALUE bridge_delete(VALUE self) +{ + bridge_t *bridge; + + Data_Get_Struct(self, bridge_t, bridge); + dumm->delete_bridge(dumm, bridge); + return Qnil; +} + +static void bridge_init() +{ + rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject); + rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1); + rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1); + rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1); + rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0); + rb_define_method(rbc_bridge, "each", bridge_each_iface, -1); + rb_define_method(rbc_bridge, "delete", bridge_delete, 0); +} + +/** + * Iface wrapper + */ +static VALUE iface_to_s(VALUE self) +{ + iface_t *iface; + + Data_Get_Struct(self, iface_t, iface); + return rb_str_new2(iface->get_hostif(iface)); +} + +static VALUE iface_connect(VALUE self, VALUE vbridge) +{ + iface_t *iface; + bridge_t *bridge; + + Data_Get_Struct(self, iface_t, iface); + Data_Get_Struct(vbridge, bridge_t, bridge); + if (bridge->connect_iface(bridge, iface)) + { + return self; + } + return Qnil; +} + +static VALUE iface_disconnect(VALUE self) +{ + iface_t *iface; + bridge_t *bridge; + + Data_Get_Struct(self, iface_t, iface); + bridge = iface->get_bridge(iface); + if (bridge && bridge->disconnect_iface(bridge, iface)) + { + return self; + } + return Qnil; +} + +static VALUE iface_delete(VALUE self) +{ + guest_t *guest; + iface_t *iface; + + Data_Get_Struct(self, iface_t, iface); + guest = iface->get_guest(iface); + guest->destroy_iface(guest, iface); + return Qnil; +} + +static void iface_init() +{ + rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject); + rb_define_method(rbc_iface, "to_s", iface_to_s, 0); + rb_define_method(rbc_iface, "connect", iface_connect, 1); + rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0); + rb_define_method(rbc_iface, "delete", iface_delete, 0); +} + +/** + * main routine, parses args and reads from console + */ +int main(int argc, char *argv[]) +{ + int state; + struct sigaction action; + + ruby_init(); + ruby_init_loadpath(); + + /* there are to many to report, rubyruby... */ + setenv("LEAK_DETECTIVE_DISABLE", "1", 1); + + library_init(NULL); + + dumm = dumm_create(NULL); + + rbm_dumm = rb_define_module("Dumm"); + + guest_init(); + bridge_init(); + iface_init(); + + sigemptyset(&action.sa_mask); + action.sa_sigaction = sigchld_handler; + action.sa_flags = SA_SIGINFO; + sigaction(SIGCHLD, &action, NULL); + + rb_require("irb"); + rb_eval_string_protect("include Dumm", &state); + rb_eval_string_protect("IRB.start", &state); + if (state) + { + rb_p(ruby_errinfo); + } + + dumm->destroy(dumm); + + action.sa_handler = SIG_DFL; + action.sa_flags = 0; + sigaction(SIGCHLD, &action, NULL); + + library_deinit(); + return 0; +} + |