forked from I2P_Developers/i2p.i2p
* I2CP:
- Better fix for logging dropped messages (ticket #758) - Implement fast receive to reduce per-message handshakes - Make messageReliability=none the default
This commit is contained in:
@ -40,6 +40,24 @@ public interface I2PClient {
|
|||||||
/** @since 0.8.1 */
|
/** @since 0.8.1 */
|
||||||
public final static String PROP_RELIABILITY_NONE = "none";
|
public final static String PROP_RELIABILITY_NONE = "none";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For router->client payloads.
|
||||||
|
*
|
||||||
|
* If false, the router will send the MessageStatus,
|
||||||
|
* the client must respond with a ReceiveMessageBegin,
|
||||||
|
* the router will send the MessagePayload,
|
||||||
|
* and the client respond with a ReceiveMessageEnd.
|
||||||
|
*
|
||||||
|
* If true, the router will send the MessagePayload immediately,
|
||||||
|
* and will not send a MessageStatus.
|
||||||
|
* The client will not send ReceiveMessageBegin or ReceiveMessageEnd.
|
||||||
|
*
|
||||||
|
* Default false, but the implementation in this package sets to true.
|
||||||
|
*
|
||||||
|
* @since 0.9.4
|
||||||
|
*/
|
||||||
|
public final static String PROP_FAST_RECEIVE = "i2cp.fastReceive";
|
||||||
|
|
||||||
/** protocol flag that must be sent when opening the i2cp connection to the router */
|
/** protocol flag that must be sent when opening the i2cp connection to the router */
|
||||||
public final static int PROTOCOL_BYTE = 0x2A;
|
public final static int PROTOCOL_BYTE = 0x2A;
|
||||||
|
|
||||||
|
@ -136,6 +136,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
|||||||
|
|
||||||
private long _lastActivity;
|
private long _lastActivity;
|
||||||
private boolean _isReduced;
|
private boolean _isReduced;
|
||||||
|
private final boolean _fastReceive;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 0.8.9
|
* @since 0.8.9
|
||||||
@ -168,6 +169,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
|||||||
if (options == null)
|
if (options == null)
|
||||||
options = (Properties) System.getProperties().clone();
|
options = (Properties) System.getProperties().clone();
|
||||||
loadConfig(options);
|
loadConfig(options);
|
||||||
|
_fastReceive = Boolean.parseBoolean(_options.getProperty(I2PClient.PROP_FAST_RECEIVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -228,6 +230,10 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
|||||||
_options.setProperty("i2cp.password", configPW);
|
_options.setProperty("i2cp.password", configPW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_options.getProperty(I2PClient.PROP_FAST_RECEIVE) == null)
|
||||||
|
_options.setProperty(I2PClient.PROP_FAST_RECEIVE, "true");
|
||||||
|
if (_options.getProperty(I2PClient.PROP_RELIABILITY) == null)
|
||||||
|
_options.setProperty(I2PClient.PROP_RELIABILITY, "none");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** save some memory, don't pass along the pointless properties */
|
/** save some memory, don't pass along the pointless properties */
|
||||||
@ -280,6 +286,13 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
|||||||
} catch (I2PSessionException ise) {}
|
} catch (I2PSessionException ise) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.9.4
|
||||||
|
*/
|
||||||
|
public boolean getFastReceive() {
|
||||||
|
return _fastReceive;
|
||||||
|
}
|
||||||
|
|
||||||
void setLeaseSet(LeaseSet ls) {
|
void setLeaseSet(LeaseSet ls) {
|
||||||
_leaseSet = ls;
|
_leaseSet = ls;
|
||||||
if (ls != null) {
|
if (ls != null) {
|
||||||
|
@ -40,10 +40,19 @@ class MessagePayloadMessageHandler extends HandlerImpl {
|
|||||||
decryptPayload(msg, session);
|
decryptPayload(msg, session);
|
||||||
session.addNewMessage(msg);
|
session.addNewMessage(msg);
|
||||||
|
|
||||||
|
// Small chance of this, but
|
||||||
|
// if we are a new I2P lib talking to an old router
|
||||||
|
// and we don't send this, the router will OOM as it has
|
||||||
|
// no cleaner for old messages.
|
||||||
|
// TODO after 0.9.4 is out, check router version from handshake
|
||||||
|
// and send it all the time if 0.9.3 or less
|
||||||
|
// (needs router version saving support in SetDateMessageHandler)
|
||||||
|
//if (!session.getFastReceive()) {
|
||||||
ReceiveMessageEndMessage m = new ReceiveMessageEndMessage();
|
ReceiveMessageEndMessage m = new ReceiveMessageEndMessage();
|
||||||
m.setMessageId(id);
|
m.setMessageId(id);
|
||||||
m.setSessionId(msg.getSessionId());
|
m.setSessionId(msg.getSessionId());
|
||||||
session.sendMessage(m);
|
session.sendMessage(m);
|
||||||
|
//}
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
session.propogateError("Error handling a new payload message", dfe);
|
session.propogateError("Error handling a new payload message", dfe);
|
||||||
} catch (I2PSessionException ise) {
|
} catch (I2PSessionException ise) {
|
||||||
|
17
history.txt
17
history.txt
@ -1,3 +1,20 @@
|
|||||||
|
2012-11-02 zzz
|
||||||
|
* configstats: Fix group sorting, translate groups
|
||||||
|
* I2CP:
|
||||||
|
- Better fix for logging dropped messages (ticket #758)
|
||||||
|
- Implement fast receive to reduce per-message handshakes
|
||||||
|
- Make messageReliability=none the default
|
||||||
|
* i2psnark:
|
||||||
|
- Split buckets correctly
|
||||||
|
- More exploration fixes
|
||||||
|
* i2ptunnel:
|
||||||
|
- Better privkey backup file name
|
||||||
|
- Revert increment of privkey tunnel name
|
||||||
|
- Move deleted privkeys to backup dir
|
||||||
|
- Fix jsp build dependencies
|
||||||
|
- Fix layout issue on Chrome (ticket #757)
|
||||||
|
* KeyManager: Eliminate races, buffer I/O, eliminate periodic syncing
|
||||||
|
|
||||||
2012-10-31 zzz
|
2012-10-31 zzz
|
||||||
* FIFOBandwidthRefiller: Reduce refill interval to smooth output
|
* FIFOBandwidthRefiller: Reduce refill interval to smooth output
|
||||||
* I2CP: Reduce log level when outbound queue is full (ticket #758)
|
* I2CP: Reduce log level when outbound queue is full (ticket #758)
|
||||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 3;
|
public final static long BUILD = 4;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
@ -90,6 +90,8 @@ class ClientConnectionRunner {
|
|||||||
private volatile boolean _dead;
|
private volatile boolean _dead;
|
||||||
/** For outbound traffic. true if i2cp.messageReliability = "none"; @since 0.8.1 */
|
/** For outbound traffic. true if i2cp.messageReliability = "none"; @since 0.8.1 */
|
||||||
private boolean _dontSendMSM;
|
private boolean _dontSendMSM;
|
||||||
|
/** For inbound traffic. true if i2cp.fastReceive = "true"; @since 0.9.4 */
|
||||||
|
private boolean _dontSendMSMOnReceive;
|
||||||
private final AtomicInteger _messageId; // messageId counter
|
private final AtomicInteger _messageId; // messageId counter
|
||||||
|
|
||||||
// Was 32767 since the beginning (04-2004).
|
// Was 32767 since the beginning (04-2004).
|
||||||
@ -113,6 +115,7 @@ class ClientConnectionRunner {
|
|||||||
_log = _context.logManager().getLog(ClientConnectionRunner.class);
|
_log = _context.logManager().getLog(ClientConnectionRunner.class);
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_socket = socket;
|
_socket = socket;
|
||||||
|
// unused for fastReceive
|
||||||
_messages = new ConcurrentHashMap();
|
_messages = new ConcurrentHashMap();
|
||||||
_alreadyProcessed = new ArrayList();
|
_alreadyProcessed = new ArrayList();
|
||||||
_acceptedPending = new ConcurrentHashSet();
|
_acceptedPending = new ConcurrentHashSet();
|
||||||
@ -136,7 +139,6 @@ class ClientConnectionRunner {
|
|||||||
I2PThread t = new I2PThread(_writer);
|
I2PThread t = new I2PThread(_writer);
|
||||||
t.setName("I2CP Writer " + __id.incrementAndGet());
|
t.setName("I2CP Writer " + __id.incrementAndGet());
|
||||||
t.setDaemon(true);
|
t.setDaemon(true);
|
||||||
t.setPriority(I2PThread.MAX_PRIORITY);
|
|
||||||
t.start();
|
t.start();
|
||||||
_out = new BufferedOutputStream(_socket.getOutputStream());
|
_out = new BufferedOutputStream(_socket.getOutputStream());
|
||||||
_reader.startReading();
|
_reader.startReading();
|
||||||
@ -200,15 +202,24 @@ class ClientConnectionRunner {
|
|||||||
/** already closed? */
|
/** already closed? */
|
||||||
boolean isDead() { return _dead; }
|
boolean isDead() { return _dead; }
|
||||||
|
|
||||||
/** message body */
|
/**
|
||||||
|
* Only call if _dontSendMSMOnReceive is false, otherwise will always be null
|
||||||
|
*/
|
||||||
Payload getPayload(MessageId id) {
|
Payload getPayload(MessageId id) {
|
||||||
return _messages.get(id);
|
return _messages.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only call if _dontSendMSMOnReceive is false
|
||||||
|
*/
|
||||||
void setPayload(MessageId id, Payload payload) {
|
void setPayload(MessageId id, Payload payload) {
|
||||||
|
if (!_dontSendMSMOnReceive)
|
||||||
_messages.put(id, payload);
|
_messages.put(id, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only call if _dontSendMSMOnReceive is false
|
||||||
|
*/
|
||||||
void removePayload(MessageId id) {
|
void removePayload(MessageId id) {
|
||||||
_messages.remove(id);
|
_messages.remove(id);
|
||||||
}
|
}
|
||||||
@ -221,8 +232,10 @@ class ClientConnectionRunner {
|
|||||||
// We process a few options here, but most are handled by the tunnel manager.
|
// We process a few options here, but most are handled by the tunnel manager.
|
||||||
// The ones here can't be changed later.
|
// The ones here can't be changed later.
|
||||||
Properties opts = config.getOptions();
|
Properties opts = config.getOptions();
|
||||||
if (opts != null)
|
if (opts != null) {
|
||||||
_dontSendMSM = "none".equals(config.getOptions().getProperty(I2PClient.PROP_RELIABILITY, "").toLowerCase(Locale.US));
|
_dontSendMSM = "none".equals(opts.getProperty(I2PClient.PROP_RELIABILITY, "").toLowerCase(Locale.US));
|
||||||
|
_dontSendMSMOnReceive = Boolean.parseBoolean(opts.getProperty(I2PClient.PROP_FAST_RECEIVE));
|
||||||
|
}
|
||||||
// per-destination session key manager to prevent rather easy correlation
|
// per-destination session key manager to prevent rather easy correlation
|
||||||
if (_sessionKeyManager == null) {
|
if (_sessionKeyManager == null) {
|
||||||
int tags = TransientSessionKeyManager.DEFAULT_TAGS;
|
int tags = TransientSessionKeyManager.DEFAULT_TAGS;
|
||||||
@ -306,7 +319,7 @@ class ClientConnectionRunner {
|
|||||||
doSend(msg);
|
doSend(msg);
|
||||||
} catch (I2CPMessageException ime) {
|
} catch (I2CPMessageException ime) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Error writing out the disconnect message: " + ime);
|
_log.warn("Error writing out the disconnect message", ime);
|
||||||
}
|
}
|
||||||
// give it a little time to get sent out...
|
// give it a little time to get sent out...
|
||||||
// even better would be to have stopRunning() flush it?
|
// even better would be to have stopRunning() flush it?
|
||||||
@ -378,7 +391,8 @@ class ClientConnectionRunner {
|
|||||||
doSend(status);
|
doSend(status);
|
||||||
_acceptedPending.remove(id);
|
_acceptedPending.remove(id);
|
||||||
} catch (I2CPMessageException ime) {
|
} catch (I2CPMessageException ime) {
|
||||||
_log.error("Error writing out the message status message: " + ime);
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Error writing out the message status message", ime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +402,7 @@ class ClientConnectionRunner {
|
|||||||
*/
|
*/
|
||||||
void receiveMessage(Destination toDest, Destination fromDest, Payload payload) {
|
void receiveMessage(Destination toDest, Destination fromDest, Payload payload) {
|
||||||
if (_dead) return;
|
if (_dead) return;
|
||||||
MessageReceivedJob j = new MessageReceivedJob(_context, this, toDest, fromDest, payload);
|
MessageReceivedJob j = new MessageReceivedJob(_context, this, toDest, fromDest, payload, _dontSendMSMOnReceive);
|
||||||
// This is fast and non-blocking, run in-line
|
// This is fast and non-blocking, run in-line
|
||||||
//_context.jobQueue().addJob(j);
|
//_context.jobQueue().addJob(j);
|
||||||
j.runJob();
|
j.runJob();
|
||||||
@ -680,6 +694,7 @@ class ClientConnectionRunner {
|
|||||||
try {
|
try {
|
||||||
doSend(msg);
|
doSend(msg);
|
||||||
} catch (I2CPMessageException ime) {
|
} catch (I2CPMessageException ime) {
|
||||||
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Error updating the status for message ID " + _messageId, ime);
|
_log.warn("Error updating the status for message ID " + _messageId, ime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,8 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
|
|||||||
*/
|
*/
|
||||||
public void messageReceived(I2CPMessageReader reader, I2CPMessage message) {
|
public void messageReceived(I2CPMessageReader reader, I2CPMessage message) {
|
||||||
if (_runner.isDead()) return;
|
if (_runner.isDead()) return;
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.info("Message recieved: \n" + message);
|
_log.debug("Message received: \n" + message);
|
||||||
switch (message.getType()) {
|
switch (message.getType()) {
|
||||||
case GetDateMessage.MESSAGE_TYPE:
|
case GetDateMessage.MESSAGE_TYPE:
|
||||||
handleGetDate(reader, (GetDateMessage)message);
|
handleGetDate(reader, (GetDateMessage)message);
|
||||||
@ -225,7 +225,7 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
|
|||||||
MessageId id = _runner.distributeMessage(message);
|
MessageId id = _runner.distributeMessage(message);
|
||||||
long timeToDistribute = _context.clock().now() - beforeDistribute;
|
long timeToDistribute = _context.clock().now() - beforeDistribute;
|
||||||
_runner.ackSendMessage(id, message.getNonce());
|
_runner.ackSendMessage(id, message.getNonce());
|
||||||
_context.statManager().addRateData("client.distributeTime", timeToDistribute, timeToDistribute);
|
_context.statManager().addRateData("client.distributeTime", timeToDistribute);
|
||||||
if ( (timeToDistribute > 50) && (_log.shouldLog(Log.WARN)) )
|
if ( (timeToDistribute > 50) && (_log.shouldLog(Log.WARN)) )
|
||||||
_log.warn("Took too long to distribute the message (which holds up the ack): " + timeToDistribute);
|
_log.warn("Took too long to distribute the message (which holds up the ack): " + timeToDistribute);
|
||||||
}
|
}
|
||||||
@ -253,7 +253,9 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
|
|||||||
try {
|
try {
|
||||||
_runner.doSend(msg);
|
_runner.doSend(msg);
|
||||||
} catch (I2CPMessageException ime) {
|
} catch (I2CPMessageException ime) {
|
||||||
_log.error("Error delivering the payload", ime);
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Error delivering the payload", ime);
|
||||||
|
_runner.removePayload(new MessageId(message.getMessageId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +332,8 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
|
|||||||
try {
|
try {
|
||||||
_runner.doSend(msg);
|
_runner.doSend(msg);
|
||||||
} catch (I2CPMessageException ime) {
|
} catch (I2CPMessageException ime) {
|
||||||
_log.error("Error writing out the session status message", ime);
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Error writing out the session status message", ime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +351,8 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
|
|||||||
try {
|
try {
|
||||||
_runner.doSend(msg);
|
_runner.doSend(msg);
|
||||||
} catch (I2CPMessageException ime) {
|
} catch (I2CPMessageException ime) {
|
||||||
_log.error("Error writing out the session status message", ime);
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Error writing out the session status message", ime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,39 +12,50 @@ import net.i2p.data.Destination;
|
|||||||
import net.i2p.data.Payload;
|
import net.i2p.data.Payload;
|
||||||
import net.i2p.data.i2cp.I2CPMessageException;
|
import net.i2p.data.i2cp.I2CPMessageException;
|
||||||
import net.i2p.data.i2cp.MessageId;
|
import net.i2p.data.i2cp.MessageId;
|
||||||
|
import net.i2p.data.i2cp.MessagePayloadMessage;
|
||||||
import net.i2p.data.i2cp.MessageStatusMessage;
|
import net.i2p.data.i2cp.MessageStatusMessage;
|
||||||
import net.i2p.router.JobImpl;
|
import net.i2p.router.JobImpl;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async job to notify the client that a new message is available for them
|
* Async job to notify the client that a new message is available for them,
|
||||||
|
* or just send it directly if specified.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class MessageReceivedJob extends JobImpl {
|
class MessageReceivedJob extends JobImpl {
|
||||||
private final Log _log;
|
private final Log _log;
|
||||||
private final ClientConnectionRunner _runner;
|
private final ClientConnectionRunner _runner;
|
||||||
private final Payload _payload;
|
private final Payload _payload;
|
||||||
|
private final boolean _sendDirect;
|
||||||
|
|
||||||
public MessageReceivedJob(RouterContext ctx, ClientConnectionRunner runner, Destination toDest, Destination fromDest, Payload payload) {
|
public MessageReceivedJob(RouterContext ctx, ClientConnectionRunner runner, Destination toDest,
|
||||||
|
Destination fromDest, Payload payload, boolean sendDirect) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
_log = ctx.logManager().getLog(MessageReceivedJob.class);
|
_log = ctx.logManager().getLog(MessageReceivedJob.class);
|
||||||
_runner = runner;
|
_runner = runner;
|
||||||
_payload = payload;
|
_payload = payload;
|
||||||
|
_sendDirect = sendDirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() { return "Deliver New Message"; }
|
public String getName() { return "Deliver New Message"; }
|
||||||
|
|
||||||
public void runJob() {
|
public void runJob() {
|
||||||
if (_runner.isDead()) return;
|
if (_runner.isDead()) return;
|
||||||
MessageId id = new MessageId();
|
MessageId id = null;
|
||||||
id.setMessageId(_runner.getNextMessageId());
|
long nextID = _runner.getNextMessageId();
|
||||||
_runner.setPayload(id, _payload);
|
|
||||||
try {
|
try {
|
||||||
|
if (_sendDirect) {
|
||||||
|
sendMessage(nextID);
|
||||||
|
} else {
|
||||||
|
id = new MessageId(nextID);
|
||||||
|
_runner.setPayload(id, _payload);
|
||||||
messageAvailable(id, _payload.getSize());
|
messageAvailable(id, _payload.getSize());
|
||||||
|
}
|
||||||
} catch (I2CPMessageException ime) {
|
} catch (I2CPMessageException ime) {
|
||||||
if (_log.shouldLog(Log.ERROR))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.error("Error writing out the message status message", ime);
|
_log.warn("Error writing out the message", ime);
|
||||||
|
if (!_sendDirect)
|
||||||
_runner.removePayload(id);
|
_runner.removePayload(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,4 +76,16 @@ class MessageReceivedJob extends JobImpl {
|
|||||||
msg.setStatus(MessageStatusMessage.STATUS_AVAILABLE);
|
msg.setStatus(MessageStatusMessage.STATUS_AVAILABLE);
|
||||||
_runner.doSend(msg);
|
_runner.doSend(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deliver the message directly, skip notification
|
||||||
|
* @since 0.9.4
|
||||||
|
*/
|
||||||
|
private void sendMessage(long id) throws I2CPMessageException {
|
||||||
|
MessagePayloadMessage msg = new MessagePayloadMessage();
|
||||||
|
msg.setMessageId(id);
|
||||||
|
msg.setSessionId(_runner.getSessionId().getSessionId());
|
||||||
|
msg.setPayload(_payload);
|
||||||
|
_runner.doSend(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,16 +60,13 @@ class QueuedClientConnectionRunner extends ClientConnectionRunner {
|
|||||||
/**
|
/**
|
||||||
* Actually send the I2CPMessage to the client.
|
* Actually send the I2CPMessage to the client.
|
||||||
* Nonblocking.
|
* Nonblocking.
|
||||||
|
* @throws I2CPMessageException if queue full or on other errors
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
void doSend(I2CPMessage msg) throws I2CPMessageException {
|
void doSend(I2CPMessage msg) throws I2CPMessageException {
|
||||||
// This will never fail, for now, as the router uses unbounded queues
|
|
||||||
// Perhaps in the future we may want to use bounded queues,
|
|
||||||
// with non-blocking writes for the router
|
|
||||||
// and blocking writes for the client?
|
|
||||||
boolean success = queue.offer(msg);
|
boolean success = queue.offer(msg);
|
||||||
if (!success && _log.shouldLog(Log.WARN))
|
if (!success)
|
||||||
_log.warn("I2CP write to queue failed: " + msg);
|
throw new I2CPMessageException("I2CP write to queue failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user