diff --git a/src/mod/languages/mod_mono/mod_mono/Makefile b/src/mod/languages/mod_mono/mod_mono/Makefile new file mode 100644 index 0000000000..d63a4b911c --- /dev/null +++ b/src/mod/languages/mod_mono/mod_mono/Makefile @@ -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 index 0000000000..e294563317 --- /dev/null +++ b/src/mod/languages/mod_mono/mod_mono/mod_mono.c @@ -0,0 +1,278 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2006, James Martelletti + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * James Martelletti + * + * + * mod_mono.c -- Embedded mono runtime. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +}