1// Copyright (c) 2005 Brian Wellington (bwelling@xbill.org) 2 3package org.xbill.DNS; 4 5import java.io.*; 6import java.net.*; 7import java.security.SecureRandom; 8import java.nio.*; 9import java.nio.channels.*; 10 11final class UDPClient extends Client { 12 13private static final int EPHEMERAL_START = 1024; 14private static final int EPHEMERAL_STOP = 65535; 15private static final int EPHEMERAL_RANGE = EPHEMERAL_STOP - EPHEMERAL_START; 16 17private static SecureRandom prng = new SecureRandom(); 18private static volatile boolean prng_initializing = true; 19 20/* 21 * On some platforms (Windows), the SecureRandom module initialization involves 22 * a call to InetAddress.getLocalHost(), which can end up here if using a 23 * dnsjava name service provider. 24 * 25 * This can cause problems in multiple ways. 26 * - If the SecureRandom seed generation process calls into here, and this 27 * module attempts to seed the local SecureRandom object, the thread hangs. 28 * - If something else calls InetAddress.getLocalHost(), and that causes this 29 * module to seed the local SecureRandom object, the thread hangs. 30 * 31 * To avoid both of these, check at initialization time to see if InetAddress 32 * is in the call chain. If so, initialize the SecureRandom object in a new 33 * thread, and disable port randomization until it completes. 34 */ 35static { 36 new Thread(new Runnable() { 37 public void run() { 38 int n = prng.nextInt(); 39 prng_initializing = false; 40 }}).start(); 41} 42 43private boolean bound = false; 44 45public 46UDPClient(long endTime) throws IOException { 47 super(DatagramChannel.open(), endTime); 48} 49 50private void 51bind_random(InetSocketAddress addr) throws IOException 52{ 53 if (prng_initializing) { 54 try { 55 Thread.sleep(2); 56 } 57 catch (InterruptedException e) { 58 } 59 if (prng_initializing) 60 return; 61 } 62 63 DatagramChannel channel = (DatagramChannel) key.channel(); 64 InetSocketAddress temp; 65 66 for (int i = 0; i < 1024; i++) { 67 try { 68 int port = prng.nextInt(EPHEMERAL_RANGE) + 69 EPHEMERAL_START; 70 if (addr != null) 71 temp = new InetSocketAddress(addr.getAddress(), 72 port); 73 else 74 temp = new InetSocketAddress(port); 75 channel.socket().bind(temp); 76 bound = true; 77 return; 78 } 79 catch (SocketException e) { 80 } 81 } 82} 83 84void 85bind(SocketAddress addr) throws IOException { 86 if (addr == null || 87 (addr instanceof InetSocketAddress && 88 ((InetSocketAddress)addr).getPort() == 0)) 89 { 90 bind_random((InetSocketAddress) addr); 91 if (bound) 92 return; 93 } 94 95 if (addr != null) { 96 DatagramChannel channel = (DatagramChannel) key.channel(); 97 channel.socket().bind(addr); 98 bound = true; 99 } 100} 101 102void 103connect(SocketAddress addr) throws IOException { 104 if (!bound) 105 bind(null); 106 DatagramChannel channel = (DatagramChannel) key.channel(); 107 channel.connect(addr); 108} 109 110void 111send(byte [] data) throws IOException { 112 DatagramChannel channel = (DatagramChannel) key.channel(); 113 verboseLog("UDP write", data); 114 channel.write(ByteBuffer.wrap(data)); 115} 116 117byte [] 118recv(int max) throws IOException { 119 DatagramChannel channel = (DatagramChannel) key.channel(); 120 byte [] temp = new byte[max]; 121 key.interestOps(SelectionKey.OP_READ); 122 try { 123 while (!key.isReadable()) 124 blockUntil(key, endTime); 125 } 126 finally { 127 if (key.isValid()) 128 key.interestOps(0); 129 } 130 long ret = channel.read(ByteBuffer.wrap(temp)); 131 if (ret <= 0) 132 throw new EOFException(); 133 int len = (int) ret; 134 byte [] data = new byte[len]; 135 System.arraycopy(temp, 0, data, 0, len); 136 verboseLog("UDP read", data); 137 return data; 138} 139 140static byte [] 141sendrecv(SocketAddress local, SocketAddress remote, byte [] data, int max, 142 long endTime) 143throws IOException 144{ 145 UDPClient client = new UDPClient(endTime); 146 try { 147 client.bind(local); 148 client.connect(remote); 149 client.send(data); 150 return client.recv(max); 151 } 152 finally { 153 client.cleanup(); 154 } 155} 156 157static byte [] 158sendrecv(SocketAddress addr, byte [] data, int max, long endTime) 159throws IOException 160{ 161 return sendrecv(null, addr, data, max, endTime); 162} 163 164} 165