blob: beb59426e3ddb038fa9db30e552dd9d5b874b3a2 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include "jni.h"
#include "osl/security.h"
#include <osl/pipe.h>
/* On Windows, jpipe.dll must not have dependencies on any other URE DLLs, as
Java System.LoadLibrary could otherwise not load it. Therefore, on Windows,
this code goes into a jpipx.dll that the jpipe.dll wrapper loads with
LoadLibraryEx(LOAD_WITH_ALTERED_SEARCH_PATH). The function names in this
wrapped code are truncated from the long JNICALL names, as JNICALL causes
some "@N" with different numeric values for N (and probably different across
32 and 64 bit) to be added to the symbol names, which the calls to
GetProcAddress in wrapper/wrapper.c would otheriwse have to take into
account.
*/
/*****************************************************************************/
/* exception macros */
static void ThrowException(JNIEnv * env, char const * type, char const * msg) {
jclass c;
(*env)->ExceptionClear(env);
c = (*env)->FindClass(env, type);
if (c == NULL) {
(*env)->ExceptionClear(env);
(*env)->FatalError(env, "JNI FindClass failed");
}
if ((*env)->ThrowNew(env, c, msg) != 0) {
(*env)->ExceptionClear(env);
(*env)->FatalError(env, "JNI ThrowNew failed");
}
}
/*****************************************************************************/
/* helper functions prototypes */
static oslPipe getPipe(JNIEnv * env, jobject obj_this);
static rtl_uString * jstring2ustring(JNIEnv * env, jstring jstr);
/*****************************************************************************/
/* get pipe */
static oslPipe getPipe(JNIEnv * env, jobject obj_this)
{
jclass tclass;
jfieldID fid;
tclass = (*env)->GetObjectClass(env, obj_this);
if (tclass == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot find class");
return NULL;
}
fid = (*env)->GetFieldID(env, tclass, "_nPipeHandle", "J");
if (fid == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot find field");
return NULL;
}
return (oslPipe) SAL_INT_CAST(
sal_IntPtr, (*env)->GetLongField(env, obj_this, fid));
}
/*****************************************************************************/
/* convert jstring to rtl_uString */
static rtl_uString * jstring2ustring(JNIEnv * env, jstring jstr)
{
const char * cstr;
rtl_uString * ustr = NULL;
cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
rtl_uString_newFromAscii(&ustr, cstr);
(*env)->ReleaseStringUTFChars(env, jstr, cstr);
return ustr;
}
/*****************************************************************************/
/*
* Class: com_sun_star_lib_connections_pipe_PipeConnection
* Method: connect
* Signature: (Lcom/sun/star/beans/NativeService;)V
*/
SAL_DLLPUBLIC_EXPORT void
#if defined WNT
PipeConnection_create
#else
JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_createJNI
#endif
(JNIEnv * env, jobject obj_this, jstring name)
{
enum {
START = 0,
INMONITOR,
GOTNAME,
CREATED
};
short state = START;
jclass tclass;
jfieldID fid;
oslSecurity psec = osl_getCurrentSecurity();
oslPipe npipe = NULL;
rtl_uString * pname = NULL;
if ((*env)->MonitorEnter(env, obj_this) != 0)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot synchronize on the object");
goto error;
}
state = INMONITOR;
/* check connection state */
npipe = getPipe(env, obj_this);
if ((*env)->ExceptionOccurred(env) != NULL)
goto error;
if (npipe != NULL)
{
ThrowException(env,
"com/sun/star/io/IOException",
"native pipe is already connected");
goto error;
}
/* save the pipe name */
tclass = (*env)->GetObjectClass(env, obj_this);
if (tclass == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot find class");
goto error;
}
fid = (*env)->GetFieldID(env, tclass,
"_aDescription", "Ljava/lang/String;");
if (fid == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot find field");
goto error;
}
(*env)->SetObjectField(env, obj_this, fid, (jobject)name);
/* convert pipe name to rtl_uString */
pname = jstring2ustring(env, name);
if (pname == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot convert name");
goto error;
}
state = GOTNAME;
/* try to connect */
npipe = osl_createPipe(pname, osl_Pipe_OPEN, psec);
if (npipe == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"cannot create native pipe");
goto error;
}
state = CREATED;
/* save the pipe */
tclass = (*env)->GetObjectClass(env, obj_this);
if (tclass == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot find class");
goto error;
}
fid = (*env)->GetFieldID(env, tclass, "_nPipeHandle", "J");
if (fid == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot find field");
goto error;
}
(*env)->SetLongField(
env, obj_this, fid, SAL_INT_CAST(jlong, (sal_IntPtr) npipe));
/* done */
rtl_uString_release(pname);
(*env)->MonitorExit(env, obj_this);
osl_freeSecurityHandle(psec);
return;
error:
switch (state)
{
case CREATED:
osl_closePipe(npipe);
osl_releasePipe(npipe);
case GOTNAME:
rtl_uString_release(pname);
case INMONITOR:
(*env)->MonitorExit(env, obj_this);
case START:
osl_freeSecurityHandle(psec);
default:
break;
}
return;
}
/*****************************************************************************/
/*
* Class: com_sun_star_lib_connections_pipe_PipeConnection
* Method: closeJNI
* Signature: ()V
*/
SAL_DLLPUBLIC_EXPORT void
#if defined WNT
PipeConnection_close
#else
JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_closeJNI
#endif
(JNIEnv * env, jobject obj_this)
{
enum {
START = 0,
INMONITOR
};
short state = START;
oslPipe npipe; /* native pipe */
jclass tclass; /* this class */
jfieldID fid; /* a field identifier */
if ((*env)->MonitorEnter(env, obj_this) != 0)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot synchronize on the object");
goto error;
}
state = INMONITOR;
/* check connection state */
npipe = getPipe(env, obj_this);
if ((*env)->ExceptionOccurred(env) != NULL)
goto error;
if (npipe == NULL)
{
ThrowException(env,
"com/sun/star/io/IOException",
"native pipe is not connected");
goto error;
}
/* remove the reference to the pipe */
tclass = (*env)->GetObjectClass(env, obj_this);
if (tclass == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot find class");
goto error;
}
fid = (*env)->GetFieldID(env, tclass, "_nPipeHandle", "J");
if (fid == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot find field");
goto error;
}
(*env)->SetLongField(env, obj_this, fid, (jlong)0);
/* release the pipe */
osl_closePipe(npipe);
osl_releasePipe(npipe);
/* done */
(*env)->MonitorExit(env, obj_this);
return;
error:
switch (state)
{
case INMONITOR:
(*env)->MonitorExit(env, obj_this);
case START:
default:
break;
}
return;
}
/*****************************************************************************/
/*
* Class: com_sun_star_lib_connections_pipe_PipeConnection
* Method: readJNI
* Signature: ([[BI)I
*/
SAL_DLLPUBLIC_EXPORT jint
#if defined WNT
PipeConnection_read
#else
JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_readJNI
#endif
(JNIEnv * env, jobject obj_this, jobjectArray buffer, jint len)
{
enum {
START = 0,
INMONITOR,
AQUIRED,
GOTBUFFER
};
short state = START;
oslPipe npipe; /* native pipe */
void * nbuff = NULL; /* native read buffer */
jbyteArray bytes; /* java read buffer */
jint nread; /* number of bytes has been read */
/* enter monitor */
if ((*env)->MonitorEnter(env, obj_this) != 0)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot synchronize on the object");
goto error;
}
state = INMONITOR;
/* check connection state */
npipe = getPipe(env, obj_this);
if ((*env)->ExceptionOccurred(env) != NULL)
goto error;
if (npipe == NULL)
{
ThrowException(env,
"com/sun/star/io/IOException",
"native pipe is not connected");
goto error;
}
/* aquire pipe */
osl_acquirePipe( npipe );
state = AQUIRED;
/* allocate a buffer */
if ((nbuff = malloc(len)) == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe out of memory");
goto error;
}
state = GOTBUFFER;
/* exit monitor */
(*env)->MonitorExit(env, obj_this);
/* reading */
nread = osl_readPipe(npipe, nbuff, len);
/* enter monitor again */
if ((*env)->MonitorEnter(env, obj_this) != 0)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot synchronize on the object");
goto error;
}
/* copy buffer */
if (nread >= 0)
{
bytes = (*env)->NewByteArray(env, len);
if (bytes == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe out of memory");
goto error;
}
/* save the data */
(*env)->SetByteArrayRegion(env, bytes, 0, len, nbuff);
(*env)->SetObjectArrayElement(env, buffer, 0, bytes);
(*env)->DeleteLocalRef(env, bytes);
}
/* done */
free(nbuff);
if ( state >= AQUIRED )
osl_releasePipe( npipe );
/* exit monitor */
(*env)->MonitorExit(env, obj_this);
return nread;
error:
switch (state)
{
case GOTBUFFER:
free(nbuff);
case INMONITOR:
(*env)->MonitorExit(env, obj_this);
case START:
default:
break;
}
return -1;
}
/*****************************************************************************/
/*
* Class: com_sun_star_lib_connections_pipe_PipeConnection
* Method: writeJNI
* Signature: ([B)V
*/
SAL_DLLPUBLIC_EXPORT void
#if defined WNT
PipeConnection_write
#else
JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_writeJNI
#endif
(JNIEnv * env, jobject obj_this, jbyteArray buffer)
{
enum {
START = 0,
INMONITOR,
GOTBUFFER
};
short state = START;
oslPipe npipe; /* native pipe */
long count; /* number of bytes has been written */
jsize nwrite; /* number of bytes to write */
jbyte * nbuff = NULL; /* native buffer */
if ((*env)->MonitorEnter(env, obj_this) != 0)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot synchronize on the object");
goto error;
}
state = INMONITOR;
/* check connection state */
npipe = getPipe(env, obj_this);
if ((*env)->ExceptionOccurred(env) != NULL)
goto error;
if (npipe == NULL)
{
ThrowException(env,
"com/sun/star/io/IOException",
"native pipe is not connected");
goto error;
}
nwrite = (*env)->GetArrayLength(env, buffer);
if (nwrite > 0)
{
nbuff = (*env)->GetByteArrayElements(env, buffer, NULL);
if (nbuff == NULL)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe out of memory");
goto error;
}
state = GOTBUFFER;
(*env)->MonitorExit(env, obj_this);
/* writing */
count = osl_writePipe(npipe, nbuff, nwrite);
if ((*env)->MonitorEnter(env, obj_this) != 0)
{
ThrowException(env,
"java/lang/RuntimeException",
"native pipe cannot synchronize on the object");
goto error;
}
if (count != nwrite)
{
ThrowException(env,
"com/sun/star/io/IOException",
"native pipe is failed to write");
goto error;
}
}
/* done */
(*env)->ReleaseByteArrayElements(env, buffer, nbuff, JNI_ABORT);
(*env)->MonitorExit(env, obj_this);
return;
error:
switch (state)
{
case GOTBUFFER:
(*env)->ReleaseByteArrayElements(env, buffer, nbuff, JNI_ABORT);
case INMONITOR:
(*env)->MonitorExit(env, obj_this);
case START:
default:
break;
}
return;
}
/*****************************************************************************/
/*
* Class: com_sun_star_lib_connections_pipe_PipeConnection
* Method: flushJNI
* Signature: ()V
*/
SAL_DLLPUBLIC_EXPORT void
#if defined WNT
PipeConnection_flush
#else
JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_flushJNI
#endif
(JNIEnv * env, jobject obj_this)
{
(void) env; /* not used */
(void) obj_this; /* not used */
return;
}