1 18 19 package com.knowgate.jcifs.netbios; 20 21 import java.net.InetAddress ; 22 import java.net.DatagramSocket ; 23 import java.net.DatagramPacket ; 24 import java.net.UnknownHostException ; 25 import java.io.IOException ; 26 import java.io.InterruptedIOException ; 27 import java.util.HashMap ; 28 import java.util.StringTokenizer ; 29 30 import com.knowgate.debug.*; 31 import com.knowgate.misc.Gadgets; 32 import com.knowgate.jcifs.Config; 33 34 class NameServiceClient implements Runnable { 35 36 static final int DEFAULT_SO_TIMEOUT = 5000; 37 static final int DEFAULT_RCV_BUF_SIZE = 576; 38 static final int DEFAULT_SND_BUF_SIZE = 576; 39 static final int NAME_SERVICE_UDP_PORT = 137; 40 static final int DEFAULT_RETRY_COUNT = 2; 41 static final int DEFAULT_RETRY_TIMEOUT = 3000; 42 43 static final int RESOLVER_LMHOSTS = 1; 44 static final int RESOLVER_BCAST = 2; 45 static final int RESOLVER_WINS = 3; 46 47 private static final int SND_BUF_SIZE = Config.getInt( "jcifs.netbios.snd_buf_size", DEFAULT_SND_BUF_SIZE ); 48 private static final int RCV_BUF_SIZE = Config.getInt( "jcifs.netbios.rcv_buf_size", DEFAULT_RCV_BUF_SIZE ); 49 private static final int SO_TIMEOUT = Config.getInt( "jcifs.netbios.soTimeout", DEFAULT_SO_TIMEOUT ); 50 private static final int RETRY_COUNT = Config.getInt( "jcifs.netbios.retryCount", DEFAULT_RETRY_COUNT ); 51 private static final int RETRY_TIMEOUT = Config.getInt( "jcifs.netbios.retryTimeout", DEFAULT_RETRY_TIMEOUT); 52 private static final int LPORT = Config.getInt( "jcifs.netbios.lport", 0 ); 53 private static final InetAddress LADDR = Config.getInetAddress( "jcifs.netbios.laddr", null ); 54 private static final String RO = Config.getProperty( "jcifs.resolveOrder" ); 55 56 private final Object LOCK = new Object (); 57 58 private int lport, closeTimeout; 59 private byte[] snd_buf, rcv_buf; 60 private DatagramSocket socket; 61 private DatagramPacket in, out; 62 private HashMap responseTable = new HashMap (); 63 private Thread thread; 64 private int nextNameTrnId = 0; 65 private int[] resolveOrder; 66 67 InetAddress laddr, baddr; 68 69 NameServiceClient() { 70 this( LPORT, LADDR ); 71 } 72 NameServiceClient( int lport, InetAddress laddr ) { 73 this.lport = lport; 74 this.laddr = laddr; 75 76 try { 77 baddr = Config.getInetAddress( "jcifs.netbios.baddr", 78 InetAddress.getByName( "255.255.255.255" )); 79 } catch( UnknownHostException uhe ) { 80 } 81 82 snd_buf = new byte[SND_BUF_SIZE]; 83 rcv_buf = new byte[RCV_BUF_SIZE]; 84 out = new DatagramPacket ( snd_buf, SND_BUF_SIZE, baddr, NAME_SERVICE_UDP_PORT ); 85 in = new DatagramPacket ( rcv_buf, RCV_BUF_SIZE ); 86 87 if( RO == null || RO.length() == 0 ) { 88 89 94 95 if( NbtAddress.getWINSAddress() == null ) { 96 resolveOrder = new int[2]; 97 resolveOrder[0] = RESOLVER_LMHOSTS; 98 resolveOrder[1] = RESOLVER_BCAST; 99 } else { 100 resolveOrder = new int[3]; 101 resolveOrder[0] = RESOLVER_LMHOSTS; 102 resolveOrder[1] = RESOLVER_WINS; 103 resolveOrder[2] = RESOLVER_BCAST; 104 } 105 } else { 106 int[] tmp = new int[3]; 107 StringTokenizer st = new StringTokenizer ( RO, "," ); 108 int i = 0; 109 while( st.hasMoreTokens() ) { 110 String s = st.nextToken().trim(); 111 if( s.equalsIgnoreCase( "LMHOSTS" )) { 112 tmp[i++] = RESOLVER_LMHOSTS; 113 } else if( s.equalsIgnoreCase( "WINS" )) { 114 if( NbtAddress.getWINSAddress() == null ) { 115 if( DebugFile.trace ) { 116 DebugFile.writeln( "NetBIOS resolveOrder specifies WINS however the " + 117 "jcifs.netbios.wins property has not been set" ); 118 } 119 continue; 120 } 121 tmp[i++] = RESOLVER_WINS; 122 } else if( s.equalsIgnoreCase( "BCAST" )) { 123 tmp[i++] = RESOLVER_BCAST; 124 } else if( s.equalsIgnoreCase( "DNS" )) { 125 ; } else if( DebugFile.trace ) { 127 DebugFile.writeln( "unknown resolver method: " + s ); 128 } 129 } 130 resolveOrder = new int[i]; 131 System.arraycopy( tmp, 0, resolveOrder, 0, i ); 132 } 133 } 134 135 int getNextNameTrnId() { 136 if(( ++nextNameTrnId & 0xFFFF ) == 0 ) { 137 nextNameTrnId = 1; 138 } 139 return nextNameTrnId; 140 } 141 void ensureOpen( int timeout ) throws IOException { 142 closeTimeout = 0; 143 if( SO_TIMEOUT != 0 ) { 144 closeTimeout = Math.max( SO_TIMEOUT, timeout ); 145 } 146 if( socket == null ) { 149 socket = new DatagramSocket ( lport, laddr ); 150 thread = new Thread ( this, "JCIFS-NameServiceClient" ); 151 thread.setDaemon( true ); 152 thread.start(); 153 } 154 } 155 void tryClose() { 156 synchronized( LOCK ) { 157 158 165 166 if( socket != null ) { 167 socket.close(); 168 socket = null; 169 } 170 thread = null; 171 responseTable.clear(); 172 } 173 } 174 public void run() { 175 int nameTrnId; 176 NameServicePacket response; 177 178 while( thread == Thread.currentThread() ) { 179 in.setLength( RCV_BUF_SIZE ); 180 try { 181 socket.setSoTimeout( closeTimeout ); 182 socket.receive( in ); 183 } catch( IOException ioe ) { 184 tryClose(); 185 break; 186 } 187 188 if( DebugFile.trace ) 189 DebugFile.writeln( "NetBIOS: new data read from socket" ); 190 191 nameTrnId = NameServicePacket.readNameTrnId( rcv_buf, 0 ); 192 response = (NameServicePacket)responseTable.get( new Integer ( nameTrnId )); 193 if( response == null || response.received ) { 194 continue; 195 } 196 synchronized( response ) { 197 response.readWireFormat( rcv_buf, 0 ); 198 response.received = true; 199 200 response.notify(); 201 } 202 } 203 } 204 void send( NameServicePacket request, NameServicePacket response, 205 int timeout ) throws IOException { 206 Integer nid = null; 207 int count = 0; 208 209 synchronized( response ) { 210 do { 211 try { 212 synchronized( LOCK ) { 213 request.nameTrnId = getNextNameTrnId(); 214 nid = new Integer ( request.nameTrnId ); 215 216 out.setAddress( request.addr ); 217 out.setLength( request.writeWireFormat( snd_buf, 0 )); 218 response.received = false; 219 220 responseTable.put( nid, response ); 221 ensureOpen( timeout + 1000 ); 222 socket.send( out ); 223 224 } 225 226 response.wait( timeout ); 227 228 } catch( InterruptedException ie ) { 229 } finally { 230 responseTable.remove( nid ); 231 } 232 233 if( !response.received && 234 NbtAddress.NBNS.length > 1 && 235 NbtAddress.isWINS( request.addr )) { 236 240 request.addr = NbtAddress.switchWINS(); 241 if( count == 0 ) { 242 count = NbtAddress.NBNS.length - 1; 243 } 244 } 245 } while( count-- > 0 ); 246 } 247 } 248 249 NbtAddress getByName( Name name, InetAddress addr ) 250 throws UnknownHostException { 251 int n; 252 NameQueryRequest request = new NameQueryRequest( name ); 253 NameQueryResponse response = new NameQueryResponse(); 254 255 if( addr != null ) { 258 request.addr = addr; 259 request.isBroadcast = (addr.getAddress()[3] == (byte)0xFF); 260 261 n = RETRY_COUNT; 262 do { 263 try { 264 send( request, response, RETRY_TIMEOUT ); 265 } catch( IOException ioe ) { 266 if( DebugFile.trace ) 267 new ErrorHandler (ioe); 268 throw new UnknownHostException ( name.name ); 269 } 270 271 if( response.received && response.resultCode == 0 ) { 272 response.addrEntry.hostName.srcHashCode = addr.hashCode(); 273 return response.addrEntry; 274 } 275 } while( --n > 0 && request.isBroadcast ); 276 277 throw new UnknownHostException ( name.name ); 278 } 279 280 283 284 for( int i = 0; i < resolveOrder.length; i++ ) { 285 try { 286 switch( resolveOrder[i] ) { 287 case RESOLVER_LMHOSTS: 288 NbtAddress ans = Lmhosts.getByName( name ); 289 if( ans != null ) { 290 ans.hostName.srcHashCode = 0; return ans; 293 } 294 break; 295 case RESOLVER_WINS: 296 case RESOLVER_BCAST: 297 if( resolveOrder[i] == RESOLVER_WINS && 298 name.name != NbtAddress.MASTER_BROWSER_NAME && 299 name.hexCode != 0x1d ) { 300 request.addr = NbtAddress.getWINSAddress(); 301 request.isBroadcast = false; 302 } else { 303 request.addr = baddr; 304 request.isBroadcast = true; 305 } 306 307 n = RETRY_COUNT; 308 while( n-- > 0 ) { 309 try { 310 send( request, response, RETRY_TIMEOUT ); 311 } catch( IOException ioe ) { 312 if( DebugFile.trace ) 313 new ErrorHandler(ioe); 314 throw new UnknownHostException ( name.name ); 315 } 316 if( response.received && response.resultCode == 0 ) { 317 318 323 response.addrEntry.hostName.srcHashCode = 324 request.addr.hashCode(); 325 return response.addrEntry; 326 } else if( resolveOrder[i] == RESOLVER_WINS ) { 327 329 break; 330 } 331 } 332 break; 333 } 334 } catch( IOException ioe ) { 335 } 336 } 337 throw new UnknownHostException ( name.name ); 338 } 339 NbtAddress[] getNodeStatus( NbtAddress addr ) throws UnknownHostException { 340 int n, srcHashCode; 341 NodeStatusRequest request; 342 NodeStatusResponse response; 343 344 response = new NodeStatusResponse( addr ); 345 request = new NodeStatusRequest( 346 new Name( NbtAddress.ANY_HOSTS_NAME, 0x00, null)); 347 request.addr = addr.getInetAddress(); 348 349 n = RETRY_COUNT; 350 while( n-- > 0 ) { 351 try { 352 send( request, response, RETRY_TIMEOUT ); 353 } catch( IOException ioe ) { 354 if( DebugFile.trace ) 355 new ErrorHandler(ioe); 356 throw new UnknownHostException ( addr.toString() ); 357 } 358 if( response.received && response.resultCode == 0 ) { 359 360 372 373 srcHashCode = request.addr.hashCode(); 374 for( int i = 0; i < response.addressArray.length; i++ ) { 375 response.addressArray[i].hostName.srcHashCode = srcHashCode; 376 } 377 return response.addressArray; 378 } 379 } 380 throw new UnknownHostException ( addr.hostName.name ); 381 } 382 } 383 | Popular Tags |