浏览代码

Merge branch 'master' of ssh://git.sip-router.org/sip-router

* 'master' of ssh://git.sip-router.org/sip-router:
  modules/app_java: refactoring, changed parameter 'force_kam_cmd_exec' to 'force_cmd_exec', updated docs     - moved ThrowNewException from utils to java_support     - removed macro FORCE_CAST_O2P     - removed get_struct_sip_msg     - renamed parameter 'force_kam_cmd_exec' to 'force_cmd_exec'     - updated docs caused parameter change
  modules/app_java: README to README-draft, added actual README
  modules/app_java: moved README, removed other formats except xml from doc directory.
  modules/app_java: added documentation, removed *.class,*.jar
  modules/sca: fix -Waddress warnings caused by static strs in SCA_STR_EMPTY
  modules/sca: process BYE without Call-Info from shared line.
  modules/outbound: Warn during mod_init() if STUN is not built or enabled
  modules/outbound: free shared memory for flow-token key during shutdown
  sca: reduce log level to DBG when replacing RURI when retrieving held call.
  modules/outbound: Fixed bug in outbound mod_init
  modules/outbound: The flow-token key is now automatically generated
Hugh Waite 12 年之前
父节点
当前提交
3a45d925c7

+ 1 - 1
modules/app_java/QUICKSTART.TXT

@@ -14,7 +14,7 @@ modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=<KA
 
 # 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);
+modparam("app_java", "force_cmd_exec", 1);
 
 
 

+ 573 - 0
modules/app_java/README

