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