diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java index 8a8aa4e4dbece5677f89e8ff1f2d45b4b93951d8..6ba93bf3b709666e0f37176938201604f2ed18f0 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java @@ -126,12 +126,31 @@ public interface I2PSocketManager { * Ping the specified peer, returning true if they replied to the ping within * the timeout specified, false otherwise. This call blocks. * + * Uses the ports from the default options. + * * @param peer Destination to ping - * @param timeoutMs timeout in ms + * @param timeoutMs timeout in ms, greater than zero + * @throws IllegalArgumentException * @return success or failure */ public boolean ping(Destination peer, long timeoutMs); + /** + * Ping the specified peer, returning true if they replied to the ping within + * the timeout specified, false otherwise. This call blocks. + * + * Uses the ports specified. + * + * @param peer Destination to ping + * @param localPort 0 - 65535 + * @param remotePort 0 - 65535 + * @param timeoutMs timeout in ms, greater than zero + * @return success or failure + * @throws IllegalArgumentException + * @since 0.9.12 + */ + public boolean ping(Destination peer, int localPort, int remotePort, long timeoutMs); + public String getName(); public void setName(String name); diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/Connection.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/Connection.java index 47cfd6a53d7f8d1371ddb2c37487c864fc3bafd2..8cec3cad8c36ac15bcfecf39f6b843edf6c7ec33 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/Connection.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/Connection.java @@ -307,6 +307,8 @@ class Connection { reply.setSendStreamId(_sendStreamId); reply.setReceiveStreamId(_receiveStreamId); reply.setOptionalFrom(_connectionManager.getSession().getMyDestination()); + reply.setLocalPort(_localPort); + reply.setRemotePort(_remotePort); // this just sends the packet - no retries or whatnot if (_outboundQueue.enqueue(reply)) { _unackedPacketsReceived = 0; diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionDataReceiver.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionDataReceiver.java index dbf546ad880f36568cbf9ae5d54c5f7024eb4e40..8568e7c69b0a131b00799c971a83608da604c139 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionDataReceiver.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionDataReceiver.java @@ -206,9 +206,9 @@ class ConnectionDataReceiver implements MessageOutputStream.DataReceiver { packet.setFlag(Packet.FLAG_SYNCHRONIZE); packet.setOptionalFrom(con.getSession().getMyDestination()); packet.setOptionalMaxSize(con.getOptions().getMaxMessageSize()); - packet.setLocalPort(con.getLocalPort()); - packet.setRemotePort(con.getPort()); } + packet.setLocalPort(con.getLocalPort()); + packet.setRemotePort(con.getPort()); if (con.getSendStreamId() == Packet.STREAM_ID_UNKNOWN) { packet.setFlag(Packet.FLAG_NO_ACK); } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionManager.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionManager.java index 435a09ce42cd4d17ef69fe6d43b1238d4bb39c2d..3e09c79978901455221b4678c01f0d73a9693afc 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionManager.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionManager.java @@ -262,6 +262,8 @@ class ConnectionManager { reply.setSendStreamId(synPacket.getReceiveStreamId()); reply.setReceiveStreamId(0); reply.setOptionalFrom(_session.getMyDestination()); + reply.setLocalPort(synPacket.getLocalPort()); + reply.setRemotePort(synPacket.getRemotePort()); // this just sends the packet - no retries or whatnot _outboundQueue.enqueue(reply); return null; @@ -284,6 +286,44 @@ class ConnectionManager { return con; } + /** + * Process a ping by checking for throttling, etc., then sending a pong. + * + * @param con null if unknown + * @param ping Ping packet to process, must have From and Sig fields, + * with signature already verified, only if answerPings() returned true + * @return true if we sent a pong + * @since 0.9.12 from PacketHandler.receivePing() + */ + public boolean receivePing(Connection con, Packet ping) { + Destination dest = ping.getOptionalFrom(); + if (dest == null) + return false; + if (con == null) { + // Use the same throttling as for connections + String why = shouldRejectConnection(ping); + if (why != null) { + if ((!_defaultOptions.getDisableRejectLogging()) || _log.shouldLog(Log.WARN)) + _log.logAlways(Log.WARN, "Dropping ping since peer is " + why + ": " + dest.calculateHash()); + return false; + } + } else { + // in-connection ping to a 3rd party ??? + if (!dest.equals(con.getRemotePeer())) { + _log.logAlways(Log.WARN, "Dropping ping from " + con.getRemotePeer().calculateHash() + + " to " + dest.calculateHash()); + return false; + } + } + PacketLocal pong = new PacketLocal(_context, dest); + pong.setFlag(Packet.FLAG_ECHO | Packet.FLAG_NO_ACK); + pong.setReceiveStreamId(ping.getSendStreamId()); + pong.setLocalPort(ping.getLocalPort()); + pong.setRemotePort(ping.getRemotePort()); + _outboundQueue.enqueue(pong); + return true; + } + private static final long DEFAULT_STREAM_DELAY_MAX = 10*1000; /** @@ -572,24 +612,34 @@ class ConnectionManager { return new HashSet<Connection>(_connectionByInboundId.values()); } - /** blocking */ - public boolean ping(Destination peer, long timeoutMs) { - return ping(peer, timeoutMs, true, null); - } - public boolean ping(Destination peer, long timeoutMs, boolean blocking) { - return ping(peer, timeoutMs, blocking, null); + /** + * blocking + * + * @param timeoutMs greater than zero + * @return true if pong received + * @since 0.9.12 added port args + */ + public boolean ping(Destination peer, int fromPort, int toPort, long timeoutMs) { + return ping(peer, fromPort, toPort, timeoutMs, true, null); } /** - * @deprecated I2PSession ignores tags, use non-tag variant - * @param keyToUse ignored - * @param tagsToSend ignored + * @param timeoutMs greater than zero + * @return true if blocking and pong received + * @since 0.9.12 added port args */ - public boolean ping(Destination peer, long timeoutMs, boolean blocking, SessionKey keyToUse, Set<?> tagsToSend, PingNotifier notifier) { - return ping(peer, timeoutMs, blocking, notifier); + public boolean ping(Destination peer, int fromPort, int toPort, long timeoutMs, boolean blocking) { + return ping(peer, fromPort, toPort, timeoutMs, blocking, null); } - public boolean ping(Destination peer, long timeoutMs, boolean blocking, PingNotifier notifier) { + /** + * @param timeoutMs greater than zero + * @param notifier may be null + * @return true if blocking and pong received + * @since 0.9.12 added port args + */ + public boolean ping(Destination peer, int fromPort, int toPort, long timeoutMs, + boolean blocking, PingNotifier notifier) { Long id = Long.valueOf(_context.random().nextLong(Packet.MAX_STREAM_ID-1)+1); PacketLocal packet = new PacketLocal(_context, peer); packet.setSendStreamId(id.longValue()); @@ -597,13 +647,15 @@ class ConnectionManager { Packet.FLAG_NO_ACK | Packet.FLAG_SIGNATURE_INCLUDED); packet.setOptionalFrom(_session.getMyDestination()); + packet.setLocalPort(fromPort); + packet.setRemotePort(toPort); //if ( (keyToUse != null) && (tagsToSend != null) ) { // packet.setKeyUsed(keyToUse); // packet.setTagsSent(tagsToSend); //} if (_log.shouldLog(Log.INFO)) { - _log.info(String.format("about to ping %s timeout=%d blocking=%b", - peer,timeoutMs,blocking)); + _log.info(String.format("about to ping %s port %d from port %d timeout=%d blocking=%b", + peer.calculateHash().toString(), toPort, fromPort, timeoutMs, blocking)); } @@ -658,6 +710,7 @@ class ConnectionManager { private boolean _ponged; private final PingNotifier _notifier; + /** @param notifier may be null */ public PingRequest(PingNotifier notifier) { _notifier = notifier; } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java index 757eb37f42d2dddfbbc51ba405ab1cb63f37c4ca..435207b6c31cc9c2d381918a5a63bd60b49418b0 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java @@ -148,13 +148,41 @@ public class I2PSocketManagerFull implements I2PSocketManager { * Ping the specified peer, returning true if they replied to the ping within * the timeout specified, false otherwise. This call blocks. * + * Uses the ports from the default options. * * @param peer - * @param timeoutMs + * @param timeoutMs timeout in ms, greater than zero * @return true on success, false on failure + * @throws IllegalArgumentException */ public boolean ping(Destination peer, long timeoutMs) { - return _connectionManager.ping(peer, timeoutMs); + if (timeoutMs <= 0) + throw new IllegalArgumentException("bad timeout"); + return _connectionManager.ping(peer, _defaultOptions.getLocalPort(), + _defaultOptions.getPort(), timeoutMs); + } + + /** + * Ping the specified peer, returning true if they replied to the ping within + * the timeout specified, false otherwise. This call blocks. + * + * Uses the ports specified. + * + * @param peer Destination to ping + * @param localPort 0 - 65535 + * @param remotePort 0 - 65535 + * @param timeoutMs timeout in ms, greater than zero + * @return success or failure + * @throws IllegalArgumentException + * @since 0.9.12 + */ + public boolean ping(Destination peer, int localPort, int remotePort, long timeoutMs) { + if (localPort < 0 || localPort > 65535 || + remotePort < 0 || remotePort > 65535) + throw new IllegalArgumentException("bad port"); + if (timeoutMs <= 0) + throw new IllegalArgumentException("bad timeout"); + return _connectionManager.ping(peer, localPort, remotePort, timeoutMs); } /** diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/PacketHandler.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/PacketHandler.java index c40afe453a4b41d38b31c07397f90e5c52fb4afa..1deef1f226531653bb42c980f4dfbe9479bdc987 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/PacketHandler.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/PacketHandler.java @@ -136,7 +136,7 @@ class PacketHandler { if (packet.isFlagSet(Packet.FLAG_ECHO)) { if (packet.getSendStreamId() > 0) { if (con.getOptions().getAnswerPings()) - receivePing(packet); + receivePing(con, packet); else if (_log.shouldLog(Log.WARN)) _log.warn("Dropping Echo packet on existing con: " + packet); } else if (packet.getReceiveStreamId() > 0) { @@ -247,6 +247,8 @@ class PacketHandler { reply.setSendStreamId(packet.getReceiveStreamId()); reply.setReceiveStreamId(packet.getSendStreamId()); reply.setOptionalFrom(_manager.getSession().getMyDestination()); + reply.setLocalPort(packet.getLocalPort()); + reply.setRemotePort(packet.getRemotePort()); // this just sends the packet - no retries or whatnot _manager.getPacketQueue().enqueue(reply); } @@ -255,7 +257,7 @@ class PacketHandler { if (packet.isFlagSet(Packet.FLAG_ECHO)) { if (packet.getSendStreamId() > 0) { if (_manager.answerPings()) - receivePing(packet); + receivePing(null, packet); else if (_log.shouldLog(Log.WARN)) _log.warn("Dropping Echo packet on unknown con: " + packet); } else if (packet.getReceiveStreamId() > 0) { @@ -335,7 +337,10 @@ class PacketHandler { } } - private void receivePing(Packet packet) { + /** + * @param con null if unknown + */ + private void receivePing(Connection con, Packet packet) { boolean ok = packet.verifySignature(_context, packet.getOptionalFrom(), null); if (!ok) { if (_log.shouldLog(Log.WARN)) { @@ -348,10 +353,7 @@ class PacketHandler { + " sig=" + packet.getOptionalSignature().toBase64() + ")"); } } else { - PacketLocal pong = new PacketLocal(_context, packet.getOptionalFrom()); - pong.setFlag(Packet.FLAG_ECHO | Packet.FLAG_NO_ACK); - pong.setReceiveStreamId(packet.getSendStreamId()); - _manager.getPacketQueue().enqueue(pong); + _manager.receivePing(con, packet); } }