static jobject makeInterfaceAddress(JNIEnv* env, jint interfaceIndex, ifaddrs* ifa) {
    jmethodID constructor = env->GetMethodID(JniConstants::interfaceAddressClass, "<init>",
            "(ILjava/lang/String;Ljava/net/InetAddress;Ljava/net/InetAddress;)V");
    if (constructor == NULL) {
        return NULL;
    }
    jobject javaName = env->NewStringUTF(ifa->ifa_name);
    if (javaName == NULL) {
        return NULL;
    }
    sockaddr_storage* addr = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr);
    jobject javaAddress = socketAddressToInetAddress(env, addr);
    if (javaAddress == NULL) {
        return NULL;
    }
    sockaddr_storage* mask = reinterpret_cast<sockaddr_storage*>(ifa->ifa_netmask);
    jobject javaMask = socketAddressToInetAddress(env, mask);
    if (javaMask == NULL) {
        return NULL;
    }
    return env->NewObject(JniConstants::interfaceAddressClass, constructor,
            interfaceIndex, javaName, javaAddress, javaMask);
}
Пример #2
0
static jobject OSNetworkSystem_getSocketLocalAddress(JNIEnv* env,
        jobject, jobject fileDescriptor) {
    NetFd fd(env, fileDescriptor);
    if (fd.isClosed()) {
        return NULL;
    }

    sockaddr_storage ss;
    socklen_t ssLen = sizeof(ss);
    memset(&ss, 0, ssLen);
    int rc = getsockname(fd.get(), reinterpret_cast<sockaddr*>(&ss), &ssLen);
    if (rc == -1) {
        // TODO: the public API doesn't allow failure, so this whole method
        // represents a broken design. In practice, though, getsockname can't
        // fail unless we give it invalid arguments.
        LOGE("getsockname failed: %s (errno=%i)", strerror(errno), errno);
        return NULL;
    }
    return socketAddressToInetAddress(env, &ss);
}
Пример #3
0
static void OSNetworkSystem_accept(JNIEnv* env, jobject, jobject serverFileDescriptor,
        jobject newSocket, jobject clientFileDescriptor) {

    if (newSocket == NULL) {
        jniThrowNullPointerException(env, NULL);
        return;
    }

    NetFd serverFd(env, serverFileDescriptor);
    if (serverFd.isClosed()) {
        return;
    }

    sockaddr_storage ss;
    socklen_t addrLen = sizeof(ss);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);

    int clientFd;
    {
        int intFd = serverFd.get();
        AsynchronousSocketCloseMonitor monitor(intFd);
        clientFd = NET_FAILURE_RETRY(serverFd, accept(intFd, sa, &addrLen));
    }
    if (env->ExceptionOccurred()) {
        return;
    }
    if (clientFd == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            jniThrowSocketTimeoutException(env, errno);
        } else {
            jniThrowSocketException(env, errno);
        }
        return;
    }

    // Reset the inherited read timeout to the Java-specified default of 0.
    timeval timeout(toTimeval(0));
    int rc = setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
    if (rc == -1) {
        LOGE("couldn't reset SO_RCVTIMEO on accepted socket fd %i: %s", clientFd, strerror(errno));
        jniThrowSocketException(env, errno);
    }

    /*
     * For network sockets, put the peer address and port in instance variables.
     * We don't bother to do this for UNIX domain sockets, since most peers are
     * anonymous anyway.
     */
    if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
        // Remote address and port.
        jobject remoteAddress = socketAddressToInetAddress(env, &ss);
        if (remoteAddress == NULL) {
            close(clientFd);
            return;
        }
        int remotePort = getSocketAddressPort(&ss);
        env->SetObjectField(newSocket, gCachedFields.socketimpl_address, remoteAddress);
        env->SetIntField(newSocket, gCachedFields.socketimpl_port, remotePort);

        // Local port.
        memset(&ss, 0, addrLen);
        int rc = getsockname(clientFd, sa, &addrLen);
        if (rc == -1) {
            close(clientFd);
            jniThrowSocketException(env, errno);
            return;
        }
        int localPort = getSocketAddressPort(&ss);
        env->SetIntField(newSocket, gCachedFields.socketimpl_localport, localPort);
    }

    jniSetFileDescriptorOfFD(env, clientFileDescriptor, clientFd);
}
Пример #4
0
static jobject OSNetworkSystem_getSocketOption(JNIEnv* env, jobject, jobject fileDescriptor, jint option) {
    NetFd fd(env, fileDescriptor);
    if (fd.isClosed()) {
        return NULL;
    }

    int family = getSocketAddressFamily(fd.get());
    if (family != AF_INET && family != AF_INET6) {
        jniThrowSocketException(env, EAFNOSUPPORT);
        return NULL;
    }

    switch (option) {
    case JAVASOCKOPT_TCP_NODELAY:
        return getSocketOption_Boolean(env, fd, IPPROTO_TCP, TCP_NODELAY);
    case JAVASOCKOPT_SO_SNDBUF:
        return getSocketOption_Integer(env, fd, SOL_SOCKET, SO_SNDBUF);
    case JAVASOCKOPT_SO_RCVBUF:
        return getSocketOption_Integer(env, fd, SOL_SOCKET, SO_RCVBUF);
    case JAVASOCKOPT_SO_BROADCAST:
        return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_BROADCAST);
    case JAVASOCKOPT_SO_REUSEADDR:
        return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_REUSEADDR);
    case JAVASOCKOPT_SO_KEEPALIVE:
        return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_KEEPALIVE);
    case JAVASOCKOPT_SO_OOBINLINE:
        return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_OOBINLINE);
    case JAVASOCKOPT_IP_TOS:
        if (family == AF_INET) {
            return getSocketOption_Integer(env, fd, IPPROTO_IP, IP_TOS);
        } else {
            return getSocketOption_Integer(env, fd, IPPROTO_IPV6, IPV6_TCLASS);
        }
    case JAVASOCKOPT_SO_LINGER:
        {
            linger lingr;
            bool ok = getSocketOption(env, fd, SOL_SOCKET, SO_LINGER, &lingr);
            if (!ok) {
                return NULL; // We already threw.
            } else if (!lingr.l_onoff) {
                return booleanValueOf(env, false);
            } else {
                return integerValueOf(env, lingr.l_linger);
            }
        }
    case JAVASOCKOPT_SO_TIMEOUT:
        {
            timeval timeout;
            bool ok = getSocketOption(env, fd, SOL_SOCKET, SO_RCVTIMEO, &timeout);
            return ok ? integerValueOf(env, toMs(timeout)) : NULL;
        }
