diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java index 9e43a79eb309f295319c39f39f782ddbeeb757c2..afab743d9fe06926452fc4972ed3f9d9687e9432 100644 --- a/router/java/src/net/i2p/router/transport/TransportImpl.java +++ b/router/java/src/net/i2p/router/transport/TransportImpl.java @@ -25,7 +25,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ConcurrentHashMap; import net.i2p.data.DataHelper; @@ -55,7 +54,7 @@ import net.i2p.util.VersionComparator; public abstract class TransportImpl implements Transport { private final Log _log; private TransportEventListener _listener; - protected final List<RouterAddress> _currentAddresses; + private final List<RouterAddress> _currentAddresses; // Only used by NTCP. SSU does not use. See send() below. private final BlockingQueue<OutNetMessage> _sendPool; protected final RouterContext _context; @@ -112,7 +111,7 @@ public abstract class TransportImpl implements Transport { //_context.statManager().createRateStat("transport.sendProcessingTime." + getStyle(), "Time to process and send a message (ms)", "Transport", new long[] { 60*1000l }); _context.statManager().createRateStat("transport.expiredOnQueueLifetime", "How long a message that expires on our outbound queue is processed", "Transport", new long[] { 60*1000l, 10*60*1000l, 60*60*1000l, 24*60*60*1000l } ); - _currentAddresses = new CopyOnWriteArrayList<RouterAddress>(); + _currentAddresses = new ArrayList<RouterAddress>(3); if (getStyle().equals("NTCP")) _sendPool = new ArrayBlockingQueue<OutNetMessage>(8); else @@ -550,11 +549,13 @@ public abstract class TransportImpl implements Transport { /** * What addresses are we currently listening to? * Replaces getCurrentAddress() - * @return all addresses, non-null + * @return a copy of all addresses, non-null * @since IPv6 */ public List<RouterAddress> getCurrentAddresses() { - return _currentAddresses; + synchronized(_currentAddresses) { + return new ArrayList<RouterAddress>(_currentAddresses); + } } /** @@ -568,9 +569,11 @@ public abstract class TransportImpl implements Transport { * @since IPv6 */ public RouterAddress getCurrentAddress(boolean ipv6) { - for (RouterAddress ra : _currentAddresses) { - if (ipv6 == TransportUtil.isIPv6(ra)) - return ra; + synchronized(_currentAddresses) { + for (RouterAddress ra : _currentAddresses) { + if (ipv6 == TransportUtil.isIPv6(ra)) + return ra; + } } return null; } @@ -580,17 +583,21 @@ public abstract class TransportImpl implements Transport { * @since IPv6 */ public boolean hasCurrentAddress() { - return !_currentAddresses.isEmpty(); + synchronized(_currentAddresses) { + return !_currentAddresses.isEmpty(); + } } /** * Ask the transport to update its address based on current information and return it * Transports should override. - * @return all addresses, non-null + * @return a copy of all addresses, non-null * @since 0.7.12 */ public List<RouterAddress> updateAddress() { - return _currentAddresses; + synchronized(_currentAddresses) { + return new ArrayList<RouterAddress>(_currentAddresses); + } } /** @@ -603,21 +610,27 @@ public abstract class TransportImpl implements Transport { * @param address null to remove all */ protected void replaceAddress(RouterAddress address) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Replacing address with " + address, new Exception()); - if (address == null) { - _currentAddresses.clear(); - } else { - boolean isIPv6 = TransportUtil.isIPv6(address); - for (RouterAddress ra : _currentAddresses) { - if (isIPv6 == TransportUtil.isIPv6(ra)) - // COWAL - _currentAddresses.remove(ra); + boolean isIPv6 = TransportUtil.isIPv6(address); + if (_log.shouldWarn()) + _log.warn("Replacing IPv" + (isIPv6 ? '6' : '4') + " address with " + address, new Exception()); + int sz; + synchronized(_currentAddresses) { + if (address == null) { + _currentAddresses.clear(); + sz = 0; + } else { + for (Iterator<RouterAddress> iter = _currentAddresses.iterator(); iter.hasNext(); ) { + RouterAddress ra = iter.next(); + if (isIPv6 == TransportUtil.isIPv6(ra)) { + iter.remove(); + } + } + _currentAddresses.add(address); + sz = _currentAddresses.size(); } - _currentAddresses.add(address); } - if (_log.shouldLog(Log.WARN)) - _log.warn(getStyle() + " now has " + _currentAddresses.size() + " addresses"); + if (_log.shouldWarn()) + _log.warn(getStyle() + " now has " + sz + " addresses"); if (_listener != null) _listener.transportAddressChanged(); } @@ -633,11 +646,15 @@ public abstract class TransportImpl implements Transport { protected void removeAddress(RouterAddress address) { if (_log.shouldWarn()) _log.warn("Removing address " + address, new Exception()); - boolean changed = _currentAddresses.remove(address); - changed = true; + boolean changed; + int sz; + synchronized(_currentAddresses) { + changed = _currentAddresses.remove(address); + sz = _currentAddresses.size(); + } if (changed) { if (_log.shouldWarn()) - _log.warn(getStyle() + " now has " + _currentAddresses.size() + " addresses"); + _log.warn(getStyle() + " now has " + sz + " addresses"); if (_listener != null) _listener.transportAddressChanged(); } else { @@ -658,16 +675,20 @@ public abstract class TransportImpl implements Transport { if (_log.shouldWarn()) _log.warn("Removing addresses, ipv6? " + ipv6, new Exception()); boolean changed = false; - for (RouterAddress ra : _currentAddresses) { - if (ipv6 == TransportUtil.isIPv6(ra)) { - // COWAL - if (_currentAddresses.remove(ra)) + int sz; + synchronized(_currentAddresses) { + for (Iterator<RouterAddress> iter = _currentAddresses.iterator(); iter.hasNext(); ) { + RouterAddress ra = iter.next(); + if (ipv6 == TransportUtil.isIPv6(ra)) { + iter.remove(); changed = true; + } } + sz = _currentAddresses.size(); } if (changed) { if (_log.shouldWarn()) - _log.warn(getStyle() + " now has " + _currentAddresses.size() + " addresses"); + _log.warn(getStyle() + " now has " + sz + " addresses"); if (_listener != null) _listener.transportAddressChanged(); } else {