1 /* gnu_java_nio_VMChannel.c -
2    Copyright (C) 2003, 2004, 2005, 2006, 2007  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42 
43 #include <config-int.h>
44 
45 #include <sys/types.h>
46 #ifdef HAVE_SYS_MMAN_H
47 #include <sys/mman.h>
48 #endif
49 #include <sys/socket.h>
50 #include <sys/stat.h>
51 #include <sys/uio.h>
52 
53 #include <netinet/in.h>
54 
55 #include <stdlib.h>
56 #include <errno.h>
57 #include <unistd.h>
58 #include <string.h>
59 
60 #include <jni.h>
61 #include <jcl.h>
62 
63 #include "cpio.h"
64 #include "gnu_java_nio_VMChannel.h"
65 #include "javanio.h"
66 
67 #ifdef HAVE_FCNTL_H
68 #include <fcntl.h>
69 #endif /* HAVE_FCNTL_H */
70 
71 #if defined(HAVE_SYS_IOCTL_H)
72 #define BSD_COMP /* Get FIONREAD on Solaris2 */
73 #include <sys/ioctl.h>
74 #endif
75 #if defined(HAVE_SYS_FILIO_H) /* Get FIONREAD on Solaris 2.5 */
76 #include <sys/filio.h>
77 #endif
78 
79 #define CONNECT_EXCEPTION "java/net/ConnectException"
80 #define IO_EXCEPTION "java/io/IOException"
81 #define SOCKET_EXCEPTION "java/net/SocketException"
82 #define INTERRUPTED_IO_EXCEPTION "java/io/InterruptedIOException"
83 #define NON_READABLE_CHANNEL_EXCEPTION "java/nio/channels/NonReadableChannelException"
84 #define NON_WRITABLE_CHANNEL_EXCEPTION "java/nio/channels/NonWritableChannelException"
85 #define SOCKET_TIMEOUT_EXCEPTION "java/net/SocketTimeoutException"
86 
87 /* Align a value up or down to a multiple of the pagesize. */
88 #define ALIGN_DOWN(p,s) ((p) - ((p) % (s)))
89 #define ALIGN_UP(p,s) ((p) + ((s) - ((p) % (s))))
90 
91 /*
92  * Limit to maximum of 16 buffers
93  */
94 #define JCL_IOV_MAX 16
95 
96 #ifdef __cplusplus
97 extern "C"
98 {
99 #endif
100 
101 enum JCL_buffer_type { DIRECT, HEAP, ARRAY, UNKNOWN };
102 
103 struct JCL_buffer
104 {
105   enum JCL_buffer_type type;
106   jbyte *ptr;
107   jint offset;
108   jint position;
109   jint limit;
110   jint count;
111 };
112 
113 jmethodID get_method_id(JNIEnv *, jclass, const char *, const char *);
114 void JCL_print_buffer(JNIEnv *, struct JCL_buffer *);
115 int JCL_init_buffer(JNIEnv *, struct JCL_buffer *, jobject);
116 void JCL_release_buffer(JNIEnv *, struct JCL_buffer *, jobject, jint);
117 void JCL_cleanup_buffers(JNIEnv *, struct JCL_buffer *, jint, jobjectArray, jint, jlong);
118 int JCL_thread_interrupted(JNIEnv *);
119 
120 static jfieldID address_fid;
121 static jmethodID get_position_mid;
122 static jmethodID set_position_mid;
123 static jmethodID get_limit_mid;
124 static jmethodID set_limit_mid;
125 static jmethodID has_array_mid;
126 static jmethodID array_mid;
127 static jmethodID array_offset_mid;
128 static jmethodID thread_interrupted_mid;
129 static jclass vm_channel_class;
130 
131 jmethodID
get_method_id(JNIEnv * env,jclass clazz,const char * name,const char * sig)132 get_method_id(JNIEnv *env,  jclass clazz, const char *name,
133 	          const char *sig)
134 {
135   jmethodID mid = (*env)->GetMethodID(env, clazz, name, sig);
136 /*   NIODBG("name: %s; sig: %s", name, sig); */
137   if (mid == NULL)
138     {
139       JCL_ThrowException(env, "java/lang/InternalError", name);
140       return NULL;
141     }
142 
143   return mid;
144 }
145 
146 inline void
JCL_print_buffer(JNIEnv * env,struct JCL_buffer * buf)147 JCL_print_buffer(JNIEnv *env __attribute__((__unused__)), struct JCL_buffer *buf)
148 {
149   fprintf (stderr, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr);
150 }
151 
152 
153 int
JCL_init_buffer(JNIEnv * env,struct JCL_buffer * buf,jobject bbuf)154 JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf)
155 {
156   void *addr = (*env)->GetDirectBufferAddress (env, bbuf);
157 
158 /*   NIODBG("buf: %p; bbuf: %p; addr: %p", (void *) buf, bbuf, addr); */
159 
160   buf->position = (*env)->CallIntMethod(env, bbuf, get_position_mid);
161   buf->limit = (*env)->CallIntMethod(env, bbuf, get_limit_mid);
162   buf->offset = 0;
163   buf->count = 0;
164   buf->type = UNKNOWN;
165 
166   if (addr != NULL)
167     {
168       buf->ptr = (jbyte *) addr;
169       buf->type = DIRECT;
170     }
171   else
172     {
173       jboolean has_array;
174       has_array = (*env)->CallBooleanMethod(env, bbuf, has_array_mid);
175 
176       if (has_array == JNI_TRUE)
177         {
178           jbyteArray arr;
179           buf->offset = (*env)->CallIntMethod(env, bbuf, array_offset_mid);
180           arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
181           buf->ptr = (*env)->GetByteArrayElements(env, arr, 0);
182           buf->type = ARRAY;
183           (*env)->DeleteLocalRef(env, arr);
184         }
185       else
186         {
187           jobject address = (*env)->GetObjectField (env, bbuf, address_fid);
188           if (address == NULL)
189             return -1; /* XXX handle non-array, non-native buffers? */
190           buf->ptr = (jbyte *) JCL_GetRawData(env, address);
191           buf->type = HEAP;
192           (*env)->DeleteLocalRef(env, address);
193         }
194     }
195 
196   return 0;
197 }
198 
199 void
JCL_release_buffer(JNIEnv * env,struct JCL_buffer * buf,jobject bbuf,jint action)200 JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf,
201     jint action)
202 {
203   jbyteArray arr;
204 
205 /*   NIODBG("buf: %p; bbuf: %p; action: %x", (void *) buf, bbuf, action); */
206 
207   /* Set the position to the appropriate value */
208   if (buf->count > 0)
209     {
210       jobject bbufTemp;
211       bbufTemp = (*env)->CallObjectMethod(env, bbuf, set_position_mid,
212                                           buf->position + buf->count);
213       (*env)->DeleteLocalRef(env, bbufTemp);
214     }
215 
216   switch (buf->type)
217     {
218     case DIRECT:
219     case HEAP:
220       break;
221     case ARRAY:
222       arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
223       (*env)->ReleaseByteArrayElements(env, arr, buf->ptr, action);
224       (*env)->DeleteLocalRef(env, arr);
225       break;
226     case UNKNOWN:
227       /* TODO: Handle buffers that are not direct or array backed */
228       break;
229     }
230 }
231 
232 void
JCL_cleanup_buffers(JNIEnv * env,struct JCL_buffer * bi_list,jint vec_len,jobjectArray bbufs,jint offset,jlong num_bytes)233 JCL_cleanup_buffers(JNIEnv *env,
234                     struct JCL_buffer *bi_list,
235                     jint vec_len,
236                     jobjectArray bbufs,
237                     jint offset,
238                     jlong num_bytes)
239 {
240   jint i;
241 
242 /*   NIODBG("bi_list: %p; vec_len: %d; bbufs: %p; offset: %d; num_bytes: %lld", */
243 /*       (void *) bi_list, vec_len, bbufs, offset, num_bytes); */
244 
245   /* Update all of the bbufs with the approriate information */
246   for (i = 0; i < vec_len; i++)
247     {
248       struct JCL_buffer* buf;
249       jobject bbuf;
250 
251       buf = &bi_list[i];
252       bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
253 
254       if (num_bytes > (buf->limit - buf->position))
255         buf->count = (buf->limit - buf->position);
256       else
257         buf->count = num_bytes;
258 
259       num_bytes -= buf->count;
260 
261       JCL_release_buffer(env, buf, bbuf, JNI_ABORT);
262       (*env)->DeleteLocalRef(env, bbuf);
263     }
264 }
265 
266 
267 int
JCL_thread_interrupted(JNIEnv * env)268 JCL_thread_interrupted(JNIEnv *env)
269 {
270   return (int) (*env)->CallStaticBooleanMethod(env, vm_channel_class,
271 					       thread_interrupted_mid);
272 }
273 
274 
275 /*
276  * Class:     gnu_java_nio_VMChannel
277  * Method:    stdin_fd
278  * Signature: ()I
279  */
280 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_stdin_1fd(JNIEnv * env,jclass c)281 Java_gnu_java_nio_VMChannel_stdin_1fd (JNIEnv *env __attribute__((unused)),
282                                        jclass c __attribute__((unused)))
283 {
284 /*   NIODBG("%d", fileno (stdin)); */
285   return fileno (stdin);
286 }
287 
288 
289 /*
290  * Class:     gnu_java_nio_VMChannel
291  * Method:    stdout_fd
292  * Signature: ()I
293  */
294 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_stdout_1fd(JNIEnv * env,jclass c)295 Java_gnu_java_nio_VMChannel_stdout_1fd (JNIEnv *env __attribute__((unused)),
296                                        jclass c __attribute__((unused)))
297 {
298 /*   NIODBG("%d", fileno (stdout)); */
299   return fileno (stdout);
300 }
301 
302 
303 /*
304  * Class:     gnu_java_nio_VMChannel
305  * Method:    stderr_fd
306  * Signature: ()I
307  */
308 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_stderr_1fd(JNIEnv * env,jclass c)309 Java_gnu_java_nio_VMChannel_stderr_1fd (JNIEnv *env __attribute__((unused)),
310                                        jclass c __attribute__((unused)))
311 {
312 /*   NIODBG("%d", fileno (stderr)); */
313   return fileno (stderr);
314 }
315 
316 
317 JNIEXPORT void JNICALL
Java_gnu_java_nio_VMChannel_initIDs(JNIEnv * env,jclass clazz)318 Java_gnu_java_nio_VMChannel_initIDs  (JNIEnv *env,
319 	jclass clazz)
320 {
321   jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer");
322   jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer");
323 
324 /*   NIODBG("%s", "..."); */
325 
326   address_fid = (*env)->GetFieldID(env, bufferClass, "address",
327                                    "Lgnu/classpath/Pointer;");
328   if (address_fid == NULL)
329     {
330   	  JCL_ThrowException(env, "java/lang/InternalError",
331   	  	"Unable to find internal field");
332       return;
333     }
334 
335   get_position_mid = get_method_id(env, bufferClass, "position", "()I");
336   set_position_mid = get_method_id(env, bufferClass, "position",
337                                    "(I)Ljava/nio/Buffer;");
338   get_limit_mid = get_method_id(env, bufferClass, "limit", "()I");
339   set_limit_mid = get_method_id(env, bufferClass, "limit",
340                                 "(I)Ljava/nio/Buffer;");
341   has_array_mid = get_method_id(env, byteBufferClass, "hasArray", "()Z");
342   array_mid = get_method_id(env, byteBufferClass, "array", "()[B");
343   array_offset_mid = get_method_id(env, byteBufferClass, "arrayOffset", "()I");
344 
345   vm_channel_class = clazz;
346   thread_interrupted_mid = (*env)->GetStaticMethodID(env, clazz,
347                                                   "isThreadInterrupted",
348                                                   "()Z");
349 }
350 
351 JNIEXPORT void JNICALL
Java_gnu_java_nio_VMChannel_setBlocking(JNIEnv * env,jobject o,jint fd,jboolean blocking)352 Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env,
353 	jobject o __attribute__ ((__unused__)),
354 	jint fd,
355 	jboolean blocking)
356 {
357   int opts;
358 
359 /*   NIODBG("fd: %d; blocking: %d", fd, blocking); */
360 
361   opts = fcntl(fd, F_GETFL);
362   if (opts < 0)
363     {
364       JCL_ThrowException(env, IO_EXCEPTION,
365         "Failed to get flags for file desriptor");
366       return;
367     }
368 
369   if (blocking == JNI_TRUE)
370     opts &= ~(O_NONBLOCK);
371   else
372     opts |= O_NONBLOCK;
373 
374   opts = fcntl(fd, F_SETFL, opts);
375 
376   if (opts < 0)
377     {
378       JCL_ThrowException(env, IO_EXCEPTION,
379         "Failed to set flags for file desriptor");
380       return;
381     }
382 }
383 
384 /* Return true if fd is in non-blocking mode. */
385 static jboolean
is_non_blocking_fd(jint fd)386 is_non_blocking_fd(jint fd)
387 {
388   int opts;
389   opts = fcntl(fd, F_GETFL);
390   if (opts == -1)
391     {
392       /* Assume blocking on error. */
393       return 0;
394     }
395   return (opts & O_NONBLOCK) != 0;
396 }
397 
398 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2(JNIEnv * env,jobject o,jint fd,jobject bbuf)399 Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
400                                                            jobject o __attribute__ ((__unused__)),
401                                                            jint fd,
402                                                            jobject bbuf)
403 {
404 #ifdef HAVE_READ
405   jint len;
406   ssize_t result;
407   struct JCL_buffer buf;
408   int tmp_errno;
409 
410 /*   NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
411 
412   if (JCL_init_buffer(env, &buf, bbuf) < 0)
413     {
414       /* TODO: Rethrown exception */
415       JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
416       return -1;
417     }
418 
419   len = buf.limit - buf.position;
420 
421   if (len == 0)
422     {
423       JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
424       return 0;
425     }
426 
427   do
428     {
429       result = cpnio_read (fd, &(buf.ptr[buf.position + buf.offset]), len);
430       tmp_errno = errno;
431     }
432   while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
433   errno = tmp_errno;
434 
435   if (result == 0)
436     {
437       result = -1;
438       buf.count = 0;
439     }
440   else if (result == -1)
441     {
442       buf.count = 0;
443       if (errno == EAGAIN)
444         {
445           if (is_non_blocking_fd(fd))
446             {
447               /* Non-blocking */
448               result = 0;
449             }
450           else
451             {
452               /* Read timeout on a socket with SO_RCVTIMEO != 0. */
453               JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
454               JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
455               return -1;
456             }
457         }
458       else if (errno == EBADF) /* Bad fd */
459         {
460           JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
461           JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION,
462                               strerror(errno));
463           return -1;
464         }
465       else if (EINTR == errno) /* read interrupted */
466         {
467           JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
468           JCL_ThrowException(env, INTERRUPTED_IO_EXCEPTION, strerror (errno));
469           return -1;
470         }
471       else
472         {
473           JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
474       	  JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
475       	  return -1;
476         }
477     }
478   else
479     buf.count = result;
480 
481   JCL_release_buffer(env, &buf, bbuf, 0);
482 
483   return result;
484 #else
485   (void) fd;
486   (void) bbuf;
487   JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
488   return -1;
489 #endif /* HAVE_READ */
490 }
491 
492 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2(JNIEnv * env,jobject o,jint fd,jobject bbuf)493 Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
494                                                             jobject o __attribute__ ((__unused__)),
495                                                             jint fd,
496                                                             jobject bbuf)
497 {
498 #ifdef HAVE_WRITE
499   jint len;
500   ssize_t result;
501   struct JCL_buffer buf;
502   int tmp_errno;
503 
504 /*   NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
505 
506   if (JCL_init_buffer(env, &buf, bbuf) < 0)
507     {
508       /* TODO: Rethrown exception */
509       JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
510       return -1;
511     }
512 
513   len = buf.limit - buf.position;
514 
515   if (len == 0)
516     {
517       JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
518       return 0;
519     }
520 
521   do
522     {
523       result = cpnio_write (fd, &(buf.ptr[buf.position + buf.offset]), len);
524       tmp_errno = errno;
525     }
526   while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
527   errno = tmp_errno;
528 
529   buf.count = result;
530 
531   if (result == -1)
532     {
533       if (errno == EAGAIN) /* Non-blocking */
534         {
535           result = 0;
536         }
537       else
538         {
539           JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
540           JCL_ThrowException(env, IO_EXCEPTION, strerror(errno));
541           return -1;
542         }
543     }
544 
545   JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
546 
547   return result;
548 #else
549   (void) fd;
550   (void) bbuf;
551   JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
552   return -1;
553 #endif /* HAVE_WRITE */
554 }
555 
556 
557 /*
558  * Implementation of a scattering read.  Will use the appropriate
559  * vector based read call (currently readv on Linux).
560  *
561  * This has a limit to the number of buffers that will be read.  It
562  * will not make muliple readv calls.  This is to ensure that operations
563  * are atomic.  Currently it is limited to 16 buffers.  This is for
564  * compatibiliy with Sun.
565  */
566 JNIEXPORT jlong JNICALL
Java_gnu_java_nio_VMChannel_readScattering(JNIEnv * env,jobject o,jint fd,jobjectArray bbufs,jint offset,jint length)567 Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env,
568 	jobject o __attribute__ ((__unused__)),
569 	jint fd,
570 	jobjectArray bbufs,
571 	jint offset,
572 	jint length)
573 {
574   jint i;
575 /*   jboolean is_error = JNI_FALSE; */
576 /*   char *error_msg; */
577   struct iovec buffers[JCL_IOV_MAX];
578   struct JCL_buffer bi_list[JCL_IOV_MAX];
579   ssize_t result;
580   jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
581   jlong bytes_read = 0;
582   int tmp_errno;
583 
584 /*   NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
585 /*          fd, bbufs, offset, length); */
586 
587   /* Build the vector of buffers to read into */
588   for (i = 0; i < vec_len; i++)
589     {
590       struct JCL_buffer* buf;
591       jobject bbuf;
592 
593       buf = &bi_list[i];
594       bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
595 
596       JCL_init_buffer(env, buf, bbuf);
597 
598 /*       JCL_print_buffer (env, buf); */
599 
600       buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
601       buffers[i].iov_len = buf->limit - buf->position;
602       (*env)->DeleteLocalRef(env, bbuf);
603     }
604 
605   /* Work the scattering magic */
606   do
607     {
608       result = cpnio_readv (fd, buffers, vec_len);
609       tmp_errno = errno;
610     }
611   while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
612   errno = tmp_errno;
613   bytes_read = (jlong) result;
614 
615   /* Handle the response */
616   if (result < 0)
617     {
618       if (errno == EAGAIN)
619         {
620           if (is_non_blocking_fd(fd))
621             {
622               /* Non-blocking */
623               result = 0;
624             }
625           else
626             {
627               /* Read timeout on a socket with SO_RCVTIMEO != 0. */
628               JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
629               JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
630               return -1;
631             }
632         }
633       else if (errno == EBADF) /* Bad fd */
634         {
635           JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
636           JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION,
637                               strerror(errno));
638           return -1;
639         }
640       else
641         {
642           JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
643           JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
644           return -1;
645         }
646       bytes_read = 0;
647     }
648   else if (result == 0) /* EOF */
649     {
650       result = -1;
651     }
652 
653   JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
654 
655   return (jlong) result;
656 }
657 
658 
659 /*
660  * Implementation of a gathering write.  Will use the appropriate
661  * vector based read call (currently readv on Linux).
662  *
663  * This has a limit to the number of buffers that will be read.  It
664  * will not make muliple readv calls.  This is to ensure that operations
665  * are atomic.  Currently it is limited to 16 buffers.  This is for
666  * compatibiliy with Sun.
667  */
668 JNIEXPORT jlong JNICALL
Java_gnu_java_nio_VMChannel_writeGathering(JNIEnv * env,jobject o,jint fd,jobjectArray bbufs,jint offset,jint length)669 Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env,
670 	jobject o __attribute__ ((__unused__)),
671 	jint fd,
672 	jobjectArray bbufs,
673 	jint offset,
674 	jint length)
675 {
676   int i;
677 /*   jboolean is_error = JNI_FALSE; */
678 /*   char *error_msg; */
679   struct iovec buffers[JCL_IOV_MAX];
680   struct JCL_buffer bi_list[JCL_IOV_MAX];
681   ssize_t result;
682   jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
683   jlong bytes_written;
684   int tmp_errno;
685 
686 /*   NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
687 /*          fd, bbufs, offset, length); */
688 
689   /* Build the vector of buffers to read into */
690   for (i = 0; i < vec_len; i++)
691     {
692       struct JCL_buffer* buf;
693       jobject bbuf;
694 
695       buf = &bi_list[i];
696       bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
697 
698       JCL_init_buffer(env, buf, bbuf);
699 
700 /*       JCL_print_buffer(env, buf); */
701 
702       buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
703       buffers[i].iov_len = buf->limit - buf->position;
704       (*env)->DeleteLocalRef(env, bbuf);
705     }
706 
707   /* Work the gathering magic */
708   do
709     {
710       result = cpnio_writev (fd, buffers, vec_len);
711       tmp_errno = errno;
712     }
713   while (result == -1 && tmp_errno == EINTR && ! JCL_thread_interrupted(env));
714   errno = tmp_errno;
715 
716   bytes_written = (jlong) result;
717 
718   if (result < 0)
719     {
720       bytes_written = 0;
721       if (errno == EAGAIN) /* Non blocking */
722         result = 0;
723       else if (errno == EBADF) /* Bad fd */
724         {
725           JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
726                               bytes_written);
727           JCL_ThrowException (env, NON_WRITABLE_CHANNEL_EXCEPTION,
728                               strerror(errno));
729           return -1;
730         }
731       else
732         {
733           JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
734                               bytes_written);
735           JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
736           return -1;
737         }
738     }
739   else if (result == 0) /* EOF??  Does this happen on a write */
740     result = -1;
741 
742   JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_written);
743   return (jlong) result;
744 }
745 
746 
747 /*
748  * Class:     gnu_java_nio_VMChannel
749  * Method:    receive
750  * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I
751  */
752 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_receive(JNIEnv * env,jclass c,jint fd,jobject dst,jobject addrPort)753 Java_gnu_java_nio_VMChannel_receive (JNIEnv *env,
754                                      jclass c __attribute__((unused)),
755                                      jint fd, jobject dst, jobject addrPort)
756 {
757 #ifdef HAVE_RECVFROM
758   char *addrPortPtr = (*env)->GetDirectBufferAddress (env, addrPort);
759   struct JCL_buffer buf;
760 #ifdef HAVE_INET6
761   struct sockaddr_in6 sock_storage;
762   struct sockaddr_in6 *sock6;
763   socklen_t slen = sizeof (struct sockaddr_in6);
764 #else
765   struct sockaddr_in sock_storage;
766   socklen_t slen = sizeof (struct sockaddr_in);
767 #endif /* HAVE_INET6 */
768   struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
769   struct sockaddr_in *sock4;
770   int ret;
771   jint result = -1;
772 
773   if (JCL_init_buffer (env, &buf, dst) == -1)
774     JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
775 
776 #ifndef HAVE_MSG_WAITALL
777 #define MSG_WAITALL       0
778 #endif
779 
780   ret = cpnio_recvfrom (fd, &(buf.ptr[buf.position + buf.offset]),
781                         buf.limit - buf.position, MSG_WAITALL,
782                         sockaddr, &slen);
783 
784   if (-1 == ret)
785     {
786       JCL_release_buffer (env, &buf, dst, JNI_ABORT);
787       if (EINTR == errno)
788         JCL_ThrowException (env, "java/io/InterruptedIOException", strerror (errno));
789       else if (EAGAIN == errno)
790         {
791           /* If the socket is in blocking mode, our timeout expired. */
792           int val = fcntl (fd, F_GETFL, 0);
793           if (val == -1)
794             JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
795           else if ((val & O_NONBLOCK) == 0)
796             JCL_ThrowException (env, "java/net/SocketTimeoutException",
797                                 "read timed out");
798         }
799       else
800         JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
801       return 0;
802     }
803 
804   if (sockaddr->sa_family == AF_INET)
805     {
806       sock4 = (struct sockaddr_in *) sockaddr;
807       memcpy (addrPortPtr, &(sock4->sin_addr.s_addr), 4);
808       ;memcpy (addrPortPtr + 4, &(sock4->sin_port), 2);
809       result = 4;
810     }
811 #ifdef HAVE_INET6
812   else if (sockaddr->sa_family == AF_INET6)
813     {
814       sock6 = (struct sockaddr_in6 *) sockaddr;
815       memcpy (addrPortPtr, &(sock6->sin6_addr.s6_addr), 16);
816       memcpy (addrPortPtr + 16, &(sock6->sin6_port), 2);
817       result = 16;
818     }
819 #endif /* HAVE_INET6 */
820   else if (ret == 0)
821     {
822       result = 0;
823     }
824   else
825     {
826       JCL_ThrowException (env, "java/net/SocketException",
827                           "unsupported address type returned");
828     }
829 
830   buf.count += ret;
831   JCL_release_buffer (env, &buf, dst, 0);
832   return result;
833 #else
834   (void) fd;
835   (void) dst;
836   (void) addrPort;
837   JCL_ThrowException (env, IO_EXCEPTION, "recvfrom not supported");
838 #endif /* HAVE_RECVFROM */
839 }
840 
841 
842 /*
843  * Class:     gnu_java_nio_VMChannel
844  * Method:    send
845  * Signature: (Ljava/nio/ByteBuffer;[BI)I
846  */
847 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_send(JNIEnv * env,jclass c,int fd,jobject src,jbyteArray addr,jint port)848 Java_gnu_java_nio_VMChannel_send (JNIEnv *env,
849                                   jclass c __attribute__((unused)),
850                                   int fd, jobject src, jbyteArray addr, jint port)
851 {
852 #ifdef HAVE_SENDTO
853   struct sockaddr_in sockaddr;
854   jbyte *elems;
855   struct JCL_buffer buf;
856   int ret;
857 
858 /*   NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
859 /*          fd, src, addr, port); */
860 
861   if (JCL_init_buffer (env, &buf, src) == -1)
862     {
863       JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
864       return -1;
865     }
866 
867 /*   JCL_print_buffer (env, &buf); */
868 
869   elems = (*env)->GetByteArrayElements (env, addr, NULL);
870 
871   sockaddr.sin_family = AF_INET;
872   sockaddr.sin_addr.s_addr = *((uint32_t *) elems);
873   sockaddr.sin_port = htons (port);
874 
875   do
876     {
877       ret = cpnio_sendto (fd, &(buf.ptr[buf.position + buf.offset]),
878                           buf.limit - buf.position,
879                           0, (const struct sockaddr *) &sockaddr,
880                           sizeof (struct sockaddr_in));
881     }
882   while (-1 == ret && EINTR == errno);
883 
884   (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
885 
886   if (-1 == ret)
887     {
888       if (errno != EAGAIN)
889         JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
890       JCL_release_buffer (env, &buf, src, JNI_ABORT);
891       return 0;
892     }
893 
894   buf.count += ret;
895   JCL_release_buffer (env, &buf, src, JNI_ABORT);
896   return ret;
897 #else
898   (void) fd;
899   (void) src;
900   (void) addr;
901   (void) port;
902 #endif /* HAVE_SENDTO */
903 }
904 
905 
906 /*
907  * Class:     gnu_java_nio_VMChannel
908  * Method:    send6
909  * Signature: (Ljava/nio/ByteBuffer;[BI)I
910  */
911 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_send6(JNIEnv * env,jclass c,int fd,jobject src,jbyteArray addr,jint port)912 Java_gnu_java_nio_VMChannel_send6 (JNIEnv *env,
913                                    jclass c __attribute__((unused)),
914                                    int fd, jobject src, jbyteArray addr, jint port)
915 {
916 #if defined(HAVE_SENDTO) && defined(HAVE_INET6)
917   struct sockaddr_in6 sockaddr;
918   jbyte *elems;
919   struct JCL_buffer buf;
920   int ret;
921 
922 /*   NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
923 /*          fd, src, addr, port); */
924 
925   if (JCL_init_buffer (env, &buf, src) == -1)
926     {
927       JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
928       return -1;
929     }
930 
931 /*   JCL_print_buffer (env, &buf); */
932 
933   elems = (*env)->GetByteArrayElements (env, addr, NULL);
934 
935   sockaddr.sin6_family = AF_INET6;
936   memcpy (&sockaddr.sin6_addr.s6_addr, elems, 16);
937   sockaddr.sin6_port = htons (port);
938 
939   do
940     {
941       ret = cpnio_sendto (fd, (const void *) (buf.ptr + buf.offset),
942                           buf.limit - buf.position,
943                           0, (const struct sockaddr *) &sockaddr,
944                           sizeof (struct sockaddr_in6));
945     }
946   while (-1 == ret && EINTR == errno);
947 
948   (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
949 
950   if (-1 == ret)
951     {
952       if (errno != EAGAIN)
953         JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
954       JCL_release_buffer (env, &buf, src, JNI_ABORT);
955       return 0;
956     }
957 
958   buf.count += ret;
959   JCL_release_buffer (env, &buf, src, JNI_ABORT);
960   return ret;
961 #else
962   (void) fd;
963   (void) src;
964   (void) addr;
965   (void) port;
966   JCL_ThrowException (env, IO_EXCEPTION, "IPv6 sendto not supported");
967   return -1;
968 #endif /* HAVE_SENDTO && HAVE_INET6 */
969 }
970 
971 
972 /*
973  * Class:     gnu_java_nio_VMChannel
974  * Method:    read
975  * Signature: (I)I
976  */
977 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_read__I(JNIEnv * env,jclass c,jint fd)978 Java_gnu_java_nio_VMChannel_read__I (JNIEnv *env,
979                                      jclass c __attribute__((unused)),
980                                      jint fd)
981 {
982 #ifdef HAVE_READ
983   char in;
984   int ret;
985   int tmp_errno;
986 
987 /*   NIODBG("fd: %d", fd); */
988 
989   do
990     {
991       ret = cpnio_read (fd, &in, 1);
992       tmp_errno = errno;
993     }
994   while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
995   errno = tmp_errno;
996 
997   if (-1 == ret)
998     {
999       if (errno == EAGAIN && !is_non_blocking_fd(fd))
1000         {
1001           /* Read timeout on a socket with SO_RCVTIMEO != 0. */
1002           JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
1003         }
1004       else
1005         JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1006       return -1;
1007     }
1008 
1009   if (0 == ret)
1010     return -1;
1011 
1012   return (in & 0xFF);
1013 #else
1014   (void) fd;
1015   JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
1016 #endif /* HAVE_READ */
1017 }
1018 
1019 
1020 /*
1021  * Class:     gnu_java_nio_VMChannel
1022  * Method:    write
1023  * Signature: (I)V
1024  */
1025 JNIEXPORT void JNICALL
Java_gnu_java_nio_VMChannel_write__II(JNIEnv * env,jclass c,jint fd,jint data)1026 Java_gnu_java_nio_VMChannel_write__II (JNIEnv *env,
1027                                        jclass c __attribute__((unused)),
1028                                        jint fd, jint data)
1029 {
1030 #ifdef HAVE_WRITE
1031   char out = (char) data;
1032   int ret;
1033   int tmp_errno;
1034 
1035 /*   NIODBG("fd: %d; data: %d", fd, data); */
1036 
1037   do
1038     {
1039       ret = cpnio_write (fd, &out, 1);
1040       tmp_errno = errno;
1041     }
1042   while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
1043   errno = tmp_errno;
1044 
1045   if (-1 == ret)
1046     JCL_ThrowException(env, IO_EXCEPTION, strerror (errno));
1047 #else
1048   (void) fd;
1049   (void) data;
1050   JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
1051 #endif /* HAVE_WRITE */
1052 }
1053 
1054 
1055 /*
1056  * Class:     gnu_java_nio_VMChannel
1057  * Method:    socket
1058  * Signature: (Z)I
1059  */
1060 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_socket(JNIEnv * env,jclass clazz,jboolean stream)1061 Java_gnu_java_nio_VMChannel_socket (JNIEnv *env, jclass clazz __attribute__((unused)),
1062                                     jboolean stream)
1063 {
1064 #ifdef HAVE_SOCKET
1065   int ret;
1066 
1067   do
1068     {
1069       ret = cpnio_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
1070     }
1071   while (-1 == ret && EINTR == errno);
1072 
1073   if (ret == -1)
1074     JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
1075 /*   NIODBG("created socket %d", ret); */
1076 
1077   return ret;
1078 #else
1079   (void) stream;
1080   JCL_ThrowException (env, IO_EXCEPTION, "socket not supported");
1081   return -1;
1082 #endif /* HAVE_SOCKET */
1083 }
1084 
1085 
1086 /*
1087  * Class:     gnu_java_nio_VMChannel
1088  * Method:    connect
1089  * Signature: (I[BI)Z
1090  */
1091 JNIEXPORT jboolean JNICALL
Java_gnu_java_nio_VMChannel_connect(JNIEnv * env,jclass clazz,jint fd,jbyteArray addr,jint port,jint timeout)1092 Java_gnu_java_nio_VMChannel_connect (JNIEnv *env, jclass clazz __attribute__((unused)),
1093                                      jint fd, jbyteArray addr, jint port, jint timeout)
1094 {
1095 #ifdef HAVE_CONNECT
1096   struct sockaddr_in sockaddr;
1097   struct timeval timeo;
1098   int origflags = 0, flags;
1099   jbyte *addr_elems;
1100   int ret;
1101   int tmpErrno;
1102 
1103   if ((*env)->GetArrayLength (env, addr) != 4)
1104     {
1105       JCL_ThrowException (env, SOCKET_EXCEPTION,
1106                           "expecting 4-byte address");
1107       return JNI_FALSE;
1108     }
1109 
1110   if (timeout > 0)
1111     {
1112       timeo.tv_sec = timeout / 1000;
1113       timeo.tv_usec = (timeout % 1000) * 1000;
1114       origflags = fcntl (fd, F_GETFL, 0);
1115       if (origflags == -1)
1116         {
1117           JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1118           return JNI_FALSE;
1119         }
1120       /* Set nonblocking mode, if not already set. */
1121       if (!(origflags & O_NONBLOCK))
1122         {
1123           flags = origflags | O_NONBLOCK;
1124           if (fcntl (fd, F_SETFL, flags) == -1)
1125             {
1126               JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1127               return JNI_FALSE;
1128             }
1129         }
1130     }
1131 
1132   addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
1133 
1134   memset (&sockaddr, 0, sizeof (struct sockaddr_in));
1135   sockaddr.sin_family = AF_INET;
1136   sockaddr.sin_port = htons (port);
1137   sockaddr.sin_addr.s_addr = *((uint32_t *) addr_elems);
1138 
1139 
1140   do
1141     {
1142       ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
1143                            sizeof (struct sockaddr_in));
1144       tmpErrno = errno;
1145     }
1146   while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
1147   errno = tmpErrno;
1148 
1149   (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
1150 
1151   /* If a timeout was specified, select on the file descriptor with
1152      the timeout. */
1153   if (timeout > 0 && ret == -1)
1154     {
1155       /* Reset the non-blocking flag, if needed. */
1156       if (!(origflags & O_NONBLOCK))
1157         {
1158           if (fcntl (fd, F_SETFL, origflags) == -1)
1159             {
1160               /* oops */
1161               JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1162               return JNI_FALSE;
1163             }
1164         }
1165       if (EINPROGRESS == errno)
1166         {
1167           fd_set wrfds;
1168           FD_ZERO(&wrfds);
1169           FD_SET(fd, &wrfds);
1170           ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
1171           if (ret == -1)
1172             {
1173               JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1174               return JNI_FALSE;
1175             }
1176           if (ret == 0) /* connect timed out */
1177             {
1178               JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
1179                                   "connect timed out");
1180               return JNI_FALSE;
1181             }
1182           return JNI_TRUE; /* Connected! */
1183         }
1184       else if (ECONNREFUSED == errno)
1185         {
1186           JCL_ThrowException (env, CONNECT_EXCEPTION,
1187                               strerror (errno));
1188           return JNI_FALSE;
1189         }
1190       else
1191         {
1192           JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1193           return JNI_FALSE;
1194         }
1195     }
1196 
1197   if (ret == -1)
1198     {
1199       if (EINPROGRESS == errno)
1200         return JNI_FALSE;
1201       else if (ECONNREFUSED == errno)
1202         {
1203           JCL_ThrowException (env, CONNECT_EXCEPTION,
1204                               strerror (errno));
1205           return JNI_FALSE;
1206         }
1207       else
1208         {
1209           JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1210           return JNI_FALSE;
1211         }
1212     }
1213 
1214   return JNI_TRUE;
1215 #else
1216   (void) fd;
1217   (void) addr;
1218   (void) port;
1219   (void) timeout;
1220   JCL_ThrowException (env, SOCKET_EXCEPTION, "connect not supported");
1221   return JNI_FALSE;
1222 #endif /* HAVE_CONNECT */
1223 }
1224 
1225 
1226 /*
1227  * Class:     gnu_java_nio_VMChannel
1228  * Method:    connect6
1229  * Signature: (I[BI)Z
1230  */
1231 JNIEXPORT jboolean JNICALL
Java_gnu_java_nio_VMChannel_connect6(JNIEnv * env,jclass clazz,jint fd,jbyteArray addr,jint port,int timeout)1232 Java_gnu_java_nio_VMChannel_connect6 (JNIEnv *env, jclass clazz __attribute__((unused)),
1233                                       jint fd, jbyteArray addr, jint port, int timeout)
1234 {
1235 #if defined(HAVE_CONNECT) && defined(HAVE_INET6)
1236   struct sockaddr_in6 sockaddr;
1237   struct timeval timeo;
1238   int flags, origflags = 0;
1239   jbyte *addr_elems;
1240   int ret;
1241 
1242   if (timeout > 0)
1243     {
1244       timeo.tv_sec = timeout / 1000;
1245       timeo.tv_usec = (timeout % 1000) * 1000;
1246       origflags = fcntl (fd, F_GETFL, 0);
1247       if (origflags == -1)
1248         {
1249           JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1250           return JNI_FALSE;
1251         }
1252       /* Set nonblocking mode, if not already set. */
1253       if (!(origflags & O_NONBLOCK))
1254         {
1255           flags = origflags | O_NONBLOCK;
1256           if (fcntl (fd, F_SETFL, flags) == -1)
1257             {
1258               JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1259               return JNI_FALSE;
1260             }
1261         }
1262     }
1263 
1264   addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
1265 
1266   memset (&sockaddr, 0, sizeof (struct sockaddr_in6));
1267   sockaddr.sin6_family = AF_INET6;
1268   sockaddr.sin6_port = htons (port);
1269   memcpy (&sockaddr.sin6_addr.s6_addr, addr_elems, 16);
1270 
1271   ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
1272                        sizeof (struct sockaddr_in6));
1273 
1274   (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
1275 
1276   /* If a timeout was specified, select on the file descriptor with
1277      the timeout. */
1278   if (timeout > 0 && ret == -1)
1279     {
1280       /* Reset the non-blocking flag, if needed. */
1281       if (!(origflags & O_NONBLOCK))
1282         {
1283           if (fcntl (fd, F_SETFL, origflags) == -1)
1284             {
1285               /* oops */
1286               JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1287               return JNI_FALSE;
1288             }
1289         }
1290       if (EINPROGRESS == errno)
1291         {
1292           fd_set wrfds;
1293           FD_ZERO(&wrfds);
1294           FD_SET(fd, &wrfds);
1295           ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
1296           if (ret == -1)
1297             {
1298               JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1299               return JNI_FALSE;
1300             }
1301           if (ret == 0) /* connect timed out */
1302             {
1303               JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
1304                                   "connect timed out");
1305               return JNI_FALSE;
1306             }
1307           return JNI_TRUE; /* Connected! */
1308         }
1309       else if (ECONNREFUSED == errno)
1310         {
1311           JCL_ThrowException (env, CONNECT_EXCEPTION,
1312                               strerror (errno));
1313           return JNI_FALSE;
1314         }
1315       else
1316         {
1317           JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1318           return JNI_FALSE;
1319         }
1320     }
1321 
1322   if (ret == -1)
1323     {
1324       if (EAGAIN == errno)
1325         return JNI_FALSE;
1326       else if (ECONNREFUSED == errno)
1327         {
1328           JCL_ThrowException (env, CONNECT_EXCEPTION,
1329                               strerror (errno));
1330           return JNI_FALSE;
1331         }
1332       else
1333         {
1334           JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1335           return JNI_FALSE;
1336         }
1337     }
1338 
1339   return JNI_TRUE;
1340 #else
1341   (void) fd;
1342   (void) addr;
1343   (void) port;
1344   (void) timeout;
1345   JCL_ThrowException (env, SOCKET_EXCEPTION, "IPv6 connect not supported");
1346   return JNI_FALSE;
1347 #endif /* HAVE_CONNECT && HAVE_INET6 */
1348 }
1349 
1350 
1351 /*
1352  * Class:     gnu_java_nio_VMChannel
1353  * Method:    getsockname
1354  * Signature: (ILjava/nio/ByteBuffer;)I
1355  */
1356 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_getsockname(JNIEnv * env,jclass clazz,jint fd,jobject name)1357 Java_gnu_java_nio_VMChannel_getsockname (JNIEnv *env, jclass clazz __attribute__((unused)),
1358                                          jint fd, jobject name)
1359 {
1360 #ifdef HAVE_GETSOCKNAME
1361 #ifdef HAVE_INET6
1362   struct sockaddr_in6 *addr6;
1363   struct sockaddr_in6 sock_storage;
1364   socklen_t socklen = sizeof (struct sockaddr_in6);
1365 #else
1366   struct sockaddr_in sock_storage;
1367   socklen_t socklen = sizeof (struct sockaddr_in);
1368 #endif /* HAVE_INET6 */
1369 
1370   struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
1371   struct sockaddr_in *addr4;
1372   int ret;
1373   char *nameptr = (*env)->GetDirectBufferAddress (env, name);
1374 
1375   ret = getsockname (fd, sockaddr, &socklen);
1376   if (ret == -1)
1377     {
1378       JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
1379       return 0;
1380     }
1381 
1382   if (sockaddr->sa_family == AF_INET)
1383     {
1384       addr4 = (struct sockaddr_in *) sockaddr;
1385       memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
1386       memcpy (nameptr + 4, &(addr4->sin_port), 2);
1387       return 4;
1388     }
1389 
1390 #ifdef HAVE_INET6
1391   /* IPv6 */
1392   if (sockaddr->sa_family == AF_INET6)
1393     {
1394       addr6 = (struct sockaddr_in6 *) sockaddr;
1395       memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
1396       memcpy (nameptr + 16, &(addr6->sin6_port), 2);
1397       return 16;
1398     }
1399 #endif /* HAVE_INET6 */
1400   JCL_ThrowException (env, IO_EXCEPTION, "unsupported address format");
1401   return -1;
1402 #else
1403   (void) fd;
1404   (void) name;
1405   JCL_ThrowException (env, IO_EXCEPTION, "getsockname not supported");
1406   return -1;
1407 #endif /* HAVE_GETSOCKNAME */
1408 }
1409 
1410 
1411 /*
1412  * Class:     gnu_java_nio_VMChannel
1413  * Method:    getpeername
1414  * Signature: (ILjava/nio/ByteBuffer;)I
1415  */
1416 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_getpeername(JNIEnv * env,jclass clazz,jint fd,jobject name)1417 Java_gnu_java_nio_VMChannel_getpeername (JNIEnv *env, jclass clazz __attribute__((unused)),
1418                                          jint fd, jobject name)
1419 {
1420 #ifdef HAVE_GETPEERNAME
1421 #ifdef HAVE_INET6
1422   struct sockaddr_in6 *addr6;
1423   struct sockaddr_in6 sock_storage;
1424   socklen_t socklen = sizeof (struct sockaddr_in6);
1425 #else
1426   struct sockaddr_in sock_storage;
1427   socklen_t socklen = sizeof (struct sockaddr_in);
1428 #endif /* HAVE_INET6 */
1429 
1430   struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
1431   struct sockaddr_in *addr4;
1432   int ret;
1433   char *nameptr = (*env)->GetDirectBufferAddress (env, name);
1434 
1435   ret = getpeername (fd, sockaddr, &socklen);
1436   if (ret == -1)
1437     {
1438       if (ENOTCONN != errno)
1439         JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
1440       return 0;
1441     }
1442 
1443   if (sockaddr->sa_family == AF_INET)
1444     {
1445       addr4 = (struct sockaddr_in *) sockaddr;
1446       memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
1447       memcpy (nameptr + 4, &(addr4->sin_port), 2);
1448       return 4;
1449     }
1450 #ifdef HAVE_INET6
1451   else if (sockaddr->sa_family == AF_INET6)
1452     {
1453       addr6 = (struct sockaddr_in6 *) sockaddr;
1454       memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
1455       memcpy (nameptr + 16, &(addr6->sin6_port), 2);
1456       return 16;
1457     }
1458 #endif /* HAVE_INET6 */
1459 
1460   JCL_ThrowException (env, "java/net/SocketException",
1461                       "unsupported address type");
1462   return -1;
1463 #else
1464   (void) fd;
1465   (void) name;
1466   JCL_ThrowException (env, IO_EXCEPTION, "getpeername not supported");
1467   return -1;
1468 #endif /* HAVE_GETPEERNAME */
1469 }
1470 
1471 
1472 /*
1473  * Class:     gnu_java_nio_VMChannel
1474  * Method:    accept
1475  * Signature: (I)I
1476  */
1477 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_accept(JNIEnv * env,jclass c,jint fd)1478 Java_gnu_java_nio_VMChannel_accept (JNIEnv *env,
1479                                     jclass c __attribute__((unused)),
1480                                     jint fd)
1481 {
1482 #ifdef HAVE_ACCEPT
1483   int ret;
1484   int tmp_errno = 0;
1485 
1486 #ifdef HAVE_INET6
1487   struct sockaddr_in6 addr;
1488   socklen_t alen = sizeof (struct sockaddr_in6);
1489 #else
1490   struct sockaddr_in addr;
1491   socklen_t alen = sizeof (struct sockaddr_in);
1492 #endif /* HAVE_INET6 */
1493 
1494   do
1495     {
1496       ret = cpnio_accept (fd, (struct sockaddr *) &addr, &alen);
1497       tmp_errno = errno;
1498 
1499       if (ret == -1)
1500         switch (tmp_errno)
1501         {
1502           case EINTR:
1503             /* Check if interrupted by Thread.interrupt(). If not then some
1504              * other unrelated signal interrupted the system function and
1505              * we should start over again.
1506              */
1507             if (JCL_thread_interrupted(env))
1508               {
1509                 JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
1510                 return -1;
1511               }
1512             break;
1513 #if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN
1514           case EWOULDBLOCK:
1515 #endif
1516           case EAGAIN:
1517             if (!is_non_blocking_fd(fd))
1518               {
1519                 JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "Accept timed out");
1520               }
1521             /* Socket in non-blocking mode and no pending connection. */
1522             return -1;
1523           default:
1524             JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
1525             return -1;
1526         }
1527       else
1528         break;
1529     }
1530   while (1);
1531 
1532   cpio_closeOnExec(ret);
1533 
1534   return ret;
1535 #else
1536   (void) fd;
1537   JCL_ThrowException (env, IO_EXCEPTION, "accept not supported");
1538   return -1;
1539 #endif /* HAVE_ACCEPT */
1540 }
1541 
1542 
1543 
1544 /*
1545  * Class:     gnu_java_nio_VMChannel
1546  * Method:    disconnect
1547  * Signature: (I)V
1548  */
1549 JNIEXPORT void JNICALL
Java_gnu_java_nio_VMChannel_disconnect(JNIEnv * env,jclass c,jint fd)1550 Java_gnu_java_nio_VMChannel_disconnect (JNIEnv *env,
1551                                         jclass c __attribute__((unused)),
1552                                         jint fd)
1553 {
1554   struct sockaddr sockaddr;
1555 
1556   sockaddr.sa_family = AF_UNSPEC;
1557   if (connect (fd, &sockaddr, sizeof (struct sockaddr)) == -1)
1558     {
1559       /* The expected error for a successful disconnect is EAFNOSUPPORT. */
1560       if (errno != EAFNOSUPPORT)
1561         JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1562     }
1563 }
1564 
1565 
1566 /*
1567  * Class:     gnu_java_nio_VMChannel
1568  * Method:    close
1569  * Signature: (I)V
1570  */
1571 JNIEXPORT void JNICALL
Java_gnu_java_nio_VMChannel_close(JNIEnv * env,jclass c,jint fd)1572 Java_gnu_java_nio_VMChannel_close (JNIEnv *env,
1573                                    jclass c __attribute__((unused)),
1574                                    jint fd)
1575 {
1576   if (close (fd) == -1)
1577     JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1578 }
1579 
1580 
1581 /*
1582  * Class:     gnu_java_nio_VMChannel
1583  * Method:    available
1584  * Signature: (I)I
1585  */
1586 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_available(JNIEnv * env,jclass c,jint fd)1587 Java_gnu_java_nio_VMChannel_available (JNIEnv *env,
1588                                        jclass c __attribute__((unused)),
1589                                        jint fd)
1590 {
1591 #if defined (FIONREAD)
1592 
1593   jint avail = 0;
1594 
1595 #if defined(ENOTTY) && defined(HAVE_FSTAT)
1596   struct stat statBuffer;
1597   off_t n;
1598 #endif
1599 
1600 /*   NIODBG("fd: %d", fd); */
1601   if (ioctl (fd, FIONREAD, &avail) == -1)
1602     {
1603 #if defined(ENOTTY) && defined(HAVE_FSTAT)
1604       if (errno == ENOTTY)
1605         {
1606           if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
1607             {
1608               n = lseek (fd, 0, SEEK_CUR);
1609               if (n != -1)
1610                 {
1611                   avail = statBuffer.st_size - n;
1612                   return avail;
1613                 }
1614             }
1615         }
1616 #endif
1617       JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1618     }
1619 /*   NIODBG("avail: %d", avail); */
1620 
1621   return avail;
1622 
1623 #elif defined(HAVE_FSTAT)
1624 
1625   jint avail = 0;
1626 
1627   struct stat statBuffer;
1628   off_t n;
1629 
1630   if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
1631     {
1632       n = lseek (fd, 0, SEEK_CUR);
1633       if (n != -1)
1634         {
1635 	  avail = statBuffer.st_size - n;
1636 	  return avail;
1637         }
1638     }
1639   JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1640 
1641 #elif defined(HAVE_SELECT)
1642 
1643   jint avail = 0;
1644   fd_set filedescriptset;
1645   struct timeval tv;
1646 
1647   FD_ZERO (&filedescriptset);
1648   FD_SET (fd,&filedescriptset);
1649   memset (&tv, 0, sizeof(tv));
1650 
1651   switch (select (fd+1, &filedescriptset, NULL, NULL, &tv))
1652     {
1653       case -1:
1654         break;
1655       case  0:
1656         avail = 0;
1657 	return avail;
1658       default:
1659         avail = 1;
1660 	return avail;
1661     }
1662   JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1663 
1664 #else
1665 
1666   JCL_ThrowException (env, IO_EXCEPTION, "No native method for available");
1667 
1668 #endif
1669 }
1670 
1671 
1672 enum FileChannel_mode {
1673   CPNIO_READ   = 1,
1674   CPNIO_WRITE  = 2,
1675   CPNIO_APPEND = 4,
1676   CPNIO_EXCL   = 8,
1677   CPNIO_SYNC   = 16,
1678   CPNIO_DSYNC  = 32
1679 };
1680 
1681 
1682 /*
1683  * Class:     gnu_java_nio_VMChannel
1684  * Method:    open
1685  * Signature: (Ljava/lang/String;I)I
1686  */
1687 JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMChannel_open(JNIEnv * env,jclass c,jstring path,jint mode)1688 Java_gnu_java_nio_VMChannel_open (JNIEnv *env,
1689                                   jclass c __attribute__((unused)),
1690                                   jstring path, jint mode)
1691 {
1692   int nmode = 0;
1693   int ret;
1694   const char *npath;
1695 
1696   if ((mode & CPNIO_READ) && (mode & CPNIO_WRITE))
1697     nmode = O_RDWR;
1698   else if (mode & CPNIO_WRITE)
1699     nmode = O_WRONLY;
1700   else
1701     nmode = O_RDONLY;
1702 
1703   nmode = (nmode
1704            | ((nmode == O_RDWR || nmode == O_WRONLY) ? O_CREAT : 0)
1705            | ((mode & CPNIO_APPEND) ? O_APPEND :
1706               ((nmode == O_WRONLY) ? O_TRUNC : 0))
1707            | ((mode & CPNIO_EXCL) ? O_EXCL : 0)
1708            | ((mode & CPNIO_SYNC) ? O_SYNC : 0));
1709 
1710   npath = JCL_jstring_to_cstring (env, path);
1711 
1712 /*   NIODBG("path: %s; mode: %x", npath, nmode); */
1713 
1714   ret = open (npath, nmode, 0666);
1715 
1716 /*   NIODBG("ret: %d\n", ret); */
1717 
1718   JCL_free_cstring (env, path, npath);
1719 
1720   if (-1 == ret)
1721     JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1722 
1723   return ret;
1724 }
1725 
1726 
1727 /*
1728  * Class:     gnu_java_nio_VMChannel
1729  * Method:    position
1730  * Signature: (I)J
1731  */
1732 JNIEXPORT jlong JNICALL
Java_gnu_java_nio_VMChannel_position(JNIEnv * env,jclass c,jint fd)1733 Java_gnu_java_nio_VMChannel_position (JNIEnv *env,
1734                                       jclass c __attribute__((unused)),
1735                                       jint fd)
1736 {
1737 #ifdef HAVE_LSEEK
1738   off_t ret;
1739 
1740   ret = lseek (fd, 0, SEEK_CUR);
1741 
1742   if (-1 == ret)
1743     JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1744 
1745   return (jlong) ret;
1746 #else
1747   JCL_ThrowException (env, IO_EXCEPTION, "position not supported");
1748   return -1;
1749 #endif /* HAVE_LSEEK */
1750 }
1751 
1752 
1753 /*
1754  * Class:     gnu_java_nio_VMChannel
1755  * Method:    seek
1756  * Signature: (IJ)V
1757  */
1758 JNIEXPORT void JNICALL
Java_gnu_java_nio_VMChannel_seek(JNIEnv * env,jclass c,jint fd,jlong pos)1759 Java_gnu_java_nio_VMChannel_seek (JNIEnv *env,
1760                                   jclass c __attribute__((unused)),
1761                                   jint fd, jlong pos)
1762 {
1763 #ifdef HAVE_LSEEK
1764   if (lseek (fd, (off_t) pos, SEEK_SET) == -1)
1765     JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1766 #else
1767   JCL_ThrowException (env, IO_EXCEPTION, "seek not supported");
1768 #endif /* HAVE_LSEEK */
1769 }
1770 
1771 
1772 /*
1773  * Class:     gnu_java_nio_VMChannel
1774  * Method:    truncate
1775  * Signature: (IJ)V
1776  */
1777 JNIEXPORT void JNICALL
Java_gnu_java_nio_VMChannel_truncate(JNIEnv * env,jclass c,jint fd,jlong len)1778 Java_gnu_java_nio_VMChannel_truncate (JNIEnv *env,
1779                                       jclass c __attribute__((unused)),
1780                                       jint fd, jlong len)
1781 {
1782 #if defined(HAVE_FTRUNCATE) && defined(HAVE_LSEEK)
1783   off_t pos = lseek (fd, 0, SEEK_CUR);
1784   if (pos == -1)
1785     {
1786       JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1787       return;
1788     }
1789   if (ftruncate (fd, (off_t) len) == -1)
1790     {
1791       JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1792       return;
1793     }
1794   if (pos > len)
1795     {
1796       if (lseek (fd, len, SEEK_SET) == -1)
1797         JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1798     }
1799 #else
1800   JCL_ThrowException (env, IO_EXCEPTION, "truncate not supported");
1801 #endif /* HAVE_FTRUNCATE && HAVE_LSEEK */
1802 }
1803 
1804 
1805 /*
1806  * Class:     gnu_java_nio_VMChannel
1807  * Method:    lock
1808  * Signature: (IJJZZ)Z
1809  */
1810 JNIEXPORT jboolean JNICALL
Java_gnu_java_nio_VMChannel_lock(JNIEnv * env,jclass c,jint fd,jlong pos,jlong len,jboolean shared,jboolean wait)1811 Java_gnu_java_nio_VMChannel_lock (JNIEnv *env,
1812                                   jclass c __attribute__((unused)),
1813                                   jint fd, jlong pos, jlong len,
1814                                   jboolean shared, jboolean wait)
1815 {
1816 #if HAVE_FCNTL
1817   struct flock fl;
1818 
1819   fl.l_start  = (off_t) pos;
1820   /* Long.MAX_VALUE means lock everything possible starting at pos. */
1821   if (len == 9223372036854775807LL)
1822     fl.l_len = 0;
1823   else
1824     fl.l_len = (off_t) len;
1825   fl.l_pid    = getpid ();
1826   fl.l_type   = (shared ? F_RDLCK : F_WRLCK);
1827   fl.l_whence = SEEK_SET;
1828 
1829   if (cpnio_fcntl (fd, (wait ? F_SETLKW : F_SETLK), (long) &fl) == -1)
1830     {
1831       if (errno != EAGAIN)
1832         JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1833       return JNI_FALSE;
1834     }
1835 
1836   return JNI_TRUE;
1837 #else
1838   JCL_ThrowException (env, IO_EXCEPTION, "lock not supported");
1839   return JNI_FALSE;
1840 #endif /* HAVE_FCNTL */
1841 }
1842 
1843 /*
1844  * Class:     gnu_java_nio_VMChannel
1845  * Method:    unlock
1846  * Signature: (IJJ)V
1847  */
1848 JNIEXPORT void JNICALL
Java_gnu_java_nio_VMChannel_unlock(JNIEnv * env,jclass c,jint fd,jlong pos,jlong len)1849 Java_gnu_java_nio_VMChannel_unlock (JNIEnv *env,
1850                                     jclass c __attribute__((unused)),
1851                                     jint fd, jlong pos, jlong len)
1852 {
1853 #if HAVE_FCNTL
1854   struct flock fl;
1855 
1856   fl.l_start  = (off_t) pos;
1857   fl.l_len    = (off_t) len;
1858   fl.l_pid    = getpid ();
1859   fl.l_type   = F_UNLCK;
1860   fl.l_whence = SEEK_SET;
1861 
1862   if (cpnio_fcntl (fd, F_SETLK, (long) &fl) == -1)
1863     {
1864       JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1865     }
1866 #else
1867   JCL_ThrowException (env, IO_EXCEPTION, "unlock not supported");
1868 #endif /* HAVE_FCNTL */
1869 }
1870 
1871 /*
1872  * Class:     gnu_java_nio_VMChannel
1873  * Method:    size
1874  * Signature: (I)J
1875  */
1876 JNIEXPORT jlong JNICALL
Java_gnu_java_nio_VMChannel_size(JNIEnv * env,jclass c,jint fd)1877 Java_gnu_java_nio_VMChannel_size (JNIEnv *env,
1878                                   jclass c __attribute__((unused)),
1879                                   jint fd)
1880 {
1881 #ifdef HAVE_FSTAT
1882   struct stat st;
1883 
1884   if (fstat (fd, &st) == -1)
1885     JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1886 
1887   return (jlong) st.st_size;
1888 #else
1889   JCL_ThrowException (env, IO_EXCEPTION, "size not supported");
1890   return 0;
1891 #endif
1892 }
1893 
1894 /*
1895  * Class:     gnu_java_nio_VMChannel
1896  * Method:    map
1897  * Signature: (ICJI)Lgnu/classpath/Pointer;
1898  */
1899 JNIEXPORT jobject JNICALL
Java_gnu_java_nio_VMChannel_map(JNIEnv * env,jclass clazz,jint fd,jchar mode,jlong position,jint size)1900 Java_gnu_java_nio_VMChannel_map (JNIEnv *env,
1901                                  jclass clazz __attribute__((unused)),
1902                                  jint fd, jchar mode, jlong position, jint size)
1903 {
1904 #ifdef HAVE_MMAP
1905   jclass MappedByteBufferImpl_class;
1906   jmethodID MappedByteBufferImpl_init = NULL;
1907   jobject Pointer_instance;
1908   volatile jobject buffer;
1909   long pagesize;
1910   int prot, flags;
1911   void *p;
1912   void *address;
1913 
1914 /*   NIODBG("fd: %d; mode: %x; position: %lld; size: %d", */
1915 /*          fd, mode, position, size); */
1916 
1917   /* FIXME: should we just assume we're on an OS modern enough to
1918      have 'sysconf'? And not check for 'getpagesize'? */
1919 #if defined(HAVE_GETPAGESIZE)
1920   pagesize = getpagesize ();
1921 #elif defined(HAVE_SYSCONF)
1922   pagesize = sysconf (_SC_PAGESIZE);
1923 #else
1924   JCL_ThrowException (env, IO_EXCEPTION,
1925 		      "can't determine memory page size");
1926   return NULL;
1927 #endif /* HAVE_GETPAGESIZE/HAVE_SYSCONF */
1928 
1929   if ((*env)->ExceptionOccurred (env))
1930     {
1931       return NULL;
1932     }
1933 
1934   prot = PROT_READ;
1935   if (mode == '+' || mode == 'c')
1936     {
1937       /* When writing we need to make sure the file is big enough,
1938          otherwise the result of mmap is undefined. */
1939       struct stat st;
1940       if (fstat (fd, &st) == -1)
1941         {
1942           JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1943           return NULL;
1944         }
1945       if (position + size > st.st_size)
1946         {
1947           if (ftruncate(fd, position + size) == -1)
1948             {
1949               JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1950               return NULL;
1951             }
1952         }
1953       prot |= PROT_WRITE;
1954     }
1955 
1956   flags = (mode == 'c' ? MAP_PRIVATE : MAP_SHARED);
1957   p = mmap (NULL, (size_t) ALIGN_UP (size, pagesize), prot, flags,
1958 	    fd, ALIGN_DOWN (position, pagesize));
1959   if (p == MAP_FAILED)
1960     {
1961       JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1962       return NULL;
1963     }
1964 
1965   /* Unalign the mapped value back up, since we aligned offset
1966      down to a multiple of the page size. */
1967   address = (void *) ((char *) p + (position % pagesize));
1968 
1969   Pointer_instance = JCL_NewRawDataObject(env, address);
1970 
1971   MappedByteBufferImpl_class = (*env)->FindClass (env,
1972 						  "java/nio/MappedByteBufferImpl");
1973   if (MappedByteBufferImpl_class != NULL)
1974     {
1975       MappedByteBufferImpl_init =
1976 	(*env)->GetMethodID (env, MappedByteBufferImpl_class,
1977 			     "<init>", "(Lgnu/classpath/Pointer;IZ)V");
1978     }
1979 
1980   if ((*env)->ExceptionOccurred (env))
1981     {
1982       munmap (p, ALIGN_UP (size, pagesize));
1983       return NULL;
1984     }
1985   if (MappedByteBufferImpl_init == NULL)
1986     {
1987       JCL_ThrowException (env, "java/lang/InternalError",
1988                           "could not get MappedByteBufferImpl constructor");
1989       munmap (p, ALIGN_UP (size, pagesize));
1990       return NULL;
1991     }
1992 
1993   buffer = (*env)->NewObject (env, MappedByteBufferImpl_class,
1994                               MappedByteBufferImpl_init, Pointer_instance,
1995                               (jint) size, mode == 'r');
1996   return buffer;
1997 #else
1998   (void) fd;
1999   (void) mode;
2000   (void) position;
2001   (void) size;
2002   JCL_ThrowException (env, IO_EXCEPTION,
2003 		      "memory-mapped files not implemented");
2004   return 0;
2005 #endif /* HAVE_MMAP */
2006 }
2007 
2008 /*
2009  * Class:     gnu_java_nio_VMChannel
2010  * Method:    flush
2011  * Signature: (IZ)Z
2012  */
2013 JNIEXPORT jboolean JNICALL
Java_gnu_java_nio_VMChannel_flush(JNIEnv * env,jclass c,jint fd,jboolean metadata)2014 Java_gnu_java_nio_VMChannel_flush (JNIEnv *env,
2015                                    jclass c __attribute__((unused)),
2016                                    jint fd, jboolean metadata __attribute__((unused)))
2017 {
2018 #ifdef HAVE_FSYNC
2019   /* XXX blocking? */
2020   if (fsync (fd) == -1)
2021     {
2022       JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
2023       return JNI_FALSE;
2024     }
2025   return JNI_TRUE;
2026 #else
2027   JCL_ThrowException (env, IO_EXCEPTION, "flush not implemented");
2028   return JNI_TRUE;
2029 #endif /* HAVE_FSYNC */
2030 }
2031 
2032 
2033 #ifdef __cplusplus
2034 }
2035 #endif
2036