xref: /AOO42X/main/jurt/source/pipe/com_sun_star_lib_connections_pipe_PipeConnection.c (revision 41d20774a16afad938c3dac4fc9bd4f17ded7904)
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