diff options
author | Casey Marshall <csm@gnu.org> | 2006-09-17 07:31:39 +0000 |
---|---|---|
committer | Casey Marshall <csm@gnu.org> | 2006-09-17 07:31:39 +0000 |
commit | 133e014be0604b45f8ccede687acf1ea979d4955 (patch) | |
tree | 03bfec201e509081586497b0e4db7944e633cab7 /native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c | |
parent | a344c95abdd44f1c697d0520bf97ac3c8403a3b6 (diff) | |
download | classpath-133e014be0604b45f8ccede687acf1ea979d4955.tar.gz |
2006-09-16 Casey Marshall <csm@gnu.org>
* NEWS: updated.
* configure.ac (AC_CHECK_HEADERS): check for `sys/event.h'.
(AC_CHECK_FUNCS): add checks for readv, writev, getifaddrs,
kqueue, and kevent.
(HAVE_INET6): define if IPv6 is supported.
* gnu/java/net/PlainDatagramSocketImpl.java (channel): new field.
(native_fd): removed.
(impl): new field.
(<init>): throw IOException; initialize fields.
(finalize): removed.
(getNativeFD): removed.
(bind): use `PlainSocketImpl.bind.'
(create): use `PlainSocketImpl.initSocket.'
(disconnect): use `PlainSocketImpl.disconnect.'
(getLocalPort): new method.
(send): use `VMChannel.send.'
(receive): use `VMChannel.receive.'
(setOption): use `PlainSocketImpl.setOption.'
(getOption): use `PlainSocketImpl.getOption.'
(close): use `VMChannel.State.close.'
(join): use `PlainSocketImpl.join.'
(leave): use `PlainSocketImpl.leave.'
(joinGroup, leaveGroup): implemented.
* gnu/java/net/PlainSocketImpl.java: make non-final.
(native_fd): removed.
(impl): new field.
(channel): new field.
(<init>): initialize `impl.'
(finalize, getNativeFD): removed.
(setOption): use `PlainSocketImpl.setOption.'
(getOption): use `PlainSocketImpl.getOption.'
(shutdownInput): use `PlainSocketImpl.shutdownInput.'
(shutdownOutput): use `PlainSocketImpl.shutdownOutput.'
(create): create `channel,' initialize `impl's native state.
(connect): use `connect(SocketAddress, int).'
(connect): use `SocketChannelImpl.connect;' initialize `address'
and `port.'
(bind): use `VMPlainSocketImpl.bind.'
(listen): use `VMPlainSocketImpl.listen.'
(accept): use `SocketChannelImpl.accept.'
(available): use `VMChannel.available.'
(close): use `PlainSocketImpl.close.'
(sendUrgentData): use `PlainSocketImpl.sendUrgentData.'
(getVMChannel, getInetAddress, getLocalPort, getLocalAddress,
getPort): new methods.
(SocketInputStream.read): use `VMChannel.read.'
(SocketInputStream.read): use `SocketChannel.read.'
(SocketOutputStream.write): use `VMChannel.write.'
(SocketOutputStream.write): use `SocketChannel.write.'
* gnu/java/nio/DatagramChannelImpl.java: implement VMChannel.
(channel): new field.
(<init>): initialize `channel.'
(implCloseSelectableChannel): use `VMChannel.close.'
(implConfigureBlocking): use `VMChannel.setBlocking.'
(connect): use `VMChannel.connect.'
(disconnect): use `VMChannel.disconnect.'
(isConnected): use `VMChannel.getPeerAddress.'
(write): use `VMChannel.write.'
(write): use `VMChannel.writeGathering.'
(read): use `VMChannel.read.'
(read): use `VMChannel.readScattering.'
(receive): use `VMChannel.receive.'
(send): use `VMChannel.send.'
(getVMChannel): new method.
* gnu/java/nio/DatagramChannelSelectionKey.java (getNativeFD):
access native FD through VMChannel.State.
* gnu/java/nio/FileChannelImpl.java: moved from
gnu/java/nio/channels/FileChannelImpl.java.
* gnu/java/nio/FileLockImpl.java: fix imports.
* gnu/java/nio/KqueueSelectionKeyImpl.java: new file.
* gnu/java/nio/KqueueSelectorImpl.java: new file.
* gnu/java/nio/NIOSocket.java (impl): removed.
(channel): new field.
(<init>): init superclass with a `NIOSocketImpl;' init `channel.'
(getPlainSocketImpl, setChannel): removed.
(isConnected): new method.
* gnu/java/nio/NIOSocketImpl.java: new file.
* gnu/java/nio/PipeImpl.java (SourceChannelImpl): implement
`VMChannelOwner.'
(SourceChannelImpl.native_fd): removed.
(SourceChannelImpl.<init>): init with a `VMChannel.'
(SourceChannelImpl.getNativeFD): removed.
(SourceChannelImpl.getVMChannel): new method.
(SourceChannelImpl.implCloseSelectableChannel): implement.
(SinkChannelImpl): implement `VMChannelOwner.'
(SinkChannelImpl.native_fd): removed.
(SinkChannelImpl.<init>): init with a `VMChannel.'
(SinkChannelImpl.implCloseSelectableChannel): implement.
(SinkChannelImpl.getNativeFD): removed.
(SinkChannelImpl.getVMChannel): new method.
* gnu/java/nio/SelectionKeyImpl.java (getNativeFD): mark
deprecated.
* gnu/java/nio/SelectorProviderImpl.java (SELECTOR_IMPL_KQUEUE,
SELECTOR_IMPL_EPOLL, SELECTOR_IMPL): new constants.
(openSelector): return kqueue selector if available.
* gnu/java/nio/ServerSocketChannelImpl.java: implement
`VMChannelOwner.'
(channel): new field.
(<init>): init `channel.'
(finalizer): check if the `VMChannel.State' is valid.
(implCloseSelectableChannel): use `VMChannel.close.'
(implConfigureBlocking): use `VMChannel.setBlocking.'
(accept): use `VMChannel.accept.'
(getVMChannel): new method.
* gnu/java/nio/ServerSocketChannelSelectionKey.java (getNativeFD):
access native FD through `VMChannel.State.'
* gnu/java/nio/SocketChannelImpl.java: implement `VMChannelOwner.'
(impl): removed.
(channel, connected, connectAddress): new field.
(<init>): new constructors.
(getPlainSocketImpl): removed.
(implCloseSelectableChannel): use `VMChannel.close.'
(implConfigureBlocking): use `VMChannel.setBlocking.'
(connect): use `connect(SocketAddress,int).'
(connect): use `VMChannel.connect.'
(finishConnect): don't use a selector.
(isConnected): use `VMChannel.getPeerAddress.'
(read): use `VMChannel.read.'
(read): use `VMChannel.readScattering.'
(write): use `VMChannel.write.'
(write): use `VMChannel.writeGathering.'
(getVMChannel): new method.
* gnu/java/nio/SocketChannelSelectionKey.java (getNativeFD): get
native FD from `VMChannel.State.'
* gnu/java/nio/SocketChannelSelectionKeyImpl.java (getNativeFD):
get native FD from `VMChannel.State.'
* gnu/java/nio/VMChannelOwner.java: new file.
* gnu/java/nio/channels/FileChannelImpl.java: removed.
* include/Makefile.am: generate `gnu_java_nio_FileChannelImpl.h'
and `gnu_java_nio_KqueueSelectorImpl.h;' don't generate
`gnu_java_nio_channels_FileChannelImpl.h.'
* include/gnu_java_net_VMPlainSocketImpl.h: regenerated.
* include/gnu_java_nio_FileChannelImpl.h: new file.
* include/gnu_java_nio_KqueueSelectorImpl.h: new file.
* include/gnu_java_nio_VMChannel.h: regenerated.
* include/gnu_java_nio_VMPipe.h: regenerated.
* include/java_net_VMNetworkInterface.h: regenerated.
* java/io/FileDescriptor.java: fix imports.
* java/io/FileInputStream.java (<init>): handle exceptions.
(read): wrap the destination arary.
* java/io/FileOutputStream.java (<init>): handle exceptions.
(write): wrap the source array.
* java/io/RandomAccessFile.java (<init>): handle exceptions.
* java/net/DatagramSocket.java (<init>): handle exceptions.
(receive): handle length/port setting.
(connect): bind to any address/port if the argument is null.
* java/net/NetworkInterface.java (name, inetAddress): removed.
(netif): new field.
(<init>): make private.
(getName): return `netif.name.'
(getInetAddresses): access `netif.addresses.'
(getDisplayName): return `netif.name.'
(getByName, getByAddress): handle changes to `VMNetworkInterface.'
(condense): removed.
(getNetworkInterfaces): handle changes to `VMNetworkInterface.'
(equals): compare `netif' fields.
(hashCode): get hash codes from `netif.'
(toString): use a StringBuffer.
* java/net/ServerSocket.java (close): don't set `impl' to null.
(isClosed): use `VMChannel.State.isClosed.'
* java/net/Socket.java (getLocalAddress): don't use `getOption' if
the `SocketImpl' is a `PlainSocketImpl.'
(close): just close the `impl.'
(toString): use `super.toString' in the value we return.
(isConnected): just access `impl,' not `getImpl.'
(isBound): use `PlainSocketImpl' methods if we can.
(isClosed): look at `VMChannel.State.'
* native/jni/classpath/jcl.c (JNI_OnLoad): new function.
(JCL_NewRawDataObject): don't initialize cached fields here; throw
an exception if they were not.
(JCL_GetRawData): throw an exception if cached fields weren't
created.
* native/jni/java-lang/java_lang_VMProcess.c: handle
FileChannelImpl move.
* native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c
(IO_EXCEPTION, SOCKET_EXCEPTION, BIND_EXCEPTION,
THROW_NO_NETWORK): new macros.
(Java_gnu_java_net_VMPlainSocketImpl_bind): reipmlemented.
(Java_gnu_java_net_VMPlainSocketImpl_bind6): new function.
(Java_gnu_java_net_VMPlainSocketImpl_listen): reimplemented.
(java_sockopt): new enum.
(Java_gnu_java_net_VMPlainSocketImpl_setOption): reimplemented.
(Java_gnu_java_net_VMPlainSocketImpl_getOption): reimplemented.
(Java_gnu_java_net_VMPlainSocketImpl_shutdownInput):
reimplemented.
(Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput):
reimplemented.
(Java_gnu_java_net_VMPlainSocketImpl_sendUrgentData): new
function.
(Java_gnu_java_net_VMPlainSocketImpl_join): new function.
(Java_gnu_java_net_VMPlainSocketImpl_join6): new function.
(Java_gnu_java_net_VMPlainSocketImpl_read): removed.
(Java_gnu_java_net_VMPlainSocketImpl_leave): new function.
(Java_gnu_java_net_VMPlainSocketImpl_leave6): new function.
(Java_gnu_java_net_VMPlainSocketImpl_joinGroup): new function.
(Java_gnu_java_net_VMPlainSocketImpl_write): removed.
(Java_gnu_java_net_VMPlainSocketImpl_joinGroup6): new function.
(Java_gnu_java_net_VMPlainSocketImpl_leaveGroup): new function.
(Java_gnu_java_net_VMPlainSocketImpl_leaveGroup6): new function.
(getif_address): new function.
(getif_index): new function.
* native/jni/java-net/java_net_VMNetworkInterface.c
(java_net_VMNetworkInterface_init,
java_net_VMNetworkInterface_addAddress): new file-scope globals.
(Java_java_net_VMNetworkInterface_initIds): new function.
(struct netif_entry): new struct.
(free_netif_list): new function.
(Java_java_net_VMNetworkInterface_getInterfaces): removed.
(Java_java_net_VMNetworkInterface_getVMInterfaces): new function.
* native/jni/java-nio/Makefile.am (libjavanio_la_SOURCES): remove
gnu_java_nio_channels_FileChannelImpl.c, add
gnu_java_nio_KqueueSelectorImpl.c.
* native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c: new file.
* native/jni/java-nio/gnu_java_nio_VMChannel.c
(INTERRUPTED_IO_EXCEPTION, SOCKET_TIMEOUT_EXCEPTION, ALIGN_UP,
ALIGN_DOWN): new macros.
(JCL_init_buffer): get the address through GetDirectBufferAddress
if possible.
(Java_gnu_java_nio_VMChannel_stdin_1fd,
Java_gnu_java_nio_VMChannel_stdout_1fd,
Java_gnu_java_nio_VMChannel_stderr_1fd): new functions.
(Java_gnu_java_nio_VMChannel_setBlocking): fix setting blocking
value.
(Java_gnu_java_nio_VMChannel_read): renamed...
(Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2): to
this; handle interrupted IO; add HAVE_READ check.
(Java_gnu_java_nio_VMChannel_write): renamed...
(Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2): to
this; handle zero-length write; add HAVE_WRITE check.
(Java_gnu_java_nio_VMChannel_receive): new function.
(Java_gnu_java_nio_VMChannel_send): new function.
(Java_gnu_java_nio_VMChannel_send6): new function.
(Java_gnu_java_nio_VMChannel_read__I): new function.
(Java_gnu_java_nio_VMChannel_write__II): new function.
(Java_gnu_java_nio_VMChannel_socket): new function.
(Java_gnu_java_nio_VMChannel_connect): new function.
(Java_gnu_java_nio_VMChannel_connect6): new function.
(Java_gnu_java_nio_VMChannel_getsockname): new function.
(Java_gnu_java_nio_VMChannel_getpeername): new function.
(Java_gnu_java_nio_VMChannel_accept): new function.
(Java_gnu_java_nio_VMChannel_disconnect): new function.
(Java_gnu_java_nio_VMChannel_close): new function.
(Java_gnu_java_nio_VMChannel_available): new function.
(FileChannel_mode): new enum.
(Java_gnu_java_nio_VMChannel_open): new function.
(Java_gnu_java_nio_VMChannel_position): new function.
(Java_gnu_java_nio_VMChannel_seek): new function.
(Java_gnu_java_nio_VMChannel_truncate): new funciton.
(Java_gnu_java_nio_VMChannel_lock): new function.
(Java_gnu_java_nio_VMChannel_unlock): new function.
(Java_gnu_java_nio_VMChannel_size): new function.
(Java_gnu_java_nio_VMChannel_map): new function.
(Java_gnu_java_nio_VMChannel_flush): new function.
* native/jni/java-nio/gnu_java_nio_VMPipe.c
(Java_gnu_java_nio_VMPipe_init): removed.
(Java_gnu_java_nio_VMPipe_pipe0): new function.
* native/jni/java-nio/javanio.c: new file.
* native/jni/java-nio/javanio.h: new file.
* native/jni/native-lib/cpnet.c (cpnet_getHostByName): fix for
systems without `gethostbyname_r.'
* vm/reference/gnu/java/net/VMPlainSocketImpl.java (nfd): new
field.
(<init>, <init>): new constructors.
(setOption, getOption): make instance methods; defer to native
implementation.
(connect): removed.
(bind): make an instance method; defer to native methods.
(accept): removed.
(available): removed.
(listen): make an instance method; defer to native method.
(read): removed.
(join, leave): new methods.
(write): removed.
(joinGroup, leaveGroup): new methods.
(shutdownInput, shutdownOutput): make instance methods.
(sendUrgentData): removed.
(State): new class.
* vm/reference/gnu/java/nio/VMChannel.java: make final.
(fd): removed.
(nfd): new field.
(<init>): new, public constructors.
(getVMChannel): methods removed.
(getState, getStdin, getStdout, getStderr, stdin_fd, stdout_fd,
stderr_fd): new methods.
(setBlocking): make an instance method.
(available): new method.
(read): get native fd from `nfd.'
(read): new single-byte read method.
(readScattering): get native fd from `nfd.'
(receive): new method.
(write, writeGathering): get native fd from `nfd.'
(send): new method.
(write): new single-byte write method.
(initSocket): new method.
(connect): new method.
(disconnect): new method.
(getLocalAddress): new method.
(getPeerAddress): new method.
(accept): new method.
(openFile): new method.
(position): new method.
(seek): new method.
(truncate): new method.
(lock): new method.
(unlock): new method.
(size): new method.
(map): new method.
(flush): new method.
(close): new method.
(State): new class.
(Kind): new class.
* vm/reference/gnu/java/nio/VMPipe.java (init): removed.
(pipe, pipe0): new method.
* vm/reference/java/net/VMNetworkInterface.java (name, addresses):
new fields.
(<clinit>): call `initIds.'
(initIds): new method.
(getInterfaces): removed.
(getVMInterfaces): new method.
(addAddress): new method.
* vm/reference/java/nio/channels/VMChannels.java: fix imports.
Diffstat (limited to 'native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c')
-rw-r--r-- | native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c | 876 |
1 files changed, 706 insertions, 170 deletions
diff --git a/native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c b/native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c index fb9855908..989ed3146 100644 --- a/native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c +++ b/native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c @@ -35,265 +35,801 @@ 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. */ -/* do not move; needed here because of some macro definitions */ -#include <config.h> +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <ifaddrs.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <unistd.h> #include <jni.h> #include <jcl.h> -#include <cpnative.h> -#include <cpnet.h> -#include "javanet.h" +/* #include "javanet.h" */ #include "gnu_java_net_VMPlainSocketImpl.h" -/* - * Note that the functions in this module simply redirect to another - * internal function. Why? Because many of these functions are shared - * with PlainDatagramSocketImpl. The unshared ones were done the same - * way for consistency. - */ +#define IO_EXCEPTION "java/io/IOException" +#define SOCKET_EXCEPTION "java/net/SocketException" +#define BIND_EXCEPTION "java/net/BindException" + +#define THROW_NO_NETWORK(env) JCL_ThrowException (env, "java/lang/InternalError", "this platform not configured for network support") -/*************************************************************************/ /* - * Creates a new stream or datagram socket + * Class: gnu_java_net_VMPlainSocketImpl + * Method: bind + * Signature: (I[BI)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_create(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj) +Java_gnu_java_net_VMPlainSocketImpl_bind (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint fd, jbyteArray addr, jint port) { -#ifndef WITHOUT_NETWORK - _javanet_create(env, obj, JNI_TRUE); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + struct sockaddr_in sockaddr; + jbyte *elems = NULL; + int ret; + + if (addr != NULL) + elems = (*env)->GetByteArrayElements (env, addr, NULL); + + memset(&sockaddr, 0, sizeof (struct sockaddr_in)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons (port); + /* addr is already in network byte order. */ + if (elems != NULL) + sockaddr.sin_addr.s_addr = *((uint32_t *) elems); + else + sockaddr.sin_addr.s_addr = INADDR_ANY; + + /* bind(2) from BSD says bind will never return EINTR */ + /* bind is not a blocking system call */ + ret = bind (fd, (struct sockaddr *) &sockaddr, sizeof (struct sockaddr_in)); + + if (elems != NULL) + (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT); + + if (-1 == ret) + JCL_ThrowException (env, BIND_EXCEPTION, strerror (errno)); } -/*************************************************************************/ /* - * Close the socket. Any underlying streams will be closed by this - * action as well. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: bind6 + * Signature: (I[BI)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_close(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj) +Java_gnu_java_net_VMPlainSocketImpl_bind6 (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, jint port) { -#ifndef WITHOUT_NETWORK - _javanet_close(env, obj, 1); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + /* FIXME! Add check if we have IPv6! */ + struct sockaddr_in6 sockaddr; + jbyte *elems; + int ret; + + 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, elems, 16); + + /* bind(2) from BSD says bind will never return EINTR */ + /* bind is not a blocking system call */ + ret = bind (fd, (struct sockaddr *) &sockaddr, + sizeof (struct sockaddr_in6)); + + (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT); + + if (-1 == ret) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); } -/*************************************************************************/ /* - * Connects to the specified destination. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: listen + * Signature: (II)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_connect(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jobject addr, jint port) +Java_gnu_java_net_VMPlainSocketImpl_listen (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jint backlog) { -#ifndef WITHOUT_NETWORK - _javanet_connect(env, obj, addr, port, 1); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + int ret; + + /* listen(2) says that this call will never return EINTR */ + /* listen is not a blocking system call */ + if ((ret = listen (fd, backlog)) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + printf("listen returns %d\n", ret); } -/*************************************************************************/ + +/* These constants are also defined in java/net/SocketOptions.java */ +enum java_sockopt { + CPNET_SO_KEEPALIVE = 0x8, + CPNET_SO_LINGER = 0x80, + CPNET_SO_TIMEOUT = 0x1006, + CPNET_SO_BINDADDR = 0x0F, + CPNET_SO_SNDBUF = 0x1001, + CPNET_SO_RCVBUF = 0x1002, + CPNET_SO_REUSEADDR = 0x04, + CPNET_SO_BROADCAST = 0x20, + CPNET_SO_OOBINLINE = 0x1003, + CPNET_TCP_NODELAY = 0x01, + CPNET_IP_MULTICAST_IF = 0x10, + CPNET_IP_MULTICAST_IF2 = 0x1F, + CPNET_IP_MULTICAST_LOOP = 0x12, + CPNET_IP_TOS = 0x03 +}; + /* - * This method binds the specified address to the specified local port. - * Note that we have to set the local address and local port public instance - * variables. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: setOption + * Signature: (III)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_bind(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jobject addr, - jint port) +Java_gnu_java_net_VMPlainSocketImpl_setOption (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jint option, jint value) { -#ifndef WITHOUT_NETWORK - _javanet_bind(env, obj, addr, port, 1); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + enum java_sockopt joption = (enum java_sockopt) option; + int optname = -1; + int level = SOL_SOCKET; + const int _value = value; + struct linger _linger; + struct timeval _timeo; + void *optval = (void *) &_value; + socklen_t optlen = sizeof (int); + + switch (joption) + { + case CPNET_IP_MULTICAST_LOOP: + level = IPPROTO_IP; + optname = IP_MULTICAST_LOOP; + break; + + case CPNET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + + case CPNET_SO_LINGER: + optname = SO_LINGER; + if (_value == 0) + _linger.l_onoff = 0; + else + _linger.l_onoff = 1; + _linger.l_linger = _value; + optval = &_linger; + optlen = sizeof (struct linger); + break; + + case CPNET_SO_TIMEOUT: + optname = SO_RCVTIMEO; + _timeo.tv_sec = value / 1000; + _timeo.tv_usec = (value % 1000) * 1000; + optval = &_timeo; + optlen = sizeof (struct timeval); + break; + + case CPNET_SO_SNDBUF: + optname = SO_SNDBUF; + break; + + case CPNET_SO_RCVBUF: + optname = SO_RCVBUF; + break; + + case CPNET_SO_REUSEADDR: + optname = SO_REUSEADDR; + break; + + case CPNET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + + case CPNET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + + case CPNET_TCP_NODELAY: + level = IPPROTO_TCP; + optname = TCP_NODELAY; + break; + + case CPNET_IP_TOS: + level = IPPROTO_IP; + optname = IP_TOS; + break; + + case CPNET_SO_BINDADDR: + case CPNET_IP_MULTICAST_IF: + case CPNET_IP_MULTICAST_IF2: + JCL_ThrowException (env, IO_EXCEPTION, "argument not a boolean or integer option"); + return; + } + + if (setsockopt (fd, level, optname, (const void *) optval, optlen) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); +} + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: getOption + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_gnu_java_net_VMPlainSocketImpl_getOption (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jint option) +{ + enum java_sockopt joption = (enum java_sockopt) option; + int optname = -1; + int level = SOL_SOCKET; + int value; + struct linger linger; + struct timeval timeo; + void *optval = &value; + socklen_t optlen = sizeof (int); + + switch (joption) + { + case CPNET_IP_MULTICAST_LOOP: + level = IPPROTO_IP; + optname = IP_MULTICAST_LOOP; + break; + + case CPNET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + + case CPNET_SO_LINGER: + optname = SO_LINGER; + optval = &linger; + optlen = sizeof (struct linger); + break; + + case CPNET_SO_TIMEOUT: + optname = SO_RCVTIMEO; + optval = &timeo; + optlen = sizeof (struct timeval); + break; + + case CPNET_SO_SNDBUF: + optname = SO_SNDBUF; + break; + + case CPNET_SO_RCVBUF: + optname = SO_RCVBUF; + break; + + case CPNET_SO_REUSEADDR: + optname = SO_REUSEADDR; + break; + + case CPNET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + + case CPNET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + + case CPNET_TCP_NODELAY: + level = IPPROTO_TCP; + optname = TCP_NODELAY; + break; + + case CPNET_IP_TOS: + level = IPPROTO_IP; + optname = IP_TOS; + break; + + case CPNET_SO_BINDADDR: + case CPNET_IP_MULTICAST_IF: + case CPNET_IP_MULTICAST_IF2: + JCL_ThrowException (env, IO_EXCEPTION, "argument not a boolean or integer option"); + return -1; + } + + if (getsockopt (fd, level, optname, optval, &optlen) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + + if (joption == CPNET_SO_LINGER) + return linger.l_linger; + if (joption == CPNET_SO_TIMEOUT) + return (timeo.tv_sec * 1000) + (timeo.tv_usec / 1000); + + return value; } -/*************************************************************************/ /* - * Starts listening on a socket with the specified number of pending - * connections allowed. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: shutdownInput + * Signature: (I)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_listen(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jint queuelen) +Java_gnu_java_net_VMPlainSocketImpl_shutdownInput (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) { -#ifndef WITHOUT_NETWORK - _javanet_listen(env, obj, queuelen); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + if (shutdown (fd, SHUT_RD) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); } -/*************************************************************************/ - /* - * Accepts a new connection and assigns it to the passed in SocketImpl - * object. Note that we assume this is a PlainSocketImpl just like us. + * Class: gnu_java_net_VMPlainSocketImpl + * Method: shutdownOutput + * Signature: (I)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_accept(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jobject impl) +Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd) { -#ifndef WITHOUT_NETWORK - _javanet_accept(env, obj, impl); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ + if (shutdown (fd, SHUT_WR) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); } -/*************************************************************************/ -JNIEXPORT jint JNICALL -Java_gnu_java_net_VMPlainSocketImpl_available(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj) +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: sendUrgentData + * Signature: (II)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_sendUrgentData (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jint data) { -#ifndef WITHOUT_NETWORK - jclass cls; - jfieldID fid; - int fd; - int bytesAvailable; - int result; - - cls = (*env)->GetObjectClass(env, obj); - if (cls == 0) - { - JCL_ThrowException(env, IO_EXCEPTION, "internal error"); - return 0; - } - - fid = (*env)->GetFieldID(env, cls, "native_fd", "I"); - if (fid == 0) - { - JCL_ThrowException(env, IO_EXCEPTION, "internal error"); - return 0; - } + const char x = (char) data; - fd = (*env)->GetIntField(env, obj, fid); - - result = cpnet_getAvailableBytes (env, fd, &bytesAvailable); - if (result != CPNATIVE_OK) - { - JCL_ThrowException(env, IO_EXCEPTION, cpnative_getErrorString (result)); - return 0; - } - - return bytesAvailable; -#else /* not WITHOUT_NETWORK */ - return 0; -#endif /* not WITHOUT_NETWORK */ + if (send (fd, &x, 1, MSG_OOB) == -1) + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); } -/*************************************************************************/ /* - * This method sets the specified option for a socket + * Class: gnu_java_net_VMPlainSocketImpl + * Method: join + * Signature: (I[B)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_setOption(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jint option_id, jobject val) +Java_gnu_java_net_VMPlainSocketImpl_join (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint fd, jbyteArray addr) { -#ifndef WITHOUT_NETWORK - _javanet_set_option(env, obj, option_id, val); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +#ifdef HAVE_SETSOCKOPT + struct ip_mreq maddr; + jbyte *addr_elems; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems); + maddr.imr_interface.s_addr = INADDR_ANY; + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &maddr, sizeof (struct ip_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } -/*************************************************************************/ /* - * This method gets the specified option for a socket + * Class: gnu_java_net_VMPlainSocketImpl + * Method: join6 + * Signature: (I[B)V */ -JNIEXPORT jobject JNICALL -Java_gnu_java_net_VMPlainSocketImpl_getOption(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, - jint option_id) +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_join6 (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint fd, jbyteArray addr) { -#ifndef WITHOUT_NETWORK - return(_javanet_get_option(env, obj, option_id)); -#else /* not WITHOUT_NETWORK */ - return NULL; -#endif /* not WITHOUT_NETWORK */ +#ifdef HAVE_SETSOCKOPT +#ifdef HAVE_INET6 + struct ipv6_mreq maddr; + jbyte *addr_elems; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16); + maddr.ipv6mr_interface = 0; + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &maddr, sizeof (struct ipv6_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "IPv6 support not available"); +#endif /* HAVE_INET6 */ +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } -/*************************************************************************/ +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leave + * Signature: (I[B)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_leave (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr) +{ +#ifdef HAVE_SETSOCKOPT + struct ip_mreq maddr; + jbyte *addr_elems; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems); + maddr.imr_interface.s_addr = INADDR_ANY; + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + &maddr, sizeof (struct ip_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ +} /* - * Reads a buffer from a remote host + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leave6 + * Signature: (I[B)V */ -JNIEXPORT jint JNICALL -Java_gnu_java_net_VMPlainSocketImpl_read(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jarray buf, - jint offset, jint len) +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_leave6 (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr) { -#ifndef WITHOUT_NETWORK - return(_javanet_recvfrom(env, obj, buf, offset, len, 0)); -#else /* not WITHOUT_NETWORK */ - return 0; -#endif /* not WITHOUT_NETWORK */ +#ifdef HAVE_SETSOCKOPT +#ifdef HAVE_INET6 + struct ipv6_mreq maddr; + jbyte *addr_elems; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16); + maddr.ipv6mr_interface = 0; + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &maddr, sizeof (struct ipv6_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "IPv6 support not available"); +#endif /* HAVE_INET6 */ +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } -/*************************************************************************/ +static uint32_t getif_address (JNIEnv *env, char *ifname); +static int getif_index (JNIEnv *env, char *ifname); /* - * Writes a buffer to the remote host + * Class: gnu_java_net_VMPlainSocketImpl + * Method: joinGroup + * Signature: (I[BILjava/lang/String;)V */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_write(JNIEnv *env, - jclass klass __attribute__ ((__unused__)), - jobject obj, jarray buf, - jint offset, jint len) +Java_gnu_java_net_VMPlainSocketImpl_joinGroup (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, + jstring ifname) { -#ifndef WITHOUT_NETWORK - _javanet_sendto(env, obj, buf, offset, len, 0); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +#ifdef HAVE_SETSOCKOPT + struct ip_mreq maddr; + jbyte *addr_elems; + + if (ifname != NULL) + { + maddr.imr_interface.s_addr = getif_address (env, ifname); + if ((*env)->ExceptionCheck (env)) + return; + } + else + maddr.imr_interface.s_addr = INADDR_ANY; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &maddr, sizeof (struct ip_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + (void) ifname; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: joinGroup6 + * Signature: (I[BILjava/lang/String;)V + */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_shutdownInput (JNIEnv * env, - jclass klass __attribute__ ((__unused__)), - jobject this) +Java_gnu_java_net_VMPlainSocketImpl_joinGroup6 (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, + jstring ifname) { -#ifndef WITHOUT_NETWORK - _javanet_shutdownInput (env, this); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +#ifdef HAVE_SETSOCKOPT +#ifdef HAVE_INET6 + struct ipv6_mreq maddr; + jbyte *addr_elems; + + if (ifname == NULL) + { + maddr.ipv6mr_interface = getif_index (env, ifname); + if ((*env)->ExceptionCheck (env)) + return; + } + else + maddr.ipv6mr_interface = 0; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &maddr, sizeof (struct ipv6_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "IPv6 support not available"); +#endif /* HAVE_INET6 */ +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leaveGroup + * Signature: (I[BILjava/lang/String;)V + */ JNIEXPORT void JNICALL -Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput (JNIEnv * env, - jclass klass __attribute__ ((__unused__)), - jobject this) +Java_gnu_java_net_VMPlainSocketImpl_leaveGroup (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, + jstring ifname) { -#ifndef WITHOUT_NETWORK - _javanet_shutdownOutput (env, this); -#else /* not WITHOUT_NETWORK */ -#endif /* not WITHOUT_NETWORK */ +#ifdef HAVE_SETSOCKOPT + struct ip_mreq maddr; + jbyte *addr_elems; + + if (ifname != NULL) + { + maddr.imr_interface.s_addr = getif_address (env, ifname); + if ((*env)->ExceptionCheck (env)) + return; + } + else + maddr.imr_interface.s_addr = INADDR_ANY; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + maddr.imr_multiaddr.s_addr = * ((uint32_t *) addr_elems); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + &maddr, sizeof (struct ip_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + (void) ifname; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ +} + +/* + * Class: gnu_java_net_VMPlainSocketImpl + * Method: leaveGroup6 + * Signature: (I[BILjava/lang/String;)V + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_VMPlainSocketImpl_leaveGroup6 (JNIEnv *env, + jclass c __attribute__((unused)), + jint fd, jbyteArray addr, + jstring ifname) +{ +#ifdef HAVE_SETSOCKOPT +#ifdef HAVE_INET6 + struct ipv6_mreq maddr; + jbyte *addr_elems; + + if (ifname == NULL) + { + maddr.ipv6mr_interface = getif_index (env, ifname); + if ((*env)->ExceptionCheck (env)) + return; + } + else + maddr.ipv6mr_interface = 0; + + addr_elems = (*env)->GetByteArrayElements (env, addr, NULL); + if (addr_elems == NULL) + return; + + memcpy (&(maddr.ipv6mr_multiaddr.s6_addr), addr_elems, 16); + + (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT); + + if (-1 == setsockopt (fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + &maddr, sizeof (struct ipv6_mreq))) + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "IPv6 support not available"); +#endif /* HAVE_INET6 */ +#else + (void) fd; + (void) addr; + JCL_ThrowException (env, "java/lang/InternalError", + "socket options not supported"); +#endif /* HAVE_SETSOCKOPT */ } -/* end of file */ +static uint32_t +getif_address (JNIEnv *env, char *ifname) +{ +#ifdef HAVE_GETIFADDRS + struct ifaddrs *ifaddrs, *i; + uint32_t addr = 0; + int foundaddr = 0; + + if (getifaddrs (&ifaddrs) == -1) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); + return 0; + } + + for (i = ifaddrs; i != NULL; i = i->ifa_next) + { + if (strcmp (ifname, i->ifa_name) == 0) + { + /* Matched the name; see if there is an IPv4 address. */ + if (i->ifa_addr->sa_family == AF_INET) + { + foundaddr = 1; + addr = ((struct sockaddr_in *) i->ifa_addr)->sin_addr.s_addr; + break; + } + } + } + + if (!foundaddr) + JCL_ThrowException (env, SOCKET_EXCEPTION, "interface has no IPv4 address"); + + freeifaddrs (ifaddrs); + + return addr; +#else + (void) ifname; + JCL_ThrowException (env, "java/lang/InternalError", + "getifaddrs not available"); + return 0; +#endif /* HAVE_GETIFADDRS */ +} + +static int +getif_index (JNIEnv *env, char *ifname) +{ +#ifdef HAVE_GETIFADDRS + struct ifaddrs *ifaddrs, *i; + char *lastname = NULL; + int index = 1; + int foundname = 0; + + if (getifaddrs (&ifaddrs) == -1) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno)); + return -1; + } + + lastname = ifaddrs->ifa_name; + for (i = ifaddrs; i != NULL; i = i->ifa_next) + { + if (strcmp (lastname, ifaddrs->ifa_name) != 0) + { + lastname = ifaddrs->ifa_name; + index++; + } + if (strcmp (ifname, ifaddrs->ifa_name) == 0) + { + foundname = 1; + break; + } + } + + if (!foundname) + JCL_ThrowException (env, SOCKET_EXCEPTION, + "no interface with that name"); + + freeifaddrs (ifaddrs); + + return index; +#else + (void) ifname; + JCL_ThrowException (env, "java/lang/InternalError", + "getifaddrs not available"); + return -1; +#endif /* HAVE_GETIFADDRS */ +} |