1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "jni.h"
25 #include "osl/security.h"
26 #include <osl/pipe.h>
27 
28 /* On Windows, jpipe.dll must not have dependencies on any other URE DLLs, as
29    Java System.LoadLibrary could otherwise not load it.  Therefore, on Windows,
30    this code goes into a jpipx.dll that the jpipe.dll wrapper loads with
31    LoadLibraryEx(LOAD_WITH_ALTERED_SEARCH_PATH).  The function names in this
32    wrapped code are truncated from the long JNICALL names, as JNICALL causes
33    some "@N" with different numeric values for N (and probably different across
34    32 and 64 bit) to be added to the symbol names, which the calls to
35    GetProcAddress in wrapper/wrapper.c would otheriwse have to take into
36    account.
37 */
38 
39 /*****************************************************************************/
40 /* exception macros */
41 
ThrowException(JNIEnv * env,char const * type,char const * msg)42 static void ThrowException(JNIEnv * env, char const * type, char const * msg) {
43     jclass c;
44     (*env)->ExceptionClear(env);
45     c = (*env)->FindClass(env, type);
46     if (c == NULL) {
47         (*env)->ExceptionClear(env);
48         (*env)->FatalError(env, "JNI FindClass failed");
49     }
50     if ((*env)->ThrowNew(env, c, msg) != 0) {
51         (*env)->ExceptionClear(env);
52         (*env)->FatalError(env, "JNI ThrowNew failed");
53     }
54 }
55 
56 /*****************************************************************************/
57 /* helper functions prototypes */
58 
59 static oslPipe getPipe(JNIEnv * env, jobject obj_this);
60 static rtl_uString * jstring2ustring(JNIEnv * env, jstring jstr);
61 
62 /*****************************************************************************/
63 /* get pipe */
64 
getPipe(JNIEnv * env,jobject obj_this)65 static oslPipe getPipe(JNIEnv * env, jobject obj_this)
66 {
67 	jclass		tclass;
68 	jfieldID	fid;
69     tclass	= (*env)->GetObjectClass(env, obj_this);
70     if (tclass == NULL)
71     {
72         ThrowException(env,
73                        "java/lang/RuntimeException",
74                        "native pipe cannot find class");
75         return NULL;
76     }
77 
78     fid		= (*env)->GetFieldID(env, tclass, "_nPipeHandle", "J");
79     if (fid == NULL)
80     {
81         ThrowException(env,
82                        "java/lang/RuntimeException",
83                        "native pipe cannot find field");
84         return NULL;
85     }
86     return (oslPipe) SAL_INT_CAST(
87         sal_IntPtr, (*env)->GetLongField(env, obj_this, fid));
88 }
89 
90 /*****************************************************************************/
91 /* convert jstring to rtl_uString */
92 
jstring2ustring(JNIEnv * env,jstring jstr)93 static rtl_uString * jstring2ustring(JNIEnv * env, jstring jstr)
94 {
95 	const char *	cstr;
96 	rtl_uString *	ustr	= NULL;
97 	cstr	= (*env)->GetStringUTFChars(env, jstr, NULL);
98 	rtl_uString_newFromAscii(&ustr, cstr);
99 	(*env)->ReleaseStringUTFChars(env, jstr, cstr);
100 	return ustr;
101 }
102 
103 /*****************************************************************************/
104 /*
105  * Class:     com_sun_star_lib_connections_pipe_PipeConnection
106  * Method:    connect
107  * Signature: (Lcom/sun/star/beans/NativeService;)V
108  */
109 SAL_DLLPUBLIC_EXPORT void
110 #if defined WNT
PipeConnection_create(JNIEnv * env,jobject obj_this,jstring name)111 PipeConnection_create
112 #else
113 JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_createJNI
114 #endif
115   (JNIEnv * env, jobject obj_this, jstring name)
116 {
117 	enum {
118 		START	= 0,
119 		INMONITOR,
120 		GOTNAME,
121 		CREATED
122 	};
123 
124 	short		state	= START;
125 
126 	jclass		tclass;
127 	jfieldID	fid;
128 
129     oslSecurity     psec    = osl_getCurrentSecurity();
130 	oslPipe			npipe	= NULL;
131 	rtl_uString *	pname	= NULL;
132     if ((*env)->MonitorEnter(env, obj_this) != 0)
133     {
134         ThrowException(env,
135                        "java/lang/RuntimeException",
136                        "native pipe cannot synchronize on the object");
137         goto error;
138     }
139     state	= INMONITOR;
140 
141     /* check connection state */
142     npipe	= getPipe(env, obj_this);
143     if ((*env)->ExceptionOccurred(env) != NULL)
144         goto error;
145     if (npipe != NULL)
146     {
147         ThrowException(env,
148                        "com/sun/star/io/IOException",
149                        "native pipe is already connected");
150         goto error;
151     }
152 
153     /* save the pipe name */
154     tclass	= (*env)->GetObjectClass(env, obj_this);
155     if (tclass == NULL)
156     {
157         ThrowException(env,
158                        "java/lang/RuntimeException",
159                        "native pipe cannot find class");
160         goto error;
161     }
162 
163     fid		= (*env)->GetFieldID(env, tclass,
164                                  "_aDescription", "Ljava/lang/String;");
165     if (fid == NULL)
166     {
167         ThrowException(env,
168                        "java/lang/RuntimeException",
169                        "native pipe cannot find field");
170         goto error;
171     }
172 
173     (*env)->SetObjectField(env, obj_this, fid, (jobject)name);
174 
175     /* convert pipe name to rtl_uString */
176     pname	= jstring2ustring(env, name);
177     if (pname == NULL)
178     {
179         ThrowException(env,
180                        "java/lang/RuntimeException",
181                        "native pipe cannot convert name");
182         goto error;
183     }
184     state	= GOTNAME;
185 
186     /* try to connect */
187     npipe	= osl_createPipe(pname, osl_Pipe_OPEN, psec);
188     if (npipe == NULL)
189     {
190         ThrowException(env,
191                        "java/lang/RuntimeException",
192                        "cannot create native pipe");
193         goto error;
194     }
195     state	= CREATED;
196 
197     /* save the pipe */
198     tclass	= (*env)->GetObjectClass(env, obj_this);
199     if (tclass == NULL)
200     {
201         ThrowException(env,
202                        "java/lang/RuntimeException",
203                        "native pipe cannot find class");
204         goto error;
205     }
206 
207     fid		= (*env)->GetFieldID(env, tclass, "_nPipeHandle", "J");
208     if (fid == NULL)
209     {
210         ThrowException(env,
211                        "java/lang/RuntimeException",
212                        "native pipe cannot find field");
213         goto error;
214     }
215     (*env)->SetLongField(
216         env, obj_this, fid, SAL_INT_CAST(jlong, (sal_IntPtr) npipe));
217 
218     /* done */
219     rtl_uString_release(pname);
220     (*env)->MonitorExit(env, obj_this);
221     osl_freeSecurityHandle(psec);
222     return;
223 
224  error:
225 	switch (state)
226 	{
227 		case CREATED:
228 			osl_closePipe(npipe);
229 			osl_releasePipe(npipe);
230 		case GOTNAME:
231 			rtl_uString_release(pname);
232 		case INMONITOR:
233 			(*env)->MonitorExit(env, obj_this);
234 		case START:
235             osl_freeSecurityHandle(psec);
236 		default:
237 			break;
238 	}
239 	return;
240 }
241 
242 /*****************************************************************************/
243 /*
244  * Class:     com_sun_star_lib_connections_pipe_PipeConnection
245  * Method:    closeJNI
246  * Signature: ()V
247  */
248 SAL_DLLPUBLIC_EXPORT void
249 #if defined WNT
PipeConnection_close(JNIEnv * env,jobject obj_this)250 PipeConnection_close
251 #else
252 JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_closeJNI
253 #endif
254   (JNIEnv * env, jobject obj_this)
255 {
256 	enum {
257 		START	= 0,
258 		INMONITOR
259 	};
260 
261 	short		state	= START;
262 	oslPipe		npipe;		/* native pipe */
263 	jclass		tclass;		/* this class */
264 	jfieldID	fid;		/* a field identifier */
265 
266     if ((*env)->MonitorEnter(env, obj_this) != 0)
267     {
268         ThrowException(env,
269                        "java/lang/RuntimeException",
270                        "native pipe cannot synchronize on the object");
271         goto error;
272     }
273     state	= INMONITOR;
274 
275     /* check connection state */
276     npipe	= getPipe(env, obj_this);
277     if ((*env)->ExceptionOccurred(env) != NULL)
278         goto error;
279     if (npipe == NULL)
280     {
281         ThrowException(env,
282                        "com/sun/star/io/IOException",
283                        "native pipe is not connected");
284         goto error;
285     }
286 
287     /* remove the reference to the pipe */
288     tclass	= (*env)->GetObjectClass(env, obj_this);
289     if (tclass == NULL)
290     {
291         ThrowException(env,
292                        "java/lang/RuntimeException",
293                        "native pipe cannot find class");
294         goto error;
295     }
296 
297     fid		= (*env)->GetFieldID(env, tclass, "_nPipeHandle", "J");
298     if (fid == NULL)
299     {
300         ThrowException(env,
301                        "java/lang/RuntimeException",
302                        "native pipe cannot find field");
303         goto error;
304     }
305 
306     (*env)->SetLongField(env, obj_this, fid, (jlong)0);
307 
308     /* release the pipe */
309     osl_closePipe(npipe);
310     osl_releasePipe(npipe);
311 
312     /* done */
313     (*env)->MonitorExit(env, obj_this);
314     return;
315 
316  error:
317 	switch (state)
318 	{
319 		case INMONITOR:
320 			(*env)->MonitorExit(env, obj_this);
321 		case START:
322 		default:
323 			break;
324 	}
325 	return;
326 }
327 
328 /*****************************************************************************/
329 /*
330  * Class:     com_sun_star_lib_connections_pipe_PipeConnection
331  * Method:    readJNI
332  * Signature: ([[BI)I
333  */
334 SAL_DLLPUBLIC_EXPORT jint
335 #if defined WNT
PipeConnection_read(JNIEnv * env,jobject obj_this,jobjectArray buffer,jint len)336 PipeConnection_read
337 #else
338 JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_readJNI
339 #endif
340   (JNIEnv * env, jobject obj_this, jobjectArray buffer, jint len)
341 {
342 	enum {
343 		START	= 0,
344 		INMONITOR,
345 		ACQUIRED,
346 		GOTBUFFER
347 	};
348 
349 	short		state	= START;
350     oslPipe     npipe;          /* native pipe */
351     void *      nbuff = NULL;   /* native read buffer */
352     jbyteArray  bytes;          /* java read buffer */
353     jint        nread;          /* number of bytes has been read */
354 
355     /* enter monitor */
356     if ((*env)->MonitorEnter(env, obj_this) != 0)
357     {
358         ThrowException(env,
359                        "java/lang/RuntimeException",
360                        "native pipe cannot synchronize on the object");
361         goto error;
362     }
363     state = INMONITOR;
364 
365     /* check connection state */
366     npipe	= getPipe(env, obj_this);
367     if ((*env)->ExceptionOccurred(env) != NULL)
368         goto error;
369     if (npipe == NULL)
370     {
371         ThrowException(env,
372                        "com/sun/star/io/IOException",
373                        "native pipe is not connected");
374         goto error;
375     }
376 
377     /* acquire pipe */
378     osl_acquirePipe( npipe );
379     state = ACQUIRED;
380 
381     /* allocate a buffer */
382     if ((nbuff = malloc(len)) == NULL)
383     {
384         ThrowException(env,
385                        "java/lang/RuntimeException",
386                        "native pipe out of memory");
387         goto error;
388     }
389 
390     state = GOTBUFFER;
391 
392     /* exit monitor */
393     (*env)->MonitorExit(env, obj_this);
394 
395     /* reading */
396     nread = osl_readPipe(npipe, nbuff, len);
397 
398     /* enter monitor again */
399     if ((*env)->MonitorEnter(env, obj_this) != 0)
400     {
401         ThrowException(env,
402                        "java/lang/RuntimeException",
403                        "native pipe cannot synchronize on the object");
404         goto error;
405     }
406 
407     /* copy buffer */
408     if (nread >= 0)
409     {
410         bytes	= (*env)->NewByteArray(env, len);
411         if (bytes == NULL)
412         {
413             ThrowException(env,
414                            "java/lang/RuntimeException",
415                            "native pipe out of memory");
416             goto error;
417         }
418 
419         /* save the data */
420         (*env)->SetByteArrayRegion(env, bytes, 0, len, nbuff);
421         (*env)->SetObjectArrayElement(env, buffer, 0, bytes);
422         (*env)->DeleteLocalRef(env, bytes);
423     }
424 
425     /* done */
426     free(nbuff);
427     if ( state >= ACQUIRED )
428         osl_releasePipe( npipe );
429 
430     /* exit monitor */
431     (*env)->MonitorExit(env, obj_this);
432     return nread;
433 
434  error:
435 	switch (state)
436 	{
437 		case GOTBUFFER:
438 			free(nbuff);
439 		case INMONITOR:
440 			(*env)->MonitorExit(env, obj_this);
441 		case START:
442 		default:
443 			break;
444 	}
445 	return -1;
446 }
447 
448 /*****************************************************************************/
449 /*
450  * Class:     com_sun_star_lib_connections_pipe_PipeConnection
451  * Method:    writeJNI
452  * Signature: ([B)V
453  */
454 SAL_DLLPUBLIC_EXPORT void
455 #if defined WNT
PipeConnection_write(JNIEnv * env,jobject obj_this,jbyteArray buffer)456 PipeConnection_write
457 #else
458 JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_writeJNI
459 #endif
460   (JNIEnv * env, jobject obj_this, jbyteArray buffer)
461 {
462 	enum {
463 		START	= 0,
464 		INMONITOR,
465 		GOTBUFFER
466 	};
467 
468 	short	state	= START;
469     oslPipe npipe;          /* native pipe */
470     long    count;          /* number of bytes has been written */
471     jsize   nwrite;         /* number of bytes to write */
472     jbyte * nbuff = NULL;   /* native buffer */
473 
474     if ((*env)->MonitorEnter(env, obj_this) != 0)
475     {
476         ThrowException(env,
477                        "java/lang/RuntimeException",
478                        "native pipe cannot synchronize on the object");
479         goto error;
480     }
481     state	= INMONITOR;
482 
483     /* check connection state */
484     npipe	= getPipe(env, obj_this);
485     if ((*env)->ExceptionOccurred(env) != NULL)
486         goto error;
487     if (npipe == NULL)
488     {
489         ThrowException(env,
490                        "com/sun/star/io/IOException",
491                        "native pipe is not connected");
492         goto error;
493     }
494 
495     nwrite	= (*env)->GetArrayLength(env, buffer);
496     if (nwrite > 0)
497     {
498         nbuff	= (*env)->GetByteArrayElements(env, buffer, NULL);
499         if (nbuff == NULL)
500         {
501             ThrowException(env,
502                            "java/lang/RuntimeException",
503                            "native pipe out of memory");
504             goto error;
505         }
506         state	= GOTBUFFER;
507 
508         (*env)->MonitorExit(env, obj_this);
509         /* writing */
510         count	= osl_writePipe(npipe, nbuff, nwrite);
511         if ((*env)->MonitorEnter(env, obj_this) != 0)
512         {
513             ThrowException(env,
514                            "java/lang/RuntimeException",
515                            "native pipe cannot synchronize on the object");
516             goto error;
517         }
518         if (count != nwrite)
519         {
520             ThrowException(env,
521                            "com/sun/star/io/IOException",
522                            "native pipe is failed to write");
523             goto error;
524         }
525     }
526     /* done */
527     (*env)->ReleaseByteArrayElements(env, buffer, nbuff, JNI_ABORT);
528     (*env)->MonitorExit(env, obj_this);
529     return;
530 
531  error:
532 	switch (state)
533 	{
534 		case GOTBUFFER:
535 			(*env)->ReleaseByteArrayElements(env, buffer, nbuff, JNI_ABORT);
536 		case INMONITOR:
537 			(*env)->MonitorExit(env, obj_this);
538 		case START:
539 		default:
540 			break;
541 	}
542 	return;
543 }
544 
545 /*****************************************************************************/
546 /*
547  * Class:     com_sun_star_lib_connections_pipe_PipeConnection
548  * Method:    flushJNI
549  * Signature: ()V
550  */
551 SAL_DLLPUBLIC_EXPORT void
552 #if defined WNT
PipeConnection_flush(JNIEnv * env,jobject obj_this)553 PipeConnection_flush
554 #else
555 JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_flushJNI
556 #endif
557   (JNIEnv * env, jobject obj_this)
558 {
559     (void) env; /* not used */
560     (void) obj_this; /* not used */
561     return;
562 }
563