core, lib, modules: restructured source code tree
[sip-router] / src / modules / app_java / java_iface.c
1 /*
2  * Copyright (C) 2013 Konstantin Mosesov
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #include "../../str.h"
24 #include "../../sr_module.h"
25
26 #include <string.h>
27 #include <jni.h>
28
29 #include "global.h"
30 #include "java_iface.h"
31 #include "utils.h"
32 #include "app_java_mod.h"
33 #include "java_iface.h"
34 #include "java_support.h"
35 #include "java_native_methods.h"
36 #include "java_msgobj.h"
37 #include "java_sig_parser.h"
38
39 /*
40     example of java prototype: public int method_name();
41     example of kamailio invocation: java_method_exec("method_name", "V");
42 */
43 int j_nst_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
44 {
45     return java_exec(msgp, 0, 0, method_name, signature, NULL);
46 }
47 /*
48     example of java prototype: public int method_name(int param);
49     example of kamailio invocation: java_method_exec("method_name", "I", "5");
50 */
51 int j_nst_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
52 {
53     return java_exec(msgp, 0, 0, method_name, signature, param);
54 }
55 /*
56     example of java prototype: public synchronized int method_name();
57     example of kamailio invocation: java_s_method_exec("method_name", "V");
58 */
59 int j_s_nst_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
60 {
61     return java_exec(msgp, 0, 1, method_name, signature, NULL);
62 }
63 /*
64     example of java prototype: public synchronized int method_name(int param);
65     example of kamailio invocation: java_s_method_exec("method_name", "I", "5");
66 */
67 int j_s_nst_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
68 {
69     return java_exec(msgp, 0, 1, method_name, signature, param);
70 }
71
72
73 /*
74     example of java prototype: public static int method_name();
75     example of kamailio invocation: java_staticmethod_exec("method_name", "V");
76 */
77 int j_st_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
78 {
79     return java_exec(msgp, 1, 0, method_name, signature, NULL);
80 }
81 /*
82     example of java prototype: public static int method_name(int param);
83     example of kamailio invocation: java_staticmethod_exec("method_name", "I", "5");
84 */
85 int j_st_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
86 {
87     return java_exec(msgp, 1, 0, method_name, signature, param);
88 }
89 /*
90     example of java prototype: public static synchronized int method_name();
91     example of kamailio invocation: java_s_staticmethod_exec("method_name", "V");
92 */
93 int j_s_st_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
94 {
95     return java_exec(msgp, 1, 1, method_name, signature, NULL);
96 }
97 /*
98     example of java prototype: public static synchronized int method_name(int param);
99     example of kamailio invocation: java_s_staticmethod_exec("method_name", "I", "5");
100 */
101 int j_s_st_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
102 {
103     return java_exec(msgp, 1, 1, method_name, signature, param);
104 }
105
106
107 int java_exec(struct sip_msg *msgp, int is_static, int is_synchronized, char *method_name, char *signature, char *param)
108 {
109     char *retval_sig;
110     char *cs;
111     size_t cslen;
112     jint retval;
113     int locked;
114     jfieldID fid;
115     jclass cls;
116     jmethodID invk_method, invk_method_ref;
117     jvalue *jparam;
118
119     if (signature == NULL || !strcmp(signature, ""))
120     {
121         LM_ERR("%s: java_method_exec(): signature is empty or invalid.\n", APP_NAME);
122         return -1;
123     }
124
125     if (param == NULL && strcmp(signature, "V"))
126     {
127         LM_ERR("%s: java_method_exec(): no parameter (parameter is NULL) but signature '%s' is not equals to 'V'.\n", APP_NAME, signature);
128         return -1;
129     }
130
131     if (is_sig_allowed(signature) == 0)
132     {
133         LM_ERR("%s: java_method_exec(): error: signature '%s' isn't supported yet.\n", APP_NAME, signature);
134         return -1;
135     }
136
137     if (!strcmp(signature, "V"))
138     {
139         signature = "";
140     }
141
142     retval_sig = "I";
143
144     cslen = strlen(signature) + 2 + 1 + 1;      // '(' + 'signature' + ')' + 'return signature' + null terminator
145     cs = (char *)pkg_malloc(cslen * sizeof(char));
146     if (!cs)
147     {
148         LM_ERR("%s: pkg_malloc() has failed. Can't allocate %lu bytes. Not enough memory!\n", APP_NAME, (unsigned long)cslen);
149         return -1;
150     }
151     snprintf(cs, cslen, "(%s)%s", signature, retval_sig);
152     cs[cslen] = '\0';
153
154     // attach to current thread
155     (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
156     if ((*env)->ExceptionCheck(env))
157     {
158         handle_exception();
159         return -1;
160     }
161
162     cls = (*env)->GetObjectClass(env, KamailioClassInstance);
163     if ((*env)->ExceptionCheck(env))
164     {
165         handle_exception();
166         (*jvm)->DetachCurrentThread(jvm);
167         return -1;
168     }
169     fid = (*env)->GetFieldID(env, cls, "mop", "I");
170     if (!fid)
171     {
172         handle_exception();
173         (*jvm)->DetachCurrentThread(jvm);
174         return -1;
175     }
176
177     msg = msgp;
178
179     // find a method by signature
180     invk_method = is_static ? 
181                     (*env)->GetStaticMethodID(env, KamailioClassRef, method_name, cs) : 
182                     (*env)->GetMethodID(env, KamailioClassRef, method_name, cs);
183     if (!invk_method || (*env)->ExceptionCheck(env))
184     {
185         handle_exception();
186         (*jvm)->DetachCurrentThread(jvm);
187         return -1;
188     }
189
190     pkg_free(cs);
191
192     // keep local reference to method
193     invk_method_ref = (*env)->NewLocalRef(env, invk_method);
194     if (!invk_method_ref || (*env)->ExceptionCheck(env))
195     {
196         handle_exception();
197         (*env)->DeleteLocalRef(env, invk_method_ref);
198         (*jvm)->DetachCurrentThread(jvm);
199         return -1;
200     }
201
202     retval = -1;
203
204     if (is_synchronized)
205     {
206         if ((*env)->MonitorEnter(env, invk_method_ref) != JNI_OK)
207         {
208             locked = 0;
209             LM_ERR("%s: MonitorEnter() has failed! Can't synchronize!\n", APP_NAME);
210         }
211         else
212         {
213             locked = 1;
214         }
215     }
216
217     if (param == NULL)
218     {
219         retval = is_static ?
220                     (int)(*env)->CallStaticIntMethod(env, KamailioClassRef, invk_method_ref) :
221                     (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, invk_method_ref);
222     }
223     else
224     {
225         jparam = get_value_by_sig_type(signature, param);
226         if (jparam == NULL)
227         {
228             (*env)->DeleteLocalRef(env, invk_method_ref);
229             (*env)->DeleteLocalRef(env, invk_method);
230             (*jvm)->DetachCurrentThread(jvm);
231             return -1;
232         }
233
234         retval = is_static ?
235                     (int)(*env)->CallStaticIntMethod(env, KamailioClassRef, invk_method_ref, *jparam) :
236                     (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, invk_method_ref, *jparam);
237     }
238
239     if ((*env)->ExceptionCheck(env))
240     {
241         LM_ERR("%s: %s(): %s() has failed. See exception below.\n", APP_NAME,
242                 (is_static ? 
243                         (is_synchronized ? "java_s_staticmethod_exec" : "java_staticmethod_exec") :
244                         (is_synchronized ? "java_s_method_exec" : "java_method_exec")
245                 ),
246                 is_static ? "CallStaticIntMethod" : "CallIntMethod"
247         );
248
249         handle_exception();
250
251         (*env)->DeleteLocalRef(env, invk_method_ref);
252         (*env)->DeleteLocalRef(env, invk_method);
253         (*jvm)->DetachCurrentThread(jvm);
254
255         return -1;
256     }
257
258     if (is_synchronized && locked)
259     {
260         if ((*env)->MonitorExit(env, invk_method_ref) != JNI_OK)
261         {
262             LM_ERR("%s: MonitorExit() has failed! Can't synchronize!\n", APP_NAME);
263         }
264     }
265
266     (*env)->DeleteLocalRef(env, invk_method_ref);
267     (*env)->DeleteLocalRef(env, invk_method);
268     (*jvm)->DetachCurrentThread(jvm);
269
270     return retval;
271 }
272
273
274
275
276
277
278
279
280
281
282