|
@@ -0,0 +1,871 @@
|
|
|
+/**
|
|
|
+ * Copyright (C) 2011 Daniel-Constantin Mierla (asipto.com)
|
|
|
+ *
|
|
|
+ * This file is part of Kamailio, a free SIP server.
|
|
|
+ *
|
|
|
+ * Kamailio is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
|
+ * (at your option) any later version
|
|
|
+ *
|
|
|
+ * Kamailio is distributed in the hope that it will be useful,
|
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+ * GNU General Public License for more details.
|
|
|
+ *
|
|
|
+ * You should have received a copy of the GNU General Public License
|
|
|
+ * along with this program; if not, write to the Free Software
|
|
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <sys/stat.h>
|
|
|
+#include <unistd.h>
|
|
|
+
|
|
|
+#include "../../core/data_lump.h"
|
|
|
+#include "../../core/data_lump_rpl.h"
|
|
|
+#include "../../core/dprint.h"
|
|
|
+#include "../../core/mem/mem.h"
|
|
|
+#include "../../core/sr_module.h"
|
|
|
+#include "../../core/strutils.h"
|
|
|
+#include "../../core/ut.h"
|
|
|
+
|
|
|
+#include "app_mono_api.h"
|
|
|
+
|
|
|
+#include <mono/metadata/mono-config.h>
|
|
|
+
|
|
|
+#define SRVERSION "1.0"
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+typedef struct _sr_mono_load {
|
|
|
+ char *script;
|
|
|
+ MonoDomain *domain;
|
|
|
+ MonoAssembly *assembly;
|
|
|
+ struct _sr_mono_load *next;
|
|
|
+} sr_mono_load_t;
|
|
|
+
|
|
|
+static sr_mono_load_t *_sr_mono_load_list = NULL;
|
|
|
+
|
|
|
+int sr_mono_load_class_core();
|
|
|
+int sr_mono_load_class_pv();
|
|
|
+int sr_mono_load_class_hdr();
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static sr_mono_env_t _sr_M_env;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @return the static Mono env
|
|
|
+ */
|
|
|
+sr_mono_env_t *sr_mono_env_get(void) { return &_sr_M_env; }
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int sr_mono_load_script(char *script) {
|
|
|
+ sr_mono_load_t *mi;
|
|
|
+
|
|
|
+ if (_sr_mono_load_list != NULL) {
|
|
|
+ LM_ERR("only one assembly can be loaded\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ mi = (sr_mono_load_t *)pkg_malloc(sizeof(sr_mono_load_t));
|
|
|
+ if (mi == NULL) {
|
|
|
+ PKG_MEM_ERROR;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ memset(mi, 0, sizeof(sr_mono_load_t));
|
|
|
+ mi->script = script;
|
|
|
+ mi->next = _sr_mono_load_list;
|
|
|
+ _sr_mono_load_list = mi;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int sr_mono_assembly_loaded(void) {
|
|
|
+ if (_sr_mono_load_list != NULL)
|
|
|
+ return 1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int sr_mono_register_module(char *mname) {
|
|
|
+ // if(mono_sr_exp_register_mod(mname)==0)
|
|
|
+ // return 0;
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int mono_sr_init_mod(void) {
|
|
|
+ memset(&_sr_M_env, 0, sizeof(sr_mono_env_t));
|
|
|
+ // if(mono_sr_exp_init_mod()<0)
|
|
|
+ // return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int mono_sr_init_load(void) {
|
|
|
+ sr_mono_load_t *mi;
|
|
|
+ if (_sr_mono_load_list == NULL) {
|
|
|
+ LM_DBG("no assembly to load\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ mono_config_parse(NULL);
|
|
|
+ mi = _sr_mono_load_list;
|
|
|
+ if (mi && mi->domain != NULL) {
|
|
|
+ LM_ERR("worker mono environment already initialized\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ while (mi != NULL) {
|
|
|
+ mi->domain = mono_jit_init(mi->script);
|
|
|
+ if (mi->domain == NULL) {
|
|
|
+ LM_ERR("failed to init domain for: %s\n", mi->script);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ sr_mono_load_class_core();
|
|
|
+ sr_mono_load_class_pv();
|
|
|
+ sr_mono_load_class_hdr();
|
|
|
+
|
|
|
+ mi->assembly = mono_domain_assembly_open(mi->domain, mi->script);
|
|
|
+ if (mi->assembly == NULL) {
|
|
|
+ LM_ERR("failed to open assembly: %s\n", mi->script);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ mi = mi->next;
|
|
|
+ /* only one (first) assembly for now */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int mono_sr_init_probe(void) {
|
|
|
+ /* todo: test if assemblies exist */
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int mono_sr_init_child(void) {
|
|
|
+ memset(&_sr_M_env, 0, sizeof(sr_mono_env_t));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Load the default Mono configuration file, this is needed
|
|
|
+ * if you are planning on using the dllmaps defined on the
|
|
|
+ * system configuration
|
|
|
+ */
|
|
|
+ mono_config_parse(NULL);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+void mono_sr_destroy(void) { memset(&_sr_M_env, 0, sizeof(sr_mono_env_t)); }
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int mono_sr_initialized(void) {
|
|
|
+ if (_sr_M_env.domain == NULL)
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int app_mono_exec(struct sip_msg *msg, char *script, char *param) {
|
|
|
+ int ret;
|
|
|
+ char *argv[2];
|
|
|
+ int argc;
|
|
|
+
|
|
|
+ argc = 1;
|
|
|
+ argv[0] = script;
|
|
|
+ if (param != NULL) {
|
|
|
+ argc++;
|
|
|
+ argv[1] = param;
|
|
|
+ }
|
|
|
+ LM_DBG("executing Mono assembly: [[%s]]\n", argv[0]);
|
|
|
+ _sr_M_env.msg = msg;
|
|
|
+
|
|
|
+ mono_config_parse(NULL);
|
|
|
+ /*
|
|
|
+ * mono_jit_init() creates a domain: each assembly is
|
|
|
+ * loaded and run in a MonoDomain.
|
|
|
+ */
|
|
|
+ _sr_M_env.domain = mono_jit_init(argv[0]);
|
|
|
+ /*
|
|
|
+ * We add our special internal functions, so that C# code
|
|
|
+ * can call us back.
|
|
|
+ */
|
|
|
+ sr_mono_load_class_core();
|
|
|
+ sr_mono_load_class_pv();
|
|
|
+ sr_mono_load_class_hdr();
|
|
|
+
|
|
|
+ _sr_M_env.assembly = mono_domain_assembly_open(_sr_M_env.domain, argv[0]);
|
|
|
+ if (_sr_M_env.assembly == NULL) {
|
|
|
+ ret = -1;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * mono_jit_exec() will run the Main() method in the assembly.
|
|
|
+ * The return value needs to be looked up from
|
|
|
+ * System.Environment.ExitCode.
|
|
|
+ */
|
|
|
+ mono_jit_exec(_sr_M_env.domain, _sr_M_env.assembly, argc, argv);
|
|
|
+ ret = mono_environment_exitcode_get();
|
|
|
+ LM_DBG("returned code from mono environment: %d\n", ret);
|
|
|
+
|
|
|
+done:
|
|
|
+ mono_jit_cleanup(_sr_M_env.domain);
|
|
|
+
|
|
|
+ memset(&_sr_M_env, 0, sizeof(sr_mono_env_t));
|
|
|
+ return (ret == 0) ? 1 : -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+int app_mono_run(struct sip_msg *msg, char *arg) {
|
|
|
+ int ret;
|
|
|
+ char *argv[2];
|
|
|
+ int argc;
|
|
|
+ sr_mono_load_t *mi;
|
|
|
+
|
|
|
+ if (_sr_mono_load_list == NULL)
|
|
|
+ return -1;
|
|
|
+ mi = _sr_mono_load_list;
|
|
|
+
|
|
|
+ LM_DBG("running Mono assembly: [[%s]]\n", mi->script);
|
|
|
+ _sr_M_env.msg = msg;
|
|
|
+
|
|
|
+ _sr_M_env.domain = mi->domain;
|
|
|
+ _sr_M_env.assembly = mi->assembly;
|
|
|
+ if (_sr_M_env.assembly == NULL) {
|
|
|
+ LM_DBG("empty assembly\n");
|
|
|
+ memset(&_sr_M_env, 0, sizeof(sr_mono_env_t));
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ mono_domain_set(_sr_M_env.domain, 0);
|
|
|
+ argc = 1;
|
|
|
+ argv[0] = mi->script;
|
|
|
+ if (arg != NULL) {
|
|
|
+ argc++;
|
|
|
+ argv[1] = arg;
|
|
|
+ }
|
|
|
+ mono_jit_exec(_sr_M_env.domain, _sr_M_env.assembly, argc, argv);
|
|
|
+ ret = mono_environment_exitcode_get();
|
|
|
+ LM_DBG("returned code from mono environment: %d\n", ret);
|
|
|
+
|
|
|
+ memset(&_sr_M_env, 0, sizeof(sr_mono_env_t));
|
|
|
+ return (ret == 0) ? 1 : -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static MonoString *sr_mono_api_version() {
|
|
|
+ return mono_string_new(mono_domain_get(), SRVERSION);
|
|
|
+}
|
|
|
+
|
|
|
+static void sr_mono_log(int level, MonoString *text) {
|
|
|
+ char *logmsg;
|
|
|
+ logmsg = mono_string_to_utf8(text);
|
|
|
+ LOG(level, "%s", logmsg);
|
|
|
+ mono_free(logmsg);
|
|
|
+}
|
|
|
+
|
|
|
+static void sr_mono_err(MonoString *text) {
|
|
|
+ char *logmsg;
|
|
|
+ logmsg = mono_string_to_utf8(text);
|
|
|
+ LOG(L_ERR, "%s", logmsg);
|
|
|
+ mono_free(logmsg);
|
|
|
+}
|
|
|
+
|
|
|
+static void sr_mono_dbg(MonoString *text) {
|
|
|
+ char *logmsg;
|
|
|
+ logmsg = mono_string_to_utf8(text);
|
|
|
+ LOG(L_DBG, "%s", logmsg);
|
|
|
+ mono_free(logmsg);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_modf(MonoString *nfunc) {
|
|
|
+ int ret;
|
|
|
+ int mod_type;
|
|
|
+ struct run_act_ctx ra_ctx;
|
|
|
+ struct action *act = NULL;
|
|
|
+ ksr_cmd_export_t *expf;
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+ char *func = NULL;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ if (env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ func = mono_string_to_utf8(nfunc);
|
|
|
+
|
|
|
+ expf = find_export_record(func, 0, 0);
|
|
|
+ if (expf == NULL) {
|
|
|
+ LM_ERR("function '%s' is not available\n", func);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ /* check fixups */
|
|
|
+ if (expf->fixup != NULL && expf->free_fixup == NULL) {
|
|
|
+ LM_ERR("function '%s' has fixup - cannot be used\n", func);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ mod_type = MODULE0_T;
|
|
|
+
|
|
|
+ act = mk_action(mod_type, 1 /* number of (type, value) pairs */, MODEXP_ST,
|
|
|
+ expf, /* function */
|
|
|
+ NUMBER_ST, 0, /* parameter number */
|
|
|
+ STRING_ST, NULL, /* param. 1 */
|
|
|
+ STRING_ST, NULL, /* param. 2 */
|
|
|
+ STRING_ST, NULL, /* param. 3 */
|
|
|
+ STRING_ST, NULL, /* param. 4 */
|
|
|
+ STRING_ST, NULL, /* param. 5 */
|
|
|
+ STRING_ST, NULL /* param. 6 */
|
|
|
+ );
|
|
|
+
|
|
|
+ if (act == NULL) {
|
|
|
+ LM_ERR("action structure could not be created for '%s'\n", func);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* handle fixups */
|
|
|
+ if (expf->fixup) {
|
|
|
+ /* no parameters */
|
|
|
+ if (expf->fixup(0, 0) < 0) {
|
|
|
+ LM_ERR("Error in fixup (0) for '%s'\n", func);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ init_run_actions_ctx(&ra_ctx);
|
|
|
+ ret = do_action(&ra_ctx, act, env_M->msg);
|
|
|
+ pkg_free(act);
|
|
|
+ mono_free(func);
|
|
|
+ return ret;
|
|
|
+
|
|
|
+error:
|
|
|
+ if (func != NULL)
|
|
|
+ mono_free(func);
|
|
|
+ if (act != NULL)
|
|
|
+ pkg_free(act);
|
|
|
+ return -127;
|
|
|
+}
|
|
|
+
|
|
|
+static const sr_M_export_t _sr_M_export_core[] = {
|
|
|
+ {"SR.Core::APIVersion", sr_mono_api_version},
|
|
|
+ {"SR.Core::Log", sr_mono_log},
|
|
|
+ {"SR.Core::Err", sr_mono_err},
|
|
|
+ {"SR.Core::Dbg", sr_mono_dbg},
|
|
|
+ {"SR.Core::ModF", sr_mono_modf},
|
|
|
+ {NULL, NULL}};
|
|
|
+
|
|
|
+int sr_mono_load_class_core() {
|
|
|
+ int i;
|
|
|
+ for (i = 0; _sr_M_export_core[i].name != NULL; i++)
|
|
|
+ mono_add_internal_call(_sr_M_export_core[i].name,
|
|
|
+ _sr_M_export_core[i].method);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static MonoString *sr_mono_pv_gets(MonoString *pv) {
|
|
|
+ str pvn = {0};
|
|
|
+ pv_spec_t *pvs;
|
|
|
+ pv_value_t val;
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+ int pl;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+
|
|
|
+ pvn.s = mono_string_to_utf8(pv);
|
|
|
+ if (pvn.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ pvn.len = strlen(pvn.s);
|
|
|
+ LM_DBG("pv get: %s\n", pvn.s);
|
|
|
+ pl = pv_locate_name(&pvn);
|
|
|
+ if (pl != pvn.len) {
|
|
|
+ LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ pvs = pv_cache_get(&pvn);
|
|
|
+ if (pvs == NULL) {
|
|
|
+ LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ memset(&val, 0, sizeof(pv_value_t));
|
|
|
+ if (pv_get_spec_value(env_M->msg, pvs, &val) != 0) {
|
|
|
+ LM_ERR("unable to get pv value for [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ if ((val.flags & PV_VAL_NULL) || !(val.flags & PV_VAL_STR)) {
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return mono_string_new_len(mono_domain_get(), val.rs.s, val.rs.len);
|
|
|
+
|
|
|
+error:
|
|
|
+ if (pvn.s != NULL)
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_pv_geti(MonoString *pv) {
|
|
|
+ str pvn = {0};
|
|
|
+ pv_spec_t *pvs;
|
|
|
+ pv_value_t val;
|
|
|
+ int pl;
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ pvn.s = mono_string_to_utf8(pv);
|
|
|
+
|
|
|
+ if (pvn.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ pvn.len = strlen(pvn.s);
|
|
|
+ LM_DBG("pv get: %s\n", pvn.s);
|
|
|
+ pl = pv_locate_name(&pvn);
|
|
|
+ if (pl != pvn.len) {
|
|
|
+ LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ pvs = pv_cache_get(&pvn);
|
|
|
+ if (pvs == NULL) {
|
|
|
+ LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ memset(&val, 0, sizeof(pv_value_t));
|
|
|
+ if (pv_get_spec_value(env_M->msg, pvs, &val) != 0) {
|
|
|
+ LM_ERR("unable to get pv value for [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ if ((val.flags & PV_VAL_NULL) || !(val.flags & PV_TYPE_INT)) {
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return val.ri;
|
|
|
+
|
|
|
+error:
|
|
|
+ if (pvn.s != NULL)
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_pv_seti(MonoString *pv, int iv) {
|
|
|
+ str pvn = {0};
|
|
|
+ pv_spec_t *pvs;
|
|
|
+ pv_value_t val;
|
|
|
+ int pl;
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ pvn.s = mono_string_to_utf8(pv);
|
|
|
+
|
|
|
+ if (pvn.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ memset(&val, 0, sizeof(pv_value_t));
|
|
|
+ val.ri = iv;
|
|
|
+ val.flags |= PV_TYPE_INT | PV_VAL_INT;
|
|
|
+
|
|
|
+ pvn.len = strlen(pvn.s);
|
|
|
+ LM_DBG("pv set: %s\n", pvn.s);
|
|
|
+ pl = pv_locate_name(&pvn);
|
|
|
+ if (pl != pvn.len) {
|
|
|
+ LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ pvs = pv_cache_get(&pvn);
|
|
|
+ if (pvs == NULL) {
|
|
|
+ LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ if (pv_set_spec_value(env_M->msg, pvs, 0, &val) < 0) {
|
|
|
+ LM_ERR("unable to set pv [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return 0;
|
|
|
+error:
|
|
|
+ if (pvn.s != NULL)
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_pv_sets(MonoString *pv, MonoString *sv) {
|
|
|
+ str pvn = {0};
|
|
|
+ pv_spec_t *pvs;
|
|
|
+ pv_value_t val;
|
|
|
+ int pl;
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ pvn.s = mono_string_to_utf8(pv);
|
|
|
+
|
|
|
+ if (pvn.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ memset(&val, 0, sizeof(pv_value_t));
|
|
|
+ val.rs.s = mono_string_to_utf8(sv);
|
|
|
+ if (val.rs.s == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ val.rs.len = strlen(val.rs.s);
|
|
|
+ val.flags |= PV_VAL_STR;
|
|
|
+
|
|
|
+ pvn.len = strlen(pvn.s);
|
|
|
+ LM_DBG("pv set: %s\n", pvn.s);
|
|
|
+ pl = pv_locate_name(&pvn);
|
|
|
+ if (pl != pvn.len) {
|
|
|
+ LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ pvs = pv_cache_get(&pvn);
|
|
|
+ if (pvs == NULL) {
|
|
|
+ LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ if (pv_set_spec_value(env_M->msg, pvs, 0, &val) < 0) {
|
|
|
+ LM_ERR("unable to set pv [%s]\n", pvn.s);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return 0;
|
|
|
+error:
|
|
|
+ if (pvn.s != NULL)
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_pv_unset(MonoString *pv) {
|
|
|
+ str pvn = {0};
|
|
|
+ pv_spec_t *pvs;
|
|
|
+ pv_value_t val;
|
|
|
+ int pl;
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ pvn.s = mono_string_to_utf8(pv);
|
|
|
+
|
|
|
+ if (pvn.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ pvn.len = strlen(pvn.s);
|
|
|
+ LM_DBG("pv unset: %s\n", pvn.s);
|
|
|
+ pl = pv_locate_name(&pvn);
|
|
|
+ if (pl != pvn.len) {
|
|
|
+ LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ pvs = pv_cache_get(&pvn);
|
|
|
+ if (pvs == NULL) {
|
|
|
+ LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ memset(&val, 0, sizeof(pv_value_t));
|
|
|
+ val.flags |= PV_VAL_NULL;
|
|
|
+ if (pv_set_spec_value(env_M->msg, pvs, 0, &val) < 0) {
|
|
|
+ LM_ERR("unable to unset pv [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return 0;
|
|
|
+error:
|
|
|
+ if (pvn.s != NULL)
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_pv_is_null(MonoString *pv) {
|
|
|
+ str pvn = {0};
|
|
|
+ pv_spec_t *pvs;
|
|
|
+ pv_value_t val;
|
|
|
+ int pl;
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ pvn.s = mono_string_to_utf8(pv);
|
|
|
+
|
|
|
+ if (pvn.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ pvn.len = strlen(pvn.s);
|
|
|
+ LM_DBG("pv is null test: %s\n", pvn.s);
|
|
|
+ pl = pv_locate_name(&pvn);
|
|
|
+ if (pl != pvn.len) {
|
|
|
+ LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ pvs = pv_cache_get(&pvn);
|
|
|
+ if (pvs == NULL) {
|
|
|
+ LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ memset(&val, 0, sizeof(pv_value_t));
|
|
|
+ if (pv_get_spec_value(env_M->msg, pvs, &val) != 0) {
|
|
|
+ LM_INFO("unable to get pv value for [%s]\n", pvn.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ mono_free(pvn.s);
|
|
|
+ if (val.flags & PV_VAL_NULL) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+error:
|
|
|
+ if (pvn.s != NULL)
|
|
|
+ mono_free(pvn.s);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static const sr_M_export_t _sr_M_export_pv[] = {
|
|
|
+ {"SR.PV::GetS", sr_mono_pv_gets},
|
|
|
+ {"SR.PV::GetI", sr_mono_pv_geti},
|
|
|
+ {"SR.PV::SetI", sr_mono_pv_seti},
|
|
|
+ {"SR.PV::SetS", sr_mono_pv_sets},
|
|
|
+ {"SR.PV::Unset", sr_mono_pv_unset},
|
|
|
+ {"SR.PV::IsNull", sr_mono_pv_is_null},
|
|
|
+ {NULL, NULL}};
|
|
|
+
|
|
|
+int sr_mono_load_class_pv() {
|
|
|
+ int i;
|
|
|
+ for (i = 0; _sr_M_export_pv[i].name != NULL; i++)
|
|
|
+ mono_add_internal_call(_sr_M_export_pv[i].name, _sr_M_export_pv[i].method);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_hdr_append(MonoString *hv) {
|
|
|
+ struct lump *anchor;
|
|
|
+ struct hdr_field *hf;
|
|
|
+ char *hdr;
|
|
|
+ str txt = {0};
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ txt.s = mono_string_to_utf8(hv);
|
|
|
+
|
|
|
+ if (txt.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ txt.len = strlen(txt.s);
|
|
|
+
|
|
|
+ LM_DBG("append hf: %s\n", txt.s);
|
|
|
+ if (parse_headers(env_M->msg, HDR_EOH_F, 0) == -1) {
|
|
|
+ LM_ERR("error while parsing message\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ hf = env_M->msg->last_header;
|
|
|
+ hdr = (char *)pkg_malloc(txt.len + 1);
|
|
|
+ if (hdr == NULL) {
|
|
|
+ PKG_MEM_ERROR;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ memcpy(hdr, txt.s, txt.len);
|
|
|
+ hdr[txt.len] = '\0';
|
|
|
+ anchor =
|
|
|
+ anchor_lump(env_M->msg, hf->name.s + hf->len - env_M->msg->buf, 0, 0);
|
|
|
+ if ((anchor == NULL) ||
|
|
|
+ (insert_new_lump_before(anchor, hdr, txt.len, 0) == 0)) {
|
|
|
+ LM_ERR("can't insert lump\n");
|
|
|
+ pkg_free(hdr);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ mono_free(txt.s);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+error:
|
|
|
+ if (txt.s != NULL)
|
|
|
+ mono_free(txt.s);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_hdr_remove(MonoString *hv) {
|
|
|
+ struct lump *anchor;
|
|
|
+ struct hdr_field *hf;
|
|
|
+ str hname;
|
|
|
+ str txt = {0};
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ txt.s = mono_string_to_utf8(hv);
|
|
|
+
|
|
|
+ if (txt.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ txt.len = strlen(txt.s);
|
|
|
+
|
|
|
+ LM_DBG("remove hf: %s\n", txt.s);
|
|
|
+ if (parse_headers(env_M->msg, HDR_EOH_F, 0) == -1) {
|
|
|
+ LM_ERR("error while parsing message\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ hname.s = txt.s;
|
|
|
+ hname.len = txt.len;
|
|
|
+ for (hf = env_M->msg->headers; hf; hf = hf->next) {
|
|
|
+ if (cmp_hdrname_str(&hf->name, &hname) == 0) {
|
|
|
+ anchor = del_lump(env_M->msg, hf->name.s - env_M->msg->buf, hf->len, 0);
|
|
|
+ if (anchor == 0) {
|
|
|
+ LM_ERR("cannot remove hdr %s\n", txt.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mono_free(txt.s);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+error:
|
|
|
+ if (txt.s != NULL)
|
|
|
+ mono_free(txt.s);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_hdr_insert(MonoString *hv) {
|
|
|
+ struct lump *anchor;
|
|
|
+ struct hdr_field *hf;
|
|
|
+ char *hdr;
|
|
|
+ str txt = {0};
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ txt.s = mono_string_to_utf8(hv);
|
|
|
+
|
|
|
+ if (txt.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ txt.len = strlen(txt.s);
|
|
|
+
|
|
|
+ LM_DBG("insert hf: %s\n", txt.s);
|
|
|
+ hf = env_M->msg->headers;
|
|
|
+ hdr = (char *)pkg_malloc(txt.len + 1);
|
|
|
+ if (hdr == NULL) {
|
|
|
+ PKG_MEM_ERROR;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ memcpy(hdr, txt.s, txt.len);
|
|
|
+ hdr[txt.len] = '\0';
|
|
|
+ anchor =
|
|
|
+ anchor_lump(env_M->msg, hf->name.s + hf->len - env_M->msg->buf, 0, 0);
|
|
|
+ if ((anchor == NULL) ||
|
|
|
+ (insert_new_lump_before(anchor, hdr, txt.len, 0) == 0)) {
|
|
|
+ LM_ERR("can't insert lump\n");
|
|
|
+ pkg_free(hdr);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ mono_free(txt.s);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+error:
|
|
|
+ if (txt.s != NULL)
|
|
|
+ mono_free(txt.s);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int sr_mono_hdr_append_to_reply(MonoString *hv) {
|
|
|
+ str txt = {0};
|
|
|
+ sr_mono_env_t *env_M;
|
|
|
+
|
|
|
+ env_M = sr_mono_env_get();
|
|
|
+ txt.s = mono_string_to_utf8(hv);
|
|
|
+
|
|
|
+ if (txt.s == NULL || env_M->msg == NULL)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ txt.len = strlen(txt.s);
|
|
|
+
|
|
|
+ LM_DBG("append to reply: %s\n", txt.s);
|
|
|
+
|
|
|
+ if (add_lump_rpl(env_M->msg, txt.s, txt.len, LUMP_RPL_HDR) == 0) {
|
|
|
+ LM_ERR("unable to add reply lump\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ mono_free(txt.s);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+error:
|
|
|
+ if (txt.s != NULL)
|
|
|
+ mono_free(txt.s);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ */
|
|
|
+static const sr_M_export_t _sr_M_export_hdr[] = {
|
|
|
+ {"SR.HDR::Append", sr_mono_hdr_append},
|
|
|
+ {"SR.HDR::Remove", sr_mono_hdr_remove},
|
|
|
+ {"SR.HDR::Insert", sr_mono_hdr_insert},
|
|
|
+ {"SR.HDR::AppendToReply", sr_mono_hdr_append_to_reply},
|
|
|
+ {NULL, NULL}};
|
|
|
+
|
|
|
+int sr_mono_load_class_hdr() {
|
|
|
+ int i;
|
|
|
+ for (i = 0; _sr_M_export_hdr[i].name != NULL; i++)
|
|
|
+ mono_add_internal_call(_sr_M_export_hdr[i].name,
|
|
|
+ _sr_M_export_hdr[i].method);
|
|
|
+ return 0;
|
|
|
+}
|