1/* 2 * Copyright (c) 2001, 2010, 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 26package sun.nio.ch; 27 28import java.io.*; 29import java.net.*; 30import java.nio.*; 31import 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 41public 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 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 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 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 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 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 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 111 public void disconnect() { 112 try { 113 dc.disconnect(); 114 } catch (IOException x) { 115 throw new Error(x); 116 } 117 } 118 119 public boolean isBound() { 120 return dc.localAddress() != null; 121 } 122 123 public boolean isConnected() { 124 return dc.remoteAddress() != null; 125 } 126 127 public InetAddress getInetAddress() { 128 return (isConnected() 129 ? Net.asInetSocketAddress(dc.remoteAddress()).getAddress() 130 : null); 131 } 132 133 public int getPort() { 134 return (isConnected() 135 ? Net.asInetSocketAddress(dc.remoteAddress()).getPort() 136 : -1); 137 } 138 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 // 174 private SocketAddress receive(ByteBuffer bb) throws IOException { 175 if (timeout == 0) { 176 return dc.receive(bb); 177 } 178 179 // Implement timeout with a selector 180 SelectionKey sk = null; 181 Selector sel = null; 182 dc.configureBlocking(false); 183 try { 184 int n; 185 SocketAddress sender; 186 if ((sender = dc.receive(bb)) != null) 187 return sender; 188 sel = Util.getTemporarySelector(dc); 189 sk = dc.register(sel, SelectionKey.OP_READ); 190 long to = timeout; 191 for (;;) { 192 if (!dc.isOpen()) 193 throw new ClosedChannelException(); 194 long st = System.currentTimeMillis(); 195 int ns = sel.select(to); 196 if (ns > 0 && sk.isReadable()) { 197 if ((sender = dc.receive(bb)) != null) 198 return sender; 199 } 200 sel.selectedKeys().remove(sk); 201 to -= System.currentTimeMillis() - st; 202 if (to <= 0) 203 throw new SocketTimeoutException(); 204 205 } 206 } finally { 207 if (sk != null) 208 sk.cancel(); 209 if (dc.isOpen()) 210 dc.configureBlocking(true); 211 if (sel != null) 212 Util.releaseTemporarySelector(sel); 213 } 214 } 215 216 public void receive(DatagramPacket p) throws IOException { 217 synchronized (dc.blockingLock()) { 218 if (!dc.isBlocking()) 219 throw new IllegalBlockingModeException(); 220 try { 221 synchronized (p) { 222 ByteBuffer bb = ByteBuffer.wrap(p.getData(), 223 p.getOffset(), 224 p.getLength()); 225 SocketAddress sender = receive(bb); 226 p.setSocketAddress(sender); 227 p.setLength(bb.position() - p.getOffset()); 228 } 229 } catch (IOException x) { 230 Net.translateException(x); 231 } 232 } 233 } 234 235 public InetAddress getLocalAddress() { 236 if (isClosed()) 237 return null; 238 SocketAddress local = dc.localAddress(); 239 if (local == null) 240 local = new InetSocketAddress(0); 241 InetAddress result = ((InetSocketAddress)local).getAddress(); 242 SecurityManager sm = System.getSecurityManager(); 243 if (sm != null) { 244 try { 245 sm.checkConnect(result.getHostAddress(), -1); 246 } catch (SecurityException x) { 247 return new InetSocketAddress(0).getAddress(); 248 } 249 } 250 return result; 251 } 252 253 public int getLocalPort() { 254 if (isClosed()) 255 return -1; 256 try { 257 SocketAddress local = dc.getLocalAddress(); 258 if (local != null) { 259 return ((InetSocketAddress)local).getPort(); 260 } 261 } catch (Exception x) { 262 } 263 return 0; 264 } 265 266 public void setSoTimeout(int timeout) throws SocketException { 267 this.timeout = timeout; 268 } 269 270 public int getSoTimeout() throws SocketException { 271 return timeout; 272 } 273 274 private void setBooleanOption(SocketOption<Boolean> name, boolean value) 275 throws SocketException 276 { 277 try { 278 dc.setOption(name, value); 279 } catch (IOException x) { 280 Net.translateToSocketException(x); 281 } 282 } 283 284 private void setIntOption(SocketOption<Integer> name, int value) 285 throws SocketException 286 { 287 try { 288 dc.setOption(name, value); 289 } catch (IOException x) { 290 Net.translateToSocketException(x); 291 } 292 } 293 294 private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException { 295 try { 296 return dc.getOption(name).booleanValue(); 297 } catch (IOException x) { 298 Net.translateToSocketException(x); 299 return false; // keep compiler happy 300 } 301 } 302 303 private int getIntOption(SocketOption<Integer> name) throws SocketException { 304 try { 305 return dc.getOption(name).intValue(); 306 } catch (IOException x) { 307 Net.translateToSocketException(x); 308 return -1; // keep compiler happy 309 } 310 } 311 312 public void setSendBufferSize(int size) throws SocketException { 313 if (size <= 0) 314 throw new IllegalArgumentException("Invalid send size"); 315 setIntOption(StandardSocketOptions.SO_SNDBUF, size); 316 } 317 318 public int getSendBufferSize() throws SocketException { 319 return getIntOption(StandardSocketOptions.SO_SNDBUF); 320 } 321 322 public void setReceiveBufferSize(int size) throws SocketException { 323 if (size <= 0) 324 throw new IllegalArgumentException("Invalid receive size"); 325 setIntOption(StandardSocketOptions.SO_RCVBUF, size); 326 } 327 328 public int getReceiveBufferSize() throws SocketException { 329 return getIntOption(StandardSocketOptions.SO_RCVBUF); 330 } 331 332 public void setReuseAddress(boolean on) throws SocketException { 333 setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on); 334 } 335 336 public boolean getReuseAddress() throws SocketException { 337 return getBooleanOption(StandardSocketOptions.SO_REUSEADDR); 338 339 } 340 341 public void setBroadcast(boolean on) throws SocketException { 342 setBooleanOption(StandardSocketOptions.SO_BROADCAST, on); 343 } 344 345 public boolean getBroadcast() throws SocketException { 346 return getBooleanOption(StandardSocketOptions.SO_BROADCAST); 347 } 348 349 public void setTrafficClass(int tc) throws SocketException { 350 setIntOption(StandardSocketOptions.IP_TOS, tc); 351 } 352 353 public int getTrafficClass() throws SocketException { 354 return getIntOption(StandardSocketOptions.IP_TOS); 355 } 356 357 public void close() { 358 try { 359 dc.close(); 360 } catch (IOException x) { 361 throw new Error(x); 362 } 363 } 364 365 public boolean isClosed() { 366 return !dc.isOpen(); 367 } 368 369 public DatagramChannel getChannel() { 370 return dc; 371 } 372 373 /** @hide */ 374 @Override 375 public final FileDescriptor getFileDescriptor$() { 376 return dc.fd; 377 } 378 379 /* 380 * A dummy implementation of DatagramSocketImpl that can be passed to the 381 * DatagramSocket constructor so that no native resources are allocated in 382 * super class. 383 */ 384 private static final DatagramSocketImpl dummyDatagramSocket 385 = new DatagramSocketImpl() 386 { 387 protected void create() throws SocketException {} 388 389 protected void bind(int lport, InetAddress laddr) throws SocketException {} 390 391 protected void send(DatagramPacket p) throws IOException {} 392 393 protected int peek(InetAddress i) throws IOException { return 0; } 394 395 protected int peekData(DatagramPacket p) throws IOException { return 0; } 396 397 protected void receive(DatagramPacket p) throws IOException {} 398 399 protected void setTTL(byte ttl) throws IOException {} 400 401 protected byte getTTL() throws IOException { return 0; } 402 403 protected void setTimeToLive(int ttl) throws IOException {} 404 405 protected int getTimeToLive() throws IOException { return 0;} 406 407 protected void join(InetAddress inetaddr) throws IOException {} 408 409 protected void leave(InetAddress inetaddr) throws IOException {} 410 411 protected void joinGroup(SocketAddress mcastaddr, 412 NetworkInterface netIf) throws IOException {} 413 414 protected void leaveGroup(SocketAddress mcastaddr, 415 NetworkInterface netIf) throws IOException {} 416 417 protected void close() {} 418 419 public Object getOption(int optID) throws SocketException { return null;} 420 421 public void setOption(int optID, Object value) throws SocketException {} 422 }; 423} 424