xref: /AOO41X/main/jurt/source/pipe/com_sun_star_lib_connections_pipe_PipeConnection.c (revision 5fa9200e5407b17ec3f8d5becf0382bd524a8844)
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         AQUIRED,
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     /* aquire pipe */
378     osl_acquirePipe( npipe );
379     state = AQUIRED;
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 >= AQUIRED )
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