libprelude/master: Initial prelude-log C++/Python/Ruby/Perl/Lua bindings support.

[email protected] Wed, 8 Jul 2009 16:51:57 +0200 (CEST)
Newsgroups gmane.comp.security.ids.prelude.cvs
Message-ID <[email protected]>
commit dfed1bc7fb7dbb3eaeac20b36f7738ea582378d2
Author: Yoann Vandoorselaere <[email protected]>
Date:   Fri Jun 19 00:33:19 2009 +0200

    Initial prelude-log C++/Python/Ruby/Perl/Lua bindings support.
    
    This implement language bindings for the PreludeLog interface. High
    level language use a specific check so that the log callback is not
    called from a different thread than the initialisation thread, since
    we cannot efficiently protect SWIG generated object.


========================================

 bindings/c++/Makefile.am               |    3 +-
 bindings/c++/include/Makefile.am       |    3 +-
 bindings/c++/include/prelude-log.hxx   |   56 ++++++++++++++++++++++++++++++++
 bindings/c++/prelude-log.cxx           |   42 ++++++++++++++++++++++++
 bindings/libpreludecpp-perl.i          |   41 ++++++++++++++++++++++-
 bindings/libpreludecpp.i               |    5 +++
 bindings/lua/Makefile.am               |    2 +-
 bindings/lua/libpreludecpp-lua.i       |   35 +++++++++++++++++++-
 bindings/perl/Makefile.PL.in           |    2 +-
 bindings/python/libpreludecpp-python.i |   34 +++++++++++++++++++
 bindings/python/setup.py.in            |    2 +-
 bindings/ruby/Makefile.am              |    2 +-
 bindings/ruby/libpreludecpp-ruby.i     |   31 +++++++++++++++++-
 bindings/tests/test.lua                |    5 +++
 bindings/tests/test.pl                 |    9 +++++
 bindings/tests/test.py                 |    6 +++
 bindings/tests/test.rb                 |    1 +
 17 files changed, 268 insertions(+), 11 deletions(-)

========================================

diff --git a/bindings/c++/Makefile.am b/bindings/c++/Makefile.am
index 5bffc88..d4519cd 100644
--- a/bindings/c++/Makefile.am
+++ b/bindings/c++/Makefile.am
@@ -16,7 +16,8 @@ libpreludecpp_la_SOURCES = \
 	prelude-client-easy.cxx \
 	prelude-client-profile.cxx \
 	prelude-connection.cxx	\
-	prelude-connection-pool.cxx
+	prelude-connection-pool.cxx \
+	prelude-log.cxx
 
 libpreludecpp_la_LDFLAGS = -no-undefined -version-info @LIBPRELUDECPP_SONAME@
 libpreludecpp_la_LIBADD  = $(top_builddir)/src/.libs/libprelude.la
diff --git a/bindings/c++/include/Makefile.am b/bindings/c++/include/Makefile.am
index 596ce78..17cc572 100644
--- a/bindings/c++/include/Makefile.am
+++ b/bindings/c++/include/Makefile.am
@@ -12,7 +12,8 @@ include_HEADERS = \
 	prelude-client-easy.hxx \
 	prelude-client-profile.hxx \
 	prelude-connection.hxx	\
-	prelude-connection-pool.hxx
+	prelude-connection-pool.hxx \
+	prelude-log.hxx
 
 
 -include $(top_srcdir)/git.mk
