using System;
using System.Collections;
using System.Text;
-using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace CollectdAPI
{
- public interface IRead /* {{{ */
- {
- int read ();
- } /* }}} interface IRead */
-
- public class Collectd /* {{{ */
- {
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public extern static int log (int severity, string message);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public extern static int registerRead (string name, IRead obj);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public extern static int dispatchValues (ValueList vl);
- } /* }}} class Collectd */
+ public delegate int CollectdReadCallback ();
- public abstract class Value /* {{{ */
+ public interface IValue /* {{{ */
{
- public abstract long toLong ();
- public abstract double toDouble ();
- } /* }}} class Value */
+ long ToLong ();
+ double ToDouble ();
+ } /* }}} class IValue */
- public class gaugeValue: Value /* {{{ */
+ public class GaugeValue: IValue /* {{{ */
{
private double _value;
- public gaugeValue (double v)
+ public GaugeValue (double v)
{
this._value = v;
}
- public override long toLong () { return ((long) this._value); }
- public override double toDouble () { return (this._value); }
+ public long ToLong () { return ((long) this._value); }
+ public double ToDouble () { return (this._value); }
public override string ToString ()
{
return (this._value.ToString ());
}
- } /* }}} class gaugeValue */
+ } /* }}} class GaugeValue */
- public class deriveValue: Value /* {{{ */
+ public class DeriveValue: IValue /* {{{ */
{
private long _value;
- public deriveValue (long v)
+ public DeriveValue (long v)
{
this._value = v;
}
- public override long toLong () { return (this._value); }
- public override double toDouble () { return ((double) this._value); }
+ public long ToLong () { return (this._value); }
+ public double ToDouble () { return ((double) this._value); }
public override string ToString ()
{
return (this._value.ToString ());
}
- } /* }}} class deriveValue */
+ } /* }}} class DeriveValue */
public class Identifier /* {{{ */
{
+ [MarshalAs (UnmanagedType.LPStr)]
protected string _host;
+ [MarshalAs (UnmanagedType.LPStr)]
protected string _plugin;
+ [MarshalAs (UnmanagedType.LPStr)]
protected string _pluginInstance;
+ [MarshalAs (UnmanagedType.LPStr)]
protected string _type;
+ [MarshalAs (UnmanagedType.LPStr)]
protected string _typeInstance;
public Identifier (string host,
this._typeInstance = id._typeInstance;
} /* Identifier() */
- public string getHost () { return (this._host); }
- public string getPlugin () { return (this._plugin); }
- public string getPluginInstance () { return (this._pluginInstance); }
- public string getType () { return (this._type); }
- public string getTypeInstance () { return (this._typeInstance); }
+ public string Host /* {{{ */
+ {
+ get
+ {
+ return (this._host);
+ }
+ set
+ {
+ if ((value == null) || (value.Length < 1))
+ throw new ArgumentException ();
+ this._host = value;
+ }
+ } /* }}} */
- public void setHost (string s) { this._host = s; }
- public void setPlugin (string s) { this._plugin = s; }
- public void setPluginInstance (string s) { this._pluginInstance = s; }
- public void setType (string s) { this._type = s; }
- public void setTypeInstance (string s) { this._typeInstance = s; }
+ public string Plugin /* {{{ */
+ {
+ get
+ {
+ return (this._plugin);
+ }
+ set
+ {
+ if ((value == null) || (value.Length < 1))
+ throw new ArgumentException ();
+ this._plugin = value;
+ }
+ } /* }}} string Plugin */
+
+ public string PluginInstance /* {{{ */
+ {
+ get
+ {
+ return (this._pluginInstance);
+ }
+ set
+ {
+ if (value == null)
+ this._pluginInstance = "";
+ else
+ this._pluginInstance = value;
+ }
+ } /* }}} string PluginInstance */
+
+ public string Type /* {{{ */
+ {
+ get
+ {
+ return (this._type);
+ }
+ set
+ {
+ if ((value == null) || (value.Length < 1))
+ throw new ArgumentException ();
+ this._type = value;
+ }
+ } /* }}} string Type */
+
+ public string TypeInstance /* {{{ */
+ {
+ get
+ {
+ return (this._typeInstance);
+ }
+ set
+ {
+ if (value == null)
+ this._typeInstance = "";
+ else
+ this._typeInstance = value;
+ }
+ } /* }}} string TypeInstance */
public override string ToString ()
{
{
this._interval = 10.0;
this._values = new ArrayList ();
- this.setTime (DateTime.Now);
+ this._time = 0.0;
}
public ValueList (ValueList vl)
this._time = vl._time;
}
- public IList getValues ()
+ public IList GetValues ()
{
return (this._values);
}
- public void setValues (IList values)
+ public void SetValues (IList values)
{
this._values = new ArrayList (values);
}
- public void addValue (Value v)
+ public void AddValue (IValue v)
{
this._values.Add (v);
}
- public void clearValues ()
+ public void ClearValues ()
{
this._values.Clear ();
}
- public double getInterval ()
- {
- return (this._interval);
- }
-
- public void setInterval (double interval)
+ public double Interval
{
- if (interval > 0.0)
- this._interval = interval;
+ get
+ {
+ return (this._interval);
+ }
+ set
+ {
+ if (value > 0.0)
+ this._interval = value;
+ }
}
- public double getTime ()
+ public double Time
{
- return (this._time);
+ get
+ {
+ return (this._time);
+ }
+ set
+ {
+ if (value >= 0.0)
+ this._time = value;
+ }
}
- public void setTime (DateTime dt)
+ public void SetTime (DateTime dt)
{
DateTime dtBase = new DateTime (1970,1,1,0,0,0);
TimeSpan tsDiff = dt.ToUniversalTime () - dtBase;
this._time = (double) tsDiff.TotalSeconds;
}
- public void setTime (double t)
- {
- if (t > 0.0)
- this._time = t;
- }
-
public override string ToString ()
{
StringBuilder sb = new StringBuilder ("{");
return (sb.ToString ());
} /* string ToString */
} /* }}} class ValueList */
+
+ [StructLayout (LayoutKind.Explicit)]
+ struct value_u /* {{{ */
+ {
+ /* Emulate a union */
+ [FieldOffset (0)] public double gauge;
+ [FieldOffset (0)] public long derive;
+ } /* }}} struct value_u */
+
+ [StructLayout (LayoutKind.Sequential)]
+ struct value_list_s /* {{{ */
+ {
+ public value_u[] values;
+ public int values_num;
+ public double time;
+ public double interval;
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string host;
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string plugin;
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string plugin_instance;
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string type;
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string type_instance;
+
+ public value_list_s (ValueList vl)
+ {
+ IList values = vl.GetValues ();
+
+ this.values_num = values.Count;
+ this.values = new value_u[this.values_num];
+ for (int i = 0; i < values.Count; i++)
+ {
+ IValue v = values[i] as IValue;
+
+ if (v is GaugeValue)
+ this.values[i].gauge = v.ToDouble ();
+ else
+ this.values[i].derive = v.ToLong ();
+ }
+ this.time = vl.Time;
+ this.interval = vl.Interval;
+
+ this.host = vl.Host;
+ this.plugin = vl.Plugin;
+ this.plugin_instance = vl.PluginInstance;
+ this.type = vl.Type;
+ this.type_instance = vl.TypeInstance;
+ }
+ } /* }}} struct value_list_s */
+
+ public class Collectd /* {{{ */
+ {
+ private static Hashtable _readFunctions = new Hashtable ();
+
+ [DllImport("__Internal", EntryPoint="plugin_log")]
+ private extern static int _log (
+ [MarshalAs(UnmanagedType.SysInt)] int severity,
+ [MarshalAs(UnmanagedType.LPStr)] string message);
+
+ [DllImport("__Internal", EntryPoint="dotnet_register_read")]
+ private extern static int _registerRead (
+ [MarshalAs(UnmanagedType.LPStr)] string name,
+ CollectdReadCallback func);
+
+ [DllImport("__Internal", EntryPoint="dotnet_dispatch_values")]
+ private extern static int _dispatchValues (value_list_s vl);
+
+ public static int DispatchValues (ValueList vl)
+ {
+ return (_dispatchValues (new value_list_s (vl)));
+ }
+
+ public static int LogError (string message)
+ {
+ return (_log (3, message));
+ }
+
+ public static int LogWarning (string message)
+ {
+ return (_log (4, message));
+ }
+
+ public static int LogNotice (string message)
+ {
+ return (_log (5, message));
+ }
+
+ public static int LogInfo (string message)
+ {
+ return (_log (6, message));
+ }
+
+ public static int LogDebug (string message)
+ {
+ return (_log (7, message));
+ }
+
+ public static int RegisterRead (string name, CollectdReadCallback func)
+ {
+ if (_readFunctions.Contains (name))
+ return (-1);
+ _readFunctions.Add (name, func);
+
+ return (_registerRead (name, func));
+ }
+ } /* }}} class Collectd */
+
}
/* vim: set sw=2 sts=2 et fdm=marker : */
#include <mono/metadata/assembly.h>
#include <mono/metadata/threads.h>
-struct dotnet_callback_info_s
+struct dotnet_value_list_s
{
- gint32 domain_id;
- guint32 obj_handle;
+ value_t *values;
+ int values_len;
+ double time;
+ double interval;
+ char *host;
+ char *plugin;
+ char *plugin_instance;
+ char *type;
+ char *type_instance;
};
-typedef struct dotnet_callback_info_s dotnet_callback_info_t;
+typedef struct dotnet_value_list_s dotnet_value_list_t;
+
+typedef int (*dotnet_read_cb) (void);
static MonoDomain *_domain = NULL;
static int dotnet_read (user_data_t *ud) /* {{{ */
{
- dotnet_callback_info_t *ci = ud->data;
- MonoDomain *domain;
- MonoThread *thread;
- MonoClass *class;
- MonoObject *object;
- MonoMethod *method;
- MonoObject *ret;
-
- DEBUG ("dotnet plugin: mono_domain_get_by_id (%"PRIi32") ...",
- (int32_t) ci->domain_id);
- domain = mono_domain_get_by_id (ci->domain_id);
- if (domain == NULL)
- {
- ERROR ("dotnet plugin: mono_domain_get_by_id failed.");
- return (-1);
- }
-
- thread = mono_thread_attach (domain);
- if (thread == NULL)
- {
- ERROR ("dotnet plugin: mono_thread_attach failed.");
- return (-1);
- }
-
- if (!mono_domain_set (domain, /* force = */ 0))
- {
- ERROR ("dotnet plugin: mono_domain_set failed.");
- return (-1);
- }
-
- DEBUG ("dotnet plugin: mono_gchandle_get_target ...");
- object = mono_gchandle_get_target (ci->obj_handle);
- if (object == NULL)
- {
- ERROR ("dotnet plugin: mono_gchandle_get_target failed.");
- mono_thread_detach (thread);
- return (-1);
- }
-
- DEBUG ("dotnet plugin: mono_object_get_class ...");
- class = mono_object_get_class (object);
- if (class == NULL)
- {
- ERROR ("dotnet plugin: mono_object_get_class failed.");
- mono_thread_detach (thread);
- return (-1);
- }
-
- DEBUG ("dotnet plugin: mono_class_get_method_from_name ...");
- method = mono_class_get_method_from_name (class,
- /* name = */ "read", /* nargs = */ 0);
- if (method == NULL)
- {
- ERROR ("dotnet plugin: mono_class_get_method_from_name failed.");
- mono_thread_detach (thread);
- return (-1);
- }
+ dotnet_read_cb cb = ud->data;
- DEBUG ("dotnet plugin: mono_runtime_invoke ...");
- ret = mono_runtime_invoke (method, object, /* params = */ NULL,
- /* exception ptr = */ NULL);
- DEBUG ("dotnet plugin: mono_runtime_invoke returned %p.", (void *) ret);
-
- mono_thread_detach (thread);
- return (0);
+ return ((*cb) ());
} /* }}} int dotnet_read */
-static void dotnet_callback_info_free (void *ptr) /* {{{ */
-{
- dotnet_callback_info_t *ci = ptr;
-
- if (ci == NULL)
- return;
-
- mono_gchandle_free (ci->obj_handle);
- sfree (ci);
-} /* }}} void dotnet_callback_info_free */
-
-static MonoMethod *dotnet_object_method_get_from_name (MonoObject *object, /* {{{ */
- const char *name, int param_count)
-{
- MonoClass *class;
-
- class = mono_object_get_class (object);
- if (class == NULL)
- return (NULL);
-
- while (42)
- {
- MonoClass *pclass;
- MonoMethod *method;
-
- method = mono_class_get_method_from_name (class, name, param_count);
- if (method != NULL)
- return (method);
-
- pclass = mono_class_get_parent (class);
- if ((pclass == NULL) || (pclass == class))
- {
- ERROR ("dotnet plugin: Unable to find method \"%s\" in class \"%s\".",
- name, mono_class_get_name (mono_object_get_class (object)));
- return (NULL);
- }
- class = pclass;
- } /* while (42) */
- /* Not reached */
- return (NULL);
-} /* }}} MonoMethod *dotnet_object_method_get_from_name */
-
-static MonoProperty *dotnet_object_get_property_from_name (MonoObject *object, /* {{{ */
- const char *name)
-{
- MonoClass *class;
-
- class = mono_object_get_class (object);
-
- while (42)
- {
- MonoClass *pclass;
- MonoProperty *prop;
-
- prop = mono_class_get_property_from_name (class, name);
- if (prop != NULL)
- return (prop);
-
- pclass = mono_class_get_parent (class);
- if ((pclass == NULL) || (pclass == class))
- {
- ERROR ("dotnet plugin: Unable to find property \"%s\" in class \"%s\".",
- name, mono_class_get_name (mono_object_get_class (object)));
- return (NULL);
- }
- class = pclass;
- } /* while (42) */
- /* Not reached */
- return (NULL);
-} /* }}} MonoProperty *dotnet_object_get_property_from_name */
-
-static int dotnet_object_method_get_string (MonoObject *obj, /* {{{ */
- const char *method_name, char *buffer, size_t buffer_size)
-{
- MonoMethod *method;
- MonoObject *ret;
- char *tmp;
-
- method = dotnet_object_method_get_from_name (obj, method_name, /* nargs = */ 0);
- if (method == NULL)
- return (-1);
-
- ret = mono_runtime_invoke (method, obj, /* params = */ NULL, /* exception = */ NULL);
- if (ret == NULL)
- return (-2);
-
- tmp = mono_string_to_utf8 ((MonoString *) ret);
- if (tmp == NULL)
- {
- ERROR ("dotnet plugin: mono_string_to_utf8 failed.");
- return (-3);
- }
- DEBUG ("dotnet plugin: Method \"%s\" returned string \"%s\".",
- mono_method_get_name (method), tmp);
-
- sstrncpy (buffer, tmp, buffer_size);
- return (0);
-} /* }}} int dotnet_object_method_get_string */
-
-static int dotnet_object_method_get_cdtime (MonoObject *obj, /* {{{ */
- const char *method_name, cdtime_t *ret_value)
-{
- MonoMethod *method;
- MonoObject *ret_obj;
- double tmp;
-
- method = dotnet_object_method_get_from_name (obj, method_name, /* nargs = */ 0);
- if (method == NULL)
- return (-1);
-
- ret_obj = mono_runtime_invoke (method, obj, /* params = */ NULL, /* exception = */ NULL);
- if (ret_obj == NULL)
- return (-2);
-
- tmp = *((double *) mono_object_unbox (ret_obj));
- DEBUG ("dotnet plugin: Method \"%s\" returned value %.3f.",
- mono_method_get_name (method), tmp);
- *ret_value = DOUBLE_TO_CDTIME_T (tmp);
-
- return (0);
-} /* }}} int dotnet_object_method_get_cdtime */
-
-static int dotnet_object_method_get_values (MonoObject *obj, /* {{{ */
- value_list_t *vl)
-{
- MonoMethod *method;
- MonoObject *ilist_obj;
- MonoObject *tmp_obj;
- MonoProperty *count_prop;
- MonoProperty *item_prop;
- int32_t i;
-
- method = dotnet_object_method_get_from_name (obj, "getValues", /* nargs = */ 0);
- if (method == NULL)
- return (-1);
-
- ilist_obj = mono_runtime_invoke (method, obj, /* params = */ NULL, /* exception = */ NULL);
- if (ilist_obj == NULL)
- return (-2);
-
- count_prop = dotnet_object_get_property_from_name (ilist_obj, "Count");
- if (count_prop == NULL)
- {
- ERROR ("dotnet plugin: dotnet_object_get_property_from_name (\"Count\") failed.");
- return (-4);
- }
-
- item_prop = dotnet_object_get_property_from_name (ilist_obj, "Item");
- if (item_prop == NULL)
- {
- ERROR ("dotnet plugin: dotnet_object_get_property_from_name (\"Item\") failed.");
- return (-5);
- }
-
- method = mono_property_get_get_method (count_prop);
- tmp_obj = mono_runtime_invoke (method, ilist_obj, /* params = */ NULL, /* exception = */ NULL);
- if (tmp_obj == NULL)
- {
- ERROR ("dotnet plugin: mono_runtime_invoke failed.");
- return (-6);
- }
- DEBUG ("dotnet plugin: Type of the Count property is \"%s\".",
- mono_class_get_name (mono_object_get_class (tmp_obj)));
-
- vl->values_len = (int) *((int32_t *) mono_object_unbox (tmp_obj));
- DEBUG ("dotnet plugin: vl->values_len = %i;", vl->values_len);
-
- if (vl->values_len <= 0)
- {
- vl->values_len = 0;
- return (-7);
- }
-
- vl->values = calloc ((size_t) vl->values_len, sizeof (*vl->values));
- if (vl->values == NULL)
- {
- vl->values_len = 0;
- return (-8);
- }
-
- for (i = 0; i < ((int32_t) vl->values_len); i++)
- {
- void *args[2] = { &i, NULL };
- MonoObject *value_obj;
- const char *class_name;
-
- method = mono_property_get_get_method (item_prop);
- value_obj = mono_runtime_invoke (method, ilist_obj, /* params = */ args, /* exception = */ NULL);
- if (value_obj == NULL)
- {
- ERROR ("dotnet plugin: Item(%i) failed.", i);
- return (-7);
- }
-
- class_name = mono_class_get_name (mono_object_get_class (value_obj));
- if (strcmp ("gaugeValue", class_name) == 0)
- {
- MonoObject *gauge_obj;
-
- method = dotnet_object_method_get_from_name (value_obj, "toDouble", /* nargs = */ 0);
- if (method == NULL)
- return (-9);
-
- gauge_obj = mono_runtime_invoke (method, value_obj, /* args = */ NULL, /* exception = */ NULL);
- if (gauge_obj == NULL)
- return (-10);
-
- vl->values[i].gauge = (gauge_t) *((double *) mono_object_unbox (gauge_obj));
- DEBUG ("dotnet plugin: Gauge value %"PRIi32" = %g;",
- i, vl->values[i].gauge);
- }
- else if (strcmp ("deriveValue", class_name) == 0)
- {
- MonoObject *derive_obj;
-
- method = dotnet_object_method_get_from_name (value_obj, "toLong", /* nargs = */ 0);
- if (method == NULL)
- return (-9);
-
- derive_obj = mono_runtime_invoke (method, value_obj, /* args = */ NULL, /* exception = */ NULL);
- if (derive_obj == NULL)
- return (-10);
-
- vl->values[i].derive = (derive_t) *((int64_t *) mono_object_unbox (derive_obj));
- DEBUG ("dotnet plugin: Derive value %"PRIi32" = %"PRIi64";",
- i, vl->values[i].derive);
- }
- }
-
- return (0);
-} /* }}} int dotnet_object_method_get_values */
-
/*
* Functions exposed to .Net
*/
-static int dotnet_log (int severity, MonoString *message) /* {{{ */
-{
- char *tmp = mono_string_to_utf8 (message);
-
- DEBUG ("dotnet_log (severity = %i, message = \"%s\");", severity, tmp);
-
- return (0);
-} /* }}} int dotnet_log */
-
-static int dotnet_register_read (MonoString *name, MonoObject *obj) /* {{{ */
+int dotnet_register_read (const char *name, dotnet_read_cb cb) /* {{{ */
{
user_data_t ud;
- dotnet_callback_info_t *ci;
- MonoClass *class;
- MonoMethod *method;
-
- /* Sanity checks: Make sure this object actually has the required method. */
- class = mono_object_get_class (obj);
- if (class == NULL)
- {
- ERROR ("dotnet plugin: mono_object_get_class failed.");
- return (-1);
- }
-
- method = mono_class_get_method_from_name (class,
- /* name = */ "read", /* param count = */ 0);
- if (method == NULL)
- {
- ERROR ("dotnet plugin: mono_class_get_method_from_name failed.");
- return (-1);
- }
-
- ci = malloc (sizeof (*ci));
- if (ci == NULL)
- {
- ERROR ("dotnet plugin: malloc failed.");
- return (-1);
- }
- memset (ci, 0, sizeof (*ci));
-
- ci->domain_id = mono_domain_get_id (mono_domain_get ());
- ci->obj_handle = mono_gchandle_new (obj, /* pinned = */ 1);
-
- ud.data = ci;
- ud.free_func = dotnet_callback_info_free;
+ memset (&ud, 0, sizeof (ud));
+ ud.data = cb;
+ ud.free_func = NULL;
plugin_register_complex_read (/* group = */ "dotnet",
- /* name = */ mono_string_to_utf8 (name),
+ /* name = */ name,
/* callback = */ dotnet_read,
/* interval = */ NULL,
/* user data = */ &ud);
return (0);
} /* }}} int dotnet_register_read */
-static int dotnet_dispatch_values (MonoObject *obj) /* {{{ */
+int dotnet_dispatch_values (dotnet_value_list_t *dvl) /* {{{ */
{
value_list_t vl = VALUE_LIST_INIT;
- int status;
- status = dotnet_object_method_get_string (obj, "getHost", vl.host, sizeof (vl.host));
- if (status != 0)
- return (status);
+ vl.values = dvl->values;
+ vl.values_len = dvl->values_len;
- status = dotnet_object_method_get_string (obj, "getPlugin", vl.plugin, sizeof (vl.plugin));
- if (status != 0)
- return (status);
+ if (dvl->time > 0.0)
+ vl.time = DOUBLE_TO_CDTIME_T (dvl->time);
+ else
+ vl.interval = 0;
- status = dotnet_object_method_get_string (obj, "getPluginInstance", vl.plugin_instance, sizeof (vl.plugin_instance));
- if (status != 0)
- return (status);
+ if (dvl->interval > 0.0)
+ vl.interval = DOUBLE_TO_CDTIME_T (dvl->interval);
+ else
+ vl.interval = interval_g;
- status = dotnet_object_method_get_string (obj, "getType", vl.type, sizeof (vl.type));
- if (status != 0)
- return (status);
-
- status = dotnet_object_method_get_string (obj, "getTypeInstance", vl.type_instance, sizeof (vl.type_instance));
- if (status != 0)
- return (status);
-
- status = dotnet_object_method_get_cdtime (obj, "getInterval", &vl.interval);
- if (status != 0)
- return (status);
+ sstrncpy (vl.host, dvl->host, sizeof (vl.host));
+ sstrncpy (vl.plugin, dvl->plugin, sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, dvl->plugin_instance, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, dvl->type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, dvl->type_instance, sizeof (vl.type_instance));
- status = dotnet_object_method_get_cdtime (obj, "getTime", &vl.time);
- if (status != 0)
- return (status);
-
- status = dotnet_object_method_get_values (obj, &vl);
- if (status != 0)
- return (status);
-
- status = plugin_dispatch_values (&vl);
- sfree (vl.values);
-
- return (status);
+ return (plugin_dispatch_values (&vl));
} /* }}} int dotnet_dispatch_values */
/*
return;
}
- mono_add_internal_call ("CollectdAPI.Collectd::log", dotnet_log);
- mono_add_internal_call ("CollectdAPI.Collectd::registerRead", dotnet_register_read);
- mono_add_internal_call ("CollectdAPI.Collectd::dispatchValues", dotnet_dispatch_values);
-
plugin_register_complex_config ("dotnet", dotnet_config);
} /* void module_register */