src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c
changeset 47216 71c04702a3d5
parent 43889 212e765112d4
child 50275 69204b98dc3d
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #include "jni.h"
       
    27 #include "jni_util.h"
       
    28 #include "jvm.h"
       
    29 #include "jlong.h"
       
    30 
       
    31 #include <netdb.h>
       
    32 #include <sys/types.h>
       
    33 #include <sys/socket.h>
       
    34 #include <stdlib.h>
       
    35 #include <string.h>
       
    36 #include <errno.h>
       
    37 
       
    38 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
       
    39 #include <netinet/in.h>
       
    40 #endif
       
    41 
       
    42 #include "net_util.h"
       
    43 #include "net_util_md.h"
       
    44 #include "nio.h"
       
    45 #include "nio_util.h"
       
    46 
       
    47 #include "sun_nio_ch_DatagramChannelImpl.h"
       
    48 
       
    49 static jfieldID dci_senderID;   /* sender in sun.nio.ch.DatagramChannelImpl */
       
    50 static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */
       
    51 static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */
       
    52 static jclass isa_class;        /* java.net.InetSocketAddress */
       
    53 static jmethodID isa_ctorID;    /*   .InetSocketAddress(InetAddress, int) */
       
    54 
       
    55 JNIEXPORT void JNICALL
       
    56 Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz)
       
    57 {
       
    58     clazz = (*env)->FindClass(env, "java/net/InetSocketAddress");
       
    59     CHECK_NULL(clazz);
       
    60     isa_class = (*env)->NewGlobalRef(env, clazz);
       
    61     if (isa_class == NULL) {
       
    62         JNU_ThrowOutOfMemoryError(env, NULL);
       
    63         return;
       
    64     }
       
    65     isa_ctorID = (*env)->GetMethodID(env, clazz, "<init>",
       
    66                                      "(Ljava/net/InetAddress;I)V");
       
    67     CHECK_NULL(isa_ctorID);
       
    68 
       
    69     clazz = (*env)->FindClass(env, "sun/nio/ch/DatagramChannelImpl");
       
    70     CHECK_NULL(clazz);
       
    71     dci_senderID = (*env)->GetFieldID(env, clazz, "sender",
       
    72                                       "Ljava/net/SocketAddress;");
       
    73     CHECK_NULL(dci_senderID);
       
    74     dci_senderAddrID = (*env)->GetFieldID(env, clazz,
       
    75                                           "cachedSenderInetAddress",
       
    76                                           "Ljava/net/InetAddress;");
       
    77     CHECK_NULL(dci_senderAddrID);
       
    78     dci_senderPortID = (*env)->GetFieldID(env, clazz,
       
    79                                           "cachedSenderPort", "I");
       
    80     CHECK_NULL(dci_senderPortID);
       
    81 }
       
    82 
       
    83 JNIEXPORT void JNICALL
       
    84 Java_sun_nio_ch_DatagramChannelImpl_disconnect0(JNIEnv *env, jobject this,
       
    85                                                 jobject fdo, jboolean isIPv6)
       
    86 {
       
    87     jint fd = fdval(env, fdo);
       
    88     int rv;
       
    89 
       
    90 #if defined(__solaris__)
       
    91     rv = connect(fd, 0, 0);
       
    92 #else
       
    93     SOCKETADDRESS sa;
       
    94     socklen_t len = isIPv6 ? sizeof(struct sockaddr_in6) :
       
    95                              sizeof(struct sockaddr_in);
       
    96 
       
    97     memset(&sa, 0, sizeof(sa));
       
    98 #if defined(_ALLBSD_SOURCE)
       
    99     sa.sa.sa_family = isIPv6 ? AF_INET6 : AF_INET;
       
   100 #else
       
   101     sa.sa.sa_family = AF_UNSPEC;
       
   102 #endif
       
   103 
       
   104     rv = connect(fd, &sa.sa, len);
       
   105 
       
   106 #if defined(_ALLBSD_SOURCE)
       
   107     if (rv < 0 && errno == EADDRNOTAVAIL)
       
   108         rv = errno = 0;
       
   109 #elif defined(_AIX)
       
   110     /* See W. Richard Stevens, "UNIX Network Programming, Volume 1", p. 254:
       
   111      * 'Setting the address family to AF_UNSPEC might return EAFNOSUPPORT
       
   112      * but that is acceptable.
       
   113      */
       
   114     if (rv < 0 && errno == EAFNOSUPPORT)
       
   115         rv = errno = 0;
       
   116 #endif // defined(_ALLBSD_SOURCE) || defined(_AIX)
       
   117 
       
   118 #endif // defined(__solaris__)
       
   119 
       
   120     if (rv < 0)
       
   121         handleSocketError(env, errno);
       
   122 }
       
   123 
       
   124 JNIEXPORT jint JNICALL
       
   125 Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
       
   126                                              jobject fdo, jlong address,
       
   127                                              jint len, jboolean connected)
       
   128 {
       
   129     jint fd = fdval(env, fdo);
       
   130     void *buf = (void *)jlong_to_ptr(address);
       
   131     SOCKETADDRESS sa;
       
   132     socklen_t sa_len = sizeof(SOCKETADDRESS);
       
   133     jboolean retry = JNI_FALSE;
       
   134     jint n = 0;
       
   135     jobject senderAddr;
       
   136 
       
   137     if (len > MAX_PACKET_LEN) {
       
   138         len = MAX_PACKET_LEN;
       
   139     }
       
   140 
       
   141     do {
       
   142         retry = JNI_FALSE;
       
   143         n = recvfrom(fd, buf, len, 0, &sa.sa, &sa_len);
       
   144         if (n < 0) {
       
   145             if (errno == EWOULDBLOCK) {
       
   146                 return IOS_UNAVAILABLE;
       
   147             }
       
   148             if (errno == EINTR) {
       
   149                 return IOS_INTERRUPTED;
       
   150             }
       
   151             if (errno == ECONNREFUSED) {
       
   152                 if (connected == JNI_FALSE) {
       
   153                     retry = JNI_TRUE;
       
   154                 } else {
       
   155                     JNU_ThrowByName(env, JNU_JAVANETPKG
       
   156                                     "PortUnreachableException", 0);
       
   157                     return IOS_THROWN;
       
   158                 }
       
   159             } else {
       
   160                 return handleSocketError(env, errno);
       
   161             }
       
   162         }
       
   163     } while (retry == JNI_TRUE);
       
   164 
       
   165     /*
       
   166      * If the source address and port match the cached address
       
   167      * and port in DatagramChannelImpl then we don't need to
       
   168      * create InetAddress and InetSocketAddress objects.
       
   169      */
       
   170     senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID);
       
   171     if (senderAddr != NULL) {
       
   172         if (!NET_SockaddrEqualsInetAddress(env, &sa, senderAddr)) {
       
   173             senderAddr = NULL;
       
   174         } else {
       
   175             jint port = (*env)->GetIntField(env, this, dci_senderPortID);
       
   176             if (port != NET_GetPortFromSockaddr(&sa)) {
       
   177                 senderAddr = NULL;
       
   178             }
       
   179         }
       
   180     }
       
   181     if (senderAddr == NULL) {
       
   182         jobject isa = NULL;
       
   183         int port = 0;
       
   184         jobject ia = NET_SockaddrToInetAddress(env, &sa, &port);
       
   185         if (ia != NULL) {
       
   186             isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
       
   187         }
       
   188         CHECK_NULL_RETURN(isa, IOS_THROWN);
       
   189 
       
   190         (*env)->SetObjectField(env, this, dci_senderAddrID, ia);
       
   191         (*env)->SetIntField(env, this, dci_senderPortID,
       
   192                             NET_GetPortFromSockaddr(&sa));
       
   193         (*env)->SetObjectField(env, this, dci_senderID, isa);
       
   194     }
       
   195     return n;
       
   196 }
       
   197 
       
   198 JNIEXPORT jint JNICALL
       
   199 Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this,
       
   200                                           jboolean preferIPv6, jobject fdo, jlong address,
       
   201                                           jint len, jobject destAddress, jint destPort)
       
   202 {
       
   203     jint fd = fdval(env, fdo);
       
   204     void *buf = (void *)jlong_to_ptr(address);
       
   205     SOCKETADDRESS sa;
       
   206     int sa_len = 0;
       
   207     jint n = 0;
       
   208 
       
   209     if (len > MAX_PACKET_LEN) {
       
   210         len = MAX_PACKET_LEN;
       
   211     }
       
   212 
       
   213     if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa,
       
   214                                   &sa_len, preferIPv6) != 0) {
       
   215       return IOS_THROWN;
       
   216     }
       
   217 
       
   218     n = sendto(fd, buf, len, 0, &sa.sa, sa_len);
       
   219     if (n < 0) {
       
   220         if (errno == EAGAIN) {
       
   221             return IOS_UNAVAILABLE;
       
   222         }
       
   223         if (errno == EINTR) {
       
   224             return IOS_INTERRUPTED;
       
   225         }
       
   226         if (errno == ECONNREFUSED) {
       
   227             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0);
       
   228             return IOS_THROWN;
       
   229         }
       
   230         return handleSocketError(env, errno);
       
   231     }
       
   232     return n;
       
   233 }