DatagramChannelImpl.c revision cd47759eda5173e761c6536350225e2793374d69
1/* 2 * Copyright (c) 2001, 2008, 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#include "JNIHelp.h" 50 51#define NATIVE_METHOD(className, functionName, signature) \ 52{ #functionName, signature, (void*)(Java_sun_nio_ch_ ## className ## _ ## functionName) } 53 54 55static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */ 56static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */ 57static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */ 58static jclass isa_class; /* java.net.InetSocketAddress */ 59static jmethodID isa_ctorID; /* .InetSocketAddress(InetAddress, int) */ 60 61JNIEXPORT void JNICALL 62Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz) 63{ 64 clazz = (*env)->FindClass(env, "java/net/InetSocketAddress"); 65 isa_class = (*env)->NewGlobalRef(env, clazz); 66 isa_ctorID = (*env)->GetMethodID(env, clazz, "<init>", 67 "(Ljava/net/InetAddress;I)V"); 68 69 clazz = (*env)->FindClass(env, "sun/nio/ch/DatagramChannelImpl"); 70 dci_senderID = (*env)->GetFieldID(env, clazz, "sender", 71 "Ljava/net/SocketAddress;"); 72 dci_senderAddrID = (*env)->GetFieldID(env, clazz, 73 "cachedSenderInetAddress", 74 "Ljava/net/InetAddress;"); 75 dci_senderPortID = (*env)->GetFieldID(env, clazz, 76 "cachedSenderPort", "I"); 77} 78 79JNIEXPORT void JNICALL 80Java_sun_nio_ch_DatagramChannelImpl_disconnect0(JNIEnv *env, jobject this, 81 jobject fdo, jboolean isIPv6) 82{ 83 jint fd = fdval(env, fdo); 84 int rv; 85 86#ifdef __solaris__ 87 rv = connect(fd, 0, 0); 88#endif 89 90#if defined(__linux__) || defined(_ALLBSD_SOURCE) 91 { 92 int len; 93 SOCKADDR sa; 94 95 memset(&sa, 0, sizeof(sa)); 96 97#ifdef AF_INET6 98 if (isIPv6) { 99 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&sa; 100#if defined(_ALLBSD_SOURCE) 101 him6->sin6_family = AF_INET6; 102#else 103 him6->sin6_family = AF_UNSPEC; 104#endif 105 len = sizeof(struct sockaddr_in6); 106 } else 107#endif 108 { 109 struct sockaddr_in *him4 = (struct sockaddr_in*)&sa; 110#if defined(_ALLBSD_SOURCE) 111 him4->sin_family = AF_INET; 112#else 113 him4->sin_family = AF_UNSPEC; 114#endif 115 len = sizeof(struct sockaddr_in); 116 } 117 118 rv = connect(fd, (struct sockaddr *)&sa, len); 119 120#if defined(_ALLBSD_SOURCE) 121 if (rv < 0 && errno == EADDRNOTAVAIL) 122 rv = errno = 0; 123#endif 124 } 125#endif 126 127 if (rv < 0) 128 handleSocketError(env, errno); 129 130} 131 132JNIEXPORT jint JNICALL 133Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, 134 jobject fdo, jlong address, 135 jint len, jboolean connected) 136{ 137 jint fd = fdval(env, fdo); 138 void *buf = (void *)jlong_to_ptr(address); 139 SOCKADDR sa; 140 socklen_t sa_len = SOCKADDR_LEN; 141 jboolean retry = JNI_FALSE; 142 jint n = 0; 143 jobject senderAddr; 144 145 if (len > MAX_PACKET_LEN) { 146 len = MAX_PACKET_LEN; 147 } 148 149 do { 150 retry = JNI_FALSE; 151 n = recvfrom(fd, buf, len, 0, (struct sockaddr *)&sa, &sa_len); 152 if (n < 0) { 153 if (errno == EWOULDBLOCK) { 154 return IOS_UNAVAILABLE; 155 } 156 if (errno == EINTR) { 157 return IOS_INTERRUPTED; 158 } 159 if (errno == ECONNREFUSED) { 160 if (connected == JNI_FALSE) { 161 retry = JNI_TRUE; 162 } else { 163 JNU_ThrowByName(env, JNU_JAVANETPKG 164 "PortUnreachableException", 0); 165 return IOS_THROWN; 166 } 167 } else { 168 return handleSocketError(env, errno); 169 } 170 } 171 } while (retry == JNI_TRUE); 172 173 /* 174 * If the source address and port match the cached address 175 * and port in DatagramChannelImpl then we don't need to 176 * create InetAddress and InetSocketAddress objects. 177 */ 178 senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID); 179 if (senderAddr != NULL) { 180 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa, 181 senderAddr)) { 182 senderAddr = NULL; 183 } else { 184 jint port = (*env)->GetIntField(env, this, dci_senderPortID); 185 if (port != NET_GetPortFromSockaddr((struct sockaddr *)&sa)) { 186 senderAddr = NULL; 187 } 188 } 189 } 190 if (senderAddr == NULL) { 191 jobject isa = NULL; 192 int port; 193 jobject ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, 194 &port); 195 196 if (ia != NULL) { 197 isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); 198 } 199 200 if (isa == NULL) { 201 JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); 202 return IOS_THROWN; 203 } 204 205 (*env)->SetObjectField(env, this, dci_senderAddrID, ia); 206 (*env)->SetIntField(env, this, dci_senderPortID, 207 NET_GetPortFromSockaddr((struct sockaddr *)&sa)); 208 (*env)->SetObjectField(env, this, dci_senderID, isa); 209 } 210 return n; 211} 212 213JNIEXPORT jint JNICALL 214Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, 215 jboolean preferIPv6, jobject fdo, jlong address, 216 jint len, jobject destAddress, jint destPort) 217{ 218 jint fd = fdval(env, fdo); 219 void *buf = (void *)jlong_to_ptr(address); 220 SOCKADDR sa; 221 int sa_len = SOCKADDR_LEN; 222 jint n = 0; 223 224 if (len > MAX_PACKET_LEN) { 225 len = MAX_PACKET_LEN; 226 } 227 228 if (NET_InetAddressToSockaddr(env, destAddress, destPort, 229 (struct sockaddr *)&sa, 230 &sa_len, preferIPv6) != 0) { 231 return IOS_THROWN; 232 } 233 234 n = sendto(fd, buf, len, 0, (struct sockaddr *)&sa, sa_len); 235 if (n < 0) { 236 if (errno == EAGAIN) { 237 return IOS_UNAVAILABLE; 238 } 239 if (errno == EINTR) { 240 return IOS_INTERRUPTED; 241 } 242 if (errno == ECONNREFUSED) { 243 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 0); 244 return IOS_THROWN; 245 } 246 return handleSocketError(env, errno); 247 } 248 return n; 249} 250 251static JNINativeMethod gMethods[] = { 252 NATIVE_METHOD(DatagramChannelImpl, initIDs, "()V"), 253 NATIVE_METHOD(DatagramChannelImpl, disconnect0, "(Ljava/io/FileDescriptor;Z)V"), 254 NATIVE_METHOD(DatagramChannelImpl, receive0, "(Ljava/io/FileDescriptor;JIZ)I"), 255 NATIVE_METHOD(DatagramChannelImpl, send0, "(ZLjava/io/FileDescriptor;JILjava/net/InetAddress;I)I"), 256}; 257 258void register_sun_nio_ch_DatagramChannelImpl(JNIEnv* env) { 259 jniRegisterNativeMethods(env, "sun/nio/ch/DatagramChannelImpl", gMethods, NELEM(gMethods)); 260} 261