diff --git a/bindings/c++/include/prelude-log.hxx b/bindings/c++/include/prelude-log.hxx
new file mode 100644
index 0000000..328f2e8
--- /dev/null
+++ b/bindings/c++/include/prelude-log.hxx
@@ -0,0 +1,56 @@
+/*****
+*
+* Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
+* Author: Yoann Vandoorselaere <[email protected]>
+*
+* This file is part of the Prelude library.
+*
+* This program 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, or (at your option)
+* any later version.
+*
+* This program 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; see the file COPYING.  If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****/
+
+#ifndef _LIBPRELUDE_PRELUDE_LOG_HXX
+#define _LIBPRELUDE_PRELUDE_LOG_HXX
+
+#include "prelude.h"
+#include "idmef-path.h"
+
+
+namespace Prelude {
+        class PreludeLog {
+            public:
+                enum LogLevelEnum {
+                        DEBUG    = PRELUDE_LOG_DEBUG,
+                        INFO     = PRELUDE_LOG_INFO,
+                        WARNING  = PRELUDE_LOG_WARN,
+                        ERROR    = PRELUDE_LOG_ERR,
+                        CRITICAL = PRELUDE_LOG_CRIT
+                };
+
+                enum LogFlagsEnum {
+                        QUIET    = PRELUDE_LOG_FLAGS_QUIET,
+                        SYSLOG   = PRELUDE_LOG_FLAGS_SYSLOG
+                };
+
+                static void SetLevel(int level);
+                static void SetDebugLevel(int level);
+                static void SetFlags(int flags);
+                static int GetFlags(void);
+                static void SetLogfile(const char *filename);
+                static void SetCallback(void (*log_cb)(int level, const char *log));
+        };
+};
+
+#endif
diff --git a/bindings/c++/prelude-log.cxx b/bindings/c++/prelude-log.cxx
new file mode 100644
index 0000000..d2d729d
--- /dev/null
+++ b/bindings/c++/prelude-log.cxx
@@ -0,0 +1,42 @@
+#include <prelude.h>
+
+#include <prelude-log.hxx>
+
+
+using namespace Prelude;
+
+void PreludeLog::SetLevel(int level)
+{
+        prelude_log_set_level((prelude_log_t) level);
+}
+
+
+void PreludeLog::SetDebugLevel(int level)
+{
+        prelude_log_set_debug_level(level);
+}
+
+
+void PreludeLog::SetFlags(int flags)
+{
+        prelude_log_set_flags((prelude_log_flags_t) flags);
+}
+
+
+int PreludeLog::GetFlags()
+{
+        return prelude_log_get_flags();
+}
+
+
+void PreludeLog::SetLogfile(const char *filename)
+{
+        prelude_log_set_logfile(filename);
+}
+
+
+void PreludeLog::SetCallback(void (*log_cb)(int level, const char *log))
+{
+
+        prelude_log_set_callback((void (*)(prelude_log_t level, const char *log)) log_cb);
+}
diff --git a/bindings/libpreludecpp-perl.i b/bindings/libpreludecpp-perl.i
index caa8f85..2b7488c 100644
--- a/bindings/libpreludecpp-perl.i
+++ b/bindings/libpreludecpp-perl.i
@@ -55,7 +55,32 @@ SV *IDMEFValueList_to_SWIG(const Prelude::IDMEFValue &value)
         $1 = $input;
 }
 
