1/*
2 * Copyright (c) 2000, 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 <stdlib.h>
27#include <netdb.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30
31#if __linux__
32#include <netinet/in.h>
33#endif
34
35#if defined(__solaris__) && !defined(_SOCKLEN_T)
36typedef size_t socklen_t;       /* New in SunOS 5.7, so need this for 5.6 */
37#endif
38
39#include "jni.h"
40#include "jni_util.h"
41#include "net_util.h"
42#include "jvm.h"
43#include "jlong.h"
44#include "sun_nio_ch_ServerSocketChannelImpl.h"
45#include "nio.h"
46#include "nio_util.h"
47
48#include "JNIHelp.h"
49
50
51#define NATIVE_METHOD(className, functionName, signature) \
52{ #functionName, signature, (void*)(className ## _ ## functionName) }
53
54
55static jfieldID fd_fdID;        /* java.io.FileDescriptor.fd */
56static jclass isa_class;        /* java.net.InetSocketAddress */
57static jmethodID isa_ctorID;    /*   .InetSocketAddress(InetAddress, int) */
58
59
60JNIEXPORT void JNICALL
61Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv *env, jclass c)
62{
63    jclass cls;
64
65    cls = (*env)->FindClass(env, "java/io/FileDescriptor");
66    CHECK_NULL(cls);
67    fd_fdID = (*env)->GetFieldID(env, cls, "descriptor", "I");
68    CHECK_NULL(fd_fdID);
69
70    cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
71    CHECK_NULL(cls);
72    isa_class = (*env)->NewGlobalRef(env, cls);
73    if (isa_class == NULL) {
74        JNU_ThrowOutOfMemoryError(env, NULL);
75        return;
76    }
77    isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
78                                     "(Ljava/net/InetAddress;I)V");
79    CHECK_NULL(isa_ctorID);
80}
81
82JNIEXPORT jint JNICALL
83Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this,
84                                                jobject ssfdo, jobject newfdo,
85                                                jobjectArray isaa)
86{
87    jint ssfd = (*env)->GetIntField(env, ssfdo, fd_fdID);
88    jint newfd;
89    struct sockaddr *sa;
90    int alloc_len;
91    jobject remote_ia = 0;
92    jobject isa;
93    jint remote_port;
94
95    NET_AllocSockaddr(&sa, &alloc_len);
96    if (sa == NULL) {
97        JNU_ThrowOutOfMemoryError(env, NULL);
98        return IOS_THROWN;
99    }
100
101    /*
102     * accept connection but ignore ECONNABORTED indicating that
103     * a connection was eagerly accepted but was reset before
104     * accept() was called.
105     */
106    for (;;) {
107        socklen_t sa_len = alloc_len;
108        newfd = accept(ssfd, sa, &sa_len);
109        if (newfd >= 0) {
110            break;
111        }
112        if (errno != ECONNABORTED) {
113            break;
114        }
115        /* ECONNABORTED => restart accept */
116    }
117
118    if (newfd < 0) {
119        free((void *)sa);
120        if (errno == EAGAIN)
121            return IOS_UNAVAILABLE;
122        if (errno == EINTR)
123            return IOS_INTERRUPTED;
124        JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
125        return IOS_THROWN;
126    }
127
128    (*env)->SetIntField(env, newfdo, fd_fdID, newfd);
129    remote_ia = NET_SockaddrToInetAddress(env, sa, (int *)&remote_port);
130    free((void *)sa);
131    CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
132    isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port);
133    CHECK_NULL_RETURN(isa, IOS_THROWN);
134    (*env)->SetObjectArrayElement(env, isaa, 0, isa);
135    return 1;
136}
137
138
139
140static JNINativeMethod gMethods[] = {
141  NATIVE_METHOD(Java_sun_nio_ch_ServerSocketChannelImpl, initIDs, "()V"),
142  NATIVE_METHOD(Java_sun_nio_ch_ServerSocketChannelImpl, accept0,
143                "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;[Ljava/net/InetSocketAddress;)I"),
144};
145
146void register_sun_nio_ch_ServerSocketChannelImpl(JNIEnv* env) {
147  jniRegisterNativeMethods(env, "sun/nio/ch/ServerSocketChannelImpl", gMethods, NELEM(gMethods));
148}
149