1 /*
2 * Copyright 2016 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 /* Licensed to the Apache Software Foundation (ASF) under one or more
17 * contributor license agreements. See the NOTICE file distributed with
18 * this work for additional information regarding copyright ownership.
19 * The ASF licenses this file to You under the Apache License, Version 2.0
20 * (the "License"); you may not use this file except in compliance with
21 * the License. You may obtain a copy of the License at
22 *
23 * http://www.apache.org/licenses/LICENSE-2.0
24 *
25 * Unless required by applicable law or agreed to in writing, software
26 * distributed under the License is distributed on an "AS IS" BASIS,
27 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 * See the License for the specific language governing permissions and
29 * limitations under the License.
30 */
31
32 #include "tcn.h"
33 #include "apr_version.h"
34 #include "apr_atomic.h"
35 #include "apr_strings.h"
36
37 #ifndef TCN_JNI_VERSION
38 #define TCN_JNI_VERSION JNI_VERSION_1_4
39 #endif
40
41 apr_pool_t *tcn_global_pool = NULL;
42 static JavaVM *tcn_global_vm = NULL;
43
44 static jclass jString_class;
45 static jmethodID jString_init;
46 static jmethodID jString_getBytes;
47 static jclass byteArrayClass;
48 static jclass keyMaterialClass;
49 static jfieldID keyMaterialCertificateChainFieldId;
50 static jfieldID keyMaterialPrivateKeyFieldId;
51
52 /* Called by the JVM when APR_JAVA is loaded */
JNI_OnLoad_netty_tcnative(JavaVM * vm,void * reserved)53 JNIEXPORT jint JNICALL JNI_OnLoad_netty_tcnative(JavaVM *vm, void *reserved)
54 {
55 JNIEnv *env;
56 apr_version_t apv;
57 int apvn;
58
59 UNREFERENCED(reserved);
60 if ((*vm)->GetEnv(vm, (void **)&env, TCN_JNI_VERSION)) {
61 return JNI_ERR;
62 }
63 tcn_global_vm = vm;
64
65 /* Before doing anything else check if we have a valid
66 * APR version.
67 */
68 apr_version(&apv);
69 apvn = apv.major * 1000 + apv.minor * 100 + apv.patch;
70 if (apvn < 1201) {
71 tcn_Throw(env, "Unsupported APR version (%s)",
72 apr_version_string());
73 return JNI_ERR;
74 }
75
76
77 /* Initialize global java.lang.String class */
78 TCN_LOAD_CLASS(env, jString_class, "java/lang/String", JNI_ERR);
79
80 TCN_GET_METHOD(env, jString_class, jString_init,
81 "<init>", "([B)V", JNI_ERR);
82 TCN_GET_METHOD(env, jString_class, jString_getBytes,
83 "getBytes", "()[B", JNI_ERR);
84
85 // Load the class which makes JNI references available in a static scope before loading any other classes.
86 if ((*env)->FindClass(env, "io/netty/internal/tcnative/NativeStaticallyReferencedJniMethods") == NULL) {
87 return JNI_ERR;
88 }
89
90 TCN_LOAD_CLASS(env, byteArrayClass, "[B", JNI_ERR);
91 TCN_LOAD_CLASS(env, keyMaterialClass, "io/netty/internal/tcnative/CertificateRequestedCallback$KeyMaterial", JNI_ERR);
92
93 TCN_GET_FIELD(env, keyMaterialClass, keyMaterialCertificateChainFieldId,
94 "certificateChain", "J", JNI_ERR);
95 TCN_GET_FIELD(env, keyMaterialClass, keyMaterialPrivateKeyFieldId,
96 "privateKey", "J", JNI_ERR);
97
98 return TCN_JNI_VERSION;
99 }
100
101 /* Called by the JVM when APR_JAVA is loaded */
JNI_OnLoad(JavaVM * vm,void * reserved)102 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
103 {
104 return JNI_OnLoad_netty_tcnative(vm, reserved);
105 }
106
107 /* Called by the JVM before the APR_JAVA is unloaded */
JNI_OnUnload_netty_tcnative(JavaVM * vm,void * reserved)108 JNIEXPORT void JNICALL JNI_OnUnload_netty_tcnative(JavaVM *vm, void *reserved)
109 {
110 JNIEnv *env;
111
112 UNREFERENCED(reserved);
113
114 if ((*vm)->GetEnv(vm, (void **)&env, TCN_JNI_VERSION)) {
115 return;
116 }
117 if (tcn_global_pool) {
118 TCN_UNLOAD_CLASS(env, jString_class);
119 apr_terminate();
120 }
121
122 TCN_UNLOAD_CLASS(env, byteArrayClass);
123 TCN_UNLOAD_CLASS(env, keyMaterialClass);
124 }
125
126 /* Called by the JVM before the APR_JAVA is unloaded */
JNI_OnUnload(JavaVM * vm,void * reserved)127 JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
128 {
129 JNI_OnUnload_netty_tcnative(vm, reserved);
130 }
131
tcn_new_stringn(JNIEnv * env,const char * str,size_t l)132 jstring tcn_new_stringn(JNIEnv *env, const char *str, size_t l)
133 {
134 jstring result;
135 jbyteArray bytes = 0;
136
137 if (!str)
138 return NULL;
139 if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
140 return NULL; /* out of memory error */
141 }
142 bytes = (*env)->NewByteArray(env, l);
143 if (bytes != NULL) {
144 (*env)->SetByteArrayRegion(env, bytes, 0, l, (jbyte *)str);
145 result = (*env)->NewObject(env, jString_class, jString_init, bytes);
146 (*env)->DeleteLocalRef(env, bytes);
147 return result;
148 } /* else fall through */
149 return NULL;
150 }
151
tcn_new_string(JNIEnv * env,const char * str)152 jstring tcn_new_string(JNIEnv *env, const char *str)
153 {
154 if (!str)
155 return NULL;
156 else
157 return (*env)->NewStringUTF(env, str);
158 }
159
TCN_IMPLEMENT_CALL(jboolean,Library,initialize0)160 TCN_IMPLEMENT_CALL(jboolean, Library, initialize0)(TCN_STDARGS)
161 {
162
163 UNREFERENCED_STDARGS;
164 if (!tcn_global_pool) {
165 apr_initialize();
166 if (apr_pool_create(&tcn_global_pool, NULL) != APR_SUCCESS) {
167 return JNI_FALSE;
168 }
169 apr_atomic_init(tcn_global_pool);
170 }
171 return JNI_TRUE;
172 }
173
TCN_IMPLEMENT_CALL(jint,Library,version)174 TCN_IMPLEMENT_CALL(jint, Library, version)(TCN_STDARGS, jint what)
175 {
176 apr_version_t apv;
177
178 UNREFERENCED_STDARGS;
179 apr_version(&apv);
180
181 switch (what) {
182 case 0x11:
183 return apv.major;
184 break;
185 case 0x12:
186 return apv.minor;
187 break;
188 case 0x13:
189 return apv.patch;
190 break;
191 case 0x14:
192 return apv.is_dev;
193 break;
194 }
195 return 0;
196 }
197
TCN_IMPLEMENT_CALL(jstring,Library,aprVersionString)198 TCN_IMPLEMENT_CALL(jstring, Library, aprVersionString)(TCN_STDARGS)
199 {
200 UNREFERENCED(o);
201 return AJP_TO_JSTRING(apr_version_string());
202 }
203
TCN_IMPLEMENT_CALL(jboolean,Library,has)204 TCN_IMPLEMENT_CALL(jboolean, Library, has)(TCN_STDARGS, jint what)
205 {
206 jboolean rv = JNI_FALSE;
207 UNREFERENCED_STDARGS;
208 switch (what) {
209 case 0:
210 #if APR_HAVE_IPV6
211 rv = JNI_TRUE;
212 #endif
213 break;
214 case 1:
215 #if APR_HAS_SHARED_MEMORY
216 rv = JNI_TRUE;
217 #endif
218 break;
219 case 2:
220 #if APR_HAS_THREADS
221 rv = JNI_TRUE;
222 #endif
223 break;
224 case 3:
225 #if APR_HAS_SENDFILE
226 rv = JNI_TRUE;
227 #endif
228 break;
229 case 4:
230 #if APR_HAS_MMAP
231 rv = JNI_TRUE;
232 #endif
233 break;
234 case 5:
235 #if APR_HAS_FORK
236 rv = JNI_TRUE;
237 #endif
238 break;
239 case 6:
240 #if APR_HAS_RANDOM
241 rv = JNI_TRUE;
242 #endif
243 break;
244 case 7:
245 #if APR_HAS_OTHER_CHILD
246 rv = JNI_TRUE;
247 #endif
248 break;
249 case 8:
250 #if APR_HAS_DSO
251 rv = JNI_TRUE;
252 #endif
253 break;
254 case 9:
255 #if APR_HAS_SO_ACCEPTFILTER
256 rv = JNI_TRUE;
257 #endif
258 break;
259 case 10:
260 #if APR_HAS_UNICODE_FS
261 rv = JNI_TRUE;
262 #endif
263 break;
264 case 11:
265 #if APR_HAS_PROC_INVOKED
266 rv = JNI_TRUE;
267 #endif
268 break;
269 case 12:
270 #if APR_HAS_USER
271 rv = JNI_TRUE;
272 #endif
273 break;
274 case 13:
275 #if APR_HAS_LARGE_FILES
276 rv = JNI_TRUE;
277 #endif
278 break;
279 case 14:
280 #if APR_HAS_XTHREAD_FILES
281 rv = JNI_TRUE;
282 #endif
283 break;
284 case 15:
285 #if APR_HAS_OS_UUID
286 rv = JNI_TRUE;
287 #endif
288 break;
289 case 16:
290 #if APR_IS_BIGENDIAN
291 rv = JNI_TRUE;
292 #endif
293 break;
294
295 case 17:
296 #if APR_FILES_AS_SOCKETS
297 rv = JNI_TRUE;
298 #endif
299 break;
300 case 18:
301 #if APR_CHARSET_EBCDIC
302 rv = JNI_TRUE;
303 #endif
304 break;
305 case 19:
306 #if APR_TCP_NODELAY_INHERITED
307 rv = JNI_TRUE;
308 #endif
309 break;
310 case 20:
311 #if APR_O_NONBLOCK_INHERITED
312 rv = JNI_TRUE;
313 #endif
314 break;
315 }
316 return rv;
317 }
318
tcn_get_string_class()319 jclass tcn_get_string_class()
320 {
321 return jString_class;
322 }
323
tcn_get_byte_array_class()324 jclass tcn_get_byte_array_class()
325 {
326 return byteArrayClass;
327 }
328
tcn_get_key_material_certificate_chain_field()329 jfieldID tcn_get_key_material_certificate_chain_field()
330 {
331 return keyMaterialCertificateChainFieldId;
332 }
333
tcn_get_key_material_private_key_field()334 jfieldID tcn_get_key_material_private_key_field()
335 {
336 return keyMaterialPrivateKeyFieldId;
337 }
338
tcn_get_java_env(JNIEnv ** env)339 jint tcn_get_java_env(JNIEnv **env)
340 {
341 if ((*tcn_global_vm)->GetEnv(tcn_global_vm, (void **)env,
342 TCN_JNI_VERSION)) {
343 return JNI_ERR;
344 }
345 return JNI_OK;
346 }
347