Module: sems
Branch: master
Commit: 21ddd3ca67ee4fdc643ed26516a6c710842803bb
URL:    
http://git.sip-router.org/cgi-bin/gitweb.cgi/sems/?a=commit;h=21ddd3ca67ee4fdc643ed26516a6c710842803bb

Author: Stefan Sayer <[email protected]>
Committer: Stefan Sayer <[email protected]>
Date:   Thu Mar  8 14:26:01 2012 +0100

dsm: mod_regex module for regular expressions in DSM

---

 apps/dsm/mods/mod_regex/CMakeLists.txt     |    7 ++
 apps/dsm/mods/mod_regex/Makefile           |   10 ++
 apps/dsm/mods/mod_regex/ModRegex.cpp       |  163 ++++++++++++++++++++++++++++
 apps/dsm/mods/mod_regex/ModRegex.h         |   65 +++++++++++
 apps/dsm/mods/mod_regex/etc/mod_regex.conf |    6 +
 doc/dsm/mods/Readme.mod_regex.txt          |   30 +++++
 6 files changed, 281 insertions(+), 0 deletions(-)

diff --git a/apps/dsm/mods/mod_regex/CMakeLists.txt 
b/apps/dsm/mods/mod_regex/CMakeLists.txt
new file mode 100644
index 0000000..007a582
--- /dev/null
+++ b/apps/dsm/mods/mod_regex/CMakeLists.txt
@@ -0,0 +1,7 @@
+set (mod_regex_SRCS
+ModRegex.cpp
+)
+
+SET(sems_dsm_module_name mod_regex)
+INCLUDE(${CMAKE_SOURCE_DIR}/cmake/dsm.lib.rules.txt)
+
diff --git a/apps/dsm/mods/mod_regex/Makefile b/apps/dsm/mods/mod_regex/Makefile
new file mode 100644
index 0000000..8cd44a4
--- /dev/null
+++ b/apps/dsm/mods/mod_regex/Makefile
@@ -0,0 +1,10 @@
+plug_in_name = mod_regex
+
+DSMPATH ?= ../..
+
+module_ldflags = 
+module_cflags  = -DMOD_NAME=\"$(plug_in_name)\" -I$(DSMPATH) 
+
+COREPATH ?=$(DSMPATH)/../../core
+lib_full_name = $(DSMPATH)/mods/lib/$(lib_name)
+include $(DSMPATH)/mods/Makefile.dsm_module
diff --git a/apps/dsm/mods/mod_regex/ModRegex.cpp 
b/apps/dsm/mods/mod_regex/ModRegex.cpp
new file mode 100644
index 0000000..0e562e0
--- /dev/null
+++ b/apps/dsm/mods/mod_regex/ModRegex.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2012 Stefan Sayer
+ * 
+ * This file is part of SEMS, a free SIP media server.
+ *
+ * SEMS 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. This program is released under
+ * the GPL with the additional exemption that compiling, linking,
+ * and/or using OpenSSL is allowed.
+ *
+ * For a license to use the SEMS software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * SEMS 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ModRegex.h"
+
+#include "log.h"
+#include "AmUtils.h"
+#include "AmConfigReader.h"
+
+SC_EXPORT(MOD_CLS_NAME);
+
+map<string, TsRegex> MOD_CLS_NAME::regexes;
+
+MOD_ACTIONEXPORT_BEGIN(MOD_CLS_NAME) {
+
+  DEF_CMD("regex.compile", SCCompileRegexAction);
+  DEF_CMD("regex.match", SCExecRegexAction);
+  DEF_CMD("regex.clear", SCClearRegexAction);
+} MOD_ACTIONEXPORT_END;
+
+MOD_CONDITIONEXPORT_BEGIN(MOD_CLS_NAME) {
+
+  if (cmd == "regex.match") {
+    return new SCExecRegexCondition(params, false);
+  }
+
+} MOD_CONDITIONEXPORT_END;
+
+int MOD_CLS_NAME::preload() {
+   AmConfigReader cfg;
+   if(cfg.loadPluginConf(MOD_NAME)) {
+     INFO("no module configuration for '%s' found, not preloading regular 
expressions\n",
+         MOD_NAME);
+     return 0;
+   }
+
+   bool failed = false;
+   for (std::map<string,string>::const_iterator it =
+         cfg.begin(); it != cfg.end(); it++) {
+     if (add_regex(it->first, it->second)) {
+       ERROR("compiling regex '%s' for '%s'\n",
+            it->second.c_str(), it->first.c_str());
+       failed = true;
+     } else {
+       DBG("compiled regex '%s' as '%s'\n", it->second.c_str(), 
it->first.c_str());
+     }
+   }
+
+   return failed? -1 : 0;
+}
+
+int MOD_CLS_NAME::add_regex(const string& r_name, const string& r_reg) {
+  if (regexes[r_name].regcomp(r_reg.c_str(), REG_NOSUB | REG_EXTENDED)) {
+    ERROR("compiling '%s' for regex '%s'\n", r_reg.c_str(), r_name.c_str());
+    regexes.erase(r_name);
+    return -1;
+  }
+  return 0;
+}
+
+
+CONST_CONDITION_2P(SCExecRegexCondition, ',', false);
+MATCH_CONDITION_START(SCExecRegexCondition) {
+  DBG("checking condition '%s' '%s'\n", par1.c_str(), par2.c_str());
+  return true;
+} MATCH_CONDITION_END;
+
+
+CONST_ACTION_2P(SCCompileRegexAction, ',', false);
+EXEC_ACTION_START(SCCompileRegexAction) {
+  string rname = resolveVars(par1, sess, sc_sess, event_params);
+  string rval = par2; //resolveVars(par2, sess, sc_sess, event_params);
+  DBG("compiling '%s' for regex '%s'\n", rval.c_str(), rname.c_str());
+
+  if (MOD_CLS_NAME::add_regex(rname, rval)) {
+    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
+    ERROR("compiling '%s' for regex '%s'\n", rval.c_str(), rname.c_str());
+  }
+} EXEC_ACTION_END;
+
+CONST_ACTION_2P(SCExecRegexAction, ',', false);
+EXEC_ACTION_START(SCExecRegexAction) {
+  string rname = resolveVars(par1, sess, sc_sess, event_params);
+  string val = resolveVars(par2, sess, sc_sess, event_params);
+  DBG("matching '%s' on regex '%s'\n", val.c_str(), rname.c_str());
+  map<string, TsRegex>::iterator it=MOD_CLS_NAME::regexes.find(rname);
+  if (it == MOD_CLS_NAME::regexes.end()) {
+    ERROR("regex '%s' not found for matching '%s'\n", rname.c_str(), 
val.c_str());
+    EXEC_ACTION_STOP;
+  }
+
+  int res = it->second.regexec(val.c_str(), 1, NULL, 0);
+  if (!res) {
+    // yeah side effects
+    sc_sess->var["regex.match"] = "1";
+  } else {
+    sc_sess->var["regex.match"] = "0";
+  }
+} EXEC_ACTION_END;
+
+EXEC_ACTION_START(SCClearRegexAction) {
+  string r_name = resolveVars(arg, sess, sc_sess, event_params);
+  DBG("clearing  regex '%s'\n", r_name.c_str());
+  MOD_CLS_NAME::regexes.erase(r_name);
+} EXEC_ACTION_END;
+
+TsRegex::TsRegex()
+  : i(false) { }
+
+TsRegex::~TsRegex()
+{
+  if (i) {
+    regfree(&reg);
+  }
+}
+
+int TsRegex::regcomp(const char *regex, int cflags) {
+  m.lock();
+  if (i) {
+    regfree(&reg);
+  }
+  int res = ::regcomp(&reg, regex, cflags);
+  if (!res)
+    i=true;
+  m.unlock();
+  return res;
+}
+
+int TsRegex::regexec(const char *_string, size_t nmatch,
+                    regmatch_t pmatch[], int eflags) {
+  if (!i) {
+    ERROR("uninitialized regex when matching '%s'\n", _string);
+    return -1;
+  }
+  m.lock();
+  int res = ::regexec(&reg, _string, nmatch, pmatch, eflags);
+  m.unlock();
+  return res;
+}
diff --git a/apps/dsm/mods/mod_regex/ModRegex.h 
b/apps/dsm/mods/mod_regex/ModRegex.h
new file mode 100644
index 0000000..f553389
--- /dev/null
+++ b/apps/dsm/mods/mod_regex/ModRegex.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 Stefan Sayer
+ *
+ * This file is part of SEMS, a free SIP media server.
+ *
+ * SEMS 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. This program is released under
+ * the GPL with the additional exemption that compiling, linking,
+ * and/or using OpenSSL is allowed.
+ *
+ * For a license to use the SEMS software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * SEMS 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _MOD_REGEX_H
+#define _MOD_REGEX_H
+#include "DSMModule.h"
+#include "DSMSession.h"
+
+#define MOD_CLS_NAME SCRegexModule
+
+#include <sys/types.h>
+#include <regex.h>
+#include <map>
+
+// in some earlier versions of libc apparently regex were inot thread-safe
+class TsRegex {
+  regex_t reg;
+  AmMutex m;
+  bool i;
+
+ public:
+  TsRegex(); 
+  ~TsRegex();
+  int regcomp(const char *regex, int cflags);
+  int regexec(const char *_string, size_t nmatch, regmatch_t pmatch[], int 
eflags);
+
+};
+
+DECLARE_MODULE_BEGIN(MOD_CLS_NAME);
+int preload();
+static map<string, TsRegex> regexes;
+static int add_regex(const string& r_name, const string& r_reg);
+DECLARE_MODULE_END;
+ /* }; */
+
+
+DEF_ACTION_2P(SCCompileRegexAction);
+DEF_ACTION_2P(SCExecRegexAction);
+DEF_ACTION_1P(SCClearRegexAction);
+DEF_CONDITION_2P(SCExecRegexCondition);
+
+#endif
diff --git a/apps/dsm/mods/mod_regex/etc/mod_regex.conf 
b/apps/dsm/mods/mod_regex/etc/mod_regex.conf
new file mode 100644
index 0000000..91503da
--- /dev/null
+++ b/apps/dsm/mods/mod_regex/etc/mod_regex.conf
@@ -0,0 +1,6 @@
+# list of regex's to compile on start
+# use preload_mods=mod_regex in dsm.conf if you want to use those
+
+# ex:
+#my_r1=^sip:
+#my_r2=mydomain\.net
\ No newline at end of file
diff --git a/doc/dsm/mods/Readme.mod_regex.txt 
b/doc/dsm/mods/Readme.mod_regex.txt
new file mode 100644
index 0000000..bf74068
--- /dev/null
+++ b/doc/dsm/mods/Readme.mod_regex.txt
@@ -0,0 +1,30 @@
+mod_regex - regular expressions
+
+This module uses regex(3) for regular expressions.
+
+Regular expressions are referenced by a regex name. They are compiled using
+regex.compile action or by adding a line to mod_regex.conf and preloading
+mod_regex. The compiled regular expressions can be used with the action
+regex.match or the condition regex.match.
+
+Actions:
+regex.compile(name, reg_ex)
+ Compile a regular expressions in reg_ex to be referenced by name.
+ REG_NOSUB | REG_EXTENDED is used.
+
+regex.match(name, match_string)
+ Match match_string on regex referenced by name.
+ $regex.match is set to 1 if matched, 0 if not matched.
+
+regex.clear(name)
+ Clear the regex referenced by name.
+
+Conditions:
+ regex.match(name, match_string)
+  Match match_string on regex referenced by name.
+
+
+
+TODO:
+ - implement substring adressing
+ - find a better way for $regex.match side-effect

_______________________________________________
Semsdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/semsdev

Reply via email to