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 | |
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 == 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 | |
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 || 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 | |