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 java.io.FileDescriptor;
29import sun.net.ResourceManager;
30
31/*
32 * This class defines the plain SocketImpl that is used for all
33 * Windows version lower than Vista. It adds support for IPv6 on
34 * these platforms where available.
35 *
36 * For backward compatibility Windows platforms that do not have IPv6
37 * support also use this implementation, and fd1 gets set to null
38 * during socket creation.
39 *
40 * @author Chris Hegarty
41 */
42
43class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl
44{
45    /* second fd, used for ipv6 on windows only.
46     * fd1 is used for listeners and for client sockets at initialization
47     * until the socket is connected. Up to this point fd always refers
48     * to the ipv4 socket and fd1 to the ipv6 socket. After the socket
49     * becomes connected, fd always refers to the connected socket
50     * (either v4 or v6) and fd1 is closed.
51     *
52     * For ServerSockets, fd always refers to the v4 listener and
53     * fd1 the v6 listener.
54     */
55    private FileDescriptor fd1;
56
57    /*
58     * Needed for ipv6 on windows because we need to know
59     * if the socket is bound to ::0 or 0.0.0.0, when a caller
60     * asks for it. Otherwise we don't know which socket to ask.
61     */
62    private InetAddress anyLocalBoundAddr = null;
63
64    /* to prevent starvation when listening on two sockets, this is
65     * is used to hold the id of the last socket we accepted on.
66     */
67    private int lastfd = -1;
68
69    // true if this socket is exclusively bound
70    private final boolean exclusiveBind;
71
72    // emulates SO_REUSEADDR when exclusiveBind is true
73    private boolean isReuseAddress;
74
75    static {
76        initProto();
77    }
78
79    public TwoStacksPlainSocketImpl(boolean exclBind) {
80        exclusiveBind = exclBind;
81    }
82
83    public TwoStacksPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
84        this.fd = fd;
85        exclusiveBind = exclBind;
86    }
87
88    /**
89     * Creates a socket with a boolean that specifies whether this
90     * is a stream socket (true) or an unconnected UDP socket (false).
91     */
92    protected synchronized void create(boolean stream) throws IOException {
93        fd1 = new FileDescriptor();
94        try {
95            super.create(stream);
96        } catch (IOException e) {
97            fd1 = null;
98            throw e;
99        }
100    }
101
102     /**
103     * Binds the socket to the specified address of the specified local port.
104     * @param address the address
105     * @param port the port
106     */
107    protected synchronized void bind(InetAddress address, int lport)
108        throws IOException
109    {
110        super.bind(address, lport);
111        if (address.isAnyLocalAddress()) {
112            anyLocalBoundAddr = address;
113        }
114    }
115
116    public Object getOption(int opt) throws SocketException {
117        if (isClosedOrPending()) {
118            throw new SocketException("Socket Closed");
119        }
120        if (opt == SO_BINDADDR) {
121            if (fd != null && fd1 != null ) {
122                /* must be unbound or else bound to anyLocal */
123                return anyLocalBoundAddr;
124            }
125            InetAddressContainer in = new InetAddressContainer();
126            socketGetOption(opt, in);
127            return in.addr;
128        } else if (opt == SO_REUSEADDR && exclusiveBind) {
129            // SO_REUSEADDR emulated when using exclusive bind
130            return isReuseAddress;
131        } else if (opt == SO_REUSEPORT) {
132            // SO_REUSEPORT is not supported on Windows.
133            throw new UnsupportedOperationException("unsupported option");
134        } else
135            return super.getOption(opt);
136    }
137
138    @Override
139    void socketBind(InetAddress address, int port) throws IOException {
140        socketBind(address, port, exclusiveBind);
141    }
142
143    @Override
144    void socketSetOption(int opt, boolean on, Object value)
145        throws SocketException
146    {
147        // SO_REUSEADDR emulated when using exclusive bind
148        if (opt == SO_REUSEADDR && exclusiveBind)
149            isReuseAddress = on;
150        else if (opt == SO_REUSEPORT) {
151            // SO_REUSEPORT is not supported on Windows.
152            throw new UnsupportedOperationException("unsupported option");
153        }
154        else
155            socketNativeSetOption(opt, on, value);
156    }
157
158    /**
159     * Closes the socket.
160     */
161    @Override
162    protected void close() throws IOException {
163        synchronized(fdLock) {
164            if (fd != null || fd1 != null) {
165                if (!stream) {
166                    ResourceManager.afterUdpClose();
167                }
168                if (fdUseCount == 0) {
169                    if (closePending) {
170                        return;
171                    }
172                    closePending = true;
173                    socketClose();
174                    fd = null;
175                    fd1 = null;
176                    return;
177                } else {
178                    /*
179                     * If a thread has acquired the fd and a close
180                     * isn't pending then use a deferred close.
181                     * Also decrement fdUseCount to signal the last
182                     * thread that releases the fd to close it.
183                     */
184                    if (!closePending) {
185                        closePending = true;
186                        fdUseCount--;
187                        socketClose();
188                    }
189                }
190            }
191        }
192    }
193
194    @Override
195    void reset() throws IOException {
196        if (fd != null || fd1 != null) {
197            socketClose();
198        }
199        fd = null;
200        fd1 = null;
201        super.reset();
202    }
203
204    /*
205     * Return true if already closed or close is pending
206     */
207    @Override
208    public boolean isClosedOrPending() {
209        /*
210         * Lock on fdLock to ensure that we wait if a
211         * close is in progress.
212         */
213        synchronized (fdLock) {
214            if (closePending || (fd == null && fd1 == null)) {
215                return true;
216            } else {
217                return false;
218            }
219        }
220    }
221
222    /* Native methods */
223
224    static native void initProto();
225
226    native void socketCreate(boolean isServer) throws IOException;
227
228    native void socketConnect(InetAddress address, int port, int timeout)
229        throws IOException;
230
231    native void socketBind(InetAddress address, int port, boolean exclBind)
232        throws IOException;
233
234    native void socketListen(int count) throws IOException;
235
236    native void socketAccept(SocketImpl s) throws IOException;
237
238    native int socketAvailable() throws IOException;
239
240    native void socketClose0(boolean useDeferredClose) throws IOException;
241
242    native void socketShutdown(int howto) throws IOException;
243
244    native void socketNativeSetOption(int cmd, boolean on, Object value)
245        throws SocketException;
246
247    native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
248
249    native void socketSendUrgentData(int data) throws IOException;
250}
251