use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class UDPTransport method bid.
public TransportBid bid(RouterInfo toAddress, long dataSize) {
if (dataSize > OutboundMessageState.MAX_MSG_SIZE) {
// NTCP max is lower, so msg will get dropped
return null;
}
Hash to = toAddress.getIdentity().calculateHash();
PeerState peer = getPeerState(to);
if (peer != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("bidding on a message to an established peer: " + peer);
if (preferUDP())
return _cachedBid[FAST_PREFERRED_BID];
else
return _cachedBid[FAST_BID];
} else {
// If we don't have a port, all is lost
if (_reachabilityStatus == Status.HOSED) {
markUnreachable(to);
return null;
}
// Validate his SSU address
RouterAddress addr = getTargetAddress(toAddress);
if (addr == null) {
markUnreachable(to);
return null;
}
// Check for supported sig type
SigType type = toAddress.getIdentity().getSigType();
if (type == null || !type.isAvailable()) {
markUnreachable(to);
return null;
}
// Can we connect to them if we are not DSA?
RouterInfo us = _context.router().getRouterInfo();
if (us != null) {
RouterIdentity id = us.getIdentity();
if (id.getSigType() != SigType.DSA_SHA1) {
String v = toAddress.getVersion();
if (VersionComparator.comp(v, MIN_SIGTYPE_VERSION) < 0) {
markUnreachable(to);
return null;
}
}
}
if (!allowConnection())
return _cachedBid[TRANSIENT_FAIL_BID];
if (_log.shouldLog(Log.DEBUG))
_log.debug("bidding on a message to an unestablished peer: " + to);
// Try to maintain at least 5 peers (30 for v6) so we can determine our IP address and
// we have a selection to run peer tests with.
// If we are firewalled, and we don't have enough peers that volunteered to
// also introduce us, also bid aggressively so we are preferred over NTCP.
// (Otherwise we only talk UDP to those that are firewalled, and we will
// never get any introducers)
int count = _peersByIdent.size();
if (alwaysPreferUDP()) {
return _cachedBid[SLOW_PREFERRED_BID];
} else if (count < _min_peers || (_haveIPv6Address && count < _min_v6_peers) || (introducersRequired() && _introManager.introducerCount() < MIN_INTRODUCER_POOL)) {
// TODO After some time, decide that UDP is blocked/broken and return TRANSIENT_FAIL_BID?
if (_context.random().nextInt(4) == 0)
return _cachedBid[SLOWEST_BID];
else
return _cachedBid[SLOW_PREFERRED_BID];
} else if (preferUDP()) {
return _cachedBid[SLOW_BID];
} else if (haveCapacity()) {
if (addr.getCost() > DEFAULT_COST)
return _cachedBid[SLOWEST_COST_BID];
else
return _cachedBid[SLOWEST_BID];
} else {
if (addr.getCost() > DEFAULT_COST)
return _cachedBid[NEAR_CAPACITY_COST_BID];
else
return _cachedBid[NEAR_CAPACITY_BID];
}
}
}
use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class UDPTransport method locked_rebuildExternalAddress.
private RouterAddress locked_rebuildExternalAddress(String host, int port, boolean allowRebuildRouterInfo) {
if (_log.shouldDebug())
_log.debug("REA4 " + host + ':' + port);
if (_context.router().isHidden())
return null;
OrderedProperties options = new OrderedProperties();
boolean directIncluded;
// DNS name assumed IPv4
boolean isIPv6 = host != null && host.contains(":");
boolean introducersRequired = (!isIPv6) && introducersRequired();
if (!introducersRequired && allowDirectUDP() && port > 0 && host != null) {
options.setProperty(UDPAddress.PROP_PORT, String.valueOf(port));
options.setProperty(UDPAddress.PROP_HOST, host);
directIncluded = true;
} else {
directIncluded = false;
}
boolean introducersIncluded = false;
if (introducersRequired) {
// intro manager now sorts introducers, so
// deepEquals() below will not fail even with same introducers.
// Was only a problem when we had very very few peers to pick from.
RouterAddress current = getCurrentAddress(isIPv6);
int found = _introManager.pickInbound(current, options, PUBLIC_RELAY_COUNT);
if (found > 0) {
if (_log.shouldLog(Log.INFO))
_log.info("Direct? " + directIncluded + " reqd? " + introducersRequired + " picked introducers: " + found);
_introducersSelectedOn = _context.clock().now();
introducersIncluded = true;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Direct? " + directIncluded + " reqd? " + introducersRequired + " no introducers");
}
}
// if we have explicit external addresses, they had better be reachable
if (introducersRequired)
options.setProperty(UDPAddress.PROP_CAPACITY, CAP_TESTING);
else
options.setProperty(UDPAddress.PROP_CAPACITY, CAP_TESTING_INTRO);
// MTU since 0.9.2
int mtu;
if (host == null) {
mtu = _mtu;
} else {
try {
InetAddress ia = InetAddress.getByName(host);
mtu = setMTU(ia);
} catch (UnknownHostException uhe) {
mtu = _mtu;
}
}
if (mtu != PeerState.LARGE_MTU)
options.setProperty(UDPAddress.PROP_MTU, Integer.toString(mtu));
if (directIncluded || introducersIncluded) {
// Note that peers won't connect to us without this - see EstablishmentManager
if (_introKey != null)
options.setProperty(UDPAddress.PROP_INTRO_KEY, _introKey.toBase64());
// SSU seems to regulate at about 85%, so make it a little higher.
// If this is too low, both NTCP and SSU always have incremented cost and
// the whole mechanism is not helpful.
int cost = DEFAULT_COST;
if (ADJUST_COST && !haveCapacity(91))
cost += CONGESTION_COST_ADJUSTMENT;
if (introducersIncluded)
cost += 2;
if (isIPv6) {
TransportUtil.IPv6Config config = getIPv6Config();
if (config == IPV6_PREFERRED)
cost--;
else if (config == IPV6_NOT_PREFERRED)
cost++;
}
RouterAddress addr = new RouterAddress(STYLE, options, cost);
RouterAddress current = getCurrentAddress(isIPv6);
boolean wantsRebuild = !addr.deepEquals(current);
// save the external address, even if we didn't publish it
if (port > 0 && host != null) {
RouterAddress local;
if (directIncluded) {
local = addr;
} else {
OrderedProperties localOpts = new OrderedProperties();
localOpts.setProperty(UDPAddress.PROP_PORT, String.valueOf(port));
localOpts.setProperty(UDPAddress.PROP_HOST, host);
local = new RouterAddress(STYLE, localOpts, cost);
}
replaceCurrentExternalAddress(local, isIPv6);
}
if (wantsRebuild) {
if (_log.shouldLog(Log.INFO))
_log.info("Address rebuilt: " + addr, new Exception());
replaceAddress(addr);
// via CSFI.createAddresses->TM.getAddresses()->updateAddress()->REA
if (allowRebuildRouterInfo)
_context.router().rebuildRouterInfo();
} else {
addr = null;
}
if (!isIPv6)
_needsRebuild = false;
return addr;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Wanted to rebuild my SSU address, but couldn't specify either the direct or indirect info (needs introducers? " + introducersRequired + ")", new Exception("source"));
_needsRebuild = true;
// save the external address, even if we didn't publish it
if (port > 0 && host != null) {
OrderedProperties localOpts = new OrderedProperties();
localOpts.setProperty(UDPAddress.PROP_PORT, String.valueOf(port));
localOpts.setProperty(UDPAddress.PROP_HOST, host);
RouterAddress local = new RouterAddress(STYLE, localOpts, DEFAULT_COST);
replaceCurrentExternalAddress(local, isIPv6);
}
if (hasCurrentAddress()) {
// We must remove current address, otherwise the user will see
// "firewalled with inbound NTCP enabled" warning in console.
// Remove the IPv4 address only
removeAddress(false);
// via CSFI.createAddresses->TM.getAddresses()->updateAddress()->REA
if (allowRebuildRouterInfo)
_context.router().rebuildRouterInfo();
}
return null;
}
}
use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class PublishLocalRouterInfoJob method runJob.
public void runJob() {
long last = getContext().netDb().getLastRouterInfoPublishTime();
long now = getContext().clock().now();
if (last + MIN_PUBLISH_DELAY > now) {
long delay = getDelay();
requeue(last + delay - now);
return;
}
RouterInfo oldRI = getContext().router().getRouterInfo();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Old routerInfo contains " + oldRI.getAddresses().size() + " addresses and " + oldRI.getOptionsMap().size() + " options");
try {
List<RouterAddress> oldAddrs = new ArrayList<RouterAddress>(oldRI.getAddresses());
List<RouterAddress> newAddrs = getContext().commSystem().createAddresses();
int count = _runCount.incrementAndGet();
RouterInfo ri = new RouterInfo(oldRI);
if (_notFirstTime && (count % 4) != 0 && oldAddrs.size() == newAddrs.size()) {
// 3 times out of 4, we don't republish if everything is the same...
// If something changed, including the cost, then publish,
// otherwise don't.
String newcaps = getContext().router().getCapabilities();
boolean different = !oldRI.getCapabilities().equals(newcaps);
if (!different) {
Comparator<RouterAddress> comp = new AddrComparator();
Collections.sort(oldAddrs, comp);
Collections.sort(newAddrs, comp);
for (int i = 0; i < oldAddrs.size(); i++) {
// deepEquals() includes cost
if (!oldAddrs.get(i).deepEquals(newAddrs.get(i))) {
different = true;
break;
}
}
if (!different) {
if (_log.shouldLog(Log.INFO))
_log.info("Not republishing early because costs and caps and addresses are the same");
requeue(getDelay());
return;
}
}
if (_log.shouldLog(Log.INFO))
_log.info("Republishing early because addresses or costs or caps have changed -" + " oldCaps: " + oldRI.getCapabilities() + " newCaps: " + newcaps + " old:\n" + oldAddrs + "\nnew:\n" + newAddrs);
}
ri.setPublished(getContext().clock().now());
Properties stats = getContext().statPublisher().publishStatistics();
ri.setOptions(stats);
ri.setAddresses(newAddrs);
SigningPrivateKey key = getContext().keyManager().getSigningPrivateKey();
if (key == null) {
_log.log(Log.CRIT, "Internal error - signing private key not known? rescheduling publish for 30s");
requeue(30 * 1000);
return;
}
ri.sign(key);
getContext().router().setRouterInfo(ri);
if (_log.shouldLog(Log.INFO))
_log.info("Newly updated routerInfo is published with " + stats.size() + "/" + ri.getOptionsMap().size() + " options on " + new Date(ri.getPublished()));
try {
// This won't really publish until the netdb is initialized.
getContext().netDb().publish(ri);
} catch (IllegalArgumentException iae) {
_log.log(Log.CRIT, "Error publishing our identity - corrupt? Restart required", iae);
getContext().router().rebuildNewIdentity();
}
} catch (DataFormatException dfe) {
_log.error("Error signing the updated local router info!", dfe);
}
if (_notFirstTime) {
requeue(getDelay());
} else {
requeue(FIRST_TIME_DELAY);
_notFirstTime = true;
}
}
use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class KademliaNetworkDatabaseFacade method validate.
/**
* Determine whether this routerInfo will be accepted as valid and current
* given what we know now.
*
* Call this before each use, to check expiration
*
* @return reason why the entry is not valid, or null if it is valid
* @since 0.9.7
*/
String validate(RouterInfo routerInfo) throws IllegalArgumentException {
long now = _context.clock().now();
boolean upLongEnough = _context.router().getUptime() > 60 * 60 * 1000;
// Once we're over MIN_ROUTERS routers, reduce the expiration time down from the default,
// as a crude way of limiting memory usage.
// i.e. at 2*MIN_ROUTERS routers the expiration time will be about half the default, etc.
// And if we're floodfill, we can keep the expiration really short, since
// we are always getting the latest published to us.
// As the net grows this won't be sufficient, and we'll have to implement
// flushing some from memory, while keeping all on disk.
long adjustedExpiration;
if (floodfillEnabled())
adjustedExpiration = ROUTER_INFO_EXPIRATION_FLOODFILL;
else
// _kb.size() includes leasesets but that's ok
adjustedExpiration = Math.min(ROUTER_INFO_EXPIRATION, ROUTER_INFO_EXPIRATION_MIN + ((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * MIN_ROUTERS / (_kb.size() + 1)));
if (upLongEnough && !routerInfo.isCurrent(adjustedExpiration)) {
long age = _context.clock().now() - routerInfo.getPublished();
int existing = _kb.size();
if (existing >= MIN_REMAINING_ROUTERS) {
if (_log.shouldLog(Log.INFO))
_log.info("Expired RI " + routerInfo.getIdentity().getHash(), new Exception());
return "Peer expired " + DataHelper.formatDuration(age) + " ago";
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Even though the peer is old, we have only " + existing + " peers left " + routerInfo);
}
}
if (routerInfo.getPublished() > now + 2 * Router.CLOCK_FUDGE_FACTOR) {
long age = routerInfo.getPublished() - _context.clock().now();
if (_log.shouldLog(Log.INFO))
_log.info("Peer " + routerInfo.getIdentity().getHash() + " published their routerInfo in the future?! [" + new Date(routerInfo.getPublished()) + "]", new Exception());
return "Peer published " + DataHelper.formatDuration(age) + " in the future?!";
}
if (!routerInfo.isCurrent(ROUTER_INFO_EXPIRATION_INTRODUCED)) {
if (routerInfo.getAddresses().isEmpty())
return "Old peer with no addresses";
// And even better, catches the case where the router is unreachable but knows no introducers
if (routerInfo.getCapabilities().indexOf(Router.CAPABILITY_UNREACHABLE) >= 0)
return "Old peer and thinks it is unreachable";
// Just check all the addresses, faster than getting just the SSU ones
for (RouterAddress ra : routerInfo.getAddresses()) {
// Introducers change often, introducee will ping introducer for 2 hours
if (ra.getOption("ihost0") != null)
return "Old peer with SSU Introducers";
}
}
if (upLongEnough && (routerInfo.getPublished() < now - 2 * 24 * 60 * 60 * 1000l)) {
long age = _context.clock().now() - routerInfo.getPublished();
return "Peer published " + DataHelper.formatDuration(age) + " ago";
}
if (upLongEnough && !routerInfo.isCurrent(ROUTER_INFO_EXPIRATION_SHORT)) {
if (routerInfo.getTargetAddress("NTCP") == null)
return "Peer published > 75m ago, SSU only without introducers";
}
return null;
}
use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class ProfileOrganizer method selectPeersLocallyUnreachable.
/**
* Get the peers the transport layer thinks are unreachable, and
* add in the peers with the SSU peer testing bug,
* and peers requiring introducers.
*/
public List<Hash> selectPeersLocallyUnreachable() {
List<Hash> n;
int count;
getReadLock();
try {
count = _notFailingPeers.size();
n = new ArrayList<Hash>(_notFailingPeers.keySet());
} finally {
releaseReadLock();
}
List<Hash> l = new ArrayList<Hash>(count / 4);
for (Hash peer : n) {
if (_context.commSystem().wasUnreachable(peer))
l.add(peer);
else {
// Blacklist <= 0.6.1.32 SSU-only peers, they don't know if they are unreachable,
// and we may not know either if they contacted us first, so assume they are.
// Also blacklist all peers requiring SSU introducers, because either
// a) it's slow; or
// b) it doesn't work very often; or
// c) in the event they are advertising NTCP, it probably won't work because
// they probably don't have a TCP hole punched in their firewall either.
RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer);
if (info != null) {
String v = info.getVersion();
// this only works if there is no 0.6.1.34!
if ((!v.equals("0.6.1.33")) && v.startsWith("0.6.1.") && info.getTargetAddress("NTCP") == null)
l.add(peer);
else {
RouterAddress ra = info.getTargetAddress("SSU");
// as long as they have NTCP
if (ra == null) {
if (info.getTargetAddress("NTCP") == null)
l.add(peer);
continue;
}
// This is the quick way of doing UDPAddress.getIntroducerCount() > 0
if (ra.getOption("ihost0") != null)
l.add(peer);
}
}
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Unreachable: " + l);
return l;
}
Aggregations