1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "tcn.h"
18 #include "apr_version.h"
19 #include "apr_file_io.h"
20 #include "apr_mmap.h"
21 #include "apr_atomic.h"
22 #include "apr_poll.h"
23 
24 #include "tcn_version.h"
25 
26 #ifdef WIN32
27 #include <Windows.h>
28 #endif
29 
30 #ifdef DARWIN
31 #include <pthread.h>
32 #endif
33 
34 #ifdef __FreeBSD__
35 #include <pthread_np.h>
36 #endif
37 
38 #ifdef __linux__
39 #include <sys/syscall.h>
40 #endif
41 
42 #ifdef TCN_DO_STATISTICS
43 extern void sp_poll_dump_statistics();
44 extern void sp_network_dump_statistics();
45 extern void ssl_network_dump_statistics();
46 #endif
47 
48 apr_pool_t *tcn_global_pool = NULL;
49 static JavaVM     *tcn_global_vm = NULL;
50 
51 static jclass    jString_class;
52 static jclass    jFinfo_class;
53 static jclass    jAinfo_class;
54 static jmethodID jString_init;
55 static jmethodID jString_getBytes;
56 
57 int tcn_parent_pid = 0;
58 
59 /* Called by the JVM when APR_JAVA is loaded */
JNI_OnLoad(JavaVM * vm,void * reserved)60 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
61 {
62     JNIEnv *env;
63     void   *ppe;
64     apr_version_t apv;
65     int apvn;
66 
67     UNREFERENCED(reserved);
68     if ((*vm)->GetEnv(vm, &ppe, JNI_VERSION_1_4)) {
69         return JNI_ERR;
70     }
71     tcn_global_vm = vm;
72     env           = (JNIEnv *)ppe;
73     /* Before doing anything else check if we have a valid
74      * APR version. We need version 1.4.3 as minimum.
75      */
76     apr_version(&apv);
77     apvn = apv.major * 1000 + apv.minor * 100 + apv.patch;
78     if (apvn < 1403) {
79         tcn_Throw(env, "Unsupported APR version %s: this tcnative requires at least 1.4.3",
80                   apr_version_string());
81         return JNI_ERR;
82     }
83 
84     /* Initialize global java.lang.String class */
85     TCN_LOAD_CLASS(env, jString_class, "java/lang/String", JNI_ERR);
86     TCN_LOAD_CLASS(env, jFinfo_class, TCN_FINFO_CLASS, JNI_ERR);
87     TCN_LOAD_CLASS(env, jAinfo_class, TCN_AINFO_CLASS, JNI_ERR);
88 
89     TCN_GET_METHOD(env, jString_class, jString_init,
90                    "<init>", "([B)V", JNI_ERR);
91     TCN_GET_METHOD(env, jString_class, jString_getBytes,
92                    "getBytes", "()[B", JNI_ERR);
93 
94     if(tcn_load_finfo_class(env, jFinfo_class) != APR_SUCCESS)
95         return JNI_ERR;
96     if(tcn_load_ainfo_class(env, jAinfo_class) != APR_SUCCESS)
97         return JNI_ERR;
98 #ifdef WIN32
99     {
100         char *ppid = getenv(TCN_PARENT_IDE);
101         if (ppid)
102             tcn_parent_pid = atoi(ppid);
103     }
104 #else
105     tcn_parent_pid = getppid();
106 #endif
107 
108     return  JNI_VERSION_1_4;
109 }
110 
111 
112 /* Called by the JVM before the APR_JAVA is unloaded */
JNI_OnUnload(JavaVM * vm,void * reserved)113 JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
114 {
115     JNIEnv *env;
116     void   *ppe;
117 
118     UNREFERENCED(reserved);
119 
120     if ((*vm)->GetEnv(vm, &ppe, JNI_VERSION_1_2)) {
121         return;
122     }
123     if (tcn_global_pool) {
124         env  = (JNIEnv *)ppe;
125         TCN_UNLOAD_CLASS(env, jString_class);
126         TCN_UNLOAD_CLASS(env, jFinfo_class);
127         TCN_UNLOAD_CLASS(env, jAinfo_class);
128         apr_terminate();
129     }
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_arrayb(JNIEnv * env,const unsigned char * data,size_t len)152 jbyteArray tcn_new_arrayb(JNIEnv *env, const unsigned char *data, size_t len)
153 {
154     jbyteArray bytes = (*env)->NewByteArray(env, (jsize)len);
155     if (bytes != NULL) {
156         (*env)->SetByteArrayRegion(env, bytes, 0, (jint)len, (jbyte *)data);
157     }
158     return bytes;
159 }
160 
tcn_new_arrays(JNIEnv * env,size_t len)161 jobjectArray tcn_new_arrays(JNIEnv *env, size_t len)
162 {
163     return (*env)->NewObjectArray(env, (jsize)len, jString_class, NULL);
164 }
165 
tcn_new_string(JNIEnv * env,const char * str)166 jstring tcn_new_string(JNIEnv *env, const char *str)
167 {
168     if (!str)
169         return NULL;
170     else
171         return (*env)->NewStringUTF(env, str);
172 }
173 
tcn_get_string(JNIEnv * env,jstring jstr)174 char *tcn_get_string(JNIEnv *env, jstring jstr)
175 {
176     jbyteArray bytes = NULL;
177     jthrowable exc;
178     char *result = NULL;
179 
180     if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
181         return NULL; /* out of memory error */
182     }
183     bytes = (*env)->CallObjectMethod(env, jstr, jString_getBytes);
184     exc = (*env)->ExceptionOccurred(env);
185     if (!exc) {
186         jint len = (*env)->GetArrayLength(env, bytes);
187         result = (char *)malloc(len + 1);
188         if (result == NULL) {
189             TCN_THROW_OS_ERROR(env);
190             (*env)->DeleteLocalRef(env, bytes);
191             return 0;
192         }
193         (*env)->GetByteArrayRegion(env, bytes, 0, len, (jbyte *)result);
194         result[len] = '\0'; /* NULL-terminate */
195     }
196     else {
197         (*env)->DeleteLocalRef(env, exc);
198     }
199     (*env)->DeleteLocalRef(env, bytes);
200 
201     return result;
202 }
203 
tcn_strdup(JNIEnv * env,jstring jstr)204 char *tcn_strdup(JNIEnv *env, jstring jstr)
205 {
206     char *result = NULL;
207     const char *cjstr;
208 
209     cjstr = (const char *)((*env)->GetStringUTFChars(env, jstr, 0));
210     if (cjstr) {
211         result = strdup(cjstr);
212         (*env)->ReleaseStringUTFChars(env, jstr, cjstr);
213     }
214     return result;
215 }
216 
tcn_pstrdup(JNIEnv * env,jstring jstr,apr_pool_t * pool)217 char *tcn_pstrdup(JNIEnv *env, jstring jstr, apr_pool_t *pool)
218 {
219     char *result = NULL;
220     const char *cjstr;
221 
222     cjstr = (const char *)((*env)->GetStringUTFChars(env, jstr, 0));
223     if (cjstr) {
224         result = apr_pstrdup(pool, cjstr);
225         (*env)->ReleaseStringUTFChars(env, jstr, cjstr);
226     }
227     return result;
228 }
229 
TCN_IMPLEMENT_CALL(jboolean,Library,initialize)230 TCN_IMPLEMENT_CALL(jboolean, Library, initialize)(TCN_STDARGS)
231 {
232 
233     UNREFERENCED_STDARGS;
234     if (!tcn_global_pool) {
235         apr_initialize();
236         if (apr_pool_create(&tcn_global_pool, NULL) != APR_SUCCESS) {
237             return JNI_FALSE;
238         }
239         apr_atomic_init(tcn_global_pool);
240     }
241     return JNI_TRUE;
242 }
243 
TCN_IMPLEMENT_CALL(void,Library,terminate)244 TCN_IMPLEMENT_CALL(void, Library, terminate)(TCN_STDARGS)
245 {
246 
247     UNREFERENCED_STDARGS;
248     if (tcn_global_pool) {
249         apr_pool_t *p = tcn_global_pool;
250         tcn_global_pool = NULL;
251 #ifdef TCN_DO_STATISTICS
252         fprintf(stderr, "APR Statistical data ....\n");
253 #endif
254         apr_pool_destroy(p);
255 #ifdef TCN_DO_STATISTICS
256         sp_poll_dump_statistics();
257         sp_network_dump_statistics();
258         ssl_network_dump_statistics();
259         fprintf(stderr, "APR Terminated\n");
260 #endif
261         apr_terminate();
262     }
263 }
264 
TCN_IMPLEMENT_CALL(jlong,Library,globalPool)265 TCN_IMPLEMENT_CALL(jlong, Library, globalPool)(TCN_STDARGS)
266 {
267     UNREFERENCED_STDARGS;
268     return P2J(tcn_global_pool);
269 }
270 
TCN_IMPLEMENT_CALL(jint,Library,version)271 TCN_IMPLEMENT_CALL(jint, Library, version)(TCN_STDARGS, jint what)
272 {
273     apr_version_t apv;
274 
275     UNREFERENCED_STDARGS;
276     apr_version(&apv);
277 
278     switch (what) {
279         case 0x01:
280             return TCN_MAJOR_VERSION;
281         break;
282         case 0x02:
283             return TCN_MINOR_VERSION;
284         break;
285         case 0x03:
286             return TCN_PATCH_VERSION;
287         break;
288         case 0x04:
289             return TCN_IS_DEV_VERSION;
290         break;
291         case 0x11:
292             return apv.major;
293         break;
294         case 0x12:
295             return apv.minor;
296         break;
297         case 0x13:
298             return apv.patch;
299         break;
300         case 0x14:
301             return apv.is_dev;
302         break;
303     }
304     return 0;
305 }
306 
TCN_IMPLEMENT_CALL(jstring,Library,versionString)307 TCN_IMPLEMENT_CALL(jstring, Library, versionString)(TCN_STDARGS)
308 {
309     UNREFERENCED(o);
310     return AJP_TO_JSTRING(TCN_VERSION_STRING);
311 }
312 
TCN_IMPLEMENT_CALL(jstring,Library,aprVersionString)313 TCN_IMPLEMENT_CALL(jstring, Library, aprVersionString)(TCN_STDARGS)
314 {
315     UNREFERENCED(o);
316     return AJP_TO_JSTRING(apr_version_string());
317 }
318 
TCN_IMPLEMENT_CALL(jboolean,Library,has)319 TCN_IMPLEMENT_CALL(jboolean, Library, has)(TCN_STDARGS, jint what)
320 {
321     jboolean rv = JNI_FALSE;
322     UNREFERENCED_STDARGS;
323     switch (what) {
324         case 0:
325 #if APR_HAVE_IPV6
326             rv = JNI_TRUE;
327 #endif
328         break;
329         case 1:
330 #if APR_HAS_SHARED_MEMORY
331             rv = JNI_TRUE;
332 #endif
333         break;
334         case 2:
335 #if APR_HAS_THREADS
336             rv = JNI_TRUE;
337 #endif
338         break;
339         case 3:
340 #if APR_HAS_SENDFILE
341             rv = JNI_TRUE;
342 #endif
343         break;
344         case 4:
345 #if APR_HAS_MMAP
346             rv = JNI_TRUE;
347 #endif
348         break;
349         case 5:
350 #if APR_HAS_FORK
351             rv = JNI_TRUE;
352 #endif
353         break;
354         case 6:
355 #if APR_HAS_RANDOM
356             rv = JNI_TRUE;
357 #endif
358         break;
359         case 7:
360 #if APR_HAS_OTHER_CHILD
361             rv = JNI_TRUE;
362 #endif
363         break;
364         case 8:
365 #if APR_HAS_DSO
366             rv = JNI_TRUE;
367 #endif
368         break;
369         case 9:
370 #if APR_HAS_SO_ACCEPTFILTER
371             rv = JNI_TRUE;
372 #endif
373         break;
374         case 10:
375 #if APR_HAS_UNICODE_FS
376             rv = JNI_TRUE;
377 #endif
378         break;
379         case 11:
380 #if APR_HAS_PROC_INVOKED
381             rv = JNI_TRUE;
382 #endif
383         break;
384         case 12:
385 #if APR_HAS_USER
386             rv = JNI_TRUE;
387 #endif
388         break;
389         case 13:
390 #if APR_HAS_LARGE_FILES
391             rv = JNI_TRUE;
392 #endif
393         break;
394         case 14:
395 #if APR_HAS_XTHREAD_FILES
396             rv = JNI_TRUE;
397 #endif
398         break;
399         case 15:
400 #if APR_HAS_OS_UUID
401             rv = JNI_TRUE;
402 #endif
403         break;
404         case 16:
405 #if APR_IS_BIGENDIAN
406             rv = JNI_TRUE;
407 #endif
408         break;
409 
410         case 17:
411 #if APR_FILES_AS_SOCKETS
412             rv = JNI_TRUE;
413 #endif
414         break;
415         case 18:
416 #if APR_CHARSET_EBCDIC
417             rv = JNI_TRUE;
418 #endif
419         break;
420         case 19:
421 #if APR_TCP_NODELAY_INHERITED
422             rv = JNI_TRUE;
423 #endif
424         break;
425         case 20:
426 #if APR_O_NONBLOCK_INHERITED
427             rv = JNI_TRUE;
428 #endif
429         break;
430         case 21:
431 #if defined(APR_POLLSET_WAKEABLE)
432             rv = JNI_TRUE;
433 #endif
434         break;
435     }
436     return rv;
437 }
438 
TCN_IMPLEMENT_CALL(jint,Library,size)439 TCN_IMPLEMENT_CALL(jint, Library, size)(TCN_STDARGS, jint what)
440 {
441 
442     UNREFERENCED_STDARGS;
443 
444     switch (what) {
445         case 1:
446             return APR_SIZEOF_VOIDP;
447         break;
448         case 2:
449             return APR_PATH_MAX;
450         break;
451         case 3:
452             return APRMAXHOSTLEN;
453         break;
454         case 4:
455             return APR_MAX_IOVEC_SIZE;
456         break;
457         case 5:
458             return APR_MAX_SECS_TO_LINGER;
459         break;
460         case 6:
461             return APR_MMAP_THRESHOLD;
462         break;
463         case 7:
464             return APR_MMAP_LIMIT;
465         break;
466 
467     }
468     return 0;
469 }
470 
tcn_get_global_pool()471 apr_pool_t *tcn_get_global_pool()
472 {
473     if (!tcn_global_pool) {
474         if (apr_pool_create(&tcn_global_pool, NULL) != APR_SUCCESS) {
475             return NULL;
476         }
477         apr_atomic_init(tcn_global_pool);
478     }
479     return tcn_global_pool;
480 }
481 
tcn_get_string_class()482 jclass tcn_get_string_class()
483 {
484     return jString_class;
485 }
486 
tcn_get_java_vm()487 JavaVM * tcn_get_java_vm()
488 {
489     return tcn_global_vm;
490 }
491 
tcn_get_java_env(JNIEnv ** env)492 jint tcn_get_java_env(JNIEnv **env)
493 {
494     if ((*tcn_global_vm)->GetEnv(tcn_global_vm, (void **)env,
495                                  JNI_VERSION_1_4)) {
496         return JNI_ERR;
497     }
498     return JNI_OK;
499 }
500 
tcn_get_thread_id(void)501 unsigned long tcn_get_thread_id(void)
502 {
503     /* OpenSSL needs this to return an unsigned long.  On OS/390, the pthread
504      * id is a structure twice that big.  Use the TCB pointer instead as a
505      * unique unsigned long.
506      */
507 #ifdef __MVS__
508     struct PSA {
509         char unmapped[540];
510         unsigned long PSATOLD;
511     } *psaptr = 0;
512 
513     return psaptr->PSATOLD;
514 #elif defined(WIN32)
515     return (unsigned long)GetCurrentThreadId();
516 #elif defined(DARWIN)
517     uint64_t tid;
518     pthread_threadid_np(NULL, &tid);
519     return (unsigned long)tid;
520 #elif defined(__FreeBSD__)
521     return (unsigned long)pthread_getthreadid_np();
522 #elif defined(__linux__)
523     return (unsigned long)syscall(SYS_gettid);
524 #else
525     return (unsigned long)pthread_self();
526 #endif
527 }
528 
529