|
Java example source code file (netty_unix_socket.c)
The netty_unix_socket.c Java example source code/* * Copyright 2015 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <sys/un.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/tcp.h> #include "netty_unix_errors.h" #include "netty_unix_socket.h" #include "netty_unix_util.h" static jclass datagramSocketAddressClass = NULL; static jmethodID datagramSocketAddrMethodId = NULL; static jmethodID inetSocketAddrMethodId = NULL; static jclass inetSocketAddressClass = NULL; static jclass netUtilClass = NULL; static jmethodID netUtilClassIpv4PreferredMethodId = NULL; static int socketType; static const char* ip4prefix = "::ffff:"; static const unsigned char wildcardAddress[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const unsigned char ipv4MappedWildcardAddress[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }; // Optional external methods extern int accept4(int sockFd, struct sockaddr* addr, socklen_t* addrlen, int flags) __attribute__((weak)); // macro to calculate the length of a sockaddr_un struct for a given path length. // see sys/un.h#SUN_LEN, this is modified to allow nul bytes #define _UNIX_ADDR_LENGTH(path_len) (uintptr_t) (((struct sockaddr_un *) 0)->sun_path) + path_len static jobject createDatagramSocketAddress(JNIEnv* env, const struct sockaddr_storage* addr, int len) { char ipstr[INET6_ADDRSTRLEN]; int port; jstring ipString; if (addr->ss_family == AF_INET) { struct sockaddr_in* s = (struct sockaddr_in*) addr; port = ntohs(s->sin_port); inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); ipString = (*env)->NewStringUTF(env, ipstr); } else { struct sockaddr_in6* s = (struct sockaddr_in6*) addr; port = ntohs(s->sin6_port); inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr); if (strncasecmp(ipstr, ip4prefix, 7) == 0) { // IPv4-mapped-on-IPv6. // Cut of ::ffff: prefix to workaround performance issues when parsing these // addresses in InetAddress.getByName(...). // // See https://github.com/netty/netty/issues/2867 ipString = (*env)->NewStringUTF(env, &ipstr[7]); } else { ipString = (*env)->NewStringUTF(env, ipstr); } } jobject socketAddr = (*env)->NewObject(env, datagramSocketAddressClass, datagramSocketAddrMethodId, ipString, port, len); return socketAddr; } static int addressLength(const struct sockaddr_storage* addr) { if (addr->ss_family == AF_INET) { return 8; } else { struct sockaddr_in6* s = (struct sockaddr_in6*) addr; if (s->sin6_addr.s6_addr[0] == 0x00 && s->sin6_addr.s6_addr[1] == 0x00 && s->sin6_addr.s6_addr[2] == 0x00 && s->sin6_addr.s6_addr[3] == 0x00 && s->sin6_addr.s6_addr[4] == 0x00 && s->sin6_addr.s6_addr[5] == 0x00 && s->sin6_addr.s6_addr[6] == 0x00 && s->sin6_addr.s6_addr[7] == 0x00 && s->sin6_addr.s6_addr[8] == 0x00 && s->sin6_addr.s6_addr[9] == 0x00 && s->sin6_addr.s6_addr[10] == 0xff && s->sin6_addr.s6_addr[11] == 0xff) { // IPv4-mapped-on-IPv6 return 8; } else { return 24; } } } static void initInetSocketAddressArray(JNIEnv* env, const struct sockaddr_storage* addr, jbyteArray bArray, int offset, int len) { int port; if (addr->ss_family == AF_INET) { struct sockaddr_in* s = (struct sockaddr_in*) addr; port = ntohs(s->sin_port); // Encode address and port into the array unsigned char a[4]; a[0] = port >> 24; a[1] = port >> 16; a[2] = port >> 8; a[3] = port; (*env)->SetByteArrayRegion(env, bArray, offset, 4, (jbyte*) &s->sin_addr.s_addr); (*env)->SetByteArrayRegion(env, bArray, offset + 4, 4, (jbyte*) &a); } else { struct sockaddr_in6* s = (struct sockaddr_in6*) addr; port = ntohs(s->sin6_port); if (len == 8) { // IPv4-mapped-on-IPv6 // Encode port into the array and write it into the jbyteArray unsigned char a[4]; a[0] = port >> 24; a[1] = port >> 16; a[2] = port >> 8; a[3] = port; // we only need the last 4 bytes for mapped address (*env)->SetByteArrayRegion(env, bArray, offset, 4, (jbyte*) &(s->sin6_addr.s6_addr[12])); (*env)->SetByteArrayRegion(env, bArray, offset + 4, 4, (jbyte*) &a); } else { // Encode scopeid and port into the array unsigned char a[8]; a[0] = s->sin6_scope_id >> 24; a[1] = s->sin6_scope_id >> 16; a[2] = s->sin6_scope_id >> 8; a[3] = s->sin6_scope_id; a[4] = port >> 24; a[5] = port >> 16; a[6] = port >> 8; a[7] = port; (*env)->SetByteArrayRegion(env, bArray, offset, 16, (jbyte*) &(s->sin6_addr.s6_addr)); (*env)->SetByteArrayRegion(env, bArray, offset + 16, 8, (jbyte*) &a); } } } static jbyteArray createInetSocketAddressArray(JNIEnv* env, const struct sockaddr_storage* addr) { int len = addressLength(addr); jbyteArray bArray = (*env)->NewByteArray(env, len); initInetSocketAddressArray(env, addr, bArray, 0, len); return bArray; } static int socket_type(JNIEnv* env) { jboolean ipv4Preferred = (*env)->CallStaticBooleanMethod(env, netUtilClass, netUtilClassIpv4PreferredMethodId); if (ipv4Preferred) { // User asked to use ipv4 explicitly. return AF_INET; } int fd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0); if (fd == -1) { if (errno == EAFNOSUPPORT) { return AF_INET; } return AF_INET6; } else { close(fd); return AF_INET6; } } static jint _socket(JNIEnv* env, jclass clazz, int type) { int fd = socket(socketType, type | SOCK_NONBLOCK, 0); if (fd == -1) { return -errno; } else if (socketType == AF_INET6) { // Allow to listen /connect ipv4 and ipv6 int optval = 0; if (netty_unix_socket_setOption(env, fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) < 0) { // Something went wrong so close the fd and return here. setOption(...) itself throws the exception already. close(fd); return -1; } } return fd; } int netty_unix_socket_initSockaddr(JNIEnv* env, jbyteArray address, jint scopeId, jint jport, const struct sockaddr_storage* addr) { uint16_t port = htons((uint16_t) jport); // Use GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical to signal the VM that we really would like // to not do a memory copy here. This is ok as we not do any blocking action here anyway. // This is important as the VM may suspend GC for the time! jbyte* addressBytes = (*env)->GetPrimitiveArrayCritical(env, address, 0); if (addressBytes == NULL) { // No memory left ?!?!? netty_unix_errors_throwOutOfMemoryError(env); return -1; } if (socketType == AF_INET6) { struct sockaddr_in6* ip6addr = (struct sockaddr_in6*) addr; ip6addr->sin6_family = AF_INET6; ip6addr->sin6_port = port; if (scopeId != 0) { ip6addr->sin6_scope_id = (uint32_t) scopeId; } // check if this is an any address and if so we need to handle it like this. if (memcmp(addressBytes, wildcardAddress, 16) == 0 || memcmp(addressBytes, ipv4MappedWildcardAddress, 16) == 0) { ip6addr->sin6_addr = in6addr_any; } else { memcpy(&(ip6addr->sin6_addr.s6_addr), addressBytes, 16); } } else { struct sockaddr_in* ipaddr = (struct sockaddr_in*) addr; ipaddr->sin_family = AF_INET; ipaddr->sin_port = port; memcpy(&(ipaddr->sin_addr.s_addr), addressBytes + 12, 4); } (*env)->ReleasePrimitiveArrayCritical(env, address, addressBytes, JNI_ABORT); return 0; } static jint _sendTo(JNIEnv* env, jint fd, void* buffer, jint pos, jint limit, jbyteArray address, jint scopeId, jint port) { struct sockaddr_storage addr; if (netty_unix_socket_initSockaddr(env, address, scopeId, port, &addr) == -1) { return -1; } ssize_t res; int err; do { res = sendto(fd, buffer + pos, (size_t) (limit - pos), 0, (struct sockaddr*) &addr, sizeof(struct sockaddr_storage)); // keep on writing if it was interrupted } while (res == -1 && ((err = errno) == EINTR)); if (res < 0) { return -err; } return (jint) res; } static jobject _recvFrom(JNIEnv* env, jint fd, void* buffer, jint pos, jint limit) { struct sockaddr_storage addr; socklen_t addrlen = sizeof(addr); ssize_t res; int err; do { res = recvfrom(fd, buffer + pos, (size_t) (limit - pos), 0, (struct sockaddr*) &addr, &addrlen); // Keep on reading if we was interrupted } while (res == -1 && ((err = errno) == EINTR)); if (res < 0) { if (err == EAGAIN || err == EWOULDBLOCK) { // Nothing left to read return NULL; } if (err == EBADF) { netty_unix_errors_throwClosedChannelException(env); return NULL; } netty_unix_errors_throwIOExceptionErrorNo(env, "recvfrom() failed: ", err); return NULL; } return createDatagramSocketAddress(env, &addr, res); } int netty_unix_socket_getOption(JNIEnv* env, jint fd, int level, int optname, void* optval, socklen_t optlen) { int rc = getsockopt(fd, level, optname, optval, &optlen); if (rc < 0) { int err = errno; if (err == EBADF) { netty_unix_errors_throwClosedChannelException(env); } else { netty_unix_errors_throwChannelExceptionErrorNo(env, "getsockopt() failed: ", err); } } return rc; } int netty_unix_socket_setOption(JNIEnv* env, jint fd, int level, int optname, const void* optval, socklen_t len) { int rc = setsockopt(fd, level, optname, optval, len); if (rc < 0) { int err = errno; if (err == EBADF) { netty_unix_errors_throwClosedChannelException(env); } else { netty_unix_errors_throwChannelExceptionErrorNo(env, "setsockopt() failed: ", err); } } return rc; } // JNI Registered Methods Begin static jint netty_unix_socket_shutdown(JNIEnv* env, jclass clazz, jint fd, jboolean read, jboolean write) { int mode; if (read && write) { mode = SHUT_RDWR; } else if (read) { mode = SHUT_RD; } else if (write) { mode = SHUT_WR; } else { return -EINVAL; } if (shutdown(fd, mode) < 0) { return -errno; } return 0; } static jint netty_unix_socket_bind(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port) { struct sockaddr_storage addr; if (netty_unix_socket_initSockaddr(env, address, scopeId, port, &addr) == -1) { return -1; } if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) { return -errno; } return 0; } static jint netty_unix_socket_listen(JNIEnv* env, jclass clazz, jint fd, jint backlog) { if (listen(fd, backlog) == -1) { return -errno; } return 0; } static jint netty_unix_socket_connect(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port) { struct sockaddr_storage addr; if (netty_unix_socket_initSockaddr(env, address, scopeId, port, &addr) == -1) { // A runtime exception was thrown return -1; } int res; int err; do { res = connect(fd, (struct sockaddr*) &addr, sizeof(addr)); } while (res == -1 && ((err = errno) == EINTR)); if (res < 0) { return -err; } return 0; } static jint netty_unix_socket_finishConnect(JNIEnv* env, jclass clazz, jint fd) { // connect may be done // return true if connection finished successfully // return false if connection is still in progress // throw exception if connection failed int optval; int res = netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_ERROR, &optval, sizeof(optval)); if (res != 0) { // getOption failed return -1; } if (optval == 0) { // connect succeeded return 0; } return -optval; } static jint netty_unix_socket_accept(JNIEnv* env, jclass clazz, jint fd, jbyteArray acceptedAddress) { jint socketFd; int err; struct sockaddr_storage addr; socklen_t address_len = sizeof(addr); do { if (accept4) { socketFd = accept4(fd, (struct sockaddr*) &addr, &address_len, SOCK_NONBLOCK | SOCK_CLOEXEC); } else { socketFd = accept(fd, (struct sockaddr*) &addr, &address_len); } } while (socketFd == -1 && ((err = errno) == EINTR)); if (socketFd == -1) { return -err; } int len = addressLength(&addr); // Fill in remote address details (*env)->SetByteArrayRegion(env, acceptedAddress, 0, 4, (jbyte*) &len); initInetSocketAddressArray(env, &addr, acceptedAddress, 1, len); if (accept4) { return socketFd; } else { // accept4 was not present so need two more sys-calls ... if (fcntl(socketFd, F_SETFD, FD_CLOEXEC) == -1 || fcntl(socketFd, F_SETFL, O_NONBLOCK) == -1) { return -errno; } } return socketFd; } static jbyteArray netty_unix_socket_remoteAddress(JNIEnv* env, jclass clazz, jint fd) { struct sockaddr_storage addr; socklen_t len = sizeof(addr); if (getpeername(fd, (struct sockaddr*) &addr, &len) == -1) { return NULL; } return createInetSocketAddressArray(env, &addr); } static jbyteArray netty_unix_socket_localAddress(JNIEnv* env, jclass clazz, jint fd) { struct sockaddr_storage addr; socklen_t len = sizeof(addr); if (getsockname(fd, (struct sockaddr*) &addr, &len) == -1) { return NULL; } return createInetSocketAddressArray(env, &addr); } static jint netty_unix_socket_newSocketDgramFd(JNIEnv* env, jclass clazz) { return _socket(env, clazz, SOCK_DGRAM); } static jint netty_unix_socket_newSocketStreamFd(JNIEnv* env, jclass clazz) { return _socket(env, clazz, SOCK_STREAM); } static jint netty_unix_socket_newSocketDomainFd(JNIEnv* env, jclass clazz) { int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); if (fd == -1) { return -errno; } return fd; } static jint netty_unix_socket_sendTo(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit, jbyteArray address, jint scopeId, jint port) { // We check that GetDirectBufferAddress will not return NULL in OnLoad return _sendTo(env, fd, (*env)->GetDirectBufferAddress(env, jbuffer), pos, limit, address, scopeId, port); } static jint netty_unix_socket_sendToAddress(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint pos, jint limit, jbyteArray address, jint scopeId, jint port) { return _sendTo(env, fd, (void *) (intptr_t) memoryAddress, pos, limit, address, scopeId, port); } static jint netty_unix_socket_sendToAddresses(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint length, jbyteArray address, jint scopeId, jint port) { struct sockaddr_storage addr; if (netty_unix_socket_initSockaddr(env, address, scopeId, port, &addr) == -1) { return -1; } struct msghdr m; m.msg_name = (void*) &addr; m.msg_namelen = (socklen_t) sizeof(struct sockaddr_storage); m.msg_iov = (struct iovec*) (intptr_t) memoryAddress; m.msg_iovlen = length; ssize_t res; int err; do { res = sendmsg(fd, &m, 0); // keep on writing if it was interrupted } while (res == -1 && ((err = errno) == EINTR)); if (res < 0) { return -err; } return (jint) res; } static jobject netty_unix_socket_recvFrom(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit) { // We check that GetDirectBufferAddress will not return NULL in OnLoad return _recvFrom(env, fd, (*env)->GetDirectBufferAddress(env, jbuffer), pos, limit); } static jobject netty_unix_socket_recvFromAddress(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit) { return _recvFrom(env, fd, (void *) (intptr_t) address, pos, limit); } static jint netty_unix_socket_bindDomainSocket(JNIEnv* env, jclass clazz, jint fd, jbyteArray socketPath) { struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; jbyte* socket_path = (*env)->GetByteArrayElements(env, socketPath, 0); jint socket_path_len = (*env)->GetArrayLength(env, socketPath); if (socket_path_len > sizeof(addr.sun_path)) { socket_path_len = sizeof(addr.sun_path); } memcpy(addr.sun_path, socket_path, socket_path_len); if (unlink(socket_path) == -1 && errno != ENOENT) { return -errno; } int res = bind(fd, (struct sockaddr*) &addr, _UNIX_ADDR_LENGTH(socket_path_len)); (*env)->ReleaseByteArrayElements(env, socketPath, socket_path, 0); if (res == -1) { return -errno; } return res; } static jint netty_unix_socket_connectDomainSocket(JNIEnv* env, jclass clazz, jint fd, jbyteArray socketPath) { struct sockaddr_un addr; jint socket_path_len; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; jbyte* socket_path = (*env)->GetByteArrayElements(env, socketPath, 0); socket_path_len = (*env)->GetArrayLength(env, socketPath); if (socket_path_len > sizeof(addr.sun_path)) { socket_path_len = sizeof(addr.sun_path); } memcpy(addr.sun_path, socket_path, socket_path_len); int res; int err; do { res = connect(fd, (struct sockaddr*) &addr, _UNIX_ADDR_LENGTH(socket_path_len)); } while (res == -1 && ((err = errno) == EINTR)); (*env)->ReleaseByteArrayElements(env, socketPath, socket_path, 0); if (res < 0) { return -err; } return 0; } static void netty_unix_socket_setTcpNoDelay(JNIEnv* env, jclass clazz, jint fd, jint optval) { netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)); } static void netty_unix_socket_setReceiveBufferSize(JNIEnv* env, jclass clazz, jint fd, jint optval) { netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval)); } static void netty_unix_socket_setSendBufferSize(JNIEnv* env, jclass clazz, jint fd, jint optval) { netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)); } static void netty_unix_socket_setKeepAlive(JNIEnv* env, jclass clazz, jint fd, jint optval) { netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)); } static void netty_unix_socket_setTcpCork(JNIEnv* env, jclass clazz, jint fd, jint optval) { netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval)); } static void netty_unix_socket_setSoLinger(JNIEnv* env, jclass clazz, jint fd, jint optval) { struct linger solinger; if (optval < 0) { solinger.l_onoff = 0; solinger.l_linger = 0; } else { solinger.l_onoff = 1; solinger.l_linger = optval; } netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_LINGER, &solinger, sizeof(solinger)); } static void netty_unix_socket_setTcpDeferAccept(JNIEnv* env, jclass clazz, jint fd, jint optval) { netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &optval, sizeof(optval)); } static void netty_unix_socket_setTcpQuickAck(JNIEnv* env, jclass clazz, jint fd, jint optval) { netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_QUICKACK, &optval, sizeof(optval)); } static jint netty_unix_socket_isKeepAlive(JNIEnv* env, jclass clazz, jint fd) { int optval; if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) { return -1; } return optval; } static jint netty_unix_socket_isTcpNoDelay(JNIEnv* env, jclass clazz, jint fd) { int optval; if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)) == -1) { return -1; } return optval; } static jint netty_unix_socket_getReceiveBufferSize(JNIEnv* env, jclass clazz, jint fd) { int optval; if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval)) == -1) { return -1; } return optval; } static jint netty_unix_socket_getSendBufferSize(JNIEnv* env, jclass clazz, jint fd) { int optval; if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) == -1) { return -1; } return optval; } static jint netty_unix_socket_isTcpCork(JNIEnv* env, jclass clazz, jint fd) { int optval; if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval)) == -1) { return -1; } return optval; } static jint netty_unix_socket_getSoLinger(JNIEnv* env, jclass clazz, jint fd) { struct linger optval; if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_LINGER, &optval, sizeof(optval)) == -1) { return -1; } if (optval.l_onoff == 0) { return -1; } else { return optval.l_linger; } } static jint netty_unix_socket_getSoError(JNIEnv* env, jclass clazz, jint fd) { int optval; if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_ERROR, &optval, sizeof(optval)) == -1) { return -1; } return optval; } static jint netty_unix_socket_getTcpDeferAccept(JNIEnv* env, jclass clazz, jint fd) { int optval; if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &optval, sizeof(optval)) == -1) { return -1; } return optval; } static jint netty_unix_socket_isTcpQuickAck(JNIEnv* env, jclass clazz, jint fd) { int optval; if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_QUICKACK, &optval, sizeof(optval)) == -1) { return -1; } return optval; } // JNI Registered Methods End // JNI Method Registration Table Begin static const JNINativeMethod fixed_method_table[] = { { "shutdown", "(IZZ)I", (void *) netty_unix_socket_shutdown }, { "bind", "(I[BII)I", (void *) netty_unix_socket_bind }, { "listen", "(II)I", (void *) netty_unix_socket_listen }, { "connect", "(I[BII)I", (void *) netty_unix_socket_connect }, { "finishConnect", "(I)I", (void *) netty_unix_socket_finishConnect }, { "accept", "(I[B)I", (void *) netty_unix_socket_accept }, { "remoteAddress", "(I)[B", (void *) netty_unix_socket_remoteAddress }, { "localAddress", "(I)[B", (void *) netty_unix_socket_localAddress }, { "newSocketDgramFd", "()I", (void *) netty_unix_socket_newSocketDgramFd }, { "newSocketStreamFd", "()I", (void *) netty_unix_socket_newSocketStreamFd }, { "newSocketDomainFd", "()I", (void *) netty_unix_socket_newSocketDomainFd }, { "sendTo", "(ILjava/nio/ByteBuffer;II[BII)I", (void *) netty_unix_socket_sendTo }, { "sendToAddress", "(IJII[BII)I", (void *) netty_unix_socket_sendToAddress }, { "sendToAddresses", "(IJI[BII)I", (void *) netty_unix_socket_sendToAddresses }, // "recvFrom" has a dynamic signature // "recvFromAddress" has a dynamic signature { "bindDomainSocket", "(I[B)I", (void *) netty_unix_socket_bindDomainSocket }, { "connectDomainSocket", "(I[B)I", (void *) netty_unix_socket_connectDomainSocket }, { "setTcpNoDelay", "(II)V", (void *) netty_unix_socket_setTcpNoDelay }, { "setReceiveBufferSize", "(II)V", (void *) netty_unix_socket_setReceiveBufferSize }, { "setSendBufferSize", "(II)V", (void *) netty_unix_socket_setSendBufferSize }, { "setKeepAlive", "(II)V", (void *) netty_unix_socket_setKeepAlive }, { "setTcpCork", "(II)V", (void *) netty_unix_socket_setTcpCork }, { "setSoLinger", "(II)V", (void *) netty_unix_socket_setSoLinger }, { "setTcpDeferAccept", "(II)V", (void *) netty_unix_socket_setTcpDeferAccept }, { "setTcpQuickAck", "(II)V", (void *) netty_unix_socket_setTcpQuickAck }, { "isKeepAlive", "(I)I", (void *) netty_unix_socket_isKeepAlive }, { "isTcpNoDelay", "(I)I", (void *) netty_unix_socket_isTcpNoDelay }, { "getReceiveBufferSize", "(I)I", (void *) netty_unix_socket_getReceiveBufferSize }, { "getSendBufferSize", "(I)I", (void *) netty_unix_socket_getSendBufferSize }, { "isTcpCork", "(I)I", (void *) netty_unix_socket_isTcpCork }, { "getSoLinger", "(I)I", (void *) netty_unix_socket_getSoLinger }, { "getSoError", "(I)I", (void *) netty_unix_socket_getSoError }, { "getTcpDeferAccept", "(I)I", (void *) netty_unix_socket_getTcpDeferAccept }, { "isTcpQuickAck", "(I)I", (void *) netty_unix_socket_isTcpQuickAck } }; static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]); static jint dynamicMethodsTableSize() { return fixed_method_table_size + 2; } static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) { JNINativeMethod* dynamicMethods = malloc(sizeof(JNINativeMethod) * dynamicMethodsTableSize()); memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table)); char* dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress;"); JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size]; dynamicMethod->name = "recvFrom"; dynamicMethod->signature = netty_unix_util_prepend("(ILjava/nio/ByteBuffer;II)L", dynamicTypeName); dynamicMethod->fnPtr = (void *) netty_unix_socket_recvFrom; free(dynamicTypeName); ++dynamicMethod; dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress;"); dynamicMethod->name = "recvFromAddress"; dynamicMethod->signature = netty_unix_util_prepend("(IJII)L", dynamicTypeName); dynamicMethod->fnPtr = (void *) netty_unix_socket_recvFromAddress; free(dynamicTypeName); return dynamicMethods; } static void freeDynamicMethodsTable(JNINativeMethod* dynamicMethods) { jint fullMethodTableSize = dynamicMethodsTableSize(); jint i = fixed_method_table_size; for (; i < fullMethodTableSize; ++i) { free(dynamicMethods[i].signature); } free(dynamicMethods); } // JNI Method Registration Table End jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix); if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/unix/Socket", dynamicMethods, dynamicMethodsTableSize()) != 0) { freeDynamicMethodsTable(dynamicMethods); return JNI_ERR; } freeDynamicMethodsTable(dynamicMethods); dynamicMethods = NULL; char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress"); jclass localDatagramSocketAddressClass = (*env)->FindClass(env, nettyClassName); free(nettyClassName); nettyClassName = NULL; if (localDatagramSocketAddressClass == NULL) { // pending exception... return JNI_ERR; } datagramSocketAddressClass = (jclass) (*env)->NewGlobalRef(env, localDatagramSocketAddressClass); if (datagramSocketAddressClass == NULL) { // out-of-memory! netty_unix_errors_throwOutOfMemoryError(env); return JNI_ERR; } datagramSocketAddrMethodId = (*env)->GetMethodID(env, datagramSocketAddressClass, "<init>", "(Ljava/lang/String;II)V"); if (datagramSocketAddrMethodId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get method ID: DatagramSocketAddress.<init>(String, int, int)"); return JNI_ERR; } jclass localInetSocketAddressClass = (*env)->FindClass(env, "java/net/InetSocketAddress"); if (localInetSocketAddressClass == NULL) { // pending exception... return JNI_ERR; } inetSocketAddressClass = (jclass) (*env)->NewGlobalRef(env, localInetSocketAddressClass); if (inetSocketAddressClass == NULL) { // out-of-memory! netty_unix_errors_throwOutOfMemoryError(env); return JNI_ERR; } inetSocketAddrMethodId = (*env)->GetMethodID(env, inetSocketAddressClass, "<init>", "(Ljava/lang/String;I)V"); if (inetSocketAddrMethodId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get method ID: InetSocketAddress.<init>(String, int)"); return JNI_ERR; } nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/util/NetUtil"); jclass localNetUtilClass = (*env)->FindClass(env, nettyClassName); free(nettyClassName); nettyClassName = NULL; if (localNetUtilClass == NULL) { // pending exception... return JNI_ERR; } netUtilClass = (jclass) (*env)->NewGlobalRef(env, localNetUtilClass); if (netUtilClass == NULL) { // out-of-memory! netty_unix_errors_throwOutOfMemoryError(env); return JNI_ERR; } netUtilClassIpv4PreferredMethodId = (*env)->GetStaticMethodID(env, netUtilClass, "isIpV4StackPreferred", "()Z" ); if (netUtilClassIpv4PreferredMethodId == NULL) { // position method was not found.. something is wrong so bail out netty_unix_errors_throwRuntimeException(env, "failed to get method ID: NetUild.isIpV4StackPreferred()"); return JNI_ERR; } void* mem = malloc(1); if (mem == NULL) { netty_unix_errors_throwOutOfMemoryError(env); return JNI_ERR; } jobject directBuffer = (*env)->NewDirectByteBuffer(env, mem, 1); if (directBuffer == NULL) { free(mem); netty_unix_errors_throwOutOfMemoryError(env); return JNI_ERR; } if ((*env)->GetDirectBufferAddress(env, directBuffer) == NULL) { free(mem); netty_unix_errors_throwRuntimeException(env, "failed to get direct buffer address"); return JNI_ERR; } free(mem); socketType = socket_type(env); return JNI_VERSION_1_6; } void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env) { if (datagramSocketAddressClass != NULL) { (*env)->DeleteGlobalRef(env, datagramSocketAddressClass); datagramSocketAddressClass = NULL; } if (inetSocketAddressClass != NULL) { (*env)->DeleteGlobalRef(env, inetSocketAddressClass); inetSocketAddressClass = NULL; } if (netUtilClass != NULL) { (*env)->DeleteGlobalRef(env, netUtilClass); netUtilClass = NULL; } } Other Java examples (source code examples)Here is a short list of links related to this Java netty_unix_socket.c source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.