java_mod.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /**
  2. * $Id$
  3. *
  4. * Copyright (C) 2013 Konstantin Mosesov
  5. *
  6. * This file is part of Kamailio, a free SIP server.
  7. *
  8. * This file is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. *
  14. * This file is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22. *
  23. */
  24. #include <libgen.h>
  25. #include "../../str.h"
  26. #include "../../sr_module.h"
  27. #include <jni.h>
  28. #include "global.h"
  29. #include "utils.h"
  30. #include "java_mod.h"
  31. #include "java_iface.h"
  32. #include "java_support.h"
  33. #include "java_native_methods.h"
  34. MODULE_VERSION
  35. static str script_name = {.s = "/usr/local/etc/sip-router/handler.java", .len = 0};
  36. static str class_name = {.s = "Kamailio", .len = 10};
  37. static str child_init_mname = { .s = "child_init", .len = 0};
  38. static str java_pkg_tree_path_str = { .s = "pkg_tree_path", .len = 0};
  39. static str java_options_str = { .s = "java_options", .len = 0};
  40. static int mod_init(void);
  41. static int child_init(int rank);
  42. static void mod_destroy(void);
  43. char *dname = NULL, *bname = NULL;
  44. /** module parameters */
  45. static param_export_t params[]={
  46. {"script_name", STR_PARAM, &script_name },
  47. {"class_name", STR_PARAM, &class_name },
  48. {"pkg_tree_path", STR_PARAM, &java_pkg_tree_path_str },
  49. {"child_init_method", STR_PARAM, &child_init_mname },
  50. {"java_options", STR_PARAM, &java_options_str },
  51. {0,0,0}
  52. };
  53. /*
  54. * Exported functions
  55. */
  56. static cmd_export_t cmds[] = {
  57. { "java_exec", (cmd_function)java_exec, 1, NULL, 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
  58. { 0, 0, 0, 0, 0, 0 }
  59. };
  60. /** module exports */
  61. struct module_exports exports = {
  62. "app_java", /* module name */
  63. RTLD_NOW | RTLD_GLOBAL, /* dlopen flags */
  64. cmds, /* exported functions */
  65. params, /* exported parameters */
  66. 0, /* exported statistics */
  67. 0, /* exported MI functions */
  68. 0, /* exported pseudo-variables */
  69. 0, /* extra processes */
  70. mod_init, /* module initialization function */
  71. (response_function) NULL, /* response handling function */
  72. (destroy_function) mod_destroy, /* destroy function */
  73. child_init /* per-child init function */
  74. };
  75. static int mod_init(void)
  76. {
  77. JavaVMInitArgs vm_args;
  78. jint res;
  79. JavaVMOption *options;
  80. char **opts;
  81. int nOptions;
  82. char *class_object_name;
  83. size_t class_object_name_len;
  84. options = (JavaVMOption *)pkg_realloc(NULL, sizeof(JavaVMOption));
  85. if (!options)
  86. {
  87. LM_ERR("Couldn't initialize Java VM: not enough memory\n");
  88. return -1;
  89. }
  90. memset(options, 0, sizeof(JavaVMOption));
  91. LM_INFO("Initializing Java VM with options: %s\n", java_options_str.s);
  92. opts = split(java_options_str.s, " ");
  93. for (nOptions=0; opts[nOptions] != NULL; nOptions++)
  94. {
  95. options[nOptions].optionString = opts[nOptions];
  96. }
  97. /* IMPORTANT: specify vm_args version # if you use JDK1.1.2 and beyond */
  98. vm_args.version = JNI_VERSION_1_2;
  99. vm_args.nOptions = nOptions;
  100. vm_args.ignoreUnrecognized = JNI_FALSE;
  101. vm_args.options = options;
  102. res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
  103. if (res < 0)
  104. {
  105. handle_VM_init_failure(res);
  106. return -1;
  107. }
  108. LM_INFO("app_java: Java VM initialization OK\n");
  109. // attach to current thread
  110. (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
  111. if ((*env)->ExceptionCheck(env))
  112. {
  113. handle_exception();
  114. return -1;
  115. }
  116. // Loading main class
  117. if (java_pkg_tree_path_str.len <= 0)
  118. {
  119. class_object_name_len = strlen(JAVA_MODULE_PKG_PATH) + class_name.len + 1; // default package name plus class name plus package trailing slash
  120. }
  121. else
  122. {
  123. class_object_name_len = java_pkg_tree_path_str.len + class_name.len + 1; // package name plus class name plus package trailing slash
  124. }
  125. class_object_name = (char *)pkg_realloc(NULL, (class_object_name_len + 1) * sizeof(char));
  126. if (!class_object_name)
  127. {
  128. LM_ERR("pkg_realloc has failed. Not enough memory!\n");
  129. return -1;
  130. }
  131. memset(class_object_name, 0, (class_object_name_len + 1) * sizeof(char));
  132. if (java_pkg_tree_path_str.len <= 0)
  133. {
  134. snprintf(class_object_name, class_object_name_len, "%s%s", java_pkg_tree_path_str.s, class_name.s);
  135. }
  136. else
  137. {
  138. snprintf(class_object_name, class_object_name_len, "%s/%s", JAVA_MODULE_PKG_PATH, class_name.s);
  139. }
  140. // KamailioClass = (*env)->FindClass(env, class_name.s);
  141. KamailioClass = (*env)->FindClass(env, class_object_name);
  142. pkg_free(class_object_name);
  143. if (!KamailioClass || (*env)->ExceptionCheck(env))
  144. {
  145. handle_exception();
  146. if (jvm != NULL)
  147. (*jvm)->DetachCurrentThread(jvm);
  148. return -1;
  149. }
  150. KamailioID = (*env)->GetMethodID(env, KamailioClass, "<init>", "()V");
  151. if (!KamailioID || (*env)->ExceptionCheck(env))
  152. {
  153. handle_exception();
  154. if (jvm != NULL)
  155. (*jvm)->DetachCurrentThread(jvm);
  156. return -1;
  157. }
  158. // calling constructor
  159. KamailioClassInstance = (*env)->NewObject(env, KamailioClass, KamailioID);
  160. if (!KamailioClassInstance || (*env)->ExceptionCheck(env))
  161. {
  162. handle_exception();
  163. if (jvm != NULL)
  164. (*jvm)->DetachCurrentThread(jvm);
  165. return -1;
  166. }
  167. // keep a reference to kamailio class instance
  168. KamailioClassInstanceRef = (*env)->NewGlobalRef(env, KamailioClassInstance);
  169. if (!KamailioClassInstanceRef || (*env)->ExceptionCheck(env))
  170. {
  171. handle_exception();
  172. if (jvm != NULL)
  173. (*jvm)->DetachCurrentThread(jvm);
  174. return -1;
  175. }
  176. LM_INFO("app_java: initialization OK\n");
  177. if (jvm != NULL)
  178. (*jvm)->DetachCurrentThread(jvm);
  179. return 0;
  180. }
  181. static int child_init(int rank)
  182. {
  183. int retval;
  184. jmethodID child_init_id;
  185. // attach to current thread
  186. (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
  187. if ((*env)->ExceptionCheck(env))
  188. {
  189. handle_exception();
  190. return -1;
  191. }
  192. child_init_id = (*env)->GetMethodID(env, KamailioClass, "child_init", "(I)I");
  193. if ((*env)->ExceptionCheck(env))
  194. {
  195. handle_exception();
  196. if (jvm != NULL)
  197. (*jvm)->DetachCurrentThread(jvm);
  198. return -1;
  199. }
  200. retval = (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, child_init_id, rank);
  201. if ((*env)->ExceptionCheck(env))
  202. {
  203. handle_exception();
  204. if (jvm != NULL)
  205. (*jvm)->DetachCurrentThread(jvm);
  206. return -1;
  207. }
  208. (*env)->DeleteLocalRef(env, child_init_id);
  209. if (jvm != NULL)
  210. (*jvm)->DetachCurrentThread(jvm);
  211. return retval;
  212. }
  213. static void mod_destroy(void)
  214. {
  215. if (env != NULL)
  216. {
  217. if (KamailioClassInstanceRef != NULL)
  218. (*env)->DeleteGlobalRef(env, KamailioClassInstanceRef);
  219. }
  220. if (jvm != NULL)
  221. {
  222. (*jvm)->DetachCurrentThread(jvm);
  223. (*jvm)->DestroyJavaVM(jvm);
  224. }
  225. }