mod_managed allows execution of Common Language Infrastructure code inside FreeSWITCH. It supports the Microsoft CLR (".NET") on Windows, as well as Mono on Windows and other platforms. Effectively, this allows use of any .NET language, such as F#, VB.NET, C#, IronRuby, IronPython, JScript.NET, and many others, to create FreeSWITCH modules, applications, and API functions. (mod_managed replaces mod_mono.)
As of July 27, 2010, mod_managed has a new plugin architecture. This breaks backwards compatibility -- plugins no longer subclass ApiFunction or AppFunction, but instead implement specific interfaces. With this, reloading (multiple AppDomains) and scripting support has been added.
mod_managed only supports the .NET Framework 3.5 or (as of November, 2011) Mono 2.8+. Support for older versions of Mono has been discontinued.
To get mod_managed to build on Windows, you’ll need Visual Studio 2008 (C++ and C# to build the entire thing, although C# binaries are provided).
The precompiled Windows binaries do not include the managed part of mod_managed. At the moment (3-Mar-2010) you need to build the complete SLN from source to get mod_managed.
Microsoft CLR Build
mod_managed should "just work" with the .NET Framework 3.5 and Visual Studio 2008 installed. In the build configuration manager inside Visual Studio, mod_managed has configurations for both Debug/Release CLR and Mono. Simply select Debug_CLR and build.
For the Mono version, the Windows build requires that Mono install be accessible at "C:\Program Files\Mono". If you installed somewhere else, symlink it:
mklink /d "C:\Program Files\Mono" "C:\Program Files\Mono-2.4"
Get Junction: http://technet.microsoft.com/en-us/sysinternals/bb896768.aspx junction -d "C:\Program Files\Mono" "C:\Program Files\Mono-2.4"
You’ll have to generate mono.lib for your compiler. Details here: http://www.mono-project.com/Embedding_Mono (Search for mono.def). A batch file is provided: monolibx86.cmd:
C:\freeswitch\src\mod\languages\mod_managed>monolibx86 C:\freeswitch\src\mod\languages\mod_managed>lib /nologo /def:mono.def /out:mono.lib /machine:x86 Creating library mono.lib and object mono.exp
Make sure your PATH has the Mono bin folder in it (such as "C:\Program files\Mono\bin") or the mod will not load.
From there, simply compile the mod_managed project in the languages folder. This will build the unmanaged side and the managed loader and put them in your mod directory. If you get errors, the SWIG generated interface might be out of date. From the mod_managed directory, you can run "runswig.cmd" to regenerate the SWIG files. This batch file assumes SWIG is accessible at "\dev\swig".
To build on Linux, first install Mono and make sure "languages\mod_managed" is uncommented in modules.conf. In the src/mod/mod_managed dir, you should be able to:
make && make install
If this complains about pkgconfig, try:
When running on Linux, you might get a DllNotFoundException for libc. Try making sure libc.so is in one of the ldconfig paths. For example, on a clean CentOS 5.3 x64 system, I had to do this:
ln -s /lib64/libc-2.5.so /lib64/libc.so
Followed by ldconfig. Almost all DllNotFoundExceptions are because of incorrect ld paths.
As of November 2011, the error with finding libc.so has been resolved. You do not need to create a symlink anymore.
If you are experiencing NullReferenceExceptions with any plugin run through the dialplan, make sure you have included the appropriate entry in your dllmap configuration:
<dllmap dll="mod_managed.dll" target="mod_managed.so" os="!windows"/>
This should fix NullReferenceExceptions not caused by the plugin.
Edit (05/17/10): I found that adding the above to mono's dllmap config file (/etc/mono/config) does not resolve this issue. It was necessary for me to both create and add the above to the file "FreeSWITCH.Native.dll.config" under the FS mod directory. The above dllmap entry must be wrapped in <configuration> </configuration> tags.
Linux Mono 2.8 and greater Build
Mono 2.8+ support is now enabled by default, and older Mono versions are unsupported.
To load mod_managed at FreeSWITCH start up you will need to add "<load module="mod_managed" />" to the modules.conf.xml. The best place for this line is in the languages sections.
Modules.conf.xml is located in <FS install dir>\conf\autoload_configs\
mod_managed automatically scans the <FreeSWITCH mod dir>\managed for managed modules. (For example, this may be "C:\freeswitch\debug\mod\managed".) mod_managed will not load if the "managed" subdirectory under the modules directory does not exist.
There are two main plugin interfaces: IApiPlugin, and IAppPlugin. Any assembly or script in the managed directory containing types implementing those interfaces will automatically get loaded and registered. The name registered is the full name (Namespace.TypeName), as well as just the TypeName. If there are conflicts, the last loaded type will overwrite previous ones.
IAppPlugins are only called on sessions, say, from the dialplan. IApiPlugins can be called anywhere from FreeSWITCH. IApiPlugins can be run normally ("managed"/Execute), as well as in the background on their own thread ("managedrun"/ExecuteBackground).
A third plugin interface, ILoadNotificationPlugin, is for controlling loading of scripts or assemblies. If any ILoadNotificationPlugin returns false from Load, the file will not be loaded. This is also a way to get notified when your code is being loaded and perform initialization tasks.
mod_managed will watch the managed directory for changes to loaded files and their config files. Any changes will trigger a reload of that file. First, the file will be re-read and loaded. Then the previous version will be unloaded. The only notification provided is via the AppDomain.CurrentDomain.DomainUnload event.
To force a reload, use the managedreload command: "managedreload my.dll".
mod_managed now supports scripting via any managed language. Simply drop a script file in the managed directory, and mod_managed will compile it and load it into memory (and reload it when changed).
Scripts must produce a valid entry point. Entry points must be public for use on Mono. An entry point may return a value, and may take a single string array parameter, however, the return value is not checked, and the string array parameter will always be empty.
Inside the script, check the static variable FreeSWITCH.Script.ContextType to see how the script is being invoked: App, Api or, ApiBackground. Based on that, obtain the context via Script.GetAppContext(), Script.GetApiContext() or Script.GetApiBackgroundContext(). At that point, it is exactly like having a precompiled plugin.
In contrast to other scripting environments, mod_managed loads your script into memory and initializes it once. This provides a huge performance increase over loading it each time. Static variables are shared across invocations of a script, so that caching and other scenarios are enabled. Do be aware of multithreading issues, as multiple threads will be in your script at the same time.
Scripts can define types that implement the plugin interfaces. These will be loaded and registered like normal.
The built-in supported languages are F# (.fsx), VB (.vbx), C# (.csx) and JScript.NET (.jsx). Note the different extensions -- mod_managed will ignore .cs, .vb, and .js files. Mono does not seem to support JScript.NET. Other language support is being looked at.
Scripts can be precompiled as .exes. Simply drop a .exe into the managed directory, and mod_managed will pick it up like any other script file. This allows deployment without source, as well as deploying scripts that mod_managed cannot dynamically compile.
mod_managed exposes nearly the entire FreeSWITCH C API (courtesy of SWIG). This allows creation of not just API functions and call apps, but any type of module that FreeSWITCH supports (codecs, endpoints, etc.). The types are in the FreeSWITCH.Native namespace. FreeSWITCH.Native. The FreeSWITCH.Native.freeswitch type contains static members to access all the functions.
Dave Kompel (DRK) gave a presentation about mod_managed on the May 12, 2010 weekly FreeSWITCH conf call:
See Demo.cs in mod_managed\managed. To specify a function, use the name of the type (such as AppDemo or ApiDemo). You can also fully qualify with the namespace and type name, ex: FreeSWITCH.Demo.AppDemo.
2008-10-08 17:41:05 [INFO] mod_managed.cpp:310 mod_managed_load() Loading mod_managed (Common Language Infrastructure), Microsoft CLR Version 2008-10-08 17:41:05 [DEBUG] mod_managed.cpp:299 findLoader() Found all FreeSWITCH.Loader functions. 2008-10-08 17:41:05 [DEBUG] switch_cpp.cpp:1059 console_log() mod_managed_lib loader is starting with directory 'C:\freeswitch\Debug\mod\managed'. 2008-10-08 17:41:05 [NOTICE] switch_cpp.cpp:1059 console_log() loadAssemblies: C:\freeswitch\Debug\mod\managed 2008-10-08 17:41:05 [DEBUG] switch_cpp.cpp:1059 console_log() Loading 'C:\freeswitch\Debug\mod\managed\fsfsdemos.dll'. 2008-10-08 17:41:05 [DEBUG] switch_cpp.cpp:1059 console_log() Loading 'C:\freeswitch\Debug\mod\managed\pizzacs.dll'. 2008-10-08 17:41:05 [INFO] switch_cpp.cpp:1059 console_log() Inside AppDemo::Load. 2008-10-08 17:41:05 [NOTICE] switch_cpp.cpp:1059 console_log() Function FreeSWITCH.Demo.AppDemo loaded. 2008-10-08 17:41:05 [DEBUG] switch_cpp.cpp:1059 console_log() Inside ApiDemo::Load. 2008-10-08 17:41:05 [NOTICE] switch_cpp.cpp:1059 console_log() Function FreeSWITCH.Demo.ApiDemo loaded. 2008-10-08 17:41:05 [DEBUG] switch_cpp.cpp:1059 console_log() Trying to resolve assembly 'mod_managed_lib, Version=188.8.131.52, Culture=neutral, PublicKeyToken=null'. 2008-10-08 17:41:05 [NOTICE] switch_cpp.cpp:1059 console_log() Function rss.RssReader loaded. 2008-10-08 17:41:05 [DEBUG] switch_cpp.cpp:1059 console_log() Trying to resolve assembly 'mod_managed_lib, Version=184.108.40.206, Culture=neutral, PublicKeyToken=null'. 2008-10-08 17:41:05 [NOTICE] switch_cpp.cpp:1059 console_log() Function pizzacs.PizzaApp loaded. 2008-10-08 17:41:05 [DEBUG] mod_managed.cpp:328 mod_managed_load() Load completed successfully. 2008-10-08 17:41:05 [DEBUG] mod_managed.cpp:354 mod_managed_load() Load completed successfully. > help ... managed,<module> [<args>],Run a module as an API function (Execute) managedreload,<filename>,ReLoad assembly managedrun,<module> [<args>],Run a module (ExecuteBackground) >managed apidemo a1 123 API CALL [managed(apidemo a1 123)] output: ApiDemo executed with args 'a1 123' and event type API. >freeswitch@ODIN> managedrun apidemo a1 123 API CALL [managedrun(apidemo a1 123)] output: +OK 2008-10-08 17:44:25 [DEBUG] switch_cpp.cpp:1059 console_log() ApiDemo on a background thread #(3), with args 'a1 123'. 2008-10-08 17:44:25 [DEBUG] switch_cpp.cpp:1059 console_log() ExecuteBackground in apidemo completed.
Parking Lot Sample
An implementation of a FreePBX-like parking lot module demonstrates using API and APP plugins with ceptstral text to speech.
Dialplan and Example
You may point to your managed application by entering the routing into the dialplan as demonstrated below.
<extension name="testapp"> <condition field="destination_number" expression="^(1024)"> <action application="managed" data="yourclassname"/> </condition> </extension>
With mod_managed 1.0.4, this is no longer used. Email the freeswitch developer list if you need this functionality.
ODBC on Linux
For some reason, mod_managed doesn't pickup Mono's dllmap entries for odbc32.dll to unixodbc.so. So, to get ODBC support working, you'll need to create an odbc32.dll link, for example:
ln -s /lib64/libodbc.so /lib64/odbc32.dll