Changeset 94e34ff


Ignore:
Timestamp:
May 8, 2013 4:48:39 PM (8 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
3a49d6d
Parents:
af27c76
Message:

RouterAddress?:

  • Add new constructor
  • Add add getHost() and deepEquals()
  • Compare host string, not IP, in equals()

SSU:

  • Remove all _external* fields; use _currentAddresses in super
  • Big rework of externalAddressReceived(), rebuildExternalAddress(), needsRebuild(), and replaceAddress() for multiple addresses and IPv6
  • Add caching in UDPAddress
  • More IPv6 flavors of utility methods
  • Remove two-art replaceAddress()
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/data/RouterAddress.java

    raf27c76 r94e34ff  
    5656
    5757    /**
     58     *  For efficiency when created by a Transport.
     59     *  @param options not copied; do not reuse or modify
     60     *  @since IPv6
     61     */
     62    public RouterAddress(String style, OrderedProperties options, int cost) {
     63        _transportStyle = style;
     64        _options = options;
     65        _cost = cost;
     66    }
     67
     68    /**
    5869     * Retrieve the weighted cost of this address, relative to other methods of
    5970     * contacting this router.  The value 0 means free and 255 means really expensive.
     
    172183            return _ip;
    173184        byte[] rv = null;
    174         String host = _options.getProperty(PROP_HOST);
     185        String host = getHost();
    175186        if (host != null) {
    176187            rv = Addresses.getIP(host);
     
    182193        }
    183194        return rv;
     195    }
     196   
     197    /**
     198     *  Convenience, same as getOption("host").
     199     *  Does no parsing, so faster than getIP().
     200     *
     201     *  @return host string or null
     202     *  @since IPv6
     203     */
     204    public String getHost() {
     205        return _options.getProperty(PROP_HOST);
    184206    }
    185207   
     
    240262   
    241263    /**
    242      * Transport, IP, and port only.
     264     * Transport, host, and port only.
    243265     * Never look at cost or other properties.
    244266     */
     
    250272        return
    251273               getPort() == addr.getPort() &&
    252                DataHelper.eq(getIP(), addr.getIP()) &&
     274               DataHelper.eq(getHost(), addr.getHost()) &&
    253275               DataHelper.eq(_transportStyle, addr._transportStyle);
    254276               //DataHelper.eq(_options, addr._options) &&
    255277               //DataHelper.eq(_expiration, addr._expiration);
     278    }
     279   
     280    /**
     281     *  Everything, including Transport, host, port, options, and cost
     282     *  @param addr may be null
     283     *  @since IPv6
     284     */
     285    public boolean deepEquals(RouterAddress addr) {
     286        return
     287               equals(addr) &&
     288               _cost == addr._cost &&
     289               _options.equals(addr._options);
    256290    }
    257291   
  • router/java/src/net/i2p/router/transport/TransportImpl.java

    raf27c76 r94e34ff  
    481481
    482482    /**
     483     *  What address are we currently listening to?
     484     *  Replaces getCurrentAddress()
     485     *  @param ipv6 true for IPv6 only; false for IPv4 only
     486     *  @return first matching address or null
     487     *  @since IPv6
     488     */
     489    public RouterAddress getCurrentAddress(boolean ipv6) {
     490        for (RouterAddress ra : _currentAddresses) {
     491            if (ipv6 == TransportUtil.isIPv6(ra))
     492                return ra;
     493        }
     494        return null;
     495    }
     496
     497    /**
    483498     *  Do we have any current address?
    484499     *  @since IPv6
     
    512527            _currentAddresses.clear();
    513528        } else {
    514             byte[] ip = address.getIP();
    515             if (ip == null) {
    516                 _log.error("WTF null ip for " + address);
    517                 return;
    518             }
    519             int len = ip.length;
     529            boolean isIPv6 = TransportUtil.isIPv6(address);
    520530            for (RouterAddress ra : _currentAddresses) {
    521                 byte[] ipx = ra.getIP();
    522                 if (ipx != null && ipx.length == len)
     531                if (isIPv6 == TransportUtil.isIPv6(ra))
    523532                    _currentAddresses.remove(ra);
    524533            }
  • router/java/src/net/i2p/router/transport/TransportUtil.java

    raf27c76 r94e34ff  
    1414import java.util.Map;
    1515
     16import net.i2p.data.RouterAddress;
    1617import net.i2p.router.RouterContext;
    1718
     
    8081
    8182    /**
     83     *  Addresses without a host (i.e. w/introducers)
     84     *  are assumed to be IPv4
     85     */
     86    public static boolean isIPv6(RouterAddress addr) {
     87        // do this the fast way, without calling getIP() to parse the host string
     88        String host = addr.getOption(RouterAddress.PROP_HOST);
     89        return host != null && host.contains(":");
     90    }
     91
     92    /**
    8293     *  @param addr non-null
    8394     *  @since IPv6 moved from TransportImpl
  • router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java

    raf27c76 r94e34ff  
    448448                if (!_transport.allowConnection())
    449449                    return; // drop the packet
    450                 state = new InboundEstablishState(_context, from.getIP(), from.getPort(), _transport.getExternalPort(),
     450                byte[] fromIP = from.getIP();
     451                state = new InboundEstablishState(_context, fromIP, from.getPort(),
     452                                                  _transport.getExternalPort(fromIP.length == 16),
    451453                                                  _transport.getDHBuilder());
    452454                state.receiveSessionRequest(reader.getSessionRequestReader());
     
    836838            return;
    837839        }
    838         _transport.send(_builder.buildSessionCreatedPacket(state, _transport.getExternalPort(), _transport.getIntroKey()));
     840        _transport.send(_builder.buildSessionCreatedPacket(state,
     841                                                           _transport.getExternalPort(state.getSentIP().length == 16),
     842                                                           _transport.getIntroKey()));
    839843        state.createdPacketSent();
    840844    }
  • router/java/src/net/i2p/router/transport/udp/UDPAddress.java

    raf27c76 r94e34ff  
    33import java.net.InetAddress;
    44import java.net.UnknownHostException;
     5import java.util.Map;
    56
    67import net.i2p.data.Base64;
    78import net.i2p.data.RouterAddress;
    89import net.i2p.data.SessionKey;
     10import net.i2p.util.LHMCache;
    911
    1012/**
     
    134136
    135137    InetAddress getHostAddress() {
    136         if (_hostAddress == null) {
    137             try {
    138                 _hostAddress = InetAddress.getByName(_host);
    139             } catch (UnknownHostException uhe) {
    140                 _hostAddress = null;
    141             }
    142         }
     138        if (_hostAddress == null)
     139            _hostAddress = getByName(_host);
    143140        return _hostAddress;
    144141    }
     
    154151
    155152    InetAddress getIntroducerHost(int i) {
    156         if (_introAddresses[i] == null) {
    157             try {
    158                 _introAddresses[i] = InetAddress.getByName(_introHosts[i]);
    159             } catch (UnknownHostException uhe) {
    160                 _introAddresses[i] = null;
    161             }
    162         }
     153        if (_introAddresses[i] == null)
     154            _introAddresses[i] = getByName(_introHosts[i]);
    163155        return _introAddresses[i];
    164156    }
     
    198190        return rv.toString();
    199191    }
     192
     193    ////////////////
     194    // cache copied from Addresses.java but caching InetAddress instead of byte[]
     195
     196
     197    /**
     198     *  Textual IP to InetAddress, because InetAddress.getByName() is slow.
     199     *
     200     *  @since IPv6
     201     */
     202    private static final Map<String, InetAddress> _inetAddressCache;
     203
     204    static {
     205        long maxMemory = Runtime.getRuntime().maxMemory();
     206        if (maxMemory == Long.MAX_VALUE)
     207            maxMemory = 96*1024*1024l;
     208        long min = 128;
     209        long max = 2048;
     210        // 512 nominal for 128 MB
     211        int size = (int) Math.max(min, Math.min(max, 1 + (maxMemory / (256*1024))));
     212        _inetAddressCache = new LHMCache(size);
     213    }
     214
     215    /**
     216     *  Caching version of InetAddress.getByName(host), which is slow.
     217     *  Caches numeric host names only.
     218     *  Will resolve but not cache DNS host names.
     219     *
     220     *  Unlike InetAddress.getByName(), we do NOT allow numeric IPs
     221     *  of the form d.d.d, d.d, or d, as these are almost certainly mistakes.
     222     *
     223     *  @param host DNS or IPv4 or IPv6 host name; if null returns null
     224     *  @return InetAddress or null
     225     *  @since IPv6
     226     */
     227    private static InetAddress getByName(String host) {
     228        if (host == null)
     229            return null;
     230        InetAddress rv;
     231        synchronized (_inetAddressCache) {
     232            rv = _inetAddressCache.get(host);
     233        }
     234        if (rv == null) {
     235            try {
     236                boolean isIPv4 = host.replaceAll("[0-9\\.]", "").length() == 0;
     237                if (isIPv4 && host.replaceAll("[0-9]", "").length() != 3)
     238                    return null;
     239                rv = InetAddress.getByName(host);
     240                if (isIPv4 ||
     241                    host.replaceAll("[0-9a-fA-F:]", "").length() == 0) {
     242                    synchronized (_inetAddressCache) {
     243                        _inetAddressCache.put(host, rv);
     244                    }
     245                }
     246            } catch (UnknownHostException uhe) {}
     247        }
     248        return rv;
     249    }
     250
     251    /**
     252     *  @since IPv6
     253     */
     254    static void clearCache() {
     255        synchronized(_inetAddressCache) {
     256            _inetAddressCache.clear();
     257        }
     258    }
    200259}
  • router/java/src/net/i2p/router/transport/udp/UDPTransport.java

    raf27c76 r94e34ff  
    4646import net.i2p.util.ConcurrentHashSet;
    4747import net.i2p.util.Log;
     48import net.i2p.util.OrderedProperties;
    4849import net.i2p.util.SimpleScheduler;
    4950import net.i2p.util.SimpleTimer;
     
    9192    private boolean _needsRebuild;
    9293   
    93     /** summary info to distribute */
    94     private RouterAddress _externalAddress;
    95     /**
    96      * Port number on which we can be reached, or -1 for error, or 0 for unset
    97      * Do NOT use this for current internal port - use UDPEndpoint.getListenPort()
    98      */
    99     private int _externalListenPort;
    100     /** IP address of externally reachable host, or null */
    101     private InetAddress _externalListenHost;
    10294    /** introduction key */
    10395    private SessionKey _introKey;
     
    333325        int port;
    334326        int oldIPort = _context.getProperty(PROP_INTERNAL_PORT, -1);
    335         int oldBindPort = getIPv4ListenPort();
     327        int oldBindPort = getListenPort(false);
    336328        int oldEPort = _context.getProperty(PROP_EXTERNAL_PORT, -1);
    337329        if (oldIPort > 0)
     
    388380                if (newPort < 0 && endpoint.isIPv4()) {
    389381                    newPort = endpoint.getListenPort();
    390                     _externalListenPort = newPort;
    391382                }
    392383            } catch (SocketException se) {
     
    450441        _introManager.reset();
    451442        UDPPacket.clearCache();
     443        UDPAddress.clearCache();
    452444    }
    453445   
     
    458450    SessionKey getIntroKey() { return _introKey; }
    459451
    460     int getExternalPort() { return _externalListenPort; }
    461 
    462     /**
     452    int getExternalPort(boolean ipv6) {
     453        RouterAddress addr = getCurrentAddress(ipv6);
     454        if (addr != null) {
     455            int rv = addr.getPort();
     456            if (rv > 0)
     457                return rv;
     458        }
     459        return getRequestedPort(ipv6);
     460    }
     461
     462    /**
     463     *  IPv4 only
    463464     *  @return IP or null
    464465     *  @since 0.9.2
    465466     */
    466467    byte[] getExternalIP() {
    467        InetAddress ia = _externalListenHost;
    468        if (ia == null)
    469            return null;
    470        return ia.getAddress();
    471     }
    472 
    473     /**
    474      *  The current port of the first IPv4 endpoint.
    475      *  To be enhanced to handle multiple IPv4 endpoints.
     468        RouterAddress addr = getCurrentAddress(false);
     469        if (addr != null)
     470            return addr.getIP();
     471        return null;
     472    }
     473
     474    /**
     475     *  The current port of the first matching endpoint.
     476     *  To be enhanced to handle multiple endpoints of the same type.
    476477     *  @return port or -1
    477478     *  @since IPv6
    478479     */
    479     private int getIPv4ListenPort() {
     480    private int getListenPort(boolean ipv6) {
    480481        for (UDPEndpoint endpoint : _endpoints) {
    481             if (endpoint.isIPv4())
     482            if (((!ipv6) && endpoint.isIPv4()) ||
     483                (ipv6 && endpoint.isIPv6()))
    482484                return endpoint.getListenPort();
    483485       }
    484486       return -1;
     487    }
     488
     489    /**
     490     *  The current or configured internal IPv4 port.
     491     *  UDPEndpoint should always be instantiated (and a random port picked if not configured)
     492     *  before this is called, so the returned value should be > 0
     493     *  unless the endpoint failed to bind.
     494     */
     495    @Override
     496    public int getRequestedPort() {
     497        return getRequestedPort(false);
    485498    }
    486499
     
    491504     *  unless the endpoint failed to bind.
    492505     */
    493     @Override
    494     public int getRequestedPort() {
    495         int rv = getIPv4ListenPort();
     506    private int getRequestedPort(boolean ipv6) {
     507        int rv = getListenPort(ipv6);
    496508        if (rv > 0)
    497509            return rv;
     
    605617                _log.warn("UPnP has failed to open the SSU port: " + port + " reason: " + reason);
    606618        }
    607         if (success && _externalListenHost != null)
     619        if (success && getExternalIP() != null)
    608620            setReachabilityStatus(CommSystemFacade.STATUS_OK);
    609621    }
     
    629641            return;
    630642        boolean isValid = isValid(ourIP) &&
    631                           ((ourPort >= MIN_EXTERNAL_PORT && ourPort <= MAX_EXTERNAL_PORT) ||
    632                            ourPort == _externalListenPort || _externalListenPort <= 0);
     643                          (ourPort >= MIN_EXTERNAL_PORT && ourPort <= MAX_EXTERNAL_PORT);
    633644        boolean explicitSpecified = explicitAddressSpecified();
    634645        boolean inboundRecent = _lastInboundReceivedOn + ALLOW_IP_CHANGE_INTERVAL > System.currentTimeMillis();
     
    652663            //_context.banlist().banlistRouter(from, "They said we had an invalid IP", STYLE);
    653664            return;
    654         } else if (inboundRecent && _externalListenPort > 0 && _externalListenHost != null) {
     665        }
     666        RouterAddress addr = getCurrentAddress(false);
     667        if (inboundRecent && addr != null && addr.getPort() > 0 && addr.getHost() != null) {
    655668            // use OS clock since its an ordering thing, not a time thing
    656669            // Note that this fails us if we switch from one IP to a second, then back to the first,
     
    687700   
    688701    /**
     702     * Possibly change our external address to the IP/port.
     703     * IP/port are already validated, but not yet compared to current IP/port.
     704     * We compare here.
     705     *
    689706     * @param ourIP MUST have been previously validated with isValid()
    690707     *              IPv4 or IPv6 OK
     
    697714        boolean fireTest = false;
    698715
     716        boolean isIPv6 = ourIP.length == 16;
     717        RouterAddress current = getCurrentAddress(isIPv6);
     718        byte[] externalListenHost = current != null ? current.getIP() : null;
     719        int externalListenPort = current != null ? current.getPort() : getRequestedPort(isIPv6);
     720
    699721        if (_log.shouldLog(Log.INFO))
    700722            _log.info("Change address? status = " + _reachabilityStatus +
    701723                      " diff = " + (_context.clock().now() - _reachabilityStatusLastUpdated) +
    702                       " old = " + _externalListenHost + ':' + _externalListenPort +
     724                      " old = " + Addresses.toString(externalListenHost, externalListenPort) +
    703725                      " new = " + Addresses.toString(ourIP, ourPort));
    704726
     727        if ((fixedPort && externalListenPort > 0) || ourPort <= 0)
     728            ourPort = externalListenPort;
     729
    705730            synchronized (this) {
    706                 if ( (_externalListenHost == null) ||
    707                      (!eq(_externalListenHost.getAddress(), _externalListenPort, ourIP, ourPort)) ) {
     731                if (ourPort > 0 &&
     732                    !eq(externalListenHost, externalListenPort, ourIP, ourPort)) {
    708733                    // This prevents us from changing our IP when we are not firewalled
    709734                    //if ( (_reachabilityStatus != CommSystemFacade.STATUS_OK) ||
     
    711736                    //     (_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) {
    712737                        // they told us something different and our tests are either old or failing
    713                         try {
    714                             _externalListenHost = InetAddress.getByAddress(ourIP);
    715                             // fixed port defaults to true so we never do this
    716                             if (ourPort >= MIN_EXTERNAL_PORT && ourPort <= MAX_EXTERNAL_PORT && !fixedPort)
    717                                 _externalListenPort = ourPort;
    718738                            if (_log.shouldLog(Log.WARN))
    719739                                _log.warn("Trying to change our external address to " +
    720                                           Addresses.toString(ourIP, _externalListenPort));
    721                             if (_externalListenPort > 0)  {
    722                                 rebuildExternalAddress();
    723                                 replaceAddress(_externalAddress);
    724                                 updated = true;
    725                             }
    726                         } catch (UnknownHostException uhe) {
    727                             _externalListenHost = null;
    728                             if (_log.shouldLog(Log.WARN))
    729                                 _log.warn("Error trying to change our external address to " +
    730                                           Addresses.toString(ourIP, ourPort), uhe);
    731                         }
     740                                          Addresses.toString(ourIP, ourPort));
     741                            RouterAddress newAddr = rebuildExternalAddress(ourIP, ourPort, true);
     742                            updated = newAddr != null;
    732743                    //} else {
    733744                    //    // they told us something different, but our tests are recent and positive,
     
    749760            _context.statManager().addRateData("udp.addressUpdated", 1);
    750761            Map<String, String> changes = new HashMap();
    751             if (!fixedPort)
     762            if (ourIP.length == 4 && !fixedPort)
    752763                changes.put(PROP_EXTERNAL_PORT, Integer.toString(ourPort));
    753764            // queue a country code lookup of the new IP
    754             _context.commSystem().queueLookup(ourIP);
     765            if (ourIP.length == 4)
     766                _context.commSystem().queueLookup(ourIP);
    755767            // store these for laptop-mode (change ident on restart... or every time... when IP changes)
     768            // IPV4 ONLY
    756769            String oldIP = _context.getProperty(PROP_IP);
    757             if (!_externalListenHost.getHostAddress().equals(oldIP)) {
     770            String newIP = Addresses.toString(ourIP);
     771            if (ourIP.length == 4 && !newIP.equals(oldIP)) {
    758772                long lastChanged = 0;
    759773                long now = _context.clock().now();
     
    765779                }
    766780
    767                 changes.put(PROP_IP, _externalListenHost.getHostAddress());
     781                changes.put(PROP_IP, newIP);
    768782                changes.put(PROP_IP_CHANGE, Long.toString(now));
    769783                _context.router().saveConfig(changes, null);
     
    785799                    // doesn't return
    786800                }
    787             } else if (!fixedPort) {
     801            } else if (ourIP.length == 4 && !fixedPort) {
    788802                // save PROP_EXTERNAL_PORT
    789803                _context.router().saveConfig(changes, null);
     
    796810    }
    797811
     812    /**
     813     *  @param laddr and raddr may be null
     814     */
    798815    private static final boolean eq(byte laddr[], int lport, byte raddr[], int rport) {
    799816        return (rport == lport) && DataHelper.eq(laddr, raddr);
     
    840857     *  Get the states for all peers at the given remote host, ignoring port.
    841858     *  Used for a last-chance search for a peer that changed port, by PacketHandler.
     859     *  Always returns empty list for IPv6 hostInfo.
    842860     *  @since 0.9.3
    843861     */
     
    845863        List<PeerState> rv = new ArrayList(4);
    846864        byte[] ip = hostInfo.getIP();
    847         if (ip != null) {
     865        if (ip != null && ip.length == 4) {
    848866            for (PeerState ps : _peersByIdent.values()) {
    849867                if (DataHelper.eq(ip, ps.getRemoteIP()))
     
    866884     *  @since 0.9.3
    867885     */
    868     public void changePeerPort(PeerState peer, int newPort) {
     886    void changePeerPort(PeerState peer, int newPort) {
    869887        int oldPort;
    870888        synchronized (_addDropLock) {
     
    888906        return _establisher;
    889907    }
     908
    890909    /**
    891910     * Intercept RouterInfo entries received directly from a peer to inject them into
     
    12171236    }
    12181237   
     1238    /**
     1239     *  Does the IPv4 external address need to be rebuilt?
     1240     */
    12191241    private boolean needsRebuild() {
    12201242        if (_needsRebuild) return true; // simple enough
    12211243        if (_context.router().isHidden()) return false;
     1244        RouterAddress addr = getCurrentAddress(false);
    12221245        if (introducersRequired()) {
    1223             RouterAddress addr = _externalAddress;
    12241246            UDPAddress ua = new UDPAddress(addr);
    12251247            int valid = 0;
     
    12471269            }
    12481270        } else {
    1249             boolean rv = (_externalListenHost == null) || (_externalListenPort <= 0);
     1271            byte[] externalListenHost = addr != null ? addr.getIP() : null;
     1272            int externalListenPort = addr != null ? addr.getPort() : -1;
     1273            boolean rv = (externalListenHost == null) || (externalListenPort <= 0);
    12501274            if (!rv) {
    1251                 RouterAddress addr = _externalAddress;
    1252                 UDPAddress ua = new UDPAddress(addr);
    1253                 if (ua.getIntroducerCount() > 0)
     1275                // shortcut to determine if introducers are present
     1276                if (addr.getOption("ihost0") != null)
    12541277                    rv = true;  // status == ok and we don't actually need introducers, so rebuild
    12551278            }
    1256             if (_log.shouldLog(Log.INFO)) {
    1257                 if (rv) {
    1258                     _log.info("Need to initialize our direct SSU info (" + _externalListenHost + ":" + _externalListenPort + ")");
    1259                 } else {
    1260                     RouterAddress addr = _externalAddress;
    1261                     UDPAddress ua = new UDPAddress(addr);
    1262                     if ( (ua.getPort() <= 0) || (ua.getHost() == null) ) {
    1263                         _log.info("Our direct SSU info is initialized, but not used in our address yet");
    1264                         rv = true;
    1265                     } else {
    1266                         //_log.info("Our direct SSU info is initialized");
    1267                     }
    1268                 }
     1279            if (rv) {
     1280                if (_log.shouldLog(Log.INFO))
     1281                    _log.info("Need to initialize our direct SSU info (" + Addresses.toString(externalListenHost, externalListenPort) + ')');
     1282            } else if (addr.getPort() <= 0 || addr.getHost() == null) {
     1283                if (_log.shouldLog(Log.INFO))
     1284                    _log.info("Our direct SSU info is initialized, but not used in our address yet");
     1285                rv = true;
     1286            } else {
     1287                //_log.info("Our direct SSU info is initialized");
    12691288            }
    12701289            return rv;
     
    15581577        shutdown();
    15591578        // will this work?
    1560         _externalAddress = null;
    15611579        replaceAddress(null);
    15621580    }
     
    15791597    }
    15801598
    1581     private void rebuildExternalAddress() { rebuildExternalAddress(true); }
    1582 
    1583     private void rebuildExternalAddress(boolean allowRebuildRouterInfo) {
     1599    /**
     1600     *  Update our IPv4 addresses AND tell the router to rebuild and republish the router info.
     1601     *
     1602     *  @return the new address if changed, else null
     1603     */
     1604    private RouterAddress rebuildExternalAddress() {
     1605        return rebuildExternalAddress(true);
     1606    }
     1607
     1608    /**
     1609     *  Update our IPv4 address and optionally tell the router to rebuild and republish the router info.
     1610     *
     1611     *  @param allowRebuildRouterInfo whether to tell the router
     1612     *  @return the new address if changed, else null
     1613     */
     1614    private RouterAddress rebuildExternalAddress(boolean allowRebuildRouterInfo) {
    15841615        // if the external port is specified, we want to use that to bind to even
    15851616        // if we don't know the external host.
    1586         _externalListenPort = _context.getProperty(PROP_EXTERNAL_PORT, -1);
    1587        
     1617        int port = _context.getProperty(PROP_EXTERNAL_PORT, -1);
     1618       
     1619        byte[] ip = null;
    15881620        if (explicitAddressSpecified()) {
    1589             try {
    1590                 String host = _context.getProperty(PROP_EXTERNAL_HOST);
    1591                 _externalListenHost = InetAddress.getByName(host);
    1592             } catch (UnknownHostException uhe) {
    1593                 _externalListenHost = null;
    1594             }
    1595         }
     1621            String host = _context.getProperty(PROP_EXTERNAL_HOST);
     1622            return rebuildExternalAddress(host, port, allowRebuildRouterInfo);
     1623        }
     1624        return rebuildExternalAddress(ip, port, allowRebuildRouterInfo);
     1625    }
    15961626           
     1627
     1628    /**
     1629     *  Update our IPv4 or IPv6 address and optionally tell the router to rebuild and republish the router info.
     1630     *
     1631     *  @param ip new ip valid IPv4 or IPv6 or null
     1632     *  @param port new valid port or -1
     1633     *  @param allowRebuildRouterInfo whether to tell the router
     1634     *  @return the new address if changed, else null
     1635     *  @since IPv6
     1636     */
     1637    private RouterAddress rebuildExternalAddress(byte[] ip, int port, boolean allowRebuildRouterInfo) {
     1638        if (ip == null || isValid(ip))
     1639            return rebuildExternalAddress(Addresses.toString(ip), port, allowRebuildRouterInfo);
     1640        return null;
     1641    }
     1642
     1643    /**
     1644     *  Update our IPv4 or IPv6 address and optionally tell the router to rebuild and republish the router info.
     1645     *
     1646     *  @param host new valid IPv4 or IPv6 or DNS hostname or null
     1647     *  @param port new valid port or -1
     1648     *  @param allowRebuildRouterInfo whether to tell the router
     1649     *  @return the new address if changed, else null
     1650     *  @since IPv6
     1651     */
     1652    private RouterAddress rebuildExternalAddress(String host, int port, boolean allowRebuildRouterInfo) {
    15971653        if (_context.router().isHidden())
    1598             return;
    1599        
    1600         Properties options = new Properties();
     1654            return null;
     1655       
     1656        OrderedProperties options = new OrderedProperties();
    16011657        boolean directIncluded = false;
    1602         if ( allowDirectUDP() && (_externalListenPort > 0) && (_externalListenHost != null) && (isValid(_externalListenHost.getAddress())) ) {
    1603             options.setProperty(UDPAddress.PROP_PORT, String.valueOf(_externalListenPort));
    1604             options.setProperty(UDPAddress.PROP_HOST, _externalListenHost.getHostAddress());
     1658        // DNS name assumed IPv4
     1659        boolean isIPv6 = host != null && host.contains(":");
     1660        if (allowDirectUDP() && port > 0 && host != null) {
     1661            options.setProperty(UDPAddress.PROP_PORT, String.valueOf(port));
     1662            options.setProperty(UDPAddress.PROP_HOST, host);
    16051663            directIncluded = true;
    16061664        }
    16071665       
    1608         boolean introducersRequired = introducersRequired();
     1666        boolean introducersRequired = (!isIPv6) && introducersRequired();
    16091667        boolean introducersIncluded = false;
    16101668        if (introducersRequired || !directIncluded) {
     
    16391697                options.setProperty(UDPAddress.PROP_INTRO_KEY, _introKey.toBase64());
    16401698
    1641             RouterAddress addr = new RouterAddress();
    16421699            // SSU seems to regulate at about 85%, so make it a little higher.
    16431700            // If this is too low, both NTCP and SSU always have incremented cost and
    16441701            // the whole mechanism is not helpful.
     1702            int cost = DEFAULT_COST;
    16451703            if (ADJUST_COST && !haveCapacity(91))
    1646                 addr.setCost(DEFAULT_COST + 1);
    1647             else
    1648                 addr.setCost(DEFAULT_COST);
    1649             //addr.setExpiration(null);
    1650             addr.setTransportStyle(STYLE);
    1651             addr.setOptions(options);
    1652 
    1653             boolean wantsRebuild = false;
    1654             if ( (_externalAddress == null) || !(_externalAddress.equals(addr)) )
    1655                 wantsRebuild = true;
    1656 
    1657             RouterAddress oldAddress = _externalAddress;
    1658             _externalAddress = addr;
    1659             if (_log.shouldLog(Log.INFO))
    1660                 _log.info("Address rebuilt: " + addr);
    1661             replaceAddress(addr, oldAddress);
    1662             if (allowRebuildRouterInfo && wantsRebuild)
    1663                 _context.router().rebuildRouterInfo();
    1664             _needsRebuild = false;
     1704                cost++;
     1705            RouterAddress addr = new RouterAddress(STYLE, options, cost);
     1706
     1707            RouterAddress current = getCurrentAddress(isIPv6);
     1708            boolean wantsRebuild = !addr.deepEquals(current);
     1709
     1710            if (wantsRebuild) {
     1711                if (_log.shouldLog(Log.INFO))
     1712                    _log.info("Address rebuilt: " + addr);
     1713                replaceAddress(addr);
     1714                if (allowRebuildRouterInfo)
     1715                    _context.router().rebuildRouterInfo();
     1716            } else {
     1717                addr = null;
     1718            }
     1719            if (!isIPv6)
     1720                _needsRebuild = false;
     1721            return addr;
    16651722        } else {
    16661723            if (_log.shouldLog(Log.WARN))
     
    16681725                           + introducersRequired + ")", new Exception("source"));
    16691726            _needsRebuild = true;
    1670         }
    1671     }
    1672 
    1673     /**
    1674      * Replace then tell NTCP that we changed.
     1727            return null;
     1728        }
     1729    }
     1730
     1731    /**
     1732     *  Replace then tell NTCP that we changed.
     1733     *
     1734     *  @param address the new address or null to remove all
    16751735     */
    16761736    @Override
     
    16801740    }
    16811741
     1742    /**
     1743     *  Calls replaceAddress(address), then shuts down the router if
     1744     *  dynamic keys is enabled, which it never is, so all this is unused.
     1745     *
     1746     *  @param address the new address or null to remove all
     1747     */
     1748/****
    16821749    protected void replaceAddress(RouterAddress address, RouterAddress oldAddress) {
    16831750        replaceAddress(address);
     
    17051772        }
    17061773    }
    1707    
     1774****/
     1775   
     1776    /**
     1777     *  Do we require introducers?
     1778     */
    17081779    public boolean introducersRequired() {
    17091780        /******************
     
    26222693            long pingFirewallCutoff = now - PING_FIREWALL_CUTOFF;
    26232694            boolean shouldPingFirewall = _reachabilityStatus != CommSystemFacade.STATUS_OK;
    2624             int currentListenPort = getIPv4ListenPort();
    2625             boolean pingOneOnly = shouldPingFirewall && _externalListenPort == currentListenPort;
     2695            int currentListenPort = getListenPort(false);
     2696            boolean pingOneOnly = shouldPingFirewall && getExternalPort(false) == currentListenPort;
    26262697            boolean shortLoop = shouldPingFirewall;
    26272698            _expireBuffer.clear();
Note: See TracChangeset for help on using the changeset viewer.