1 /*
2  * Copyright (c) 2007, 2019, 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 package java.net;
26 
27 import java.io.IOException;
28 import java.io.FileDescriptor;
29 import sun.net.ResourceManager;
30 
31 /**
32  * This class defines the plain DatagramSocketImpl that is used for all
33  * Windows versions 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 
43 final class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
44 {
45     /* Used for IPv6 on Windows only */
46     private FileDescriptor fd1;
47 
48     /*
49      * Needed for ipv6 on windows because we need to know
50      * if the socket was bound to ::0 or 0.0.0.0, when a caller
51      * asks for it. In this case, both sockets are used, but we
52      * don't know whether the caller requested ::0 or 0.0.0.0
53      * and need to remember it here.
54      */
55     private InetAddress anyLocalBoundAddr=null;
56 
57     private int fduse=-1; /* saved between peek() and receive() calls */
58 
59     /* saved between successive calls to receive, if data is detected
60      * on both sockets at same time. To ensure that one socket is not
61      * starved, they rotate using this field
62      */
63     private int lastfd=-1;
64 
65     static {
init()66         init();
67     }
68 
69     // true if this socket is exclusively bound
70     private final boolean exclusiveBind;
71 
72     /*
73      * Set to true if SO_REUSEADDR is set after the socket is bound to
74      * indicate SO_REUSEADDR is being emulated
75      */
76     private boolean reuseAddressEmulated;
77 
78     // emulates SO_REUSEADDR when exclusiveBind is true and socket is bound
79     private boolean isReuseAddress;
80 
TwoStacksPlainDatagramSocketImpl(boolean exclBind, boolean isMulticast)81     TwoStacksPlainDatagramSocketImpl(boolean exclBind, boolean isMulticast) {
82         super(isMulticast);
83         exclusiveBind = exclBind;
84     }
85 
create()86     protected synchronized void create() throws SocketException {
87         fd1 = new FileDescriptor();
88         try {
89             super.create();
90             // make SocketCleanable treat fd1 as a stream socket
91             // to avoid touching the counter in ResourceManager
92             SocketCleanable.register(fd1, true);
93         } catch (SocketException e) {
94             fd1 = null;
95             throw e;
96         }
97     }
98 
bind(int lport, InetAddress laddr)99     protected synchronized void bind(int lport, InetAddress laddr)
100         throws SocketException {
101         super.bind(lport, laddr);
102         if (laddr.isAnyLocalAddress()) {
103             anyLocalBoundAddr = laddr;
104         }
105     }
106 
107     @Override
bind0(int lport, InetAddress laddr)108     protected synchronized void bind0(int lport, InetAddress laddr)
109         throws SocketException
110     {
111         // The native bind0 may close one or both of the underlying file
112         // descriptors, and even create new sockets, so the safest course of
113         // action is to unregister the socket cleaners, and register afterwards.
114         SocketCleanable.unregister(fd);
115         SocketCleanable.unregister(fd1);
116 
117         bind0(lport, laddr, exclusiveBind);
118 
119         SocketCleanable.register(fd, false);
120         // make SocketCleanable treat fd1 as a stream socket
121         // to avoid touching the counter in ResourceManager
122         SocketCleanable.register(fd1, true);
123     }
124 
receive(DatagramPacket p)125     protected synchronized void receive(DatagramPacket p)
126         throws IOException {
127         try {
128             receive0(p);
129         } finally {
130             fduse = -1;
131         }
132     }
133 
getOption(int optID)134     public Object getOption(int optID) throws SocketException {
135         if (isClosed()) {
136             throw new SocketException("Socket Closed");
137         }
138 
139         if (optID == SO_BINDADDR) {
140             if ((fd != null && fd1 != null) && !connected) {
141                 return anyLocalBoundAddr;
142             }
143             int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily();
144             return socketLocalAddress(family);
145         } else if (optID == SO_REUSEADDR && reuseAddressEmulated) {
146             return isReuseAddress;
147         } else if (optID == SO_REUSEPORT) {
148             // SO_REUSEPORT is not supported on Windows.
149             throw new UnsupportedOperationException("unsupported option");
150         } else {
151             return super.getOption(optID);
152         }
153     }
154 
socketSetOption(int opt, Object val)155     protected void socketSetOption(int opt, Object val)
156         throws SocketException
157     {
158         if (opt == SO_REUSEADDR && exclusiveBind && localPort != 0)  {
159             // socket already bound, emulate
160             reuseAddressEmulated = true;
161             isReuseAddress = (Boolean)val;
162         } else if (opt == SO_REUSEPORT) {
163             // SO_REUSEPORT is not supported on Windows.
164             throw new UnsupportedOperationException("unsupported option");
165         } else {
166             socketNativeSetOption(opt, val);
167         }
168 
169     }
170 
isClosed()171     protected boolean isClosed() {
172         return (fd == null && fd1 == null) ? true : false;
173     }
174 
close()175     protected void close() {
176         if (fd != null || fd1 != null) {
177             SocketCleanable.unregister(fd);
178             SocketCleanable.unregister(fd1);
179             datagramSocketClose();
180             ResourceManager.afterUdpClose();
181             fd = null;
182             fd1 = null;
183         }
184     }
185 
186     /* Native methods */
187 
bind0(int lport, InetAddress laddr, boolean exclBind)188     protected synchronized native void bind0(int lport, InetAddress laddr,
189                                              boolean exclBind)
190         throws SocketException;
191 
send0(DatagramPacket p)192     protected native void send0(DatagramPacket p) throws IOException;
193 
peek(InetAddress i)194     protected synchronized native int peek(InetAddress i) throws IOException;
195 
peekData(DatagramPacket p)196     protected synchronized native int peekData(DatagramPacket p) throws IOException;
197 
receive0(DatagramPacket p)198     protected synchronized native void receive0(DatagramPacket p)
199         throws IOException;
200 
setTimeToLive(int ttl)201     protected native void setTimeToLive(int ttl) throws IOException;
202 
getTimeToLive()203     protected native int getTimeToLive() throws IOException;
204 
205     @Deprecated
setTTL(byte ttl)206     protected native void setTTL(byte ttl) throws IOException;
207 
208     @Deprecated
getTTL()209     protected native byte getTTL() throws IOException;
210 
join(InetAddress inetaddr, NetworkInterface netIf)211     protected native void join(InetAddress inetaddr, NetworkInterface netIf)
212         throws IOException;
213 
leave(InetAddress inetaddr, NetworkInterface netIf)214     protected native void leave(InetAddress inetaddr, NetworkInterface netIf)
215         throws IOException;
216 
datagramSocketCreate()217     protected native void datagramSocketCreate() throws SocketException;
218 
datagramSocketClose()219     protected native void datagramSocketClose();
220 
socketNativeSetOption(int opt, Object val)221     protected native void socketNativeSetOption(int opt, Object val)
222         throws SocketException;
223 
socketGetOption(int opt)224     protected native Object socketGetOption(int opt) throws SocketException;
225 
connect0(InetAddress address, int port)226     protected native void connect0(InetAddress address, int port) throws SocketException;
227 
socketLocalAddress(int family)228     protected native Object socketLocalAddress(int family) throws SocketException;
229 
disconnect0(int family)230     protected native void disconnect0(int family);
231 
dataAvailable()232     native int dataAvailable();
233 
234     /**
235      * Perform class load-time initializations.
236      */
init()237     private static native void init();
238 }
239