Bladeren bron

modules/app_java - New module app_java: Java Native Interface support.

Konstantin Mosesov 12 jaren geleden
bovenliggende
commit
c5f47af145
36 gewijzigde bestanden met toevoegingen van 4334 en 0 verwijderingen
  1. 54 0
      modules/app_java/BUILDING_JAR.TXT
  2. 29 0
      modules/app_java/Makefile
  3. 25 0
      modules/app_java/QUICKSTART.TXT
  4. 48 0
      modules/app_java/global.h
  5. 284 0
      modules/app_java/java_iface.c
  6. 44 0
      modules/app_java/java_iface.h
  7. 260 0
      modules/app_java/java_mod.c
  8. 30 0
      modules/app_java/java_mod.h
  9. 324 0
      modules/app_java/java_msgobj.c
  10. 34 0
      modules/app_java/java_msgobj.h
  11. 1223 0
      modules/app_java/java_native_methods.c
  12. 86 0
      modules/app_java/java_native_methods.h
  13. 439 0
      modules/app_java/java_sig_parser.c
  14. 50 0
      modules/app_java/java_sig_parser.h
  15. 207 0
      modules/app_java/java_support.c
  16. 37 0
      modules/app_java/java_support.h
  17. BIN
      modules/app_java/kamailio_java_folder/java-untested/Kamailio.class
  18. 388 0
      modules/app_java/kamailio_java_folder/java-untested/Kamailio.java
  19. 87 0
      modules/app_java/kamailio_java_folder/java-untested/WrappedMethods.java
  20. 46 0
      modules/app_java/kamailio_java_folder/java-untested/build.xml
  21. BIN
      modules/app_java/kamailio_java_folder/java-untested/kamailio.jar
  22. 34 0
      modules/app_java/kamailio_java_folder/java-untested/siprouter_src/CoreMethods.java
  23. 15 0
      modules/app_java/kamailio_java_folder/java-untested/siprouter_src/IPPair.java
  24. 46 0
      modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeInterface.java
  25. 22 0
      modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeMethods.java
  26. 43 0
      modules/app_java/kamailio_java_folder/java-untested/siprouter_src/SipMsg.java
  27. BIN
      modules/app_java/kamailio_java_folder/java/Kamailio.class
  28. 130 0
      modules/app_java/kamailio_java_folder/java/Kamailio.java
  29. 46 0
      modules/app_java/kamailio_java_folder/java/build.xml
  30. BIN
      modules/app_java/kamailio_java_folder/java/kamailio.jar
  31. 15 0
      modules/app_java/kamailio_java_folder/java/siprouter_src/IPPair.java
  32. 46 0
      modules/app_java/kamailio_java_folder/java/siprouter_src/NativeInterface.java
  33. 23 0
      modules/app_java/kamailio_java_folder/java/siprouter_src/NativeMethods.java
  34. 43 0
      modules/app_java/kamailio_java_folder/java/siprouter_src/SipMsg.java
  35. 137 0
      modules/app_java/utils.c
  36. 39 0
      modules/app_java/utils.h

+ 54 - 0
modules/app_java/BUILDING_JAR.TXT

@@ -0,0 +1,54 @@
+
+Prerequistites:
+1) Java JDK (either openjdk or oracle's)
+2) GNU Java Compiler (gcj)
+3) Apache ANT (http://ant.apache.org/)
+
+Build process:
+
+1) Open Kamailio.java with any text editor and change (if differs) a FULL PATH to app_java.so :
+   Example:
+        static
+        {
+            System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+        }
+
+2) Type: ant
+   Example: ant
+Buildfile: /opt/dev/kamailio/modules/app_java/build.xml
+
+clean:
+   [delete] Deleting directory /opt/dev/kamailio/modules/app_java/build
+   [delete] Deleting: /opt/dev/kamailio/modules/app_java/Kamailio.class
+
+make.dirs:
+    [mkdir] Created dir: /opt/dev/kamailio/modules/app_java/build
+
+siprouter_compile:
+    [javac] Compiling 4 source files to /opt/dev/kamailio/modules/app_java/build
+
+kamailio.jar:
+      [jar] Building jar: /opt/dev/kamailio/modules/app_java/kamailio.jar
+
+main_compile:
+    [javac] Compiling 1 source file to /opt/dev/kamailio/modules/app_java
+
+all:
+     [echo] Building Kamailio examples
+
+BUILD SUCCESSFUL
+Total time: 4 seconds
+
+3) If no errors, copy file kamailio.jar into 'java' directory (see file app_java.mod)
+4) Copy file Kamailio.class to 'java' folder.
+5) Enjoy! :)
+
+
+
+
+
+
+
+
+
+

+ 29 - 0
modules/app_java/Makefile

@@ -0,0 +1,29 @@
+# $Id$
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=app_java.so
+
+#DEFS += -DEXTRA_DEBUG
+
+
+# for now is hard coded, will resolve this later
+JAVA_HOME ?= /usr/lib/jvm/java-gcj-4.7
+DEFS += $(shell pkg-config libgcj-4.7 --cflags) -I$(JAVA_HOME)/include
+LIBS += $(shell pkg-config libgcj-4.7 --libs) -L$(JAVA_HOME)/lib  -ljvm
+
+ifeq ($(OS), freebsd)
+LIBS+=-pthread
+endif
+
+# disable optimisation for segfaults debugging
+INCLUDE += -O0 -g
+INCLUDES += -O0 -g
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+include ../../Makefile.modules
+

+ 25 - 0
modules/app_java/QUICKSTART.TXT

@@ -0,0 +1,25 @@
+
+Quick start:
+----------------------
+1) Supposed that kamailio home folder is '/opt/kamailio' (I'll use a term '<KAM_HOME>')
+2) mkdir <KAM_HOME>/java (I'll use a term <KAM_JAVA_HOME>)
+3) copy kamailio.jar to <KAM_JAVA_HOME>
+4) copy Kamailio.class to <KAM_JAVA_HOME>
+5) add to kamailio configuration file:
+
+loadmodule "app_java.so"
+modparam("app_java", "class_name", "Kamailio")
+modparam("app_java", "child_init_method", "child_init")
+modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=<KAM_HOME>/lib/kamailio/modules:<KAM_JAVA_HOME>:<KAM_JAVA_HOME>/kamailio.jar  -verbose:gc,jni")
+
+# This parameter forces execution a kamailio comnmand with java native method KamExec.
+# Note: this is an untested feature, may cause (but may not) a memory leaks if used from embedded languages.
+modparam("app_java", "force_kam_cmd_exec", 1);
+
+
+
+Rebulding java stuff:
+----------------------
+
+For re-building kamailio.jar see: BUILD_JAR.TXT
+

+ 48 - 0
modules/app_java/global.h

@@ -0,0 +1,48 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 __GLOBAL_H__
+#define	__GLOBAL_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+#include "../../action.h"
+#include "../../mem/mem.h"
+#include "../../sr_module.h"
+#include "../../dset.h"
+#include "../../parser/msg_parser.h"
+
+#include <jni.h>
+
+JavaVM *jvm;
+JNIEnv *env;
+jclass KamailioClass;
+jclass KamailioClassRef;
+jclass KamailioClassInstanceRef;
+jobject KamailioClassInstance;
+jmethodID KamailioID;
+
+struct sip_msg *msg;
+
+#endif

+ 284 - 0
modules/app_java/java_iface.c

