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