summaryrefslogtreecommitdiff
path: root/external/ikvm/openjdk/java/net/TwoStacksPlainDatagramSocketImpl.java
blob: 2b2bde1b41210915b3a0a94444a35803b830cb44 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/*
 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package java.net;

import java.io.IOException;
import java.io.FileDescriptor;
import sun.net.ResourceManager;

/**
 * This class defines the plain DatagramSocketImpl that is used for all
 * Windows versions lower than Vista. It adds support for IPv6 on
 * these platforms where available.
 *
 * For backward compatibility windows platforms that do not have IPv6
 * support also use this implementation, and fd1 gets set to null
 * during socket creation.
 *
 * @author Chris Hegarty
 */

class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
{
    /* Used for IPv6 on Windows only */
    FileDescriptor fd1;

    /*
     * Needed for ipv6 on windows because we need to know
     * if the socket was bound to ::0 or 0.0.0.0, when a caller
     * asks for it. In this case, both sockets are used, but we
     * don't know whether the caller requested ::0 or 0.0.0.0
     * and need to remember it here.
     */
    private InetAddress anyLocalBoundAddr=null;

    cli.System.Net.Sockets.Socket fduse=null; /* saved between peek() and receive() calls */

    /* saved between successive calls to receive, if data is detected
     * on both sockets at same time. To ensure that one socket is not
     * starved, they rotate using this field
     */
    cli.System.Net.Sockets.Socket lastfd=null;

    // true if this socket is exclusively bound
    private final boolean exclusiveBind;

    /*
     * Set to true if SO_REUSEADDR is set after the socket is bound to
     * indicate SO_REUSEADDR is being emulated
     */
    private boolean reuseAddressEmulated;

    // emulates SO_REUSEADDR when exclusiveBind is true and socket is bound
    private boolean isReuseAddress;

    TwoStacksPlainDatagramSocketImpl(boolean exclBind) {
        exclusiveBind = exclBind;
    }

    protected synchronized void create() throws SocketException {
        fd1 = new FileDescriptor();
        try {
            super.create();
        } catch (SocketException e) {
            fd1 = null;
            throw e;
        }
    }

    protected synchronized void bind(int lport, InetAddress laddr)
        throws SocketException {
        super.bind(lport, laddr);
        if (laddr.isAnyLocalAddress()) {
            anyLocalBoundAddr = laddr;
        }
    }

    @Override
    protected synchronized void bind0(int lport, InetAddress laddr)
        throws SocketException
    {
        bind0(lport, laddr, exclusiveBind);

    }

    protected synchronized void receive(DatagramPacket p)
        throws IOException {
        try {
            receive0(p);
        } finally {
            fduse = null;
        }
    }

    public Object getOption(int optID) throws SocketException {
        if (isClosed()) {
            throw new SocketException("Socket Closed");
        }

        if (optID == SO_BINDADDR) {
            if (fd != null && fd1 != null) {
                return anyLocalBoundAddr;
            }
            return socketGetOption(optID);
        } else if (optID == SO_REUSEADDR && reuseAddressEmulated) {
            return isReuseAddress;
        } else {
            return super.getOption(optID);
        }
    }

    protected void socketSetOption(int opt, Object val)
        throws SocketException
    {
        if (opt == SO_REUSEADDR && exclusiveBind && localPort != 0)  {
            // socket already bound, emulate
            reuseAddressEmulated = true;
            isReuseAddress = (Boolean)val;
        } else {
            socketNativeSetOption(opt, val);
        }

    }

    protected boolean isClosed() {
        return (fd == null && fd1 == null) ? true : false;
    }

    protected void close() {
        if (fd != null || fd1 != null) {
            datagramSocketClose();
            ResourceManager.afterUdpClose();
            fd = null;
            fd1 = null;
        }
    }

    /* Native methods */

    protected synchronized void bind0(int lport, InetAddress laddr,
                                             boolean exclBind) throws SocketException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.bind0(env, this, lport, laddr, exclBind);
        env.ThrowPendingException();
    }

    protected void send(DatagramPacket packet) throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.send(env, this, packet);
        env.ThrowPendingException();
    }

    protected synchronized int peek(InetAddress addressObj) throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        int ret = TwoStacksPlainDatagramSocketImpl_c.peek(env, this, addressObj);
        env.ThrowPendingException();
        return ret;
    }

    protected synchronized int peekData(DatagramPacket p) throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        int ret = TwoStacksPlainDatagramSocketImpl_c.peekData(env, this, p);
        env.ThrowPendingException();
        return ret;
    }

    protected synchronized void receive0(DatagramPacket packet) throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.receive0(env, this, packet);
        env.ThrowPendingException();
    }

    protected void setTimeToLive(int ttl) throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.setTimeToLive(env, this, ttl);
        env.ThrowPendingException();
    }

    protected int getTimeToLive() throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        int ret = TwoStacksPlainDatagramSocketImpl_c.getTimeToLive(env, this);
        env.ThrowPendingException();
        return ret;
    }

    protected void setTTL(byte ttl) throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.setTTL(env, this, ttl);
        env.ThrowPendingException();
    }

    protected byte getTTL() throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        byte ret = TwoStacksPlainDatagramSocketImpl_c.getTTL(env, this);
        env.ThrowPendingException();
        return ret;
    }

    protected void join(InetAddress inetaddr, NetworkInterface netIf) throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.join(env, this, inetaddr, netIf);
        env.ThrowPendingException();
    }

    protected void leave(InetAddress inetaddr, NetworkInterface netIf) throws IOException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.leave(env, this, inetaddr, netIf);
        env.ThrowPendingException();
    }

    protected void datagramSocketCreate() throws SocketException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.datagramSocketCreate(env, this);
        env.ThrowPendingException();
    }

    protected void datagramSocketClose() {
        TwoStacksPlainDatagramSocketImpl_c.datagramSocketClose(this);
    }

    protected void socketNativeSetOption(int opt, Object val) throws SocketException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.socketNativeSetOption(env, this, opt, val);
        env.ThrowPendingException();
    }

    protected Object socketGetOption(int opt) throws SocketException {
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        Object ret = TwoStacksPlainDatagramSocketImpl_c.socketGetOption(env, this, opt);
        env.ThrowPendingException();
        return ret;
    }

    protected void connect0(InetAddress address, int port) throws SocketException {
        if (ikvm.internal.Util.MONO) {
            // MONOBUG Mono doesn't allow Socket.Connect(IPAddress.Any, 0) to disconnect a datagram socket,
            // so we throw a SocketException, this will cause DatagramSocket to emulate connectedness
            throw new SocketException("connected datagram sockets not supported on Mono");
        }
        ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
        TwoStacksPlainDatagramSocketImpl_c.connect0(env, this, address, port);
        env.ThrowPendingException();
    }

    protected void disconnect0(int family) {
        TwoStacksPlainDatagramSocketImpl_c.disconnect0(this, family);
    }
}