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