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