xref: /illumos-gate/usr/src/lib/libslp/clib/slp_jni_support.c (revision 374858d291554c199353841e2900bc130463934a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1998,2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * This file contains native methods for the Java SLP implementation.
29  * So far this is just the syslog function.
30  *
31  * The file also contains two support functions, one for throwing exceptions
32  * given a class name, and one for correctly converting unicode Strings to C
33  * byte arrays.
34  */
35 
36 #include <malloc.h>
37 #include <jni.h>
38 #include <syslog.h>
39 
40 #define	CLASS_JAVA_LANG_OUTOFMEMORYERROR "java/lang/OutOfMemoryError"
41 #define	CLASS_JAVA_LANG_STRING "java/lang/String"
42 
43 #define	METHOD_GETBYTES "getBytes"
44 
45 #define	SIG_JAVA_LANG_STRING_GETBYTES "()[B"
46 
47 /*
48  * Given a class name of an exception and a message attempt to throw
49  * a new instance of the exception.
50  */
51 static void
52 JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg)
53 {
54 	jclass class = (*env)->FindClass(env, name);
55 
56 	/*
57 	 * If class is NULL FindClass() encountered a problem locating the
58 	 * desired class and has already called ThrowNew() with an
59 	 * exception.
60 	 */
61 	if (class == NULL) {
62 		return;
63 	}
64 
65 	(*env)->ThrowNew(env, class, msg);
66 	(*env)->DeleteLocalRef(env, class);
67 }
68 
69 /*
70  * Convert a Java String into a native set of characters using the
71  * method String.getBytes(). This will ensure that the appropriate
72  * character set encoding will be used. This is necessary if the
73  * Java String uses unicode characters that cannot be easily
74  * encoded into native chars.
75  *
76  * The buffer returned must be released by using free() once it is
77  * finished with.
78  *
79  * This function returns NULL if an exception has been thrown during its
80  * execution.
81  */
82 static char
83 *JNU_GetStringNativeChars(JNIEnv *env, jstring jstr)
84 {
85 	jclass class;
86 	jmethodID method;
87 	jint len;
88 	jbyteArray bytes = NULL;
89 	char *result = NULL;
90 
91 	/*
92 	 * Need a local reference for (1) FindClass(), (2) the bytes and
93 	 * (3) the FindClass() in ThrowByName() if all goes wrong.
94 	 */
95 	if ((*env)->EnsureLocalCapacity(env, 3) < 0) {
96 		JNU_ThrowByName(
97 		    env,
98 		    CLASS_JAVA_LANG_OUTOFMEMORYERROR,
99 		    NULL);
100 
101 		return (NULL);
102 	}
103 
104 	class = (*env)->FindClass(env, CLASS_JAVA_LANG_STRING);
105 
106 	/*
107 	 * If class is NULL FindClass() encountered a problem locating the
108 	 * desired class and has already called ThrowNew() with an
109 	 * exception.
110 	 */
111 	if (class == NULL) {
112 		return (NULL);
113 	}
114 
115 	method = (*env)->GetMethodID(
116 	    env,
117 	    class,
118 	    METHOD_GETBYTES,
119 	    SIG_JAVA_LANG_STRING_GETBYTES);
120 
121 	/*
122 	 * If method is NULL GetMethodID() encountered a problem
123 	 * locating the desired method and has already called
124 	 * ThrowNew() with an exception.
125 	 */
126 	if (method != NULL) {
127 		/*
128 		 * Call String.getBytes(), creating our temporary
129 		 * byte array
130 		 */
131 		bytes = (*env)->CallObjectMethod(env, jstr, method);
132 
133 		/* See if CallObjectMethod() threw an exception */
134 		if ((*env)->ExceptionCheck(env) == JNI_FALSE) {
135 
136 			len = (*env)->GetArrayLength(env, bytes);
137 
138 			/*
139 			 * Allocate a buffer for the native characters,
140 			 * need an extra char for string terminator.
141 			 * Note: calloc will provide the terminating
142 			 * '\0' for us.
143 			 */
144 			result = (char *)calloc(len + 1, sizeof (char));
145 
146 			/*
147 			 * If allocation failed assume we are out of
148 			 * memory
149 			 */
150 			if (result == NULL) {
151 				JNU_ThrowByName(
152 				    env,
153 				    CLASS_JAVA_LANG_OUTOFMEMORYERROR,
154 				    NULL);
155 			} else {
156 				/*
157 				 * Copy the encoded bytes into the
158 				 * native string buffer
159 				 */
160 				(*env)->GetByteArrayRegion(
161 				    env,
162 				    bytes,
163 				    0,
164 				    len,
165 				    (jbyte *)result);
166 			}
167 		}
168 
169 		if (bytes != NULL) {
170 		    (*env)->DeleteLocalRef(env, bytes);
171 		}
172 	}
173 
174 	/* Clean up by deleting the local references */
175 	(*env)->DeleteLocalRef(env, class);
176 
177 	return (result);
178 }
179 
180 /*
181  * Class:     com_sun_slp_Syslog
182  * Method:    syslog
183  * Signature: (ILjava/lang/String;)V
184  */
185 /* ARGSUSED */
186 JNIEXPORT
187 void JNICALL Java_com_sun_slp_Syslog_syslog(JNIEnv *env,
188 					    jobject obj,
189 					    jint priority,
190 					    jstring jmsg) {
191 
192 	char *msg = JNU_GetStringNativeChars(env, jmsg);
193 
194 	/*
195 	 * Check to see if the String conversion was successful,
196 	 * if it wasn't an exception will have already been thrown.
197 	 */
198 	if (msg != NULL) {
199 		openlog("slpd", LOG_PID, LOG_DAEMON);
200 		syslog(priority, "%s", msg);
201 		closelog();
202 
203 		free(msg);
204 	}
205 }
206