]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Importing mod_mono, hoorah, still need to import managed stuff.
authorJames Green <james.green@stealthnet.net>
Tue, 12 Sep 2006 13:03:23 +0000 (13:03 +0000)
committerJames Green <james.green@stealthnet.net>
Tue, 12 Sep 2006 13:03:23 +0000 (13:03 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2661 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/mod/languages/mod_mono/mod_mono/Makefile [new file with mode: 0644]
src/mod/languages/mod_mono/mod_mono/mod_mono.c [new file with mode: 0755]

diff --git a/src/mod/languages/mod_mono/mod_mono/Makefile b/src/mod/languages/mod_mono/mod_mono/Makefile
new file mode 100644 (file)
index 0000000..d63a4b9
--- /dev/null
@@ -0,0 +1,22 @@
+VERSION = mono-1.1.13.8
+TARBALL = mono-1.1.13.8.tar.gz
+CFLAGS += `pkg-config --cflags mono`
+LDFLAGS += `pkg-config --libs mono` 
+
+all:   depends $(MODNAME).$(DYNAMIC_LIB_EXTEN)
+
+depends:
+       MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install $(TARBALL) --prefix=$(PREFIX) --with-pic
+
+%.o:  %.c
+       $(CC) -fPIC $(CFLAGS) -c -o $@ $<
+
+$(MODNAME).$(DYNAMIC_LIB_EXTEN): $(MODNAME).c
+       $(CC) $(CFLAGS) -fPIC -c $(MODNAME).c -o $(MODNAME).o 
+       $(LINKER) $(SOLINK) -o $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(MODNAME).o $(LDFLAGS)
+
+clean:
+       rm -fr *.$(DYNAMIC_LIB_EXTEN) *.o *~
+
+install:
+       cp -f $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(PREFIX)/mod
diff --git a/src/mod/languages/mod_mono/mod_mono/mod_mono.c b/src/mod/languages/mod_mono/mod_mono/mod_mono.c
new file mode 100755 (executable)
index 0000000..e294563
--- /dev/null
@@ -0,0 +1,278 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2006, James Martelletti <james@nerdc0re.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * James Martelletti <james@nerdc0re.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * James Martelletti <james@nerdc0re.com>
+ *
+ *
+ * mod_mono.c -- Embedded mono runtime.
+ *
+ */
+#include <mono/jit/jit.h>
+#include <mono/metadata/assembly.h>
+#include <mono/metadata/environment.h>
+#include <mono/metadata/tokentype.h>
+#include <mono/metadata/debug-helpers.h>
+#include <mono/metadata/image.h>
+#include <mono/metadata/threads.h>
+#include <gc/gc.h>
+#include <switch.h>
+
+#define SWITCH_MONO_MODULES  "mono/" 
+#define SWITCH_MONO_LIBDIR   "lib/"
+#define SWITCH_MONO_ASSEMBLY "Freeswitch.dll"
+
+/* Module functions */
+switch_status_t mod_mono_load_modules(const char *module_dir);
+MonoClass* mod_mono_find_assembly_class(MonoImage *image);
+
+/* Managed functions */
+void mod_mono_switch_console_printf(switch_text_channel_t channel, char *file, const char *func, int line, char *fmt, char *msg);
+
+static const char modname[] = "mod_mono";
+static switch_memory_pool_t *mono_pool = NULL;
+
+static struct {
+       MonoDomain *domain;
+       switch_hash_t *plugins;
+} globals;
+
+typedef struct {
+       MonoAssembly *assembly;
+       MonoClass *class;
+       MonoObject *object;     
+} mono_plugin;
+
+static switch_loadable_module_interface_t mono_module_interface = {
+       /*.module_name */ modname,
+};
+
+/*
+ * Load mod_mono module and initialise domain
+ *
+ * This function will initialise the memory pool and plugin hash for this module,
+ * it will then initialise a new mono domain.
+ */
+SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **interface, char *filename)
+{
+       *interface = &mono_module_interface;
+
+       /* Initialise memory pool */
+       if (switch_core_new_memory_pool(&mono_pool) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate memory pool\n");
+               return SWITCH_STATUS_FALSE;
+       }
+       
+       /* Initialise plugin hash */
+       if (switch_core_hash_init(&globals.plugins, mono_pool) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not initialise plugins hash\n");
+               return SWITCH_STATUS_FALSE;
+       }               
+       
+       /* Construct the path to the Freeswitch assembly, then check to make sure it exists */
+       switch_size_t assembly_dir_len  = strlen(SWITCH_GLOBAL_dirs.base_dir) + strlen(SWITCH_MONO_LIBDIR) + 2; /* Account for / and \0 */
+       switch_size_t assembly_file_len = assembly_dir_len + strlen(SWITCH_MONO_ASSEMBLY);
+       char *assembly_dir  = (char *) switch_core_alloc(mono_pool, assembly_dir_len);
+       char *assembly_file = (char *) switch_core_alloc(mono_pool, assembly_file_len);
+
+       apr_finfo_t *finfo = (apr_finfo_t *) switch_core_alloc(mono_pool, sizeof(*finfo));
+
+       snprintf(assembly_dir, assembly_dir_len, "%s/%s", SWITCH_GLOBAL_dirs.base_dir, SWITCH_MONO_LIBDIR);
+       snprintf(assembly_file, assembly_file_len, "%s/%s%s", SWITCH_GLOBAL_dirs.base_dir, SWITCH_MONO_LIBDIR, SWITCH_MONO_ASSEMBLY);
+
+       if (apr_stat(finfo, assembly_file, 0, mono_pool) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Could not find Freeswitch.NET assembly");
+               return SWITCH_STATUS_FALSE;
+       }
+
+       /* Mono wants to know where it will be able to find the Freeswitch assembly if it's not in the GAC */
+       if (getenv("MONO_PATH") != NULL) {
+               switch_size_t mono_path_len = strlen(getenv("MONO_PATH")) + strlen(assembly_dir) + 2; /* Account for : and \0 */ 
+               char *mono_path = (char *) switch_core_alloc(mono_pool, mono_path_len);
+       
+               snprintf(mono_path, mono_path_len, "%s:%s", getenv("MONO_PATH"), assembly_dir);
+
+               setenv("MONO_PATH", mono_path, 1);
+       }
+       else
+               setenv("MONO_PATH", assembly_dir, 1);
+
+       /* Now find where our managed modules are */
+       switch_size_t module_dir_len = strlen(SWITCH_GLOBAL_dirs.mod_dir) + strlen(SWITCH_MONO_MODULES) + 2; /* Account for / and \0 */
+       char *module_dir = (char *) switch_core_alloc(mono_pool, module_dir_len);
+
+       snprintf(module_dir, module_dir_len, "%s/%s", SWITCH_GLOBAL_dirs.mod_dir, SWITCH_MONO_MODULES);
+       
+       /* Initialise the mono domain */
+       if (!(globals.domain = mono_jit_init("freeswitch"))) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error initialising mono runtime\n");
+               return SWITCH_STATUS_FALSE;
+       }
+
+       /* Let user know everything initialised fine */
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Initialised mono runtime\n");
+
+       /* Load our modules */
+       if (mod_mono_load_modules(module_dir) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error loading modules\n");
+               return SWITCH_STATUS_FALSE;
+       }
+
+       /* Finally, go through and initialise each plugin before returning SUCCESS */ 
+       switch_hash_index_t *p = NULL;
+
+       for (p = switch_hash_first(mono_pool, globals.plugins); p; p = switch_hash_next(p)) {
+               mono_plugin *plugin = (mono_plugin *) switch_core_alloc(mono_pool, sizeof(*plugin));
+               switch_size_t *key_length = NULL;
+               const void *key = NULL;
+               void *value = NULL;
+
+               switch_hash_this(p, &key, key_length, &value);
+               plugin = (mono_plugin *) value;
+               
+               mono_runtime_object_init(plugin->object);
+       }
+       
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/*
+ * Function for cleanly shutting down mod_mono
+ * 
+ */
+SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void)
+{
+       if (globals.domain) {
+               mono_jit_cleanup(globals.domain);
+               globals.domain = NULL;
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deallocated mono runtime.\n");
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/*
+ * This function will load the managed modules
+ *
+ */ 
+switch_status_t mod_mono_load_modules(const char *module_dir)
+{
+       apr_dir_t *module_dir_handle;
+       char *file;
+       size_t len;
+       char *ptr;
+       apr_finfo_t finfo;
+       apr_int32_t finfo_flags = APR_FINFO_DIRENT | APR_FINFO_TYPE | APR_FINFO_NAME;
+       const char *ext = ".dll";
+       const char *EXT = ".DLL";
+       MonoAssembly *assembly;
+       MonoImage *image;
+       gpointer iter;
+       iter=NULL;
+       mono_plugin *plugin=NULL;
+
+       if (apr_dir_open(&module_dir_handle, module_dir, mono_pool) != SWITCH_STATUS_SUCCESS)
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Could not open directory: %s\n", module_dir);
+
+       /* Read the modules directory */
+       while (apr_dir_read(&finfo, finfo_flags, module_dir_handle) == SWITCH_STATUS_SUCCESS)
+       {
+               assembly = (MonoAssembly *) switch_core_alloc(mono_pool, sizeof(assembly));
+               image = (MonoImage *) switch_core_alloc(mono_pool, sizeof(image));
+               const char *fname = finfo.fname;
+
+               if (finfo.filetype != APR_REG)
+                       continue;
+                        
+               if (!fname)
+                       fname = finfo.name;
+
+               if (!(ptr = (char *) fname))
+                       continue;
+
+               if (!strstr(fname, ext) && !strstr(fname, EXT))
+                       continue;
+
+               len = strlen(module_dir) + strlen(fname) + 2;
+               file = (char *)switch_core_alloc(mono_pool, len);
+               snprintf(file, len, "%s%s", module_dir, fname);
+
+               /* Attempt to open the assembly */
+               assembly = mono_domain_assembly_open(globals.domain, file);
+
+               if (!assembly) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Not a valid assembly\n");
+                       continue;
+               }
+
+               /* Get the image from assembly */       
+               image = mono_assembly_get_image(assembly);
+       
+               plugin = (mono_plugin *)switch_core_alloc(mono_pool, sizeof(*plugin));
+
+               plugin->assembly = assembly;
+               plugin->class    = mod_mono_find_assembly_class(mono_assembly_get_image(plugin->assembly));
+
+               if (!plugin->class)
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No plugin class\n");
+
+               plugin->object = mono_object_new(globals.domain, plugin->class);
+
+               switch_core_hash_insert(globals.plugins, (char *) mono_image_get_name(mono_assembly_get_image(assembly)), plugin);
+
+               plugin = NULL;
+       }       
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/*
+ *
+ */ 
+MonoClass* mod_mono_find_assembly_class(MonoImage *image)
+{
+       MonoClass *class, *parent_class = NULL;
+       int i, total;
+
+       total = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF);
+       
+       for (i = 1; i <= total; ++i)
+       {
+               class = mono_class_get(image, MONO_TOKEN_TYPE_DEF | i);
+               parent_class = mono_class_get_parent(class);
+               
+               if (parent_class) 
+                       if (!strcmp("Module", mono_class_get_name(parent_class)))
+                               return class;
+       }
+                                               
+       return NULL;
+}
+
+/*
+ *
+ */
+void mono_switch_console_printf(switch_text_channel_t channel, char *file, const char *func, int line, char *fmt, char *msg)
+{
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, msg);
+}