1/*
2 * Copyright (c) 2007, 2016, 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 */
25package java.net;
26
27import java.io.IOException;
28import jdk.internal.misc.SharedSecrets;
29import jdk.internal.misc.JavaIOFileDescriptorAccess;
30
31/**
32 * This class defines the plain DatagramSocketImpl that is used on
33 * Windows platforms greater than or equal to Windows Vista. These
34 * platforms have a dual layer TCP/IP stack and can handle both IPv4
35 * and IPV6 through a single file descriptor.
36 * <p>
37 * Note: Multicasting on a dual layer TCP/IP stack is always done with
38 * TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
39 * of behavior defined for multicasting over a dual layer socket by the RFC.
40 *
41 * @author Chris Hegarty
42 */
43
44class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
45{
46    static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
47
48    static {
49        initIDs();
50    }
51
52    // true if this socket is exclusively bound
53    private final boolean exclusiveBind;
54
55    /*
56     * Set to true if SO_REUSEADDR is set after the socket is bound to
57     * indicate SO_REUSEADDR is being emulated
58     */
59    private boolean reuseAddressEmulated;
60
61    // emulates SO_REUSEADDR when exclusiveBind is true and socket is bound
62    private boolean isReuseAddress;
63
64    DualStackPlainDatagramSocketImpl(boolean exclBind) {
65        exclusiveBind = exclBind;
66    }
67
68    protected void datagramSocketCreate() throws SocketException {
69        if (fd == null)
70            throw new SocketException("Socket closed");
71
72        int newfd = socketCreate(false /* v6Only */);
73
74        fdAccess.set(fd, newfd);
75    }
76
77    protected synchronized void bind0(int lport, InetAddress laddr)
78        throws SocketException {
79        int nativefd = checkAndReturnNativeFD();
80
81        if (laddr == null)
82            throw new NullPointerException("argument address");
83
84        socketBind(nativefd, laddr, lport, exclusiveBind);
85        if (lport == 0) {
86            localPort = socketLocalPort(nativefd);
87        } else {
88            localPort = lport;
89        }
90    }
91
92    protected synchronized int peek(InetAddress address) throws IOException {
93        int nativefd = checkAndReturnNativeFD();
94
95        if (address == null)
96            throw new NullPointerException("Null address in peek()");
97
98        // Use peekData()
99        DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
100        int peekPort = peekData(peekPacket);
101        address = peekPacket.getAddress();
102        return peekPort;
103    }
104
105    protected synchronized int peekData(DatagramPacket p) throws IOException {
106        int nativefd = checkAndReturnNativeFD();
107
108        if (p == null)
109            throw new NullPointerException("packet");
110        if (p.getData() == null)
111            throw new NullPointerException("packet buffer");
112
113        return socketReceiveOrPeekData(nativefd, p, timeout, connected, true /*peek*/);
114    }
115
116    protected synchronized void receive0(DatagramPacket p) throws IOException {
117        int nativefd = checkAndReturnNativeFD();
118
119        if (p == null)
120            throw new NullPointerException("packet");
121        if (p.getData() == null)
122            throw new NullPointerException("packet buffer");
123
124        socketReceiveOrPeekData(nativefd, p, timeout, connected, false /*receive*/);
125    }
126
127    protected void send(DatagramPacket p) throws IOException {
128        int nativefd = checkAndReturnNativeFD();
129
130        if (p == null)
131            throw new NullPointerException("null packet");
132
133        if (p.getAddress() == null ||p.getData() ==null)
134            throw new NullPointerException("null address || null buffer");
135
136        socketSend(nativefd, p.getData(), p.getOffset(), p.getLength(),
137                   p.getAddress(), p.getPort(), connected);
138    }
139
140    protected void connect0(InetAddress address, int port) throws SocketException {
141        int nativefd = checkAndReturnNativeFD();
142
143        if (address == null)
144            throw new NullPointerException("address");
145
146        socketConnect(nativefd, address, port);
147    }
148
149    protected void disconnect0(int family /*unused*/) {
150        if (fd == null || !fd.valid())
151            return;   // disconnect doesn't throw any exceptions
152
153        socketDisconnect(fdAccess.get(fd));
154    }
155
156    protected void datagramSocketClose() {
157        if (fd == null || !fd.valid())
158            return;   // close doesn't throw any exceptions
159
160        socketClose(fdAccess.get(fd));
161        fdAccess.set(fd, -1);
162    }
163
164    @SuppressWarnings("fallthrough")
165    protected void socketSetOption(int opt, Object val) throws SocketException {
166        int nativefd = checkAndReturnNativeFD();
167
168        int optionValue = 0;
169
170        // SO_REUSEPORT is not supported on Windows.
171        if (opt == SO_REUSEPORT) {
172            throw new UnsupportedOperationException("unsupported option");
173        }
174
175        switch(opt) {
176            case IP_TOS :
177            case SO_RCVBUF :
178            case SO_SNDBUF :
179                optionValue = ((Integer)val).intValue();
180                break;
181            case SO_REUSEADDR :
182                if (exclusiveBind && localPort != 0)  {
183                    // socket already bound, emulate SO_REUSEADDR
184                    reuseAddressEmulated = true;
185                    isReuseAddress = (Boolean)val;
186                    return;
187                }
188                //Intentional fallthrough
189            case SO_BROADCAST :
190                optionValue = ((Boolean)val).booleanValue() ? 1 : 0;
191                break;
192            default: /* shouldn't get here */
193                throw new SocketException("Option not supported");
194        }
195
196        socketSetIntOption(nativefd, opt, optionValue);
197    }
198
199    protected Object socketGetOption(int opt) throws SocketException {
200        int nativefd = checkAndReturnNativeFD();
201
202         // SO_BINDADDR is not a socket option.
203        if (opt == SO_BINDADDR) {
204            return socketLocalAddress(nativefd);
205        }
206        if (opt == SO_REUSEADDR && reuseAddressEmulated)
207            return isReuseAddress;
208        // SO_REUSEPORT is not supported on Windows.
209        if (opt == SO_REUSEPORT)
210            throw new UnsupportedOperationException("unsupported option");
211
212        int value = socketGetIntOption(nativefd, opt);
213        Object returnValue = null;
214
215        switch (opt) {
216            case SO_REUSEADDR :
217            case SO_BROADCAST :
218                returnValue =  (value == 0) ? Boolean.FALSE : Boolean.TRUE;
219                break;
220            case IP_TOS :
221            case SO_RCVBUF :
222            case SO_SNDBUF :
223                returnValue = Integer.valueOf(value);
224                break;
225            default: /* shouldn't get here */
226                throw new SocketException("Option not supported");
227        }
228
229        return returnValue;
230    }
231
232    /* Multicast specific methods.
233     * Multicasting on a dual layer TCP/IP stack is always done with
234     * TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
235     * of behavior defined for multicasting over a dual layer socket by the RFC.
236     */
237    protected void join(InetAddress inetaddr, NetworkInterface netIf)
238        throws IOException {
239        throw new IOException("Method not implemented!");
240    }
241
242    protected void leave(InetAddress inetaddr, NetworkInterface netIf)
243        throws IOException {
244        throw new IOException("Method not implemented!");
245    }
246
247    protected void setTimeToLive(int ttl) throws IOException {
248        throw new IOException("Method not implemented!");
249    }
250
251    protected int getTimeToLive() throws IOException {
252        throw new IOException("Method not implemented!");
253    }
254
255    @Deprecated
256    protected void setTTL(byte ttl) throws IOException {
257        throw new IOException("Method not implemented!");
258    }
259
260    @Deprecated
261    protected byte getTTL() throws IOException {
262        throw new IOException("Method not implemented!");
263    }
264    /* END Multicast specific methods */
265
266    private int checkAndReturnNativeFD() throws SocketException {
267        if (fd == null || !fd.valid())
268            throw new SocketException("Socket closed");
269
270        return fdAccess.get(fd);
271    }
272
273    /* Native methods */
274
275    private static native void initIDs();
276
277    private static native int socketCreate(boolean v6Only);
278
279    private static native void socketBind(int fd, InetAddress localAddress,
280            int localport, boolean exclBind) throws SocketException;
281
282    private static native void socketConnect(int fd, InetAddress address, int port)
283        throws SocketException;
284
285    private static native void socketDisconnect(int fd);
286
287    private static native void socketClose(int fd);
288
289    private static native int socketLocalPort(int fd) throws SocketException;
290
291    private static native Object socketLocalAddress(int fd) throws SocketException;
292
293    private static native int socketReceiveOrPeekData(int fd, DatagramPacket packet,
294        int timeout, boolean connected, boolean peek) throws IOException;
295
296    private static native void socketSend(int fd, byte[] data, int offset, int length,
297        InetAddress address, int port, boolean connected) throws IOException;
298
299    private static native void socketSetIntOption(int fd, int cmd,
300        int optionValue) throws SocketException;
301
302    private static native int socketGetIntOption(int fd, int cmd) throws SocketException;
303
304    native int dataAvailable();
305}
306