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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file contains native methods for the Java SLP implementation.
31  * So far this is just the syslog function.
32  *
33  * The file also contains two support functions, one for throwing exceptions
34  * given a class name, and one for correctly converting unicode Strings to C
35  * byte arrays.
36  */
37 
38 #include <malloc.h>
39 #include <jni.h>
40 #include <syslog.h>
41 
42 #define	CLASS_JAVA_LANG_OUTOFMEMORYERROR "java/lang/OutOfMemoryError"
43 #define	CLASS_JAVA_LANG_STRING "java/lang/String"
44 
45 #define	METHOD_GETBYTES "getBytes"
46 
47 #define	SIG_JAVA_LANG_STRING_GETBYTES "()[B"
48 
49 /*
50  * Given a class name of an exception and a message attempt to throw
51  * a new instance of the exception.
52  */
53 static void
JNU_ThrowByName(JNIEnv * env,const char * name,const char * msg)54 JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg)
55 {
56 	jclass class = (*env)->FindClass(env, name);
57 
58 	/*
59 	 * If class is NULL FindClass() encountered a problem locating the
60 	 * desired class and has already called ThrowNew() with an
61 	 * exception.
62 	 */
63 	if (class == NULL) {
64 		return;
65 	}
66 
67 	(*env)->ThrowNew(env, class, msg);
68 	(*env)->DeleteLocalRef(env, class);
69 }
70 
71 /*
72  * Convert a Java String into a native set of characters using the
73  * method String.getBytes(). This will ensure that the appropriate
74  * character set encoding will be used. This is necessary if the
75  * Java String uses unicode characters that cannot be easily
76  * encoded into native chars.
77  *
78  * The buffer returned must be released by using free() once it is
79  * finished with.
80  *
81  * This function returns NULL if an exception has been thrown during its
82  * execution.
83  */
84 static char
JNU_GetStringNativeChars(JNIEnv * env,jstring jstr)85 *JNU_GetStringNativeChars(JNIEnv *env, jstring jstr)
86 {
87 	jclass class;
88 	jmethodID method;
89 	jint len;
90 	jbyteArray bytes = NULL;
91 	char *result = NULL;
92 
93 	/*
94 	 * Need a local reference for (1) FindClass(), (2) the bytes and
95 	 * (3) the FindClass() in ThrowByName() if all goes wrong.
96 	 */
97 	if ((*env)->EnsureLocalCapacity(env, 3) < 0) {
98 		JNU_ThrowByName(
99 		    env,
100 		    CLASS_JAVA_LANG_OUTOFMEMORYERROR,
101 		    NULL);
102 
103 		return (NULL);
104 	}
105 
106 	class = (*env)->FindClass(env, CLASS_JAVA_LANG_STRING);
107 
108 	/*
109 	 * If class is NULL FindClass() encountered a problem locating the
110 	 * desired class and has already called ThrowNew() with an
111 	 * exception.
112 	 */
113 	if (class == NULL) {
114 		return (NULL);
115 	}
116 
117 	method = (*env)->GetMethodID(
118 	    env,
119 	    class,
120 	    METHOD_GETBYTES,
121 	    SIG_JAVA_LANG_STRING_GETBYTES);
122 
123 	/*
124 	 * If method is NULL GetMethodID() encountered a problem
125 	 * locating the desired method and has already called
126 	 * ThrowNew() with an exception.
127 	 */
128 	if (method != NULL) {
129 		/*
130 		 * Call String.getBytes(), creating our temporary
131 		 * byte array
132 		 */
133 		bytes = (*env)->CallObjectMethod(env, jstr, method);
134 
135 		/* See if CallObjectMethod() threw an exception */
136 		if ((*env)->ExceptionCheck(env) == JNI_FALSE) {
137 
138 			len = (*env)->GetArrayLength(env, bytes);
139 
140 			/*
141 			 * Allocate a buffer for the native characters,
142 			 * need an extra char for string terminator.
143 			 * Note: calloc will provide the terminating
144 			 * '\0' for us.
145 			 */
146 			result = (char *)calloc(len + 1, sizeof (char));
147 
148 			/*
149 			 * If allocation failed assume we are out of
150 			 * memory
151 			 */
152 			if (result == NULL) {
153 				JNU_ThrowByName(
154 				    env,
155 				    CLASS_JAVA_LANG_OUTOFMEMORYERROR,
156 				    NULL);
157 			} else {
158 				/*
159 				 * Copy the encoded bytes into the
160 				 * native string buffer
161 				 */
162 				(*env)->GetByteArrayRegion(
163 				    env,
164 				    bytes,
165 				    0,
166 				    len,
167 				    (jbyte *)result);
168 			}
169 		}
170 
171 		if (bytes != NULL) {
172 		    (*env)->DeleteLocalRef(env, bytes);
173 		}
174 	}
175 
176 	/* Clean up by deleting the local references */
177 	(*env)->DeleteLocalRef(env, class);
178 
179 	return (result);
180 }
181 
182 /*
183  * Class:     com_sun_slp_Syslog
184  * Method:    syslog
185  * Signature: (ILjava/lang/String;)V
186  */
187 /* ARGSUSED */
188 JNIEXPORT
Java_com_sun_slp_Syslog_syslog(JNIEnv * env,jobject obj,jint priority,jstring jmsg)189 void JNICALL Java_com_sun_slp_Syslog_syslog(JNIEnv *env,
190 					    jobject obj,
191 					    jint priority,
192 					    jstring jmsg) {
193 
194 	char *msg = JNU_GetStringNativeChars(env, jmsg);
195 
196 	/*
197 	 * Check to see if the String conversion was successful,
198 	 * if it wasn't an exception will have already been thrown.
199 	 */
200 	if (msg != NULL) {
201 		openlog("slpd", LOG_PID, LOG_DAEMON);
202 		syslog(priority, "%s", msg);
203 		closelog();
204 
205 		free(msg);
206 	}
207 }
208