@@ -0,0 +1,573 @@
+app_java Module
+
+Konstantin Mosesov
+
+Edited by
+
+Konstantin Mosesov
+
+   Copyright © 2013 Konstantin Mosesov
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Java runtime
+
+              3.1.
+
+        4. Parameters
+
+              4.1. class_name (string)
+              4.2. child_init_method (string)
+              4.3. java_options (string)
+              4.4. force_cmd_exec (int)
+
+        5. Functions
+
+              5.1. Common requirements
+              5.2. java_method_exec(method, method_signature, [param1[,
+                      param2[, ...]]])
+
+              5.3. java_staticmethod_exec(method, method_signature,
+                      [param1[, param2[, ...]]])
+
+              5.4. java_s_method_exec(method, method_signature, [param1[,
+                      param2[, ...]]])
+
+              5.5. java_s_staticmethod_exec(method, method_signature,
+                      [param1[, param2[, ...]]])
+
+        6. Java Module API
+
+              6.1. Minimal program skeleton
+
+   List of Examples
+
+   1.1. Set class_name parameter
+   1.2. Set child_init_method parameter
+   1.3. Set java_options parameter
+   1.4. Set java_options parameter (live configuration)
+   1.5. Set java_options parameter (verbose configuration)
+   1.6. Set java_options parameter (debug configuration)
+   1.7. Set force_cmd_exec parameter
+   1.8. Signature: "V"
+   1.9. Signature: "Ljava/lang/String;I"
+   1.10. Signature: "ZB"
+   1.11. Signature: "V"
+   1.12. Signature: "Ljava/lang/String;I"
+   1.13. Signature: "ZB"
+   1.14. Signature: "V"
+   1.15. Signature: "Ljava/lang/String;I"
+   1.16. Signature: "ZB"
+   1.17. Signature: "V"
+   1.18. Signature: "Ljava/lang/String;I"
+   1.19. Signature: "ZB"
+   1.20. Minimal program skeleton
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Java runtime
+
+        3.1.
+
+   4. Parameters
+
+        4.1. class_name (string)
+        4.2. child_init_method (string)
+        4.3. java_options (string)
+        4.4. force_cmd_exec (int)
+
+   5. Functions
+
+        5.1. Common requirements
+        5.2. java_method_exec(method, method_signature, [param1[, param2[,
+                ...]]])
+
+        5.3. java_staticmethod_exec(method, method_signature, [param1[,
+                param2[, ...]]])
+
+        5.4. java_s_method_exec(method, method_signature, [param1[,
+                param2[, ...]]])
+
+        5.5. java_s_staticmethod_exec(method, method_signature, [param1[,
+                param2[, ...]]])
+
+   6. Java Module API
+
+        6.1. Minimal program skeleton
+
+1. Overview
+
+   This module allows executing Java compiled classes from config file,
+   exporting functions to access the SIP message from Java using Java
+   Native Interface (JNI).
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following packages are runtime libraries, required to launch
+     * java-common Base of all Java packages.
+     * default-jre Standard Java or Java compatible Runtime.
+     * gcj-jre Java runtime environment using GIJ/classpath.
+     * libgcj12 (>=12) Java runtime library for use with gcj.
+
+   The following packages are optional, required for development
+     * ant Java based build tool like make.
+     * ant-contrib Collection of tasks, types and other tools for Apache
+       Ant.
+     * ant-gcj Java based build tool like make (GCJ).
+     * default-jdk Standard Java or Java compatible Development Kit
+     * gcj-jdk gcj and classpath development tools for Java(TM)
+     * libgcj13-dev (>=12) Java development headers for use with gcj
+     * jdk JDK Development Kit (either oracle jdk or openjdk)
+
+   The following libraries or applications must be compiled before running
+   Kamailio with this module loaded:
+
+   The following packages are runtime libraries, required to launch
+     * <class_name>.class
+     * kamailio.jar
+
+3. Java runtime
+
+   3.1.
+
+3.1.
+
+   Java runtime library (JRE or JDK) is required to use this module.
+
+4. Parameters
+
+   4.1. class_name (string)
+   4.2. child_init_method (string)
+   4.3. java_options (string)
+   4.4. force_cmd_exec (int)
+
+4.1. class_name (string)
+
+   The class name should have the same compiled file name. If the value is
+   "Kamailio", then the compiled file should be named as "Kamailio.class".
+
+   Default value is “Kamailio”.
+
+   Example 1.1. Set class_name parameter
+...
+modparam("app_java", "class_name", "Kamailio")
+...
+
+4.2. child_init_method (string)
+
+   TBD.
+
+   Default value is “child_init”.
+
+   Example 1.2. Set child_init_method parameter
+...
+modparam("app_java", "child_init_method", "my_mod_init")
+...
+
+4.3. java_options (string)
+
+   Java options for Java Virtual Machine. For more info read java docs
+
+   Default value is “-Djava.compiler=NONE”.
+
+   Example 1.3. Set java_options parameter
+...
+modparam("app_java", "java_options", "-Djava.compiler=NONE")
+...
+
+   Example 1.4. Set java_options parameter (live configuration)
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=/pa
+th/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+...
+
+   Example 1.5. Set java_options parameter (verbose configuration)
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-verbose:gc,class,jni -Djava.compiler=NONE
+ -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/ja
+va/kamailio.jar")
+...
+
+   Example 1.6. Set java_options parameter (debug configuration)
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni -Djava.compi
+ler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kam
+ailio/java/kamailio.jar")
+...
+
+4.4. force_cmd_exec (int)
+
+   This parameter forces execution a kamailio comnmand with java native
+   method “KamExec”. # Note: this is an untested yet feature, may cause
+   (but may not) a memory leaks if used from embedded languages.
+
+   Default value is “0 (off)”.
+
+   Example 1.7. Set force_cmd_exec parameter
+...
+modparam("app_java", "force_cmd_exec", 1)
+...
+
+5. Functions
+
+   5.1. Common requirements
+   5.2. java_method_exec(method, method_signature, [param1[, param2[,
+          ...]]])
+
+   5.3. java_staticmethod_exec(method, method_signature, [param1[,
+          param2[, ...]]])
+
+   5.4. java_s_method_exec(method, method_signature, [param1[, param2[,
+          ...]]])
+
+   5.5. java_s_staticmethod_exec(method, method_signature, [param1[,
+          param2[, ...]]])
+
+5.1.  Common requirements
+
+   Each function has a required parameter “method_signature”. For more
+   info see Determine the signature of a method. Signature represents the
+   variable type. The mapping between the Java type and C type is
+                Type     Chararacter
+                boolean      Z
+                byte         B
+                char         C
+                double       D
+                float        F
+                int          I
+                long         J
+                object       L
+                short        S
+                void         V
+                Note that to specify an object, the "L" is followed by the objec
+t's class name and ends with a semi-colon, ';' .
+
+   app_java supports the following signatures:
+                Primitives: Z,B,C,D,F,I,J,L,S,V
+                Objects:
+                        Ljava/lang/Boolean;
+                        Ljava/lang/Byte;
+                        Ljava/lang/Character;
+                        Ljava/lang/Double;
+                        Ljava/lang/Float;
+                        Ljava/lang/Integer;
+                        Ljava/lang/Long;
+                        Ljava/lang/Short;
+                        Ljava/lang/String;
+                        NULL parameter: V
+
+        Each parameter passed to function will be cast according to given signat
+ure.
+
+        Parameters are optional, ommitting a parameter meant the passed value is
+ NULL.
+        Parameters count should be exactly the same as signature count.
+        Note 1: Arrays representation (symbol '[') is not supported yet.
+        Note 2: You shall use a correct signature, e.g. the following examples o
+f combinations are invalid:
+        java_method_exec("ExampleMethod", "ZI", "False");
+        java_method_exec("ExampleMethod", "LI", "something", "5");
+
+5.2. java_method_exec(method, method_signature, [param1[, param2[, ...]]])
+
+   Executes a java class method method. Parameter method_signature is
+   required.
+     * Example 1.8. Signature: "V"
+       Kamailio prototype
+java_method_exec("ExampleMethod", "V");
+       Java prototype
+public int ExampleMethod();
+       Example of usage:
+# Kamailio
+java_method_exec("ExampleMethod", "V");
+
+# Java
+public int ExampleMethod()
+{
+                ... do something;
+                return 1;
+}
+     * Example 1.9. Signature: "Ljava/lang/String;I"
+       Kamailio prototype
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");
+       Java prototype
+public int ExampleMethod(String param1, int param2);
+       In the above scenario parameter 2 ("5") will be cast to integer
+       representation.
+       Example of usage:
+# Kamailio
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+                ... do something with buffer;
+                return 1;
+}
+     * Example 1.10. Signature: "ZB"
+       Kamailio prototype
+java_method_exec("ExampleMethod", "ZB", "true", "0x05");
+       Java prototype
+public int ExampleMethod(boolean param1, byte param2);
+       In the above scenario parameter 1 ("true") will be cast to boolean
+       representation.
+       Example of usage:
+# Kamailio
+java_method_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public int ExampleMethod(boolean flagSet, byte bFlag);
+{
+                if (flagSet)
+                {
+                        ... do something with flags;
+                }
+                return 1;
+}
+
+5.3. java_staticmethod_exec(method, method_signature, [param1[, param2[,
+...]]])
+
+   Executes a java static method method. Parameter method_signature is
+   required.
+     * Example 1.11. Signature: "V"
+       Kamailio prototype
+java_staticmethod_exec("ExampleMethod", "V");
+       Java prototype
+public static int ExampleMethod();
+       Example of usage:
+# Kamailio
+java_staticmethod_exec("ExampleMethod", "V");
+
+# Java
+public static int ExampleMethod()
+{
+                ... do something;
+                return 1;
+}
+     * Example 1.12. Signature: "Ljava/lang/String;I"
+       Kamailio prototype
+java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5
+");
+       Java prototype
+public static int ExampleMethod(String param1, int param2);
+       In the above scenario parameter 2 ("5") will be cast to integer
+       representation.
+       Example of usage:
+# Kamailio
+java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+                ... do something with buffer;
+                return 1;
+}
+     * Example 1.13. Signature: "ZB"
+       Kamailio prototype
+java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+       Java prototype
+public static int ExampleMethod(boolean param1, byte param2);
+       In the above scenario parameter 1 ("true") will be cast to boolean
+       representation.
+       Example of usage:
+# Kamailio
+java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public static int ExampleMethod(boolean flagSet, byte bFlag);
+{
+                if (flagSet)
+                {
+                        ... do something with flags;
+                }
+                return 1;
+}
+
+5.4. java_s_method_exec(method, method_signature, [param1[, param2[, ...]]])
+
+   Executes a java class synchronized method method. Parameter
+   method_signature is required.
+
+   For more info see Synchronized Methods
+     * Example 1.14. Signature: "V"
+       Kamailio prototype
+java_s_method_exec("ExampleMethod", "V");
+       Java prototype
+public synchronized int ExampleMethod();
+       Example of usage:
+# Kamailio
+java_s_method_exec("ExampleMethod", "V");
+
+# Java
+public synchronized int ExampleMethod()
+{
+                ... do something;
+                return 1;
+}
+     * Example 1.15. Signature: "Ljava/lang/String;I"
+       Kamailio prototype
+java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");
+       Java prototype
+public synchronized int ExampleMethod(String param1, int param2);
+       In the above scenario parameter 2 ("5") will be cast to integer
+       representation.
+       Example of usage:
+# Kamailio
+java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLen
+ght)
+{
+                ... do something with buffer;
+                return 1;
+}
+     * Example 1.16. Signature: "ZB"
+       Kamailio prototype
+java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");
+       Java prototype
+public synchronized int ExampleMethod(boolean param1, byte param2);
+       In the above scenario parameter 1 ("true") will be cast to boolean
+       representation.
+       Example of usage:
+# Kamailio
+java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public synchronized int ExampleMethod(boolean flagSet, byte bFlag);
+{
+                if (flagSet)
+                {
+                        ... do something with flags;
+                }
+                return 1;
+}
+
+5.5. java_s_staticmethod_exec(method, method_signature, [param1[, param2[,
+...]]])
+
+   Executes a java synchronized static method method. Parameter
+   method_signature is required.
+
+   For more info see Synchronized Methods
+     * Example 1.17. Signature: "V"
+       Kamailio prototype
+java_s_staticmethod_exec("ExampleMethod", "V");
+       Java prototype
+public static synchronized int ExampleMethod();
+       Example of usage:
+# Kamailio
+java_s_staticmethod_exec("ExampleMethod", "V");
+
+# Java
+public static synchronized int ExampleMethod()
+{
+                ... do something;
+                return 1;
+}
+     * Example 1.18. Signature: "Ljava/lang/String;I"
+       Kamailio prototype
+java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world",
+"5");
+       Java prototype
+public static synchronized int ExampleMethod(String param1, int param2);
+       In the above scenario parameter 2 ("5") will be cast to integer
+       representation.
+       Example of usage:
+# Kamailio
+java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMes
+sageLenght)
+{
+                ... do something with buffer;
+                return 1;
+}
+     * Example 1.19. Signature: "ZB"
+       Kamailio prototype
+java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+       Java prototype
+public static synchronized int ExampleMethod(boolean param1, byte param2);
+       In the above scenario parameter 1 ("true") will be cast to boolean
+       representation.
+       Example of usage:
+# Kamailio
+java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public static synchronized int ExampleMethod(boolean flagSet, byte bFlag);
+{
+                if (flagSet)
+                {
+                        ... do something with flags;
+                }
+                return 1;
+}
+
+6. Java Module API
+
+   6.1. Minimal program skeleton
+
+6.1. Minimal program skeleton
+
+   Example 1.20. Minimal program skeleton
+
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class Kamailio extends NativeMethods
+{
+                /* Here you should specify a full path to app_java.so */
+                static
+                {
+                                System.load("/opt/kamailio/lib/kamailio/modules/
+app_java.so");
+                }
+
+                /* Constructor. Do not remove !!! */
+                public Kamailio()
+                {
+                }
+
+                /*
+                This method should be executed for each children process, immedi
+ately after forking.
+                Required. Do not remove !!!
+                */
+                public int child_init(int rank)
+                {
+                                return 1;
+                }
+}

+ 837 - 0
modules/app_java/README-draft

@@ -0,0 +1,837 @@
+app_java Module
+
+Konstantin Mosesov
+
+Edited by
+
+Konstantin Mosesov
+
+   <[email protected]>
+
+   Copyright © 2013 Konstantin Mosesov
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+	      3.1. class_name (string)
+              3.2. child_init_method (string)
+	      3.3. java_options (string)
+	      3.4. force_cmd_exec (int)
+
+        4. Functions
+
+	      4.0. Common requirements.
+              4.1. java_method_exec(method, method_signature, [param1[, param2]])
+	      4.2. java_s_method_exec(method, method_signature, [param1[, param2]])
+	      4.3. java_staticmethod_exec(method, method_signature, [param1[, param2]])
+	      4.4. java_s_staticmethod_exec(method, method_signature, [param1[, param2]])
+
+	5. Java module API
+
+	      5.0. Minimal program skeleton and structure of package org.siprouter
+		   5.0.1.  Minimal program skeleton
+		   5.0.2.  Structure of package org.siprouter
+	      5.1. abstract class NativeMethods
+	           5.1.1.  General logging
+			   5.1.1.0.   Logging levels and facilities
+			   5.1.1.1.   native void LM_GEN1(int logLevel, String s);
+			   5.1.1.2.   native void LM_GEN2(int logFacility, int logLevel, String s);
+			   5.1.1.3.   native void LM_ALERT(String s);
+			   5.1.1.4.   native void LM_CRIT(String s);
+			   5.1.1.5.   native void LM_WARN(String s);
+			   5.1.1.6.   native void LM_NOTICE(String s);
+			   5.1.1.7.   native void LM_ERR(String s);
+			   5.1.1.8.   native void LM_INFO(String s);
+			   5.1.1.9.   native void LM_DBG(String s);
+		   5.1.2.  Execution of kamailio commands
+			   5.1.2.1.   static native int KamExec(String fname, String... params);
+    			   5.1.2.2.   static native int SetURI(String ruri);
+    			   5.1.2.3.   static native int RewriteURI(String ruri);
+
+	      5.2. class IPPair.
+		   5.2.1.   final String ip;
+		   5.2.2.   final int port;
+	      5.3. abstract class SipMsg
+		   5.3.0.   Internal structure understanding.
+		   5.3.1.   int id;
+		   5.3.2.   int pid;
+		   5.3.3.   String eoh;
+		   5.3.4.   String unparsed;
+		   5.3.5.   String buf;
+		   5.3.6.   int len;
+		   5.3.7.   String new_uri;
+		   5.3.8.   String dst_uri;
+		   5.3.9.   int parsed_uri_ok;
+		   5.3.10.  int parsed_orig_ruri_ok;
+		   5.3.11.  String add_to_branch_s;
+		   5.3.12.  int add_to_branch_len;
+		   5.3.13.  int hash_index;
+		   5.3.14.  int msg_flags;
+		   5.3.15.  static native SipMsg ParseSipMsg();
+		   5.3.16.  static native String getMsgType();
+		   5.3.17.  static native String getRURI();
+		   5.3.18.  static native IPPair getSrcAddress();
+		   5.3.19.  static native IPPair getDstAddress();
+		   5.3.20.  static native String getBuffer();
+	      5.4. interface NativeInterface
+		   5.4.1.   abstract class Ranks
+			    5.4.1.1.  static final int PROC_MAIN
+			    5.4.1.2.  static final int PROC_TIMER
+			    5.4.1.3.  static final int PROC_RPC
+			    5.4.1.4.  static final int PROC_FIFO
+			    5.4.1.5.  static final int PROC_TCP_MAIN
+			    5.4.1.6.  static final int PROC_UNIXSOCK
+			    5.4.1.7.  static final int PROC_ATTENDANT
+			    5.4.1.8.  static final int PROC_INIT
+			    5.4.1.9.  static final int PROC_NOCHLDINIT
+			    5.4.1.10. static final int PROC_SIPINIT
+			    5.4.1.11. static final int PROC_SIPRPC
+			    5.4.1.12. static final int PROC_MIN
+		   5.4.2.   abstract class LogParams
+			    5.4.2.0.  Loggigng params
+			    5.4.2.1.  static final int L_ALERT
+			    5.4.2.2.  static final int L_BUG
+			    5.4.2.3.  static final int L_CRIT2
+			    5.4.2.4.  static final int L_CRIT
+			    5.4.2.5.  static final int L_ERR
+			    5.4.2.6.  static final int L_WARN
+			    5.4.2.7.  static final int L_NOTICE
+			    5.4.2.8.  static final int L_INFO
+			    5.4.2.9.  static final int L_DBG
+			    5.4.2.10. static final int DEFAULT_FACILITY
+	      5.5. Examples of usage Java API
+
+   List of Examples
+
+   1.1. Set class_name parameter
+   1.2. Set child_init_method parameter
+   1.3. Set java_options parameter
+   1.4. Set java_options parameter (live configuration)
+   1.5. Set java_options parameter (verbose configuration)
+   1.6. Set java_options parameter (debug configuration)
+
+   2.0. Example of usage signatures.
+   2.1. Example of usage java_method_exec()
+   2.2. Example of usage java_s_method_exec()
+   2.3. Example of usage java_staticmethod_exec()
+   3.4. Example of usage java_s_staticmethod_exec()
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. class_name (string)
+        3.2. child_init_method (string)
+        3.3. java_options (string)
+	3.4. force_cmd_exec (int)
+
+   4. Functions
+
+	4.0. Common requirements.
+        4.1. java_method_exec(method, method_signature, [param1[, param2]])         - class method
+        4.2. java_s_method_exec(method, method_signature, [param1[, param2]])       - class synchronized method
+        4.3. java_staticmethod_exec(method, method_signature, [param1[, param2]])   - static method
+        4.4. java_s_staticmethod_exec(method, method_signature, [param1[, param2]]) - static synchronized method
+
+1. Overview
+
+   This module allows executing Java compiled classes from config file, exporting
+   functions to access the SIP message from Java using Java Native Interface (JNI).
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+   2.3. Java runtime
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   Legend:
+      * - Runtime library, required to launch
+      R - Required
+      O - Optional
+      D - Development (for building-rebuilding java)
+      P - Dependance of package
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     [*]    java-common            - Base of all Java packages
+     [*]    default-jre            - Standard Java or Java compatible Runtime
+     [*]    gcj-jre                - Java runtime environment using GIJ/classpath
+     [*]    libgcj12 (>=12)        - Java runtime library for use with gcj
+     [DR]   ant                    - Java based build tool like make
+     [DO]   ant-contrib            - collection of tasks, types and other tools for Apache Ant
+     [DPO]  ant-gcj                - Java based build tool like make (GCJ)
+     [DPO]  ant-optional           - Java based build tool like make - optional libraries
+     [DPO]  ant-optional-gcj       - Java based build tool like make - optional libraries (GCJ)
+     [DR]   default-jdk            - Standard Java or Java compatible Development Kit
+     [DR]   gcj-jdk                - gcj and classpath development tools for Java(TM)
+     [DR]   libgcj13-dev (>=12)    - Java development headers for use with gcj
+     [DO]   jdk                    - JDK Development Kit (either oracle jdk or openjdk)
+
+   The following libraries or applications must be compiled before
+   running Kamailio with this module loaded:
+     [*]   <class_name>.class
+     [*]   kamailio.jar
+
+2.3. Java runtime
+
+   Java runtime library (JRE or JDK) is required to use this module.
+
+3. Parameters
+
+   3.1. class_name (string)
+   3.2. child_init_method (string)
+   3.3. java_options (string)
+   3.4. force_cmd_exec (int)
+
+3.1. class_name (string)
+
+   The class name should have the same compiled file name.
+   If the value is "Kamailio", then the compiled file should be named as "Kamailio.class".
+
+   Default value is “Kamailio”.
+
+   Example 1.1. Set class_name parameter
+...
+modparam("app_java", "class_name", "Kamailio")
+...
+
+3.2. child_init_method (string)
+
+   TBD.
+
+   Default value is “child_init”.
+
+   Example 1.2. Set child_init_method parameter
+...
+modparam("app_java", "child_init_method", "my_mod_init")
+...
+
+3.3. java_options (string)
+
+   Java options for Java Virtual Machine.
+   For more info see: http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html
+
+   Default value is “-Djava.compiler=NONE”.
+
+   Example 1.3. Set java_options parameter
+...
+modparam("app_java", "java_options", "-Djava.compiler=NONE")
+...
+
+   Example 1.4. Set java_options parameter (live configuration)
+...
+modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/path/to/<class_name>_file_directory:/path/to/kamailio.jar")
+...
+
+   Example 1.5. Set java_options parameter (verbose configuration)
+...
+modparam("app_java", "java_options", "-verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/path/to/class_name_file_directory:/path/to/kamailio.jar")
+...
+
+   Example 1.6. Set java_options parameter (debug configuration)
+...
+modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/path/to/class_name_file_directory:/path/to/kamailio.jar")
+...
+
+3.4. force_cmd_exec (int)
+
+   This parameter forces execution a kamailio comnmand with java native method KamExec_raw.
+   Note: may cause a memory leaks if used from embedded languages.
+
+   Default value is 0 (off).
+
+4. Functions
+
+   4.0. Common requirements.
+   4.1. java_method_exec(method, method_signature, [param1[, param2]])
+   4.2. java_s_method_exec(method, method_signature, [param1[, param2]])
+   4.3. java_staticmethod_exec(method, method_signature, [param1[, param2]])
+   4.4. java_s_staticmethod_exec(method, method_signature, [param1[, param2]])
+
+4.0. Common requirements.
+
+   Each function has a required parameter “method_signature”.
+   For more info see: http://www.rgagnon.com/javadetails/java-0286.html
+   There are two parts to the signature. The first part is enclosed within the parentheses and represents the method's arguments. 
+   The second portion follows the closing parenthesis and represents the return type. The mapping between the Java type and C type is
+	Type     Chararacter 
+	boolean      Z 
+	byte         B 
+	char         C 
+	double       D 
+	float        F 
+	int          I 
+	long         J 
+	object       L 
+	short        S 
+	void         V 
+	array        [ 
+   Note that to specify an object, the "L" is followed by the object's class name and ends with a semi-colon, ';' .
+
+   app_java supports the following signatures
+      primitives: Z,B,C,D,F,I,J,L,S,V
+      objects: 
+		Ljava/lang/Boolean;
+		Ljava/lang/Byte;
+		Ljava/lang/Character;
+		Ljava/lang/Double;
+		Ljava/lang/Float;
+		Ljava/lang/Integer;
+		Ljava/lang/Long;
+		Ljava/lang/Short;
+		Ljava/lang/String;
+      NULL parameter: V
+
+   Each parameter passed to function will be cast according to given signature.
+
+   Example 2.0. Example of usage signatures.
+        0. Equivalent of java prototype:  public int ExampleMethod();
+...
+java_method_exec("ExampleMethod", "V");
+...
+
+        1. Equivalent of java prototype:  public int ExampleMethod(String param1, int param2);
+...
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");
+...
+           In the above scenario parameter 2 ("5") will be cast to integer representation.
+
+        2. Equivalent of java prototype:  public int ExampleMethod(boolean param1, byte param2);
+...
+java_method_exec("ExampleMethod", "ZB", "true", "0x05");
+...
+           In the above scenario parameter 1 ("true") will be cast to boolean representation.
+
+   Parameters are optional, ommitting a parameter meant the passed value is NULL.
+   Parameters count should be exactly the same as signature count.
+   Note, you shall use a correct signature, e.g. the following examples of combinations are invalid:
+        *) java_method_exec("ExampleMethod", "ZI", "False");
+        *) java_method_exec("ExampleMethod", "VI", "", "5");
+        *) java_method_exec("ExampleMethod", "LI", "something", "5");
+
+
+4.1.  java_method_exec(method, method_signature, [param1[, param2]])
+
+   Executes a java method “method”. Parameter “method_signature” is required (see 4.0).
+
+   Example 2.1. java_method_exec usage
+...
+# Equivalent of java prototype:  public int ExampleMethod();
+java_method_exec("ExampleMethod", "V");
+
+# Equivalent of java prototype:  public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght);
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+...
+
+
+4.2.  java_s_method_exec(method, method_signature, [param1[, param2]])
+
+   Executes a java synchronized method “method”. Parameter “method_signature” is required (see 4.0).
+   See a more info about to synchronization: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
+
+   Example 2.2. java_s_method_exec usage
+...
+# Equivalent of java prototype:  public synchronized int ExampleMethod();
+java_s_method_exec("ExampleMethod", "V");
+
+# Equivalent of java prototype:  public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght);
+java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+...
+
+
+4.3.  java_staticmethod_exec(method, method_signature, [param1[, param2]])
+
+   Executes a java static method “method”. Parameter “method_signature” is required (see 4.0).
+
+   Example 2.3. java_staticmethod_exec usage
+...
+# Equivalent of java prototype:  public static int ExampleMethod();
+java_staticmethod_exec("ExampleMethod", "V");
+
+# Equivalent of java prototype:  public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght);
+java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+...
+
+
+4.4.  java_s_staticmethod_exec(method, method_signature, [param1[, param2]])
+
+   Executes a java synchronized static method “method”. Parameter “method_signature” is required (see 4.0).
+   See a more info about to synchronization: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
+
+   Example 2.4. java_s_staticmethod_exec usage
+...
+# Equivalent of java prototype:  public static synchronized int ExampleMethod();
+java_s_staticmethod_exec("ExampleMethod", "V");
+
+# Equivalent of java prototype:  public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght);
+java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+...
+
+
+5. Java module API
+
+
+5.0. Minimal program skeleton and structure of package org.siprouter
+
+   5.0.1.  Minimal program skeleton
+
+...
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class Kamailio extends NativeMethods
+{
+	/* Here you should specify a full path to app_java.so */
+        static
+        {
+            System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+        }
+
+        /* Constructor. Do not remove !!! */
+        public Kamailio()
+        {
+        }
+
+	/*
+	    This method should be executed for each children process, immediately after forking.
+	    Required. Do not remove !!!
+	*/
+        public int child_init(int rank)
+        {
+	    return 1;
+	}
+}
+...
+
+   5.0.2.  Structure of package org.siprouter
+
+            org.siprouter ---*---*--*-------> class NativeMethods
+                             |   |  +--> class IPPair
+                             |   +--> class SipMsg
+                             +--> interface NativeInterface
+                                        |
+                                        +--> class Ranks
+                                        +--> class LogParams
+
+
+5.1. abstract class NativeMethods
+
+   5.1.1.   General logging
+
+	5.1.1.0.   Log levels and facilities
+
+		   Log levels:
+			L_ALERT		= -5
+			L_BUG		= -4
+			L_CRIT2		= -3
+			L_CRIT		= -2
+			L_ERR		= -1
+			L_WARN		= 0
+			L_NOTICE	= 1
+			L_INFO		= 2
+			L_DBG		= 3
+
+		   Log facilities (see man syslog(3)):
+			DEFAULT_FACILITY	= 0  (LOG_KERN (Linux))
+
+		   1. Example of usage log levels and facilities:
+		     LM_GEN1(LogParams.L_BUG, "Hello World!\n");
+		     produces (example of output):
+		      0(3003) BUG: app_java [java_native_methods.c:255]: Hello World!
+
+		   2. Example of usage log levels and facilities:
+		     LM_GEN2(LogParams.DEFAULT_FACILITY, LogParams.L_WARN, "Hello World!\n");
+		     produces (example of output):
+		      2(3147) WARNING: app_java [java_native_methods.c:279]: Hello World!
+
+
+	5.1.1.1.   native void LM_GEN1(int logLevel, String s);
+	5.1.1.2.   native void LM_GEN2(int logFacility, int logLevel, String s);
+	5.1.1.3.   native void LM_ALERT(String s);
+        5.1.1.4.   native void LM_CRIT(String s);
+        5.1.1.5.   native void LM_WARN(String s);
+        5.1.1.6.   native void LM_NOTICE(String s);
+        5.1.1.7.   native void LM_ERR(String s);
+        5.1.1.8.   native void LM_INFO(String s);
+        5.1.1.9.   native void LM_DBG(String s);
+
+   5.1.2.   Execution of kamailio commands
+
+	5.1.2.1.   static native int KamExec(String fname, String... params);
+
+		   Executes a kamailio command.
+
+		   Parameter 'fname'  - Required. Kamailio function name.
+		   Parameter 'params' - An array of string parameters. Note, this method allows up to 6 params,
+					it will ignore all parameters if more than 6.
+
+		   Returns:
+			     1 - command was successfully executed.
+			    -1 - execution of command was failed.
+
+        5.1.2.2.   static native int SetURI(String ruri);
+
+		   Rewrites the request URI.
+
+		   Returns:
+			    1 - Ok
+			   -1 - Failed
+
+		   Online reference: http://www.kamailio.org/wiki/cookbooks/3.3.x/core#rewriteuri
+
+        5.1.2.3.   static native int RewriteURI(String ruri);
+
+		   Rewrites the request URI.
+		   Alias method: SetURI
+
+		   Returns:
+			    1 - Ok
+			   -1 - Failed
+
+		   Online reference: http://www.kamailio.org/wiki/cookbooks/3.3.x/core#rewriteuri
+
+
+
+5.2.   class IPPair.
+
+   Represents an IP-address pair (IP, Port)
+
+   5.2.1.   final String ip;
+
+	    IP Address
+
+   5.2.2.   final int port;
+
+	    Port
+
+
+5.3. abstract class SipMsg
+
+   5.3.0.   Internal structure understanding.
+
+	    The class SipMsg is partially incapsulating kamailio's struct sip_msg.
+	    References: parser/msg_parser.h, parser/parse_fline.h
+
+   5.3.1.   int id;
+
+	    Message id, unique/process
+
+   5.3.2.   int pid;
+
+	    Process ID
+
+   5.3.3.   String eoh;
+
+	    Pointer to the end of header (if found) or null
+
+   5.3.4.   String unparsed;
+
+	    Here we stopped parsing
+
+   5.3.5.   String buf;
+
+	    Scratch pad, holds a modified message, via, etc. point into it.
+
+   5.3.6.   int len;
+
+	    Message len (orig)
+
+   5.3.7.   String new_uri;
+
+	    Changed first line uri, when you change this
+
+   5.3.8.   String dst_uri;
+
+	    Destination URI, must be forwarded to this URI if dst_url lenght != 0
+
+   5.3.9.   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)
+
+   5.3.10.  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)
+
+   5.3.11.  String add_to_branch_s;
+
+	    Whatever whoever want to append to branch comes here
+
+   5.3.12.  int add_to_branch_len;
+
+	    Lenght of add_to_branch_s
+
+   5.3.13.  int hash_index;
+
+	    Index to TM hash table; stored in core to avoid unnecessary calculations
+
+   5.3.14.  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 reache.
+
+   5.3.15.  static native SipMsg ParseSipMsg();
+
+	    This method is using to get an instance of class SipMsg and populate a properties
+	    of this class with a fields specified at 5.3.1 - 5.3.14.
+
+   5.3.16.  static native String getMsgType();
+
+	    Gets a message type. Return value:
+		'SIP_REQUEST' - if message is request
+		'SIP_REPLY'   - if message is reply
+		'SIP_INVALID' - if invalid message
+
+   5.3.17.  static native String getRURI();
+
+	    Gets a request URI (RURI).
+
+   5.3.18.  static native IPPair getSrcAddress();
+
+	    Gets a source IP address and port.
+
+   5.3.19.  static native IPPair getDstAddress();
+
+	    Gets a destination IP address and port.
+
+   5.3.20.  static native String getBuffer();
+
+	    Gets a message buffer.
+
+
+5.4. interface NativeInterface
+
+   5.4.1.   abstract class Ranks
+
+	5.4.1.1.  static final int PROC_MAIN
+
+		  Main ser process
+
+        5.4.1.2.  static final int PROC_TIMER
+
+		  Timer attendant process
+
+        5.4.1.3.  static final int PROC_RPC
+
+		  RPC type process
+
+        5.4.1.4.  static final int PROC_FIFO
+
+		  FIFO attendant process.
+		  Alias to PROC_RPC.
+
+        5.4.1.5.  static final int PROC_TCP_MAIN
+
+		  TCP main process
+
+        5.4.1.6.  static final int PROC_UNIXSOCK
+
+		  Unix socket server
+
+        5.4.1.7.  static final int PROC_ATTENDANT
+
+		  Main "attendant process
+
+        5.4.1.8.  static final int PROC_INIT
+
+		  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, 
+		  both in PROC_MAIN and PROC_INT
+
+        5.4.1.9.  static final int PROC_NOCHLDINIT
+
+		  no child init functions will be called if this rank is used in fork_process()
+
+        5.4.1.10. static final int PROC_SIPINIT
+
+		  First SIP worker - some modules do special processing in this child, 
+		  like loading db data
+
+        5.4.1.11. static final int PROC_SIPRPC
+
+		  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
+
+        5.4.1.12. static final int PROC_MIN
+
+		  Minimum process rank.
+		  Alias to PROC_NOCHLDINIT.
+
+   5.4.2.   abstract class LogParams
+	5.4.2.0.  Loggigng params
+        5.4.2.1.  static final int L_ALERT
+        5.4.2.2.  static final int L_BUG
+        5.4.2.3.  static final int L_CRIT2
+        5.4.2.4.  static final int L_CRIT
+        5.4.2.5.  static final int L_ERR
+        5.4.2.6.  static final int L_WARN
+        5.4.2.7.  static final int L_NOTICE
+        5.4.2.8.  static final int L_INFO
+        5.4.2.9.  static final int L_DBG
+        5.4.2.10. static final int DEFAULT_FACILITY
+
+
+5.5. Examples of usage Java API
+
+...
+
+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;
+	}
+}
+
+...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 4 - 0
modules/app_java/doc/Makefile

