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