-%{
+%fragment("TransitionFunc", "header") {
+static SV *__prelude_log_func;
+static gl_thread_t __initial_thread;
+
+
+static void _cb_perl_log(int level, const char *str)
+{
+        if ( (gl_thread_t) gl_thread_self() != __initial_thread )
+                return;
+
+        dSP;
+        ENTER;
+        SAVETMPS;
+
+        PUSHMARK(SP);
+        XPUSHs(SWIG_From_int(level));
+        XPUSHs(SWIG_FromCharPtr(str));
+        PUTBACK;
+
+        perl_call_sv(__prelude_log_func, G_VOID);
+
+        FREETMPS;
+        LEAVE;
+}
+
+
 static int _cb_perl_write(prelude_msgbuf_t *fd, prelude_msg_t *msg)
 {
         int ret;
@@ -85,7 +110,17 @@ static ssize_t _cb_perl_read(prelude_io_t *fd, void *buf, size_t size)
 
         return ret;
 }
-%}
+};
+
+%typemap(in, fragment="TransitionFunc") void (*log_cb)(int level, const char *log) {
+        if ( __prelude_log_func )
+                SvREFCNT_dec(__prelude_log_func);
+
+        __prelude_log_func = $input;
+        SvREFCNT_inc($input);
+
+        $1 = _cb_perl_log;
+};
 
 %extend Prelude::IDMEF {
         void Write(void *nocast_p) {
@@ -129,6 +164,8 @@ static ssize_t _cb_perl_read(prelude_io_t *fd, void *buf, size_t size)
         int j, argc = 1, ret;
         AV *pargv = get_av("ARGV", FALSE);
 
+        __initial_thread = (gl_thread_t) gl_thread_self();
+
         ret = av_len(pargv);
         if ( ret >= 0 )
                 argc += ret + 1;
diff --git a/bindings/libpreludecpp.i b/bindings/libpreludecpp.i
index b01f0e8..8057685 100644
--- a/bindings/libpreludecpp.i
+++ b/bindings/libpreludecpp.i
@@ -8,7 +8,10 @@
 #include <list>
 #include <sstream>
 
+#include "config.h"
+
 #include "prelude.hxx"
+#include "prelude-log.hxx"
 #include "prelude-error.hxx"
 #include "prelude-connection.hxx"
 #include "prelude-connection-pool.hxx"
@@ -20,6 +23,7 @@
 #include "idmef-path.hxx"
 #include "idmef-time.hxx"
 #include "idmef.hxx"
+#include "glthread/thread.h"
 
 using namespace Prelude;
 %}
@@ -207,6 +211,7 @@ int IDMEFValue_to_SWIG(const IDMEFValue &result, TARGET_LANGUAGE_OUTPUT_TYPE ret
 %ignore operator prelude_client_profile_t *() const;
 
 %include prelude.hxx
+%include prelude-log.hxx
 %include prelude-error.hxx
 %include prelude-connection.hxx
 %include prelude-connection-pool.hxx
diff --git a/bindings/lua/Makefile.am b/bindings/lua/Makefile.am
index 168a581..0a1ad9b 100644
--- a/bindings/lua/Makefile.am
+++ b/bindings/lua/Makefile.am
@@ -4,7 +4,7 @@ EXTRA_DIST = libpreludecpp-lua.i PreludeEasy.cxx
 
 if HAVE_LUA
 
-AM_CPPFLAGS = -I@top_srcdir@ -I@top_builddir@/src/include -I@top_srcdir@/src/include -I@top_builddir@/src/libprelude-error -I@top_srcdir@/bindings/c++/include @LUA_CFLAGS@
+AM_CPPFLAGS = -I@top_srcdir@ -I@top_builddir@/src/include -I@top_srcdir@/src/include -I@top_builddir@/src/libprelude-error -I@top_srcdir@/bindings/c++/include @LUA_CFLAGS@ -I@top_srcdir@/libmissing -I@top_builddir@/libmissing
 
 PreludeEasy_la_LDFLAGS = -module -avoid-version @LUA_LIBS@
 PreludeEasy_la_LIBADD = $(top_builddir)/bindings/c++/.libs/libpreludecpp.la
diff --git a/bindings/lua/libpreludecpp-lua.i b/bindings/lua/libpreludecpp-lua.i
index 58c0b03..b762d2d 100644
--- a/bindings/lua/libpreludecpp-lua.i
+++ b/bindings/lua/libpreludecpp-lua.i
@@ -110,7 +110,23 @@ int IDMEFValue_to_SWIG(lua_State* L, const IDMEFValue &result);
         $1 = *pf;
 }
 
-%{
+%fragment("TransitionFunc", "header") {
+static int __prelude_log_func;
+static lua_State *__lua_state = NULL;
+static gl_thread_t __initial_thread;
+
+static void _cb_lua_log(int level, const char *str)
+{
+        if ( (gl_thread_t) gl_thread_self() != __initial_thread )
+                return;
+
+        lua_rawgeti(__lua_state, LUA_REGISTRYINDEX, __prelude_log_func);
+        lua_pushnumber(__lua_state, level);
+        lua_pushstring(__lua_state, str);
+        lua_call(__lua_state, 2, 0);
+}
+
+
 static int _cb_lua_write(prelude_msgbuf_t *fd, prelude_msg_t *msg)
 {
         size_t ret;
@@ -140,7 +156,20 @@ static ssize_t _cb_lua_read(prelude_io_t *fd, void *buf, size_t size)
         return ret;
 }
 
-%}
+};
+
+
+%typemap(in, fragment="TransitionFunc") void (*log_cb)(int level, const char *log) {
+        if ( ! lua_isfunction(L, -1) )
+                SWIG_exception(SWIG_ValueError, "Argument should be a function");
+
+        if ( __lua_state )
+                luaL_unref(L, LUA_REGISTRYINDEX, __prelude_log_func);
+
+        __prelude_log_func = luaL_ref(L, LUA_REGISTRYINDEX);
+        $1 = _cb_lua_log;
+        __lua_state = L;
+};
 
 
 %extend Prelude::IDMEF {
@@ -291,6 +320,8 @@ int IDMEFValue_to_SWIG(lua_State* L, const IDMEFValue &result)
         int argc = 0, ret;
         static char *argv[1024];
 
+        __initial_thread = (gl_thread_t) gl_thread_self();
+
         lua_getglobal(L, "arg");
         lua_pushnil(L);
 
diff --git a/bindings/perl/Makefile.PL.in b/bindings/perl/Makefile.PL.in
index d2182e2..912ed2b 100644
--- a/bindings/perl/Makefile.PL.in
+++ b/bindings/perl/Makefile.PL.in
@@ -5,7 +5,7 @@ use File::Copy;
 use Cwd "abs_path";
 
 my %attributs = (NAME => 'PreludeEasy',
-		 INC => '-I@top_srcdir@ -I@top_builddir@/src/include -I@top_srcdir@/src/include -I@top_builddir@/src/libprelude-error -I@top_srcdir@/bindings/c++/include',
+		 INC => '-I@top_srcdir@ -I@top_builddir@/src/include -I@top_srcdir@/src/include -I@top_builddir@/src/libprelude-error -I@top_srcdir@/bindings/c++/include -I@top_srcdir@/libmissing -I@top_builddir@/libmissing',
 		 LIBS => ["-L@top_builddir@/src/.libs -lprelude -L@top_builddir@/bindings/c++/.libs -lpreludecpp", "-L$ENV{LIBDIR} -lprelude @LIBPRELUDE_LIBS@ @LIBADD_DL@ @LTLIBTHREAD@" ],
 		 LDDLFLAGS => "-L@top_builddir@/src/.libs $Config{lddlflags}");
 
diff --git a/bindings/python/libpreludecpp-python.i b/bindings/python/libpreludecpp-python.i
index d8f9e02..afa0fd6 100644
--- a/bindings/python/libpreludecpp-python.i
+++ b/bindings/python/libpreludecpp-python.i
@@ -15,6 +15,25 @@ int IDMEFValue_to_SWIG(const IDMEFValue &result, TARGET_LANGUAGE_OUTPUT_TYPE ret
 
 
 %{
+static gl_thread_t __initial_thread;
+PyObject *__prelude_log_func = NULL;
+
+static void _cb_python_log(int level, const char *str)
+{
+        PyObject *arglist, *result;
+
+        SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+
+        arglist = Py_BuildValue("(i,s)", level, str);
+        result = PyEval_CallObject(__prelude_log_func, arglist);
+
+        Py_DECREF(arglist);
+        Py_XDECREF(result);
+
+        SWIG_PYTHON_THREAD_END_BLOCK;
+}
+
+
 static int _cb_python_write(prelude_msgbuf_t *fd, prelude_msg_t *msg)
 {
         size_t ret;
@@ -48,6 +67,19 @@ static ssize_t _cb_python_read(prelude_io_t *fd, void *buf, size_t size)
 }
 %}
 
+%typemap(in) void (*log_cb)(int level, const char *log) {
+        if ( ! PyCallable_Check($input) )
+                SWIG_exception_fail(SWIG_ValueError, "Argument is not a callable object");
+
+        if ( __prelude_log_func )
+                Py_DECREF(__prelude_log_func);
+
+        __prelude_log_func = $input;
+        Py_INCREF($input);
+
+        $1 = _cb_python_log;
+};
+
 
 /* tell squid not to cast void * value */
 %typemap(in) void *nocast_file_p {
@@ -128,6 +160,8 @@ PyObject *IDMEFValueList_to_SWIG(const Prelude::IDMEFValue &value)
         PyObject *sys = PyImport_ImportModule("sys");
         PyObject *pyargv = PyObject_GetAttrString(sys, "argv");
 
+        __initial_thread = (gl_thread_t) gl_thread_self();
+
         argc = PyObject_Length(pyargv);
         assert(argc >= 1);
         assert(PyList_Check(pyargv));
diff --git a/bindings/python/setup.py.in b/bindings/python/setup.py.in
index 85f0437..ec053f8 100644
--- a/bindings/python/setup.py.in
+++ b/bindings/python/setup.py.in
@@ -84,6 +84,6 @@ setup(name="PreludeEasy",
       py_modules=["PreludeEasy"],
       ext_modules=[Extension("_PreludeEasy",
                              ["_PreludeEasy.cxx"],
-                             extra_compile_args=split_args("-I@top_builddir@ -I@top_srcdir@/src/include -I@top_builddir@/src/include -I@top_builddir@/src/libprelude-error -I@top_srcdir@/bindings/c++/include"),
+                             extra_compile_args=split_args("-I@top_builddir@ -I@top_srcdir@/src/include -I@top_builddir@/src/include -I@top_builddir@/src/libprelude-error -I@top_srcdir@/bindings/c++/include -I@top_srcdir@/libmissing -I@top_builddir@/libmissing"),
                              library_dirs=[ "@top_builddir@/src/.libs/", "@top_builddir@/bindings/c++/.libs/" ],
                              extra_link_args=split_args("-lpreludecpp -lprelude @LIBPRELUDE_LIBS@ @LIBADD_DL@ @LTLIBTHREAD@"))])
diff --git a/bindings/ruby/Makefile.am b/bindings/ruby/Makefile.am
index 4796152..d8351fc 100644
--- a/bindings/ruby/Makefile.am
+++ b/bindings/ruby/Makefile.am
@@ -4,7 +4,7 @@ if HAVE_RUBY
 EXTRA_DIST = libpreludecpp-ruby.i PreludeEasy.cxx
 
 rbexec_LTLIBRARIES = PreludeEasy.la
-PreludeEasy_la_CPPFLAGS = $(RUBY_INCLUDES) $(RUBY_CCFLAGS) -I@top_builddir@ -I$(top_srcdir)/src/include -I$(top_builddir)/src/include -I@top_builddir@/src/libprelude-error -I$(top_srcdir)/bindings/c++/include
+PreludeEasy_la_CPPFLAGS = $(RUBY_INCLUDES) $(RUBY_CCFLAGS) -I@top_builddir@ -I$(top_srcdir)/src/include -I$(top_builddir)/src/include -I@top_builddir@/src/libprelude-error -I$(top_srcdir)/bindings/c++/include -I@top_srcdir@/libmissing -I@top_builddir@/libmissing
 PreludeEasy_la_LDFLAGS = -module -avoid-version
 PreludeEasy_la_LIBADD = $(top_builddir)/bindings/c++/.libs/libpreludecpp.la $(RUBY_LIBS)
 nodist_PreludeEasy_la_SOURCES = PreludeEasy.cxx
diff --git a/bindings/ruby/libpreludecpp-ruby.i b/bindings/ruby/libpreludecpp-ruby.i
index d533b91..7b7fe01 100644
--- a/bindings/ruby/libpreludecpp-ruby.i
+++ b/bindings/ruby/libpreludecpp-ruby.i
@@ -23,6 +23,23 @@ int IDMEFValue_to_SWIG(const IDMEFValue &result, TARGET_LANGUAGE_OUTPUT_TYPE ret
 extern "C" {
 #include "rubyio.h"
 }
+%};
+
+
+%fragment("TransitionFunc", "header") {
+static gl_thread_t __initial_thread;
+static VALUE __prelude_log_func = Qnil;
+
+static void _cb_ruby_log(int level, const char *str)
+{
+        static int cid = rb_intern("call");
+
+        if ( (gl_thread_t) gl_thread_self() != __initial_thread )
+                return;
+
+        rb_funcall(__prelude_log_func, cid, 2, SWIG_From_int(level), SWIG_FromCharPtr(str));
+}
+
 
 static int _cb_ruby_write(prelude_msgbuf_t *fd, prelude_msg_t *msg)
 {
@@ -63,8 +80,18 @@ static ssize_t _cb_ruby_read(prelude_io_t *fd, void *buf, size_t size)
 
         return ret;
 }
+};
 
-%}
+
+%typemap(in, fragment="TransitionFunc") void (*log_cb)(int level, const char *log) {
+        if ( ! SWIG_Ruby_isCallable($input) )
+                SWIG_exception_fail(SWIG_ValueError, "Argument is not a callable object");
+
+        __prelude_log_func = $input;
+        rb_global_variable(&$input);
+
+        $1 = _cb_ruby_log;
+};
 
 
 %extend Prelude::IDMEF {
@@ -136,6 +163,8 @@ VALUE IDMEFValueList_to_SWIG(const Prelude::IDMEFValue &value)
         int _i, argc;
         VALUE rbargv, *ptr;
 
+        __initial_thread = (gl_thread_t) gl_thread_self();
+
         rbargv = rb_const_get(rb_cObject, rb_intern("ARGV"));
         argc = RARRAY(rbargv)->len + 1;
 
diff --git a/bindings/tests/test.lua b/bindings/tests/test.lua
index d2ef641..38e176f 100755
--- a/bindings/tests/test.lua
+++ b/bindings/tests/test.lua
@@ -2,6 +2,11 @@
 
 require("PreludeEasy")
 
+function my_cb(level, log)
+	io.write("log: " .. log)
+end
+PreludeEasy.PreludeLog_SetCallback(my_cb)
+
 idmef = PreludeEasy.IDMEF()
 
 print("*** IDMEF->Set() ***")
diff --git a/bindings/tests/test.pl b/bindings/tests/test.pl
index 937c298..3eaabd7 100755
--- a/bindings/tests/test.pl
+++ b/bindings/tests/test.pl
@@ -2,7 +2,16 @@
 
 use PreludeEasy;
 
+sub log_func {
+	($level, $str) = @_;
+	print("log: " . $str);
+}
+
+PreludeEasy::PreludeLog::SetCallback(\&log_func);
+
 $idmef = new PreludeEasy::IDMEF;
+$client = new PreludeEasy::ClientEasy("abc");
+$client->Start();
 
 print "*** IDMEF->Set() ***\n";
 $idmef->Set("alert.classification.text", "My Message");
diff --git a/bindings/tests/test.py b/bindings/tests/test.py
index 770617a..fe68e32 100755
--- a/bindings/tests/test.py
+++ b/bindings/tests/test.py
@@ -1,7 +1,13 @@
 #!/usr/bin/env python
 
+import sys
 import PreludeEasy
 
+def log_cb(level, str):
+	sys.stdout.write("log: " + str)
+
+PreludeEasy.PreludeLog.SetCallback(log_cb)
+
 idmef = PreludeEasy.IDMEF()
 
 print "*** IDMEF->Set() ***"
diff --git a/bindings/tests/test.rb b/bindings/tests/test.rb
index a6cbea2..1998ebe 100755
--- a/bindings/tests/test.rb
+++ b/bindings/tests/test.rb
@@ -2,6 +2,7 @@
 
 require("PreludeEasy")
 
+PreludeEasy::PreludeLog::SetCallback(lambda{|level,str|print "log: " + str})
 idmef = PreludeEasy::IDMEF.new()
 
 print "*** IDMEF->Set() ***\n"
_______________________________________________
Prelude-cvslog site list
[email protected]
http://lists.prelude-ids.org/mailman/listinfo/prelude-cvslog