Merged with mainline at revision 128810.
[official-gcc.git] / libjava / classpath / native / jni / java-nio / gnu_java_nio_VMChannel.c
bloba5bbd71262c5b95f427d016a65dc1481ed20c8cb
1 /* gnu_java_nio_VMChannel.c -
2 Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
43 #include <config-int.h>
45 #include <sys/types.h>
46 #include <sys/mman.h>
47 #include <sys/socket.h>
48 #include <sys/stat.h>
49 #include <sys/uio.h>
51 #include <netinet/in.h>
53 #include <stdlib.h>
54 #include <errno.h>
55 #include <unistd.h>
56 #include <string.h>
58 #include <jni.h>
59 #include <jcl.h>
61 #include "cpio.h"
62 #include "gnu_java_nio_VMChannel.h"
63 #include "javanio.h"
65 #ifdef HAVE_FCNTL_H
66 #include <fcntl.h>
67 #endif /* HAVE_FCNTL_H */
69 #if defined(HAVE_SYS_IOCTL_H)
70 #define BSD_COMP /* Get FIONREAD on Solaris2 */
71 #include <sys/ioctl.h>
72 #endif
73 #if defined(HAVE_SYS_FILIO_H) /* Get FIONREAD on Solaris 2.5 */
74 #include <sys/filio.h>
75 #endif
77 #define CONNECT_EXCEPTION "java/net/ConnectException"
78 #define IO_EXCEPTION "java/io/IOException"
79 #define SOCKET_EXCEPTION "java/net/SocketException"
80 #define INTERRUPTED_IO_EXCEPTION "java/io/InterruptedIOException"
81 #define NON_READABLE_CHANNEL_EXCEPTION "java/nio/channels/NonReadableChannelException"
82 #define NON_WRITABLE_CHANNEL_EXCEPTION "java/nio/channels/NonWritableChannelException"
83 #define SOCKET_TIMEOUT_EXCEPTION "java/net/SocketTimeoutException"
85 /* Align a value up or down to a multiple of the pagesize. */
86 #define ALIGN_DOWN(p,s) ((p) - ((p) % (s)))
87 #define ALIGN_UP(p,s) ((p) + ((s) - ((p) % (s))))
90 * Limit to maximum of 16 buffers
92 #define JCL_IOV_MAX 16
94 #ifdef __cplusplus
95 extern "C"
97 #endif
99 enum JCL_buffer_type { DIRECT, HEAP, ARRAY, UNKNOWN };
101 struct JCL_buffer
103 enum JCL_buffer_type type;
104 jbyte *ptr;
105 jint offset;
106 jint position;
107 jint limit;
108 jint count;
111 jmethodID get_method_id(JNIEnv *, jclass, const char *, const char *);
112 void JCL_print_buffer(JNIEnv *, struct JCL_buffer *);
113 int JCL_init_buffer(JNIEnv *, struct JCL_buffer *, jobject);
114 void JCL_release_buffer(JNIEnv *, struct JCL_buffer *, jobject, jint);
115 void JCL_cleanup_buffers(JNIEnv *, struct JCL_buffer *, jint, jobjectArray, jint, jlong);
116 int JCL_thread_interrupted(JNIEnv *);
118 static jfieldID address_fid;
119 static jmethodID get_position_mid;
120 static jmethodID set_position_mid;
121 static jmethodID get_limit_mid;
122 static jmethodID set_limit_mid;
123 static jmethodID has_array_mid;
124 static jmethodID array_mid;
125 static jmethodID array_offset_mid;
126 static jmethodID thread_interrupted_mid;
127 static jclass vm_channel_class;
129 jmethodID
130 get_method_id(JNIEnv *env, jclass clazz, const char *name,
131 const char *sig)
133 jmethodID mid = (*env)->GetMethodID(env, clazz, name, sig);
134 /* NIODBG("name: %s; sig: %s", name, sig); */
135 if (mid == NULL)
137 JCL_ThrowException(env, "java/lang/InternalError", name);
138 return NULL;
141 return mid;
144 inline void
145 JCL_print_buffer(JNIEnv *env __attribute__((__unused__)), struct JCL_buffer *buf)
147 fprintf (stderr, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr);
152 JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf)
154 void *addr = (*env)->GetDirectBufferAddress (env, bbuf);
156 /* NIODBG("buf: %p; bbuf: %p; addr: %p", (void *) buf, bbuf, addr); */
158 buf->position = (*env)->CallIntMethod(env, bbuf, get_position_mid);
159 buf->limit = (*env)->CallIntMethod(env, bbuf, get_limit_mid);
160 buf->offset = 0;
161 buf->count = 0;
162 buf->type = UNKNOWN;
164 if (addr != NULL)
166 buf->ptr = (jbyte *) addr;
167 buf->type = DIRECT;
169 else
171 jboolean has_array;
172 has_array = (*env)->CallBooleanMethod(env, bbuf, has_array_mid);
174 if (has_array == JNI_TRUE)
176 jbyteArray arr;
177 buf->offset = (*env)->CallIntMethod(env, bbuf, array_offset_mid);
178 arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
179 buf->ptr = (*env)->GetByteArrayElements(env, arr, 0);
180 buf->type = ARRAY;
181 (*env)->DeleteLocalRef(env, arr);
183 else
185 jobject address = (*env)->GetObjectField (env, bbuf, address_fid);
186 if (address == NULL)
187 return -1; /* XXX handle non-array, non-native buffers? */
188 buf->ptr = (jbyte *) JCL_GetRawData(env, address);
189 buf->type = HEAP;
190 (*env)->DeleteLocalRef(env, address);
194 return 0;
197 void
198 JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf,
199 jint action)
201 jbyteArray arr;
203 /* NIODBG("buf: %p; bbuf: %p; action: %x", (void *) buf, bbuf, action); */
205 /* Set the position to the appropriate value */
206 if (buf->count > 0)
208 jobject bbufTemp;
209 bbufTemp = (*env)->CallObjectMethod(env, bbuf, set_position_mid,
210 buf->position + buf->count);
211 (*env)->DeleteLocalRef(env, bbufTemp);
214 switch (buf->type)
216 case DIRECT:
217 case HEAP:
218 break;
219 case ARRAY:
220 arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
221 (*env)->ReleaseByteArrayElements(env, arr, buf->ptr, action);
222 (*env)->DeleteLocalRef(env, arr);
223 break;
224 case UNKNOWN:
225 /* TODO: Handle buffers that are not direct or array backed */
226 break;
230 void
231 JCL_cleanup_buffers(JNIEnv *env,
232 struct JCL_buffer *bi_list,
233 jint vec_len,
234 jobjectArray bbufs,
235 jint offset,
236 jlong num_bytes)
238 jint i;
240 /* NIODBG("bi_list: %p; vec_len: %d; bbufs: %p; offset: %d; num_bytes: %lld", */
241 /* (void *) bi_list, vec_len, bbufs, offset, num_bytes); */
243 /* Update all of the bbufs with the approriate information */
244 for (i = 0; i < vec_len; i++)
246 struct JCL_buffer* buf;
247 jobject bbuf;
249 buf = &bi_list[i];
250 bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
252 if (num_bytes > (buf->limit - buf->position))
253 buf->count = (buf->limit - buf->position);
254 else
255 buf->count = num_bytes;
257 num_bytes -= buf->count;
259 JCL_release_buffer(env, buf, bbuf, JNI_ABORT);
260 (*env)->DeleteLocalRef(env, bbuf);
266 JCL_thread_interrupted(JNIEnv *env)
268 return (int) (*env)->CallStaticBooleanMethod(env, vm_channel_class,
269 thread_interrupted_mid);
274 * Class: gnu_java_nio_VMChannel
275 * Method: stdin_fd
276 * Signature: ()I
278 JNIEXPORT jint JNICALL
279 Java_gnu_java_nio_VMChannel_stdin_1fd (JNIEnv *env __attribute__((unused)),
280 jclass c __attribute__((unused)))
282 /* NIODBG("%d", fileno (stdin)); */
283 return fileno (stdin);
288 * Class: gnu_java_nio_VMChannel
289 * Method: stdout_fd
290 * Signature: ()I
292 JNIEXPORT jint JNICALL
293 Java_gnu_java_nio_VMChannel_stdout_1fd (JNIEnv *env __attribute__((unused)),
294 jclass c __attribute__((unused)))
296 /* NIODBG("%d", fileno (stdout)); */
297 return fileno (stdout);
302 * Class: gnu_java_nio_VMChannel
303 * Method: stderr_fd
304 * Signature: ()I
306 JNIEXPORT jint JNICALL
307 Java_gnu_java_nio_VMChannel_stderr_1fd (JNIEnv *env __attribute__((unused)),
308 jclass c __attribute__((unused)))
310 /* NIODBG("%d", fileno (stderr)); */
311 return fileno (stderr);
315 JNIEXPORT void JNICALL
316 Java_gnu_java_nio_VMChannel_initIDs (JNIEnv *env,
317 jclass clazz)
319 jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer");
320 jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer");
322 /* NIODBG("%s", "..."); */
324 address_fid = (*env)->GetFieldID(env, bufferClass, "address",
325 "Lgnu/classpath/Pointer;");
326 if (address_fid == NULL)
328 JCL_ThrowException(env, "java/lang/InternalError",
329 "Unable to find internal field");
330 return;
333 get_position_mid = get_method_id(env, bufferClass, "position", "()I");
334 set_position_mid = get_method_id(env, bufferClass, "position",
335 "(I)Ljava/nio/Buffer;");
336 get_limit_mid = get_method_id(env, bufferClass, "limit", "()I");
337 set_limit_mid = get_method_id(env, bufferClass, "limit",
338 "(I)Ljava/nio/Buffer;");
339 has_array_mid = get_method_id(env, byteBufferClass, "hasArray", "()Z");
340 array_mid = get_method_id(env, byteBufferClass, "array", "()[B");
341 array_offset_mid = get_method_id(env, byteBufferClass, "arrayOffset", "()I");
343 vm_channel_class = clazz;
344 thread_interrupted_mid = (*env)->GetStaticMethodID(env, clazz,
345 "isThreadInterrupted",
346 "()Z");
349 JNIEXPORT void JNICALL
350 Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env,
351 jobject o __attribute__ ((__unused__)),
352 jint fd,
353 jboolean blocking)
355 int opts;
357 /* NIODBG("fd: %d; blocking: %d", fd, blocking); */
359 opts = fcntl(fd, F_GETFL);
360 if (opts < 0)
362 JCL_ThrowException(env, IO_EXCEPTION,
363 "Failed to get flags for file desriptor");
364 return;
367 if (blocking == JNI_TRUE)
368 opts &= ~(O_NONBLOCK);
369 else
370 opts |= O_NONBLOCK;
372 opts = fcntl(fd, F_SETFL, opts);
374 if (opts < 0)
376 JCL_ThrowException(env, IO_EXCEPTION,
377 "Failed to set flags for file desriptor");
378 return;
382 /* Return true if fd is in non-blocking mode. */
383 static jboolean
384 is_non_blocking_fd(jint fd)
386 int opts;
387 opts = fcntl(fd, F_GETFL);
388 if (opts == -1)
390 /* Assume blocking on error. */
391 return 0;
393 return (opts & O_NONBLOCK) != 0;
396 JNIEXPORT jint JNICALL
397 Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
398 jobject o __attribute__ ((__unused__)),
399 jint fd,
400 jobject bbuf)
402 #ifdef HAVE_READ
403 jint len;
404 ssize_t result;
405 struct JCL_buffer buf;
406 int tmp_errno;
408 /* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
410 if (JCL_init_buffer(env, &buf, bbuf) < 0)
412 /* TODO: Rethrown exception */
413 JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
414 return -1;
417 len = buf.limit - buf.position;
419 if (len == 0)
421 JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
422 return 0;
427 result = cpnio_read (fd, &(buf.ptr[buf.position + buf.offset]), len);
428 tmp_errno = errno;
430 while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
431 errno = tmp_errno;
433 if (result == 0)
435 result = -1;
436 buf.count = 0;
438 else if (result == -1)
440 buf.count = 0;
441 if (errno == EAGAIN)
443 if (is_non_blocking_fd(fd))
445 /* Non-blocking */
446 result = 0;
448 else
450 /* Read timeout on a socket with SO_RCVTIMEO != 0. */
451 JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
452 JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
453 return -1;
456 else if (errno == EBADF) /* Bad fd */
458 JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
459 JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION,
460 strerror(errno));
461 return -1;
463 else if (EINTR == errno) /* read interrupted */
465 JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
466 JCL_ThrowException(env, INTERRUPTED_IO_EXCEPTION, strerror (errno));
467 return -1;
469 else
471 JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
472 JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
473 return -1;
476 else
477 buf.count = result;
479 JCL_release_buffer(env, &buf, bbuf, 0);
481 return result;
482 #else
483 (void) fd;
484 (void) bbuf;
485 JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
486 return -1;
487 #endif /* HAVE_READ */
490 JNIEXPORT jint JNICALL
491 Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
492 jobject o __attribute__ ((__unused__)),
493 jint fd,
494 jobject bbuf)
496 #ifdef HAVE_WRITE
497 jint len;
498 ssize_t result;
499 struct JCL_buffer buf;
500 int tmp_errno;
502 /* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
504 if (JCL_init_buffer(env, &buf, bbuf) < 0)
506 /* TODO: Rethrown exception */
507 JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
508 return -1;
511 len = buf.limit - buf.position;
513 if (len == 0)
515 JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
516 return 0;
521 result = cpnio_write (fd, &(buf.ptr[buf.position + buf.offset]), len);
522 tmp_errno = errno;
524 while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
525 errno = tmp_errno;
527 buf.count = result;
529 if (result == -1)
531 if (errno == EAGAIN) /* Non-blocking */
533 result = 0;
535 else
537 JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
538 JCL_ThrowException(env, IO_EXCEPTION, strerror(errno));
539 return -1;
543 JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
545 return result;
546 #else
547 (void) fd;
548 (void) bbuf;
549 JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
550 return -1;
551 #endif /* HAVE_WRITE */
556 * Implementation of a scattering read. Will use the appropriate
557 * vector based read call (currently readv on Linux).
559 * This has a limit to the number of buffers that will be read. It
560 * will not make muliple readv calls. This is to ensure that operations
561 * are atomic. Currently it is limited to 16 buffers. This is for
562 * compatibiliy with Sun.
564 JNIEXPORT jlong JNICALL
565 Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env,
566 jobject o __attribute__ ((__unused__)),
567 jint fd,
568 jobjectArray bbufs,
569 jint offset,
570 jint length)
572 jint i;
573 /* jboolean is_error = JNI_FALSE; */
574 /* char *error_msg; */
575 struct iovec buffers[JCL_IOV_MAX];
576 struct JCL_buffer bi_list[JCL_IOV_MAX];
577 ssize_t result;
578 jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
579 jlong bytes_read = 0;
580 int tmp_errno;
582 /* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
583 /* fd, bbufs, offset, length); */
585 /* Build the vector of buffers to read into */
586 for (i = 0; i < vec_len; i++)
588 struct JCL_buffer* buf;
589 jobject bbuf;
591 buf = &bi_list[i];
592 bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
594 JCL_init_buffer(env, buf, bbuf);
596 /* JCL_print_buffer (env, buf); */
598 buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
599 buffers[i].iov_len = buf->limit - buf->position;
600 (*env)->DeleteLocalRef(env, bbuf);
603 /* Work the scattering magic */
606 result = cpnio_readv (fd, buffers, vec_len);
607 tmp_errno = errno;
609 while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
610 errno = tmp_errno;
611 bytes_read = (jlong) result;
613 /* Handle the response */
614 if (result < 0)
616 if (errno == EAGAIN)
618 if (is_non_blocking_fd(fd))
620 /* Non-blocking */
621 result = 0;
623 else
625 /* Read timeout on a socket with SO_RCVTIMEO != 0. */
626 JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
627 JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
628 return -1;
631 else if (errno == EBADF) /* Bad fd */
633 JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
634 JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION,
635 strerror(errno));
636 return -1;
638 else
640 JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
641 JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
642 return -1;
644 bytes_read = 0;
646 else if (result == 0) /* EOF */
648 result = -1;
651 JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
653 return (jlong) result;
658 * Implementation of a gathering write. Will use the appropriate
659 * vector based read call (currently readv on Linux).
661 * This has a limit to the number of buffers that will be read. It
662 * will not make muliple readv calls. This is to ensure that operations
663 * are atomic. Currently it is limited to 16 buffers. This is for
664 * compatibiliy with Sun.
666 JNIEXPORT jlong JNICALL
667 Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env,
668 jobject o __attribute__ ((__unused__)),
669 jint fd,
670 jobjectArray bbufs,
671 jint offset,
672 jint length)
674 int i;
675 /* jboolean is_error = JNI_FALSE; */
676 /* char *error_msg; */
677 struct iovec buffers[JCL_IOV_MAX];
678 struct JCL_buffer bi_list[JCL_IOV_MAX];
679 ssize_t result;
680 jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
681 jlong bytes_written;
682 int tmp_errno;
684 /* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
685 /* fd, bbufs, offset, length); */
687 /* Build the vector of buffers to read into */
688 for (i = 0; i < vec_len; i++)
690 struct JCL_buffer* buf;
691 jobject bbuf;
693 buf = &bi_list[i];
694 bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
696 JCL_init_buffer(env, buf, bbuf);
698 /* JCL_print_buffer(env, buf); */
700 buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
701 buffers[i].iov_len = buf->limit - buf->position;
702 (*env)->DeleteLocalRef(env, bbuf);
705 /* Work the gathering magic */
708 result = cpnio_writev (fd, buffers, vec_len);
709 tmp_errno = errno;
711 while (result == -1 && tmp_errno == EINTR && ! JCL_thread_interrupted(env));
712 errno = tmp_errno;
714 bytes_written = (jlong) result;
716 if (result < 0)
718 bytes_written = 0;
719 if (errno == EAGAIN) /* Non blocking */
720 result = 0;
721 else if (errno == EBADF) /* Bad fd */
723 JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
724 bytes_written);
725 JCL_ThrowException (env, NON_WRITABLE_CHANNEL_EXCEPTION,
726 strerror(errno));
727 return -1;
729 else
731 JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
732 bytes_written);
733 JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
734 return -1;
737 else if (result == 0) /* EOF?? Does this happen on a write */
738 result = -1;
740 JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_written);
741 return (jlong) result;
746 * Class: gnu_java_nio_VMChannel
747 * Method: receive
748 * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I
750 JNIEXPORT jint JNICALL
751 Java_gnu_java_nio_VMChannel_receive (JNIEnv *env,
752 jclass c __attribute__((unused)),
753 jint fd, jobject dst, jobject addrPort)
755 #ifdef HAVE_RECVFROM
756 char *addrPortPtr = (*env)->GetDirectBufferAddress (env, addrPort);
757 struct JCL_buffer buf;
758 #ifdef HAVE_INET6
759 struct sockaddr_in6 sock_storage;
760 struct sockaddr_in6 *sock6;
761 socklen_t slen = sizeof (struct sockaddr_in6);
762 #else
763 struct sockaddr_in sock_storage;
764 socklen_t slen = sizeof (struct sockaddr_in);
765 #endif /* HAVE_INET6 */
766 struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
767 struct sockaddr_in *sock4;
768 int ret;
769 jint result = -1;
771 if (JCL_init_buffer (env, &buf, dst) == -1)
772 JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
774 #ifndef HAVE_MSG_WAITALL
775 #define MSG_WAITALL 0
776 #endif
778 ret = cpnio_recvfrom (fd, &(buf.ptr[buf.position + buf.offset]),
779 buf.limit - buf.position, MSG_WAITALL,
780 sockaddr, &slen);
782 if (-1 == ret)
784 JCL_release_buffer (env, &buf, dst, JNI_ABORT);
785 if (EINTR == errno)
786 JCL_ThrowException (env, "java/io/InterruptedIOException", strerror (errno));
787 else if (EAGAIN == errno)
789 /* If the socket is in blocking mode, our timeout expired. */
790 int val = fcntl (fd, F_GETFL, 0);
791 if (val == -1)
792 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
793 else if ((val & O_NONBLOCK) == 0)
794 JCL_ThrowException (env, "java/net/SocketTimeoutException",
795 "read timed out");
797 else
798 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
799 return 0;
802 if (sockaddr->sa_family == AF_INET)
804 sock4 = (struct sockaddr_in *) sockaddr;
805 memcpy (addrPortPtr, &(sock4->sin_addr.s_addr), 4);
806 ;memcpy (addrPortPtr + 4, &(sock4->sin_port), 2);
807 result = 4;
809 #ifdef HAVE_INET6
810 else if (sockaddr->sa_family == AF_INET6)
812 sock6 = (struct sockaddr_in6 *) sockaddr;
813 memcpy (addrPortPtr, &(sock6->sin6_addr.s6_addr), 16);
814 memcpy (addrPortPtr + 16, &(sock6->sin6_port), 2);
815 result = 16;
817 #endif /* HAVE_INET6 */
818 else if (ret == 0)
820 result = 0;
822 else
824 JCL_ThrowException (env, "java/net/SocketException",
825 "unsupported address type returned");
828 buf.count += ret;
829 JCL_release_buffer (env, &buf, dst, 0);
830 return result;
831 #else
832 (void) fd;
833 (void) dst;
834 (void) addrPort;
835 JCL_ThrowException (env, IO_EXCEPTION, "recvfrom not supported");
836 #endif /* HAVE_RECVFROM */
841 * Class: gnu_java_nio_VMChannel
842 * Method: send
843 * Signature: (Ljava/nio/ByteBuffer;[BI)I
845 JNIEXPORT jint JNICALL
846 Java_gnu_java_nio_VMChannel_send (JNIEnv *env,
847 jclass c __attribute__((unused)),
848 int fd, jobject src, jbyteArray addr, jint port)
850 #ifdef HAVE_SENDTO
851 struct sockaddr_in sockaddr;
852 jbyte *elems;
853 struct JCL_buffer buf;
854 int ret;
856 /* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
857 /* fd, src, addr, port); */
859 if (JCL_init_buffer (env, &buf, src) == -1)
861 JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
862 return -1;
865 /* JCL_print_buffer (env, &buf); */
867 elems = (*env)->GetByteArrayElements (env, addr, NULL);
869 sockaddr.sin_family = AF_INET;
870 sockaddr.sin_addr.s_addr = *((uint32_t *) elems);
871 sockaddr.sin_port = htons (port);
875 ret = cpnio_sendto (fd, &(buf.ptr[buf.position + buf.offset]),
876 buf.limit - buf.position,
877 0, (const struct sockaddr *) &sockaddr,
878 sizeof (struct sockaddr_in));
880 while (-1 == ret && EINTR == errno);
882 (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
884 if (-1 == ret)
886 if (errno != EAGAIN)
887 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
888 JCL_release_buffer (env, &buf, src, JNI_ABORT);
889 return 0;
892 buf.count += ret;
893 JCL_release_buffer (env, &buf, src, JNI_ABORT);
894 return ret;
895 #else
896 (void) fd;
897 (void) src;
898 (void) addr;
899 (void) port;
900 #endif /* HAVE_SENDTO */
905 * Class: gnu_java_nio_VMChannel
906 * Method: send6
907 * Signature: (Ljava/nio/ByteBuffer;[BI)I
909 JNIEXPORT jint JNICALL
910 Java_gnu_java_nio_VMChannel_send6 (JNIEnv *env,
911 jclass c __attribute__((unused)),
912 int fd, jobject src, jbyteArray addr, jint port)
914 #if defined(HAVE_SENDTO) && defined(HAVE_INET6)
915 struct sockaddr_in6 sockaddr;
916 jbyte *elems;
917 struct JCL_buffer buf;
918 int ret;
920 /* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
921 /* fd, src, addr, port); */
923 if (JCL_init_buffer (env, &buf, src) == -1)
925 JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
926 return -1;
929 /* JCL_print_buffer (env, &buf); */
931 elems = (*env)->GetByteArrayElements (env, addr, NULL);
933 sockaddr.sin6_family = AF_INET6;
934 memcpy (&sockaddr.sin6_addr.s6_addr, elems, 16);
935 sockaddr.sin6_port = htons (port);
939 ret = cpnio_sendto (fd, (const void *) (buf.ptr + buf.offset),
940 buf.limit - buf.position,
941 0, (const struct sockaddr *) &sockaddr,
942 sizeof (struct sockaddr_in6));
944 while (-1 == ret && EINTR == errno);
946 (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
948 if (-1 == ret)
950 if (errno != EAGAIN)
951 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
952 JCL_release_buffer (env, &buf, src, JNI_ABORT);
953 return 0;
956 buf.count += ret;
957 JCL_release_buffer (env, &buf, src, JNI_ABORT);
958 return ret;
959 #else
960 (void) fd;
961 (void) src;
962 (void) addr;
963 (void) port;
964 JCL_ThrowException (env, IO_EXCEPTION, "IPv6 sendto not supported");
965 return -1;
966 #endif /* HAVE_SENDTO && HAVE_INET6 */
971 * Class: gnu_java_nio_VMChannel
972 * Method: read
973 * Signature: (I)I
975 JNIEXPORT jint JNICALL
976 Java_gnu_java_nio_VMChannel_read__I (JNIEnv *env,
977 jclass c __attribute__((unused)),
978 jint fd)
980 #ifdef HAVE_READ
981 char in;
982 int ret;
983 int tmp_errno;
985 /* NIODBG("fd: %d", fd); */
989 ret = cpnio_read (fd, &in, 1);
990 tmp_errno = errno;
992 while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
993 errno = tmp_errno;
995 if (-1 == ret)
997 if (errno == EAGAIN && !is_non_blocking_fd(fd))
999 /* Read timeout on a socket with SO_RCVTIMEO != 0. */
1000 JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
1002 else
1003 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1004 return -1;
1007 if (0 == ret)
1008 return -1;
1010 return (in & 0xFF);
1011 #else
1012 (void) fd;
1013 JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
1014 #endif /* HAVE_READ */
1019 * Class: gnu_java_nio_VMChannel
1020 * Method: write
1021 * Signature: (I)V
1023 JNIEXPORT void JNICALL
1024 Java_gnu_java_nio_VMChannel_write__II (JNIEnv *env,
1025 jclass c __attribute__((unused)),
1026 jint fd, jint data)
1028 #ifdef HAVE_WRITE
1029 char out = (char) data;
1030 int ret;
1031 int tmp_errno;
1033 /* NIODBG("fd: %d; data: %d", fd, data); */
1037 ret = cpnio_write (fd, &out, 1);
1038 tmp_errno = errno;
1040 while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
1041 errno = tmp_errno;
1043 if (-1 == ret)
1044 JCL_ThrowException(env, IO_EXCEPTION, strerror (errno));
1045 #else
1046 (void) fd;
1047 (void) data;
1048 JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
1049 #endif /* HAVE_WRITE */
1054 * Class: gnu_java_nio_VMChannel
1055 * Method: socket
1056 * Signature: (Z)I
1058 JNIEXPORT jint JNICALL
1059 Java_gnu_java_nio_VMChannel_socket (JNIEnv *env, jclass clazz __attribute__((unused)),
1060 jboolean stream)
1062 #ifdef HAVE_SOCKET
1063 int ret;
1067 ret = cpnio_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
1069 while (-1 == ret && EINTR == errno);
1071 if (ret == -1)
1072 JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
1073 /* NIODBG("created socket %d", ret); */
1075 return ret;
1076 #else
1077 (void) stream;
1078 JCL_ThrowException (env, IO_EXCEPTION, "socket not supported");
1079 return -1;
1080 #endif /* HAVE_SOCKET */
1085 * Class: gnu_java_nio_VMChannel
1086 * Method: connect
1087 * Signature: (I[BI)Z
1089 JNIEXPORT jboolean JNICALL
1090 Java_gnu_java_nio_VMChannel_connect (JNIEnv *env, jclass clazz __attribute__((unused)),
1091 jint fd, jbyteArray addr, jint port, jint timeout)
1093 #ifdef HAVE_CONNECT
1094 struct sockaddr_in sockaddr;
1095 struct timeval timeo;
1096 int origflags = 0, flags;
1097 jbyte *addr_elems;
1098 int ret;
1099 int tmpErrno;
1101 if ((*env)->GetArrayLength (env, addr) != 4)
1103 JCL_ThrowException (env, SOCKET_EXCEPTION,
1104 "expecting 4-byte address");
1105 return JNI_FALSE;
1108 if (timeout > 0)
1110 timeo.tv_sec = timeout / 1000;
1111 timeo.tv_usec = (timeout % 1000) * 1000;
1112 origflags = fcntl (fd, F_GETFL, 0);
1113 if (origflags == -1)
1115 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1116 return JNI_FALSE;
1118 /* Set nonblocking mode, if not already set. */
1119 if (!(origflags & O_NONBLOCK))
1121 flags = origflags | O_NONBLOCK;
1122 if (fcntl (fd, F_SETFL, flags) == -1)
1124 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1125 return JNI_FALSE;
1130 addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
1132 memset (&sockaddr, 0, sizeof (struct sockaddr_in));
1133 sockaddr.sin_family = AF_INET;
1134 sockaddr.sin_port = htons (port);
1135 sockaddr.sin_addr.s_addr = *((uint32_t *) addr_elems);
1140 ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
1141 sizeof (struct sockaddr_in));
1142 tmpErrno = errno;
1144 while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
1145 errno = tmpErrno;
1147 (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
1149 /* If a timeout was specified, select on the file descriptor with
1150 the timeout. */
1151 if (timeout > 0 && ret == -1)
1153 /* Reset the non-blocking flag, if needed. */
1154 if (!(origflags & O_NONBLOCK))
1156 if (fcntl (fd, F_SETFL, origflags) == -1)
1158 /* oops */
1159 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1160 return JNI_FALSE;
1163 if (EINPROGRESS == errno)
1165 fd_set wrfds;
1166 FD_ZERO(&wrfds);
1167 FD_SET(fd, &wrfds);
1168 ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
1169 if (ret == -1)
1171 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1172 return JNI_FALSE;
1174 if (ret == 0) /* connect timed out */
1176 JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
1177 "connect timed out");
1178 return JNI_FALSE;
1180 return JNI_TRUE; /* Connected! */
1182 else if (ECONNREFUSED == errno)
1184 JCL_ThrowException (env, CONNECT_EXCEPTION,
1185 strerror (errno));
1186 return JNI_FALSE;
1188 else
1190 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1191 return JNI_FALSE;
1195 if (ret == -1)
1197 if (EINPROGRESS == errno)
1198 return JNI_FALSE;
1199 else if (ECONNREFUSED == errno)
1201 JCL_ThrowException (env, CONNECT_EXCEPTION,
1202 strerror (errno));
1203 return JNI_FALSE;
1205 else
1207 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1208 return JNI_FALSE;
1212 return JNI_TRUE;
1213 #else
1214 (void) fd;
1215 (void) addr;
1216 (void) port;
1217 (void) timeout;
1218 JCL_ThrowException (env, SOCKET_EXCEPTION, "connect not supported");
1219 return JNI_FALSE;
1220 #endif /* HAVE_CONNECT */
1225 * Class: gnu_java_nio_VMChannel
1226 * Method: connect6
1227 * Signature: (I[BI)Z
1229 JNIEXPORT jboolean JNICALL
1230 Java_gnu_java_nio_VMChannel_connect6 (JNIEnv *env, jclass clazz __attribute__((unused)),
1231 jint fd, jbyteArray addr, jint port, int timeout)
1233 #if defined(HAVE_CONNECT) && defined(HAVE_INET6)
1234 struct sockaddr_in6 sockaddr;
1235 struct timeval timeo;
1236 int flags, origflags = 0;
1237 jbyte *addr_elems;
1238 int ret;
1240 if (timeout > 0)
1242 timeo.tv_sec = timeout / 1000;
1243 timeo.tv_usec = (timeout % 1000) * 1000;
1244 origflags = fcntl (fd, F_GETFL, 0);
1245 if (origflags == -1)
1247 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1248 return JNI_FALSE;
1250 /* Set nonblocking mode, if not already set. */
1251 if (!(origflags & O_NONBLOCK))
1253 flags = origflags | O_NONBLOCK;
1254 if (fcntl (fd, F_SETFL, flags) == -1)
1256 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1257 return JNI_FALSE;
1262 addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
1264 memset (&sockaddr, 0, sizeof (struct sockaddr_in6));
1265 sockaddr.sin6_family = AF_INET6;
1266 sockaddr.sin6_port = htons (port);
1267 memcpy (&sockaddr.sin6_addr.s6_addr, addr_elems, 16);
1269 ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
1270 sizeof (struct sockaddr_in6));
1272 (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
1274 /* If a timeout was specified, select on the file descriptor with
1275 the timeout. */
1276 if (timeout > 0 && ret == -1)
1278 /* Reset the non-blocking flag, if needed. */
1279 if (!(origflags & O_NONBLOCK))
1281 if (fcntl (fd, F_SETFL, origflags) == -1)
1283 /* oops */
1284 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1285 return JNI_FALSE;
1288 if (EINPROGRESS == errno)
1290 fd_set wrfds;
1291 FD_ZERO(&wrfds);
1292 FD_SET(fd, &wrfds);
1293 ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
1294 if (ret == -1)
1296 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1297 return JNI_FALSE;
1299 if (ret == 0) /* connect timed out */
1301 JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
1302 "connect timed out");
1303 return JNI_FALSE;
1305 return JNI_TRUE; /* Connected! */
1307 else if (ECONNREFUSED == errno)
1309 JCL_ThrowException (env, CONNECT_EXCEPTION,
1310 strerror (errno));
1311 return JNI_FALSE;
1313 else
1315 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1316 return JNI_FALSE;
1320 if (ret == -1)
1322 if (EAGAIN == errno)
1323 return JNI_FALSE;
1324 else if (ECONNREFUSED == errno)
1326 JCL_ThrowException (env, CONNECT_EXCEPTION,
1327 strerror (errno));
1328 return JNI_FALSE;
1330 else
1332 JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
1333 return JNI_FALSE;
1337 return JNI_TRUE;
1338 #else
1339 (void) fd;
1340 (void) addr;
1341 (void) port;
1342 (void) timeout;
1343 JCL_ThrowException (env, SOCKET_EXCEPTION, "IPv6 connect not supported");
1344 return JNI_FALSE;
1345 #endif /* HAVE_CONNECT && HAVE_INET6 */
1350 * Class: gnu_java_nio_VMChannel
1351 * Method: getsockname
1352 * Signature: (ILjava/nio/ByteBuffer;)I
1354 JNIEXPORT jint JNICALL
1355 Java_gnu_java_nio_VMChannel_getsockname (JNIEnv *env, jclass clazz __attribute__((unused)),
1356 jint fd, jobject name)
1358 #ifdef HAVE_GETSOCKNAME
1359 #ifdef HAVE_INET6
1360 struct sockaddr_in6 *addr6;
1361 struct sockaddr_in6 sock_storage;
1362 socklen_t socklen = sizeof (struct sockaddr_in6);
1363 #else
1364 struct sockaddr_in sock_storage;
1365 socklen_t socklen = sizeof (struct sockaddr_in);
1366 #endif /* HAVE_INET6 */
1368 struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
1369 struct sockaddr_in *addr4;
1370 int ret;
1371 char *nameptr = (*env)->GetDirectBufferAddress (env, name);
1373 ret = getsockname (fd, sockaddr, &socklen);
1374 if (ret == -1)
1376 JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
1377 return 0;
1380 if (sockaddr->sa_family == AF_INET)
1382 addr4 = (struct sockaddr_in *) sockaddr;
1383 memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
1384 memcpy (nameptr + 4, &(addr4->sin_port), 2);
1385 return 4;
1388 #ifdef HAVE_INET6
1389 /* IPv6 */
1390 if (sockaddr->sa_family == AF_INET6)
1392 addr6 = (struct sockaddr_in6 *) sockaddr;
1393 memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
1394 memcpy (nameptr + 16, &(addr6->sin6_port), 2);
1395 return 16;
1397 #endif /* HAVE_INET6 */
1398 JCL_ThrowException (env, IO_EXCEPTION, "unsupported address format");
1399 return -1;
1400 #else
1401 (void) fd;
1402 (void) name;
1403 JCL_ThrowException (env, IO_EXCEPTION, "getsockname not supported");
1404 return -1;
1405 #endif /* HAVE_GETSOCKNAME */
1410 * Class: gnu_java_nio_VMChannel
1411 * Method: getpeername
1412 * Signature: (ILjava/nio/ByteBuffer;)I
1414 JNIEXPORT jint JNICALL
1415 Java_gnu_java_nio_VMChannel_getpeername (JNIEnv *env, jclass clazz __attribute__((unused)),
1416 jint fd, jobject name)
1418 #ifdef HAVE_GETPEERNAME
1419 #ifdef HAVE_INET6
1420 struct sockaddr_in6 *addr6;
1421 struct sockaddr_in6 sock_storage;
1422 socklen_t socklen = sizeof (struct sockaddr_in6);
1423 #else
1424 struct sockaddr_in sock_storage;
1425 socklen_t socklen = sizeof (struct sockaddr_in);
1426 #endif /* HAVE_INET6 */
1428 struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
1429 struct sockaddr_in *addr4;
1430 int ret;
1431 char *nameptr = (*env)->GetDirectBufferAddress (env, name);
1433 ret = getpeername (fd, sockaddr, &socklen);
1434 if (ret == -1)
1436 if (ENOTCONN != errno)
1437 JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
1438 return 0;
1441 if (sockaddr->sa_family == AF_INET)
1443 addr4 = (struct sockaddr_in *) sockaddr;
1444 memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
1445 memcpy (nameptr + 4, &(addr4->sin_port), 2);
1446 return 4;
1448 #ifdef HAVE_INET6
1449 else if (sockaddr->sa_family == AF_INET6)
1451 addr6 = (struct sockaddr_in6 *) sockaddr;
1452 memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
1453 memcpy (nameptr + 16, &(addr6->sin6_port), 2);
1454 return 16;
1456 #endif /* HAVE_INET6 */
1458 JCL_ThrowException (env, "java/net/SocketException",
1459 "unsupported address type");
1460 return -1;
1461 #else
1462 (void) fd;
1463 (void) name;
1464 JCL_ThrowException (env, IO_EXCEPTION, "getpeername not supported");
1465 return -1;
1466 #endif /* HAVE_GETPEERNAME */
1471 * Class: gnu_java_nio_VMChannel
1472 * Method: accept
1473 * Signature: (I)I
1475 JNIEXPORT jint JNICALL
1476 Java_gnu_java_nio_VMChannel_accept (JNIEnv *env,
1477 jclass c __attribute__((unused)),
1478 jint fd)
1480 #ifdef HAVE_ACCEPT
1481 int ret;
1482 int tmp_errno = 0;
1484 #ifdef HAVE_INET6
1485 struct sockaddr_in6 addr;
1486 socklen_t alen = sizeof (struct sockaddr_in6);
1487 #else
1488 struct sockaddr_in addr;
1489 socklen_t alen = sizeof (struct sockaddr_in);
1490 #endif /* HAVE_INET6 */
1494 ret = cpnio_accept (fd, (struct sockaddr *) &addr, &alen);
1495 tmp_errno = errno;
1497 if (ret == -1)
1498 switch (tmp_errno)
1500 case EINTR:
1501 /* Check if interrupted by Thread.interrupt(). If not then some
1502 * other unrelated signal interrupted the system function and
1503 * we should start over again.
1505 if (JCL_thread_interrupted(env))
1507 JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
1508 return -1;
1510 break;
1511 #if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN
1512 case EWOULDBLOCK:
1513 #endif
1514 case EAGAIN:
1515 if (!is_non_blocking_fd(fd))
1517 JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "Accept timed out");
1519 /* Socket in non-blocking mode and no pending connection. */
1520 return -1;
1521 default:
1522 JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
1523 return -1;
1525 else
1526 break;
1528 while (1);
1530 cpio_closeOnExec(ret);
1532 return ret;
1533 #else
1534 (void) fd;
1535 JCL_ThrowException (env, IO_EXCEPTION, "accept not supported");
1536 return -1;
1537 #endif /* HAVE_ACCEPT */
1543 * Class: gnu_java_nio_VMChannel
1544 * Method: disconnect
1545 * Signature: (I)V
1547 JNIEXPORT void JNICALL
1548 Java_gnu_java_nio_VMChannel_disconnect (JNIEnv *env,
1549 jclass c __attribute__((unused)),
1550 jint fd)
1552 struct sockaddr sockaddr;
1554 sockaddr.sa_family = AF_UNSPEC;
1555 if (connect (fd, &sockaddr, sizeof (struct sockaddr)) == -1)
1557 /* The expected error for a successful disconnect is EAFNOSUPPORT. */
1558 if (errno != EAFNOSUPPORT)
1559 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1565 * Class: gnu_java_nio_VMChannel
1566 * Method: close
1567 * Signature: (I)V
1569 JNIEXPORT void JNICALL
1570 Java_gnu_java_nio_VMChannel_close (JNIEnv *env,
1571 jclass c __attribute__((unused)),
1572 jint fd)
1574 if (close (fd) == -1)
1575 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1580 * Class: gnu_java_nio_VMChannel
1581 * Method: available
1582 * Signature: (I)I
1584 JNIEXPORT jint JNICALL
1585 Java_gnu_java_nio_VMChannel_available (JNIEnv *env,
1586 jclass c __attribute__((unused)),
1587 jint fd)
1589 #if defined (FIONREAD)
1591 jint avail = 0;
1593 #if defined(ENOTTY) && defined(HAVE_FSTAT)
1594 struct stat statBuffer;
1595 off_t n;
1596 #endif
1598 /* NIODBG("fd: %d", fd); */
1599 if (ioctl (fd, FIONREAD, &avail) == -1)
1601 #if defined(ENOTTY) && defined(HAVE_FSTAT)
1602 if (errno == ENOTTY)
1604 if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
1606 n = lseek (fd, 0, SEEK_CUR);
1607 if (n != -1)
1609 avail = statBuffer.st_size - n;
1610 return avail;
1614 #endif
1615 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1617 /* NIODBG("avail: %d", avail); */
1619 return avail;
1621 #elif defined(HAVE_FSTAT)
1623 jint avail = 0;
1625 struct stat statBuffer;
1626 off_t n;
1628 if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
1630 n = lseek (fd, 0, SEEK_CUR);
1631 if (n != -1)
1633 avail = statBuffer.st_size - n;
1634 return avail;
1637 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1639 #elif defined(HAVE_SELECT)
1641 jint avail = 0;
1642 fd_set filedescriptset;
1643 struct timeval tv;
1645 FD_ZERO (&filedescriptset);
1646 FD_SET (fd,&filedescriptset);
1647 memset (&tv, 0, sizeof(tv));
1649 switch (select (fd+1, &filedescriptset, NULL, NULL, &tv))
1651 case -1:
1652 break;
1653 case 0:
1654 avail = 0;
1655 return avail;
1656 default:
1657 avail = 1;
1658 return avail;
1660 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1662 #else
1664 JCL_ThrowException (env, IO_EXCEPTION, "No native method for available");
1666 #endif
1670 enum FileChannel_mode {
1671 CPNIO_READ = 1,
1672 CPNIO_WRITE = 2,
1673 CPNIO_APPEND = 4,
1674 CPNIO_EXCL = 8,
1675 CPNIO_SYNC = 16,
1676 CPNIO_DSYNC = 32
1681 * Class: gnu_java_nio_VMChannel
1682 * Method: open
1683 * Signature: (Ljava/lang/String;I)I
1685 JNIEXPORT jint JNICALL
1686 Java_gnu_java_nio_VMChannel_open (JNIEnv *env,
1687 jclass c __attribute__((unused)),
1688 jstring path, jint mode)
1690 int nmode = 0;
1691 int ret;
1692 const char *npath;
1694 if ((mode & CPNIO_READ) && (mode & CPNIO_WRITE))
1695 nmode = O_RDWR;
1696 else if (mode & CPNIO_WRITE)
1697 nmode = O_WRONLY;
1698 else
1699 nmode = O_RDONLY;
1701 nmode = (nmode
1702 | ((nmode == O_RDWR || nmode == O_WRONLY) ? O_CREAT : 0)
1703 | ((mode & CPNIO_APPEND) ? O_APPEND :
1704 ((nmode == O_WRONLY) ? O_TRUNC : 0))
1705 | ((mode & CPNIO_EXCL) ? O_EXCL : 0)
1706 | ((mode & CPNIO_SYNC) ? O_SYNC : 0));
1708 npath = JCL_jstring_to_cstring (env, path);
1710 /* NIODBG("path: %s; mode: %x", npath, nmode); */
1712 ret = open (npath, nmode, 0666);
1714 /* NIODBG("ret: %d\n", ret); */
1716 JCL_free_cstring (env, path, npath);
1718 if (-1 == ret)
1719 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1721 return ret;
1726 * Class: gnu_java_nio_VMChannel
1727 * Method: position
1728 * Signature: (I)J
1730 JNIEXPORT jlong JNICALL
1731 Java_gnu_java_nio_VMChannel_position (JNIEnv *env,
1732 jclass c __attribute__((unused)),
1733 jint fd)
1735 #ifdef HAVE_LSEEK
1736 off_t ret;
1738 ret = lseek (fd, 0, SEEK_CUR);
1740 if (-1 == ret)
1741 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1743 return (jlong) ret;
1744 #else
1745 JCL_ThrowException (env, IO_EXCEPTION, "position not supported");
1746 return -1;
1747 #endif /* HAVE_LSEEK */
1752 * Class: gnu_java_nio_VMChannel
1753 * Method: seek
1754 * Signature: (IJ)V
1756 JNIEXPORT void JNICALL
1757 Java_gnu_java_nio_VMChannel_seek (JNIEnv *env,
1758 jclass c __attribute__((unused)),
1759 jint fd, jlong pos)
1761 #ifdef HAVE_LSEEK
1762 if (lseek (fd, (off_t) pos, SEEK_SET) == -1)
1763 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1764 #else
1765 JCL_ThrowException (env, IO_EXCEPTION, "seek not supported");
1766 #endif /* HAVE_LSEEK */
1771 * Class: gnu_java_nio_VMChannel
1772 * Method: truncate
1773 * Signature: (IJ)V
1775 JNIEXPORT void JNICALL
1776 Java_gnu_java_nio_VMChannel_truncate (JNIEnv *env,
1777 jclass c __attribute__((unused)),
1778 jint fd, jlong len)
1780 #if defined(HAVE_FTRUNCATE) && defined(HAVE_LSEEK)
1781 off_t pos = lseek (fd, 0, SEEK_CUR);
1782 if (pos == -1)
1784 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1785 return;
1787 if (ftruncate (fd, (off_t) len) == -1)
1789 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1790 return;
1792 if (pos > len)
1794 if (lseek (fd, len, SEEK_SET) == -1)
1795 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1797 #else
1798 JCL_ThrowException (env, IO_EXCEPTION, "truncate not supported");
1799 #endif /* HAVE_FTRUNCATE && HAVE_LSEEK */
1804 * Class: gnu_java_nio_VMChannel
1805 * Method: lock
1806 * Signature: (IJJZZ)Z
1808 JNIEXPORT jboolean JNICALL
1809 Java_gnu_java_nio_VMChannel_lock (JNIEnv *env,
1810 jclass c __attribute__((unused)),
1811 jint fd, jlong pos, jlong len,
1812 jboolean shared, jboolean wait)
1814 #if HAVE_FCNTL
1815 struct flock fl;
1817 fl.l_start = (off_t) pos;
1818 /* Long.MAX_VALUE means lock everything possible starting at pos. */
1819 if (len == 9223372036854775807LL)
1820 fl.l_len = 0;
1821 else
1822 fl.l_len = (off_t) len;
1823 fl.l_pid = getpid ();
1824 fl.l_type = (shared ? F_RDLCK : F_WRLCK);
1825 fl.l_whence = SEEK_SET;
1827 if (cpnio_fcntl (fd, (wait ? F_SETLKW : F_SETLK), (long) &fl) == -1)
1829 if (errno != EAGAIN)
1830 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1831 return JNI_FALSE;
1834 return JNI_TRUE;
1835 #else
1836 JCL_ThrowException (env, IO_EXCEPTION, "lock not supported");
1837 return JNI_FALSE;
1838 #endif /* HAVE_FCNTL */
1842 * Class: gnu_java_nio_VMChannel
1843 * Method: unlock
1844 * Signature: (IJJ)V
1846 JNIEXPORT void JNICALL
1847 Java_gnu_java_nio_VMChannel_unlock (JNIEnv *env,
1848 jclass c __attribute__((unused)),
1849 jint fd, jlong pos, jlong len)
1851 #if HAVE_FCNTL
1852 struct flock fl;
1854 fl.l_start = (off_t) pos;
1855 fl.l_len = (off_t) len;
1856 fl.l_pid = getpid ();
1857 fl.l_type = F_UNLCK;
1858 fl.l_whence = SEEK_SET;
1860 if (cpnio_fcntl (fd, F_SETLK, (long) &fl) == -1)
1862 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1864 #else
1865 JCL_ThrowException (env, IO_EXCEPTION, "unlock not supported");
1866 #endif /* HAVE_FCNTL */
1870 * Class: gnu_java_nio_VMChannel
1871 * Method: size
1872 * Signature: (I)J
1874 JNIEXPORT jlong JNICALL
1875 Java_gnu_java_nio_VMChannel_size (JNIEnv *env,
1876 jclass c __attribute__((unused)),
1877 jint fd)
1879 #ifdef HAVE_FSTAT
1880 struct stat st;
1882 if (fstat (fd, &st) == -1)
1883 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1885 return (jlong) st.st_size;
1886 #else
1887 JCL_ThrowException (env, IO_EXCEPTION, "size not supported");
1888 return 0;
1889 #endif
1893 * Class: gnu_java_nio_VMChannel
1894 * Method: map
1895 * Signature: (ICJI)Lgnu/classpath/Pointer;
1897 JNIEXPORT jobject JNICALL
1898 Java_gnu_java_nio_VMChannel_map (JNIEnv *env,
1899 jclass clazz __attribute__((unused)),
1900 jint fd, jchar mode, jlong position, jint size)
1902 #ifdef HAVE_MMAP
1903 jclass MappedByteBufferImpl_class;
1904 jmethodID MappedByteBufferImpl_init = NULL;
1905 jobject Pointer_instance;
1906 volatile jobject buffer;
1907 long pagesize;
1908 int prot, flags;
1909 void *p;
1910 void *address;
1912 /* NIODBG("fd: %d; mode: %x; position: %lld; size: %d", */
1913 /* fd, mode, position, size); */
1915 /* FIXME: should we just assume we're on an OS modern enough to
1916 have 'sysconf'? And not check for 'getpagesize'? */
1917 #if defined(HAVE_GETPAGESIZE)
1918 pagesize = getpagesize ();
1919 #elif defined(HAVE_SYSCONF)
1920 pagesize = sysconf (_SC_PAGESIZE);
1921 #else
1922 JCL_ThrowException (env, IO_EXCEPTION,
1923 "can't determine memory page size");
1924 return NULL;
1925 #endif /* HAVE_GETPAGESIZE/HAVE_SYSCONF */
1927 if ((*env)->ExceptionOccurred (env))
1929 return NULL;
1932 prot = PROT_READ;
1933 if (mode == '+' || mode == 'c')
1935 /* When writing we need to make sure the file is big enough,
1936 otherwise the result of mmap is undefined. */
1937 struct stat st;
1938 if (fstat (fd, &st) == -1)
1940 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1941 return NULL;
1943 if (position + size > st.st_size)
1945 if (ftruncate(fd, position + size) == -1)
1947 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1948 return NULL;
1951 prot |= PROT_WRITE;
1954 flags = (mode == 'c' ? MAP_PRIVATE : MAP_SHARED);
1955 p = mmap (NULL, (size_t) ALIGN_UP (size, pagesize), prot, flags,
1956 fd, ALIGN_DOWN (position, pagesize));
1957 if (p == MAP_FAILED)
1959 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
1960 return NULL;
1963 /* Unalign the mapped value back up, since we aligned offset
1964 down to a multiple of the page size. */
1965 address = (void *) ((char *) p + (position % pagesize));
1967 Pointer_instance = JCL_NewRawDataObject(env, address);
1969 MappedByteBufferImpl_class = (*env)->FindClass (env,
1970 "java/nio/MappedByteBufferImpl");
1971 if (MappedByteBufferImpl_class != NULL)
1973 MappedByteBufferImpl_init =
1974 (*env)->GetMethodID (env, MappedByteBufferImpl_class,
1975 "<init>", "(Lgnu/classpath/Pointer;IZ)V");
1978 if ((*env)->ExceptionOccurred (env))
1980 munmap (p, ALIGN_UP (size, pagesize));
1981 return NULL;
1983 if (MappedByteBufferImpl_init == NULL)
1985 JCL_ThrowException (env, "java/lang/InternalError",
1986 "could not get MappedByteBufferImpl constructor");
1987 munmap (p, ALIGN_UP (size, pagesize));
1988 return NULL;
1991 buffer = (*env)->NewObject (env, MappedByteBufferImpl_class,
1992 MappedByteBufferImpl_init, Pointer_instance,
1993 (jint) size, mode == 'r');
1994 return buffer;
1995 #else
1996 (void) fd;
1997 (void) mode;
1998 (void) position;
1999 (void) size;
2000 JCL_ThrowException (env, IO_EXCEPTION,
2001 "memory-mapped files not implemented");
2002 return 0;
2003 #endif /* HAVE_MMAP */
2007 * Class: gnu_java_nio_VMChannel
2008 * Method: flush
2009 * Signature: (IZ)Z
2011 JNIEXPORT jboolean JNICALL
2012 Java_gnu_java_nio_VMChannel_flush (JNIEnv *env,
2013 jclass c __attribute__((unused)),
2014 jint fd, jboolean metadata __attribute__((unused)))
2016 #ifdef HAVE_FSYNC
2017 /* XXX blocking? */
2018 if (fsync (fd) == -1)
2020 JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
2021 return JNI_FALSE;
2023 return JNI_TRUE;
2024 #else
2025 JCL_ThrowException (env, IO_EXCEPTION, "flush not implemented");
2026 return JNI_TRUE;
2027 #endif /* HAVE_FSYNC */
2031 #ifdef __cplusplus
2033 #endif