@@ -0,0 +1,4 @@
+docs = app_java.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 35 - 0
modules/app_java/doc/app_java.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding='utf-8'?>
+
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+	"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>app_java Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+	    <author>
+			<firstname>Konstantin</firstname>
+			<surname>Mosesov</surname>
+	    </author>
+	    <editor>
+	    	<firstname>Konstantin</firstname>
+	    	<surname>Mosesov</surname>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2013</year>
+		<holder>Konstantin Mosesov</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+	<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="app_java_admin.xml"/>
+    
+</book>

+ 648 - 0
modules/app_java/doc/app_java_admin.xml

@@ -0,0 +1,648 @@
+<?xml version="1.0" encoding='utf-8'?>
+
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" 
+	"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- Module User's Guide -->
+
+<chapter>
+    
+    <title>&adminguide;</title>
+    
+    <!-- Section Overview -->
+    <section>
+		<title>Overview</title>
+		<para>
+			This module allows executing Java compiled classes from config file, exporting
+			functions to access the SIP message from Java using Java Native Interface (JNI).
+		</para>
+    </section>
+	<!-- end op section Overview -->
+	
+	<!-- Section Dependencies -->
+    <section>
+		<title>Dependencies</title>
+    	<!-- Section Modules -->
+		<section>
+		    <title>&kamailio; Modules</title>
+		    <para>
+			The following modules must be loaded before this module:
+		    	<itemizedlist>
+			    <listitem>
+				<para>
+				    <emphasis>none</emphasis>.
+				</para>
+			    </listitem>
+		    	</itemizedlist>
+		    </para>
+		</section>
+    	<!-- End of section Modules -->
+    	
+    	<!-- Section External Libraries or Applications -->
+		<section>
+		    <title>External Libraries or Applications</title>
+		    <para>
+<!--
+			The following libraries or applications must be installed before running
+			&kamailio; with this module loaded:
+-->			
+		    	<itemizedlist>
+		    		<para><emphasis>The following packages are runtime libraries, required to launch</emphasis></para>
+		    		<listitem override="disc"><para><emphasis>java-common</emphasis> Base of all Java packages.</para></listitem>
+		    		<listitem override="disc"><para><emphasis>default-jre</emphasis> Standard Java or Java compatible Runtime.</para></listitem>
+		    		<listitem override="disc"><para><emphasis>gcj-jre</emphasis> Java runtime environment using GIJ/classpath.</para></listitem>
+		    		<listitem override="disc"><para><emphasis>libgcj12 (>=12)</emphasis> Java runtime library for use with gcj.</para></listitem>
+		    	</itemizedlist>
+		    	<itemizedlist>
+		    		<para><emphasis>The following packages are optional, required for development</emphasis></para>
+		    		<listitem override="box"><para><emphasis>ant</emphasis> Java based build tool like make.</para></listitem>
+		    		<listitem override="box"><para><emphasis>ant-contrib</emphasis> Collection of tasks, types and other tools for Apache Ant.</para></listitem>
+		    		<listitem override="box"><para><emphasis>ant-gcj</emphasis> Java based build tool like make (GCJ).</para></listitem>
+		    		<listitem override="box"><para><emphasis>default-jdk</emphasis> Standard Java or Java compatible Development Kit</para></listitem>
+		    		<listitem override="box"><para><emphasis>gcj-jdk</emphasis> gcj and classpath development tools for Java(TM)</para></listitem>
+		    		<listitem override="box"><para><emphasis>libgcj13-dev (>=12)</emphasis> Java development headers for use with gcj</para></listitem>
+		    		<listitem override="box"><para><emphasis>jdk</emphasis> JDK Development Kit (either oracle jdk or openjdk)</para></listitem>
+		    	</itemizedlist>
+		    </para>
+			<para>
+				The following libraries or applications must be compiled before
+				running &kamailio; with this module loaded:
+				<itemizedlist>
+					<para><emphasis>The following packages are runtime libraries, required to launch</emphasis></para>
+					<listitem override="circle"><para><emphasis>&lt;class_name&gt;</emphasis>.class</para></listitem>
+					<listitem override="circle"><para><emphasis>&kamailiobinary;</emphasis>.jar</para></listitem>
+				</itemizedlist>
+			</para>
+		</section>
+    	<!-- end of section External Libraries or Applications -->
+    </section>
+	<!-- end of section Dependencies -->
+	
+	<!-- Section Java Runtime -->
+	<section>
+		<title>Java runtime</title>
+		<section>
+			<title/>
+			<para>Java runtime library (JRE or JDK) is required to use this module.</para>
+		</section>
+	</section>
+	<!-- end of section Java Runtime -->
+	
+	<!-- Section Parameters -->
+	<section>
+		<title>Parameters</title>
+
+		<!-- class_name -->
+		<section>
+			<title><varname>class_name</varname> (string)</title>
+		    <para>
+		    	The class name should have the same compiled file name.
+		    	If the value is <emphasis>"&kamailio;"</emphasis>, then the compiled file should be named as <emphasis>"&kamailio;.class"</emphasis>.
+		    </para>
+		    <para>
+				<emphasis>
+					Default value is <quote>&kamailio;</quote>.
+				</emphasis>
+		    </para>
+		    <example>
+		    	<title>Set <varname>class_name</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("app_java", "class_name", "&kamailio;")
+...
+</programlisting>
+		    </example>
+		</section>
+
+		<!-- child_init_method -->
+		<section>
+			<title><varname>child_init_method</varname> (string)</title>
+			<para>
+				TBD.
+			</para>
+			<para>
+				<emphasis>
+					Default value is <quote>child_init</quote>.
+				</emphasis>
+			</para>
+			<example>
+				<title>Set <varname>child_init_method</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("app_java", "child_init_method", "my_mod_init")
+...
+</programlisting>
+			</example>
+		</section>
+
+		<!-- java_options -->
+		<section>
+			<title><varname>java_options</varname> (string)</title>
+			<para>
+				Java options for Java Virtual Machine.
+				For more info read <ulink url="http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html"><citetitle>java docs</citetitle></ulink>
+			</para>
+			<para>
+				<emphasis>
+					Default value is <quote>-Djava.compiler=NONE</quote>.
+				</emphasis>
+			</para>
+			<example>
+				<title>Set <varname>java_options</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("app_java", "java_options", "-Djava.compiler=NONE")
+...
+</programlisting>
+			</example>
+			<example>
+				<title>Set <varname>java_options</varname> parameter (live configuration)</title>
+				<programlisting format="linespecific">
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+...
+</programlisting>
+			</example>
+			<example>
+				<title>Set <varname>java_options</varname> parameter (verbose configuration)</title>
+				<programlisting format="linespecific">
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+...
+</programlisting>
+			</example>
+			<example>
+				<title>Set <varname>java_options</varname> parameter (debug configuration)</title>
+				<programlisting format="linespecific">
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+...
+</programlisting>
+			</example>
+		</section>
+
+		<!-- force_cmd_exec -->
+		<section>
+			<title><varname>force_cmd_exec</varname> (int)</title>
+			<para>
+				This parameter forces execution a &kamailiobinary; comnmand with java native method <quote>KamExec</quote>.
+				# Note: this is an untested yet feature, may cause (but may not) a memory leaks if used from embedded languages.
+			</para>
+			<para>
+				<emphasis>
+					Default value is <quote>0 (off)</quote>.
+				</emphasis>
+			</para>
+			<example>
+				<title>Set <varname>force_cmd_exec</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("app_java", "force_cmd_exec", 1)
+...
+</programlisting>
+			</example>
+		</section>
+	</section>
+	<!-- End of section Parameters -->
+	
+	<!-- Section Functions -->
+    <section>
+		<title>Functions</title>
+    	
+    	<!-- Section Common requirements -->
+    	<section>
+    		<title>
+    			Common requirements
+    		</title>
+    		<para>Each function has a required parameter <quote>method_signature</quote>. For more info
+				see <ulink url="http://www.rgagnon.com/javadetails/java-0286.html"
+						><citetitle>Determine the signature of a method</citetitle></ulink>.
+				Signature represents the variable type. The mapping between the Java type and C type
+				is
+				<programlisting format="linespecific">
+		Type     Chararacter 
+		boolean      Z 
+		byte         B 
+		char         C 
+		double       D 
+		float        F 
+		int          I 
+		long         J 
+		object       L 
+		short        S 
+		void         V 
+		Note that to specify an object, the "L" is followed by the object's class name and ends with a semi-colon, ';' .
+    			</programlisting>
+			</para>
+    		<para> app_java supports the following signatures:
+				<programlisting format="linespecific">
+		Primitives: Z,B,C,D,F,I,J,L,S,V
+		Objects: 
+			Ljava/lang/Boolean;
+			Ljava/lang/Byte;
+			Ljava/lang/Character;
+			Ljava/lang/Double;
+			Ljava/lang/Float;
+			Ljava/lang/Integer;
+			Ljava/lang/Long;
+			Ljava/lang/Short;
+			Ljava/lang/String;
+			NULL parameter: V
+
+	Each parameter passed to function will be cast according to given signature.
+	
+	Parameters are optional, ommitting a parameter meant the passed value is NULL.
+	Parameters count should be exactly the same as signature count.
+	Note 1: Arrays representation (symbol '[') is not supported yet.
+	Note 2: You shall use a correct signature, e.g. the following examples of combinations are invalid:    
+    	java_method_exec("ExampleMethod", "ZI", "False");
+        java_method_exec("ExampleMethod", "LI", "something", "5");
+</programlisting>
+			</para>
+
+ 
+    	</section>
+    	<!-- End of section Common Requirements -->
+  
+    	<!-- Section java_method_exec -->
+    	<section>
+    		<title>java_method_exec(method, method_signature, [param1[, param2[, ...]]])</title>
+    		<para>Executes a java class method <emphasis>method</emphasis>. Parameter <emphasis>method_signature</emphasis> is required.</para>
+    		<itemizedlist>
+	    		<listitem>
+			    	<example>
+						<title>Signature: "V"</title>
+			    		<para>&kamailio; prototype</para>
+			    		<programlisting format="linespecific">java_method_exec("ExampleMethod", "V");</programlisting>
+			    		<para>Java prototype</para>
+			    		<programlisting format="linespecific">public int ExampleMethod();</programlisting>
+			    		<para>Example of usage:</para>
+			    		<programlisting format="linespecific">
+# &kamailio;
+java_method_exec("ExampleMethod", "V");
+
+# Java
+public int ExampleMethod()
+{
+		... do something;
+		return 1;
+}
+</programlisting>
+			    	</example>
+	    		</listitem>
+    			
+	    		<listitem>
+	    			<example>
+	    				<title>Signature: "Ljava/lang/String;I"</title>
+	    				<para>&kamailio; prototype</para>
+		    			<programlisting format="linespecific">java_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");</programlisting>
+	    				<para>Java prototype</para>
+	    				<programlisting format="linespecific">public int ExampleMethod(String param1, int param2);</programlisting>
+	    				<para>In the above scenario parameter 2 ("5") will be cast to integer representation.</para>
+	    				<para>Example of usage:</para>
+	    				<programlisting format="linespecific">
+# &kamailio;
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+		... do something with buffer;
+		return 1;
+}
+</programlisting>
+	    			</example>
+	    		</listitem>
+
+    			<listitem>
+    				<example>
+    					<title>Signature: "ZB"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_method_exec("ExampleMethod", "ZB", "true", "0x05");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public int ExampleMethod(boolean param1, byte param2);</programlisting>
+    					<para>In the above scenario parameter 1 ("true") will be cast to boolean representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_method_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public int ExampleMethod(boolean flagSet, byte bFlag);
+{
+		if (flagSet)
+		{
+			... do something with flags;
+		}
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+
+    		</itemizedlist>
+    	</section>
+    	<!-- end of section java_method_exec -->
+
+    	<!-- Section java_staticmethod_method_exec -->
+    	<section>
+    		<title>java_staticmethod_exec(method, method_signature, [param1[, param2[, ...]]])</title>
+    		<para>Executes a java static method <emphasis>method</emphasis>. Parameter <emphasis>method_signature</emphasis> is required.</para>
+    		<itemizedlist>
+    			<listitem>
+    				<example>
+    					<title>Signature: "V"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_staticmethod_exec("ExampleMethod", "V");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static int ExampleMethod();</programlisting>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_staticmethod_exec("ExampleMethod", "V");
+
+# Java
+public static int ExampleMethod()
+{
+		... do something;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "Ljava/lang/String;I"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static int ExampleMethod(String param1, int param2);</programlisting>
+    					<para>In the above scenario parameter 2 ("5") will be cast to integer representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+		... do something with buffer;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "ZB"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static int ExampleMethod(boolean param1, byte param2);</programlisting>
+    					<para>In the above scenario parameter 1 ("true") will be cast to boolean representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public static int ExampleMethod(boolean flagSet, byte bFlag);
+{
+		if (flagSet)
+		{
+			... do something with flags;
+		}
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    		</itemizedlist>
+    	</section>
+    	<!-- end of section java_staticmethod_exec -->
+    	
+    	<!-- Section java_s_method_exec -->
+    	<section>
+    		<title>java_s_method_exec(method, method_signature, [param1[, param2[, ...]]])</title>
+    		<para>Executes a java class synchronized method <emphasis>method</emphasis>. Parameter <emphasis>method_signature</emphasis> is required.</para>
+    		<para>For more info see <ulink url="http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html"><citetitle>Synchronized Methods</citetitle></ulink></para>
+    		<itemizedlist>
+    			<listitem>
+    				<example>
+    					<title>Signature: "V"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_method_exec("ExampleMethod", "V");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public synchronized int ExampleMethod();</programlisting>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_method_exec("ExampleMethod", "V");
+
+# Java
+public synchronized int ExampleMethod()
+{
+		... do something;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "Ljava/lang/String;I"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public synchronized int ExampleMethod(String param1, int param2);</programlisting>
+    					<para>In the above scenario parameter 2 ("5") will be cast to integer representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+		... do something with buffer;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "ZB"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public synchronized int ExampleMethod(boolean param1, byte param2);</programlisting>
+    					<para>In the above scenario parameter 1 ("true") will be cast to boolean representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public synchronized int ExampleMethod(boolean flagSet, byte bFlag);
+{
+		if (flagSet)
+		{
+			... do something with flags;
+		}
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    		</itemizedlist>
+    	</section>
+    	<!-- end of section java_s_method_exec -->
+    	
+    	<!-- Section java_s_staticmethod_exec -->
+    	<section>
+    		<title>java_s_staticmethod_exec(method, method_signature, [param1[, param2[, ...]]])</title>
+    		<para>Executes a java synchronized static method <emphasis>method</emphasis>. Parameter <emphasis>method_signature</emphasis> is required.</para>
+    		<para>For more info see <ulink url="http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html"><citetitle>Synchronized Methods</citetitle></ulink></para>
+    		<itemizedlist>
+    			<listitem>
+    				<example>
+    					<title>Signature: "V"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_staticmethod_exec("ExampleMethod", "V");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static synchronized int ExampleMethod();</programlisting>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_staticmethod_exec("ExampleMethod", "V");
+
+# Java
+public static synchronized int ExampleMethod()
+{
+		... do something;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "Ljava/lang/String;I"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static synchronized int ExampleMethod(String param1, int param2);</programlisting>
+    					<para>In the above scenario parameter 2 ("5") will be cast to integer representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+		... do something with buffer;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "ZB"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static synchronized int ExampleMethod(boolean param1, byte param2);</programlisting>
+    					<para>In the above scenario parameter 1 ("true") will be cast to boolean representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public static synchronized int ExampleMethod(boolean flagSet, byte bFlag);
+{
+		if (flagSet)
+		{
+			... do something with flags;
+		}
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    		</itemizedlist>
+    	</section>
+    	<!-- end of section java_s_method_exec -->
+
+    </section>
+	<!-- End of section Functions -->
+	
+	<!-- Section Java API-->
+    <section>
+		<title>Java Module API</title>
+    	<para></para>
+    	
+    	<!-- Section Minimal program skeleton -->
+    	<section>
+    		<title>Minimal program skeleton</title>
+    		<para></para>
+    		<example>
+    			<title>Minimal program skeleton</title>
+    			<para></para>
+    			<programlisting format="linespecific">
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class Kamailio extends NativeMethods
+{
+		/* Here you should specify a full path to app_java.so */
+		static
+		{
+				System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+		}
+
+		/* Constructor. Do not remove !!! */
+		public Kamailio()
+		{
+		}
+
+		/*
+		This method should be executed for each children process, immediately after forking.
+		Required. Do not remove !!!
+		*/
+		public int child_init(int rank)
+		{
+				return 1;
+		}
+}
+</programlisting>
+    		</example>
+    	</section>
+    	<!-- End of section Minimal program skeleton -->
+    	
+    </section>
+	<!-- End of section Java API -->
+	
+</chapter>
+

+ 5 - 5
modules/app_java/java_mod.c

@@ -54,7 +54,7 @@ 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 },
+    {"force_cmd_exec", INT_PARAM, &force_cmd_exec },
     {0,0,0}
 };
 
@@ -101,15 +101,15 @@ static int mod_init(void)
     char **opts;
     int nOptions;
 
-    if (force_kam_cmd_exec < 0 || force_kam_cmd_exec > 1)
+    if (force_cmd_exec < 0 || force_cmd_exec > 1)
     {
-	LM_ERR("Parameter force_kam_cmd_exec should be either 0 or 1\n");
+	LM_ERR("Parameter force_cmd_exec should be either 0 or 1\n");
 	return -1;
     }
 
-    if (force_kam_cmd_exec)
+    if (force_cmd_exec)
     {
-	LM_NOTICE("app_java: Parameter force_kam_cmd_exec may cause a memory leaks if used from embedded languages\n");
+	LM_NOTICE("app_java: Parameter force_cmd_exec may cause a memory leaks if used from embedded languages\n");
     }
 
     options = (JavaVMOption *)pkg_malloc(sizeof(JavaVMOption));

+ 1 - 1
modules/app_java/java_mod.h

@@ -25,6 +25,6 @@
 #ifndef __JAVA_MOD_H__
 #define	__JAVA_MOD_H__
 
-int force_kam_cmd_exec;
+int force_cmd_exec;
 
 #endif

+ 1 - 1
modules/app_java/java_native_methods.c

@@ -374,7 +374,7 @@ int KamExec(JNIEnv *jenv, char *fname, int argc, char **argv)
     }
 
     /* check fixups */
-    if (force_kam_cmd_exec == 0 && fexport->fixup != NULL && fexport->free_fixup == NULL)
+    if (force_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;

+ 13 - 0
modules/app_java/java_support.c

@@ -175,6 +175,19 @@ void handle_exception(void)
 
 }
 
+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);
+}
 
 void handle_VM_init_failure(int res)
 {

+ 1 - 0
modules/app_java/java_support.h

@@ -31,6 +31,7 @@
 #include <jni.h>
 
 void handle_exception(void);
+void ThrowNewException(JNIEnv *, char *, ...);
 void handle_VM_init_failure(int res);
 
 

二进制
modules/app_java/kamailio_java_folder/java-untested/Kamailio.class


二进制
modules/app_java/kamailio_java_folder/java-untested/kamailio.jar


二进制
modules/app_java/kamailio_java_folder/java/Kamailio.class


二进制
modules/app_java/kamailio_java_folder/java/kamailio.jar


+ 0 - 48
modules/app_java/utils.c

@@ -87,51 +87,3 @@ char **split(char *str, char *sep)
     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 *);
-}
-
-

+ 0 - 5
modules/app_java/utils.h

@@ -29,11 +29,6 @@
 
 #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

+ 5 - 28
modules/outbound/README

@@ -4,7 +4,7 @@ Peter Dunkley
 
    Crocodile RCS Ltd
 
-   Copyright © 2012 Crocodile RCS Ltd
+   Copyright © 2012 Crocodile RCS Ltd
      __________________________________________________________________
 
    Table of Contents
@@ -24,7 +24,6 @@ Peter Dunkley
         3. Parameters
 
               3.1. force_outbound_flag (integer)
-              3.2. flow_token_key (string)
 
         4. Functions
         5. MI Commands
@@ -35,7 +34,6 @@ Peter Dunkley
    1.2. Edge Proxy Configuration
    1.3. Registrar Configuration
    1.4. Set force_outbound_flag parameter
-   1.5. Set flow_token_key parameter
 
 Chapter 1. Admin Guide
 
@@ -54,7 +52,6 @@ Chapter 1. Admin Guide
    3. Parameters
 
         3.1. force_outbound_flag (integer)
-        3.2. flow_token_key (string)
 
    4. Functions
    5. MI Commands
@@ -87,9 +84,9 @@ make all
    responses to REGISTERs.
 
    When using TCP or TLS as the SIP transport care should be taken to set
-   the "tcp_connection_lifetime" on the Edge Proxy to a value slightly
+   the “tcp_connection_lifetime� on the Edge Proxy to a value slightly
    larger than the interval the Registrar is using for flow timer. Setting
-   "tcp_connection_lifetime" to less than the interval could cause
+   “tcp_connection_lifetime� to less than the interval could cause
    connections to be lost, and setting it to a value much larger than the
    interval will keep connections open far longer than is required (which
    is wasteful).
@@ -97,9 +94,9 @@ make all
    Application-layer keep-alives are optional when the underlying
    transport already has a keep-alive mechanism. The WebSocket transport
    has a transport-layer keep-alive. When using the WebSocket transport
-   the "keepalive_timeout" should be set to a value a little greater than
+   the “keepalive_timeout� should be set to a value a little greater than
    the Registrar flow timer interval and a little less than the
-   "tcp_connection_lifetime".
+   “tcp_connection_lifetime�.
 
    Example 1.2. Edge Proxy Configuration
 ...
@@ -114,8 +111,6 @@ loadmodule "path.so"
 ...
 modparam("websocket", "keepalive_timeout", FLOW_TIMER+5)
 ...
-modparam("outbound", "flow_token_key", "!!!Kamailio rocks!!!")
-...
 route {
         route(REQINIT);
         ...
@@ -284,7 +279,6 @@ failure_route[FAIL_OUTBOUND] {
 3. Parameters
 
    3.1. force_outbound_flag (integer)
-   3.2. flow_token_key (string)
 
 3.1. force_outbound_flag (integer)
 
@@ -299,23 +293,6 @@ failure_route[FAIL_OUTBOUND] {
 modparam("outbound", "force_outbound_flag", 1)
 ...
 
-3.2. flow_token_key (string)
-
-   The outbound flow token is generated using the algorithm described in
-   RFC 5626 section 5.2. This algorithm requires a 20 octet crypto random
-   key that is unique for each Edge Proxy.
-
-Note
-
-   If this 20 character string is not set Kamailio will not start.
-
-   Default value is: "".
-
-   Example 1.5. Set flow_token_key parameter
-...
-modparam("outbound", "flow_token_key", "!!!Kamailio rocks!!!")
-...
-
 4. Functions
 
    None

+ 0 - 21
modules/outbound/doc/outbound_admin.xml

@@ -69,8 +69,6 @@ loadmodule "path.so"
 ...
 modparam("websocket", "keepalive_timeout", FLOW_TIMER+5)
 ...
-modparam("outbound", "flow_token_key", "!!!Kamailio rocks!!!")
-...
 route {
 	route(REQINIT);
 	...
@@ -271,25 +269,6 @@ failure_route[FAIL_OUTBOUND] {
 ...
 modparam("outbound", "force_outbound_flag", 1)
 ...
-</programlisting>
-		</example>
-	</section>
-	<section>
-		<title><varname>flow_token_key</varname> (string)</title>
-		<para>The outbound flow token is generated using the algorithm
-		described in RFC 5626 section 5.2. This algorithm requires a 20
-		octet crypto random key that is unique for each Edge Proxy.
-		</para>
-		<note><para>If this 20 character string is not set &kamailio;
-		will not start.</para></note>
-		<para><emphasis>Default value is: "".</emphasis></para>
-		<example>
-		<title>Set <varname>flow_token_key</varname> parameter
-		</title>
-		<programlisting format="linespecific">
-...
-modparam("outbound", "flow_token_key", "!!!Kamailio rocks!!!")
-...
 </programlisting>
 		</example>
 	</section>

+ 24 - 10
modules/outbound/ob_mod.c

@@ -21,6 +21,7 @@
  *
  */
 #include <openssl/hmac.h>
+#include <openssl/rand.h>
 
 #include "../../basex.h"
 #include "../../dprint.h"
@@ -39,7 +40,10 @@
 
 MODULE_VERSION
 
+#define OB_KEY_LEN	20
+
 static int mod_init(void);
+static void destroy(void);
 
 static unsigned int ob_force_flag = (unsigned int) -1;
 static str ob_key = {0, 0};
@@ -55,7 +59,6 @@ static cmd_export_t cmds[]=
 static param_export_t params[]=
 {
 	{ "force_outbound_flag",	INT_PARAM, &ob_force_flag },
-	{ "flow_token_key",		STR_PARAM, &ob_key.s},
 	{ 0, 0, 0 }
 };
 
@@ -71,7 +74,7 @@ struct module_exports exports=
 	0,			/* extra processes */
 	mod_init,		/* module initialization function */
 	0,			/* response function */
-	0,			/* destroy function */
+	destroy,		/* destroy function */
 	0			/* per-child initialization function */
 };
 
@@ -83,24 +86,35 @@ static int mod_init(void)
 		return -1;
 	}
 
-	if (ob_key.s == 0)
+	if ((ob_key.s = shm_malloc(OB_KEY_LEN)) == NULL)
 	{
-		LM_ERR("flow_token_key not set\n");
+		LM_ERR("Failed to allocate memory for flow-token key\n");
 		return -1;
 	}
-	else
-		ob_key.len = strlen(ob_key.s);
+	ob_key.len = OB_KEY_LEN;
+	if (RAND_bytes((unsigned char *) ob_key.s, ob_key.len) == 0)
+	{
+		LM_ERR("unable to get %d cryptographically strong pseudo-"
+		       "random bytes\n", ob_key.len);
+	}
 
-	if (ob_key.len != 20)
+#ifndef USE_STUN
+	LM_WARN("STUN support not built-in. UDP keep-alive not supported.\n");
+#else
+	if (stun_allow_stun != 1)
 	{
-		LM_ERR("flow_token_key wrong length. Expected 20 got %d\n",
-			ob_key.len);
-		return -1;
+		LM_WARN("STUN disabled.  UDP keep-alive not supported.\n");
 	}
+#endif
 
 	return 0;
 }
 
+static void destroy(void)
+{
+	shm_free(ob_key.s);
+}
+
 /* Structure of flow-token
 
    <HMAC-SHA1-80><protocol><dst_ip><dst_port><src_ip><src_port>

+ 59 - 51
modules/sca/sca_call_info.c

@@ -589,7 +589,7 @@ sca_call_info_seize_held_call( sip_msg_t *msg, sca_call_info *call_info,
 	 * to watch for it. log our overwriting of it.
 	 */
 
-	LM_INFO( "SCA caller retrieving held call, but RURI was already "
+	LM_DBG( "SCA caller retrieving held call, but RURI was already "
 		 "rewritten as %.*s. Overwriting with %.*s.",
 		 STR_FMT( &msg->new_uri ), STR_FMT( &app->callee ));
 
@@ -700,29 +700,27 @@ sca_call_info_seize_held_call( sip_msg_t *msg, sca_call_info *call_info,
     sca_hash_table_unlock_index( sca->appearances, slot_idx );
     slot_idx = -1;
 
-    if ( !SCA_STR_EMPTY( &callee_aor )) {
-	if ( sca_uri_lock_if_shared_appearance( sca, &callee_aor, &slot_idx )) {
-	    app = sca_appearance_for_tags_unsafe( sca, &callee_aor,
-			&prev_callid, &prev_totag, NULL, slot_idx );
-	    if ( app == NULL ) {
-		LM_ERR( "sca_call_info_seize_held_call: failed to find "
-			"appearance of %.*s with dialog %.*s;%.*s",
-			STR_FMT( &callee_aor ), STR_FMT( &prev_callid ),
-			STR_FMT( &prev_totag ));
-		goto done;
-	    }
+    if ( sca_uri_lock_if_shared_appearance( sca, &callee_aor, &slot_idx )) {
+	app = sca_appearance_for_tags_unsafe( sca, &callee_aor,
+		    &prev_callid, &prev_totag, NULL, slot_idx );
+	if ( app == NULL ) {
+	    LM_ERR( "sca_call_info_seize_held_call: failed to find "
+		    "appearance of %.*s with dialog %.*s;%.*s",
+		    STR_FMT( &callee_aor ), STR_FMT( &prev_callid ),
+		    STR_FMT( &prev_totag ));
+	    goto done;
+	}
 
-	    app->flags |= SCA_APPEARANCE_FLAG_CALLEE_PENDING;
+	app->flags |= SCA_APPEARANCE_FLAG_CALLEE_PENDING;
 
-	    if ( sca_appearance_update_callee_unsafe( app, contact_uri ) < 0 ) {
-		LM_ERR( "sca_call_info_seize_held_call: failed to update callee" );
-		goto done;
-	    }
-	    if ( sca_appearance_update_dialog_unsafe( app, &msg->callid->body,
-					&to->tag_value, &from->tag_value ) < 0 ) {
-		LM_ERR( "sca_call_info_seize_held_call: failed to update dialog" );
-		goto done;
-	    }
+	if ( sca_appearance_update_callee_unsafe( app, contact_uri ) < 0 ) {
+	    LM_ERR( "sca_call_info_seize_held_call: failed to update callee" );
+	    goto done;
+	}
+	if ( sca_appearance_update_dialog_unsafe( app, &msg->callid->body,
+				    &to->tag_value, &from->tag_value ) < 0 ) {
+	    LM_ERR( "sca_call_info_seize_held_call: failed to update dialog" );
+	    goto done;
 	}
     }
 
@@ -842,7 +840,7 @@ sca_call_info_is_line_seize_reinvite( sip_msg_t *msg, sca_call_info *call_info,
      *		a Call-Info header is present
      */
 
-    if ( call_info == NULL ) {
+    if ( SCA_CALL_INFO_EMPTY( call_info )) {
 	return( 0 );
     }
     if ( !SCA_STR_EMPTY( &to->tag_value )) {
@@ -961,7 +959,7 @@ sca_call_info_invite_request_handler( sip_msg_t *msg, sca_call_info *call_info,
 	goto done;
     }
 
-    if ( call_info == NULL ) {
+    if ( !SCA_CALL_INFO_IS_SHARED_CALLER( call_info )) {
 	/* caller isn't SCA, no more to do. update callee in reply handler. */
 	rc = 1;
 	goto done;
@@ -979,7 +977,6 @@ sca_call_info_invite_request_handler( sip_msg_t *msg, sca_call_info *call_info,
 	goto done;
     }
     
-
     if ( sca_call_is_held( msg )) {
 	state = SCA_APPEARANCE_STATE_HELD;
 	if ( call_info->state == SCA_APPEARANCE_STATE_HELD_PRIVATE ) {
@@ -1204,13 +1201,12 @@ sca_call_info_invite_reply_200_handler( sip_msg_t *msg,
     int			slot_idx = -1;
     int			rc = -1;
 
-    if ( call_info != NULL ) {
-	/* this implies To-AoR is SCA */
+    if ( SCA_CALL_INFO_IS_SHARED_CALLEE( call_info )) {
 	rc = sca_call_info_uri_update( to_aor, call_info, from, to,
 			contact_uri, &msg->callid->body );
     }
 
-    if ( !sca_uri_is_shared_appearance( sca, from_aor )) {
+    if ( !SCA_CALL_INFO_IS_SHARED_CALLER( call_info )) {
 	goto done;
     }
 
@@ -1519,7 +1515,7 @@ sca_call_info_bye_handler( sip_msg_t *msg, sca_call_info *call_info,
     int			rc = -1;
 
     if ( msg->first_line.type == SIP_REQUEST ) {
-	if ( call_info != NULL ) {
+	if ( SCA_CALL_INFO_IS_SHARED_CALLER( call_info )) {
 	    slot_idx = sca_uri_lock_shared_appearance( sca, from_aor );
 	    if ( slot_idx < 0 ) {
 		LM_ERR( "sca_call_info_bye_handler: failed to acquire "
@@ -1528,13 +1524,26 @@ sca_call_info_bye_handler( sip_msg_t *msg, sca_call_info *call_info,
 		goto done;
 	    }
 
-	    app = sca_appearance_for_index_unsafe( sca, from_aor,
-			call_info->index, slot_idx );
-	    if ( app == NULL ) {
-		LM_ERR( "sca_call_info_bye_handler: %.*s "
-			"appearance-index %d is not active",
-			STR_FMT( from_aor ), call_info->index );
-		goto done;
+	    if ( call_info->index != SCA_CALL_INFO_APPEARANCE_INDEX_ANY ) {
+		app = sca_appearance_for_index_unsafe( sca, from_aor,
+			    call_info->index, slot_idx );
+		if ( app == NULL ) {
+		    LM_ERR( "sca_call_info_bye_handler: %.*s "
+			    "appearance-index %d is not active",
+			    STR_FMT( from_aor ), call_info->index );
+		    goto done;
+		}
+	    } else {
+		app = sca_appearance_for_tags_unsafe( sca, from_aor,
+			&msg->callid->body, &from->tag_value, NULL, slot_idx );
+		if ( app == NULL ) {
+		    LM_ERR( "sca_call_info_bye_handler: %.*s "
+			    "dialog leg %.*s;%.*s is not active",
+			    STR_FMT( from_aor ),
+			    STR_FMT( &msg->callid->body ),
+			    STR_FMT( &from->tag_value ));
+		    goto done;
+		}
 	    }
 
 	    if ( SCA_STR_EQ( &app->dialog.call_id, &msg->callid->body )) {
@@ -1600,7 +1609,7 @@ sca_call_info_bye_handler( sip_msg_t *msg, sca_call_info *call_info,
 	    }
 	}
     } else {
-	if ( call_info != NULL ) {
+	if ( SCA_CALL_INFO_IS_SHARED_CALLEE( call_info )) {
 	    slot_idx = sca_hash_table_index_for_key( sca->appearances, to_aor );
 	    sca_hash_table_lock_index( sca->appearances, slot_idx );
 
@@ -1664,7 +1673,7 @@ sca_call_info_cancel_handler( sip_msg_t *msg, sca_call_info *call_info,
      * find appearance by dialog if Call-Info not present.
      */
     /* XXX also handle CANCEL w/ Call-Info header? Some UAs might send it */
-    if ( sca_uri_is_shared_appearance( sca, from_aor )) {
+    if ( SCA_CALL_INFO_IS_SHARED_CALLER( call_info )) {
 	app = sca_appearance_unlink_by_tags( sca, from_aor,
 			&msg->callid->body, &from->tag_value, NULL );
 	if ( app ) {
@@ -1806,7 +1815,7 @@ struct sca_call_info_dispatch	call_info_dispatch[] = {
     int
 sca_call_info_update( sip_msg_t *msg, char *p1, char *p2 )
 {
-    sca_call_info	call_info, *call_info_p = NULL;
+    sca_call_info	call_info;
     hdr_field_t		*call_info_hdr;
     struct to_body	*from;
     struct to_body	*to;
@@ -1848,8 +1857,6 @@ sca_call_info_update( sip_msg_t *msg, char *p1, char *p2 )
 		    STR_FMT( &call_info_hdr->body ));
 	    return( -1 );
 	}
-
-	call_info_p = &call_info;
     }
 
     if ( sca_get_msg_from_header( msg, &from ) < 0 ) {
@@ -1925,18 +1932,19 @@ sca_call_info_update( sip_msg_t *msg, char *p1, char *p2 )
     }
 
     /* early check to see if we're dealing with any SCA endpoints */
-    if ( call_info_p == NULL ) {
-	/* no Call-Info header in packet, check if AoRs are SCA */
-
-	if ( !sca_uri_is_shared_appearance( sca, &from_aor ) &&
-		    !sca_uri_is_shared_appearance( sca, &to_aor )) {
-	    LM_DBG( "Neither %.*s nor %.*s are SCA AoRs",
-		    STR_FMT( &from_aor ), STR_FMT( &to_aor ));
-	    goto done;
-	}
+    if ( sca_uri_is_shared_appearance( sca, &from_aor )) {
+	call_info.ua_shared |= SCA_CALL_INFO_SHARED_CALLER;
+    }
+    if ( sca_uri_is_shared_appearance( sca, &to_aor )) {
+	call_info.ua_shared |= SCA_CALL_INFO_SHARED_CALLEE;
+    }
+    if ( call_info.ua_shared == SCA_CALL_INFO_SHARED_NONE ) {
+	LM_DBG( "Neither %.*s nor %.*s are SCA AoRs",
+		STR_FMT( &from_aor ), STR_FMT( &to_aor ));
+	goto done;
     }
 
-    rc = call_info_dispatch[ i ].handler( msg, call_info_p, from, to,
+    rc = call_info_dispatch[ i ].handler( msg, &call_info, from, to,
 					&from_aor, &to_aor, &contact_uri );
     if ( rc < 0 ) {
 	LM_ERR( "Failed to update Call-Info state for %.*s",

+ 22 - 0
modules/sca/sca_call_info.h

@@ -30,14 +30,36 @@
 /* pass to sca_notify_subscriber to include all appearances in Call-Info hdr */
 #define SCA_CALL_INFO_APPEARANCE_INDEX_ANY	0
 
+enum {
+    SCA_CALL_INFO_SHARED_NONE = 0,
+    SCA_CALL_INFO_SHARED_CALLER = (1 << 0),
+    SCA_CALL_INFO_SHARED_CALLEE = (1 << 1),
+};
+
 struct _sca_call_info {
     str		sca_uri;
     int		index;
     int		state;
     str		uri;
+
+    /* mask tracking which endpoints in a call are shared */
+    int		ua_shared;
 };
 typedef struct _sca_call_info		sca_call_info;
 
+#define SCA_CALL_INFO_EMPTY( ci1 ) \
+	(!(ci1) && ((ci1)->index == SCA_CALL_INFO_APPEARANCE_INDEX_ANY && \
+			(ci1)->state == SCA_APPEARANCE_STATE_UNKNOWN))
+
+#define SCA_CALL_INFO_IS_SHARED_CALLER( ci1 ) \
+	(!SCA_CALL_INFO_EMPTY((ci1)) && \
+	(((sca_call_info *)(ci1))->ua_shared & SCA_CALL_INFO_SHARED_CALLER))
+
+#define SCA_CALL_INFO_IS_SHARED_CALLEE( ci1 ) \
+	(!SCA_CALL_INFO_EMPTY((ci1)) && \
+	(((sca_call_info *)(ci1))->ua_shared & SCA_CALL_INFO_SHARED_CALLEE))
+
+
 extern const str	SCA_CALL_INFO_HEADER_STR;
 
 

+ 1 - 2
modules/sca/sca_common.h

@@ -93,8 +93,7 @@
 		memcmp((str1)->s, (str2)->s, (str1)->len) == 0)
 
 #define SCA_STR_EMPTY( str1 ) \
-	(((str1) != NULL && ((str1)->s == NULL || (str1)->len <= 0 )) \
-		|| (str1) == NULL )
+	((str1) == NULL || ((str1)->s == NULL || (str1)->len <= 0 ))
 
 #define SCA_HEADER_EMPTY( hdr1 ) \
 	((hdr1) == NULL || SCA_STR_EMPTY( &(hdr1)->body ))

+ 1 - 3
modules/sca/sca_rpc.c

@@ -366,9 +366,7 @@ sca_rpc_update_appearance( rpc_t *rpc, void *ctx )
 	return;
     }
     if ( rpc->scan( ctx, "*S", &app_uri ) == 1 ) {
-	if ( !SCA_STR_EMPTY( &app_uri )) {
-	    app_uri_p = &app_uri;
-	}
+	app_uri_p = &app_uri;
     }
 
     app_state = sca_appearance_state_from_str( &app_state_str );

+ 1 - 1
modules/sca/sca_subscribe.c

@@ -1017,7 +1017,7 @@ sca_subscription_from_request( sca_mod *scam, sip_msg_t *msg, int event_type,
     }
 
     to_tag = to->tag_value;
-    if ( SCA_STR_EMPTY( &to_tag )) {
+    if ( to_tag.s == NULL ) {
 	/*
 	 * XXX need hook to detect when we have a subscription and the
 	 * subscriber sends an out-of-dialog SUBSCRIBE, which indicates the