src/java.base/unix/native/libnio/ch/Net.c
branchunixdomainchannels
changeset 58801 119ac9128c1b
parent 58535 ccb7bf459cbd
child 58847 692de65ab293
--- a/src/java.base/unix/native/libnio/ch/Net.c	Fri Oct 25 14:50:16 2019 +0100
+++ b/src/java.base/unix/native/libnio/ch/Net.c	Fri Oct 25 15:56:35 2019 +0100
@@ -46,6 +46,182 @@
 #include <sys/utsname.h>
 #endif
 
+
+extern jclass udsa_class;
+extern jmethodID udsa_ctorID;
+extern jfieldID udsa_pathID;
+extern jfieldID udsa_isAbstractID;
+
+JNIEXPORT jobject JNICALL
+NET_SockaddrToUnixAddress(JNIEnv *env, SOCKETADDRESS *sa) {
+    jboolean isAbstract = 0;
+
+    if (sa->sa.sa_family == AF_UNIX) {
+        char *name = sa->saun.sun_path;
+
+#ifdef NOTDEF
+        /* check for abstract name */
+        if (name[0] == 0) {
+            isAbstract = 1;
+            name++; // skip the zero byte
+        } else
+            isAbstract = 0;
+#endif
+        jstring nstr = JNU_NewStringPlatform(env, name);
+        return (*env)->NewObject(env, udsa_class, udsa_ctorID, nstr);
+    }
+    return NULL;
+}
+
+JNIEXPORT jint JNICALL
+NET_UnixSocketAddressToSockaddr(JNIEnv *env, jobject uaddr, SOCKETADDRESS *sa, int *len)
+{
+    jstring path = (*env)->GetObjectField(env, uaddr, udsa_pathID);
+    //jboolean isAbstract = (*env)->GetBooleanField(env, uaddr, udsa_isAbstractID);
+    jboolean isCopy;
+    int ret;
+    const char* pname = JNU_GetStringPlatformChars(env, path, &isCopy);
+    memset(sa, 0, sizeof(SOCKETADDRESS));
+    sa->saun.sun_family = AF_UNIX;
+    int name_len = strlen(pname) + 1; /* includes null termination */
+    if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
+        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "unix domain path too long");
+        ret = 1;
+        goto finish;
+    }
+#ifdef NOTDEF
+    if (isAbstract) {
+        strncpy(&sa->saun.sun_path[1], pname, name_len);
+        sa->saun.sun_path[0] = 0;
+        name_len++;
+    } else
+#endif
+    {
+        strncpy(&sa->saun.sun_path[0], pname, name_len);
+    }
+    *len = offsetof(struct sockaddr_un, sun_path) + name_len;
+    ret = 0;
+  finish:
+    if (isCopy)
+        JNU_ReleaseStringPlatformChars(env, path, pname);
+    return ret;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_unixDomainSocket0(JNIEnv *env, jclass cl)
+{
+    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (fd < 0) {
+        return handleSocketError(env, errno);
+    }
+    return fd;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_unixDomainSocketSupported(JNIEnv *env, jclass cl)
+{
+    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (fd < 0) {
+        return JNI_FALSE;
+    }
+    close(fd);
+    return JNI_TRUE;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_unixDomainBind(JNIEnv *env, jclass clazz, jobject fdo, jobject uaddr)
+{
+    SOCKETADDRESS sa;
+    int sa_len = 0;
+    int rv = 0;
+
+    if (NET_UnixSocketAddressToSockaddr(env, uaddr, &sa, &sa_len) != 0)
+        return;
+
+    int fd = fdval(env, fdo);
+
+    rv = NET_Bind(fdval(env, fdo), &sa, sa_len);
+    if (rv != 0) {
+        handleSocketError(env, errno);
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_unixDomainConnect(JNIEnv *env, jclass clazz, jobject fdo, jobject usa)
+{
+    SOCKETADDRESS sa;
+    int sa_len = 0;
+    int rv;
+
+    if (NET_UnixSocketAddressToSockaddr(env, usa, &sa, &sa_len) != 0) {
+        return IOS_THROWN;
+    }
+
+    rv = connect(fdval(env, fdo), &sa.sa, sa_len);
+    if (rv != 0) {
+        if (errno == EINPROGRESS) {
+            return IOS_UNAVAILABLE;
+        } else if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        }
+        return handleSocketError(env, errno);
+    }
+    return 1;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_unixDomainAccept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
+                           jobjectArray usaa)
+{
+    jint fd = fdval(env, fdo);
+    jint newfd;
+    SOCKETADDRESS sa;
+    socklen_t sa_len = sizeof(SOCKETADDRESS);
+    jobject usa;
+
+    /* accept connection but ignore ECONNABORTED */
+    for (;;) {
+        newfd = accept(fd, &sa.sa, &sa_len);
+        if (newfd >= 0) {
+            break;
+        }
+        if (errno != ECONNABORTED) {
+            break;
+        }
+        /* ECONNABORTED => restart accept */
+    }
+
+    if (newfd < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK)
+            return IOS_UNAVAILABLE;
+        if (errno == EINTR)
+            return IOS_INTERRUPTED;
+        JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
+        return IOS_THROWN;
+    }
+
+    setfdval(env, newfdo, newfd);
+
+    usa = NET_SockaddrToUnixAddress(env, &sa);
+    CHECK_NULL_RETURN(usa, IOS_THROWN);
+
+    (*env)->SetObjectArrayElement(env, usaa, 0, usa);
+
+    return 1;
+}
+
+JNIEXPORT jobject JNICALL
+Java_sun_nio_ch_Net_localUnixAddress(JNIEnv *env, jclass clazz, jobject fdo)
+{
+    SOCKETADDRESS sa;
+    socklen_t sa_len = sizeof(SOCKETADDRESS);
+    int port;
+    if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
+        handleSocketError(env, errno);
+        return NULL;
+    }
+    return NET_SockaddrToUnixAddress(env, &sa);
+}
 /**
  * IP_MULTICAST_ALL supported since 2.6.31 but may not be available at
  * build time.
@@ -867,7 +1043,8 @@
 
 /* Declared in nio_util.h */
 
-jint handleSocketError(JNIEnv *env, jint errorValue)
+JNIEXPORT jint JNICALL
+handleSocketError(JNIEnv *env, jint errorValue)
 {
     char *xn;
     switch (errorValue) {