FileDocCategorySizeDatePackage
NbtAddress.javaAPI DocJCIFS 1.3.17 API31678Tue Oct 18 15:26:24 BST 2011jcifs.netbios

NbtAddress

public final class NbtAddress extends Object
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.

Applications can use the methods getLocalHost, getByName, and getAllByAddress to create a new NbtAddress instance. This class is symmetric with {@link java.net.InetAddress}.

About NetBIOS: 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.

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

The hostname of this machine is JMORRIS2. It is a member of the group(a.k.a workgroup and domain) BILLING-NY. To obtain an {@link java.net.InetAddress} for a host one might do:

InetAddress addr = NbtAddress.getByName( "jmorris2" ).getInetAddress();

From a UNIX platform with Samba installed you can perform similar diagnostics using the nmblookup utility.

author
Michael B. Allen
see
java.net.InetAddress
since
jcifs-0.1

Fields Summary
static final String
ANY_HOSTS_NAME
public static final String
MASTER_BROWSER_NAME
This is a special name for querying the master browser that serves the list of hosts found in "Network Neighborhood".
public static final String
SMBSERVER_NAME
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 int
B_NODE
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
P_NODE
A Point-to-Point node, or P node, unicasts queries to a nameserver only. Natrually the jcifs.netbios.nameserver property must be set.
public static final int
M_NODE
Try Broadcast queries first, then try to resolve the name using the nameserver.
public static final int
H_NODE
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.
static final InetAddress[]
NBNS
private static final NameServiceClient
CLIENT
private static final int
DEFAULT_CACHE_POLICY
private static final int
CACHE_POLICY
private static final int
FOREVER
private static int
nbnsIndex
private static final HashMap
ADDRESS_CACHE
private static final HashMap
LOOKUP_TABLE
static final Name
UNKNOWN_NAME
static final NbtAddress
UNKNOWN_ADDRESS
static final byte[]
UNKNOWN_MAC_ADDRESS
static NbtAddress
localhost
Name
hostName
int
address
int
nodeType
boolean
groupName
boolean
isBeingDeleted
boolean
isInConflict
boolean
isActive
boolean
isPermanent
boolean
isDataFromNodeStatus
byte[]
macAddress
String
calledName
Constructors Summary
NbtAddress(Name hostName, int address, boolean groupName, int nodeType)

        this.hostName = hostName;
        this.address = address;
        this.groupName = groupName;
        this.nodeType = nodeType;
    
NbtAddress(Name hostName, int address, boolean groupName, int nodeType, boolean isBeingDeleted, boolean isInConflict, boolean isActive, boolean isPermanent, byte[] macAddress)


/* The NodeStatusResponse.readNodeNameArray method may also set this
 * information. These two places where node status data is populated should
 * be consistent. Be carefull!
 */
        this.hostName = hostName;
        this.address = address;
        this.groupName = groupName;
        this.nodeType = nodeType;
        this.isBeingDeleted = isBeingDeleted;
        this.isInConflict = isInConflict;
        this.isActive = isActive;
        this.isPermanent = isPermanent;
        this.macAddress = macAddress;
        isDataFromNodeStatus = true;
    
