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