1 /* 2 * Copyright (c) 2001, 2018, 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 26 package sun.nio.ch; 27 28 import java.io.IOException; 29 import java.net.DatagramPacket; 30 import java.net.DatagramSocket; 31 import java.net.DatagramSocketImpl; 32 import java.net.InetAddress; 33 import java.net.InetSocketAddress; 34 import java.net.NetworkInterface; 35 import java.net.SocketAddress; 36 import java.net.SocketException; 37 import java.net.SocketOption; 38 import java.net.SocketTimeoutException; 39 import java.net.StandardSocketOptions; 40 import java.nio.ByteBuffer; 41 import java.nio.channels.ClosedChannelException; 42 import java.nio.channels.DatagramChannel; 43 import java.nio.channels.IllegalBlockingModeException; 44 45 46 // Make a datagram-socket channel look like a datagram socket. 47 // 48 // The methods in this class are defined in exactly the same order as in 49 // java.net.DatagramSocket so as to simplify tracking future changes to that 50 // class. 51 // 52 53 public class DatagramSocketAdaptor 54 extends DatagramSocket 55 { 56 57 // The channel being adapted 58 private final DatagramChannelImpl dc; 59 60 // Timeout "option" value for receives 61 private volatile int timeout; 62 63 // ## super will create a useless impl 64 private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException { 65 // Invoke the DatagramSocketAdaptor(SocketAddress) constructor, 66 // passing a dummy DatagramSocketImpl object to aovid any native 67 // resource allocation in super class and invoking our bind method 68 // before the dc field is initialized. 69 super(dummyDatagramSocket); 70 this.dc = dc; 71 } 72 73 public static DatagramSocket create(DatagramChannelImpl dc) { 74 try { 75 return new DatagramSocketAdaptor(dc); 76 } catch (IOException x) { 77 throw new Error(x); 78 } 79 } 80 81 private void connectInternal(SocketAddress remote) 82 throws SocketException 83 { 84 InetSocketAddress isa = Net.asInetSocketAddress(remote); 85 int port = isa.getPort(); 86 if (port < 0 || port > 0xFFFF) 87 throw new IllegalArgumentException("connect: " + port); 88 if (remote == null) 89 throw new IllegalArgumentException("connect: null address"); 90 if (isClosed()) 91 return; 92 try { 93 dc.connect(remote); 94 } catch (Exception x) { 95 Net.translateToSocketException(x); 96 } 97 } 98 99 public void bind(SocketAddress local) throws SocketException { 100 try { 101 if (local == null) 102 local = new InetSocketAddress(0); 103 dc.bind(local); 104 } catch (Exception x) { 105 Net.translateToSocketException(x); 106 } 107 } 108 109 public void connect(InetAddress address, int port) { 110 try { 111 connectInternal(new InetSocketAddress(address, port)); 112 } catch (SocketException x) { 113 // Yes, j.n.DatagramSocket really does this 114 } 115 } 116 117 public void connect(SocketAddress remote) throws SocketException { 118 if (remote == null) 119 throw new IllegalArgumentException("Address can't be null"); 120 connectInternal(remote); 121 } 122 123 public void disconnect() { 124 try { 125 dc.disconnect(); 126 } catch (IOException x) { 127 throw new Error(x); 128 } 129 } 130 131 public boolean isBound() { 132 return dc.localAddress() != null; 133 } 134 135 public boolean isConnected() { 136 return dc.remoteAddress() != null; 137 } 138 139 public InetAddress getInetAddress() { 140 return (isConnected() 141 ? Net.asInetSocketAddress(dc.remoteAddress()).getAddress() 142 : null); 143 } 144 145 public int getPort() { 146 return (isConnected() 147 ? Net.asInetSocketAddress(dc.remoteAddress()).getPort() 148 : -1); 149 } 150 151 public void send(DatagramPacket p) throws IOException { 152 synchronized (dc.blockingLock()) { 153 if (!dc.isBlocking()) 154 throw new IllegalBlockingModeException(); 155 try { 156 synchronized (p) { 157 ByteBuffer bb = ByteBuffer.wrap(p.getData(), 158 p.getOffset(), 159 p.getLength()); 160 if (dc.isConnected()) { 161 if (p.getAddress() == null) { 162 // Legacy DatagramSocket will send in this case 163 // and set address and port of the packet 164 InetSocketAddress isa = (InetSocketAddress) 165 dc.remoteAddress(); 166 p.setPort(isa.getPort()); 167 p.setAddress(isa.getAddress()); 168 dc.write(bb); 169 } else { 170 // Target address may not match connected address 171 dc.send(bb, p.getSocketAddress()); 172 } 173 } else { 174 // Not connected so address must be valid or throw 175 dc.send(bb, p.getSocketAddress()); 176 } 177 } 178 } catch (IOException x) { 179 Net.translateException(x); 180 } 181 } 182 } 183 184 // Must hold dc.blockingLock() 185 // 186 private SocketAddress receive(ByteBuffer bb) throws IOException { 187 if (timeout == 0) { 188 return dc.receive(bb); 189 } 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 (;;) { 198 if (!dc.isOpen()) 199 throw new ClosedChannelException(); 200 long st = System.currentTimeMillis(); 201 int result = dc.poll(Net.POLLIN, to); 202 if (result > 0 && ((result & Net.POLLIN) != 0)) { 203 if ((sender = dc.receive(bb)) != null) 204 return sender; 205 } 206 to -= System.currentTimeMillis() - st; 207 if (to <= 0) 208 throw new SocketTimeoutException(); 209 } 210 } finally { 211 try { 212 dc.configureBlocking(true); 213 } catch (ClosedChannelException e) { } 214 } 215 } 216 217 public void receive(DatagramPacket p) throws IOException { 218 synchronized (dc.blockingLock()) { 219 if (!dc.isBlocking()) 220 throw new IllegalBlockingModeException(); 221 try { 222 synchronized (p) { 223 ByteBuffer bb = ByteBuffer.wrap(p.getData(), 224 p.getOffset(), 225 p.getLength()); 226 SocketAddress sender = receive(bb); 227 p.setSocketAddress(sender); 228 p.setLength(bb.position() - p.getOffset()); 229 } 230 } catch (IOException x) { 231 Net.translateException(x); 232 } 233 } 234 } 235 236 public InetAddress getLocalAddress() { 237 if (isClosed()) 238 return null; 239 SocketAddress local = dc.localAddress(); 240 if (local == null) 241 local = new InetSocketAddress(0); 242 InetAddress result = ((InetSocketAddress)local).getAddress(); 243 SecurityManager sm = System.getSecurityManager(); 244 if (sm != null) { 245 try { 246 sm.checkConnect(result.getHostAddress(), -1); 247 } catch (SecurityException x) { 248 return new InetSocketAddress(0).getAddress(); 249 } 250 } 251 return result; 252 } 253 254 public int getLocalPort() { 255 if (isClosed()) 256 return -1; 257 try { 258 SocketAddress local = dc.getLocalAddress(); 259 if (local != null) { 260 return ((InetSocketAddress)local).getPort(); 261 } 262 } catch (Exception x) { 263 } 264 return 0; 265 } 266 267 public void setSoTimeout(int timeout) throws SocketException { 268 this.timeout = timeout; 269 } 270 271 public int getSoTimeout() throws SocketException { 272 return timeout; 273 } 274 275 private void setBooleanOption(SocketOption<Boolean> name, boolean value) 276 throws SocketException 277 { 278 try { 279 dc.setOption(name, value); 280 } catch (IOException x) { 281 Net.translateToSocketException(x); 282 } 283 } 284 285 private void setIntOption(SocketOption<Integer> name, int value) 286 throws SocketException 287 { 288 try { 289 dc.setOption(name, value); 290 } catch (IOException x) { 291 Net.translateToSocketException(x); 292 } 293 } 294 295 private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException { 296 try { 297 return dc.getOption(name).booleanValue(); 298 } catch (IOException x) { 299 Net.translateToSocketException(x); 300 return false; // keep compiler happy 301 } 302 } 303 304 private int getIntOption(SocketOption<Integer> name) throws SocketException { 305 try { 306 return dc.getOption(name).intValue(); 307 } catch (IOException x) { 308 Net.translateToSocketException(x); 309 return -1; // keep compiler happy 310 } 311 } 312 313 public void setSendBufferSize(int size) throws SocketException { 314 if (size <= 0) 315 throw new IllegalArgumentException("Invalid send size"); 316 setIntOption(StandardSocketOptions.SO_SNDBUF, size); 317 } 318 319 public int getSendBufferSize() throws SocketException { 320 return getIntOption(StandardSocketOptions.SO_SNDBUF); 321 } 322 323 public void setReceiveBufferSize(int size) throws SocketException { 324 if (size <= 0) 325 throw new IllegalArgumentException("Invalid receive size"); 326 setIntOption(StandardSocketOptions.SO_RCVBUF, size); 327 } 328 329 public int getReceiveBufferSize() throws SocketException { 330 return getIntOption(StandardSocketOptions.SO_RCVBUF); 331 } 332 333 public void setReuseAddress(boolean on) throws SocketException { 334 setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on); 335 } 336 337 public boolean getReuseAddress() throws SocketException { 338 return getBooleanOption(StandardSocketOptions.SO_REUSEADDR); 339 340 } 341 342 public void setBroadcast(boolean on) throws SocketException { 343 setBooleanOption(StandardSocketOptions.SO_BROADCAST, on); 344 } 345 346 public boolean getBroadcast() throws SocketException { 347 return getBooleanOption(StandardSocketOptions.SO_BROADCAST); 348 } 349 350 public void setTrafficClass(int tc) throws SocketException { 351 setIntOption(StandardSocketOptions.IP_TOS, tc); 352 } 353 354 public int getTrafficClass() throws SocketException { 355 return getIntOption(StandardSocketOptions.IP_TOS); 356 } 357 358 public void close() { 359 try { 360 dc.close(); 361 } catch (IOException x) { 362 throw new Error(x); 363 } 364 } 365 366 public boolean isClosed() { 367 return !dc.isOpen(); 368 } 369 370 public DatagramChannel getChannel() { 371 return dc; 372 } 373 374 /* 375 * A dummy implementation of DatagramSocketImpl that can be passed to the 376 * DatagramSocket constructor so that no native resources are allocated in 377 * super class. 378 */ 379 private static final DatagramSocketImpl dummyDatagramSocket 380 = new DatagramSocketImpl() 381 { 382 protected void create() throws SocketException {} 383 384 protected void bind(int lport, InetAddress laddr) throws SocketException {} 385 386 protected void send(DatagramPacket p) throws IOException {} 387 388 protected int peek(InetAddress i) throws IOException { return 0; } 389 390 protected int peekData(DatagramPacket p) throws IOException { return 0; } 391 392 protected void receive(DatagramPacket p) throws IOException {} 393 394 @Deprecated 395 protected void setTTL(byte ttl) throws IOException {} 396 397 @Deprecated 398 protected byte getTTL() throws IOException { return 0; } 399 400 protected void setTimeToLive(int ttl) throws IOException {} 401 402 protected int getTimeToLive() throws IOException { return 0;} 403 404 protected void join(InetAddress inetaddr) throws IOException {} 405 406 protected void leave(InetAddress inetaddr) throws IOException {} 407 408 protected void joinGroup(SocketAddress mcastaddr, 409 NetworkInterface netIf) throws IOException {} 410 411 protected void leaveGroup(SocketAddress mcastaddr, 412 NetworkInterface netIf) throws IOException {} 413 414 protected void close() {} 415 416 public Object getOption(int optID) throws SocketException { return null;} 417 418 public void setOption(int optID, Object value) throws SocketException {} 419 }; 420 }