1 /*
2  * Copyright (c) 2001, 2012, 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
Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv * env,jclass clazz)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
Java_sun_nio_ch_DatagramChannelImpl_disconnect0(JNIEnv * env,jobject this,jobject fdo,jboolean isIPv6)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 #ifdef __solaris__
91     rv = connect(fd, 0, 0);
92 #endif
93 
94 #if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
95     {
96         int len;
97         SOCKADDR sa;
98 
99         memset(&sa, 0, sizeof(sa));
100 
101 #ifdef AF_INET6
102         if (isIPv6) {
103             struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&sa;
104 #if defined(_ALLBSD_SOURCE)
105             him6->sin6_family = AF_INET6;
106 #else
107             him6->sin6_family = AF_UNSPEC;
108 #endif
109             len = sizeof(struct sockaddr_in6);
110         } else
111 #endif
112         {
113             struct sockaddr_in *him4 = (struct sockaddr_in*)&sa;
114 #if defined(_ALLBSD_SOURCE)
115             him4->sin_family = AF_INET;
116 #else
117             him4->sin_family = AF_UNSPEC;
118 #endif
119             len = sizeof(struct sockaddr_in);
120         }
121 
122         rv = connect(fd, (struct sockaddr *)&sa, len);
123 
124 #if defined(_ALLBSD_SOURCE)
125         if (rv < 0 && errno == EADDRNOTAVAIL)
126                 rv = errno = 0;
127 #endif
128 #if defined(_AIX)
129         /* See W. Richard Stevens, "UNIX Network Programming, Volume 1", p. 254:
130          * 'Setting the address family to AF_UNSPEC might return EAFNOSUPPORT
131          * but that is acceptable.
132          */
133         if (rv < 0 && errno == EAFNOSUPPORT)
134             rv = errno = 0;
135 #endif
136     }
137 #endif
138 
139     if (rv < 0)
140         handleSocketError(env, errno);
141 
142 }
143 
144 JNIEXPORT jint JNICALL
Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv * env,jobject this,jobject fdo,jlong address,jint len,jboolean connected)145 Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
146                                              jobject fdo, jlong address,
147                                              jint len, jboolean connected)
148 {
149     jint fd = fdval(env, fdo);
150     void *buf = (void *)jlong_to_ptr(address);
151     SOCKADDR sa;
152     socklen_t sa_len = SOCKADDR_LEN;
153     jboolean retry = JNI_FALSE;
154     jint n = 0;
155     jobject senderAddr;
156 
157     if (len > MAX_PACKET_LEN) {
158         len = MAX_PACKET_LEN;
159     }
160 
161     do {
162         retry = JNI_FALSE;
163         n = recvfrom(fd, buf, len, 0, (struct sockaddr *)&sa, &sa_len);
164         if (n < 0) {
165             if (errno == EWOULDBLOCK) {
166                 return IOS_UNAVAILABLE;
167             }
168             if (errno == EINTR) {
169                 return IOS_INTERRUPTED;
170             }
171             if (errno == ECONNREFUSED) {
172                 if (connected == JNI_FALSE) {
173                     retry = JNI_TRUE;
174                 } else {
175                     JNU_ThrowByName(env, JNU_JAVANETPKG
176                                     "PortUnreachableException", 0);
177                     return IOS_THROWN;
178                 }
179             } else {
180                 return handleSocketError(env, errno);
181             }
182         }
183     } while (retry == JNI_TRUE);
184 
185     /*
186      * If the source address and port match the cached address
187      * and port in DatagramChannelImpl then we don't need to
188      * create InetAddress and InetSocketAddress objects.
189      */
190     senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID);
191     if (senderAddr != NULL) {
192         if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa,
193                                            senderAddr)) {
194             senderAddr = NULL;
195         } else {
196             jint port = (*env)->GetIntField(env, this, dci_senderPortID);
197             if (port != NET_GetPortFromSockaddr((struct sockaddr *)&sa)) {
198                 senderAddr = NULL;
199             }
200         }
201     }
202     if (senderAddr == NULL) {
203         jobject isa = NULL;
204         int port = 0;
205         jobject ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
206         if (ia != NULL) {
207             isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
208         }
209         CHECK_NULL_RETURN(isa, IOS_THROWN);
210 
211         (*env)->SetObjectField(env, this, dci_senderAddrID, ia);
212         (*env)->SetIntField(env, this, dci_senderPortID,
213                             NET_GetPortFromSockaddr((struct sockaddr *)&sa));
214         (*env)->SetObjectField(env, this, dci_senderID, isa);
215     }
216     return n;
217 }
218 
219 JNIEXPORT jint JNICALL
Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv * env,jobject this,jboolean preferIPv6,jobject fdo,jlong address,jint len,jobject destAddress,jint destPort)220 Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this,
221                                           jboolean preferIPv6, jobject fdo, jlong address,
222                                           jint len, jobject destAddress, jint destPort)
223 {
224     jint fd = fdval(env, fdo);
225     void *buf = (void *)jlong_to_ptr(address);
226     SOCKADDR sa;
227     int sa_len = SOCKADDR_LEN;
228     jint n = 0;
229 
230     if (len > MAX_PACKET_LEN) {
231         len = MAX_PACKET_LEN;
232     }
233 
234     if (NET_InetAddressToSockaddr(env, destAddress, destPort,
235                                   (struct sockaddr *)&sa,
236                                   &sa_len, preferIPv6) != 0) {
237       return IOS_THROWN;
238     }
239 
240     n = sendto(fd, buf, len, 0, (struct sockaddr *)&sa, sa_len);
241     if (n < 0) {
242         if (errno == EAGAIN) {
243             return IOS_UNAVAILABLE;
244         }
245         if (errno == EINTR) {
246             return IOS_INTERRUPTED;
247         }
248         if (errno == ECONNREFUSED) {
249             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0);
250             return IOS_THROWN;
251         }
252         return handleSocketError(env, errno);
253     }
254     return n;
255 }
256