$search
00001 // Copyright 2003-2005 Arthur van Hoff, Rick Blair 00002 // Licensed under Apache License version 2.0 00003 // Original license LGPL 00004 00005 package javax.jmdns.impl; 00006 00007 import java.io.DataOutputStream; 00008 import java.io.IOException; 00009 import java.io.UnsupportedEncodingException; 00010 import java.net.Inet4Address; 00011 import java.net.Inet6Address; 00012 import java.net.InetAddress; 00013 import java.net.UnknownHostException; 00014 import java.util.HashMap; 00015 import java.util.Map; 00016 import java.util.logging.Level; 00017 import java.util.logging.Logger; 00018 00019 import javax.jmdns.ServiceEvent; 00020 import javax.jmdns.ServiceInfo; 00021 import javax.jmdns.ServiceInfo.Fields; 00022 import javax.jmdns.impl.DNSOutgoing.MessageOutputStream; 00023 import javax.jmdns.impl.constants.DNSConstants; 00024 import javax.jmdns.impl.constants.DNSRecordClass; 00025 import javax.jmdns.impl.constants.DNSRecordType; 00026 00032 public abstract class DNSRecord extends DNSEntry { 00033 private static Logger logger = Logger.getLogger(DNSRecord.class.getName()); 00034 private int _ttl; 00035 private long _created; 00036 00040 private InetAddress _source; 00041 00045 DNSRecord(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique, int ttl) { 00046 super(name, type, recordClass, unique); 00047 this._ttl = ttl; 00048 this._created = System.currentTimeMillis(); 00049 } 00050 00051 /* 00052 * (non-Javadoc) 00053 * @see javax.jmdns.impl.DNSEntry#equals(java.lang.Object) 00054 */ 00055 @Override 00056 public boolean equals(Object other) { 00057 return (other instanceof DNSRecord) && super.equals(other) && sameValue((DNSRecord) other); 00058 } 00059 00063 abstract boolean sameValue(DNSRecord other); 00064 00068 boolean sameType(DNSRecord other) { 00069 return this.getRecordType() == other.getRecordType(); 00070 } 00071 00077 abstract boolean handleQuery(JmDNSImpl dns, long expirationTime); 00078 00084 abstract boolean handleResponse(JmDNSImpl dns); 00085 00089 abstract DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException; 00090 00094 boolean suppressedBy(DNSIncoming msg) { 00095 try { 00096 for (DNSRecord answer : msg.getAllAnswers()) { 00097 if (suppressedBy(answer)) { 00098 return true; 00099 } 00100 } 00101 return false; 00102 } catch (ArrayIndexOutOfBoundsException e) { 00103 logger.log(Level.WARNING, "suppressedBy() message " + msg + " exception ", e); 00104 // msg.print(true); 00105 return false; 00106 } 00107 } 00108 00112 boolean suppressedBy(DNSRecord other) { 00113 if (this.equals(other) && (other._ttl > _ttl / 2)) { 00114 return true; 00115 } 00116 return false; 00117 } 00118 00122 long getExpirationTime(int percent) { 00123 // ttl is in seconds the constant 10 is 1000 ms / 100 % 00124 return _created + (percent * _ttl * 10L); 00125 } 00126 00130 int getRemainingTTL(long now) { 00131 return (int) Math.max(0, (getExpirationTime(100) - now) / 1000); 00132 } 00133 00134 /* 00135 * (non-Javadoc) 00136 * @see javax.jmdns.impl.DNSEntry#isExpired(long) 00137 */ 00138 @Override 00139 public boolean isExpired(long now) { 00140 return getExpirationTime(100) <= now; 00141 } 00142 00143 /* 00144 * (non-Javadoc) 00145 * @see javax.jmdns.impl.DNSEntry#isStale(long) 00146 */ 00147 @Override 00148 public boolean isStale(long now) { 00149 return getExpirationTime(50) <= now; 00150 } 00151 00155 void resetTTL(DNSRecord other) { 00156 _created = other._created; 00157 _ttl = other._ttl; 00158 } 00159 00163 void setWillExpireSoon(long now) { 00164 _created = now; 00165 _ttl = DNSConstants.RECORD_EXPIRY_DELAY; 00166 } 00167 00171 abstract void write(MessageOutputStream out); 00172 00173 public static class IPv4Address extends Address { 00174 00175 IPv4Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, InetAddress addr) { 00176 super(name, DNSRecordType.TYPE_A, recordClass, unique, ttl, addr); 00177 } 00178 00179 IPv4Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, byte[] rawAddress) { 00180 super(name, DNSRecordType.TYPE_A, recordClass, unique, ttl, rawAddress); 00181 } 00182 00183 @Override 00184 void write(MessageOutputStream out) { 00185 if (_addr != null) { 00186 byte[] buffer = _addr.getAddress(); 00187 // If we have a type A records we should answer with a IPv4 address 00188 if (_addr instanceof Inet4Address) { 00189 // All is good 00190 } else { 00191 // Get the last four bytes 00192 byte[] tempbuffer = buffer; 00193 buffer = new byte[4]; 00194 System.arraycopy(tempbuffer, 12, buffer, 0, 4); 00195 } 00196 int length = buffer.length; 00197 out.writeBytes(buffer, 0, length); 00198 } 00199 } 00200 00201 /* 00202 * (non-Javadoc) 00203 * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean) 00204 */ 00205 @Override 00206 public ServiceInfo getServiceInfo(boolean persistent) { 00207 00208 ServiceInfoImpl info = (ServiceInfoImpl) super.getServiceInfo(persistent); 00209 info.addAddress((Inet4Address) _addr); 00210 return info; 00211 } 00212 00213 } 00214 00215 public static class IPv6Address extends Address { 00216 00217 IPv6Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, InetAddress addr) { 00218 super(name, DNSRecordType.TYPE_AAAA, recordClass, unique, ttl, addr); 00219 } 00220 00221 IPv6Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, byte[] rawAddress) { 00222 super(name, DNSRecordType.TYPE_AAAA, recordClass, unique, ttl, rawAddress); 00223 } 00224 00225 @Override 00226 void write(MessageOutputStream out) { 00227 if (_addr != null) { 00228 byte[] buffer = _addr.getAddress(); 00229 // If we have a type AAAA records we should answer with a IPv6 address 00230 if (_addr instanceof Inet4Address) { 00231 byte[] tempbuffer = buffer; 00232 buffer = new byte[16]; 00233 for (int i = 0; i < 16; i++) { 00234 if (i < 11) { 00235 buffer[i] = tempbuffer[i - 12]; 00236 } else { 00237 buffer[i] = 0; 00238 } 00239 } 00240 } 00241 int length = buffer.length; 00242 out.writeBytes(buffer, 0, length); 00243 } 00244 } 00245 00246 /* 00247 * (non-Javadoc) 00248 * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean) 00249 */ 00250 @Override 00251 public ServiceInfo getServiceInfo(boolean persistent) { 00252 00253 ServiceInfoImpl info = (ServiceInfoImpl) super.getServiceInfo(persistent); 00254 info.addAddress((Inet6Address) _addr); 00255 return info; 00256 } 00257 00258 } 00259 00263 public static abstract class Address extends DNSRecord { 00264 private static Logger logger1 = Logger.getLogger(Address.class.getName()); 00265 00266 InetAddress _addr; 00267 00268 protected Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique, int ttl, InetAddress addr) { 00269 super(name, type, recordClass, unique, ttl); 00270 this._addr = addr; 00271 } 00272 00273 protected Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique, int ttl, byte[] rawAddress) { 00274 super(name, type, recordClass, unique, ttl); 00275 try { 00276 this._addr = InetAddress.getByAddress(rawAddress); 00277 } catch (UnknownHostException exception) { 00278 logger1.log(Level.WARNING, "Address() exception ", exception); 00279 } 00280 } 00281 00282 boolean same(DNSRecord other) { 00283 if (! (other instanceof Address) ) { 00284 return false; 00285 } 00286 return ((sameName(other)) && ((sameValue(other)))); 00287 } 00288 00289 boolean sameName(DNSRecord other) { 00290 return this.getName().equalsIgnoreCase(other.getName()); 00291 } 00292 00293 @Override 00294 boolean sameValue(DNSRecord other) { 00295 if (! (other instanceof Address) ) { 00296 return false; 00297 } 00298 Address address = (Address) other; 00299 if ((this.getAddress() == null) && (address.getAddress() != null)) { 00300 return false; 00301 } 00302 return this.getAddress().equals(address.getAddress()); 00303 } 00304 00305 @Override 00306 public boolean isSingleValued() { 00307 return false; 00308 } 00309 00310 InetAddress getAddress() { 00311 return _addr; 00312 } 00313 00317 @Override 00318 protected void toByteArray(DataOutputStream dout) throws IOException { 00319 super.toByteArray(dout); 00320 byte[] buffer = this.getAddress().getAddress(); 00321 for (int i = 0; i < buffer.length; i++) { 00322 dout.writeByte(buffer[i]); 00323 } 00324 } 00325 00329 @Override 00330 boolean handleQuery(JmDNSImpl dns, long expirationTime) { 00331 if (dns.getLocalHost().conflictWithRecord(this)) { 00332 DNSRecord.Address localAddress = dns.getLocalHost().getDNSAddressRecord(this.getRecordType(), this.isUnique(), DNSConstants.DNS_TTL); 00333 int comparison = this.compareTo(localAddress); 00334 00335 if (comparison == 0) { 00336 // the 2 records are identical this probably means we are seeing our own record. 00337 // With multiple interfaces on a single computer it is possible to see our 00338 // own records come in on different interfaces than the ones they were sent on. 00339 // see section "10. Conflict Resolution" of mdns draft spec. 00340 logger1.finer("handleQuery() Ignoring an identical address query"); 00341 return false; 00342 } 00343 00344 logger1.finer("handleQuery() Conflicting query detected."); 00345 // Tie breaker test 00346 if (dns.isProbing() && comparison > 0) { 00347 // We lost the tie-break. We have to choose a different name. 00348 dns.getLocalHost().incrementHostName(); 00349 dns.getCache().clear(); 00350 for (ServiceInfo serviceInfo : dns.getServices().values()) { 00351 ServiceInfoImpl info = (ServiceInfoImpl) serviceInfo; 00352 info.revertState(); 00353 } 00354 } 00355 dns.revertState(); 00356 return true; 00357 } 00358 return false; 00359 } 00360 00364 @Override 00365 boolean handleResponse(JmDNSImpl dns) { 00366 if (dns.getLocalHost().conflictWithRecord(this)) { 00367 logger1.finer("handleResponse() Denial detected"); 00368 00369 if (dns.isProbing()) { 00370 dns.getLocalHost().incrementHostName(); 00371 dns.getCache().clear(); 00372 for (ServiceInfo serviceInfo : dns.getServices().values()) { 00373 ServiceInfoImpl info = (ServiceInfoImpl) serviceInfo; 00374 info.revertState(); 00375 } 00376 } 00377 dns.revertState(); 00378 return true; 00379 } 00380 return false; 00381 } 00382 00383 @Override 00384 DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException { 00385 return out; 00386 } 00387 00388 /* 00389 * (non-Javadoc) 00390 * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean) 00391 */ 00392 @Override 00393 public ServiceInfo getServiceInfo(boolean persistent) { 00394 ServiceInfoImpl info = new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, (byte[]) null); 00395 // info.setAddress(_addr); This is done in the sub class so we don't have to test for class type 00396 return info; 00397 } 00398 00399 /* 00400 * (non-Javadoc) 00401 * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl) 00402 */ 00403 @Override 00404 public ServiceEvent getServiceEvent(JmDNSImpl dns) { 00405 ServiceInfo info = this.getServiceInfo(false); 00406 ((ServiceInfoImpl) info).setDns(dns); 00407 return new ServiceEventImpl(dns, info.getType(), info.getName(), info); 00408 } 00409 00410 /* 00411 * (non-Javadoc) 00412 * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder) 00413 */ 00414 @Override 00415 protected void toString(StringBuilder aLog) { 00416 super.toString(aLog); 00417 aLog.append(" address: '" + (this.getAddress() != null ? this.getAddress().getHostAddress() : "null") + "'"); 00418 } 00419 00420 } 00421 00425 public static class Pointer extends DNSRecord { 00426 // private static Logger logger = Logger.getLogger(Pointer.class.getName()); 00427 private final String _alias; 00428 00429 public Pointer(String name, DNSRecordClass recordClass, boolean unique, int ttl, String alias) { 00430 super(name, DNSRecordType.TYPE_PTR, recordClass, unique, ttl); 00431 this._alias = alias; 00432 } 00433 00434 /* 00435 * (non-Javadoc) 00436 * @see javax.jmdns.impl.DNSEntry#isSameEntry(javax.jmdns.impl.DNSEntry) 00437 */ 00438 @Override 00439 public boolean isSameEntry(DNSEntry entry) { 00440 return super.isSameEntry(entry) && (entry instanceof Pointer) && this.sameValue((Pointer) entry); 00441 } 00442 00443 @Override 00444 void write(MessageOutputStream out) { 00445 out.writeName(_alias); 00446 } 00447 00448 @Override 00449 boolean sameValue(DNSRecord other) { 00450 if (! (other instanceof Pointer) ) { 00451 return false; 00452 } 00453 Pointer pointer = (Pointer) other; 00454 if ((_alias == null) && (pointer._alias != null)) { 00455 return false; 00456 } 00457 return _alias.equals(pointer._alias); 00458 } 00459 00460 @Override 00461 public boolean isSingleValued() { 00462 return false; 00463 } 00464 00465 @Override 00466 boolean handleQuery(JmDNSImpl dns, long expirationTime) { 00467 // Nothing to do (?) 00468 // I think there is no possibility for conflicts for this record type? 00469 return false; 00470 } 00471 00472 @Override 00473 boolean handleResponse(JmDNSImpl dns) { 00474 // Nothing to do (?) 00475 // I think there is no possibility for conflicts for this record type? 00476 return false; 00477 } 00478 00479 String getAlias() { 00480 return _alias; 00481 } 00482 00483 @Override 00484 DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException { 00485 return out; 00486 } 00487 00488 /* 00489 * (non-Javadoc) 00490 * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean) 00491 */ 00492 @Override 00493 public ServiceInfo getServiceInfo(boolean persistent) { 00494 if (this.isServicesDiscoveryMetaQuery()) { 00495 // The service name is in the alias 00496 Map<Fields, String> map = ServiceInfoImpl.decodeQualifiedNameMapForType(this.getAlias()); 00497 return new ServiceInfoImpl(map, 0, 0, 0, persistent, (byte[]) null); 00498 } else if (this.isReverseLookup()) { 00499 return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, (byte[]) null); 00500 } else if (this.isDomainDiscoveryQuery()) { 00501 // FIXME [PJYF Nov 16 2010] We do not currently support domain discovery 00502 return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, (byte[]) null); 00503 } 00504 Map<Fields, String> map = ServiceInfoImpl.decodeQualifiedNameMapForType(this.getAlias()); 00505 map.put(Fields.Subtype, this.getQualifiedNameMap().get(Fields.Subtype)); 00506 return new ServiceInfoImpl(map, 0, 0, 0, persistent, this.getAlias()); 00507 } 00508 00509 /* 00510 * (non-Javadoc) 00511 * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl) 00512 */ 00513 @Override 00514 public ServiceEvent getServiceEvent(JmDNSImpl dns) { 00515 ServiceInfo info = this.getServiceInfo(false); 00516 ((ServiceInfoImpl) info).setDns(dns); 00517 String domainName = info.getType(); 00518 String serviceName = JmDNSImpl.toUnqualifiedName(domainName, this.getAlias()); 00519 return new ServiceEventImpl(dns, domainName, serviceName, info); 00520 } 00521 00522 /* 00523 * (non-Javadoc) 00524 * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder) 00525 */ 00526 @Override 00527 protected void toString(StringBuilder aLog) { 00528 super.toString(aLog); 00529 aLog.append(" alias: '" + (_alias != null ? _alias.toString() : "null") + "'"); 00530 } 00531 00532 } 00533 00534 public final static byte[] EMPTY_TXT = new byte[] { 0 }; 00535 00536 public static class Text extends DNSRecord { 00537 // private static Logger logger = Logger.getLogger(Text.class.getName()); 00538 private final byte[] _text; 00539 00540 public Text(String name, DNSRecordClass recordClass, boolean unique, int ttl, byte text[]) { 00541 super(name, DNSRecordType.TYPE_TXT, recordClass, unique, ttl); 00542 this._text = (text != null && text.length > 0 ? text : EMPTY_TXT); 00543 } 00544 00548 byte[] getText() { 00549 return this._text; 00550 } 00551 00552 @Override 00553 void write(MessageOutputStream out) { 00554 out.writeBytes(_text, 0, _text.length); 00555 } 00556 00557 @Override 00558 boolean sameValue(DNSRecord other) { 00559 if (! (other instanceof Text) ) { 00560 return false; 00561 } 00562 Text txt = (Text) other; 00563 if ((_text == null) && (txt._text != null)) { 00564 return false; 00565 } 00566 if (txt._text.length != _text.length) { 00567 return false; 00568 } 00569 for (int i = _text.length; i-- > 0;) { 00570 if (txt._text[i] != _text[i]) { 00571 return false; 00572 } 00573 } 00574 return true; 00575 } 00576 00577 @Override 00578 public boolean isSingleValued() { 00579 return true; 00580 } 00581 00582 @Override 00583 boolean handleQuery(JmDNSImpl dns, long expirationTime) { 00584 // Nothing to do (?) 00585 // I think there is no possibility for conflicts for this record type? 00586 return false; 00587 } 00588 00589 @Override 00590 boolean handleResponse(JmDNSImpl dns) { 00591 // Nothing to do (?) 00592 // Shouldn't we care if we get a conflict at this level? 00593 /* 00594 * ServiceInfo info = (ServiceInfo) dns.services.get(name.toLowerCase()); if (info != null) { if (! Arrays.equals(text,info.text)) { info.revertState(); return true; } } 00595 */ 00596 return false; 00597 } 00598 00599 @Override 00600 DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException { 00601 return out; 00602 } 00603 00604 /* 00605 * (non-Javadoc) 00606 * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean) 00607 */ 00608 @Override 00609 public ServiceInfo getServiceInfo(boolean persistent) { 00610 return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, _text); 00611 } 00612 00613 /* 00614 * (non-Javadoc) 00615 * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl) 00616 */ 00617 @Override 00618 public ServiceEvent getServiceEvent(JmDNSImpl dns) { 00619 ServiceInfo info = this.getServiceInfo(false); 00620 ((ServiceInfoImpl) info).setDns(dns); 00621 return new ServiceEventImpl(dns, info.getType(), info.getName(), info); 00622 } 00623 00624 /* 00625 * (non-Javadoc) 00626 * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder) 00627 */ 00628 @Override 00629 protected void toString(StringBuilder aLog) { 00630 super.toString(aLog); 00631 aLog.append(" text: '" + ((_text.length > 20) ? new String(_text, 0, 17) + "..." : new String(_text)) + "'"); 00632 } 00633 00634 } 00635 00639 public static class Service extends DNSRecord { 00640 private static Logger logger1 = Logger.getLogger(Service.class.getName()); 00641 private final int _priority; 00642 private final int _weight; 00643 private final int _port; 00644 private final String _server; 00645 00646 public Service(String name, DNSRecordClass recordClass, boolean unique, int ttl, int priority, int weight, int port, String server) { 00647 super(name, DNSRecordType.TYPE_SRV, recordClass, unique, ttl); 00648 this._priority = priority; 00649 this._weight = weight; 00650 this._port = port; 00651 this._server = server; 00652 } 00653 00654 @Override 00655 void write(MessageOutputStream out) { 00656 out.writeShort(_priority); 00657 out.writeShort(_weight); 00658 out.writeShort(_port); 00659 if (DNSIncoming.USE_DOMAIN_NAME_FORMAT_FOR_SRV_TARGET) { 00660 out.writeName(_server); 00661 } else { 00662 // [PJYF Nov 13 2010] Do we still need this? This looks really bad. All label are supposed to start by a length. 00663 out.writeUTF(_server, 0, _server.length()); 00664 00665 // add a zero byte to the end just to be safe, this is the strange form 00666 // used by the BonjourConformanceTest 00667 out.writeByte(0); 00668 } 00669 } 00670 00671 @Override 00672 protected void toByteArray(DataOutputStream dout) throws IOException { 00673 super.toByteArray(dout); 00674 dout.writeShort(_priority); 00675 dout.writeShort(_weight); 00676 dout.writeShort(_port); 00677 try { 00678 dout.write(_server.getBytes("UTF-8")); 00679 } catch (UnsupportedEncodingException exception) { 00680 /* UTF-8 is always present */ 00681 } 00682 } 00683 00684 String getServer() { 00685 return _server; 00686 } 00687 00691 public int getPriority() { 00692 return this._priority; 00693 } 00694 00698 public int getWeight() { 00699 return this._weight; 00700 } 00701 00705 public int getPort() { 00706 return this._port; 00707 } 00708 00709 @Override 00710 boolean sameValue(DNSRecord other) { 00711 if (! (other instanceof Service) ) { 00712 return false; 00713 } 00714 Service s = (Service) other; 00715 return (_priority == s._priority) && (_weight == s._weight) && (_port == s._port) && _server.equals(s._server); 00716 } 00717 00718 @Override 00719 public boolean isSingleValued() { 00720 return true; 00721 } 00722 00723 @Override 00724 boolean handleQuery(JmDNSImpl dns, long expirationTime) { 00725 ServiceInfoImpl info = (ServiceInfoImpl) dns.getServices().get(this.getKey()); 00726 if (info != null && (info.isAnnouncing() || info.isAnnounced()) && (_port != info.getPort() || !_server.equalsIgnoreCase(dns.getLocalHost().getName()))) { 00727 logger1.finer("handleQuery() Conflicting probe detected from: " + getRecordSource()); 00728 DNSRecord.Service localService = new DNSRecord.Service(info.getQualifiedName(), DNSRecordClass.CLASS_IN, DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL, info.getPriority(), info.getWeight(), info.getPort(), dns.getLocalHost().getName()); 00729 00730 // This block is useful for debugging race conditions when jmdns is responding to itself. 00731 try { 00732 if (dns.getInetAddress().equals(getRecordSource())) { 00733 logger1.warning("Got conflicting probe from ourselves\n" + "incoming: " + this.toString() + "\n" + "local : " + localService.toString()); 00734 } 00735 } catch (IOException e) { 00736 logger1.log(Level.WARNING, "IOException", e); 00737 } 00738 00739 int comparison = this.compareTo(localService); 00740 00741 if (comparison == 0) { 00742 // the 2 records are identical this probably means we are seeing our own record. 00743 // With multiple interfaces on a single computer it is possible to see our 00744 // own records come in on different interfaces than the ones they were sent on. 00745 // see section "10. Conflict Resolution" of mdns draft spec. 00746 logger1.finer("handleQuery() Ignoring a identical service query"); 00747 return false; 00748 } 00749 00750 // Tie breaker test 00751 if (info.isProbing() && comparison > 0) { 00752 // We lost the tie break 00753 String oldName = info.getQualifiedName().toLowerCase(); 00754 info.setName(dns.incrementName(info.getName())); 00755 dns.getServices().remove(oldName); 00756 dns.getServices().put(info.getQualifiedName().toLowerCase(), info); 00757 logger1.finer("handleQuery() Lost tie break: new unique name chosen:" + info.getName()); 00758 00759 // We revert the state to start probing again with the new name 00760 info.revertState(); 00761 } else { 00762 // We won the tie break, so this conflicting probe should be ignored 00763 // See paragraph 3 of section 9.2 in mdns draft spec 00764 return false; 00765 } 00766 00767 return true; 00768 00769 } 00770 return false; 00771 } 00772 00773 @Override 00774 boolean handleResponse(JmDNSImpl dns) { 00775 ServiceInfoImpl info = (ServiceInfoImpl) dns.getServices().get(this.getKey()); 00776 if (info != null && (_port != info.getPort() || !_server.equalsIgnoreCase(dns.getLocalHost().getName()))) { 00777 logger1.finer("handleResponse() Denial detected"); 00778 00779 if (info.isProbing()) { 00780 String oldName = info.getQualifiedName().toLowerCase(); 00781 info.setName(dns.incrementName(info.getName())); 00782 dns.getServices().remove(oldName); 00783 dns.getServices().put(info.getQualifiedName().toLowerCase(), info); 00784 logger1.finer("handleResponse() New unique name chose:" + info.getName()); 00785 00786 } 00787 info.revertState(); 00788 return true; 00789 } 00790 return false; 00791 } 00792 00793 @Override 00794 DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException { 00795 ServiceInfoImpl info = (ServiceInfoImpl) dns.getServices().get(this.getKey()); 00796 if (info != null) { 00797 if (this._port == info.getPort() != _server.equals(dns.getLocalHost().getName())) { 00798 return dns.addAnswer(in, addr, port, out, new DNSRecord.Service(info.getQualifiedName(), DNSRecordClass.CLASS_IN, DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL, info.getPriority(), info.getWeight(), info.getPort(), dns 00799 .getLocalHost().getName())); 00800 } 00801 } 00802 return out; 00803 } 00804 00805 /* 00806 * (non-Javadoc) 00807 * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean) 00808 */ 00809 @Override 00810 public ServiceInfo getServiceInfo(boolean persistent) { 00811 return new ServiceInfoImpl(this.getQualifiedNameMap(), _port, _weight, _priority, persistent, _server); 00812 } 00813 00814 /* 00815 * (non-Javadoc) 00816 * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl) 00817 */ 00818 @Override 00819 public ServiceEvent getServiceEvent(JmDNSImpl dns) { 00820 ServiceInfo info = this.getServiceInfo(false); 00821 ((ServiceInfoImpl) info).setDns(dns); 00822 // String domainName = ""; 00823 // String serviceName = this.getServer(); 00824 // int index = serviceName.indexOf('.'); 00825 // if (index > 0) 00826 // { 00827 // serviceName = this.getServer().substring(0, index); 00828 // if (index + 1 < this.getServer().length()) 00829 // domainName = this.getServer().substring(index + 1); 00830 // } 00831 // return new ServiceEventImpl(dns, domainName, serviceName, info); 00832 return new ServiceEventImpl(dns, info.getType(), info.getName(), info); 00833 00834 } 00835 00836 /* 00837 * (non-Javadoc) 00838 * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder) 00839 */ 00840 @Override 00841 protected void toString(StringBuilder aLog) { 00842 super.toString(aLog); 00843 aLog.append(" server: '" + _server + ":" + _port + "'"); 00844 } 00845 00846 } 00847 00848 public static class HostInformation extends DNSRecord { 00849 String _os; 00850 String _cpu; 00851 00860 public HostInformation(String name, DNSRecordClass recordClass, boolean unique, int ttl, String cpu, String os) { 00861 super(name, DNSRecordType.TYPE_HINFO, recordClass, unique, ttl); 00862 _cpu = cpu; 00863 _os = os; 00864 } 00865 00866 /* 00867 * (non-Javadoc) 00868 * @see javax.jmdns.impl.DNSRecord#addAnswer(javax.jmdns.impl.JmDNSImpl, javax.jmdns.impl.DNSIncoming, java.net.InetAddress, int, javax.jmdns.impl.DNSOutgoing) 00869 */ 00870 @Override 00871 DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException { 00872 return out; 00873 } 00874 00875 /* 00876 * (non-Javadoc) 00877 * @see javax.jmdns.impl.DNSRecord#handleQuery(javax.jmdns.impl.JmDNSImpl, long) 00878 */ 00879 @Override 00880 boolean handleQuery(JmDNSImpl dns, long expirationTime) { 00881 return false; 00882 } 00883 00884 /* 00885 * (non-Javadoc) 00886 * @see javax.jmdns.impl.DNSRecord#handleResponse(javax.jmdns.impl.JmDNSImpl) 00887 */ 00888 @Override 00889 boolean handleResponse(JmDNSImpl dns) { 00890 return false; 00891 } 00892 00893 /* 00894 * (non-Javadoc) 00895 * @see javax.jmdns.impl.DNSRecord#sameValue(javax.jmdns.impl.DNSRecord) 00896 */ 00897 @Override 00898 boolean sameValue(DNSRecord other) { 00899 if (! (other instanceof HostInformation) ) { 00900 return false; 00901 } 00902 HostInformation hinfo = (HostInformation) other; 00903 if ((_cpu == null) && (hinfo._cpu != null)) { 00904 return false; 00905 } 00906 if ((_os == null) && (hinfo._os != null)) { 00907 return false; 00908 } 00909 return _cpu.equals(hinfo._cpu) && _os.equals(hinfo._os); 00910 } 00911 00912 /* 00913 * (non-Javadoc) 00914 * @see javax.jmdns.impl.DNSRecord#isSingleValued() 00915 */ 00916 @Override 00917 public boolean isSingleValued() { 00918 return true; 00919 } 00920 00921 /* 00922 * (non-Javadoc) 00923 * @see javax.jmdns.impl.DNSRecord#write(javax.jmdns.impl.DNSOutgoing) 00924 */ 00925 @Override 00926 void write(MessageOutputStream out) { 00927 String hostInfo = _cpu + " " + _os; 00928 out.writeUTF(hostInfo, 0, hostInfo.length()); 00929 } 00930 00931 /* 00932 * (non-Javadoc) 00933 * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean) 00934 */ 00935 @Override 00936 public ServiceInfo getServiceInfo(boolean persistent) { 00937 Map<String, String> hinfo = new HashMap<String, String>(2); 00938 hinfo.put("cpu", _cpu); 00939 hinfo.put("os", _os); 00940 return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, hinfo); 00941 } 00942 00943 /* 00944 * (non-Javadoc) 00945 * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl) 00946 */ 00947 @Override 00948 public ServiceEvent getServiceEvent(JmDNSImpl dns) { 00949 ServiceInfo info = this.getServiceInfo(false); 00950 ((ServiceInfoImpl) info).setDns(dns); 00951 return new ServiceEventImpl(dns, info.getType(), info.getName(), info); 00952 } 00953 00954 /* 00955 * (non-Javadoc) 00956 * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder) 00957 */ 00958 @Override 00959 protected void toString(StringBuilder aLog) { 00960 super.toString(aLog); 00961 aLog.append(" cpu: '" + _cpu + "' os: '" + _os + "'"); 00962 } 00963 00964 } 00965 00971 public abstract boolean isSingleValued(); 00972 00978 public ServiceInfo getServiceInfo() { 00979 return this.getServiceInfo(false); 00980 } 00981 00989 public abstract ServiceInfo getServiceInfo(boolean persistent); 00990 00998 public abstract ServiceEvent getServiceEvent(JmDNSImpl dns); 00999 01000 public void setRecordSource(InetAddress source) { 01001 this._source = source; 01002 } 01003 01004 public InetAddress getRecordSource() { 01005 return _source; 01006 } 01007 01008 /* 01009 * (non-Javadoc) 01010 * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder) 01011 */ 01012 @Override 01013 protected void toString(StringBuilder aLog) { 01014 super.toString(aLog); 01015 aLog.append(" ttl: '" + getRemainingTTL(System.currentTimeMillis()) + "/" + _ttl + "'"); 01016 } 01017 01018 public void setTTL(int ttl) { 01019 this._ttl = ttl; 01020 } 01021 01022 public int getTTL() { 01023 return _ttl; 01024 } 01025 }