1 // Copyright (c) 2005 Brian Wellington (bwelling (at) xbill.org) 2 3 package org.xbill.DNS; 4 5 import java.io.*; 6 import java.net.*; 7 import java.security.SecureRandom; 8 import java.nio.*; 9 import java.nio.channels.*; 10 11 final class UDPClient extends Client { 12 13 private static final int EPHEMERAL_START = 1024; 14 private static final int EPHEMERAL_STOP = 65535; 15 private static final int EPHEMERAL_RANGE = EPHEMERAL_STOP - EPHEMERAL_START; 16 17 private static SecureRandom prng = new SecureRandom(); 18 private 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 */ 35 static { 36 new Thread(new Runnable() { 37 public void run() { 38 int n = prng.nextInt(); 39 prng_initializing = false; 40 }}).start(); 41 } 42 43 private boolean bound = false; 44 45 public 46 UDPClient(long endTime) throws IOException { 47 super(DatagramChannel.open(), endTime); 48 } 49 50 private void 51 bind_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 84 void 85 bind(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 102 void 103 connect(SocketAddress addr) throws IOException { 104 if (!bound) 105 bind(null); 106 DatagramChannel channel = (DatagramChannel) key.channel(); 107 channel.connect(addr); 108 } 109 110 void 111 send(byte [] data) throws IOException { 112 DatagramChannel channel = (DatagramChannel) key.channel(); 113 verboseLog("UDP write", data); 114 channel.write(ByteBuffer.wrap(data)); 115 } 116 117 byte [] 118 recv(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 140 static byte [] 141 sendrecv(SocketAddress local, SocketAddress remote, byte [] data, int max, 142 long endTime) 143 throws 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 157 static byte [] 158 sendrecv(SocketAddress addr, byte [] data, int max, long endTime) 159 throws IOException 160 { 161 return sendrecv(null, addr, data, max, endTime); 162 } 163 164 } 165