@@ -0,0 +1,284 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 "../../str.h"
+#include "../../sr_module.h"
+
+#include <string.h>
+#include <jni.h>
+
+#include "global.h"
+#include "java_iface.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_native_methods.h"
+#include "java_msgobj.h"
+#include "java_sig_parser.h"
+
+/*
+    example of java prototype: public int method_name();
+    example of kamailio invocation: java_method_exec("method_name", "V");
+*/
+int j_nst_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
+{
+    return java_exec(msgp, 0, 0, method_name, signature, NULL);
+}
+/*
+    example of java prototype: public int method_name(int param);
+    example of kamailio invocation: java_method_exec("method_name", "I", "5");
+*/
+int j_nst_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
+{
+    return java_exec(msgp, 0, 0, method_name, signature, param);
+}
+/*
+    example of java prototype: public synchronized int method_name();
+    example of kamailio invocation: java_s_method_exec("method_name", "V");
+*/
+int j_s_nst_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
+{
+    return java_exec(msgp, 0, 1, method_name, signature, NULL);
+}
+/*
+    example of java prototype: public synchronized int method_name(int param);
+    example of kamailio invocation: java_s_method_exec("method_name", "I", "5");
+*/
+int j_s_nst_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
+{
+    return java_exec(msgp, 0, 1, method_name, signature, param);
+}
+
+
+/*
+    example of java prototype: public static int method_name();
+    example of kamailio invocation: java_staticmethod_exec("method_name", "V");
+*/
+int j_st_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
+{
+    return java_exec(msgp, 1, 0, method_name, signature, NULL);
+}
+/*
+    example of java prototype: public static int method_name(int param);
+    example of kamailio invocation: java_staticmethod_exec("method_name", "I", "5");
+*/
+int j_st_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
+{
+    return java_exec(msgp, 1, 0, method_name, signature, param);
+}
+/*
+    example of java prototype: public static synchronized int method_name();
+    example of kamailio invocation: java_s_staticmethod_exec("method_name", "V");
+*/
+int j_s_st_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
+{
+    return java_exec(msgp, 1, 1, method_name, signature, NULL);
+}
+/*
+    example of java prototype: public static synchronized int method_name(int param);
+    example of kamailio invocation: java_s_staticmethod_exec("method_name", "I", "5");
+*/
+int j_s_st_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
+{
+    return java_exec(msgp, 1, 1, method_name, signature, param);
+}
+
+
+int java_exec(struct sip_msg *msgp, int is_static, int is_synchronized, char *method_name, char *signature, char *param)
+{
+    char *retval_sig;
+    char *cs;
+    size_t cslen;
+    jint retval;
+    int locked;
+    jfieldID fid;
+    jclass cls;
+    jmethodID invk_method, invk_method_ref;
+    jvalue *jparam;
+
+    if (signature == NULL || !strcmp(signature, ""))
+    {
+	LM_ERR("java_method_exec(): signature is empty or invalid.\n");
+	return -1;
+    }
+
+    if (param == NULL && strcmp(signature, "V"))
+    {
+	LM_ERR("java_method_exec(): no paramter (parameter is NULL) but signature '%s' is not equals to 'V'.\n", signature);
+	return -1;
+    }
+
+    if (is_sig_allowed(signature) == 0)
+    {
+	LM_ERR("java_method_exec(): error: signature '%s' isn't supported yet.\n", signature);
+	return -1;
+    }
+
+    if (!strcmp(signature, "V"))
+    {
+	signature = "";
+    }
+
+    retval_sig = "I";
+
+    cslen = strlen(signature) + 2 + 1 + 1;	// '(' + 'signature' + ')' + 'return signature' + null terminator
+    cs = (char *)pkg_malloc(cslen * sizeof(char));
+    if (!cs)
+    {
+	LM_ERR("pkg_malloc() has failed. Can't allocate %lu bytes. Not enough memory!\n", (unsigned long)cslen);
+	return -1;
+    }
+    snprintf(cs, cslen, "(%s)%s", signature, retval_sig);
+    cs[cslen] = '\0';
+
+    // attach to current thread
+    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return -1;
+    }
+
+    cls = (*env)->GetObjectClass(env, KamailioClassInstance);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+        return -1;
+    }
+    fid = (*env)->GetFieldID(env, cls, "mop", "I");
+    if (!fid)
+    {
+        handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+        return -1;
+    }
+
+    msg = msgp;
+
+    // find a method by signature
+    invk_method = is_static ? 
+		    (*env)->GetStaticMethodID(env, KamailioClassRef, method_name, cs) : 
+		    (*env)->GetMethodID(env, KamailioClassRef, method_name, cs);
+    if (!invk_method || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+    	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    pkg_free(cs);
+
+    // keep local reference to method
+    invk_method_ref = (*env)->NewLocalRef(env, invk_method);
+    if (!invk_method_ref || (*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+	(*env)->DeleteLocalRef(env, invk_method_ref);
+	(*jvm)->DetachCurrentThread(jvm);
+        return -1;
+    }
+
+    retval = -1;
+
+    if (is_synchronized)
+    {
+	if ((*env)->MonitorEnter(env, invk_method_ref) != JNI_OK)
+        {
+	    locked = 0;
+	    LM_ERR("MonitorEnter() has failed!\n");
+	}
+	else
+	{
+	    locked = 1;
+	}
+    }
+
+    if (param == NULL)
+    {
+	retval = is_static ?
+		    (int)(*env)->CallStaticIntMethod(env, KamailioClassRef, invk_method_ref) :
+		    (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, invk_method_ref);
+    }
+    else
+    {
+	jparam = get_value_by_sig_type(signature, param);
+	if (jparam == NULL)
+	{
+	    (*env)->DeleteLocalRef(env, invk_method_ref);
+	    (*env)->DeleteLocalRef(env, invk_method);
+    	    (*jvm)->DetachCurrentThread(jvm);
+	    return -1;
+	}
+
+	retval = is_static ?
+		    (int)(*env)->CallStaticIntMethod(env, KamailioClassRef, invk_method_ref, *jparam) :
+		    (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, invk_method_ref, *jparam);
+    }
+
+    if ((*env)->ExceptionCheck(env))
+    {
+        LM_ERR("%s(): %s() has failed. See exception below.\n", 
+		(is_static ? 
+			(is_synchronized ? "java_s_staticmethod_exec" : "java_staticmethod_exec") :
+			(is_synchronized ? "java_s_method_exec" : "java_method_exec")
+		),
+		is_static ? "CallStaticIntMethod" : "CallIntMethod"
+	);
+
+        handle_exception();
+
+	(*env)->DeleteLocalRef(env, invk_method_ref);
+	(*env)->DeleteLocalRef(env, invk_method);
+        (*jvm)->DetachCurrentThread(jvm);
+
+        return -1;
+    }
+
+    if (is_synchronized && locked)
+    {
+	if ((*env)->MonitorExit(env, invk_method_ref) != JNI_OK)
+	{
+	    LM_ERR("MonitorExit) has failed!\n");
+	}
+    }
+
+    (*env)->DeleteLocalRef(env, invk_method_ref);
+    (*env)->DeleteLocalRef(env, invk_method);
+    (*jvm)->DetachCurrentThread(jvm);
+
+    return retval;
+}
+
+
+
+
+
+
+
+
+
+
+

+ 44 - 0
modules/app_java/java_iface.h

@@ -0,0 +1,44 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 __JAVA_IFACE_H__
+#define	__JAVA_IFACE_H__
+
+#include "../../parser/msg_parser.h"
+
+int j_nst_exec_0(struct sip_msg *, char *, char *);
+int j_nst_exec_1(struct sip_msg *, char *, char *, char *);
+int j_s_nst_exec_0(struct sip_msg *, char *, char *);
+int j_s_nst_exec_1(struct sip_msg *, char *, char *, char *);
+
+int j_st_exec_0(struct sip_msg *, char *, char *);
+int j_st_exec_1(struct sip_msg *, char *, char *, char *);
+int j_s_st_exec_0(struct sip_msg *, char *, char *);
+int j_s_st_exec_1(struct sip_msg *, char *, char *, char *);
+
+int java_exec(struct sip_msg *, int, int, char *, char *, char *);
+
+
+
+#endif

+ 260 - 0
modules/app_java/java_mod.c

@@ -0,0 +1,260 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 <libgen.h>
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+
+#include "java_native_methods.h"
+
+MODULE_VERSION
+
+static str class_name = {.s = "Kamailio", .len = 10};
+static str child_init_mname = { .s = "child_init", .len = 0};
+static str java_options_str = { .s = "-Djava.compiler=NONE", .len = 21};
+
+static int mod_init(void);
+static int child_init(int rank);
+static void mod_destroy(void);
+
+
+/** module parameters */
+static param_export_t params[] = {
+    {"class_name",         STR_PARAM, &class_name },
+    {"child_init_method",  STR_PARAM, &child_init_mname },
+    {"java_options",	   STR_PARAM, &java_options_str },
+    {"force_kam_cmd_exec", INT_PARAM, &force_kam_cmd_exec },
+    {0,0,0}
+};
+
+
+/*
+ * Exported functions
+ */
+static cmd_export_t cmds[] = {
+    { "java_method_exec",		(cmd_function)j_nst_exec_0,	2,	NULL,	0,	ANY_ROUTE },
+    { "java_method_exec",		(cmd_function)j_nst_exec_1,	3,	NULL,	0,	ANY_ROUTE },
+    { "java_s_method_exec",		(cmd_function)j_s_nst_exec_0,	2,	NULL,	0,	ANY_ROUTE },
+    { "java_s_method_exec",		(cmd_function)j_s_nst_exec_1,	3,	NULL,	0,	ANY_ROUTE },
+
+    { "java_staticmethod_exec",		(cmd_function)j_st_exec_0,	2,	NULL,	0,	ANY_ROUTE },
+    { "java_staticmethod_exec",		(cmd_function)j_st_exec_1,	3,	NULL,	0,	ANY_ROUTE },
+    { "java_s_staticmethod_exec",	(cmd_function)j_s_st_exec_0,	2,	NULL,	0,	ANY_ROUTE },
+    { "java_s_staticmethod_exec",	(cmd_function)j_s_st_exec_1,	3,	NULL,	0,	ANY_ROUTE },
+
+    { 0, 0, 0, 0, 0, 0 }
+};
+
+/** module exports */
+struct module_exports exports = {
+    "app_java",                     /* module name */
+//    RTLD_NOW | RTLD_GLOBAL,         /* dlopen flags */
+    DEFAULT_DLFLAGS,		    /* dlopen flags */
+    cmds,                           /* exported functions */
+    params,                         /* exported parameters */
+    0,                              /* exported statistics */
+    0,                              /* exported MI functions */
+    0,                              /* exported pseudo-variables */
+    0,                              /* extra processes */
+    mod_init,                       /* module initialization function */
+    (response_function) NULL,       /* response handling function */
+    (destroy_function) mod_destroy, /* destroy function */
+    child_init                      /* per-child init function */
+};
+
+static int mod_init(void)
+{
+    JavaVMInitArgs  vm_args;
+    jint res;
+    JavaVMOption *options;
+    char **opts;
+    int nOptions;
+
+    if (force_kam_cmd_exec < 0 || force_kam_cmd_exec > 1)
+    {
+	LM_ERR("Parameter force_kam_cmd_exec should be either 0 or 1\n");
+	return -1;
+    }
+
+    if (force_kam_cmd_exec)
+    {
+	LM_NOTICE("app_java: Parameter force_kam_cmd_exec may cause a memory leaks if used from embedded languages\n");
+    }
+
+    options = (JavaVMOption *)pkg_malloc(sizeof(JavaVMOption));
+    if (!options)
+    {
+	LM_ERR("pkg_malloc() failed: Couldn't initialize Java VM: Not enough memory\n");
+	return -1;
+    }
+    memset(options, 0, sizeof(JavaVMOption));
+
+    LM_INFO("Initializing Java VM with options: %s\n", java_options_str.s);
+
+    opts = split(java_options_str.s, " ");
+    for (nOptions=0; opts[nOptions] != NULL; nOptions++)
+    {
+	options[nOptions].optionString = opts[nOptions];
+    }
+
+    /* IMPORTANT: specify vm_args version # if you use JDK1.1.2 and beyond */
+    vm_args.version = JNI_VERSION_1_2;
+    vm_args.nOptions = nOptions;
+    vm_args.ignoreUnrecognized = JNI_FALSE;
+    vm_args.options = options;
+
+    res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
+    if (res < 0)
+    {
+	handle_VM_init_failure(res);
+	return -1;
+    }
+
+    LM_INFO("app_java: Java VM initialization OK\n");
+
+    // attach to current thread
+    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
+    if ((*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	return -1;
+    }
+
+    KamailioClass = (*env)->FindClass(env, class_name.s);
+    if (!KamailioClass || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    KamailioClassRef = (*env)->NewGlobalRef(env, KamailioClass);
+    if (!KamailioClassRef || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    KamailioID = (*env)->GetMethodID(env, KamailioClass, "<init>", "()V");
+    if (!KamailioID || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    // calling constructor
+    KamailioClassInstance = (*env)->NewObject(env, KamailioClass, KamailioID);
+    if (!KamailioClassInstance || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    // keep a reference to kamailio class instance
+    KamailioClassInstanceRef = (*env)->NewGlobalRef(env, KamailioClassInstance);
+    if (!KamailioClassInstanceRef || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    LM_INFO("app_java: module initialization OK\n");
+
+    if (jvm != NULL)
+        (*jvm)->DetachCurrentThread(jvm);
+
+    return 0;
+}
+
+static int child_init(int rank)
+{
+    int retval;
+    jmethodID child_init_id;
+
+    // attach to current thread
+    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return -1;
+    }
+
+    child_init_id = (*env)->GetMethodID(env, KamailioClass, "child_init", "(I)I");
+    if ((*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+    	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    retval = (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, child_init_id, rank);
+    if ((*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+    	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    (*env)->DeleteLocalRef(env, child_init_id);
+    (*jvm)->DetachCurrentThread(jvm);
+
+    msg = NULL;
+
+    return retval;
+}
+
+static void mod_destroy(void)
+{
+    if (env != NULL)
+    {
+	(*env)->DeleteGlobalRef(env, KamailioClassInstanceRef);
+	(*env)->DeleteGlobalRef(env, KamailioClassRef);
+    }
+
+    if (jvm != NULL)
+    {
+	(*jvm)->DetachCurrentThread(jvm);
+	(*jvm)->DestroyJavaVM(jvm);
+    }
+
+    if (msg)
+    {
+	pkg_free(msg);
+    }
+
+}

+ 30 - 0
modules/app_java/java_mod.h

@@ -0,0 +1,30 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 __JAVA_MOD_H__
+#define	__JAVA_MOD_H__
+
+int force_kam_cmd_exec;
+
+#endif

+ 324 - 0
modules/app_java/java_msgobj.c

@@ -0,0 +1,324 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 "../../action.h"
+#include "../../mem/mem.h"
+#include "../../sr_module.h"
+#include "../../dset.h"
+#include "../../parser/msg_parser.h"
+
+#include <jni.h>
+
+#include "global.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_native_methods.h"
+#include "java_msgobj.h"
+
+jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
+{
+    jobject *SipMsgInstance;
+    jclass SipMsgClass;
+    jmethodID SipMsgClassID;
+    jfieldID fid;
+    jstring jStrParam;
+
+    SipMsgInstance = (jobject *)pkg_malloc(sizeof(jobject));
+    if (!SipMsgInstance)
+    {
+	LM_ERR("pkg_malloc() has failed. Not enough memory!\n");
+	return NULL;
+    }
+    memset(SipMsgInstance, 0, sizeof(jobject));
+
+    SipMsgClass = (*env)->FindClass(env, "org/siprouter/SipMsg");
+    if (!SipMsgClass || (*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+	pkg_free(SipMsgInstance);
+        return NULL;
+    }
+
+    SipMsgClassID = (*env)->GetMethodID(env, SipMsgClass, "<init>", "()V");
+    if (!SipMsgClassID || (*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // calling constructor
+    (*SipMsgInstance) = (*env)->NewObject(env, SipMsgClass, SipMsgClassID);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->id => SipMsg.id 
+    fid = (*env)->GetFieldID(env, SipMsgClass, "id", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+	LM_ERR("Can't find symbol org.siprouter.SipMsg.id\n");
+
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->id);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->pid => SipMsg.pid
+    fid = (*env)->GetFieldID(env, SipMsgClass, "pid", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+	LM_ERR("Can't find symbol org.siprouter.SipMsg.pid\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->pid);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->eoh => SipMsg.eoh
+    fid = (*env)->GetFieldID(env, SipMsgClass, "eoh", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+	LM_ERR("Can't find symbol org.siprouter.SipMsg.eoh\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->eoh);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->unparsed => SipMsg.unparsed
+    fid = (*env)->GetFieldID(env, SipMsgClass, "unparsed", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+	LM_ERR("Can't find symbol org.siprouter.SipMsg.unparsed\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->unparsed);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->buf => SipMsg.buf
+    fid = (*env)->GetFieldID(env, SipMsgClass, "buf", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.buf\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->buf);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->len => SipMsg.len
+    fid = (*env)->GetFieldID(env, SipMsgClass, "len", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.len\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->len);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->new_uri => SipMsg.new_uri
+    fid = (*env)->GetFieldID(env, SipMsgClass, "new_uri", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.new_uri\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->new_uri.len <= 0 ? "" : msg->new_uri.s);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->dst_uri => SipMsg.dst_uri
+    fid = (*env)->GetFieldID(env, SipMsgClass, "dst_uri", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.dst_uri\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->dst_uri.len <= 0 ? "" : msg->dst_uri.s);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->parsed_orig_ruri_ok => SipMsg.parsed_orig_ruri_ok
+    fid = (*env)->GetFieldID(env, SipMsgClass, "parsed_orig_ruri_ok", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.parsed_orig_ruri_ok\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->parsed_orig_ruri_ok);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->add_to_branch_s => SipMsg.add_to_branch_s
+    fid = (*env)->GetFieldID(env, SipMsgClass, "add_to_branch_s", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.add_to_branch_s\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, (msg->add_to_branch_len <= 0 || msg->add_to_branch_s == NULL) ? "" : strdup(msg->add_to_branch_s));
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->add_to_branch_len => SipMsg.add_to_branch_len
+    fid = (*env)->GetFieldID(env, SipMsgClass, "add_to_branch_len", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.add_to_branch_len\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->add_to_branch_len);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->hash_index => SipMsg.hash_index
+    fid = (*env)->GetFieldID(env, SipMsgClass, "hash_index", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.hash_index\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->hash_index);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->msg_flags => SipMsg.msg_flags
+    fid = (*env)->GetFieldID(env, SipMsgClass, "msg_flags", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.msg_flags\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->msg_flags);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->set_global_address => SipMsg.set_global_address
+    fid = (*env)->GetFieldID(env, SipMsgClass, "set_global_address", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.set_global_address\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, (msg->set_global_address.len <= 0 || msg->set_global_address.s == NULL) ? "" : msg->set_global_address.s);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->set_global_port => SipMsg.set_global_port
+    fid = (*env)->GetFieldID(env, SipMsgClass, "set_global_port", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.set_global_port\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, (msg->set_global_port.len <= 0 || msg->set_global_port.s == NULL) ? "" : msg->set_global_port.s);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    return SipMsgInstance;
+}

+ 34 - 0
modules/app_java/java_msgobj.h

@@ -0,0 +1,34 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 __JAVA_MSGOBJ_H__
+#define	__JAVA_MSGOBJ_H__
+
+#include "../../parser/msg_parser.h"
+
+#include <jni.h>
+
+jobject *fill_sipmsg_object(JNIEnv *, struct sip_msg *);
+
+#endif

+ 1223 - 0
modules/app_java/java_native_methods.c

@@ -0,0 +1,1223 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 "../../str.h"
+#include "../../sr_module.h"
+#include "../../ip_addr.h"
+#include "../../flags.h"
+
+#include <jni.h>
+
+#include "global.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_msgobj.h"
+#include "java_native_methods.h"
+#include "java_sig_parser.h"
+
+
+//// native methods ////
+
+/*
+    java: native void LM_XXXXXX(Params XXXX);
+    c: JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1XXXXXX(JNIEnv *jenv, jobject this, Params XXXX)
+
+    Why (for example) Java_Kamailio_LM_1ERR but not Java_Kamailio_LM_ERR? 
+    See explaination here: http://qscribble.blogspot.ca/2012/04/underscores-in-jni-method-names.html
+
+    Also, from here: http://192.9.162.55/docs/books/jni/html/design.html
+    The JNI adopts a simple name-encoding scheme to ensure that all Unicode characters 
+    translate into valid C function names. The underscore ("_") character separates the 
+    components of fully qualified class names. Because a name or type descriptor never 
+    begins with a number, we can use _0, ..., _9 for escape sequences, as illustrated below:
+    +-------------------+------------------------------------+
+    |  Escape Sequence  |            Denotes                 |
+    +-------------------+------------------------------------+
+    |	_0XXXX          |  a Unicode character XXXX          |
+    |	_1              |  the character "_"                 |
+    |	_2              |  the character ";" in descriptors  |
+    |	_3              |  the character "[" in descriptors  |
+    +-------------------+------------------------------------+
+
+*/
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_ERR(Ljava/lang/String;)V
+    Prototype: public static native void LM_ERR(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1ERR(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_ERR("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_WARN(Ljava/lang/String;)V
+    Prototype: public static native void LM_WARN(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1WARN(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_WARN("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_NOTICE(Ljava/lang/String;)V
+    Prototype: public static native void LM_NOTICE(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1NOTICE(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_NOTICE("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_INFO(Ljava/lang/String;)V
+    Prototype: public static native void LM_INFO(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1INFO(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_INFO("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_DBG(Ljava/lang/String;)V
+    Prototype: public static native void LM_DBG(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1DBG(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_DBG("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_CRIT(Ljava/lang/String;)V
+    Prototype: public static native void LM_CRIT(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1CRIT(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_CRIT("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+
+#ifdef LM_ALERT
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_ALERT(Ljava/lang/String;)V
+    Prototype: public static native void LM_ALERT(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1ALERT(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_ALERT("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_GEN2(ILjava/lang/String;)V
+    Prototype: public static native void LM_GEN1(int logLevel, String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1GEN1(JNIEnv *jenv, jobject this, jint ll, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_GEN1((int)ll, "%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_GEN2(IILjava/lang/String;)V
+    Prototype: public static native void LM_GEN2(int logLevel, int logFacility, String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1GEN2(JNIEnv *jenv, jobject this, jint ll, jint lf, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_GEN2((int)ll, (int)lf, "%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: KamExec(Ljava/lang/String;[Ljava/lang/String;)I
+    Prototype: public static native int KamExec(String fname, String... params);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_NativeMethods_KamExec(JNIEnv *jenv, jobject this, jstring jfname, jobjectArray strArrParams)
+{
+    int retval;
+    char *fname;
+    int argc;
+    jsize pc;
+    int i;
+    char *argv[MAX_ACTIONS];
+    jboolean is_copy;
+    jstring strp;
+    char *strc;
+
+    if (jfname == NULL)
+    {
+	LM_ERR("app_java: KamExec() required at least 1 argument (function name)\n");
+	return -1;
+    }
+
+    fname = (char *)(*jenv)->GetStringUTFChars(jenv, jfname, &is_copy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return -1;
+    }
+
+    memset(argv, 0, MAX_ACTIONS * sizeof(char *));
+    argc = 0;
+
+    pc = (*jenv)->GetArrayLength(jenv, strArrParams);
+    if (pc >= 6)
+    {
+	pc = 6;
+    }
+
+    for (i=0; i<pc; i++)
+    {
+	strp = (jstring)(*jenv)->GetObjectArrayElement(jenv, strArrParams, i);
+	if ((*jenv)->ExceptionCheck(jenv))
+	{
+    	    handle_exception();
+    	    return -1;
+	}
+
+	strc = (char *)(*jenv)->GetStringUTFChars(jenv, strp, &is_copy);
+	if ((*jenv)->ExceptionCheck(jenv))
+	{
+    	    handle_exception();
+    	    return -1;
+	}
+
+	if (strc)
+	{
+	    argv[argc++] = strc;
+	}
+    }
+    
+    retval = KamExec(jenv, fname, argc, argv);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, jfname, fname);
+
+    return (jint)retval;
+}
+
+int KamExec(JNIEnv *jenv, char *fname, int argc, char **argv)
+{
+    sr31_cmd_export_t *fexport;
+    unsigned mod_ver;
+    int rval;
+    int mod_type;
+    struct action *act;
+    struct run_act_ctx ra_ctx;
+    int i;
+
+    if (!msg)
+	return -1;
+
+    fexport = find_export_record(fname, argc, 0, &mod_ver);
+    if (!fexport)
+    {
+	LM_ERR("app_java: KamExec(): '%s' - no such function\n", fname);
+        return -1;
+    }
+
+    /* check fixups */
+    if (force_kam_cmd_exec == 0 && fexport->fixup != NULL && fexport->free_fixup == NULL)
+    {
+        LM_ERR("app_java: KamExec(): function '%s' has fixup - cannot be used\n", fname);
+	return -1;
+    }
+
+    switch(fexport->param_no)
+    {
+    	case 0:			mod_type = MODULE0_T;	break;
+	case 1:			mod_type = MODULE1_T;	break;
+	case 2:			mod_type = MODULE2_T;	break;
+	case 3:			mod_type = MODULE3_T;	break;
+	case 4:			mod_type = MODULE4_T;	break;
+	case 5:			mod_type = MODULE5_T;	break;
+	case 6:			mod_type = MODULE6_T;	break;
+	case VAR_PARAM_NO:	mod_type = MODULEX_T;	break;
+	default:
+		LM_ERR("app_java: KamExec(): unknown/bad definition for function '%s' (%d params)\n", fname, fexport->param_no);
+		return -1;
+    }
+
+
+    act = mk_action(mod_type, (argc+2),			/* number of (type, value) pairs */
+                	MODEXP_ST, fexport,		/* function */
+                	NUMBER_ST, argc,		/* parameter number */
+			STRING_ST, argv[0],		/* param. 1 */
+			STRING_ST, argv[1],		/* param. 2 */
+			STRING_ST, argv[2],		/* param. 3 */
+			STRING_ST, argv[3],		/* param. 4 */
+			STRING_ST, argv[4],		/* param. 5 */
+			STRING_ST, argv[5]		/* param. 6 */
+                   );
+
+    if (!act)
+    {
+	LM_ERR("app_java: KamExec(): action structure couldn't be created\n");
+	return -1;
+    }
+
+
+    /* handle fixups */
+    if (fexport->fixup)
+    {
+        if (argc == 0)
+	{
+            rval = fexport->fixup(0, 0);
+            if (rval < 0)
+	    {
+		LM_ERR("app_java: KamExec(): (no params) Error in fixup (0) for '%s'\n", fname);
+                return -1;
+            }
+        }
+	else
+	{
+	    for (i=0; i<=argc; i++)
+	    {
+		if (act->val[i+2].u.data != 0x0)
+		{
+        	    rval = fexport->fixup(&(act->val[i+2].u.data), i+1);
+        	    if (rval < 0)
+		    {
+			LM_ERR("app_java: KamExec(): (params: %d) Error in fixup (%d) for '%s'\n", argc, i+1, fname);
+            		return -1;
+        	    }
+        	    act->val[i+2].type = MODFIXUP_ST;
+		}
+	    }
+        }
+    }
+
+    init_run_actions_ctx(&ra_ctx);
+    rval = do_action(&ra_ctx, act, msg);
+
+    /* free fixups */
+    if (fexport->free_fixup)
+    {
+	for (i=0; i<=argc; i++)
+	{
+	    if ((act->val[i+2].type == MODFIXUP_ST) && (act->val[i+2].u.data))
+	    {
+		fexport->free_fixup(&(act->val[i+2].u.data), i+1);
+	    }
+	}
+    }
+
+    pkg_free(act);
+
+    return rval;
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: ParseSipMsg()Lorg/siprouter/SipMsg;
+    Prototype: public static native org.siprouter.SipMsg ParseSipMsg();
+*/
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_ParseSipMsg(JNIEnv *jenv, jobject this)
+{
+    if (!msg)
+	return NULL;
+
+    return fill_sipmsg_object(jenv, msg);
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getMsgType()Ljava/org/String;
+    Prototype: public static native String getMsgType();
+*/
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getMsgType(JNIEnv *jenv, jobject this)
+{
+    char *cs;
+    jstring js;
+
+    if (!msg)
+	return NULL;
+
+    switch ((msg->first_line).type)
+    {
+        case SIP_REQUEST:
+            cs = "SIP_REQUEST";
+            break;
+
+        case SIP_REPLY:
+            cs = "SIP_REPLY";
+            break;
+
+        default:
+	    cs = "SIP_INVALID";
+	    break;
+    }
+
+    js = (*jenv)->NewStringUTF(jenv, cs);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return js;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getStatus()Ljava/org/String;
+    Prototype: public static native String getStatus();
+*/
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getStatus(JNIEnv *jenv, jobject this)
+{
+    str *cs;
+    jstring js;
+
+    if (!msg)
+	return NULL;
+
+    if ((msg->first_line).type != SIP_REQUEST)
+    {
+	LM_ERR("app_java: getStatus(): Unable to fetch status. Error: Not a request message - no method available.\n");
+        return NULL;
+    }
+
+    cs = &((msg->first_line).u.request.method);
+
+    js = (*jenv)->NewStringUTF(jenv, (cs && cs->s && cs->len > 0) ? cs->s : "");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return js;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getRURI()Ljava/org/String;
+    Prototype: public static native String getRURI();
+*/
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getRURI(JNIEnv *jenv, jobject this)
+{
+    str *cs;
+    jstring js;
+
+    if (!msg)
+	return NULL;
+
+    if ((msg->first_line).type != SIP_REQUEST)
+    {
+	LM_ERR("app_java: getRURI(): Unable to fetch ruri. Error: Not a request message - no method available.\n");
+        return NULL;
+    }
+
+    cs = &((msg->first_line).u.request.uri);
+
+    js = (*jenv)->NewStringUTF(jenv, (cs && cs->s && cs->len > 0) ? cs->s : "");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return js;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getSrcAddress()Lorg/siprouter/IPPair;
+    Prototype: public static native org.siprouter.IPPair getSrcAddress();
+*/
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getSrcAddress(JNIEnv *jenv, jobject this)
+{
+    jclass ippair_cls;
+    jmethodID ippair_cls_id;
+    jobject ippair_cls_instance;
+
+    char *ip;
+    jstring jip;
+    int port;
+
+    if (!msg)
+	return NULL;
+
+    ippair_cls = (*jenv)->FindClass(jenv, "org/siprouter/IPPair");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    ippair_cls_id = (*jenv)->GetMethodID(jenv, ippair_cls, "<init>", "(Ljava/lang/String;I)V");
+    if (!ippair_cls_id || (*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    ip = ip_addr2a(&msg->rcv.src_ip);
+    if (!ip)
+    {
+	LM_ERR("app_java: getSrcAddress(): Unable to fetch src ip address.\n");
+	return NULL;
+    }
+    jip = (*jenv)->NewStringUTF(jenv, ip);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    port = msg->rcv.src_port;
+    if (port == 0x0)
+    {
+	LM_ERR("app_java: getSrcAddress(): Unable to fetch src port.\n");
+	return NULL;
+    }
+
+    // calling constructor
+    ippair_cls_instance = (*jenv)->NewObject(jenv, ippair_cls, ippair_cls_id, (jstring)jip, (jint)port);
+    if (!ippair_cls_instance || (*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return ippair_cls_instance;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getDstAddress()Lorg/siprouter/IPPair;
+    Prototype: public static native org.siprouter.IPPair getDstAddress();
+*/
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getDstAddress(JNIEnv *jenv, jobject this)
+{
+    jclass ippair_cls;
+    jmethodID ippair_cls_id;
+    jobject ippair_cls_instance;
+
+    char *ip;
+    jstring jip;
+    int port;
+
+    if (!msg)
+	return NULL;
+
+    ippair_cls = (*jenv)->FindClass(jenv, "org/siprouter/IPPair");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    ippair_cls_id = (*jenv)->GetMethodID(jenv, ippair_cls, "<init>", "(Ljava/lang/String;I)V");
+    if (!ippair_cls_id || (*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    ip = ip_addr2a(&msg->rcv.dst_ip);
+    if (!ip)
+    {
+	LM_ERR("app_java: getDstAddress(): Unable to fetch src ip address.\n");
+	return NULL;
+    }
+    jip = (*jenv)->NewStringUTF(jenv, ip);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    port = msg->rcv.dst_port;
+    if (port == 0x0)
+    {
+	LM_ERR("app_java: getDstAddress(): Unable to fetch src port.\n");
+	return NULL;
+    }
+
+    // calling constructor
+    ippair_cls_instance = (*jenv)->NewObject(jenv, ippair_cls, ippair_cls_id, (jstring)jip, (jint)port);
+    if (!ippair_cls_instance || (*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return ippair_cls_instance;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getBuffer()Ljava/org/String;
+    Prototype: public static native String getBuffer();
+*/
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getBuffer(JNIEnv *jenv, jobject this)
+{
+    jstring js;
+
+    if (!msg)
+	return NULL;
+
+    if ((msg->first_line).type != SIP_REQUEST)
+    {
+	LM_ERR("app_java: getRURI(): Unable to fetch ruri. Error: Not a request message - no method available.\n");
+        return NULL;
+    }
+
+    js = (*jenv)->NewStringUTF(jenv, msg->buf ? msg->buf : "");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return js;
+}
+
+
+
+
+
+
+///// Core Functions /////
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: seturi(Ljava/org/String;)I
+    Prototype: public static native int seturi(String uri);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_seturi(JNIEnv *jenv, jobject this, jstring juri)
+{
+    return cf_seturi(jenv, this, juri, "seturi");
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: rewriteuri(Ljava/org/String;)I
+    Prototype: public static native int rewriteuri(String uri);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_rewriteuri(JNIEnv *jenv, jobject this, jstring juri)
+{
+    return cf_seturi(jenv, this, juri, "rewriteuri");
+}
+
+/* wrapped function */
+jint cf_seturi(JNIEnv *jenv, jobject this, jstring juri, char *fname)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    char *curi;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: %s: Can't process, msg=NULL\n", fname);
+	return -1;
+    }
+
+    curi = (char *)(*jenv)->GetStringUTFChars(jenv, juri, &is_copy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+    	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = SET_URI_T;
+    act.val[0].type = STRING_ST;
+    act.val[0].u.str.s = curi;
+    act.val[0].u.str.len = strlen(curi);
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    (*jenv)->ReleaseStringUTFChars(jenv, juri, curi);
+    return (jint)retval;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: add_local_rport()I
+    Prototype: public static native int add_local_rport();
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_add_1local_1rport(JNIEnv *jenv, jobject this)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: add_local_rport: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = ADD_LOCAL_RPORT_T;
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: append_branch()I
+    Method(o): append_branch(Ljava/lang/String)I
+    Prototype: public static native int append_branch();
+    Prototype(o): public static native int append_branch(String branch);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_append_1branch(JNIEnv *jenv, jobject this, jstring jbranch)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    char *cbranch;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: append_branch: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = APPEND_BRANCH_T;
+
+    cbranch = NULL;
+
+    if (jbranch)
+    {
+	cbranch = (char *)(*jenv)->GetStringUTFChars(jenv, jbranch, &is_copy);
+	if ((*jenv)->ExceptionCheck(jenv))
+	{
+	    handle_exception();
+	    return -1;
+	}
+
+	act.val[0].type = STR_ST;
+	act.val[0].u.str.s = cbranch;
+	act.val[0].u.str.len = strlen(cbranch);
+    }
+
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+
+    if (cbranch)
+    {
+	(*jenv)->ReleaseStringUTFChars(jenv, jbranch, cbranch);
+    }
+
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: drop()I
+    Prototype: public static native int drop();
+    Returns:
+	0 if action -> end of list(e.g DROP)
+        > 0 to continue processing next actions
+	< 0 on error
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_drop(JNIEnv *jenv, jobject this)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: drop: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = DROP_T;
+    act.val[0].type = NUMBER_ST;
+    act.val[0].u.number = 0;
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: force_rport()I
+    Prototype: public static native int force_rport();
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_force_1rport(JNIEnv *jenv, jobject this)
+{
+    return cf_force_rport(jenv, this, "force_rport");
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: add_rport()I
+    Prototype: public static native int add_rport();
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_add_1rport(JNIEnv *jenv, jobject this)
+{
+    return cf_force_rport(jenv, this, "add_rport");
+}
+
+/* wrapped function */
+jint cf_force_rport(JNIEnv *jenv, jobject this, char *fname)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: %s: Can't process, msg=NULL\n", fname);
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = FORCE_RPORT_T;
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    return (jint)retval;
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: force_send_socket(Ljava/lang/String;I)I
+    Prototype: public static native int force_send_socket(String srchost, int srcport);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_force_1send_1socket(JNIEnv *jenv, jobject this, jstring jsrchost, jint jsrcport)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    struct socket_id *si;
+    struct name_lst *nl;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: force_send_socket: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    nl = (struct name_lst *)pkg_malloc(sizeof(struct name_lst));
+    if (!nl)
+    {
+	LM_ERR("app_java: force_send_socket: pkg_malloc() has failed. Not enough memory!\n");
+	return -1;
+    }
+    
+    si = (struct socket_id *)pkg_malloc(sizeof(struct socket_id));
+    if (!si)
+    {
+	LM_ERR("app_java: force_send_socket: pkg_malloc() has failed. Not enough memory!\n");
+	return -1;
+    }
+    
+
+    memset(&act, 0, sizeof(act));
+    act.type = FORCE_SEND_SOCKET_T;
+
+    nl->name = (char *)(*jenv)->GetStringUTFChars(jenv, jsrchost, &is_copy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return -1;
+    }
+    nl->next = NULL;
+    nl->flags = 0;
+
+    si->addr_lst = nl;
+    si->flags = 0;
+    si->proto = PROTO_NONE;
+    si->port = (int)jsrcport;
+    
+    act.val[0].type = SOCKETINFO_ST;
+    act.val[0].u.data = si;
+
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, jsrchost, nl->name);
+    pkg_free(nl);
+    pkg_free(si);
+    return (jint)retval;
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: forward()I
+    Method(o): forward(Ljava/lang/String;I)I
+    Prototype: public static native int forward();
+    Prototype(o): public static native int forward(String ruri, int i);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_forward(JNIEnv *jenv, jobject this, jstring jrurihost, jint juriport)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    char *crurihost;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: forward: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = FORWARD_T;
+
+    crurihost = NULL;
+
+    if (jrurihost)
+    {
+	crurihost = (char *)(*jenv)->GetStringUTFChars(jenv, jrurihost, &is_copy);
+	if ((*jenv)->ExceptionCheck(jenv))
+	{
+    	    handle_exception();
+    	    return -1;
+	}
+
+	act.val[0].type = URIHOST_ST;
+	act.val[0].u.str.s = crurihost;
+	act.val[0].u.str.len = strlen(crurihost);
+
+	act.val[1].type = NUMBER_ST;
+	act.val[1].u.number = (int)juriport;
+    }
+
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+
+    if (crurihost)
+    {
+	(*jenv)->ReleaseStringUTFChars(jenv, jrurihost, crurihost);
+    }
+
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: isflagset(I)Z
+    Prototype: public static native boolean isflagset(int flag);
+*/
+JNIEXPORT jboolean JNICALL Java_org_siprouter_CoreMethods_isflagset(JNIEnv *jenv, jobject this, jint jflag)
+{
+    if (!msg)
+    {
+	LM_ERR("app_java: isflagset: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    return isflagset(msg, (int)jflag) == 1 ? JNI_TRUE : JNI_FALSE;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: setflag(I)V
+    Prototype: public static native void setflag(int flag);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_setflag(JNIEnv *jenv, jobject this, jint jflag)
+{
+    if (!msg)
+    {
+	LM_ERR("app_java: setflag: Can't process, msg=NULL\n");
+	return;
+    }
+
+    setflag(msg, (int)jflag);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: resetflag(I)V
+    Prototype: public static native void resetflag(int flag);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_resetflag(JNIEnv *jenv, jobject this, jint jflag)
+{
+    if (!msg)
+    {
+	LM_ERR("app_java: resetflag: Can't process, msg=NULL\n");
+	return;
+    }
+
+    resetflag(msg, (int)jflag);
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: revert_uri()I
+    Prototype: public static native int revert_uri();
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_revert_1uri(JNIEnv *jenv, jobject this)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: revert_uri: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = REVERT_URI_T;
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: route(Ljava/lang/String)I
+    Prototype: public static native int route(String target);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_route(JNIEnv *jenv, jobject this, jstring jtarget)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    char *ctarget;
+
+    ctarget = (char *)(*jenv)->GetStringUTFChars(jenv, jtarget, &is_copy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return -1;
+    }
+
+    retval = route_lookup(&main_rt, ctarget);
+
+    if (retval == -1)	// route index lookup failed.
+    {
+	LM_ERR("app_java: route: failed to find route name '%s'\n", ctarget);
+	(*jenv)->ReleaseStringUTFChars(jenv, jtarget, ctarget);
+	return -1;
+    }
+
+    act.type = ROUTE_T;
+    act.val[0].type = NUMBER_ST;
+    act.val[0].u.number = retval;
+
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, jtarget, ctarget);
+
+    return retval;
+}
+

+ 86 - 0
modules/app_java/java_native_methods.h

@@ -0,0 +1,86 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 __JAVA_NATIVE_METHODS_H__
+#define	__JAVA_NATIVE_METHODS_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1ERR(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1WARN(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1NOTICE(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1INFO(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1DBG(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1CRIT(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1ALERT(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1GEN1(JNIEnv *, jobject, jint, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1GEN2(JNIEnv *, jobject, jint, jint, jstring);
+
+JNIEXPORT jint JNICALL Java_org_siprouter_NativeMethods_KamExec(JNIEnv *, jobject, jstring, jobjectArray);
+int KamExec(JNIEnv *, char *, int, char **);
+
+
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_ParseSipMsg(JNIEnv *, jobject);
+
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getMsgType(JNIEnv *, jobject);
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getStatus(JNIEnv *, jobject);
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getRURI(JNIEnv *, jobject);
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getSrcAddress(JNIEnv *, jobject);
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getDstAddress(JNIEnv *, jobject);
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getBuffer(JNIEnv *, jobject);
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_seturi(JNIEnv *, jobject, jstring);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_rewriteuri(JNIEnv *, jobject, jstring);
+jint cf_seturi(JNIEnv *, jobject, jstring, char *);
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_add_1local_1rport(JNIEnv *, jobject);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_append_1branch(JNIEnv *, jobject, jstring);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_drop(JNIEnv *, jobject);
+
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_force_1rport(JNIEnv *, jobject);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_add_1rport(JNIEnv *, jobject);
+jint cf_force_rport(JNIEnv *, jobject, char *);
+
+// not confirmed as working
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_force_1send_1socket(JNIEnv *, jobject, jstring, jint);
+
+// not confirmed as working
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_forward(JNIEnv *, jobject, jstring, jint);
+
+JNIEXPORT jboolean JNICALL Java_org_siprouter_CoreMethods_isflagset(JNIEnv *, jobject, jint);
+JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_setflag(JNIEnv *, jobject, jint);
+JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_resetflag(JNIEnv *, jobject, jint);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_revert_1uri(JNIEnv *, jobject);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_route(JNIEnv *, jobject, jobject);
+
+#endif

+ 439 - 0
modules/app_java/java_sig_parser.c

@@ -0,0 +1,439 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 <string.h>
+#include <errno.h>
+#include <float.h>
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_native_methods.h"
+#include "java_sig_parser.h"
+
+int is_sig_allowed(char *s)
+{
+    if (s == NULL || strlen(s) < 1)
+	return 0;
+
+    if (!strcmp(s, " ") || !strcmp(s, "\n") || !strcmp(s, "\r") || !strcmp(s, "\t"))
+    {
+	LM_ERR("signature error: '%s' contains whitespaces or any unparsable chars.\n", s);
+	return 0;
+    }
+
+//    LM_ERR("s='%s', strlen(s)=%d\n", s, strlen(s));
+
+    if (strlen(s) == 1)			// signature is single modifier (primitive)
+    {
+	if (!strcmp(s, "["))		// invalid signature modifier definition
+	{
+	    LM_ERR("signature error: '%s': no type of array specified.\n", s);
+	    return 0;
+	}
+
+	if (!strcmp(s, "L"))		// invalid signature modifier definition
+	{
+	    LM_ERR("signature error '%s': no object specified.\n", s);
+	    return 0;
+	}
+
+#ifndef JAVA_INV_SUPP_TYPE_VOID
+	if (!strcmp(s, "V"))
+	{
+	    LM_ERR("signature error '%s': no object specified.\n", s);
+	    return 0;
+	}
+#endif
+
+    }
+    else				// a complex signature (object)
+    {
+#ifndef JAVA_INV_SUPP_TYPE_ARRAYS
+	if (strcmp(s, "[") > 0)
+	{
+	    LM_ERR("signature error: '%s' denotes array which isn't supported yet.\n", s);
+	    return 0;
+	}
+#endif
+
+
+	if (strrchr(&s[0], 'L') > 0)
+	{
+#ifndef JAVA_INV_SUPP_TYPE_OBJECTS
+	    LM_ERR("signature error: '%s' denotes object which isn't supported yet.\n", s);
+	    return 0;
+#else
+	    int f = 0;
+#ifdef	JAVA_INV_SUPP_TYPE_BOOLEAN
+	    if (!strcmp(s, "Ljava/lang/Boolean;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_BYTE
+	    if (!strcmp(s, "Ljava/lang/Byte;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_CHARACTER
+	    if (!strcmp(s, "Ljava/lang/Character;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_DOUBLE
+	    if (!strcmp(s, "Ljava/lang/Double;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_FLOAT
+	    if (!strcmp(s, "Ljava/lang/Float;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_INTEGER
+	    if (!strcmp(s, "Ljava/lang/Integer;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_LONG
+	    if (!strcmp(s, "Ljava/lang/Long;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_SHORT
+	    if (!strcmp(s, "Ljava/lang/Short;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_STRING
+	    if (!strcmp(s, "Ljava/lang/String;"))
+		f = 1;
+#endif
+	    if (f == 0)
+	    {
+		LM_ERR("signature '%s' isn't supported yet.\n", s);
+		return 0;
+	    }
+#endif
+	}
+
+    }
+
+    return 1;
+}
+
+
+
+static char *get_conv_err_str(int en)
+{
+    switch(en)
+    {
+	case EINVAL:	return "The value of base constant is not supported or no conversion could be performed";
+	case ERANGE:	return "The given string was out of range; the value converted has been clamped.";
+	default:	return "General parse error";
+    }
+}
+
+
+/* explaination of jvalue fields:
+typedef union jvalue {
+    jboolean z;
+    jbyte    b;
+    jchar    c;
+    jshort   s;
+    jint     i;
+    jlong    j;
+    jfloat   f;
+    jdouble  d;
+    jobject  l;
+} jvalue;
+*/
+
+jvalue *get_value_by_sig_type(char *sig, char *pval)
+{
+    char *endptr;
+    char scptr;
+    int siptr;
+    long slptr;
+    short ssptr;
+    double sdptr;
+    float sfptr;
+    jstring sjptr;
+    jvalue *ret;
+
+    ret = (jvalue *)pkg_malloc(sizeof(jvalue));
+    if (!ret)
+    {
+	LM_ERR("pkg_malloc() has failed. Not enouph memory!\n");
+	return NULL;
+    }
+
+    if (sig == NULL || strlen(sig) <= 0)
+    {
+	LM_ERR("app_java: Can't process empty or NULL signature.\n");
+	pkg_free(ret);
+	return NULL;
+    }
+    if (pval == NULL || strlen(pval) <= 0)
+    {
+	LM_ERR("app_java: Can't process empty or NULL parameter value.\n");
+	pkg_free(ret);
+	return NULL;
+    }
+
+    // boolean
+    if (!strncmp(sig, "Z", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_BOOLEAN)
+	|| !strcmp(sig, "Ljava/lang/Boolean;")
+#endif
+	) {
+	    if (!strncasecmp(pval, "true", 4))
+		(*ret).z = (jboolean)JNI_TRUE;
+/* comment this block to avoid conversation '1' to 'true' */
+	    else if (!strncmp(pval, "1", 1))
+		(*ret).z = (jboolean)JNI_TRUE;
+	    else if (!strncasecmp(pval, "false", 5))
+		(*ret).z = (jboolean)JNI_FALSE;
+/* comment this block to avoid conversation '0' to 'false' */
+	    else if (!strncmp(pval, "0", 1))
+		(*ret).z = (jboolean)JNI_FALSE;
+	    else
+	    {
+    		LM_ERR("app_java: Can't cast '%s' to type '%s'.\n", pval, sig);
+		pkg_free(ret);
+		return NULL;
+	    }
+
+	    return ret;
+    }
+    else
+    // byte
+    if (!strncmp(sig, "B", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_BYTE)
+	|| !strcmp(sig, "Ljava/lang/Byte;")
+#endif
+	) {
+//	    skptr = (signed char)char2jbyte(pval);
+	    sscanf(pval, "%x", &siptr);
+	    if (siptr == 0 && errno != 0)
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+            if (siptr < SCHAR_MAX || siptr > SCHAR_MAX)
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+            (*ret).b = (jbyte)siptr;
+	    return ret;
+    }
+    else
+    // char
+    if (!strncmp(sig, "C", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_CHARACTER)
+	|| !strcmp(sig, "Ljava/lang/Character;")
+#endif
+	) {
+	    sscanf(pval, "%c", &scptr);
+	    if (scptr == 0 && errno != 0)
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+            if (scptr < CHAR_MIN || scptr > CHAR_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+            (*ret).c = (jchar)scptr;
+	    return ret;
+    }
+    else
+    // double
+    if (!strncmp(sig, "D", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_DOUBLE)
+	|| !strcmp(sig, "Ljava/lang/Double;")
+#endif
+	) {
+	    sdptr = (double)strtod(pval, &endptr);
+	    if ((sdptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+            if (sdptr < LLONG_MIN || sdptr > LLONG_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).d = (jdouble)sdptr;
+	    return ret;
+    }
+    else
+    // float
+    if (!strncmp(sig, "F", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_FLOAT)
+	|| !strcmp(sig, "Ljava/lang/Float;")
+#endif
+	) {
+	    sfptr = (float)strtof(pval, &endptr);
+	    if ((sfptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+            if (sfptr < FLT_MIN || sfptr > FLT_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).f = (jfloat)sfptr;
+	    return ret;
+    }
+    else
+    // integer
+    if (!strncmp(sig, "I", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_INTEGER)
+	|| !strcmp(sig, "Ljava/lang/Integer;")
+#endif
+	) {
+	    slptr = strtol(pval, &endptr, 10);
+	    if ((slptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+	    if (slptr < INT_MIN || slptr > INT_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).i = (jint)slptr;
+	    return ret;
+    }
+    else
+    // long
+    if (!strncmp(sig, "J", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_LONG)
+	|| !strcmp(sig, "Ljava/lang/Long;")
+#endif
+	) {
+	    slptr = (long)strtol(pval, &endptr, 10);
+	    if ((slptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+	    if (slptr < LONG_MIN || slptr > LONG_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).j = (jlong)slptr;
+	    return ret;
+    }
+    else
+    // short
+    if (!strncmp(sig, "S", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_SHORT)
+	|| !strcmp(sig, "Ljava/lang/Short;")
+#endif
+	) {
+	    ssptr = (short)strtod(pval, &endptr);
+	    if ((ssptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+	    if (ssptr < SHRT_MIN || ssptr > SHRT_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).s = (jshort)ssptr;
+	    return ret;
+    }
+    // String (object)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_STRING)
+    else
+    if (!strcmp(sig, "Ljava/lang/String;"))
+    {
+	    sjptr = (*env)->NewStringUTF(env, pval);
+	    if ((*env)->ExceptionCheck(env))
+	    {
+		pkg_free(ret);
+		handle_exception();
+		return NULL;
+	    }
+/*
+	    if (pval != NULL && sjptr == NULL)
+	    {
+		pkg_free(ret);
+                return NULL;
+	    }
+*/
+	    (*ret).l = (jstring)sjptr;
+	    return ret;
+    }
+#endif
+#ifdef JAVA_INV_SUPP_TYPE_VOID
+    else
+    if (!strncmp(sig, "V", 1))
+    {
+	pkg_free(ret);
+	return NULL;
+    }
+#endif
+    else
+    {
+	// unknown sig
+	LM_ERR("app_java: Can't cast '%s' to signature '%s'\n", pval, sig);
+	pkg_free(ret);
+	return NULL;
+    }
+
+    return NULL;
+}
+

+ 50 - 0
modules/app_java/java_sig_parser.h

@@ -0,0 +1,50 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 __JAVA_SIG_PARSER_H__
+#define	__JAVA_SIG_PARSER_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#define	JAVA_INV_SUPP_TYPE_OBJECTS
+
+#define	JAVA_INV_SUPP_TYPE_BOOLEAN
+#define	JAVA_INV_SUPP_TYPE_BYTE
+#define	JAVA_INV_SUPP_TYPE_CHARACTER
+#define	JAVA_INV_SUPP_TYPE_DOUBLE
+#define	JAVA_INV_SUPP_TYPE_FLOAT
+#define	JAVA_INV_SUPP_TYPE_INTEGER
+#define	JAVA_INV_SUPP_TYPE_LONG
+#define	JAVA_INV_SUPP_TYPE_SHORT
+#define	JAVA_INV_SUPP_TYPE_STRING
+#define	JAVA_INV_SUPP_TYPE_VOID
+
+int is_sig_allowed(char *);
+jvalue *get_value_by_sig_type(char *, char *);
+
+
+#endif

+ 207 - 0
modules/app_java/java_support.c

@@ -0,0 +1,207 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 <libgen.h>
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+
+
+static char *_append_exception_trace_messages(char *msg_str, jthrowable a_exception, jmethodID a_mid_throwable_getCause, jmethodID a_mid_throwable_getStackTrace, jmethodID a_mid_throwable_toString, jmethodID a_mid_frame_toString)
+{
+    jobjectArray frames;
+    jsize frames_length, i;
+    jstring msg_obj;
+    jobject frame;
+    jthrowable cause;
+    jclass exClass;
+    jmethodID mid;
+    jboolean isCopy;
+
+    const char *tmpbuf;
+
+    // Get the array of StackTraceElements.
+    frames = (jobjectArray) (*env)->CallObjectMethod(env, a_exception, a_mid_throwable_getStackTrace);
+    if (!frames)
+    {
+        exClass = (*env)->GetObjectClass(env, a_exception);
+        mid = (*env)->GetMethodID(env, exClass, "toString", "()Ljava/lang/String;");
+        msg_obj = (jstring) (*env)->CallObjectMethod(env, a_exception, mid);
+
+        isCopy = JNI_FALSE;
+	tmpbuf = (*env)->GetStringUTFChars(env, msg_obj, &isCopy);
+
+	strcat(msg_str, tmpbuf);
+	strcat(msg_str, "\n    <<No stacktrace available>>");
+
+        (*env)->ReleaseStringUTFChars(env, msg_obj, tmpbuf);
+        (*env)->DeleteLocalRef(env, msg_obj);
+
+	return msg_str;
+    }
+    else
+    {
+	frames_length = (*env)->GetArrayLength(env, frames);
+    }
+
+    // Add Throwable.toString() before descending stack trace messages.
+    if (frames != 0)
+    {
+        msg_obj = (jstring) (*env)->CallObjectMethod(env, a_exception, a_mid_throwable_toString);
+	tmpbuf = (*env)->GetStringUTFChars(env, msg_obj, 0);
+	
+	strcat(msg_str, "Exception in thread \"main\" ");
+	strcat(msg_str, tmpbuf);
+
+        (*env)->ReleaseStringUTFChars(env, msg_obj, tmpbuf);
+        (*env)->DeleteLocalRef(env, msg_obj);
+    }
+
+
+    // Append stack trace messages if there are any.
+    if (frames_length > 0)
+    {
+        for (i=0; i<frames_length; i++)
+        {
+            // Get the string returned from the 'toString()'
+            // method of the next frame and append it to
+            // the error message.
+            frame = (*env)->GetObjectArrayElement(env, frames, i);
+            msg_obj = (jstring) (*env)->CallObjectMethod(env, frame, a_mid_frame_toString);
+
+            tmpbuf = (*env)->GetStringUTFChars(env, msg_obj, 0);
+
+	    strcat(msg_str, "\n    at ");
+	    strcat(msg_str, tmpbuf);
+
+            (*env)->ReleaseStringUTFChars(env, msg_obj, tmpbuf);
+            (*env)->DeleteLocalRef(env, msg_obj);
+            (*env)->DeleteLocalRef(env, frame);
+        }
+    }
+    else
+    {
+	strcat(msg_str, "\n    <<No stacktrace available>>");
+    }
+
+
+    // If 'a_exception' has a cause then append the
+    // stack trace messages from the cause.
+    if (frames != 0)
+    {
+        cause = (jthrowable) (*env)->CallObjectMethod(env, a_exception, a_mid_throwable_getCause);
+        if (cause != 0)
+        {
+            tmpbuf = _append_exception_trace_messages(msg_str, cause, a_mid_throwable_getCause, a_mid_throwable_getStackTrace, a_mid_throwable_toString, a_mid_frame_toString);
+	    strcat(msg_str, tmpbuf);
+        }
+    }
+
+    if (msg_str != NULL)
+	return strdup(msg_str);
+    else
+	return NULL;
+}
+
+void handle_exception(void)
+{
+    char *error_msg = NULL;
+    char msg_str[8192];
+
+    jthrowable exception;
+    jclass throwable_class, frame_class;
+    jmethodID mid_throwable_getCause, mid_throwable_getStackTrace;
+    jmethodID mid_throwable_toString, mid_frame_toString;
+
+    if (!(*env)->ExceptionCheck(env))
+	return;
+
+    memset(&msg_str, 0, sizeof(msg_str));
+
+    // Get the exception and clear as no
+    // JNI calls can be made while an exception exists.
+    exception = (*env)->ExceptionOccurred(env);
+    if (exception)
+    {
+//	(*env)->ExceptionDescribe(env);
+	(*env)->ExceptionClear(env);
+
+	throwable_class = (*env)->FindClass(env, "java/lang/Throwable");
+
+	mid_throwable_getCause = (*env)->GetMethodID(env, throwable_class, "getCause", "()Ljava/lang/Throwable;");
+        mid_throwable_getStackTrace =  (*env)->GetMethodID(env, throwable_class, "getStackTrace",  "()[Ljava/lang/StackTraceElement;");
+	mid_throwable_toString = (*env)->GetMethodID(env, throwable_class, "toString", "()Ljava/lang/String;");
+
+        frame_class = (*env)->FindClass(env, "java/lang/StackTraceElement");
+	mid_frame_toString = (*env)->GetMethodID(env, frame_class, "toString", "()Ljava/lang/String;");
+
+        error_msg = _append_exception_trace_messages(msg_str, exception, mid_throwable_getCause, mid_throwable_getStackTrace, mid_throwable_toString, mid_frame_toString);    
+
+
+	(*env)->DeleteLocalRef(env, exception);
+    }
+
+    LM_ERR("Exception:\n%s\n", error_msg == NULL ? "(no info)" : error_msg);
+
+}
+
+
+void handle_VM_init_failure(int res)
+{
+    switch(res)
+    {
+	    case -1:
+		LM_ERR("Couldn't initialize Java VM: unknown error\n");
+		break;
+	    case -2:
+		LM_ERR("Couldn't initialize Java VM: thread detached from the VM\n");
+	        break;
+	    case -3:
+		LM_ERR("Couldn't initialize Java VM: JNI version error\n");
+		break;
+	    case -4:
+		LM_ERR("Couldn't initialize Java VM: not enough memory\n");
+		break;
+	    case -5:
+		LM_ERR("Couldn't initialize Java VM: VM already created\n");
+		break;
+	    case -6:
+		LM_ERR("Couldn't initialize Java VM: invalid arguments\n");
+		break;
+	    default:
+		LM_ERR("Couldn't initialize Java VM. Error code: %d\n", res);
+		break;
+    }
+}
+
+

+ 37 - 0
modules/app_java/java_support.h

@@ -0,0 +1,37 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 __JAVA_SUPPORT_H__
+#define	__JAVA_SUPPORT_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+void handle_exception(void);
+void handle_VM_init_failure(int res);
+
+
+#endif

BIN
modules/app_java/kamailio_java_folder/java-untested/Kamailio.class


+ 388 - 0
modules/app_java/kamailio_java_folder/java-untested/Kamailio.java

@@ -0,0 +1,388 @@
+
+import java.lang.*;
+import java.io.*; 
+
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+//import org.siprouter.CoreMethods.*;
+
+public class Kamailio extends NativeMethods
+{
+	static
+	{
+	    System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+	}
+
+	/* Constructor. Do not remove !!! */
+	public Kamailio()
+	{
+	}
+
+
+	public int child_init(int rank)
+	{
+	    return 1;
+	}
+
+	public int TestMethod()
+	{
+
+	    int retval = 0;
+	    boolean boolstate = false;
+
+/*
+	    LM_INFO(String.format("Msg Type: %s\n", SipMsg.getMsgType()));
+
+	    IPPair src = SipMsg.getSrcAddress();
+	    if (src != null)
+	    {
+		LM_INFO(String.format("src address=%s, src port=%d\n", src.ip, src.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair src is null!");
+	    }
+
+	    IPPair dst = SipMsg.getDstAddress();
+	    if (dst != null)
+	    {
+		LM_INFO(String.format("dst address=%s, dst port=%d\n", dst.ip, dst.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair dst is null!");
+	    }
+
+	    LM_INFO(String.format("buffer:\n%s\n", SipMsg.getBuffer().trim()));
+
+	    SipMsg msg = SipMsg.ParseSipMsg();
+	    if (msg != null)
+	    {
+		LM_INFO("msg:\n");
+		LM_INFO(String.format("\tid=%d\n", msg.id));
+		LM_INFO(String.format("\tpid=%d\n", msg.pid));
+		LM_INFO(String.format("\teoh='%s'\n", msg.eoh));
+		LM_INFO(String.format("\tunparsed='%s'\n", msg.unparsed));
+		LM_INFO(String.format("\tbuf='%s'\n", msg.buf));
+		LM_INFO(String.format("\tlen=%d\n", msg.len));
+		LM_INFO(String.format("\tnew_uri='%s'\n", msg.new_uri));
+		LM_INFO(String.format("\tdst_uri='%s'\n", msg.dst_uri));
+		LM_INFO(String.format("\tparsed_uri_ok=%d\n", msg.parsed_uri_ok));
+		LM_INFO(String.format("\tparsed_orig_ruri_ok=%d\n", msg.parsed_orig_ruri_ok));
+		LM_INFO(String.format("\tadd_to_branch_s='%s'\n", msg.add_to_branch_s));
+		LM_INFO(String.format("\tadd_to_branch_len=%d\n", msg.add_to_branch_len));
+		LM_INFO(String.format("\thash_index=%d\n", msg.hash_index));
+		LM_INFO(String.format("\tmsg_flags=%d\n", msg.msg_flags));
+		LM_INFO(String.format("\tset_global_address='%s'\n", msg.set_global_address));
+		LM_INFO(String.format("\tset_global_port='%s'\n", msg.set_global_port));
+	    }
+	    else
+	    {
+		LM_ERR("SipMsg msg is null!\n");
+	    }
+
+*/
+//	    retval = KamExec("append_hf", "P-hint: VOICEMAIL\r\n");
+
+//	    KamExec("sl_send_reply", "404", "Not relaying");
+
+//	    retval = KamExec("is_method", "INVITE|SUBSCRIBE");
+
+//	    LM_INFO(String.format("return value: %d\n", retval));
+
+
+
+
+//	    retval = CoreMethods.rewriteuri("sip:[email protected]:5060");
+
+
+//	    retval = KamExec("rewriteuri", "sip:[email protected]:5060");
+//	    retval = KamExec("sl_send_reply", "404", "relaying failed");
+
+//	    LM_INFO(String.format("return value: %d\n", retval));
+
+
+//	    retval = CoreMethods.add_local_rport();
+//	    retval = CoreMethods.drop();
+//	    retval = CoreMethods.force_rport();
+//	    retval = CoreMethods.force_send_socket("192.168.254.9", 50349);
+//	    retval = CoreMethods.forward("198.61.206.9", 5060);
+//	    retval = CoreMethods.forward();
+
+
+//	    CoreMethods.setflag(3);
+
+//	    boolstate = CoreMethods.isflagset(3);
+//	    LM_INFO("return state: " + boolstate + "\n");
+
+//	    retval = CoreMethods.revert_uri();
+    
+//	    retval = CoreMethods.route("NATDETECT");
+//	    retval = CoreMethods.route("5");
+
+	    retval = KamExec("is_method", "INVITE");
+
+	    LM_INFO(String.format("return value: %d\n", retval));
+
+
+
+	    return 1;
+	}
+
+
+	public static final int FLT_ACC		= 1;
+	public static final int FLT_ACCMISSED	= 2;
+	public static final int FLT_ACCFAILED	= 3;
+	public static final int FLT_NATS	= 5;
+	public static final int FLB_NATB	= 6;
+	public static final int FLB_NATSIPPING	= 7;
+
+
+	/// route ///
+	public int route()
+	{
+	    return 1;
+	}
+
+
+
+	/// request_route ///
+	public int request_route()
+	{
+
+	    // per request initial checks
+	    CoreMethods.route("REQINIT");
+
+	    // NAT detection
+    	    CoreMethods.route("NATDETECT");
+
+	    // CANCEL processing
+    	    if (WrappedMethods.is_method("CANCEL"))
+    	    {
+                if (WrappedMethods.t_check_trans())
+		{
+                    WrappedMethods.t_relay();
+		}
+
+                return 1;
+    	    }
+
+/*
+
+
+    	    // handle requests within SIP dialogs
+    	    CoreMethods.route("WITHINDLG");
+
+	    //### only initial requests (no To tag)
+	    WrappedMethods.t_check_trans();
+
+	    // authentication
+	    CoreMethods.route("AUTH");
+
+    	    // record routing for dialog forming requests (in case they are routed)
+	    // - remove preloaded route headers
+	    WrappedMethods.remove_hf("Route");
+	    if (WrappedMethods.is_method("INVITE|SUBSCRIBE"))
+	    {
+                WrappedMethods.record_route();
+	    }
+
+	    // account only INVITEs
+	    if (WrappedMethods.is_method("INVITE"))
+    	    {
+        	CoreMethods.setflag(FLT_ACC); // do accounting
+	    }
+
+	    // dispatch requests to foreign domains
+	    CoreMethods.route("SIPOUT");
+
+	    // ### requests for my local domains
+
+	    // handle presence related requests
+	    CoreMethods.route("PRESENCE");
+
+	    String ruri = SipMsg.getRURI();
+    	    if (ruri == null || ruri.length() <= 0)
+    	    {
+                // request with no Username in RURI
+                WrappedMethods.sl_send_reply("484", "Address Incomplete");
+                return 1;
+    	    }
+
+	    // dispatch destinations to PSTN
+    	    CoreMethods.route("PSTN");
+
+	    // user location service
+	    CoreMethods.route("LOCATION");
+
+	    CoreMethods.route("RELAY");
+
+*/
+
+	    return 1;
+	}
+
+
+
+
+
+
+
+
+	public int Route_REQINIT()
+	{
+	    return 1;
+	}
+
+	public int Route_NATDETECT()
+	{
+	    return 1;
+	}
+
+	public int Route_WITHINDLG()	
+	{
+	    if (WrappedMethods.has_totag())
+	    {
+		// sequential request withing a dialog should
+                // take the path determined by record-routing
+
+		if (WrappedMethods.loose_route())
+		{
+		    CoreMethods.route("DLGURI");
+
+		    if (WrappedMethods.is_method("BYE"))
+		    {
+			CoreMethods.setflag(FLT_ACC);		// do accounting ...
+			CoreMethods.setflag(FLT_ACCFAILED);	// ... even if the transaction fails
+		    }
+		    else if (WrappedMethods.is_method("ACK"))
+		    {
+			// ACK is forwarded statelessy
+			CoreMethods.route("NATMANAGE");
+		    }
+		    else if (WrappedMethods.is_method("NOTIFY"))
+		    {
+			// Add Record-Route for in-dialog NOTIFY as per RFC 6665.
+			WrappedMethods.record_route();
+		    }
+
+		    CoreMethods.route("RELAY");
+		}
+		else
+		{
+/* // this block would not work -- 'uri' and 'myself' aren't implemented yet //
+                        if (is_method("SUBSCRIBE") && uri == myself) {
+                                # in-dialog subscribe requests
+                                route(PRESENCE);
+                                exit;
+                        }
+*/
+			if (WrappedMethods.is_method("ACK"))
+			{
+			    if (WrappedMethods.t_check_trans())
+			    {
+                                // no loose-route, but stateful ACK;
+                                // must be an ACK after a 487
+                                // or e.g. 404 from upstream server
+                                WrappedMethods.t_relay();
+			    }
+			    else
+			    {
+				// ACK without matching transaction ... ignore and discard
+				return 1;
+			    }	
+			}
+			WrappedMethods.sl_send_reply("404", "Not here");
+		}
+
+	    }
+
+
+	    return 1;
+	}
+
+	public int Route_AUTH()
+	{
+	    return 1;
+	}
+
+	public int Route_SIPOUT()
+	{
+	    return 1;
+	}
+
+	public int Route_PRESENCE()
+	{
+	    return 1;
+	}
+
+	public int Route_PSTN()
+	{
+	    return 1;
+	}
+
+	public int Route_LOCATION()
+	{
+	    return 1;
+	}
+
+	public int Route_RELAY()
+	{
+	    // enable additional event routes for forwarded requests
+	    //  - serial forking, RTP relaying handling, a.s.o.
+    	    if (WrappedMethods.is_method("INVITE|SUBSCRIBE"))
+	    {
+////                WrappedMethods.t_on_branch("MANAGE_BRANCH");
+////                WrappedMethods.t_on_reply("MANAGE_REPLY");
+    	    }
+	    
+	    if (WrappedMethods.is_method("INVITE"))
+	    {
+////                WrappedMethods.t_on_failure("MANAGE_FAILURE");
+    	    }
+
+    	    if (!WrappedMethods.t_relay())
+	    {
+                WrappedMethods.sl_reply_error();
+	    }
+
+	    return 1;
+	}
+
+	public int Route_REGISTRAR()
+	{
+	    if (WrappedMethods.is_method("REGISTER"))
+	    {
+		if (CoreMethods.isflagset(FLT_NATS))
+		{
+		    CoreMethods.setflag(FLB_NATB);
+		    // uncomment next line to do SIP NAT pinging
+		    // CoreMethods.setflag(FLB_NATSIPPING);
+		}
+
+		if (!WrappedMethods.save("location"))
+		{
+		    WrappedMethods.sl_reply_error();
+		}
+	    }
+
+	    return 1;
+	}
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 87 - 0
modules/app_java/kamailio_java_folder/java-untested/WrappedMethods.java

@@ -0,0 +1,87 @@
+import java.lang.*;
+import java.io.*;
+
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class WrappedMethods extends NativeMethods
+{
+	public static boolean is_method(String method)
+	{
+	    if (KamExec("is_method", method) == -1)
+		return false;
+	    else
+		return true;
+	}
+
+	public static boolean t_check_trans()
+	{
+	    if (KamExec("t_check_trans") == -1)
+		return false;
+	    else
+		return true;
+	}
+
+	public static boolean t_relay()
+	{
+	    if (KamExec("t_relay") == -1)
+		return false;
+	    else
+		return true;
+	}
+
+	public static void record_route()
+	{
+	    KamExec("record_route");
+	}
+
+	public static void append_hf(String txt)
+	{
+	    KamExec("append_hf", txt);
+	}
+
+	public static void append_hf(String txt, String hdr)
+	{
+	    KamExec("append_hf", txt, hdr);
+	}
+
+	public static void remove_hf(String hname)
+	{
+	    KamExec("remove_hf", hname);
+	}
+
+	public static void sl_send_reply(String replycode, String replymsg)
+	{
+	    KamExec("sl_send_reply", replycode, replymsg);
+	}
+
+	public static void sl_reply_error()
+	{
+	    KamExec("sl_reply_error");
+	}
+
+	public static boolean has_totag()
+	{
+	    if (KamExec("has_totag") == -1)
+                return false;
+            else
+                return true;
+        }
+
+	public static boolean loose_route()
+	{
+	    if (KamExec("loose_route") == -1)
+                return false;
+            else
+                return true;
+        }
+
+	public static boolean save(String location)
+	{
+	    if (KamExec("save", location) == -1)
+                return false;
+            else
+                return true;
+        }
+
+}

+ 46 - 0
modules/app_java/kamailio_java_folder/java-untested/build.xml

@@ -0,0 +1,46 @@
+<project name="Kamailio Examples" default="all">
+
+    <target name="all" description="Do the entire build" depends="clean,siprouter_compile,kamailio.jar,main_compile" >
+	<echo>Building Kamailio examples</echo>
+    </target>
+
+    <target name="make.dirs" description="Make a dir">
+	<mkdir dir="build"/>
+    </target>
+
+    <target name="kamailio.jar" description="make jar file" depends="siprouter_compile">
+	<jar destfile="kamailio.jar">
+    	    <fileset dir="build" includes="**">
+        	<include name="**/*.class"/>
+                <exclude name="**/CVS"/>
+                <exclude name="**/.svn"/>
+                <exclude name="**/.git"/>
+            </fileset>
+        </jar>
+    </target>
+
+    <target name="siprouter_compile" description="compile java"  depends="make.dirs">
+	<javac destdir="build" includeantruntime="false">
+    	    <src path="siprouter_src/"/>
+        </javac>
+    </target>
+
+    <target name="main_compile" description="compile java">
+	<javac destdir="." includeantruntime="false" includes="**.java">
+    	    <src path="."/>
+	    <classpath>
+		<pathelement path="."/>
+		<pathelement location="kamailio.jar"/>
+	    </classpath>
+        </javac>
+    </target>
+
+
+
+    <target name="clean" description="Clean up">
+        <delete dir="build"/>
+	<delete file="kamailio.jar"/>
+	<delete file="Kamailio.class"/>
+    </target>
+
+</project>

BIN
modules/app_java/kamailio_java_folder/java-untested/kamailio.jar


+ 34 - 0
modules/app_java/kamailio_java_folder/java-untested/siprouter_src/CoreMethods.java

@@ -0,0 +1,34 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public class CoreMethods
+{
+	    public static native int seturi(String ruri);
+	    public static native int rewriteuri(String ruri);			// alias to seturi
+
+	    public static native int add_local_rport();
+
+	    public static native int append_branch();
+	    public static native int append_branch(String branch);
+
+	    public static native int drop();
+
+	    public static native int force_rport();
+	    public static native int add_rport();				// alias to force_rport
+
+	    public static native int force_send_socket(String srchost, int srcport);
+
+	    public static native int forward();
+	    public static native int forward(String ruri, int port);
+
+	    public static native boolean isflagset(int flag);
+	    public static native void setflag(int flag);
+	    public static native void resetflag(int flag);
+
+	    public static native int revert_uri();
+
+	    public static native int route(String target);
+
+}
+

+ 15 - 0
modules/app_java/kamailio_java_folder/java-untested/siprouter_src/IPPair.java

@@ -0,0 +1,15 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public class IPPair
+{ 
+    public final String ip;
+    public final int port; 
+    
+    public IPPair(String ip, int port)
+    { 
+	this.ip = ip; 
+	this.port = port;
+    }
+}

+ 46 - 0
modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeInterface.java

@@ -0,0 +1,46 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public interface NativeInterface
+{
+    public abstract class Ranks
+    {
+	public static final int PROC_MAIN 		= 0;			// Main ser process
+	public static final int PROC_TIMER		= -1;			// Timer attendant process
+	public static final int PROC_RPC		= -2;			// RPC type process
+	public static final int PROC_FIFO		= PROC_RPC;		// FIFO attendant process
+	public static final int PROC_TCP_MAIN		= -4;			// TCP main process
+	public static final int PROC_UNIXSOCK		= -5;			// Unix socket server
+	public static final int PROC_ATTENDANT		= -10;			// main "attendant process
+	public static final int PROC_INIT		= -127;			/* special rank, the context is the main ser process, but this is 
+										    guaranteed to be executed before any rocess is forked, so it 
+										    can be used to setup shared variables that depend on some
+										    after mod_init available information (e.g. total number of processes).
+										    @warning child_init(PROC_MAIN) is again called in the same process (main)
+										    (before tcp), so make sure you don't init things twice, bot in PROC_MAIN and PROC_INT
+								*/
+	public static final int PROC_NOCHLDINIT		= -128;			// no child init functions will be called if this rank is used in fork_process()
+	public static final int PROC_SIPINIT		= 1;			// First SIP worker - some modules do special processing in this child, like loading db data
+	public static final int PROC_SIPRPC		= 127;			/* Used to init RPC worker as SIP commands handler. 
+										    Don't do any special processing in the child init with this rank - just bare child initialization
+										*/
+	public static final int PROC_MIN		= PROC_NOCHLDINIT;	// Minimum process rank
+    }
+
+    public abstract class LogParams
+    {
+	public static final int	L_ALERT			= -5;
+	public static final int L_BUG			= -4;
+	public static final int L_CRIT2			= -3;			// like L_CRIT, but adds prefix
+	public static final int L_CRIT			= -2;			// no prefix added
+	public static final int L_ERR			= -1;
+	public static final int L_WARN			= 0;
+	public static final int L_NOTICE		= 1;
+	public static final int L_INFO			= 2;
+	public static final int L_DBG			= 3;
+
+	public static final int DEFAULT_FACILITY	= 0;
+    }
+}
+

+ 22 - 0
modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeMethods.java

@@ -0,0 +1,22 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public abstract class NativeMethods
+{
+	    public static native void LM_GEN1(int logLevel, String s);
+	    public static native void LM_GEN2(int logFacility, int logLevel, String s);
+	    public static native void LM_ALERT(String s);
+	    public static native void LM_CRIT(String s);
+	    public static native void LM_WARN(String s);
+	    public static native void LM_NOTICE(String s);
+	    public static native void LM_ERR(String s);
+	    public static native void LM_INFO(String s);
+	    public static native void LM_DBG(String s);
+
+
+	    protected final int mop = 0x0;				// 'message object pointer' (pointer to an original c pointer of 'struct sip_msg')
+
+	    public static native int KamExec(String fname, String... params);
+}
+

+ 43 - 0
modules/app_java/kamailio_java_folder/java-untested/siprouter_src/SipMsg.java

@@ -0,0 +1,43 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public abstract class SipMsg
+{
+	/* Constructor. Do not remove !!! */
+	public SipMsg()
+	{
+	}
+
+	public int id;					// message id, unique/process
+	public int pid;					// process id
+	public String eoh;				// pointer to the end of header (if found) or null
+	public String unparsed;				// here we stopped parsing
+	public String buf;				// scratch pad, holds a modified message, via, etc. point into it
+	public int len;					// message len (orig)
+
+
+	public String new_uri;				// changed first line uri, when you change this
+	public String dst_uri;				// Destination URI, must be forwarded to this URI if dst_url lenght != 0
+	public int parsed_uri_ok;			// 1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+        public int parsed_orig_ruri_ok;			// 1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+
+	public String add_to_branch_s;			// whatever whoever want to append to branch comes here
+	public int add_to_branch_len;
+	public int hash_index;				// index to TM hash table; stored in core to avoid unnecessary calculations
+	public int msg_flags;				/* flags used by core. Allows to set various flags on the message; may be used for 
+							    simple inter-module communication or remembering processing state reached */
+	public String set_global_address;
+	public String set_global_port;
+
+
+	public static native SipMsg ParseSipMsg();
+
+	public static native String getMsgType();
+	public static native String getStatus();
+	public static native String getRURI();
+	public static native IPPair getSrcAddress();
+	public static native IPPair getDstAddress();
+	public static native String getBuffer();
+}
+

BIN
modules/app_java/kamailio_java_folder/java/Kamailio.class


+ 130 - 0
modules/app_java/kamailio_java_folder/java/Kamailio.java

@@ -0,0 +1,130 @@
+
+import java.lang.*;
+import java.io.*; 
+
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class Kamailio extends NativeMethods
+{
+	static
+	{
+	    System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+	}
+
+	/* Constructor. Do not remove !!! */
+	public Kamailio()
+	{
+	}
+
+
+	public int child_init(int rank)
+	{
+	    switch (rank)
+	    {
+		case Ranks.PROC_MAIN:
+		    LM_INFO("We're at PROC_MAIN\n");
+		    break;
+		case Ranks.PROC_TIMER:
+		    LM_INFO("We're at PROC_TIMER\n");
+		    break;
+		case Ranks.PROC_RPC:
+		    LM_INFO("We're at PROC_RPC/PROC_FIFO\n");
+		    break;
+		case Ranks.PROC_TCP_MAIN:
+		    LM_INFO("We're at PROC_TCP_MAIN\n");
+		    break;
+		case Ranks.PROC_UNIXSOCK:
+		    LM_INFO("We're at PROC_UNIXSOCK\n");
+		    break;
+		case Ranks.PROC_ATTENDANT:
+		    LM_INFO("We're at PROC_ATTENDANT\n");
+		    break;
+		case Ranks.PROC_INIT:
+		    LM_INFO("We're at PROC_INIT\n");
+		    break;
+		case Ranks.PROC_NOCHLDINIT:
+		    LM_INFO("We're at PROC_NOCHLDINIT/PROC_MIN\n");
+		    break;
+		case Ranks.PROC_SIPINIT:
+		    LM_INFO("We're at PROC_SIPINIT\n");
+		    break;
+		case Ranks.PROC_SIPRPC:
+		    LM_INFO("We're at PROC_SIPRPC\n");
+		    break;
+	    }
+
+	    return 1;
+	}
+
+	public int TestMethod()
+	{
+
+	    LM_INFO(String.format("Msg Type: %s\n", SipMsg.getMsgType()));
+
+	    IPPair src = SipMsg.getSrcAddress();
+	    if (src != null)
+	    {
+		LM_INFO(String.format("src address=%s, src port=%d\n", src.ip, src.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair src is null!");
+	    }
+
+	    IPPair dst = SipMsg.getDstAddress();
+	    if (dst != null)
+	    {
+		LM_INFO(String.format("dst address=%s, dst port=%d\n", dst.ip, dst.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair dst is null!");
+	    }
+
+	    LM_INFO(String.format("buffer:\n%s\n", SipMsg.getBuffer().trim()));
+
+	    SipMsg msg = SipMsg.ParseSipMsg();
+	    if (msg != null)
+	    {
+		LM_INFO("msg:\n");
+		LM_INFO(String.format("\tid=%d\n", msg.id));
+		LM_INFO(String.format("\tpid=%d\n", msg.pid));
+		LM_INFO(String.format("\teoh='%s'\n", msg.eoh));
+		LM_INFO(String.format("\tunparsed='%s'\n", msg.unparsed));
+		LM_INFO(String.format("\tbuf='%s'\n", msg.buf));
+		LM_INFO(String.format("\tlen=%d\n", msg.len));
+		LM_INFO(String.format("\tnew_uri='%s'\n", msg.new_uri));
+		LM_INFO(String.format("\tdst_uri='%s'\n", msg.dst_uri));
+		LM_INFO(String.format("\tparsed_uri_ok=%d\n", msg.parsed_uri_ok));
+		LM_INFO(String.format("\tparsed_orig_ruri_ok=%d\n", msg.parsed_orig_ruri_ok));
+		LM_INFO(String.format("\tadd_to_branch_s='%s'\n", msg.add_to_branch_s));
+		LM_INFO(String.format("\tadd_to_branch_len=%d\n", msg.add_to_branch_len));
+		LM_INFO(String.format("\thash_index=%d\n", msg.hash_index));
+		LM_INFO(String.format("\tmsg_flags=%d\n", msg.msg_flags));
+		LM_INFO(String.format("\tset_global_address='%s'\n", msg.set_global_address));
+		LM_INFO(String.format("\tset_global_port='%s'\n", msg.set_global_port));
+	    }
+	    else
+	    {
+		LM_ERR("SipMsg msg is null!\n");
+	    }
+
+	    return 1;
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 46 - 0
modules/app_java/kamailio_java_folder/java/build.xml

@@ -0,0 +1,46 @@
+<project name="Kamailio Examples" default="all">
+
+    <target name="all" description="Do the entire build" depends="clean,siprouter_compile,kamailio.jar,main_compile" >
+	<echo>Building Kamailio examples</echo>
+    </target>
+
+    <target name="make.dirs" description="Make a dir">
+	<mkdir dir="build"/>
+    </target>
+
+    <target name="kamailio.jar" description="make jar file" depends="siprouter_compile">
+	<jar destfile="kamailio.jar">
+    	    <fileset dir="build" includes="**">
+        	<include name="**/*.class"/>
+                <exclude name="**/CVS"/>
+                <exclude name="**/.svn"/>
+                <exclude name="**/.git"/>
+            </fileset>
+        </jar>
+    </target>
+
+    <target name="siprouter_compile" description="compile java"  depends="make.dirs">
+	<javac destdir="build" includeantruntime="false">
+    	    <src path="siprouter_src/"/>
+        </javac>
+    </target>
+
+    <target name="main_compile" description="compile java">
+	<javac destdir="." includeantruntime="false" includes="**.java">
+    	    <src path="."/>
+	    <classpath>
+		<pathelement path="."/>
+		<pathelement location="kamailio.jar"/>
+	    </classpath>
+        </javac>
+    </target>
+
+
+
+    <target name="clean" description="Clean up">
+        <delete dir="build"/>
+	<delete file="kamailio.jar"/>
+	<delete file="Kamailio.class"/>
+    </target>
+
+</project>

BIN
modules/app_java/kamailio_java_folder/java/kamailio.jar


+ 15 - 0
modules/app_java/kamailio_java_folder/java/siprouter_src/IPPair.java

@@ -0,0 +1,15 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public class IPPair
+{ 
+    public final String ip;
+    public final int port; 
+    
+    public IPPair(String ip, int port)
+    { 
+	this.ip = ip; 
+	this.port = port;
+    }
+}

+ 46 - 0
modules/app_java/kamailio_java_folder/java/siprouter_src/NativeInterface.java

@@ -0,0 +1,46 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public interface NativeInterface
+{
+    public abstract class Ranks
+    {
+	public static final int PROC_MAIN 		= 0;			// Main ser process
+	public static final int PROC_TIMER		= -1;			// Timer attendant process
+	public static final int PROC_RPC		= -2;			// RPC type process
+	public static final int PROC_FIFO		= PROC_RPC;		// FIFO attendant process
+	public static final int PROC_TCP_MAIN		= -4;			// TCP main process
+	public static final int PROC_UNIXSOCK		= -5;			// Unix socket server
+	public static final int PROC_ATTENDANT		= -10;			// main "attendant process
+	public static final int PROC_INIT		= -127;			/* special rank, the context is the main ser process, but this is 
+										    guaranteed to be executed before any rocess is forked, so it 
+										    can be used to setup shared variables that depend on some
+										    after mod_init available information (e.g. total number of processes).
+										    @warning child_init(PROC_MAIN) is again called in the same process (main)
+										    (before tcp), so make sure you don't init things twice, bot in PROC_MAIN and PROC_INT
+								*/
+	public static final int PROC_NOCHLDINIT		= -128;			// no child init functions will be called if this rank is used in fork_process()
+	public static final int PROC_SIPINIT		= 1;			// First SIP worker - some modules do special processing in this child, like loading db data
+	public static final int PROC_SIPRPC		= 127;			/* Used to init RPC worker as SIP commands handler. 
+										    Don't do any special processing in the child init with this rank - just bare child initialization
+										*/
+	public static final int PROC_MIN		= PROC_NOCHLDINIT;	// Minimum process rank
+    }
+
+    public abstract class LogParams
+    {
+	public static final int	L_ALERT			= -5;
+	public static final int L_BUG			= -4;
+	public static final int L_CRIT2			= -3;			// like L_CRIT, but adds prefix
+	public static final int L_CRIT			= -2;			// no prefix added
+	public static final int L_ERR			= -1;
+	public static final int L_WARN			= 0;
+	public static final int L_NOTICE		= 1;
+	public static final int L_INFO			= 2;
+	public static final int L_DBG			= 3;
+
+	public static final int DEFAULT_FACILITY	= 0;
+    }
+}
+

+ 23 - 0
modules/app_java/kamailio_java_folder/java/siprouter_src/NativeMethods.java

@@ -0,0 +1,23 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public abstract class NativeMethods
+{
+	    public static native void LM_GEN1(int logLevel, String s);
+	    public static native void LM_GEN2(int logFacility, int logLevel, String s);
+	    public static native void LM_ALERT(String s);
+	    public static native void LM_CRIT(String s);
+	    public static native void LM_WARN(String s);
+	    public static native void LM_NOTICE(String s);
+	    public static native void LM_ERR(String s);
+	    public static native void LM_INFO(String s);
+	    public static native void LM_DBG(String s);
+
+
+	    protected final int mop = 0x0;				// 'message object pointer' (pointer to an original c pointer of 'struct sip_msg')
+
+	    public static native int KamExec(String fname, String... params);
+
+}
+

+ 43 - 0
modules/app_java/kamailio_java_folder/java/siprouter_src/SipMsg.java

@@ -0,0 +1,43 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public abstract class SipMsg
+{
+	/* Constructor. Do not remove !!! */
+	public SipMsg()
+	{
+	}
+
+	public int id;					// message id, unique/process
+	public int pid;					// process id
+	public String eoh;				// pointer to the end of header (if found) or null
+	public String unparsed;				// here we stopped parsing
+	public String buf;				// scratch pad, holds a modified message, via, etc. point into it
+	public int len;					// message len (orig)
+
+
+	public String new_uri;				// changed first line uri, when you change this
+	public String dst_uri;				// Destination URI, must be forwarded to this URI if dst_url lenght != 0
+	public int parsed_uri_ok;			// 1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+        public int parsed_orig_ruri_ok;			// 1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+
+	public String add_to_branch_s;			// whatever whoever want to append to branch comes here
+	public int add_to_branch_len;
+	public int hash_index;				// index to TM hash table; stored in core to avoid unnecessary calculations
+	public int msg_flags;				/* flags used by core. Allows to set various flags on the message; may be used for 
+							    simple inter-module communication or remembering processing state reached */
+	public String set_global_address;
+	public String set_global_port;
+
+
+	public static native SipMsg ParseSipMsg();
+
+	public static native String getMsgType();
+	public static native String getStatus();
+	public static native String getRURI();
+	public static native IPPair getSrcAddress();
+	public static native IPPair getDstAddress();
+	public static native String getBuffer();
+}
+

+ 137 - 0
modules/app_java/utils.c

@@ -0,0 +1,137 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_native_methods.h"
+#include "java_sig_parser.h"
+
+
+char **split(char *str, char *sep)
+{
+    char **buf = NULL;
+    char *token = NULL;
+    char *saveptr = NULL;
+    int i;
+
+    buf = (char **)pkg_malloc(sizeof(char *));
+    if (!buf)
+    {
+	LM_ERR("pkg_malloc() has failed. Not enough memory!\n");
+	return NULL;
+    }
+    memset(&buf, 0, sizeof(char *));
+
+    if (str == NULL)
+	return buf;
+
+    if (strncmp(str, sep, strlen(sep)) <= 0)
+    {
+	// string doesn't contains a separator
+	buf[0] = strdup(str);
+	return buf;
+    }
+
+    token = strdup(str);
+    for (i=0; token != NULL; token = saveptr, i++)
+    {
+        token = strtok_r(token, (const char *)sep, &saveptr);
+
+        if (token == NULL || !strcmp(token, ""))
+            break;
+
+	buf = (char **)pkg_realloc(buf, (i+1) * sizeof(char *));
+	if (!buf)
+	{
+	    LM_ERR("pkg_realloc() has failed. Not enough memory!\n");
+	    return NULL;
+	}
+        buf[i] = strdup(token);
+    }
+    buf[i] = NULL;
+
+    free(token);
+
+    return buf;
+}
+
+void ThrowNewException(JNIEnv *env, char *fmt, ...)
+{
+    va_list ap;
+    char buf[1024];
+
+    memset(buf, 0, sizeof(char));
+
+    va_start(ap, fmt);
+    vsnprintf(buf, 1024, fmt, ap);
+    va_end(ap);
+
+    (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"), buf);
+}
+
+
+struct sip_msg *get_struct_sip_msg(JNIEnv *jenv)
+{
+    jfieldID fid;
+    int msgptr;
+    jclass cls;
+
+    cls = (*jenv)->GetObjectClass(jenv, KamailioClassInstance);
+    fid = (*jenv)->GetFieldID(jenv, cls, "mop", "I");
+    if (!fid)
+    {
+        (*jenv)->ExceptionClear(jenv);
+        LM_ERR("Failed to find protected field org.siprouter.NativeMethods.mop\n");
+        return NULL;
+    }
+    (*jenv)->DeleteLocalRef(jenv, cls);
+
+    msgptr = (int)(*jenv)->GetIntField(jenv, KamailioClassInstance, fid);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    if (msgptr == 0x0)
+    {
+        LM_ERR("app_java: KamExec(): Unable to execute. Internal Error: msgptr is NULL\n");
+        return NULL;
+    }
+
+    return FORCE_CAST_O2P(msgptr, struct sip_msg *);
+}
+
+

+ 39 - 0
modules/app_java/utils.h

@@ -0,0 +1,39 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 file 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 __UTILS_H__
+#define __UTILS_H__
+
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+// cast object to pointer
+#define FORCE_CAST_O2P(var, type) *(type*)&var
+
+char **split(char *, char *);
+void ThrowNewException(JNIEnv *, char *, ...);
+struct sip_msg *get_struct_sip_msg(JNIEnv *);
+
+#endif