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 */
53static void
54JNU_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 */
84static char
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 */
188JNIEXPORT
189void 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