mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			2036 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			2036 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
/* gnu_java_nio_VMChannel.c -
 | 
						|
   Copyright (C) 2003, 2004, 2005, 2006, 2007  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
#ifdef HAVE_CONFIG_H
 | 
						|
#include <config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <config-int.h>
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#ifdef HAVE_SYS_MMAN_H
 | 
						|
#include <sys/mman.h>
 | 
						|
#endif
 | 
						|
#include <sys/socket.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <sys/uio.h>
 | 
						|
 | 
						|
#include <netinet/in.h>
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include <jni.h>
 | 
						|
#include <jcl.h>
 | 
						|
 | 
						|
#include "cpio.h"
 | 
						|
#include "gnu_java_nio_VMChannel.h"
 | 
						|
#include "javanio.h"
 | 
						|
 | 
						|
#ifdef HAVE_FCNTL_H
 | 
						|
#include <fcntl.h>
 | 
						|
#endif /* HAVE_FCNTL_H */
 | 
						|
 | 
						|
#if defined(HAVE_SYS_IOCTL_H)
 | 
						|
#define BSD_COMP /* Get FIONREAD on Solaris2 */
 | 
						|
#include <sys/ioctl.h>
 | 
						|
#endif
 | 
						|
#if defined(HAVE_SYS_FILIO_H) /* Get FIONREAD on Solaris 2.5 */
 | 
						|
#include <sys/filio.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#define CONNECT_EXCEPTION "java/net/ConnectException"
 | 
						|
#define IO_EXCEPTION "java/io/IOException"
 | 
						|
#define SOCKET_EXCEPTION "java/net/SocketException"
 | 
						|
#define INTERRUPTED_IO_EXCEPTION "java/io/InterruptedIOException"
 | 
						|
#define NON_READABLE_CHANNEL_EXCEPTION "java/nio/channels/NonReadableChannelException"
 | 
						|
#define NON_WRITABLE_CHANNEL_EXCEPTION "java/nio/channels/NonWritableChannelException"
 | 
						|
#define SOCKET_TIMEOUT_EXCEPTION "java/net/SocketTimeoutException"
 | 
						|
 | 
						|
/* Align a value up or down to a multiple of the pagesize. */
 | 
						|
#define ALIGN_DOWN(p,s) ((p) - ((p) % (s)))
 | 
						|
#define ALIGN_UP(p,s) ((p) + ((s) - ((p) % (s))))
 | 
						|
 | 
						|
/*
 | 
						|
 * Limit to maximum of 16 buffers
 | 
						|
 */
 | 
						|
#define JCL_IOV_MAX 16
 | 
						|
 | 
						|
#ifdef __cplusplus
 | 
						|
