1/*
2 * Copyright (c) 2001, 2018, 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
49static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */
50static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */
51static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */
52static jclass isa_class; /* java.net.InetSocketAddress */
53static jmethodID isa_ctorID; /* .InetSocketAddress(InetAddress, int) */
54
55JNIEXPORT void JNICALL
56Java_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
83JNIEXPORT void JNICALL
84Java_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
124JNIEXPORT jint JNICALL
125Java_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 == EAGAIN || 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
198JNIEXPORT jint JNICALL
199Java_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 || errno == EWOULDBLOCK) {
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}
234