blob: 2bf8b83ce880e45f85d9adbf1b6518dea94da4d9 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 __linux__
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 isa_addrID; /* address in java.net.InetSocketAddress */
50static jfieldID isa_portID; /* port in java.net.InetSocketAddress */
51static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */
52static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */
53static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */
54static jclass isa_class; /* java.net.InetSocketAddress */
55static jmethodID isa_ctorID; /* .InetSocketAddress(InetAddress, int) */
56
57JNIEXPORT void JNICALL
58Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz)
59{
60 clazz = (*env)->FindClass(env, "java/net/InetSocketAddress");
61 isa_class = (*env)->NewGlobalRef(env, clazz);
62 isa_ctorID = (*env)->GetMethodID(env, clazz, "<init>",
63 "(Ljava/net/InetAddress;I)V");
64 isa_addrID = (*env)->GetFieldID(env, clazz, "addr",
65 "Ljava/net/InetAddress;");
66 isa_portID = (*env)->GetFieldID(env, clazz, "port", "I");
67
68 clazz = (*env)->FindClass(env, "sun/nio/ch/DatagramChannelImpl");
69 dci_senderID = (*env)->GetFieldID(env, clazz, "sender",
70 "Ljava/net/SocketAddress;");
71 dci_senderAddrID = (*env)->GetFieldID(env, clazz,
72 "cachedSenderInetAddress",
73 "Ljava/net/InetAddress;");
74 dci_senderPortID = (*env)->GetFieldID(env, clazz,
75 "cachedSenderPort", "I");
76}
77
78JNIEXPORT void JNICALL
79Java_sun_nio_ch_DatagramChannelImpl_disconnect0(JNIEnv *env, jobject this,
80 jobject fdo)
81{
82 jint fd = fdval(env, fdo);
83 int rv;
84
85#ifdef __solaris__
86 rv = connect(fd, 0, 0);
87#endif
88
89#ifdef __linux__
90 {
91 int len;
92 SOCKADDR sa;
93
94 memset(&sa, 0, sizeof(sa));
95
96#ifdef AF_INET6
97 if (ipv6_available()) {
98 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&sa;
99 him6->sin6_family = AF_UNSPEC;
100 len = sizeof(struct sockaddr_in6);
101 } else
102#endif
103 {
104 struct sockaddr_in *him4 = (struct sockaddr_in*)&sa;
105 him4->sin_family = AF_UNSPEC;
106 len = sizeof(struct sockaddr_in);
107 }
108
109 rv = connect(fd, (struct sockaddr *)&sa, len);
110 }
111#endif
112
113 if (rv < 0)
114 handleSocketError(env, errno);
115
116}
117
118JNIEXPORT jint JNICALL
119Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
120 jobject fdo, jlong address,
121 jint len, jboolean connected)
122{
123 jint fd = fdval(env, fdo);
124 void *buf = (void *)jlong_to_ptr(address);
125 SOCKADDR sa;
126 int sa_len = SOCKADDR_LEN;
127 jboolean retry = JNI_FALSE;
128 jint n = 0;
129 jobject senderAddr;
130
131 if (len > MAX_PACKET_LEN) {
132 len = MAX_PACKET_LEN;
133 }
134
135 do {
136 retry = JNI_FALSE;
137 n = recvfrom(fd, buf, len, 0, (struct sockaddr *)&sa, &sa_len);
138 if (n < 0) {
139 if (errno == EWOULDBLOCK) {
140 return IOS_UNAVAILABLE;
141 }
142 if (errno == EINTR) {
143 return IOS_INTERRUPTED;
144 }
145 if (errno == ECONNREFUSED) {
146 if (connected == JNI_FALSE) {
147 retry = JNI_TRUE;
148 } else {
149 JNU_ThrowByName(env, JNU_JAVANETPKG
150 "PortUnreachableException", 0);
151 return IOS_THROWN;
152 }
153 } else {
154 return handleSocketError(env, errno);
155 }
156 }
157 } while (retry == JNI_TRUE);
158
159 /*
160 * If the source address and port match the cached address
161 * and port in DatagramChannelImpl then we don't need to
162 * create InetAddress and InetSocketAddress objects.
163 */
164 senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID);
165 if (senderAddr != NULL) {
166 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa,
167 senderAddr)) {
168 senderAddr = NULL;
169 } else {
170 jint port = (*env)->GetIntField(env, this, dci_senderPortID);
171 if (port != NET_GetPortFromSockaddr((struct sockaddr *)&sa)) {
172 senderAddr = NULL;
173 }
174 }
175 }
176 if (senderAddr == NULL) {
177 jobject isa = NULL;
178 int port;
179 jobject ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa,
180 &port);
181
182 if (ia != NULL) {
183 isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
184 }
185
186 if (isa == NULL) {
187 JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
188 return IOS_THROWN;
189 }
190
191 (*env)->SetObjectField(env, this, dci_senderAddrID, ia);
192 (*env)->SetIntField(env, this, dci_senderPortID,
193 NET_GetPortFromSockaddr((struct sockaddr *)&sa));
194 (*env)->SetObjectField(env, this, dci_senderID, isa);
195 }
196 return n;
197}
198
199JNIEXPORT jint JNICALL
200Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this,
201 jobject fdo, jlong address,
202 jint len, jobject dest)
203{
204 jint fd = fdval(env, fdo);
205 void *buf = (void *)jlong_to_ptr(address);
206 SOCKADDR sa;
207 int sa_len = SOCKADDR_LEN;
208 jint n = 0;
209 jobject destAddress = (*env)->GetObjectField(env, dest, isa_addrID);
210 jint destPort = (*env)->GetIntField(env, dest, isa_portID);
211
212 if (len > MAX_PACKET_LEN) {
213 len = MAX_PACKET_LEN;
214 }
215
216 if (NET_InetAddressToSockaddr(env, destAddress, destPort,
217 (struct sockaddr *)&sa,
218 &sa_len, JNI_TRUE) != 0) {
219 return IOS_THROWN;
220 }
221
222 n = sendto(fd, buf, len, 0, (struct sockaddr *)&sa, sa_len);
223 if (n < 0) {
224 if (errno == EAGAIN) {
225 return IOS_UNAVAILABLE;
226 }
227 if (errno == EINTR) {
228 return IOS_INTERRUPTED;
229 }
230 if (errno == ECONNREFUSED) {
231 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0);
232 return IOS_THROWN;
233 }
234 return handleSocketError(env, errno);
235 }
236 return n;
237}