#ifdef ENABLE_MULTICAST
    case JAVASOCKOPT_IP_MULTICAST_IF:
        {
            // Although setsockopt(2) can take an ip_mreqn for IP_MULTICAST_IF, getsockopt(2)
            // always returns an in_addr.
            sockaddr_storage ss;
            memset(&ss, 0, sizeof(ss));
            ss.ss_family = AF_INET; // This call is IPv4-only.
            sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ss);
            if (!getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_IF, &sa->sin_addr)) {
                return NULL;
            }
            return socketAddressToInetAddress(env, &ss);
        }
    case JAVASOCKOPT_IP_MULTICAST_IF2:
        if (family == AF_INET) {
            // The caller's asking for an interface index, but that's not how IPv4 works.
            // Our Java should never get here, because we'll try IP_MULTICAST_IF first and
            // that will satisfy us.
            jniThrowSocketException(env, EAFNOSUPPORT);
        } else {
            return getSocketOption_Integer(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_IF);
        }
    case JAVASOCKOPT_IP_MULTICAST_LOOP:
        if (family == AF_INET) {
            // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
            u_char loopback;
            bool ok = getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loopback);
            return ok ? booleanValueOf(env, loopback) : NULL;
        } else {
            return getSocketOption_Boolean(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
        }
    case JAVASOCKOPT_MULTICAST_TTL:
        if (family == AF_INET) {
            // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
            // IPv4 multicast TTL uses a byte.
            u_char ttl;
            bool ok = getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl);
            return ok ? integerValueOf(env, ttl) : NULL;
        } else {
            return getSocketOption_Integer(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
        }
#else
    case JAVASOCKOPT_MULTICAST_TTL:
    case JAVASOCKOPT_IP_MULTICAST_IF:
    case JAVASOCKOPT_IP_MULTICAST_IF2:
    case JAVASOCKOPT_IP_MULTICAST_LOOP:
        jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
        return NULL;
#endif // def ENABLE_MULTICAST
    default:
        jniThrowSocketException(env, ENOPROTOOPT);
        return NULL;
    }
}