Methods Summary
static voidcacheAddress(Name hostName, jcifs.netbios.NbtAddress addr)

        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 ) {
                /* Java cannot determine the localhost. This is basically a config
                 * issue on the host. There's not much we can do about it. Just
                 * to suppress NPEs that would result we can create a possibly bogus
                 * address. Pretty sure the below cannot actually thrown a UHE tho.
                 */
                try {
                    localInetAddress = InetAddress.getByName("127.0.0.1");
                } catch( UnknownHostException ignored ) {
                }
            }
        }

        /* 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 );
    
        if( CACHE_POLICY == 0 ) {
            return;
        }
        long expiration = -1;
        if( CACHE_POLICY != FOREVER ) {
            expiration = System.currentTimeMillis() + CACHE_POLICY * 1000;
        }
        cacheAddress( hostName, addr, expiration );
    
static voidcacheAddress(Name hostName, jcifs.netbios.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 voidcacheAddressArray(jcifs.netbios.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;
                }
            }
        }
    
voidcheckData()

        if( hostName == UNKNOWN_NAME ) {
            getAllByAddress( this );
        }
    
private static java.lang.ObjectcheckLookupTable(Name name)

        Object obj;

        synchronized( LOOKUP_TABLE ) {
            if( LOOKUP_TABLE.containsKey( name ) == false ) {
                LOOKUP_TABLE.put( name, name );
                return null;
            }
            while( LOOKUP_TABLE.containsKey( name )) {
                try {
                    LOOKUP_TABLE.wait();
                } catch( InterruptedException e ) {
                }
            }
        }
        obj = getCachedAddress( name );
        if( obj == null ) {
            synchronized( LOOKUP_TABLE ) {
                LOOKUP_TABLE.put( name, name );
            }
        }

        return obj;
    
voidcheckNodeStatusData()

        if( isDataFromNodeStatus == false ) {
            getAllByAddress( this );
        }
    
static jcifs.netbios.NbtAddressdoNameQuery(Name name, java.net.InetAddress svr)

        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 );

        if( addr == null ) {
            /* This is almost exactly like InetAddress.java. See the
             * comments there for a description of how the LOOKUP_TABLE prevents
             * redundant queries from going out on the wire.
             */
            if(( addr = (NbtAddress)checkLookupTable( name )) == null ) {
                try {
                    addr = CLIENT.getByName( name, svr );
                } catch( UnknownHostException uhe ) {
                    addr = UNKNOWN_ADDRESS;
                } finally {
                    cacheAddress( name, addr );
                    updateLookupTable( name );
                }
            }
        }
        if( addr == UNKNOWN_ADDRESS ) {
            throw new UnknownHostException( name.toString() );
        }
        return addr;
    
