prototype of irdumm - interactive ruby shell for dumm
authorMartin Willi <martin@strongswan.org>
Fri, 4 Jul 2008 14:21:41 +0000 (14:21 -0000)
committerMartin Willi <martin@strongswan.org>
Fri, 4 Jul 2008 14:21:41 +0000 (14:21 -0000)
src/dumm/Makefile.am
src/dumm/dumm.c
src/dumm/guest.c
src/dumm/guest.h
src/dumm/iface.c
src/dumm/iface.h
src/dumm/irdumm.c [new file with mode: 0644]

index 1e47e89..815f38d 100644 (file)
@@ -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
index 5db8eae..0bb74e8 100644 (file)
@@ -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);
index d43f46d..75d0245 100644 (file)
@@ -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);
index 79a47fa..919726d 100644 (file)
 #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, ...)
  */
index b1fc641..a7d62ff 100644 (file)
@@ -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)
        {
index e04fe4e..e646724 100644 (file)
@@ -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 (file)
index 0000000..5989083
--- /dev/null
@@ -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;
+}
+