
* Every time we create a new router identity, add an entry to the new "identlog.txt" text file in the I2P install directory. For debugging purposes, publish the count of how many identities the router has cycled through, though not the identities itself. * Cleaned up the way the multitransport shitlisting worked, and added per-transport shitlists * When dropping a router reference locally, first fire a netDb lookup for the entry * Take the peer selection filters into account when organizing the profiles (thanks Complication!) * Avoid some obvious configuration errors for the NTCP transport (invalid ports, "null" ip, etc) * Deal with some small NTCP bugs found in the wild (unresolveable hosts, strange network discons, etc) * Send our netDb info to peers we have direct NTCP connections to after each 6-12 hours of connection uptime * Clean up the NTCP reading and writing queue logic to avoid some potential delays * Allow people to specify the IP that the SSU transport binds on locally, via the advanced config "i2np.udp.bindInterface=1.2.3.4"
140 lines
5.2 KiB
Java
140 lines
5.2 KiB
Java
package net.i2p.data.i2np;
|
|
/*
|
|
* free (adj.): unencumbered; not under the control of others
|
|
* Written by jrandom in 2003 and released into the public domain
|
|
* with no warranty of any kind, either expressed or implied.
|
|
* It probably won't make your computer catch on fire, or eat
|
|
* your children, but it might. Use at your own risk.
|
|
*
|
|
*/
|
|
|
|
import java.io.FileInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
|
|
import net.i2p.I2PAppContext;
|
|
import net.i2p.data.DataFormatException;
|
|
import net.i2p.data.DataHelper;
|
|
import net.i2p.util.Log;
|
|
|
|
/**
|
|
* Handle messages from router to router. This class is NOT threadsafe
|
|
*
|
|
*/
|
|
public class I2NPMessageHandler {
|
|
private Log _log;
|
|
private I2PAppContext _context;
|
|
private long _lastReadBegin;
|
|
private long _lastReadEnd;
|
|
private int _lastSize;
|
|
private byte _messageBuffer[];
|
|
private I2NPMessage _lastRead;
|
|
|
|
public I2NPMessageHandler(I2PAppContext context) {
|
|
_context = context;
|
|
_log = context.logManager().getLog(I2NPMessageHandler.class);
|
|
_messageBuffer = null;
|
|
_lastSize = -1;
|
|
}
|
|
|
|
/**
|
|
* Read an I2NPMessage from the stream and return the fully populated object.
|
|
*
|
|
* @throws IOException if there is an IO problem reading from the stream
|
|
* @throws I2NPMessageException if there is a problem handling the particular
|
|
* message - if it is an unknown type or has improper formatting, etc.
|
|
*/
|
|
public I2NPMessage readMessage(InputStream in) throws IOException, I2NPMessageException {
|
|
if (_messageBuffer == null) _messageBuffer = new byte[38*1024]; // more than necessary
|
|
try {
|
|
int type = (int)DataHelper.readLong(in, 1);
|
|
_lastReadBegin = System.currentTimeMillis();
|
|
I2NPMessage msg = I2NPMessageImpl.createMessage(_context, type);
|
|
if (msg == null)
|
|
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message");
|
|
try {
|
|
_lastSize = msg.readBytes(in, type, _messageBuffer);
|
|
} catch (IOException ioe) {
|
|
throw ioe;
|
|
} catch (I2NPMessageException ime) {
|
|
throw ime;
|
|
} catch (Exception e) {
|
|
if (_log.shouldLog(Log.WARN))
|
|
_log.warn("Error reading the stream", e);
|
|
throw new IOException("Unknown error reading the " + msg.getClass().getName()
|
|
+ ": " + e.getMessage());
|
|
}
|
|
_lastReadEnd = System.currentTimeMillis();
|
|
return msg;
|
|
} catch (DataFormatException dfe) {
|
|
throw new I2NPMessageException("Error reading the message", dfe);
|
|
}
|
|
}
|
|
|
|
/** clear the last message read from a byte array with an offset */
|
|
public I2NPMessage lastRead() {
|
|
I2NPMessage rv = _lastRead;
|
|
_lastRead = null;
|
|
return rv;
|
|
}
|
|
|
|
/**
|
|
* Read an I2NPMessage from the stream and return the fully populated object.
|
|
*
|
|
* @throws IOException if there is an IO problem reading from the stream
|
|
* @throws I2NPMessageException if there is a problem handling the particular
|
|
* message - if it is an unknown type or has improper formatting, etc.
|
|
*/
|
|
public I2NPMessage readMessage(byte data[]) throws IOException, I2NPMessageException {
|
|
int offset = readMessage(data, 0);
|
|
return lastRead();
|
|
}
|
|
public int readMessage(byte data[], int offset) throws IOException, I2NPMessageException {
|
|
int cur = offset;
|
|
int type = (int)DataHelper.fromLong(data, cur, 1);
|
|
cur++;
|
|
_lastReadBegin = System.currentTimeMillis();
|
|
I2NPMessage msg = I2NPMessageImpl.createMessage(_context, type);
|
|
if (msg == null) {
|
|
int sz = data.length-offset;
|
|
boolean allZero = false;
|
|
for (int i = offset; i < data.length; i++) {
|
|
if (data[i] != 0) {
|
|
allZero = false;
|
|
break;
|
|
}
|
|
}
|
|
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message (remaining sz="
|
|
+ sz + " all zeros? " + allZero + ")");
|
|
}
|
|
try {
|
|
_lastSize = msg.readBytes(data, type, cur);
|
|
cur += _lastSize;
|
|
} catch (IOException ioe) {
|
|
throw ioe;
|
|
} catch (I2NPMessageException ime) {
|
|
throw ime;
|
|
} catch (Exception e) {
|
|
if (_log.shouldLog(Log.WARN))
|
|
_log.warn("Error reading the stream", e);
|
|
throw new IOException("Unknown error reading the " + msg.getClass().getName()
|
|
+ ": " + e.getMessage());
|
|
}
|
|
_lastReadEnd = System.currentTimeMillis();
|
|
_lastRead = msg;
|
|
return cur - offset;
|
|
}
|
|
|
|
public long getLastReadTime() { return _lastReadEnd - _lastReadBegin; }
|
|
public int getLastSize() { return _lastSize; }
|
|
|
|
public static void main(String args[]) {
|
|
try {
|
|
I2NPMessage msg = new I2NPMessageHandler(I2PAppContext.getGlobalContext()).readMessage(new FileInputStream(args[0]));
|
|
System.out.println(msg);
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|