001: /* jcifs smb client library in Java
002: * Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package jcifs.netbios;
020:
021: import java.net.InetAddress;
022: import java.net.UnknownHostException;
023: import java.net.SocketException;
024: import java.io.IOException;
025: import java.io.UnsupportedEncodingException;
026: import java.util.HashMap;
027: import jcifs.Config;
028: import jcifs.util.Hexdump;
029:
030: /**
031: * This class represents a NetBIOS over TCP/IP address. Under normal
032: * conditions, users of jCIFS need not be concerned with this class as
033: * name resolution and session services are handled internally by the smb package.
034: *
035: * <p> Applications can use the methods <code>getLocalHost</code>,
036: * <code>getByName</code>, and
037: * <code>getAllByAddress</code> to create a new NbtAddress instance. This
038: * class is symmetric with {@link java.net.InetAddress}.
039: *
040: * <p><b>About NetBIOS:</b> The NetBIOS name
041: * service is a dynamic distributed service that allows hosts to resolve
042: * names by broadcasting a query, directing queries to a server such as
043: * Samba or WINS. NetBIOS is currently the primary networking layer for
044: * providing name service, datagram service, and session service to the
045: * Microsoft Windows platform. A NetBIOS name can be 15 characters long
046: * and hosts usually registers several names on the network. From a
047: * Windows command prompt you can see
048: * what names a host registers with the nbtstat command.
049: * <p><blockquote><pre>
050: * C:\>nbtstat -a 192.168.1.15
051: *
052: * NetBIOS Remote Machine Name Table
053: *
054: * Name Type Status
055: * ---------------------------------------------
056: * JMORRIS2 <00> UNIQUE Registered
057: * BILLING-NY <00> GROUP Registered
058: * JMORRIS2 <03> UNIQUE Registered
059: * JMORRIS2 <20> UNIQUE Registered
060: * BILLING-NY <1E> GROUP Registered
061: * JMORRIS <03> UNIQUE Registered
062: *
063: * MAC Address = 00-B0-34-21-FA-3B
064: * </blockquote></pre>
065: * <p> The hostname of this machine is <code>JMORRIS2</code>. It is
066: * a member of the group(a.k.a workgroup and domain) <code>BILLING-NY</code>. To
067: * obtain an {@link java.net.InetAddress} for a host one might do:
068: *
069: * <pre>
070: * InetAddress addr = NbtAddress.getByName( "jmorris2" ).getInetAddress();
071: * </pre>
072: * <p>From a UNIX platform with Samba installed you can perform similar
073: * diagnostics using the <code>nmblookup</code> utility.
074: *
075: * @author Michael B. Allen
076: * @see java.net.InetAddress
077: * @since jcifs-0.1
078: */
079:
080: public final class NbtAddress {
081:
082: /*
083: * This is a special name that means all hosts. If you wish to find all hosts
084: * on a network querying a workgroup group name is the preferred method.
085: */
086:
087: static final String ANY_HOSTS_NAME = "*\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000";
088:
089: /**
090: * This is a special name for querying the master browser that serves the
091: * list of hosts found in "Network Neighborhood".
092: */
093:
094: public static final String MASTER_BROWSER_NAME = "\u0001\u0002__MSBROWSE__\u0002";
095:
096: /**
097: * A special generic name specified when connecting to a host for which
098: * a name is not known. Not all servers respond to this name.
099: */
100:
101: public static final String SMBSERVER_NAME = "*SMBSERVER ";
102:
103: /**
104: * A B node only broadcasts name queries. This is the default if a
105: * nameserver such as WINS or Samba is not specified.
106: */
107:
108: public static final int B_NODE = 0;
109:
110: /**
111: * A Point-to-Point node, or P node, unicasts queries to a nameserver
112: * only. Natrually the <code>jcifs.netbios.nameserver</code> property must
113: * be set.
114: */
115:
116: public static final int P_NODE = 1;
117:
118: /**
119: * Try Broadcast queries first, then try to resolve the name using the
120: * nameserver.
121: */
122:
123: public static final int M_NODE = 2;
124:
125: /**
126: * A Hybrid node tries to resolve a name using the nameserver first. If
127: * that fails use the broadcast address. This is the default if a nameserver
128: * is provided. This is the behavior of Microsoft Windows machines.
129: */
130:
131: public static final int H_NODE = 3;
132:
133: static final InetAddress[] NBNS = Config.getInetAddressArray(
134: "jcifs.netbios.wins", ",", new InetAddress[0]);
135:
136: /* Construct the shared static client object that will
137: * conduct all encoding and decoding of NetBIOS name service
138: * messages as well as socket IO in a synchronized fashon.
139: */
140:
141: private static final NameServiceClient CLIENT = new NameServiceClient();
142:
143: private static final int DEFAULT_CACHE_POLICY = 30;
144: private static final int CACHE_POLICY = Config.getInt(
145: "jcifs.netbios.cachePolicy", DEFAULT_CACHE_POLICY);
146: private static final int FOREVER = -1;
147: private static int nbnsIndex = 0;
148:
149: private static final HashMap ADDRESS_CACHE = new HashMap();
150: private static final HashMap LOOKUP_TABLE = new HashMap();
151:
152: static final Name UNKNOWN_NAME = new Name("0.0.0.0", 0x00, null);
153: static final NbtAddress UNKNOWN_ADDRESS = new NbtAddress(
154: UNKNOWN_NAME, 0, false, B_NODE);
155: static final byte[] UNKNOWN_MAC_ADDRESS = new byte[] { (byte) 0x00,
156: (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
157: (byte) 0x00 };
158:
159: static final class CacheEntry {
160: Name hostName;
161: NbtAddress address;
162: long expiration;
163:
164: CacheEntry(Name hostName, NbtAddress address, long expiration) {
165: this .hostName = hostName;
166: this .address = address;
167: this .expiration = expiration;
168: }
169: }
170:
171: static NbtAddress localhost;
172:
173: static {
174: InetAddress localInetAddress;
175: String localHostname;
176: Name localName;
177:
178: /* Create an address to represent failed lookups and cache forever.
179: */
180:
181: ADDRESS_CACHE.put(UNKNOWN_NAME, new CacheEntry(UNKNOWN_NAME,
182: UNKNOWN_ADDRESS, FOREVER));
183:
184: /* Determine the InetAddress of the local interface
185: * if one was not specified.
186: */
187: localInetAddress = CLIENT.laddr;
188: if (localInetAddress == null) {
189: try {
190: localInetAddress = InetAddress.getLocalHost();
191: } catch (UnknownHostException uhe) {
192: }
193: }
194:
195: /* If a local hostname was not provided a name like
196: * JCIFS34_172_A6 will be dynamically generated for the
197: * client. This is primarily (exclusively?) used as a
198: * CallingName during session establishment.
199: */
200: localHostname = Config.getProperty("jcifs.netbios.hostname",
201: null);
202: if (localHostname == null || localHostname.length() == 0) {
203: byte[] addr = localInetAddress.getAddress();
204: localHostname = "JCIFS"
205: + (addr[2] & 0xFF)
206: + "_"
207: + (addr[3] & 0xFF)
208: + "_"
209: + Hexdump.toHexString(
210: (int) (Math.random() * (double) 0xFF), 2);
211: }
212:
213: /* Create an NbtAddress for the local interface with
214: * the name deduced above possibly with scope applied and
215: * cache it forever.
216: */
217: localName = new Name(localHostname, 0x00, Config.getProperty(
218: "jcifs.netbios.scope", null));
219: localhost = new NbtAddress(localName, localInetAddress
220: .hashCode(), false, B_NODE, false, false, true, false,
221: UNKNOWN_MAC_ADDRESS);
222: cacheAddress(localName, localhost, FOREVER);
223: }
224:
225: static void cacheAddress(Name hostName, NbtAddress addr) {
226: if (CACHE_POLICY == 0) {
227: return;
228: }
229: long expiration = -1;
230: if (CACHE_POLICY != FOREVER) {
231: expiration = System.currentTimeMillis() + CACHE_POLICY
232: * 1000;
233: }
234: cacheAddress(hostName, addr, expiration);
235: }
236:
237: static void cacheAddress(Name hostName, NbtAddress addr,
238: long expiration) {
239: if (CACHE_POLICY == 0) {
240: return;
241: }
242: synchronized (ADDRESS_CACHE) {
243: CacheEntry entry = (CacheEntry) ADDRESS_CACHE.get(hostName);
244: if (entry == null) {
245: entry = new CacheEntry(hostName, addr, expiration);
246: ADDRESS_CACHE.put(hostName, entry);
247: } else {
248: entry.address = addr;
249: entry.expiration = expiration;
250: }
251: }
252: }
253:
254: static void cacheAddressArray(NbtAddress[] addrs) {
255: if (CACHE_POLICY == 0) {
256: return;
257: }
258: long expiration = -1;
259: if (CACHE_POLICY != FOREVER) {
260: expiration = System.currentTimeMillis() + CACHE_POLICY
261: * 1000;
262: }
263: synchronized (ADDRESS_CACHE) {
264: for (int i = 0; i < addrs.length; i++) {
265: CacheEntry entry = (CacheEntry) ADDRESS_CACHE
266: .get(addrs[i].hostName);
267: if (entry == null) {
268: entry = new CacheEntry(addrs[i].hostName, addrs[i],
269: expiration);
270: ADDRESS_CACHE.put(addrs[i].hostName, entry);
271: } else {
272: entry.address = addrs[i];
273: entry.expiration = expiration;
274: }
275: }
276: }
277: }
278:
279: static NbtAddress getCachedAddress(Name hostName) {
280: if (CACHE_POLICY == 0) {
281: return null;
282: }
283: synchronized (ADDRESS_CACHE) {
284: CacheEntry entry = (CacheEntry) ADDRESS_CACHE.get(hostName);
285: if (entry != null
286: && entry.expiration < System.currentTimeMillis()
287: && entry.expiration >= 0) {
288: entry = null;
289: }
290: return entry != null ? entry.address : null;
291: }
292: }
293:
294: static NbtAddress doNameQuery(Name name, InetAddress svr)
295: throws UnknownHostException {
296: NbtAddress addr;
297:
298: if (name.hexCode == 0x1d && svr == null) {
299: svr = CLIENT.baddr; // bit of a hack but saves a lookup
300: }
301: name.srcHashCode = svr != null ? svr.hashCode() : 0;
302: addr = getCachedAddress(name);
303:
304: if (addr == null) {
305: /* This was copied amost verbatim from InetAddress.java. See the
306: * comments there for a description of how the LOOKUP_TABLE prevents
307: * redundant queries from going out on the wire.
308: */
309: if ((addr = (NbtAddress) checkLookupTable(name)) == null) {
310: try {
311: addr = CLIENT.getByName(name, svr);
312: } catch (UnknownHostException uhe) {
313: addr = UNKNOWN_ADDRESS;
314: } finally {
315: cacheAddress(name, addr);
316: updateLookupTable(name);
317: }
318: }
319: }
320: if (addr == UNKNOWN_ADDRESS) {
321: throw new UnknownHostException(name.toString());
322: }
323: return addr;
324: }
325:
326: private static Object checkLookupTable(Name name) {
327: Object obj;
328:
329: synchronized (LOOKUP_TABLE) {
330: if (LOOKUP_TABLE.containsKey(name) == false) {
331: LOOKUP_TABLE.put(name, name);
332: return null;
333: }
334: while (LOOKUP_TABLE.containsKey(name)) {
335: try {
336: LOOKUP_TABLE.wait();
337: } catch (InterruptedException e) {
338: }
339: }
340: }
341: obj = getCachedAddress(name);
342: if (obj == null) {
343: synchronized (LOOKUP_TABLE) {
344: LOOKUP_TABLE.put(name, name);
345: }
346: }
347:
348: return obj;
349: }
350:
351: private static void updateLookupTable(Name name) {
352: synchronized (LOOKUP_TABLE) {
353: LOOKUP_TABLE.remove(name);
354: LOOKUP_TABLE.notifyAll();
355: }
356: }
357:
358: /**
359: * Retrieves the local host address.
360: *
361: * @throws UnknownHostException This is not likely as the IP returned
362: * by <code>InetAddress</code> should be available
363: */
364:
365: public static NbtAddress getLocalHost() throws UnknownHostException {
366: return localhost;
367: }
368:
369: /**
370: * Determines the address of a host given it's host name. The name can be a NetBIOS name like
371: * "freto" or an IP address like "192.168.1.15". It cannot be a DNS name;
372: * the analygous {@link jcifs.UniAddress} or {@link java.net.InetAddress}
373: * <code>getByName</code> methods can be used for that.
374: *
375: * @param host hostname to resolve
376: * @throws java.net.UnknownHostException if there is an error resolving the name
377: */
378:
379: public static NbtAddress getByName(String host)
380: throws UnknownHostException {
381: return getByName(host, 0x00, null);
382: }
383:
384: /**
385: * Determines the address of a host given it's host name. NetBIOS
386: * names also have a <code>type</code>. Types(aka Hex Codes)
387: * are used to distiquish the various services on a host. <a
388: * href="../../../nbtcodes.html">Here</a> is
389: * a fairly complete list of NetBIOS hex codes. Scope is not used but is
390: * still functional in other NetBIOS products and so for completeness it has been
391: * implemented. A <code>scope</code> of <code>null</code> or <code>""</code>
392: * signifies no scope.
393: *
394: * @param host the name to resolve
395: * @param type the hex code of the name
396: * @param scope the scope of the name
397: * @throws java.net.UnknownHostException if there is an error resolving the name
398: */
399:
400: public static NbtAddress getByName(String host, int type,
401: String scope) throws UnknownHostException {
402:
403: return getByName(host, type, scope, null);
404: }
405:
406: /*
407: * The additional <code>svr</code> parameter specifies the address to
408: * query. This might be the address of a specific host, a name server,
409: * or a broadcast address.
410: */
411:
412: public static NbtAddress getByName(String host, int type,
413: String scope, InetAddress svr) throws UnknownHostException {
414:
415: if (host == null || host.length() == 0) {
416: return getLocalHost();
417: }
418: if (!Character.isDigit(host.charAt(0))) {
419: return (NbtAddress) doNameQuery(
420: new Name(host, type, scope), svr);
421: } else {
422: int IP = 0x00;
423: int hitDots = 0;
424: char[] data = host.toCharArray();
425:
426: for (int i = 0; i < data.length; i++) {
427: char c = data[i];
428: if (c < 48 || c > 57) {
429: return (NbtAddress) doNameQuery(new Name(host,
430: type, scope), svr);
431: }
432: int b = 0x00;
433: while (c != '.') {
434: if (c < 48 || c > 57) {
435: return (NbtAddress) doNameQuery(new Name(host,
436: type, scope), svr);
437: }
438: b = b * 10 + c - '0';
439:
440: if (++i >= data.length)
441: break;
442:
443: c = data[i];
444: }
445: if (b > 0xFF) {
446: return (NbtAddress) doNameQuery(new Name(host,
447: type, scope), svr);
448: }
449: IP = (IP << 8) + b;
450: hitDots++;
451: }
452: if (hitDots != 4 || host.endsWith(".")) {
453: return (NbtAddress) doNameQuery(new Name(host, type,
454: scope), svr);
455: }
456: return new NbtAddress(UNKNOWN_NAME, IP, false, B_NODE);
457: }
458: }
459:
460: public static NbtAddress[] getAllByName(String host, int type,
461: String scope, InetAddress svr) throws UnknownHostException {
462: return CLIENT.getAllByName(new Name(host, type, scope), svr);
463: }
464:
465: /**
466: * Retrieve all addresses of a host by it's address. NetBIOS hosts can
467: * have many names for a given IP address. The name and IP address make the
468: * NetBIOS address. This provides a way to retrieve the other names for a
469: * host with the same IP address.
470: *
471: * @param host hostname to lookup all addresses for
472: * @throws java.net.UnknownHostException if there is an error resolving the name
473: */
474:
475: public static NbtAddress[] getAllByAddress(String host)
476: throws UnknownHostException {
477: return getAllByAddress(getByName(host, 0x00, null));
478: }
479:
480: /**
481: * Retrieve all addresses of a host by it's address. NetBIOS hosts can
482: * have many names for a given IP address. The name and IP address make
483: * the NetBIOS address. This provides a way to retrieve the other names
484: * for a host with the same IP address. See {@link #getByName}
485: * for a description of <code>type</code>
486: * and <code>scope</code>.
487: *
488: * @param host hostname to lookup all addresses for
489: * @param type the hexcode of the name
490: * @param scope the scope of the name
491: * @throws java.net.UnknownHostException if there is an error resolving the name
492: */
493:
494: public static NbtAddress[] getAllByAddress(String host, int type,
495: String scope) throws UnknownHostException {
496: return getAllByAddress(getByName(host, type, scope));
497: }
498:
499: /**
500: * Retrieve all addresses of a host by it's address. NetBIOS hosts can
501: * have many names for a given IP address. The name and IP address make the
502: * NetBIOS address. This provides a way to retrieve the other names for a
503: * host with the same IP address.
504: *
505: * @param addr the address to query
506: * @throws UnknownHostException if address cannot be resolved
507: */
508:
509: public static NbtAddress[] getAllByAddress(NbtAddress addr)
510: throws UnknownHostException {
511: try {
512: NbtAddress[] addrs = CLIENT.getNodeStatus(addr);
513: cacheAddressArray(addrs);
514: return addrs;
515: } catch (UnknownHostException uhe) {
516: throw new UnknownHostException(
517: "no name with type 0x"
518: + Hexdump.toHexString(
519: addr.hostName.hexCode, 2)
520: + (((addr.hostName.scope == null) || (addr.hostName.scope
521: .length() == 0)) ? " with no scope"
522: : " with scope "
523: + addr.hostName.scope)
524: + " for host " + addr.getHostAddress());
525: }
526: }
527:
528: public static InetAddress getWINSAddress() {
529: return NBNS.length == 0 ? null : NBNS[nbnsIndex];
530: }
531:
532: public static boolean isWINS(InetAddress svr) {
533: for (int i = 0; svr != null && i < NBNS.length; i++) {
534: if (svr.hashCode() == NBNS[i].hashCode()) {
535: return true;
536: }
537: }
538: return false;
539: }
540:
541: static InetAddress switchWINS() {
542: nbnsIndex = (nbnsIndex + 1) < NBNS.length ? nbnsIndex + 1 : 0;
543: return NBNS.length == 0 ? null : NBNS[nbnsIndex];
544: }
545:
546: Name hostName;
547: int address, nodeType;
548: boolean groupName, isBeingDeleted, isInConflict, isActive,
549: isPermanent, isDataFromNodeStatus;
550: byte[] macAddress;
551: String calledName;
552:
553: NbtAddress(Name hostName, int address, boolean groupName,
554: int nodeType) {
555: this .hostName = hostName;
556: this .address = address;
557: this .groupName = groupName;
558: this .nodeType = nodeType;
559: }
560:
561: NbtAddress(Name hostName, int address, boolean groupName,
562: int nodeType, boolean isBeingDeleted, boolean isInConflict,
563: boolean isActive, boolean isPermanent, byte[] macAddress) {
564:
565: /* The NodeStatusResponse.readNodeNameArray method may also set this
566: * information. These two places where node status data is populated should
567: * be consistent. Be carefull!
568: */
569: this .hostName = hostName;
570: this .address = address;
571: this .groupName = groupName;
572: this .nodeType = nodeType;
573: this .isBeingDeleted = isBeingDeleted;
574: this .isInConflict = isInConflict;
575: this .isActive = isActive;
576: this .isPermanent = isPermanent;
577: this .macAddress = macAddress;
578: isDataFromNodeStatus = true;
579: }
580:
581: /* Guess next called name to try for session establishment. These
582: * methods are used by the smb package.
583: */
584:
585: public String firstCalledName() {
586:
587: calledName = hostName.name;
588:
589: if (Character.isDigit(calledName.charAt(0))) {
590: int i, len, dots;
591: char[] data;
592:
593: i = dots = 0; /* quick IP address validation */
594: len = calledName.length();
595: data = calledName.toCharArray();
596: while (i < len && Character.isDigit(data[i++])) {
597: if (i == len && dots == 3) {
598: // probably an IP address
599: calledName = SMBSERVER_NAME;
600: break;
601: }
602: if (i < len && data[i] == '.') {
603: dots++;
604: i++;
605: }
606: }
607: } else if (hostName.hexCode == 0x1D || hostName.hexCode == 0x1C) {
608: calledName = SMBSERVER_NAME;
609: }
610:
611: return calledName;
612: }
613:
614: public String nextCalledName() {
615:
616: if (calledName == hostName.name) {
617: calledName = SMBSERVER_NAME;
618: } else if (calledName == SMBSERVER_NAME) {
619: NbtAddress[] addrs;
620:
621: try {
622: addrs = CLIENT.getNodeStatus(this );
623: if (hostName.hexCode == 0x1D) {
624: for (int i = 0; i < addrs.length; i++) {
625: if (addrs[i].hostName.hexCode == 0x20) {
626: return addrs[i].hostName.name;
627: }
628: }
629: return null;
630: } else if (isDataFromNodeStatus) {
631: /* 'this' has been updated and should now
632: * have a real NetBIOS name
633: */
634: calledName = null;
635: return hostName.name;
636: }
637: } catch (UnknownHostException uhe) {
638: calledName = null;
639: }
640: } else {
641: calledName = null;
642: }
643:
644: return calledName;
645: }
646:
647: /*
648: * There are three degrees of state that any NbtAddress can have.
649: *
650: * 1) IP Address - If a dot-quad IP string is used with getByName (or used
651: * to create an NbtAddress internal to this netbios package), no query is
652: * sent on the wire and the only state this object has is it's IP address
653: * (but that's enough to connect to a host using *SMBSERVER for CallingName).
654: *
655: * 2) IP Address, NetBIOS name, nodeType, groupName - If however a
656: * legal NetBIOS name string is used a name query request will retreive
657: * the IP, node type, and whether or not this NbtAddress represents a
658: * group name. This degree of state can be obtained with a Name Query
659: * Request or Node Status Request.
660: *
661: * 3) All - The NbtAddress will be populated with all state such as mac
662: * address, isPermanent, isBeingDeleted, ...etc. This information can only
663: * be retrieved with the Node Status request.
664: *
665: * The degree of state that an NbtAddress has is dependant on how it was
666: * created and what is required of it. The second degree of state is the
667: * most common. This is the state information that would be retrieved from
668: * WINS for example. Natrually it is not practical for every NbtAddress
669: * to be populated will all state requiring a Node Status on every host
670: * encountered. The below methods allow state to be populated when requested
671: * in a lazy fashon.
672: */
673:
674: void checkData() throws UnknownHostException {
675: if (hostName == UNKNOWN_NAME) {
676: getAllByAddress(this );
677: }
678: }
679:
680: void checkNodeStatusData() throws UnknownHostException {
681: if (isDataFromNodeStatus == false) {
682: getAllByAddress(this );
683: }
684: }
685:
686: /**
687: * Determines if the address is a group address. This is also
688: * known as a workgroup name or group name.
689: *
690: * @throws UnknownHostException if the host cannot be resolved to find out.
691: */
692:
693: public boolean isGroupAddress() throws UnknownHostException {
694: checkData();
695: return groupName;
696: }
697:
698: /**
699: * Checks the node type of this address.
700: * @return {@link jcifs.netbios.NbtAddress#B_NODE},
701: * {@link jcifs.netbios.NbtAddress#P_NODE}, {@link jcifs.netbios.NbtAddress#M_NODE},
702: * {@link jcifs.netbios.NbtAddress#H_NODE}
703: *
704: * @throws UnknownHostException if the host cannot be resolved to find out.
705: */
706:
707: public int getNodeType() throws UnknownHostException {
708: checkData();
709: return nodeType;
710: }
711:
712: /**
713: * Determines if this address in the process of being deleted.
714: *
715: * @throws UnknownHostException if the host cannot be resolved to find out.
716: */
717:
718: public boolean isBeingDeleted() throws UnknownHostException {
719: checkNodeStatusData();
720: return isBeingDeleted;
721: }
722:
723: /**
724: * Determines if this address in conflict with another address.
725: *
726: * @throws UnknownHostException if the host cannot be resolved to find out.
727: */
728:
729: public boolean isInConflict() throws UnknownHostException {
730: checkNodeStatusData();
731: return isInConflict;
732: }
733:
734: /**
735: * Determines if this address is active.
736: *
737: * @throws UnknownHostException if the host cannot be resolved to find out.
738: */
739:
740: public boolean isActive() throws UnknownHostException {
741: checkNodeStatusData();
742: return isActive;
743: }
744:
745: /**
746: * Determines if this address is set to be permanent.
747: *
748: * @throws UnknownHostException if the host cannot be resolved to find out.
749: */
750:
751: public boolean isPermanent() throws UnknownHostException {
752: checkNodeStatusData();
753: return isPermanent;
754: }
755:
756: /**
757: * Retrieves the MAC address of the remote network interface. Samba returns all zeros.
758: *
759: * @return the MAC address as an array of six bytes
760: * @throws UnknownHostException if the host cannot be resolved to
761: * determine the MAC address.
762: */
763:
764: public byte[] getMacAddress() throws UnknownHostException {
765: checkNodeStatusData();
766: return macAddress;
767: }
768:
769: /**
770: * The hostname of this address. If the hostname is null the local machines
771: * IP address is returned.
772: *
773: * @return the text representation of the hostname associated with this address
774: */
775:
776: public String getHostName() {
777: try {
778: checkData();
779: } catch (UnknownHostException uhe) {
780: return getHostAddress();
781: }
782: return hostName.name;
783: }
784:
785: /**
786: * Returns the raw IP address of this NbtAddress. The result is in network
787: * byte order: the highest order byte of the address is in getAddress()[0].
788: *
789: * @return a four byte array
790: */
791:
792: public byte[] getAddress() {
793: byte[] addr = new byte[4];
794:
795: addr[0] = (byte) ((address >>> 24) & 0xFF);
796: addr[1] = (byte) ((address >>> 16) & 0xFF);
797: addr[2] = (byte) ((address >>> 8) & 0xFF);
798: addr[3] = (byte) (address & 0xFF);
799: return addr;
800: }
801:
802: /**
803: * To convert this address to an <code>InetAddress</code>.
804: *
805: * @return the {@link java.net.InetAddress} representation of this address.
806: */
807:
808: public InetAddress getInetAddress() throws UnknownHostException {
809: return InetAddress.getByName(getHostAddress());
810: }
811:
812: /**
813: * Returns this IP adress as a {@link java.lang.String} in the form "%d.%d.%d.%d".
814: */
815:
816: public String getHostAddress() {
817: return ((address >>> 24) & 0xFF) + "."
818: + ((address >>> 16) & 0xFF) + "."
819: + ((address >>> 8) & 0xFF) + "."
820: + ((address >>> 0) & 0xFF);
821: }
822:
823: /**
824: * Returned the hex code associated with this name(e.g. 0x20 is for the file service)
825: */
826:
827: public int getNameType() {
828: return hostName.hexCode;
829: }
830:
831: /**
832: * Returns a hashcode for this IP address. The hashcode comes from the IP address
833: * and is not generated from the string representation. So because NetBIOS nodes
834: * can have many names, all names associated with an IP will have the same
835: * hashcode.
836: */
837:
838: public int hashCode() {
839: return address;
840: }
841:
842: /**
843: * Determines if this address is equal two another. Only the IP Addresses
844: * are compared. Similar to the {@link #hashCode} method, the comparison
845: * is based on the integer IP address and not the string representation.
846: */
847:
848: public boolean equals(Object obj) {
849: return (obj != null) && (obj instanceof NbtAddress)
850: && (((NbtAddress) obj).address == address);
851: }
852:
853: /**
854: * Returns the {@link java.lang.String} representaion of this address.
855: */
856:
857: public String toString() {
858: return hostName.toString() + "/" + getHostAddress();
859: }
860: }
|