DatagramChannelImpl.c revision 09f993b04651359387d5e089b076994bb6cccc5f
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