extern "C"
 | 
						|
{
 | 
						|
#endif
 | 
						|
 | 
						|
enum JCL_buffer_type { DIRECT, HEAP, ARRAY, UNKNOWN };
 | 
						|
 | 
						|
struct JCL_buffer
 | 
						|
{
 | 
						|
  enum JCL_buffer_type type;
 | 
						|
  jbyte *ptr;
 | 
						|
  jint offset;
 | 
						|
  jint position;
 | 
						|
  jint limit;
 | 
						|
  jint count;
 | 
						|
};
 | 
						|
 | 
						|
jmethodID get_method_id(JNIEnv *, jclass, const char *, const char *);
 | 
						|
void JCL_print_buffer(JNIEnv *, struct JCL_buffer *);
 | 
						|
int JCL_init_buffer(JNIEnv *, struct JCL_buffer *, jobject);
 | 
						|
void JCL_release_buffer(JNIEnv *, struct JCL_buffer *, jobject, jint);
 | 
						|
void JCL_cleanup_buffers(JNIEnv *, struct JCL_buffer *, jint, jobjectArray, jint, jlong);
 | 
						|
int JCL_thread_interrupted(JNIEnv *);
 | 
						|
 | 
						|
static jfieldID address_fid;
 | 
						|
static jmethodID get_position_mid;
 | 
						|
static jmethodID set_position_mid;
 | 
						|
static jmethodID get_limit_mid;
 | 
						|
static jmethodID set_limit_mid;
 | 
						|
static jmethodID has_array_mid;
 | 
						|
static jmethodID array_mid;
 | 
						|
static jmethodID array_offset_mid;
 | 
						|
static jmethodID thread_interrupted_mid;
 | 
						|
static jclass vm_channel_class;
 | 
						|
 | 
						|
jmethodID
 | 
						|
get_method_id(JNIEnv *env,  jclass clazz, const char *name, 
 | 
						|
	          const char *sig)
 | 
						|
{
 | 
						|
  jmethodID mid = (*env)->GetMethodID(env, clazz, name, sig);
 | 
						|
/*   NIODBG("name: %s; sig: %s", name, sig); */
 | 
						|
  if (mid == NULL)
 | 
						|
    {
 | 
						|
      JCL_ThrowException(env, "java/lang/InternalError", name);
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  
 | 
						|
  return mid;
 | 
						|
}
 | 
						|
 | 
						|
inline void
 | 
						|
JCL_print_buffer(JNIEnv *env __attribute__((__unused__)), struct JCL_buffer *buf)
 | 
						|
{
 | 
						|
  fprintf (stderr, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf)
 | 
						|
{
 | 
						|
  void *addr = (*env)->GetDirectBufferAddress (env, bbuf);
 | 
						|
 | 
						|
/*   NIODBG("buf: %p; bbuf: %p; addr: %p", (void *) buf, bbuf, addr); */
 | 
						|
  
 | 
						|
  buf->position = (*env)->CallIntMethod(env, bbuf, get_position_mid);
 | 
						|
  buf->limit = (*env)->CallIntMethod(env, bbuf, get_limit_mid);
 | 
						|
  buf->offset = 0;
 | 
						|
  buf->count = 0;
 | 
						|
  buf->type = UNKNOWN;
 | 
						|
    
 | 
						|
  if (addr != NULL)
 | 
						|
    {
 | 
						|
      buf->ptr = (jbyte *) addr;
 | 
						|
      buf->type = DIRECT;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      jboolean has_array;
 | 
						|
      has_array = (*env)->CallBooleanMethod(env, bbuf, has_array_mid);
 | 
						|
      
 | 
						|
      if (has_array == JNI_TRUE)
 | 
						|
        {
 | 
						|
          jbyteArray arr;
 | 
						|
          buf->offset = (*env)->CallIntMethod(env, bbuf, array_offset_mid);
 | 
						|
          arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
 | 
						|
          buf->ptr = (*env)->GetByteArrayElements(env, arr, 0);
 | 
						|
          buf->type = ARRAY;
 | 
						|
          (*env)->DeleteLocalRef(env, arr);
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          jobject address = (*env)->GetObjectField (env, bbuf, address_fid);
 | 
						|
          if (address == NULL)
 | 
						|
            return -1; /* XXX handle non-array, non-native buffers? */
 | 
						|
          buf->ptr = (jbyte *) JCL_GetRawData(env, address);
 | 
						|
          buf->type = HEAP;
 | 
						|
          (*env)->DeleteLocalRef(env, address);
 | 
						|
        }
 | 
						|
    }
 | 
						|
      
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf, 
 | 
						|
    jint action)
 | 
						|
{
 | 
						|
  jbyteArray arr;
 | 
						|
 | 
						|
/*   NIODBG("buf: %p; bbuf: %p; action: %x", (void *) buf, bbuf, action); */
 | 
						|
  
 | 
						|
  /* Set the position to the appropriate value */
 | 
						|
  if (buf->count > 0)
 | 
						|
    {
 | 
						|
      jobject bbufTemp;
 | 
						|
      bbufTemp = (*env)->CallObjectMethod(env, bbuf, set_position_mid, 
 | 
						|
                                          buf->position + buf->count);
 | 
						|
      (*env)->DeleteLocalRef(env, bbufTemp);
 | 
						|
    }
 | 
						|
    
 | 
						|
  switch (buf->type)
 | 
						|
    {
 | 
						|
    case DIRECT:
 | 
						|
    case HEAP:
 | 
						|
      break;
 | 
						|
    case ARRAY:
 | 
						|
      arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
 | 
						|
      (*env)->ReleaseByteArrayElements(env, arr, buf->ptr, action);
 | 
						|
      (*env)->DeleteLocalRef(env, arr);
 | 
						|
      break;
 | 
						|
    case UNKNOWN:
 | 
						|
      /* TODO: Handle buffers that are not direct or array backed */
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
JCL_cleanup_buffers(JNIEnv *env, 
 | 
						|
                    struct JCL_buffer *bi_list, 
 | 
						|
                    jint vec_len, 
 | 
						|
                    jobjectArray bbufs, 
 | 
						|
                    jint offset,
 | 
						|
                    jlong num_bytes)
 | 
						|
{
 | 
						|
  jint i;
 | 
						|
 | 
						|
/*   NIODBG("bi_list: %p; vec_len: %d; bbufs: %p; offset: %d; num_bytes: %lld", */
 | 
						|
/*       (void *) bi_list, vec_len, bbufs, offset, num_bytes); */
 | 
						|
  
 | 
						|
  /* Update all of the bbufs with the approriate information */
 | 
						|
  for (i = 0; i < vec_len; i++)
 | 
						|
    {
 | 
						|
      struct JCL_buffer* buf;
 | 
						|
      jobject bbuf;
 | 
						|
      
 | 
						|
      buf = &bi_list[i];
 | 
						|
      bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
 | 
						|
 | 
						|
      if (num_bytes > (buf->limit - buf->position))
 | 
						|
        buf->count = (buf->limit - buf->position);
 | 
						|
      else
 | 
						|
        buf->count = num_bytes;
 | 
						|
        
 | 
						|
      num_bytes -= buf->count;
 | 
						|
      
 | 
						|
      JCL_release_buffer(env, buf, bbuf, JNI_ABORT);
 | 
						|
      (*env)->DeleteLocalRef(env, bbuf);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
JCL_thread_interrupted(JNIEnv *env)
 | 
						|
{
 | 
						|
  return (int) (*env)->CallStaticBooleanMethod(env, vm_channel_class,
 | 
						|
					       thread_interrupted_mid);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    stdin_fd
 | 
						|
 * Signature: ()I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_stdin_1fd (JNIEnv *env __attribute__((unused)),
 | 
						|
                                       jclass c __attribute__((unused)))
 | 
						|
{
 | 
						|
/*   NIODBG("%d", fileno (stdin)); */
 | 
						|
  return fileno (stdin);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    stdout_fd
 | 
						|
 * Signature: ()I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_stdout_1fd (JNIEnv *env __attribute__((unused)),
 | 
						|
                                       jclass c __attribute__((unused)))
 | 
						|
{
 | 
						|
/*   NIODBG("%d", fileno (stdout)); */
 | 
						|
  return fileno (stdout);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    stderr_fd
 | 
						|
 * Signature: ()I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_stderr_1fd (JNIEnv *env __attribute__((unused)),
 | 
						|
                                       jclass c __attribute__((unused)))
 | 
						|
{
 | 
						|
/*   NIODBG("%d", fileno (stderr)); */
 | 
						|
  return fileno (stderr);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
JNIEXPORT void JNICALL 
 | 
						|
Java_gnu_java_nio_VMChannel_initIDs  (JNIEnv *env, 
 | 
						|
	jclass clazz)
 | 
						|
{
 | 
						|
  jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer");
 | 
						|
  jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer");
 | 
						|
 | 
						|
/*   NIODBG("%s", "..."); */
 | 
						|
 | 
						|
  address_fid = (*env)->GetFieldID(env, bufferClass, "address", 
 | 
						|
                                   "Lgnu/classpath/Pointer;");
 | 
						|
  if (address_fid == NULL)
 | 
						|
    {
 | 
						|
  	  JCL_ThrowException(env, "java/lang/InternalError", 
 | 
						|
  	  	"Unable to find internal field");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  
 | 
						|
  get_position_mid = get_method_id(env, bufferClass, "position", "()I");
 | 
						|
  set_position_mid = get_method_id(env, bufferClass, "position", 
 | 
						|
                                   "(I)Ljava/nio/Buffer;");
 | 
						|
  get_limit_mid = get_method_id(env, bufferClass, "limit", "()I");
 | 
						|
  set_limit_mid = get_method_id(env, bufferClass, "limit", 
 | 
						|
                                "(I)Ljava/nio/Buffer;");
 | 
						|
  has_array_mid = get_method_id(env, byteBufferClass, "hasArray", "()Z");
 | 
						|
  array_mid = get_method_id(env, byteBufferClass, "array", "()[B");
 | 
						|
  array_offset_mid = get_method_id(env, byteBufferClass, "arrayOffset", "()I");
 | 
						|
  
 | 
						|
  vm_channel_class = clazz;
 | 
						|
  thread_interrupted_mid = (*env)->GetStaticMethodID(env, clazz,
 | 
						|
                                                  "isThreadInterrupted",
 | 
						|
                                                  "()Z");
 | 
						|
}
 | 
						|
 | 
						|
JNIEXPORT void JNICALL 
 | 
						|
Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env, 
 | 
						|
	jobject o __attribute__ ((__unused__)), 
 | 
						|
	jint fd, 
 | 
						|
	jboolean blocking)
 | 
						|
{
 | 
						|
  int opts;
 | 
						|
  
 | 
						|
/*   NIODBG("fd: %d; blocking: %d", fd, blocking); */
 | 
						|
 | 
						|
  opts = fcntl(fd, F_GETFL);
 | 
						|
  if (opts < 0)
 | 
						|
    {
 | 
						|
      JCL_ThrowException(env, IO_EXCEPTION, 
 | 
						|
        "Failed to get flags for file desriptor");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (blocking == JNI_TRUE)
 | 
						|
    opts &= ~(O_NONBLOCK);
 | 
						|
  else
 | 
						|
    opts |= O_NONBLOCK;
 | 
						|
  
 | 
						|
  opts = fcntl(fd, F_SETFL, opts);
 | 
						|
  
 | 
						|
  if (opts < 0)
 | 
						|
    {
 | 
						|
      JCL_ThrowException(env, IO_EXCEPTION, 
 | 
						|
        "Failed to set flags for file desriptor");
 | 
						|
      return;
 | 
						|
    }  
 | 
						|
}
 | 
						|
 | 
						|
/* Return true if fd is in non-blocking mode. */
 | 
						|
static jboolean
 | 
						|
is_non_blocking_fd(jint fd)
 | 
						|
{
 | 
						|
  int opts;
 | 
						|
  opts = fcntl(fd, F_GETFL);
 | 
						|
  if (opts == -1)
 | 
						|
    {
 | 
						|
      /* Assume blocking on error. */
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  return (opts & O_NONBLOCK) != 0;
 | 
						|
}
 | 
						|
 | 
						|
JNIEXPORT jint JNICALL 
 | 
						|
Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
 | 
						|
                                                           jobject o __attribute__ ((__unused__)), 
 | 
						|
                                                           jint fd, 
 | 
						|
                                                           jobject bbuf)
 | 
						|
{
 | 
						|
#ifdef HAVE_READ
 | 
						|
  jint len;
 | 
						|
  ssize_t result;
 | 
						|
  struct JCL_buffer buf;
 | 
						|
  int tmp_errno;
 | 
						|
 | 
						|
/*   NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
 | 
						|
  
 | 
						|
  if (JCL_init_buffer(env, &buf, bbuf) < 0)
 | 
						|
    {
 | 
						|
      /* TODO: Rethrown exception */
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  len = buf.limit - buf.position;
 | 
						|
 | 
						|
  if (len == 0)
 | 
						|
    {
 | 
						|
      JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  
 | 
						|
  do 
 | 
						|
    {
 | 
						|
      result = cpnio_read (fd, &(buf.ptr[buf.position + buf.offset]), len);
 | 
						|
      tmp_errno = errno;
 | 
						|
    }
 | 
						|
  while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
 | 
						|
  errno = tmp_errno;
 | 
						|
  
 | 
						|
  if (result == 0)
 | 
						|
    {
 | 
						|
      result = -1;
 | 
						|
      buf.count = 0;
 | 
						|
    }
 | 
						|
  else if (result == -1)
 | 
						|
    {
 | 
						|
      buf.count = 0;
 | 
						|
      if (errno == EAGAIN)
 | 
						|
        {
 | 
						|
          if (is_non_blocking_fd(fd))
 | 
						|
            {
 | 
						|
              /* Non-blocking */
 | 
						|
              result = 0;
 | 
						|
            }
 | 
						|
          else
 | 
						|
            {
 | 
						|
              /* Read timeout on a socket with SO_RCVTIMEO != 0. */
 | 
						|
              JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
 | 
						|
              JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
 | 
						|
              return -1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
      else if (errno == EBADF) /* Bad fd */
 | 
						|
        {
 | 
						|
          JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
 | 
						|
          JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION, 
 | 
						|
                              strerror(errno));
 | 
						|
          return -1;
 | 
						|
        }
 | 
						|
      else if (EINTR == errno) /* read interrupted */
 | 
						|
        {
 | 
						|
          JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
 | 
						|
          JCL_ThrowException(env, INTERRUPTED_IO_EXCEPTION, strerror (errno));
 | 
						|
          return -1;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
 | 
						|
      	  JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
 | 
						|
      	  return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
  else 
 | 
						|
    buf.count = result;
 | 
						|
      
 | 
						|
  JCL_release_buffer(env, &buf, bbuf, 0);
 | 
						|
  
 | 
						|
  return result;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) bbuf;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
 | 
						|
  return -1;
 | 
						|
#endif /* HAVE_READ */
 | 
						|
}
 | 
						|
 | 
						|
JNIEXPORT jint JNICALL 
 | 
						|
Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2 (JNIEnv *env, 
 | 
						|
                                                            jobject o __attribute__ ((__unused__)), 
 | 
						|
                                                            jint fd, 
 | 
						|
                                                            jobject bbuf)
 | 
						|
{
 | 
						|
#ifdef HAVE_WRITE
 | 
						|
  jint len;
 | 
						|
  ssize_t result;
 | 
						|
  struct JCL_buffer buf;
 | 
						|
  int tmp_errno;
 | 
						|
 | 
						|
/*   NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
 | 
						|
  
 | 
						|
  if (JCL_init_buffer(env, &buf, bbuf) < 0)
 | 
						|
    {
 | 
						|
      /* TODO: Rethrown exception */
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  len = buf.limit - buf.position;
 | 
						|
 | 
						|
  if (len == 0)
 | 
						|
    {
 | 
						|
      JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  
 | 
						|
  do
 | 
						|
    {
 | 
						|
      result = cpnio_write (fd, &(buf.ptr[buf.position + buf.offset]), len);
 | 
						|
      tmp_errno = errno;
 | 
						|
    }
 | 
						|
  while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
 | 
						|
  errno = tmp_errno;
 | 
						|
 | 
						|
  buf.count = result;
 | 
						|
 | 
						|
  if (result == -1)
 | 
						|
    {
 | 
						|
      if (errno == EAGAIN) /* Non-blocking */
 | 
						|
        {
 | 
						|
          result = 0;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
 | 
						|
          JCL_ThrowException(env, IO_EXCEPTION, strerror(errno));
 | 
						|
          return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
  JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
 | 
						|
  
 | 
						|
  return result;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) bbuf;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
 | 
						|
  return -1;
 | 
						|
#endif /* HAVE_WRITE */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Implementation of a scattering read.  Will use the appropriate
 | 
						|
 * vector based read call (currently readv on Linux).
 | 
						|
 * 
 | 
						|
 * This has a limit to the number of buffers that will be read.  It
 | 
						|
 * will not make muliple readv calls.  This is to ensure that operations 
 | 
						|
 * are atomic.  Currently it is limited to 16 buffers.  This is for 
 | 
						|
 * compatibiliy with Sun.
 | 
						|
 */
 | 
						|
JNIEXPORT jlong JNICALL 
 | 
						|
Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env, 
 | 
						|
	jobject o __attribute__ ((__unused__)), 
 | 
						|
	jint fd, 
 | 
						|
	jobjectArray bbufs, 
 | 
						|
	jint offset, 
 | 
						|
	jint length)
 | 
						|
{
 | 
						|
  jint i;
 | 
						|
/*   jboolean is_error = JNI_FALSE; */
 | 
						|
/*   char *error_msg; */
 | 
						|
  struct iovec buffers[JCL_IOV_MAX];
 | 
						|
  struct JCL_buffer bi_list[JCL_IOV_MAX];
 | 
						|
  ssize_t result;
 | 
						|
  jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
 | 
						|
  jlong bytes_read = 0;
 | 
						|
  int tmp_errno;
 | 
						|
 | 
						|
/*   NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
 | 
						|
/*          fd, bbufs, offset, length); */
 | 
						|
  
 | 
						|
  /* Build the vector of buffers to read into */
 | 
						|
  for (i = 0; i < vec_len; i++)
 | 
						|
    {
 | 
						|
      struct JCL_buffer* buf;
 | 
						|
      jobject bbuf;
 | 
						|
      
 | 
						|
      buf = &bi_list[i];
 | 
						|
      bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
 | 
						|
      
 | 
						|
      JCL_init_buffer(env, buf, bbuf);
 | 
						|
 | 
						|
/*       JCL_print_buffer (env, buf); */
 | 
						|
      
 | 
						|
      buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
 | 
						|
      buffers[i].iov_len = buf->limit - buf->position;
 | 
						|
      (*env)->DeleteLocalRef(env, bbuf);
 | 
						|
    }
 | 
						|
    
 | 
						|
  /* Work the scattering magic */
 | 
						|
  do
 | 
						|
    {
 | 
						|
      result = cpnio_readv (fd, buffers, vec_len);
 | 
						|
      tmp_errno = errno;
 | 
						|
    }
 | 
						|
  while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
 | 
						|
  errno = tmp_errno;
 | 
						|
  bytes_read = (jlong) result;
 | 
						|
  
 | 
						|
  /* Handle the response */
 | 
						|
  if (result < 0)
 | 
						|
    {
 | 
						|
      if (errno == EAGAIN)
 | 
						|
        {
 | 
						|
          if (is_non_blocking_fd(fd))
 | 
						|
            {
 | 
						|
              /* Non-blocking */
 | 
						|
              result = 0;
 | 
						|
            }
 | 
						|
          else
 | 
						|
            {
 | 
						|
              /* Read timeout on a socket with SO_RCVTIMEO != 0. */
 | 
						|
              JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
 | 
						|
              JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
 | 
						|
              return -1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
      else if (errno == EBADF) /* Bad fd */
 | 
						|
        {
 | 
						|
          JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
 | 
						|
          JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION, 
 | 
						|
                              strerror(errno));
 | 
						|
          return -1;
 | 
						|
        } 
 | 
						|
      else
 | 
						|
        {
 | 
						|
          JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
 | 
						|
          JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
 | 
						|
          return -1;
 | 
						|
        }
 | 
						|
      bytes_read = 0;
 | 
						|
    }
 | 
						|
  else if (result == 0) /* EOF */
 | 
						|
    {
 | 
						|
      result = -1;
 | 
						|
    }
 | 
						|
    
 | 
						|
  JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
 | 
						|
                  
 | 
						|
  return (jlong) result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Implementation of a gathering write.  Will use the appropriate
 | 
						|
 * vector based read call (currently readv on Linux).
 | 
						|
 * 
 | 
						|
 * This has a limit to the number of buffers that will be read.  It
 | 
						|
 * will not make muliple readv calls.  This is to ensure that operations 
 | 
						|
 * are atomic.  Currently it is limited to 16 buffers.  This is for 
 | 
						|
 * compatibiliy with Sun.
 | 
						|
 */
 | 
						|
JNIEXPORT jlong JNICALL 
 | 
						|
Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env, 
 | 
						|
	jobject o __attribute__ ((__unused__)), 
 | 
						|
	jint fd, 
 | 
						|
	jobjectArray bbufs, 
 | 
						|
	jint offset, 
 | 
						|
	jint length)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
/*   jboolean is_error = JNI_FALSE; */
 | 
						|
/*   char *error_msg; */
 | 
						|
  struct iovec buffers[JCL_IOV_MAX];
 | 
						|
  struct JCL_buffer bi_list[JCL_IOV_MAX];
 | 
						|
  ssize_t result;
 | 
						|
  jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
 | 
						|
  jlong bytes_written;
 | 
						|
  int tmp_errno;
 | 
						|
  
 | 
						|
/*   NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
 | 
						|
/*          fd, bbufs, offset, length); */
 | 
						|
  
 | 
						|
  /* Build the vector of buffers to read into */
 | 
						|
  for (i = 0; i < vec_len; i++)
 | 
						|
    {
 | 
						|
      struct JCL_buffer* buf;
 | 
						|
      jobject bbuf;
 | 
						|
      
 | 
						|
      buf = &bi_list[i];
 | 
						|
      bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
 | 
						|
      
 | 
						|
      JCL_init_buffer(env, buf, bbuf); 
 | 
						|
      
 | 
						|
/*       JCL_print_buffer(env, buf); */
 | 
						|
 | 
						|
      buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
 | 
						|
      buffers[i].iov_len = buf->limit - buf->position;
 | 
						|
      (*env)->DeleteLocalRef(env, bbuf);
 | 
						|
    }
 | 
						|
    
 | 
						|
  /* Work the gathering magic */
 | 
						|
  do
 | 
						|
    {
 | 
						|
      result = cpnio_writev (fd, buffers, vec_len);
 | 
						|
      tmp_errno = errno;
 | 
						|
    }
 | 
						|
  while (result == -1 && tmp_errno == EINTR && ! JCL_thread_interrupted(env));
 | 
						|
  errno = tmp_errno;
 | 
						|
 | 
						|
  bytes_written = (jlong) result;
 | 
						|
 | 
						|
  if (result < 0)
 | 
						|
    {
 | 
						|
      bytes_written = 0;
 | 
						|
      if (errno == EAGAIN) /* Non blocking */
 | 
						|
        result = 0;
 | 
						|
      else if (errno == EBADF) /* Bad fd */
 | 
						|
        {
 | 
						|
          JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, 
 | 
						|
                              bytes_written);
 | 
						|
          JCL_ThrowException (env, NON_WRITABLE_CHANNEL_EXCEPTION, 
 | 
						|
                              strerror(errno));
 | 
						|
          return -1;
 | 
						|
        } 
 | 
						|
      else
 | 
						|
        {
 | 
						|
          JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
 | 
						|
                              bytes_written);
 | 
						|
          JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
 | 
						|
          return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
  else if (result == 0) /* EOF??  Does this happen on a write */
 | 
						|
    result = -1;
 | 
						|
    
 | 
						|
  JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_written);    
 | 
						|
  return (jlong) result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    receive
 | 
						|
 * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_receive (JNIEnv *env,
 | 
						|
                                     jclass c __attribute__((unused)),
 | 
						|
                                     jint fd, jobject dst, jobject addrPort)
 | 
						|
{
 | 
						|
#ifdef HAVE_RECVFROM
 | 
						|
  char *addrPortPtr = (*env)->GetDirectBufferAddress (env, addrPort);
 | 
						|
  struct JCL_buffer buf;
 | 
						|
#ifdef HAVE_INET6
 | 
						|
  struct sockaddr_in6 sock_storage;
 | 
						|
  struct sockaddr_in6 *sock6;
 | 
						|
  socklen_t slen = sizeof (struct sockaddr_in6);
 | 
						|
#else
 | 
						|
  struct sockaddr_in sock_storage;
 | 
						|
  socklen_t slen = sizeof (struct sockaddr_in);
 | 
						|
#endif /* HAVE_INET6 */
 | 
						|
  struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
 | 
						|
  struct sockaddr_in *sock4;
 | 
						|
  int ret;
 | 
						|
  jint result = -1;
 | 
						|
 | 
						|
  if (JCL_init_buffer (env, &buf, dst) == -1)
 | 
						|
    JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
 | 
						|
 | 
						|
#ifndef HAVE_MSG_WAITALL
 | 
						|
#define MSG_WAITALL       0
 | 
						|
#endif
 | 
						|
 | 
						|
  ret = cpnio_recvfrom (fd, &(buf.ptr[buf.position + buf.offset]),
 | 
						|
                        buf.limit - buf.position, MSG_WAITALL,
 | 
						|
                        sockaddr, &slen);
 | 
						|
 | 
						|
  if (-1 == ret)
 | 
						|
    {
 | 
						|
      JCL_release_buffer (env, &buf, dst, JNI_ABORT);
 | 
						|
      if (EINTR == errno)
 | 
						|
        JCL_ThrowException (env, "java/io/InterruptedIOException", strerror (errno));
 | 
						|
      else if (EAGAIN == errno)
 | 
						|
        {
 | 
						|
          /* If the socket is in blocking mode, our timeout expired. */
 | 
						|
          int val = fcntl (fd, F_GETFL, 0);
 | 
						|
          if (val == -1)
 | 
						|
            JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
          else if ((val & O_NONBLOCK) == 0)
 | 
						|
            JCL_ThrowException (env, "java/net/SocketTimeoutException",
 | 
						|
                                "read timed out");
 | 
						|
        }
 | 
						|
      else
 | 
						|
        JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  if (sockaddr->sa_family == AF_INET)
 | 
						|
    {
 | 
						|
      sock4 = (struct sockaddr_in *) sockaddr;
 | 
						|
      memcpy (addrPortPtr, &(sock4->sin_addr.s_addr), 4);
 | 
						|
      ;memcpy (addrPortPtr + 4, &(sock4->sin_port), 2);
 | 
						|
      result = 4;
 | 
						|
    }
 | 
						|
#ifdef HAVE_INET6
 | 
						|
  else if (sockaddr->sa_family == AF_INET6)
 | 
						|
    {
 | 
						|
      sock6 = (struct sockaddr_in6 *) sockaddr;
 | 
						|
      memcpy (addrPortPtr, &(sock6->sin6_addr.s6_addr), 16);
 | 
						|
      memcpy (addrPortPtr + 16, &(sock6->sin6_port), 2);
 | 
						|
      result = 16;
 | 
						|
    }
 | 
						|
#endif /* HAVE_INET6 */
 | 
						|
  else if (ret == 0)
 | 
						|
    {
 | 
						|
      result = 0;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, "java/net/SocketException",
 | 
						|
                          "unsupported address type returned");
 | 
						|
    }
 | 
						|
 | 
						|
  buf.count += ret;
 | 
						|
  JCL_release_buffer (env, &buf, dst, 0);
 | 
						|
  return result;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) dst;
 | 
						|
  (void) addrPort;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "recvfrom not supported");
 | 
						|
#endif /* HAVE_RECVFROM */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    send
 | 
						|
 * Signature: (Ljava/nio/ByteBuffer;[BI)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_send (JNIEnv *env,
 | 
						|
                                  jclass c __attribute__((unused)),
 | 
						|
                                  int fd, jobject src, jbyteArray addr, jint port)
 | 
						|
{
 | 
						|
#ifdef HAVE_SENDTO
 | 
						|
  struct sockaddr_in sockaddr;
 | 
						|
  jbyte *elems;
 | 
						|
  struct JCL_buffer buf;
 | 
						|
  int ret;
 | 
						|
 | 
						|
/*   NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
 | 
						|
/*          fd, src, addr, port); */
 | 
						|
 | 
						|
  if (JCL_init_buffer (env, &buf, src) == -1)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
/*   JCL_print_buffer (env, &buf); */
 | 
						|
 | 
						|
  elems = (*env)->GetByteArrayElements (env, addr, NULL);
 | 
						|
 | 
						|
  sockaddr.sin_family = AF_INET;
 | 
						|
  sockaddr.sin_addr.s_addr = *((uint32_t *) elems);
 | 
						|
  sockaddr.sin_port = htons (port);
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
      ret = cpnio_sendto (fd, &(buf.ptr[buf.position + buf.offset]),
 | 
						|
                          buf.limit - buf.position,
 | 
						|
                          0, (const struct sockaddr *) &sockaddr,
 | 
						|
                          sizeof (struct sockaddr_in));
 | 
						|
    }
 | 
						|
  while (-1 == ret && EINTR == errno);
 | 
						|
 | 
						|
  (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
 | 
						|
 | 
						|
  if (-1 == ret)
 | 
						|
    {
 | 
						|
      if (errno != EAGAIN)
 | 
						|
        JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
      JCL_release_buffer (env, &buf, src, JNI_ABORT);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  buf.count += ret;
 | 
						|
  JCL_release_buffer (env, &buf, src, JNI_ABORT);
 | 
						|
  return ret;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) src;
 | 
						|
  (void) addr;
 | 
						|
  (void) port;
 | 
						|
#endif /* HAVE_SENDTO */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    send6
 | 
						|
 * Signature: (Ljava/nio/ByteBuffer;[BI)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_send6 (JNIEnv *env,
 | 
						|
                                   jclass c __attribute__((unused)),
 | 
						|
                                   int fd, jobject src, jbyteArray addr, jint port)
 | 
						|
{
 | 
						|
#if defined(HAVE_SENDTO) && defined(HAVE_INET6)
 | 
						|
  struct sockaddr_in6 sockaddr;
 | 
						|
  jbyte *elems;
 | 
						|
  struct JCL_buffer buf;
 | 
						|
  int ret;
 | 
						|
 | 
						|
/*   NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
 | 
						|
/*          fd, src, addr, port); */
 | 
						|
 | 
						|
  if (JCL_init_buffer (env, &buf, src) == -1)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
/*   JCL_print_buffer (env, &buf); */
 | 
						|
 | 
						|
  elems = (*env)->GetByteArrayElements (env, addr, NULL);
 | 
						|
 | 
						|
  sockaddr.sin6_family = AF_INET6;
 | 
						|
  memcpy (&sockaddr.sin6_addr.s6_addr, elems, 16);
 | 
						|
  sockaddr.sin6_port = htons (port);
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
      ret = cpnio_sendto (fd, (const void *) (buf.ptr + buf.offset),
 | 
						|
                          buf.limit - buf.position,
 | 
						|
                          0, (const struct sockaddr *) &sockaddr,
 | 
						|
                          sizeof (struct sockaddr_in6));
 | 
						|
    }
 | 
						|
  while (-1 == ret && EINTR == errno);
 | 
						|
 | 
						|
  (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
 | 
						|
 | 
						|
  if (-1 == ret)
 | 
						|
    {
 | 
						|
      if (errno != EAGAIN)
 | 
						|
        JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
      JCL_release_buffer (env, &buf, src, JNI_ABORT);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  buf.count += ret;
 | 
						|
  JCL_release_buffer (env, &buf, src, JNI_ABORT);
 | 
						|
  return ret;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) src;
 | 
						|
  (void) addr;
 | 
						|
  (void) port;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "IPv6 sendto not supported");
 | 
						|
  return -1;
 | 
						|
#endif /* HAVE_SENDTO && HAVE_INET6 */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    read
 | 
						|
 * Signature: (I)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_read__I (JNIEnv *env,
 | 
						|
                                     jclass c __attribute__((unused)),
 | 
						|
                                     jint fd)
 | 
						|
{
 | 
						|
#ifdef HAVE_READ
 | 
						|
  char in;
 | 
						|
  int ret;
 | 
						|
  int tmp_errno;
 | 
						|
 | 
						|
/*   NIODBG("fd: %d", fd); */
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
      ret = cpnio_read (fd, &in, 1);
 | 
						|
      tmp_errno = errno;
 | 
						|
    }
 | 
						|
  while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
 | 
						|
  errno = tmp_errno;
 | 
						|
 | 
						|
  if (-1 == ret)
 | 
						|
    {
 | 
						|
      if (errno == EAGAIN && !is_non_blocking_fd(fd))
 | 
						|
        {
 | 
						|
          /* Read timeout on a socket with SO_RCVTIMEO != 0. */
 | 
						|
          JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
 | 
						|
        }
 | 
						|
      else
 | 
						|
        JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (0 == ret)
 | 
						|
    return -1;
 | 
						|
 | 
						|
  return (in & 0xFF);
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
 | 
						|
#endif /* HAVE_READ */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    write
 | 
						|
 * Signature: (I)V
 | 
						|
 */
 | 
						|
JNIEXPORT void JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_write__II (JNIEnv *env,
 | 
						|
                                       jclass c __attribute__((unused)),
 | 
						|
                                       jint fd, jint data)
 | 
						|
{
 | 
						|
#ifdef HAVE_WRITE
 | 
						|
  char out = (char) data;
 | 
						|
  int ret;
 | 
						|
  int tmp_errno;
 | 
						|
 | 
						|
/*   NIODBG("fd: %d; data: %d", fd, data); */
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
      ret = cpnio_write (fd, &out, 1);
 | 
						|
      tmp_errno = errno;
 | 
						|
    }
 | 
						|
  while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
 | 
						|
  errno = tmp_errno;
 | 
						|
 | 
						|
  if (-1 == ret)
 | 
						|
    JCL_ThrowException(env, IO_EXCEPTION, strerror (errno));
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) data;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
 | 
						|
#endif /* HAVE_WRITE */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    socket
 | 
						|
 * Signature: (Z)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_socket (JNIEnv *env, jclass clazz __attribute__((unused)),
 | 
						|
                                    jboolean stream)
 | 
						|
{
 | 
						|
#ifdef HAVE_SOCKET
 | 
						|
  int ret;
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
      ret = cpnio_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
 | 
						|
    }
 | 
						|
  while (-1 == ret && EINTR == errno);
 | 
						|
 | 
						|
  if (ret == -1)
 | 
						|
    JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
 | 
						|
/*   NIODBG("created socket %d", ret); */
 | 
						|
 | 
						|
  return ret;
 | 
						|
#else
 | 
						|
  (void) stream;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "socket not supported");
 | 
						|
  return -1;
 | 
						|
#endif /* HAVE_SOCKET */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    connect
 | 
						|
 * Signature: (I[BI)Z
 | 
						|
 */
 | 
						|
JNIEXPORT jboolean JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_connect (JNIEnv *env, jclass clazz __attribute__((unused)),
 | 
						|
                                     jint fd, jbyteArray addr, jint port, jint timeout)
 | 
						|
{
 | 
						|
#ifdef HAVE_CONNECT
 | 
						|
  struct sockaddr_in sockaddr;
 | 
						|
  struct timeval timeo;
 | 
						|
  int origflags = 0, flags;
 | 
						|
  jbyte *addr_elems;
 | 
						|
  int ret;
 | 
						|
  int tmpErrno;
 | 
						|
 | 
						|
  if ((*env)->GetArrayLength (env, addr) != 4)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, SOCKET_EXCEPTION,
 | 
						|
                          "expecting 4-byte address");
 | 
						|
      return JNI_FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
  if (timeout > 0)
 | 
						|
    {
 | 
						|
      timeo.tv_sec = timeout / 1000;
 | 
						|
      timeo.tv_usec = (timeout % 1000) * 1000;
 | 
						|
      origflags = fcntl (fd, F_GETFL, 0);
 | 
						|
      if (origflags == -1)
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
      /* Set nonblocking mode, if not already set. */
 | 
						|
      if (!(origflags & O_NONBLOCK))
 | 
						|
        {
 | 
						|
          flags = origflags | O_NONBLOCK;
 | 
						|
          if (fcntl (fd, F_SETFL, flags) == -1)
 | 
						|
            {
 | 
						|
              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
              return JNI_FALSE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
 | 
						|
 | 
						|
  memset (&sockaddr, 0, sizeof (struct sockaddr_in));
 | 
						|
  sockaddr.sin_family = AF_INET;
 | 
						|
  sockaddr.sin_port = htons (port);
 | 
						|
  sockaddr.sin_addr.s_addr = *((uint32_t *) addr_elems);
 | 
						|
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
      ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
 | 
						|
                           sizeof (struct sockaddr_in));
 | 
						|
      tmpErrno = errno;
 | 
						|
    }
 | 
						|
  while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
 | 
						|
  errno = tmpErrno;
 | 
						|
 | 
						|
  (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
 | 
						|
 | 
						|
  /* If a timeout was specified, select on the file descriptor with
 | 
						|
     the timeout. */
 | 
						|
  if (timeout > 0 && ret == -1)
 | 
						|
    {
 | 
						|
      /* Reset the non-blocking flag, if needed. */
 | 
						|
      if (!(origflags & O_NONBLOCK))
 | 
						|
        {
 | 
						|
          if (fcntl (fd, F_SETFL, origflags) == -1)
 | 
						|
            {
 | 
						|
              /* oops */
 | 
						|
              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
              return JNI_FALSE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
      if (EINPROGRESS == errno)
 | 
						|
        {
 | 
						|
          fd_set wrfds;
 | 
						|
          FD_ZERO(&wrfds);
 | 
						|
          FD_SET(fd, &wrfds);
 | 
						|
          ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
 | 
						|
          if (ret == -1)
 | 
						|
            {
 | 
						|
              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
              return JNI_FALSE;
 | 
						|
            }
 | 
						|
          if (ret == 0) /* connect timed out */
 | 
						|
            {
 | 
						|
              JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
 | 
						|
                                  "connect timed out");
 | 
						|
              return JNI_FALSE;
 | 
						|
            }
 | 
						|
          return JNI_TRUE; /* Connected! */
 | 
						|
        }
 | 
						|
      else if (ECONNREFUSED == errno)
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, CONNECT_EXCEPTION,
 | 
						|
                              strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  if (ret == -1)
 | 
						|
    {
 | 
						|
      if (EINPROGRESS == errno)
 | 
						|
        return JNI_FALSE;
 | 
						|
      else if (ECONNREFUSED == errno)
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, CONNECT_EXCEPTION,
 | 
						|
                              strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  return JNI_TRUE;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) addr;
 | 
						|
  (void) port;
 | 
						|
  (void) timeout;
 | 
						|
  JCL_ThrowException (env, SOCKET_EXCEPTION, "connect not supported");
 | 
						|
  return JNI_FALSE;
 | 
						|
#endif /* HAVE_CONNECT */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    connect6
 | 
						|
 * Signature: (I[BI)Z
 | 
						|
 */
 | 
						|
JNIEXPORT jboolean JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_connect6 (JNIEnv *env, jclass clazz __attribute__((unused)),
 | 
						|
                                      jint fd, jbyteArray addr, jint port, int timeout)
 | 
						|
{
 | 
						|
#if defined(HAVE_CONNECT) && defined(HAVE_INET6)
 | 
						|
  struct sockaddr_in6 sockaddr;
 | 
						|
  struct timeval timeo;
 | 
						|
  int flags, origflags = 0;
 | 
						|
  jbyte *addr_elems;
 | 
						|
  int ret;
 | 
						|
 | 
						|
  if (timeout > 0)
 | 
						|
    {
 | 
						|
      timeo.tv_sec = timeout / 1000;
 | 
						|
      timeo.tv_usec = (timeout % 1000) * 1000;
 | 
						|
      origflags = fcntl (fd, F_GETFL, 0);
 | 
						|
      if (origflags == -1)
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
      /* Set nonblocking mode, if not already set. */
 | 
						|
      if (!(origflags & O_NONBLOCK))
 | 
						|
        {
 | 
						|
          flags = origflags | O_NONBLOCK;
 | 
						|
          if (fcntl (fd, F_SETFL, flags) == -1)
 | 
						|
            {
 | 
						|
              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
              return JNI_FALSE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
 | 
						|
 | 
						|
  memset (&sockaddr, 0, sizeof (struct sockaddr_in6));
 | 
						|
  sockaddr.sin6_family = AF_INET6;
 | 
						|
  sockaddr.sin6_port = htons (port);
 | 
						|
  memcpy (&sockaddr.sin6_addr.s6_addr, addr_elems, 16);
 | 
						|
 | 
						|
  ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
 | 
						|
                       sizeof (struct sockaddr_in6));
 | 
						|
 | 
						|
  (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
 | 
						|
 | 
						|
  /* If a timeout was specified, select on the file descriptor with
 | 
						|
     the timeout. */
 | 
						|
  if (timeout > 0 && ret == -1)
 | 
						|
    {
 | 
						|
      /* Reset the non-blocking flag, if needed. */
 | 
						|
      if (!(origflags & O_NONBLOCK))
 | 
						|
        {
 | 
						|
          if (fcntl (fd, F_SETFL, origflags) == -1)
 | 
						|
            {
 | 
						|
              /* oops */
 | 
						|
              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
              return JNI_FALSE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
      if (EINPROGRESS == errno)
 | 
						|
        {
 | 
						|
          fd_set wrfds;
 | 
						|
          FD_ZERO(&wrfds);
 | 
						|
          FD_SET(fd, &wrfds);
 | 
						|
          ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
 | 
						|
          if (ret == -1)
 | 
						|
            {
 | 
						|
              JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
              return JNI_FALSE;
 | 
						|
            }
 | 
						|
          if (ret == 0) /* connect timed out */
 | 
						|
            {
 | 
						|
              JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
 | 
						|
                                  "connect timed out");
 | 
						|
              return JNI_FALSE;
 | 
						|
            }
 | 
						|
          return JNI_TRUE; /* Connected! */
 | 
						|
        }
 | 
						|
      else if (ECONNREFUSED == errno)
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, CONNECT_EXCEPTION,
 | 
						|
                              strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  if (ret == -1)
 | 
						|
    {
 | 
						|
      if (EAGAIN == errno)
 | 
						|
        return JNI_FALSE;
 | 
						|
      else if (ECONNREFUSED == errno)
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, CONNECT_EXCEPTION,
 | 
						|
                              strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
 | 
						|
          return JNI_FALSE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  return JNI_TRUE;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) addr;
 | 
						|
  (void) port;
 | 
						|
  (void) timeout;
 | 
						|
  JCL_ThrowException (env, SOCKET_EXCEPTION, "IPv6 connect not supported");
 | 
						|
  return JNI_FALSE;
 | 
						|
#endif /* HAVE_CONNECT && HAVE_INET6 */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    getsockname
 | 
						|
 * Signature: (ILjava/nio/ByteBuffer;)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_getsockname (JNIEnv *env, jclass clazz __attribute__((unused)),
 | 
						|
                                         jint fd, jobject name)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETSOCKNAME
 | 
						|
#ifdef HAVE_INET6
 | 
						|
  struct sockaddr_in6 *addr6;
 | 
						|
  struct sockaddr_in6 sock_storage;
 | 
						|
  socklen_t socklen = sizeof (struct sockaddr_in6);
 | 
						|
#else
 | 
						|
  struct sockaddr_in sock_storage;
 | 
						|
  socklen_t socklen = sizeof (struct sockaddr_in);
 | 
						|
#endif /* HAVE_INET6 */
 | 
						|
 | 
						|
  struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
 | 
						|
  struct sockaddr_in *addr4;
 | 
						|
  int ret;
 | 
						|
  char *nameptr = (*env)->GetDirectBufferAddress (env, name);
 | 
						|
 | 
						|
  ret = getsockname (fd, sockaddr, &socklen);
 | 
						|
  if (ret == -1)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  if (sockaddr->sa_family == AF_INET)
 | 
						|
    {
 | 
						|
      addr4 = (struct sockaddr_in *) sockaddr;
 | 
						|
      memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
 | 
						|
      memcpy (nameptr + 4, &(addr4->sin_port), 2);
 | 
						|
      return 4;
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef HAVE_INET6
 | 
						|
  /* IPv6 */
 | 
						|
  if (sockaddr->sa_family == AF_INET6)
 | 
						|
    {
 | 
						|
      addr6 = (struct sockaddr_in6 *) sockaddr;
 | 
						|
      memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
 | 
						|
      memcpy (nameptr + 16, &(addr6->sin6_port), 2);
 | 
						|
      return 16;
 | 
						|
    }
 | 
						|
#endif /* HAVE_INET6 */
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "unsupported address format");
 | 
						|
  return -1;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) name;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "getsockname not supported");
 | 
						|
  return -1;
 | 
						|
#endif /* HAVE_GETSOCKNAME */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    getpeername
 | 
						|
 * Signature: (ILjava/nio/ByteBuffer;)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_getpeername (JNIEnv *env, jclass clazz __attribute__((unused)),
 | 
						|
                                         jint fd, jobject name)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETPEERNAME
 | 
						|
#ifdef HAVE_INET6
 | 
						|
  struct sockaddr_in6 *addr6;
 | 
						|
  struct sockaddr_in6 sock_storage;
 | 
						|
  socklen_t socklen = sizeof (struct sockaddr_in6);
 | 
						|
#else
 | 
						|
  struct sockaddr_in sock_storage;
 | 
						|
  socklen_t socklen = sizeof (struct sockaddr_in);
 | 
						|
#endif /* HAVE_INET6 */
 | 
						|
 | 
						|
  struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
 | 
						|
  struct sockaddr_in *addr4;
 | 
						|
  int ret;
 | 
						|
  char *nameptr = (*env)->GetDirectBufferAddress (env, name);
 | 
						|
  
 | 
						|
  ret = getpeername (fd, sockaddr, &socklen);
 | 
						|
  if (ret == -1)
 | 
						|
    {
 | 
						|
      if (ENOTCONN != errno)
 | 
						|
        JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  if (sockaddr->sa_family == AF_INET)
 | 
						|
    {
 | 
						|
      addr4 = (struct sockaddr_in *) sockaddr;
 | 
						|
      memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
 | 
						|
      memcpy (nameptr + 4, &(addr4->sin_port), 2);
 | 
						|
      return 4;
 | 
						|
    }
 | 
						|
#ifdef HAVE_INET6
 | 
						|
  else if (sockaddr->sa_family == AF_INET6)
 | 
						|
    {
 | 
						|
      addr6 = (struct sockaddr_in6 *) sockaddr;
 | 
						|
      memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
 | 
						|
      memcpy (nameptr + 16, &(addr6->sin6_port), 2);
 | 
						|
      return 16;
 | 
						|
    }
 | 
						|
#endif /* HAVE_INET6 */
 | 
						|
 | 
						|
  JCL_ThrowException (env, "java/net/SocketException",
 | 
						|
                      "unsupported address type");
 | 
						|
  return -1;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) name;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "getpeername not supported");
 | 
						|
  return -1;
 | 
						|
#endif /* HAVE_GETPEERNAME */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    accept
 | 
						|
 * Signature: (I)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_accept (JNIEnv *env,
 | 
						|
                                    jclass c __attribute__((unused)),
 | 
						|
                                    jint fd)
 | 
						|
{
 | 
						|
#ifdef HAVE_ACCEPT
 | 
						|
  int ret;
 | 
						|
  int tmp_errno = 0;
 | 
						|
 | 
						|
#ifdef HAVE_INET6
 | 
						|
  struct sockaddr_in6 addr;
 | 
						|
  socklen_t alen = sizeof (struct sockaddr_in6);
 | 
						|
#else
 | 
						|
  struct sockaddr_in addr;
 | 
						|
  socklen_t alen = sizeof (struct sockaddr_in);
 | 
						|
#endif /* HAVE_INET6 */
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
      ret = cpnio_accept (fd, (struct sockaddr *) &addr, &alen);
 | 
						|
      tmp_errno = errno;
 | 
						|
      
 | 
						|
      if (ret == -1)
 | 
						|
        switch (tmp_errno)
 | 
						|
        {
 | 
						|
          case EINTR:
 | 
						|
            /* Check if interrupted by Thread.interrupt(). If not then some
 | 
						|
             * other unrelated signal interrupted the system function and
 | 
						|
             * we should start over again.
 | 
						|
             */
 | 
						|
            if (JCL_thread_interrupted(env))
 | 
						|
              {
 | 
						|
                JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
 | 
						|
                return -1;
 | 
						|
              }
 | 
						|
            break;
 | 
						|
#if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN
 | 
						|
          case EWOULDBLOCK:
 | 
						|
#endif
 | 
						|
          case EAGAIN:
 | 
						|
            if (!is_non_blocking_fd(fd))
 | 
						|
              {
 | 
						|
                JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "Accept timed out");
 | 
						|
              }
 | 
						|
            /* Socket in non-blocking mode and no pending connection. */
 | 
						|
            return -1;
 | 
						|
          default:
 | 
						|
            JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  while (1);
 | 
						|
 | 
						|
  cpio_closeOnExec(ret);
 | 
						|
 | 
						|
  return ret;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "accept not supported");
 | 
						|
  return -1;
 | 
						|
#endif /* HAVE_ACCEPT */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    disconnect
 | 
						|
 * Signature: (I)V
 | 
						|
 */
 | 
						|
JNIEXPORT void JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_disconnect (JNIEnv *env,
 | 
						|
                                        jclass c __attribute__((unused)),
 | 
						|
                                        jint fd)
 | 
						|
{
 | 
						|
  struct sockaddr sockaddr;
 | 
						|
 | 
						|
  sockaddr.sa_family = AF_UNSPEC;
 | 
						|
  if (connect (fd, &sockaddr, sizeof (struct sockaddr)) == -1)
 | 
						|
    {
 | 
						|
      /* The expected error for a successful disconnect is EAFNOSUPPORT. */
 | 
						|
      if (errno != EAFNOSUPPORT)
 | 
						|
        JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    close
 | 
						|
 * Signature: (I)V
 | 
						|
 */
 | 
						|
JNIEXPORT void JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_close (JNIEnv *env,
 | 
						|
                                   jclass c __attribute__((unused)),
 | 
						|
                                   jint fd)
 | 
						|
{
 | 
						|
  if (close (fd) == -1)
 | 
						|
    JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    available
 | 
						|
 * Signature: (I)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_available (JNIEnv *env,
 | 
						|
                                       jclass c __attribute__((unused)),
 | 
						|
                                       jint fd)
 | 
						|
{
 | 
						|
#if defined (FIONREAD)
 | 
						|
 | 
						|
  jint avail = 0;
 | 
						|
 | 
						|
#if defined(ENOTTY) && defined(HAVE_FSTAT)
 | 
						|
  struct stat statBuffer;
 | 
						|
  off_t n;
 | 
						|
#endif
 | 
						|
 | 
						|
/*   NIODBG("fd: %d", fd); */
 | 
						|
  if (ioctl (fd, FIONREAD, &avail) == -1)
 | 
						|
    {
 | 
						|
#if defined(ENOTTY) && defined(HAVE_FSTAT)
 | 
						|
      if (errno == ENOTTY)
 | 
						|
        {
 | 
						|
          if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
 | 
						|
            {
 | 
						|
              n = lseek (fd, 0, SEEK_CUR);
 | 
						|
              if (n != -1)
 | 
						|
                {
 | 
						|
                  avail = statBuffer.st_size - n;
 | 
						|
                  return avail;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
#endif
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
    }
 | 
						|
/*   NIODBG("avail: %d", avail); */
 | 
						|
 | 
						|
  return avail;
 | 
						|
 | 
						|
#elif defined(HAVE_FSTAT)
 | 
						|
 | 
						|
  jint avail = 0;
 | 
						|
 | 
						|
  struct stat statBuffer;
 | 
						|
  off_t n;
 | 
						|
 | 
						|
  if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
 | 
						|
    {
 | 
						|
      n = lseek (fd, 0, SEEK_CUR);
 | 
						|
      if (n != -1) 
 | 
						|
        { 
 | 
						|
	  avail = statBuffer.st_size - n;
 | 
						|
	  return avail;
 | 
						|
        } 
 | 
						|
    }
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
 | 
						|
#elif defined(HAVE_SELECT)
 | 
						|
 | 
						|
  jint avail = 0;
 | 
						|
  fd_set filedescriptset;
 | 
						|
  struct timeval tv;
 | 
						|
 | 
						|
  FD_ZERO (&filedescriptset);
 | 
						|
  FD_SET (fd,&filedescriptset);
 | 
						|
  memset (&tv, 0, sizeof(tv));
 | 
						|
 | 
						|
  switch (select (fd+1, &filedescriptset, NULL, NULL, &tv))
 | 
						|
    {
 | 
						|
      case -1:
 | 
						|
        break;
 | 
						|
      case  0:
 | 
						|
        avail = 0;
 | 
						|
	return avail;
 | 
						|
      default:
 | 
						|
        avail = 1;
 | 
						|
	return avail;
 | 
						|
    }
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "No native method for available");
 | 
						|
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
enum FileChannel_mode {
 | 
						|
  CPNIO_READ   = 1,
 | 
						|
  CPNIO_WRITE  = 2,
 | 
						|
  CPNIO_APPEND = 4,
 | 
						|
  CPNIO_EXCL   = 8,
 | 
						|
  CPNIO_SYNC   = 16,
 | 
						|
  CPNIO_DSYNC  = 32
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    open
 | 
						|
 * Signature: (Ljava/lang/String;I)I
 | 
						|
 */
 | 
						|
JNIEXPORT jint JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_open (JNIEnv *env,
 | 
						|
                                  jclass c __attribute__((unused)),
 | 
						|
                                  jstring path, jint mode)
 | 
						|
{
 | 
						|
  int nmode = 0;
 | 
						|
  int ret;
 | 
						|
  const char *npath;
 | 
						|
 | 
						|
  if ((mode & CPNIO_READ) && (mode & CPNIO_WRITE))
 | 
						|
    nmode = O_RDWR;
 | 
						|
  else if (mode & CPNIO_WRITE)
 | 
						|
    nmode = O_WRONLY;
 | 
						|
  else
 | 
						|
    nmode = O_RDONLY;
 | 
						|
 | 
						|
  nmode = (nmode
 | 
						|
           | ((nmode == O_RDWR || nmode == O_WRONLY) ? O_CREAT : 0)
 | 
						|
           | ((mode & CPNIO_APPEND) ? O_APPEND :
 | 
						|
              ((nmode == O_WRONLY) ? O_TRUNC : 0))
 | 
						|
           | ((mode & CPNIO_EXCL) ? O_EXCL : 0)
 | 
						|
           | ((mode & CPNIO_SYNC) ? O_SYNC : 0));
 | 
						|
 | 
						|
  npath = JCL_jstring_to_cstring (env, path);
 | 
						|
 | 
						|
/*   NIODBG("path: %s; mode: %x", npath, nmode); */
 | 
						|
 | 
						|
  ret = open (npath, nmode, 0666);
 | 
						|
 | 
						|
/*   NIODBG("ret: %d\n", ret); */
 | 
						|
 | 
						|
  JCL_free_cstring (env, path, npath);
 | 
						|
 | 
						|
  if (-1 == ret)
 | 
						|
    JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    position
 | 
						|
 * Signature: (I)J
 | 
						|
 */
 | 
						|
JNIEXPORT jlong JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_position (JNIEnv *env,
 | 
						|
                                      jclass c __attribute__((unused)),
 | 
						|
                                      jint fd)
 | 
						|
{
 | 
						|
#ifdef HAVE_LSEEK
 | 
						|
  off_t ret;
 | 
						|
 | 
						|
  ret = lseek (fd, 0, SEEK_CUR);
 | 
						|
 | 
						|
  if (-1 == ret)
 | 
						|
    JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
 | 
						|
  return (jlong) ret;
 | 
						|
#else
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "position not supported");
 | 
						|
  return -1;
 | 
						|
#endif /* HAVE_LSEEK */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    seek
 | 
						|
 * Signature: (IJ)V
 | 
						|
 */
 | 
						|
JNIEXPORT void JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_seek (JNIEnv *env,
 | 
						|
                                  jclass c __attribute__((unused)),
 | 
						|
                                  jint fd, jlong pos)
 | 
						|
{
 | 
						|
#ifdef HAVE_LSEEK
 | 
						|
  if (lseek (fd, (off_t) pos, SEEK_SET) == -1)
 | 
						|
    JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
#else
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "seek not supported");
 | 
						|
#endif /* HAVE_LSEEK */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    truncate
 | 
						|
 * Signature: (IJ)V
 | 
						|
 */
 | 
						|
JNIEXPORT void JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_truncate (JNIEnv *env,
 | 
						|
                                      jclass c __attribute__((unused)),
 | 
						|
                                      jint fd, jlong len)
 | 
						|
{
 | 
						|
#if defined(HAVE_FTRUNCATE) && defined(HAVE_LSEEK)
 | 
						|
  off_t pos = lseek (fd, 0, SEEK_CUR);
 | 
						|
  if (pos == -1)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  if (ftruncate (fd, (off_t) len) == -1)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  if (pos > len)
 | 
						|
    {
 | 
						|
      if (lseek (fd, len, SEEK_SET) == -1)
 | 
						|
        JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
    }
 | 
						|
#else
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "truncate not supported");
 | 
						|
#endif /* HAVE_FTRUNCATE && HAVE_LSEEK */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    lock
 | 
						|
 * Signature: (IJJZZ)Z
 | 
						|
 */
 | 
						|
JNIEXPORT jboolean JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_lock (JNIEnv *env,
 | 
						|
                                  jclass c __attribute__((unused)),
 | 
						|
                                  jint fd, jlong pos, jlong len,
 | 
						|
                                  jboolean shared, jboolean wait)
 | 
						|
{
 | 
						|
#if HAVE_FCNTL
 | 
						|
  struct flock fl;
 | 
						|
 | 
						|
  fl.l_start  = (off_t) pos;
 | 
						|
  /* Long.MAX_VALUE means lock everything possible starting at pos. */
 | 
						|
  if (len == 9223372036854775807LL)
 | 
						|
    fl.l_len = 0;
 | 
						|
  else
 | 
						|
    fl.l_len = (off_t) len;
 | 
						|
  fl.l_pid    = getpid ();
 | 
						|
  fl.l_type   = (shared ? F_RDLCK : F_WRLCK);
 | 
						|
  fl.l_whence = SEEK_SET;
 | 
						|
 | 
						|
  if (cpnio_fcntl (fd, (wait ? F_SETLKW : F_SETLK), (long) &fl) == -1)
 | 
						|
    {
 | 
						|
      if (errno != EAGAIN)
 | 
						|
        JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
      return JNI_FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
  return JNI_TRUE;
 | 
						|
#else
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "lock not supported");
 | 
						|
  return JNI_FALSE;
 | 
						|
#endif /* HAVE_FCNTL */
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    unlock
 | 
						|
 * Signature: (IJJ)V
 | 
						|
 */
 | 
						|
JNIEXPORT void JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_unlock (JNIEnv *env,
 | 
						|
                                    jclass c __attribute__((unused)),
 | 
						|
                                    jint fd, jlong pos, jlong len)
 | 
						|
{
 | 
						|
#if HAVE_FCNTL
 | 
						|
  struct flock fl;
 | 
						|
 | 
						|
  fl.l_start  = (off_t) pos;
 | 
						|
  fl.l_len    = (off_t) len;
 | 
						|
  fl.l_pid    = getpid ();
 | 
						|
  fl.l_type   = F_UNLCK;
 | 
						|
  fl.l_whence = SEEK_SET;
 | 
						|
 | 
						|
  if (cpnio_fcntl (fd, F_SETLK, (long) &fl) == -1)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
    }
 | 
						|
#else
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "unlock not supported");
 | 
						|
#endif /* HAVE_FCNTL */
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    size
 | 
						|
 * Signature: (I)J
 | 
						|
 */
 | 
						|
JNIEXPORT jlong JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_size (JNIEnv *env,
 | 
						|
                                  jclass c __attribute__((unused)),
 | 
						|
                                  jint fd)
 | 
						|
{
 | 
						|
#ifdef HAVE_FSTAT
 | 
						|
  struct stat st;
 | 
						|
 | 
						|
  if (fstat (fd, &st) == -1)
 | 
						|
    JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
 | 
						|
  return (jlong) st.st_size;
 | 
						|
#else
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "size not supported");
 | 
						|
  return 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    map
 | 
						|
 * Signature: (ICJI)Lgnu/classpath/Pointer;
 | 
						|
 */
 | 
						|
JNIEXPORT jobject JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_map (JNIEnv *env,
 | 
						|
                                 jclass clazz __attribute__((unused)),
 | 
						|
                                 jint fd, jchar mode, jlong position, jint size)
 | 
						|
{
 | 
						|
#ifdef HAVE_MMAP
 | 
						|
  jclass MappedByteBufferImpl_class;
 | 
						|
  jmethodID MappedByteBufferImpl_init = NULL;
 | 
						|
  jobject Pointer_instance;
 | 
						|
  volatile jobject buffer;
 | 
						|
  long pagesize;
 | 
						|
  int prot, flags;
 | 
						|
  void *p;
 | 
						|
  void *address;
 | 
						|
 | 
						|
/*   NIODBG("fd: %d; mode: %x; position: %lld; size: %d", */
 | 
						|
/*          fd, mode, position, size); */
 | 
						|
 | 
						|
  /* FIXME: should we just assume we're on an OS modern enough to
 | 
						|
     have 'sysconf'? And not check for 'getpagesize'? */
 | 
						|
#if defined(HAVE_GETPAGESIZE)
 | 
						|
  pagesize = getpagesize ();
 | 
						|
#elif defined(HAVE_SYSCONF)
 | 
						|
  pagesize = sysconf (_SC_PAGESIZE);
 | 
						|
#else
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION,
 | 
						|
		      "can't determine memory page size");
 | 
						|
  return NULL;
 | 
						|
#endif /* HAVE_GETPAGESIZE/HAVE_SYSCONF */
 | 
						|
 | 
						|
  if ((*env)->ExceptionOccurred (env))
 | 
						|
    {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  prot = PROT_READ;
 | 
						|
  if (mode == '+' || mode == 'c')
 | 
						|
    {
 | 
						|
      /* When writing we need to make sure the file is big enough,
 | 
						|
         otherwise the result of mmap is undefined. */
 | 
						|
      struct stat st;
 | 
						|
      if (fstat (fd, &st) == -1)
 | 
						|
        {
 | 
						|
          JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
          return NULL;
 | 
						|
        }
 | 
						|
      if (position + size > st.st_size)
 | 
						|
        {
 | 
						|
          if (ftruncate(fd, position + size) == -1)
 | 
						|
            {
 | 
						|
              JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
              return NULL;
 | 
						|
            }
 | 
						|
        }
 | 
						|
      prot |= PROT_WRITE;
 | 
						|
    }
 | 
						|
 | 
						|
  flags = (mode == 'c' ? MAP_PRIVATE : MAP_SHARED);
 | 
						|
  p = mmap (NULL, (size_t) ALIGN_UP (size, pagesize), prot, flags,
 | 
						|
	    fd, ALIGN_DOWN (position, pagesize));
 | 
						|
  if (p == MAP_FAILED)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Unalign the mapped value back up, since we aligned offset
 | 
						|
     down to a multiple of the page size. */
 | 
						|
  address = (void *) ((char *) p + (position % pagesize));
 | 
						|
 | 
						|
  Pointer_instance = JCL_NewRawDataObject(env, address);
 | 
						|
 | 
						|
  MappedByteBufferImpl_class = (*env)->FindClass (env,
 | 
						|
						  "java/nio/MappedByteBufferImpl");
 | 
						|
  if (MappedByteBufferImpl_class != NULL)
 | 
						|
    {
 | 
						|
      MappedByteBufferImpl_init =
 | 
						|
	(*env)->GetMethodID (env, MappedByteBufferImpl_class,
 | 
						|
			     "<init>", "(Lgnu/classpath/Pointer;IZ)V");
 | 
						|
    }
 | 
						|
 | 
						|
  if ((*env)->ExceptionOccurred (env))
 | 
						|
    {
 | 
						|
      munmap (p, ALIGN_UP (size, pagesize));
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  if (MappedByteBufferImpl_init == NULL)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, "java/lang/InternalError",
 | 
						|
                          "could not get MappedByteBufferImpl constructor");
 | 
						|
      munmap (p, ALIGN_UP (size, pagesize));
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  buffer = (*env)->NewObject (env, MappedByteBufferImpl_class,
 | 
						|
                              MappedByteBufferImpl_init, Pointer_instance,
 | 
						|
                              (jint) size, mode == 'r');
 | 
						|
  return buffer;
 | 
						|
#else
 | 
						|
  (void) fd;
 | 
						|
  (void) mode;
 | 
						|
  (void) position;
 | 
						|
  (void) size;
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION,
 | 
						|
		      "memory-mapped files not implemented");
 | 
						|
  return 0;
 | 
						|
#endif /* HAVE_MMAP */
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Class:     gnu_java_nio_VMChannel
 | 
						|
 * Method:    flush
 | 
						|
 * Signature: (IZ)Z
 | 
						|
 */
 | 
						|
JNIEXPORT jboolean JNICALL
 | 
						|
Java_gnu_java_nio_VMChannel_flush (JNIEnv *env,
 | 
						|
                                   jclass c __attribute__((unused)),
 | 
						|
                                   jint fd, jboolean metadata __attribute__((unused)))
 | 
						|
{
 | 
						|
#ifdef HAVE_FSYNC
 | 
						|
  /* XXX blocking? */
 | 
						|
  if (fsync (fd) == -1)
 | 
						|
    {
 | 
						|
      JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
 | 
						|
      return JNI_FALSE;
 | 
						|
    }
 | 
						|
  return JNI_TRUE;
 | 
						|
#else
 | 
						|
  JCL_ThrowException (env, IO_EXCEPTION, "flush not implemented");
 | 
						|
  return JNI_TRUE;
 | 
						|
#endif /* HAVE_FSYNC */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef __cplusplus
 | 
						|
}
 | 
						|
#endif
 |