📄 nbtaddress.java
字号:
/* jcifs smb client library in Java
* Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcifs.netbios;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.SocketException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import jcifs.Config;
import jcifs.util.Hexdump;
/**
* This class represents a NetBIOS over TCP/IP address. Under normal
* conditions, users of jCIFS need not be concerned with this class as
* name resolution and session services are handled internally by the smb package.
*
* <p> Applications can use the methods <code>getLocalHost</code>,
* <code>getByName</code>, and
* <code>getAllByAddress</code> to create a new NbtAddress instance. This
* class is symmetric with {@link java.net.InetAddress}.
*
* <p><b>About NetBIOS:</b> The NetBIOS name
* service is a dynamic distributed service that allows hosts to resolve
* names by broadcasting a query, directing queries to a server such as
* Samba or WINS. NetBIOS is currently the primary networking layer for
* providing name service, datagram service, and session service to the
* Microsoft Windows platform. A NetBIOS name can be 15 characters long
* and hosts usually registers several names on the network. From a
* Windows command prompt you can see
* what names a host registers with the nbtstat command.
* <p><blockquote><pre>
* C:\>nbtstat -a 192.168.1.15
*
* NetBIOS Remote Machine Name Table
*
* Name Type Status
* ---------------------------------------------
* JMORRIS2 <00> UNIQUE Registered
* BILLING-NY <00> GROUP Registered
* JMORRIS2 <03> UNIQUE Registered
* JMORRIS2 <20> UNIQUE Registered
* BILLING-NY <1E> GROUP Registered
* JMORRIS <03> UNIQUE Registered
*
* MAC Address = 00-B0-34-21-FA-3B
* </blockquote></pre>
* <p> The hostname of this machine is <code>JMORRIS2</code>. It is
* a member of the group(a.k.a workgroup and domain) <code>BILLING-NY</code>. To
* obtain an {@link java.net.InetAddress} for a host one might do:
*
* <pre>
* InetAddress addr = NbtAddress.getByName( "jmorris2" ).getInetAddress();
* </pre>
* <p>From a UNIX platform with Samba installed you can perform similar
* diagnostics using the <code>nmblookup</code> utility.
*
* @author Michael B. Allen
* @see java.net.InetAddress
* @since jcifs-0.1
*/
public final class NbtAddress {
/*
* This is a special name that means all hosts. If you wish to find all hosts
* on a network querying a workgroup group name is the preferred method.
*/
static final String ANY_HOSTS_NAME = "*\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000";
/**
* This is a special name for querying the master browser that serves the
* list of hosts found in "Network Neighborhood".
*/
public static final String MASTER_BROWSER_NAME = "\u0001\u0002__MSBROWSE__\u0002";
/**
* A special generic name specified when connecting to a host for which
* a name is not known. Not all servers respond to this name.
*/
public static final String SMBSERVER_NAME = "*SMBSERVER ";
/**
* A B node only broadcasts name queries. This is the default if a
* nameserver such as WINS or Samba is not specified.
*/
public static final int B_NODE = 0;
/**
* A Point-to-Point node, or P node, unicasts queries to a nameserver
* only. Natrually the <code>jcifs.netbios.nameserver</code> property must
* be set.
*/
public static final int P_NODE = 1;
/**
* Try Broadcast queries first, then try to resolve the name using the
* nameserver.
*/
public static final int M_NODE = 2;
/**
* A Hybrid node tries to resolve a name using the nameserver first. If
* that fails use the broadcast address. This is the default if a nameserver
* is provided. This is the behavior of Microsoft Windows machines.
*/
public static final int H_NODE = 3;
static final InetAddress[] NBNS = Config.getInetAddressArray( "jcifs.netbios.wins", ",", new InetAddress[0] );
/* Construct the shared static client object that will
* conduct all encoding and decoding of NetBIOS name service
* messages as well as socket IO in a synchronized fashon.
*/
private static final NameServiceClient CLIENT = new NameServiceClient();
private static final int DEFAULT_CACHE_POLICY = 30;
private static final int CACHE_POLICY = Config.getInt( "jcifs.netbios.cachePolicy", DEFAULT_CACHE_POLICY );
private static final int FOREVER = -1;
private static int nbnsIndex = 0;
private static final HashMap ADDRESS_CACHE = new HashMap();
private static final HashMap LOOKUP_TABLE = new HashMap();
static final Name UNKNOWN_NAME = new Name( "0.0.0.0", 0x00, null );
static final NbtAddress UNKNOWN_ADDRESS = new NbtAddress( UNKNOWN_NAME, 0, false, B_NODE );
static final byte[] UNKNOWN_MAC_ADDRESS = new byte[] {
(byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00
};
static final class CacheEntry {
Name hostName;
NbtAddress address;
long expiration;
CacheEntry( Name hostName, NbtAddress address, long expiration ) {
this.hostName = hostName;
this.address = address;
this.expiration = expiration;
}
}
static NbtAddress localhost;
static {
InetAddress localInetAddress;
String localHostname;
Name localName;
/* Create an address to represent failed lookups and cache forever.
*/
ADDRESS_CACHE.put( UNKNOWN_NAME, new CacheEntry( UNKNOWN_NAME, UNKNOWN_ADDRESS, FOREVER ));
/* Determine the InetAddress of the local interface
* if one was not specified.
*/
localInetAddress = CLIENT.laddr;
if( localInetAddress == null ) {
try {
localInetAddress = InetAddress.getLocalHost();
} catch( UnknownHostException uhe ) {
}
}
/* If a local hostname was not provided a name like
* JCIFS34_172_A6 will be dynamically generated for the
* client. This is primarily (exclusively?) used as a
* CallingName during session establishment.
*/
localHostname = Config.getProperty( "jcifs.netbios.hostname", null );
if( localHostname == null || localHostname.length() == 0 ) {
byte[] addr = localInetAddress.getAddress();
localHostname = "JCIFS" +
( addr[2] & 0xFF ) + "_" +
( addr[3] & 0xFF ) + "_" +
Hexdump.toHexString( (int)( Math.random() * (double)0xFF ), 2 );
}
/* Create an NbtAddress for the local interface with
* the name deduced above possibly with scope applied and
* cache it forever.
*/
localName = new Name( localHostname, 0x00,
Config.getProperty( "jcifs.netbios.scope", null ));
localhost = new NbtAddress( localName,
localInetAddress.hashCode(),
false,
B_NODE,
false, false, true, false,
UNKNOWN_MAC_ADDRESS );
cacheAddress( localName, localhost, FOREVER );
}
static void cacheAddress( Name hostName, NbtAddress addr ) {
if( CACHE_POLICY == 0 ) {
return;
}
long expiration = -1;
if( CACHE_POLICY != FOREVER ) {
expiration = System.currentTimeMillis() + CACHE_POLICY * 1000;
}
cacheAddress( hostName, addr, expiration );
}
static void cacheAddress( Name hostName, NbtAddress addr, long expiration ) {
if( CACHE_POLICY == 0 ) {
return;
}
synchronized( ADDRESS_CACHE ) {
CacheEntry entry = (CacheEntry)ADDRESS_CACHE.get( hostName );
if( entry == null ) {
entry = new CacheEntry( hostName, addr, expiration );
ADDRESS_CACHE.put( hostName, entry );
} else {
entry.address = addr;
entry.expiration = expiration;
}
}
}
static void cacheAddressArray( NbtAddress[] addrs ) {
if( CACHE_POLICY == 0 ) {
return;
}
long expiration = -1;
if( CACHE_POLICY != FOREVER ) {
expiration = System.currentTimeMillis() + CACHE_POLICY * 1000;
}
synchronized( ADDRESS_CACHE ) {
for( int i = 0; i < addrs.length; i++ ) {
CacheEntry entry = (CacheEntry)ADDRESS_CACHE.get( addrs[i].hostName );
if( entry == null ) {
entry = new CacheEntry( addrs[i].hostName, addrs[i], expiration );
ADDRESS_CACHE.put( addrs[i].hostName, entry );
} else {
entry.address = addrs[i];
entry.expiration = expiration;
}
}
}
}
static NbtAddress getCachedAddress( Name hostName ) {
if( CACHE_POLICY == 0 ) {
return null;
}
synchronized( ADDRESS_CACHE ) {
CacheEntry entry = (CacheEntry)ADDRESS_CACHE.get( hostName );
if( entry != null && entry.expiration < System.currentTimeMillis() &&
entry.expiration >= 0 ) {
entry = null;
}
return entry != null ? entry.address : null;
}
}
static NbtAddress doNameQuery( Name name, InetAddress svr )
throws UnknownHostException {
NbtAddress addr;
if( name.hexCode == 0x1d && svr == null ) {
svr = CLIENT.baddr; // bit of a hack but saves a lookup
}
name.srcHashCode = svr != null ? svr.hashCode() : 0;
addr = getCachedAddress( name );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -