use of net.i2p.data.Destination in project i2p.i2p by i2p.
the class SAMv3StreamSession method connect.
/**
* Connect the SAM STREAM session to the specified Destination
* for a single connection, using the socket stolen from the handler.
*
* @param handler The handler that communicates with the requesting client
* @param dest Base64-encoded Destination to connect to
* @param props Options to be used for connection
*
* @throws DataFormatException if the destination is not valid
* @throws ConnectException if the destination refuses connections
* @throws NoRouteToHostException if the destination can't be reached
* @throws InterruptedIOException if the connection timeouts
* @throws I2PException if there's another I2P-related error
* @throws IOException
*/
public void connect(SAMv3Handler handler, String dest, Properties props) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, IOException {
boolean verbose = !Boolean.parseBoolean(props.getProperty("SILENT"));
Destination d = SAMUtils.getDest(dest);
I2PSocketOptions opts = socketMgr.buildOptions(props);
if (props.getProperty(I2PSocketOptions.PROP_CONNECT_TIMEOUT) == null)
opts.setConnectTimeout(60 * 1000);
String fromPort = props.getProperty("FROM_PORT");
if (fromPort != null) {
try {
opts.setLocalPort(Integer.parseInt(fromPort));
} catch (NumberFormatException nfe) {
throw new I2PException("Bad port " + fromPort);
}
}
String toPort = props.getProperty("TO_PORT");
if (toPort != null) {
try {
opts.setPort(Integer.parseInt(toPort));
} catch (NumberFormatException nfe) {
throw new I2PException("Bad port " + toPort);
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Connecting new I2PSocket...");
// blocking connection (SAMv3)
I2PSocket i2ps = socketMgr.connect(d, opts);
SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
if (rec == null)
throw new InterruptedIOException();
handler.notifyStreamResult(verbose, "OK", null);
handler.stealSocket();
ReadableByteChannel fromClient = handler.getClientSocket();
ReadableByteChannel fromI2P = Channels.newChannel(i2ps.getInputStream());
WritableByteChannel toClient = handler.getClientSocket();
WritableByteChannel toI2P = Channels.newChannel(i2ps.getOutputStream());
SAMBridge bridge = handler.getBridge();
(new I2PAppThread(rec.getThreadGroup(), new Pipe(fromClient, toI2P, bridge), "ConnectV3 SAMPipeClientToI2P")).start();
(new I2PAppThread(rec.getThreadGroup(), new Pipe(fromI2P, toClient, bridge), "ConnectV3 SAMPipeI2PToClient")).start();
}
use of net.i2p.data.Destination in project i2p.i2p by i2p.
the class ConnectionHandler method accept.
/**
* Receive an incoming connection (built from a received SYN)
* Non-SYN packets with a zero SendStreamID may also be queued here so
* that they don't get thrown away while the SYN packet before it is queued.
*
* @param timeoutMs max amount of time to wait for a connection (if less
* than 1ms, wait indefinitely)
* @return connection received. Prior to 0.9.17, or null if there was a timeout or the
* handler was shut down. As of 0.9.17, never null.
* @throws RouterRestartException (extends I2PException) if the router is apparently restarting, since 0.9.34
* @throws ConnectException since 0.9.17, returned null before;
* if the I2PServerSocket is closed, or if interrupted.
* @throws SocketTimeoutException since 0.9.17, returned null before;
* if a timeout was previously set with setSoTimeout and the timeout has been reached.
*/
public Connection accept(long timeoutMs) throws RouterRestartException, ConnectException, SocketTimeoutException {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Accept(" + timeoutMs + ") called");
long expiration = timeoutMs + _context.clock().now();
while (true) {
if ((timeoutMs > 0) && (expiration < _context.clock().now()))
throw new SocketTimeoutException("accept() timed out");
if (!_active) {
// fail all the ones we had queued up
while (true) {
// fails immediately if empty
Packet packet = _synQueue.poll();
if (packet == null || packet.getOptionalDelay() == PoisonPacket.POISON_MAX_DELAY_REQUEST)
break;
sendReset(packet);
}
if (_restartPending)
throw new RouterRestartException();
throw new ConnectException("ServerSocket closed");
}
Packet syn = null;
while (_active && syn == null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Accept(" + timeoutMs + "): active=" + _active + " queue: " + _synQueue.size());
if (timeoutMs <= 0) {
try {
// waits forever
syn = _synQueue.take();
} catch (InterruptedException ie) {
ConnectException ce = new ConnectException("Interrupted accept()");
ce.initCause(ie);
throw ce;
}
} else {
long remaining = expiration - _context.clock().now();
// and the thread simply waits until notified.
if (remaining < 1)
break;
try {
// waits the specified time max
syn = _synQueue.poll(remaining, TimeUnit.MILLISECONDS);
} catch (InterruptedException ie) {
ConnectException ce = new ConnectException("Interrupted accept()");
ce.initCause(ie);
throw ce;
}
break;
}
}
if (syn != null) {
if (syn.getOptionalDelay() == PoisonPacket.POISON_MAX_DELAY_REQUEST) {
if (_restartPending)
throw new RouterRestartException();
throw new ConnectException("ServerSocket closed");
}
// Handle both SYN and non-SYN packets in the queue
if (syn.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
// We are single-threaded here, so this is
// a good place to check for dup SYNs and drop them
Destination from = syn.getOptionalFrom();
if (from == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Dropping SYN packet with no FROM: " + syn);
// drop it
continue;
}
Connection oldcon = _manager.getConnectionByOutboundId(syn.getReceiveStreamId());
if (oldcon != null) {
// only drop it on a destination match too
if (from.equals(oldcon.getRemotePeer())) {
if (_log.shouldLog(Log.WARN))
_log.warn("Dropping dup SYN: " + syn);
continue;
}
}
Connection con = _manager.receiveConnection(syn);
if (con != null)
return con;
} else {
reReceivePacket(syn);
// ... and keep looping
}
}
// keep looping...
}
}
use of net.i2p.data.Destination in project i2p.i2p by i2p.
the class ConnectionManager method receiveConnection.
/**
* Create a new connection based on the SYN packet we received.
*
* @param synPacket SYN packet to process
* @return created Connection with the packet's data already delivered to
* it, or null if the syn's streamId was already taken
*/
public Connection receiveConnection(Packet synPacket) {
ConnectionOptions opts = new ConnectionOptions(_defaultOptions);
opts.setPort(synPacket.getRemotePort());
opts.setLocalPort(synPacket.getLocalPort());
boolean reject = false;
int active = 0;
int total = 0;
// }
if (locked_tooManyStreams()) {
if ((!_defaultOptions.getDisableRejectLogging()) || _log.shouldLog(Log.WARN))
_log.logAlways(Log.WARN, "Refusing connection since we have exceeded our max of " + _defaultOptions.getMaxConns() + " connections");
reject = true;
} else {
// this may not be right if more than one is enabled
String why = shouldRejectConnection(synPacket);
if (why != null) {
if ((!_defaultOptions.getDisableRejectLogging()) || _log.shouldLog(Log.WARN))
_log.logAlways(Log.WARN, "Refusing connection since peer is " + why + (synPacket.getOptionalFrom() == null ? "" : ": " + synPacket.getOptionalFrom().toBase32()));
reject = true;
}
}
_context.statManager().addRateData("stream.receiveActive", active, total);
if (reject) {
Destination from = synPacket.getOptionalFrom();
if (from == null)
return null;
String resp = _defaultOptions.getLimitAction();
if ("drop".equals(resp)) {
// always drop
return null;
}
Hash h = from.calculateHash();
if (_globalBlacklist.contains(h) || (_defaultOptions.isAccessListEnabled() && !_defaultOptions.getAccessList().contains(h)) || (_defaultOptions.isBlacklistEnabled() && _defaultOptions.getBlacklist().contains(h))) {
// always drop these regardless of setting
return null;
}
if ((_minuteThrottler != null && _minuteThrottler.isOverBy(h, DROP_OVER_LIMIT)) || (_hourThrottler != null && _hourThrottler.isOverBy(h, DROP_OVER_LIMIT)) || (_dayThrottler != null && _dayThrottler.isOverBy(h, DROP_OVER_LIMIT))) {
// thus more inbound, but let's not spend several KB on the outbound.
if (_log.shouldLog(Log.INFO))
_log.info("Dropping limit response to " + from.toBase32());
return null;
}
boolean reset = resp == null || resp.equals("reset") || resp.length() <= 0;
boolean http = !reset && "http".equals(resp);
boolean custom = !(reset || http);
String sendResponse;
if (http) {
sendResponse = LIMIT_HTTP_RESPONSE;
} else if (custom) {
sendResponse = resp.replace("\\r", "\r").replace("\\n", "\n");
} else {
sendResponse = null;
}
PacketLocal reply = new PacketLocal(_context, from, synPacket.getSession());
if (sendResponse != null) {
reply.setFlag(Packet.FLAG_SYNCHRONIZE | Packet.FLAG_CLOSE | Packet.FLAG_SIGNATURE_INCLUDED);
reply.setSequenceNum(0);
ByteArray payload = new ByteArray(DataHelper.getUTF8(sendResponse));
reply.setPayload(payload);
} else {
reply.setFlag(Packet.FLAG_RESET | Packet.FLAG_SIGNATURE_INCLUDED);
}
reply.setAckThrough(synPacket.getSequenceNum());
reply.setSendStreamId(synPacket.getReceiveStreamId());
long rcvStreamId = assignRejectId();
reply.setReceiveStreamId(rcvStreamId);
reply.setOptionalFrom();
reply.setLocalPort(synPacket.getLocalPort());
reply.setRemotePort(synPacket.getRemotePort());
if (_log.shouldInfo())
// _log.info("Over limit, sending " + (sendResponse != null ? "configured response" : "reset") + " to " + from.toBase32());
_log.info("Over limit, sending " + reply + " to " + from.toBase32());
// this just sends the packet - no retries or whatnot
_outboundQueue.enqueue(reply);
return null;
}
Connection con = new Connection(_context, this, synPacket.getSession(), _schedulerChooser, _timer, _outboundQueue, _conPacketHandler, opts, true);
_tcbShare.updateOptsFromShare(con);
assignReceiveStreamId(con);
// finally, we know enough that we can log the packet with the conn filled in
if (I2PSocketManagerFull.pcapWriter != null && _context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP))
synPacket.logTCPDump(con);
try {
// This validates the packet, and sets the con's SendStreamID and RemotePeer
con.getPacketHandler().receivePacket(synPacket, con);
} catch (I2PException ie) {
_connectionByInboundId.remove(Long.valueOf(con.getReceiveStreamId()));
return null;
}
_context.statManager().addRateData("stream.connectionReceived", 1);
return con;
}
use of net.i2p.data.Destination in project i2p.i2p by i2p.
the class ConnectionManager method receivePing.
/**
* 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, ping.getSession());
pong.setFlag(Packet.FLAG_ECHO | Packet.FLAG_NO_ACK);
pong.setReceiveStreamId(ping.getSendStreamId());
pong.setLocalPort(ping.getLocalPort());
pong.setRemotePort(ping.getRemotePort());
// as of 0.9.18, return the payload
ByteArray payload = ping.getPayload();
if (payload != null) {
if (payload.getValid() > MAX_PONG_PAYLOAD)
payload.setValid(MAX_PONG_PAYLOAD);
pong.setPayload(payload);
}
_outboundQueue.enqueue(pong);
return true;
}
use of net.i2p.data.Destination in project i2p.i2p by i2p.
the class SAMDatagramSession method messageReceived.
protected void messageReceived(byte[] msg, int proto, int fromPort, int toPort) {
byte[] payload;
Destination sender;
try {
synchronized (dgramDissector) {
dgramDissector.loadI2PDatagram(msg);
sender = dgramDissector.getSender();
payload = dgramDissector.extractPayload();
}
} catch (DataFormatException e) {
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Dropping ill-formatted I2P repliable datagram", e);
}
return;
} catch (I2PInvalidDatagramException e) {
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Dropping ill-signed I2P repliable datagram", e);
}
return;
}
try {
recv.receiveDatagramBytes(sender, payload, proto, fromPort, toPort);
} catch (IOException e) {
_log.error("Error forwarding message to receiver", e);
close();
}
}
Aggregations