1 /*
2  * Copyright (c) 2007, 2015, 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 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)81     TwoStacksPlainDatagramSocketImpl(boolean exclBind) {
82         exclusiveBind = exclBind;
83     }
84 
create()85     protected synchronized void create() throws SocketException {
86         fd1 = new FileDescriptor();
87         try {
88             super.create();
89         } catch (SocketException e) {
90             fd1 = null;
91             throw e;
92         }
93     }
94 
bind(int lport, InetAddress laddr)95     protected synchronized void bind(int lport, InetAddress laddr)
96         throws SocketException {
97         super.bind(lport, laddr);
98         if (laddr.isAnyLocalAddress()) {
99             anyLocalBoundAddr = laddr;
100         }
101     }
102 
103     @Override
bind0(int lport, InetAddress laddr)104     protected synchronized void bind0(int lport, InetAddress laddr)
105         throws SocketException
106     {
107         bind0(lport, laddr, exclusiveBind);
108 
109     }
110 
receive(DatagramPacket p)111     protected synchronized void receive(DatagramPacket p)
112         throws IOException {
113         try {
114             receive0(p);
115         } finally {
116             fduse = -1;
117         }
118     }
119 
getOption(int optID)120     public Object getOption(int optID) throws SocketException {
121         if (isClosed()) {
122             throw new SocketException("Socket Closed");
123         }
124 
125         if (optID == SO_BINDADDR) {
126             if ((fd != null && fd1 != null) && !connected) {
127                 return anyLocalBoundAddr;
128             }
129             int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily();
130             return socketLocalAddress(family);
131         } else if (optID == SO_REUSEADDR && reuseAddressEmulated) {
132             return isReuseAddress;
133         } else {
134             return super.getOption(optID);
135         }
136     }
137 
socketSetOption(int opt, Object val)138     protected void socketSetOption(int opt, Object val)
139         throws SocketException
140     {
141         if (opt == SO_REUSEADDR && exclusiveBind && localPort != 0)  {
142             // socket already bound, emulate
143             reuseAddressEmulated = true;
144             isReuseAddress = (Boolean)val;
145         } else {
146             socketNativeSetOption(opt, val);
147         }
148 
149     }
150 
isClosed()151     protected boolean isClosed() {
152         return (fd == null && fd1 == null) ? true : false;
153     }
154 
close()155     protected void close() {
156         if (fd != null || fd1 != null) {
157             datagramSocketClose();
158             ResourceManager.afterUdpClose();
159             fd = null;
160             fd1 = null;
161         }
162     }
163 
164     /* Native methods */
165 
bind0(int lport, InetAddress laddr, boolean exclBind)166     protected synchronized native void bind0(int lport, InetAddress laddr,
167                                              boolean exclBind)
168         throws SocketException;
169 
send(DatagramPacket p)170     protected native void send(DatagramPacket p) throws IOException;
171 
peek(InetAddress i)172     protected synchronized native int peek(InetAddress i) throws IOException;
173 
peekData(DatagramPacket p)174     protected synchronized native int peekData(DatagramPacket p) throws IOException;
175 
receive0(DatagramPacket p)176     protected synchronized native void receive0(DatagramPacket p)
177         throws IOException;
178 
setTimeToLive(int ttl)179     protected native void setTimeToLive(int ttl) throws IOException;
180 
getTimeToLive()181     protected native int getTimeToLive() throws IOException;
182 
183     @Deprecated
setTTL(byte ttl)184     protected native void setTTL(byte ttl) throws IOException;
185 
186     @Deprecated
getTTL()187     protected native byte getTTL() throws IOException;
188 
join(InetAddress inetaddr, NetworkInterface netIf)189     protected native void join(InetAddress inetaddr, NetworkInterface netIf)
190         throws IOException;
191 
leave(InetAddress inetaddr, NetworkInterface netIf)192     protected native void leave(InetAddress inetaddr, NetworkInterface netIf)
193         throws IOException;
194 
datagramSocketCreate()195     protected native void datagramSocketCreate() throws SocketException;
196 
datagramSocketClose()197     protected native void datagramSocketClose();
198 
socketNativeSetOption(int opt, Object val)199     protected native void socketNativeSetOption(int opt, Object val)
200         throws SocketException;
201 
socketGetOption(int opt)202     protected native Object socketGetOption(int opt) throws SocketException;
203 
connect0(InetAddress address, int port)204     protected native void connect0(InetAddress address, int port) throws SocketException;
205 
socketLocalAddress(int family)206     protected native Object socketLocalAddress(int family) throws SocketException;
207 
disconnect0(int family)208     protected native void disconnect0(int family);
209 
dataAvailable()210     native int dataAvailable();
211 
212     /**
213      * Perform class load-time initializations.
214      */
init()215     private native static void init();
216 }
217