From 7c0cf506d84430bebb3923b8e43eae4871bcd87a Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:17:57 +0300 Subject: [PATCH 1/6] mod_managed: managedlist command must return value to api stream instead of log --- .../languages/mod_managed/managed/Loader.cs | 46 ++++++++++++------- src/mod/languages/mod_managed/mod_managed.cpp | 8 ++-- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index 19ab3a52db..c655c9c867 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -26,6 +26,7 @@ * Michael Giagnocavo * David Brazier * Jeff Lenk + * Artur Kraev * * Loader.cs -- mod_managed loader * @@ -33,7 +34,6 @@ using System; using System.Collections.Generic; -using System.Text; using System.IO; using System.Linq; using System.Reflection; @@ -46,16 +46,15 @@ namespace FreeSWITCH { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ExecuteDelegate(string cmd, IntPtr streamH, IntPtr eventH); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ExecuteBackgroundDelegate(string cmd); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool RunDelegate(string cmd, IntPtr session); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ReloadDelegate(string cmd); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ListDelegate(string cmd); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ReloadDelegate(string cmd); static readonly ExecuteDelegate _execute = Execute; static readonly ExecuteBackgroundDelegate _executeBackground = ExecuteBackground; static readonly RunDelegate _run = Run; static readonly ReloadDelegate _reload = Reload; - static readonly ListDelegate _list = List; + static readonly ExecuteDelegate _list = List; [DllImport("mod_managed", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - static extern void InitManagedDelegates(RunDelegate run, ExecuteDelegate execute, ExecuteBackgroundDelegate executeBackground, ReloadDelegate reload, ListDelegate list); + static extern void InitManagedDelegates(RunDelegate run, ExecuteDelegate execute, ExecuteBackgroundDelegate executeBackground, ReloadDelegate reload, ExecuteDelegate list); static readonly object loaderLock = new object(); @@ -408,18 +407,33 @@ namespace FreeSWITCH { } } - public static bool List(string command) { - try { - Log.WriteLine(LogLevel.Info, "Available APIs:"); - getApiExecs().Values.ForEach(x => { - Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray())); - }); - Log.WriteLine(LogLevel.Info, "Available Apps:"); - getAppExecs().Values.ForEach(x => { - Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray())); - }); + public static bool List(string command, IntPtr streamHandle, IntPtr eventHandle) + { + try + { + if (streamHandle != IntPtr.Zero) + { + using (var stream = new Native.Stream(new Native.switch_stream_handle(streamHandle, false))) + { + stream.Write("Available APIs:\n"); + + getApiExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray())))); + + stream.Write("Available Apps:\n"); + getAppExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray())))); + } + } + else + { + Log.WriteLine(LogLevel.Info, "Available APIs:"); + getApiExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()))); + Log.WriteLine(LogLevel.Info, "Available Apps:"); + getAppExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()))); + } return true; - } catch (Exception ex) { + } + catch (Exception ex) + { Log.WriteLine(LogLevel.Error, "Exception listing managed modules: {0}", ex.ToString()); return false; } diff --git a/src/mod/languages/mod_managed/mod_managed.cpp b/src/mod/languages/mod_managed/mod_managed.cpp index 215a98336b..6718265d53 100644 --- a/src/mod/languages/mod_managed/mod_managed.cpp +++ b/src/mod/languages/mod_managed/mod_managed.cpp @@ -26,6 +26,7 @@ * Michael Giagnocavo * David Brazier * Jeff Lenk + * Artur Kraev * * mod_mono.cpp -- FreeSWITCH mod_mono main class * @@ -73,14 +74,13 @@ typedef int (*runFunction)(const char *data, void *sessionPtr); typedef int (*executeFunction)(const char *cmd, void *stream, void *Event); typedef int (*executeBackgroundFunction)(const char* cmd); typedef int (*reloadFunction)(const char* cmd); -typedef int (*listFunction)(const char* cmd); static runFunction runDelegate; static executeFunction executeDelegate; static executeBackgroundFunction executeBackgroundDelegate; static reloadFunction reloadDelegate; -static listFunction listDelegate; +static executeFunction listDelegate; -SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, listFunction list) +SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, executeFunction list) { runDelegate = run; executeDelegate = execute; @@ -451,7 +451,7 @@ SWITCH_STANDARD_API(managedlist_api_function) #ifndef _MANAGED mono_thread_attach(globals.domain); #endif - listDelegate(cmd); + listDelegate(cmd, stream, stream->param_event); #ifndef _MANAGED mono_thread_detach(mono_thread_current()); #endif From f3d089a998d52d07ff23110a86e0b57fd1b76c33 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:24:49 +0300 Subject: [PATCH 2/6] mod_managed: not crash when cannot remove shadow directory (this sometimes happens when restarting from FS console) --- src/mod/languages/mod_managed/managed/Loader.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index c655c9c867..a3d48fd1d1 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -64,13 +64,23 @@ namespace FreeSWITCH { public static bool Load() { managedDir = Path.Combine(Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir, "managed"); shadowDir = Path.Combine(managedDir, "shadow"); - if (Directory.Exists(shadowDir)) { - Directory.Delete(shadowDir, true); + if (Directory.Exists(shadowDir)) + { + try + { + Directory.Delete(shadowDir, true); + } + catch (Exception ex) + { + Log.WriteLine(LogLevel.Warning, "Cannot delete shadow directory: {0}", ex); + } + Directory.CreateDirectory(shadowDir); } Log.WriteLine(LogLevel.Debug, "FreeSWITCH.Managed loader is starting with directory '{0}'.", managedDir); - if (!Directory.Exists(managedDir)) { + if (!Directory.Exists(managedDir)) + { Log.WriteLine(LogLevel.Error, "Managed directory not found: {0}", managedDir); return false; } From 4037e782a586ba5862bd3666ff53a00906444399 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:32:30 +0300 Subject: [PATCH 3/6] mod_managed: support per-module references directory --- .../languages/mod_managed/managed/Loader.cs | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index a3d48fd1d1..cee7af86c2 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -229,11 +229,38 @@ namespace FreeSWITCH { setup.ConfigurationFile = fileName + ".config"; } setup.ApplicationBase = Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir; - setup.ShadowCopyDirectories = managedDir + ";"; setup.LoaderOptimization = LoaderOptimization.MultiDomainHost; // TODO: would MultiDomain work better since FreeSWITCH.Managed isn't gac'd? setup.CachePath = shadowDir; setup.ShadowCopyFiles = "true"; - setup.PrivateBinPath = "managed"; + + // computing private bin path + var binPath = setup.PrivateBinPath ?? string.Empty; + + var binPaths = binPath.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + + // adding "managed" (modules) directory + if (!binPaths.Contains("managed", StringComparer.OrdinalIgnoreCase)) + { + binPaths.Add("managed"); + } + + // adding "managed/" directory for per-module references support + var moduleRefsDir = Path.GetFileName(fileName); + moduleRefsDir = Path.GetFileNameWithoutExtension(moduleRefsDir); + + if (moduleRefsDir != null && moduleRefsDir.Trim() != "") + { + moduleRefsDir = Path.Combine("managed", moduleRefsDir); + if (!binPaths.Contains(moduleRefsDir, StringComparer.OrdinalIgnoreCase)) + { + binPaths.Add(moduleRefsDir); + } + } + + // bringing all together + setup.PrivateBinPath = string.Join(";", binPaths); // Create domain and load PM inside System.Threading.Interlocked.Increment(ref appDomainCount); From 10ebebaae0eacaed1fccf5b72185b09bb25cd210 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:34:04 +0300 Subject: [PATCH 4/6] mod_managed: added console log level --- src/mod/languages/mod_managed/managed/Log.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mod/languages/mod_managed/managed/Log.cs b/src/mod/languages/mod_managed/managed/Log.cs index 1c58ff1458..aa2bacf57e 100644 --- a/src/mod/languages/mod_managed/managed/Log.cs +++ b/src/mod/languages/mod_managed/managed/Log.cs @@ -57,6 +57,7 @@ namespace FreeSWITCH static string ToLogString(this LogLevel level) { switch (level) { + case LogLevel.Console: return "CONSOLE"; case LogLevel.Alert: return "ALERT"; case LogLevel.Critical: return "CRIT"; case LogLevel.Debug: return "DEBUG"; @@ -85,6 +86,7 @@ namespace FreeSWITCH };*/ public enum LogLevel { + Console, Debug, Info, Error, From 33cb9505003899c94386ae532e748616cba7c266 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:42:00 +0300 Subject: [PATCH 5/6] mod_managed: Added pure CreateStateHandlerDelegate in ManagedSession for native api usage --- .../mod_managed/managed/ManagedSession.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/mod/languages/mod_managed/managed/ManagedSession.cs b/src/mod/languages/mod_managed/managed/ManagedSession.cs index bed7a03878..84718df60f 100644 --- a/src/mod/languages/mod_managed/managed/ManagedSession.cs +++ b/src/mod/languages/mod_managed/managed/ManagedSession.cs @@ -149,6 +149,23 @@ namespace FreeSWITCH.Native }; return del; } + + /// Wraps a nice handler into a delegate suitable for reverse P/Invoke. For native api using + public static switch_state_handler_t_delegate CreateStateHandlerDelegate(Action handler) + { + // We create a ManagedSession on top of the session so callbacks can use it "nicely" + // Then we sort of dispose it. + switch_state_handler_t_delegate del = ptr => + { + using (var sess = new ManagedSession(new SWIGTYPE_p_switch_core_session(ptr, false))) + { + handler(sess); + return switch_status_t.SWITCH_STATUS_SUCCESS; + } + }; + return del; + } + public static SWIGTYPE_p_f_p_switch_core_session__switch_status_t WrapStateHandlerDelegate(switch_state_handler_t_delegate del) { return new SWIGTYPE_p_f_p_switch_core_session__switch_status_t(Marshal.GetFunctionPointerForDelegate(del), false); } From 889b678e58bf38eb86df7885b8f054d3d9d92d74 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:43:59 +0300 Subject: [PATCH 6/6] mod_managed: Added GetPtr to Util class for internal pointers extraction (very useful when using native api) --- src/mod/languages/mod_managed/managed/Util.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/mod/languages/mod_managed/managed/Util.cs b/src/mod/languages/mod_managed/managed/Util.cs index 18c2d89369..7fd5194770 100644 --- a/src/mod/languages/mod_managed/managed/Util.cs +++ b/src/mod/languages/mod_managed/managed/Util.cs @@ -46,5 +46,31 @@ namespace FreeSWITCH { if (cons == null) throw new ArgumentException(ty.Name + " constructor not found."); return (T)cons.Invoke(new object[] { cPtr, false }); } + + /// + /// Getting IntPtr from wrapper + /// + /// swig generated class + /// instance + /// Original pointer + public static IntPtr GetPtr(T obj) + { + // internal static HandleRef getCPtr(CoreSession obj) + var ty = typeof(T); + var bflags = BindingFlags.Static | BindingFlags.NonPublic; + var getCPtr = ty.GetMethod("getCPtr", bflags, null, new[] { typeof(T) }, null); + + if (getCPtr != null) + { + var handleRef = getCPtr.Invoke(null, new object[] { obj }); + + if (handleRef is HandleRef) + { + return ((HandleRef)handleRef).Handle; + } + } + + return IntPtr.Zero; + } } }