public booleanequals(java.lang.Object obj)
Determines if this address is equal two another. Only the IP Addresses are compared. Similar to the {@link #hashCode} method, the comparison is based on the integer IP address and not the string representation.

        return ( obj != null ) && ( obj instanceof NbtAddress ) &&
                                        ( ((NbtAddress)obj).address == address );
    
public java.lang.StringfirstCalledName()


        calledName = hostName.name;

        if( Character.isDigit( calledName.charAt( 0 ))) {
            int i, len, dots;
            char[] data;

            i = dots = 0;                    /* quick IP address validation */
            len = calledName.length();
            data = calledName.toCharArray();
            while( i < len && Character.isDigit( data[i++] )) {
                if( i == len && dots == 3 ) {
                    // probably an IP address
                    calledName = SMBSERVER_NAME;
                    break;
                }
                if( i < len && data[i] == '." ) {
                    dots++;
                    i++;
                }
            }
        } else {
            switch (hostName.hexCode) {
                case 0x1B:
                case 0x1C:
                case 0x1D:
                    calledName = SMBSERVER_NAME;
            }
        }

        return calledName;
    
public byte[]getAddress()
Returns the raw IP address of this NbtAddress. The result is in network byte order: the highest order byte of the address is in getAddress()[0].

return
a four byte array

    
        byte[] addr = new byte[4];

        addr[0] = (byte)(( address >>> 24 ) & 0xFF );
        addr[1] = (byte)(( address >>> 16 ) & 0xFF );
        addr[2] = (byte)(( address >>> 8 ) & 0xFF );
        addr[3] = (byte)( address & 0xFF );
        return addr;
    
public static jcifs.netbios.NbtAddress[]getAllByAddress(java.lang.String host)
Retrieve all addresses of a host by it's address. NetBIOS hosts can have many names for a given IP address. The name and IP address make the NetBIOS address. This provides a way to retrieve the other names for a host with the same IP address.

param
host hostname to lookup all addresses for
throws
java.net.UnknownHostException if there is an error resolving the name

        return getAllByAddress( getByName( host, 0x00, null ));
    
public static jcifs.netbios.NbtAddress[]getAllByAddress(java.lang.String host, int type, java.lang.String scope)
Retrieve all addresses of a host by it's address. NetBIOS hosts can have many names for a given IP address. The name and IP address make the NetBIOS address. This provides a way to retrieve the other names for a host with the same IP address. See {@link #getByName} for a description of type and scope.

param
host hostname to lookup all addresses for
param
type the hexcode of the name
param
scope the scope of the name
throws
java.net.UnknownHostException if there is an error resolving the name

        return getAllByAddress( getByName( host, type, scope ));
    
public static jcifs.netbios.NbtAddress[]getAllByAddress(jcifs.netbios.NbtAddress addr)
Retrieve all addresses of a host by it's address. NetBIOS hosts can have many names for a given IP address. The name and IP address make the NetBIOS address. This provides a way to retrieve the other names for a host with the same IP address.

param
addr the address to query
throws
UnknownHostException if address cannot be resolved

        try {
            NbtAddress[] addrs = CLIENT.getNodeStatus( addr );
            cacheAddressArray( addrs );
            return addrs;
        } catch( UnknownHostException uhe ) {
            throw new UnknownHostException( "no name with type 0x" +
                            Hexdump.toHexString( addr.hostName.hexCode, 2 ) +
                            ((( addr.hostName.scope == null ) ||
                            ( addr.hostName.scope.length() == 0 )) ?
                            " with no scope" : " with scope " + addr.hostName.scope ) +
                            " for host " + addr.getHostAddress() );
        }
    
public static jcifs.netbios.NbtAddress[]getAllByName(java.lang.String host, int type, java.lang.String scope, java.net.InetAddress svr)

        return CLIENT.getAllByName( new Name( host, type, scope ), svr );
    
public static jcifs.netbios.NbtAddressgetByName(java.lang.String host)
Determines the address of a host given it's host name. The name can be a NetBIOS name like "freto" or an IP address like "192.168.1.15". It cannot be a DNS name; the analygous {@link jcifs.UniAddress} or {@link java.net.InetAddress} getByName methods can be used for that.

param
host hostname to resolve
throws
java.net.UnknownHostException if there is an error resolving the name

        return getByName( host, 0x00, null );
    
public static jcifs.netbios.NbtAddressgetByName(java.lang.String host, int type, java.lang.String scope)
Determines the address of a host given it's host name. NetBIOS names also have a type. Types(aka Hex Codes) are used to distiquish the various services on a host. Here is a fairly complete list of NetBIOS hex codes. Scope is not used but is still functional in other NetBIOS products and so for completeness it has been implemented. A scope of null or "" signifies no scope.

param
host the name to resolve
param
type the hex code of the name
param
scope the scope of the name
throws
java.net.UnknownHostException if there is an error resolving the name


        return getByName( host, type, scope, null );
    
public static jcifs.netbios.NbtAddressgetByName(java.lang.String host, int type, java.lang.String scope, java.net.InetAddress svr)


        if( host == null || host.length() == 0 ) {
            return getLocalHost();
        }
        if( !Character.isDigit( host.charAt(0) )) {
            return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
        } else {
            int IP = 0x00;
            int hitDots = 0;
            char[] data = host.toCharArray();

            for( int i = 0; i < data.length; i++ ) {
                char c = data[i];
                if( c < 48 || c > 57 ) {
                    return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
                }
                int b = 0x00;
                while( c != '." ) {
                    if( c < 48 || c > 57 ) {
                        return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
                    }
                    b = b * 10 + c - '0";

                    if( ++i >= data.length )
                        break;

                    c = data[i];
                }
                if( b > 0xFF ) {
                    return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
                }
                IP = ( IP << 8 ) + b;
                hitDots++;
            }
            if( hitDots != 4 || host.endsWith( "." )) {
                return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
            }
            return new NbtAddress( UNKNOWN_NAME, IP, false, B_NODE );
        }
    
static jcifs.netbios.NbtAddressgetCachedAddress(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;
        }
    
public java.lang.StringgetHostAddress()
Returns this IP adress as a {@link java.lang.String} in the form "%d.%d.%d.%d".

    
        return (( address >>> 24 ) & 0xFF ) + "." +
            (( address >>> 16 ) & 0xFF ) + "." +
            (( address >>> 8 ) & 0xFF ) + "." +
            (( address >>> 0 ) & 0xFF );
    
public java.lang.StringgetHostName()
The hostname of this address. If the hostname is null the local machines IP address is returned.

return
the text representation of the hostname associated with this address

        /* 2010 - We no longer try a Node Status to get the
         * hostname because apparently some servers do not respond
         * anymore. I think everyone post Windows 98 will accept
         * an IP address as the tconHostName which is the principal
         * use of this method.
         */
        if (hostName == UNKNOWN_NAME) {
            return getHostAddress();
        }
        return hostName.name;
    
public java.net.InetAddressgetInetAddress()
To convert this address to an InetAddress.

return
the {@link java.net.InetAddress} representation of this address.

        return InetAddress.getByName( getHostAddress() );
    
public static jcifs.netbios.NbtAddressgetLocalHost()
Retrieves the local host address.

throws
UnknownHostException This is not likely as the IP returned by InetAddress should be available

        return localhost;
    
public static NamegetLocalName()

        return localhost.hostName;
    
public byte[]getMacAddress()
Retrieves the MAC address of the remote network interface. Samba returns all zeros.

return
the MAC address as an array of six bytes
throws
UnknownHostException if the host cannot be resolved to determine the MAC address.

        checkNodeStatusData();
        return macAddress;
    
public intgetNameType()
Returned the hex code associated with this name(e.g. 0x20 is for the file service)

        return hostName.hexCode;
    
public intgetNodeType()
Checks the node type of this address.

return
{@link jcifs.netbios.NbtAddress#B_NODE}, {@link jcifs.netbios.NbtAddress#P_NODE}, {@link jcifs.netbios.NbtAddress#M_NODE}, {@link jcifs.netbios.NbtAddress#H_NODE}
throws
UnknownHostException if the host cannot be resolved to find out.

        checkData();
        return nodeType;
    
public static java.net.InetAddressgetWINSAddress()

        return NBNS.length == 0 ? null : NBNS[nbnsIndex];
    
public inthashCode()
Returns a hashcode for this IP address. The hashcode comes from the IP address and is not generated from the string representation. So because NetBIOS nodes can have many names, all names associated with an IP will have the same hashcode.

        return address;
    
public booleanisActive()
Determines if this address is active.

throws
UnknownHostException if the host cannot be resolved to find out.

        checkNodeStatusData();
        return isActive;
    
public booleanisBeingDeleted()
Determines if this address in the process of being deleted.

throws
UnknownHostException if the host cannot be resolved to find out.

        checkNodeStatusData();
        return isBeingDeleted;
    
public booleanisGroupAddress()
Determines if the address is a group address. This is also known as a workgroup name or group name.

throws
UnknownHostException if the host cannot be resolved to find out.

        checkData();
        return groupName;
    
public booleanisInConflict()
Determines if this address in conflict with another address.

throws
UnknownHostException if the host cannot be resolved to find out.

        checkNodeStatusData();
        return isInConflict;
    
public booleanisPermanent()
Determines if this address is set to be permanent.

throws
UnknownHostException if the host cannot be resolved to find out.

        checkNodeStatusData();
        return isPermanent;
    
public static booleanisWINS(java.net.InetAddress svr)

        for( int i = 0; svr != null && i < NBNS.length; i++ ) {
            if( svr.hashCode() == NBNS[i].hashCode() ) {
                return true;
            }
        }
        return false;
    
public java.lang.StringnextCalledName()


        if( calledName == hostName.name ) {
            calledName = SMBSERVER_NAME;
        } else if( calledName == SMBSERVER_NAME ) {
            NbtAddress[] addrs;

            try {
                addrs = CLIENT.getNodeStatus( this );
                if( hostName.hexCode == 0x1D ) {
                    for( int i = 0; i < addrs.length; i++ ) {
                        if( addrs[i].hostName.hexCode == 0x20 ) {
                            return addrs[i].hostName.name;
                        }
                    }
                    return null;
                } else if( isDataFromNodeStatus ) {
                    /* 'this' has been updated and should now
                     * have a real NetBIOS name
                     */
                    calledName = null;
                    return hostName.name;
                }
            } catch( UnknownHostException uhe ) {
                calledName = null;
            }
        } else {
            calledName = null;
        }

        return calledName;
    
static java.net.InetAddressswitchWINS()

        nbnsIndex = (nbnsIndex + 1) < NBNS.length ? nbnsIndex + 1 : 0;
        return NBNS.length == 0 ? null : NBNS[nbnsIndex];
    
public java.lang.StringtoString()
Returns the {@link java.lang.String} representaion of this address.

        return hostName.toString() + "/" + getHostAddress();
    
private static voidupdateLookupTable(Name name)

        synchronized( LOOKUP_TABLE ) {
            LOOKUP_TABLE.remove( name );
            LOOKUP_TABLE.notifyAll();
        }