39 import java.net.StandardSocketOptions; |
39 import java.net.StandardSocketOptions; |
40 import java.nio.ByteBuffer; |
40 import java.nio.ByteBuffer; |
41 import java.nio.channels.ClosedChannelException; |
41 import java.nio.channels.ClosedChannelException; |
42 import java.nio.channels.DatagramChannel; |
42 import java.nio.channels.DatagramChannel; |
43 import java.nio.channels.IllegalBlockingModeException; |
43 import java.nio.channels.IllegalBlockingModeException; |
|
44 import java.util.Objects; |
44 |
45 |
45 |
46 |
46 // Make a datagram-socket channel look like a datagram socket. |
47 // Make a datagram-socket channel look like a datagram socket. |
47 // |
48 // |
48 // The methods in this class are defined in exactly the same order as in |
49 // The methods in this class are defined in exactly the same order as in |
51 // |
52 // |
52 |
53 |
53 public class DatagramSocketAdaptor |
54 public class DatagramSocketAdaptor |
54 extends DatagramSocket |
55 extends DatagramSocket |
55 { |
56 { |
56 |
|
57 // The channel being adapted |
57 // The channel being adapted |
58 private final DatagramChannelImpl dc; |
58 private final DatagramChannelImpl dc; |
59 |
59 |
60 // Timeout "option" value for receives |
60 // Timeout "option" value for receives |
61 private volatile int timeout; |
61 private volatile int timeout; |
62 |
62 |
63 // ## super will create a useless impl |
63 // ## super will create a useless impl |
64 private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException { |
64 private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException { |
65 // Invoke the DatagramSocketAdaptor(SocketAddress) constructor, |
65 // Invoke the DatagramSocketAdaptor(SocketAddress) constructor, |
66 // passing a dummy DatagramSocketImpl object to aovid any native |
66 // passing a dummy DatagramSocketImpl object to avoid any native |
67 // resource allocation in super class and invoking our bind method |
67 // resource allocation in super class and invoking our bind method |
68 // before the dc field is initialized. |
68 // before the dc field is initialized. |
69 super(dummyDatagramSocket); |
69 super(dummyDatagramSocket); |
70 this.dc = dc; |
70 this.dc = dc; |
71 } |
71 } |
85 int port = isa.getPort(); |
85 int port = isa.getPort(); |
86 if (port < 0 || port > 0xFFFF) |
86 if (port < 0 || port > 0xFFFF) |
87 throw new IllegalArgumentException("connect: " + port); |
87 throw new IllegalArgumentException("connect: " + port); |
88 if (remote == null) |
88 if (remote == null) |
89 throw new IllegalArgumentException("connect: null address"); |
89 throw new IllegalArgumentException("connect: null address"); |
90 if (isClosed()) |
|
91 return; |
|
92 try { |
90 try { |
93 dc.connect(remote); |
91 dc.connect(remote); |
|
92 } catch (ClosedChannelException e) { |
|
93 // ignore |
94 } catch (Exception x) { |
94 } catch (Exception x) { |
95 Net.translateToSocketException(x); |
95 Net.translateToSocketException(x); |
96 } |
96 } |
97 } |
97 } |
98 |
98 |
113 // Yes, j.n.DatagramSocket really does this |
113 // Yes, j.n.DatagramSocket really does this |
114 } |
114 } |
115 } |
115 } |
116 |
116 |
117 public void connect(SocketAddress remote) throws SocketException { |
117 public void connect(SocketAddress remote) throws SocketException { |
118 if (remote == null) |
118 Objects.requireNonNull(remote, "Address can't be null"); |
119 throw new IllegalArgumentException("Address can't be null"); |
|
120 connectInternal(remote); |
119 connectInternal(remote); |
121 } |
120 } |
122 |
121 |
123 public void disconnect() { |
122 public void disconnect() { |
124 try { |
123 try { |
135 public boolean isConnected() { |
134 public boolean isConnected() { |
136 return dc.remoteAddress() != null; |
135 return dc.remoteAddress() != null; |
137 } |
136 } |
138 |
137 |
139 public InetAddress getInetAddress() { |
138 public InetAddress getInetAddress() { |
140 return (isConnected() |
139 InetSocketAddress remote = dc.remoteAddress(); |
141 ? Net.asInetSocketAddress(dc.remoteAddress()).getAddress() |
140 return (remote != null) ? remote.getAddress() : null; |
142 : null); |
|
143 } |
141 } |
144 |
142 |
145 public int getPort() { |
143 public int getPort() { |
146 return (isConnected() |
144 InetSocketAddress remote = dc.remoteAddress(); |
147 ? Net.asInetSocketAddress(dc.remoteAddress()).getPort() |
145 return (remote != null) ? remote.getPort() : -1; |
148 : -1); |
|
149 } |
146 } |
150 |
147 |
151 public void send(DatagramPacket p) throws IOException { |
148 public void send(DatagramPacket p) throws IOException { |
152 synchronized (dc.blockingLock()) { |
149 synchronized (dc.blockingLock()) { |
153 if (!dc.isBlocking()) |
150 if (!dc.isBlocking()) |
159 p.getLength()); |
156 p.getLength()); |
160 if (dc.isConnected()) { |
157 if (dc.isConnected()) { |
161 if (p.getAddress() == null) { |
158 if (p.getAddress() == null) { |
162 // Legacy DatagramSocket will send in this case |
159 // Legacy DatagramSocket will send in this case |
163 // and set address and port of the packet |
160 // and set address and port of the packet |
164 InetSocketAddress isa = (InetSocketAddress) |
161 InetSocketAddress isa = dc.remoteAddress(); |
165 dc.remoteAddress(); |
|
166 p.setPort(isa.getPort()); |
162 p.setPort(isa.getPort()); |
167 p.setAddress(isa.getAddress()); |
163 p.setAddress(isa.getAddress()); |
168 dc.write(bb); |
164 dc.write(bb); |
169 } else { |
165 } else { |
170 // Target address may not match connected address |
166 // Target address may not match connected address |
179 Net.translateException(x); |
175 Net.translateException(x); |
180 } |
176 } |
181 } |
177 } |
182 } |
178 } |
183 |
179 |
184 // Must hold dc.blockingLock() |
|
185 // |
|
186 private SocketAddress receive(ByteBuffer bb) throws IOException { |
180 private SocketAddress receive(ByteBuffer bb) throws IOException { |
187 if (timeout == 0) { |
181 assert Thread.holdsLock(dc.blockingLock()) && dc.isBlocking(); |
|
182 |
|
183 long to = this.timeout; |
|
184 if (to == 0) { |
188 return dc.receive(bb); |
185 return dc.receive(bb); |
189 } |
186 } else { |
190 |
|
191 dc.configureBlocking(false); |
|
192 try { |
|
193 SocketAddress sender; |
|
194 if ((sender = dc.receive(bb)) != null) |
|
195 return sender; |
|
196 long to = timeout; |
|
197 for (;;) { |
187 for (;;) { |
198 if (!dc.isOpen()) |
188 if (!dc.isOpen()) |
199 throw new ClosedChannelException(); |
189 throw new ClosedChannelException(); |
200 long st = System.currentTimeMillis(); |
190 long st = System.currentTimeMillis(); |
201 int result = dc.poll(Net.POLLIN, to); |
191 if (dc.pollRead(to)) { |
202 if (result > 0 && ((result & Net.POLLIN) != 0)) { |
192 return dc.receive(bb); |
203 if ((sender = dc.receive(bb)) != null) |
|
204 return sender; |
|
205 } |
193 } |
206 to -= System.currentTimeMillis() - st; |
194 to -= System.currentTimeMillis() - st; |
207 if (to <= 0) |
195 if (to <= 0) |
208 throw new SocketTimeoutException(); |
196 throw new SocketTimeoutException(); |
209 } |
197 } |
210 } finally { |
|
211 try { |
|
212 dc.configureBlocking(true); |
|
213 } catch (ClosedChannelException e) { } |
|
214 } |
198 } |
215 } |
199 } |
216 |
200 |
217 public void receive(DatagramPacket p) throws IOException { |
201 public void receive(DatagramPacket p) throws IOException { |
218 synchronized (dc.blockingLock()) { |
202 synchronized (dc.blockingLock()) { |
234 } |
218 } |
235 |
219 |
236 public InetAddress getLocalAddress() { |
220 public InetAddress getLocalAddress() { |
237 if (isClosed()) |
221 if (isClosed()) |
238 return null; |
222 return null; |
239 SocketAddress local = dc.localAddress(); |
223 InetSocketAddress local = dc.localAddress(); |
240 if (local == null) |
224 if (local == null) |
241 local = new InetSocketAddress(0); |
225 local = new InetSocketAddress(0); |
242 InetAddress result = ((InetSocketAddress)local).getAddress(); |
226 InetAddress result = local.getAddress(); |
243 SecurityManager sm = System.getSecurityManager(); |
227 SecurityManager sm = System.getSecurityManager(); |
244 if (sm != null) { |
228 if (sm != null) { |
245 try { |
229 try { |
246 sm.checkConnect(result.getHostAddress(), -1); |
230 sm.checkConnect(result.getHostAddress(), -1); |
247 } catch (SecurityException x) { |
231 } catch (SecurityException x) { |