use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class StoreJob method sendStoreThroughClient.
/**
* Send a leaseset store message out the client tunnel,
* with the reply to come back through a client tunnel.
* Stores are garlic encrypted to hide the identity from the OBEP.
*
* This makes it harder for an exploratory OBEP or IBGW to correlate it
* with one or more destinations. Since we are publishing the leaseset,
* it's easy to find out that an IB tunnel belongs to this dest, and
* it isn't much harder to do the same for an OB tunnel.
*
* As a side benefit, client tunnels should be faster and more reliable than
* exploratory tunnels.
*
* @param msg must contain a leaseset
* @since 0.7.10
*/
private void sendStoreThroughClient(DatabaseStoreMessage msg, RouterInfo peer, long expiration) {
long token = 1 + getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE);
Hash client = msg.getKey();
Hash to = peer.getIdentity().getHash();
TunnelInfo replyTunnel = getContext().tunnelManager().selectInboundTunnel(client, to);
if (replyTunnel == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No reply inbound tunnels available!");
fail();
return;
}
TunnelId replyTunnelId = replyTunnel.getReceiveTunnelId(0);
msg.setReplyToken(token);
msg.setReplyTunnel(replyTunnelId);
msg.setReplyGateway(replyTunnel.getPeer(0));
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": send(dbStore) w/ token expected " + token);
TunnelInfo outTunnel = getContext().tunnelManager().selectOutboundTunnel(client, to);
if (outTunnel != null) {
I2NPMessage sent;
boolean shouldEncrypt = supportsEncryption(peer);
if (shouldEncrypt) {
// garlic encrypt
MessageWrapper.WrappedMessage wm = MessageWrapper.wrap(getContext(), msg, client, peer);
if (wm == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Fail garlic encrypting from: " + client);
fail();
return;
}
sent = wm.getMessage();
_state.addPending(to, wm);
} else {
_state.addPending(to);
// now that almost all floodfills are at 0.7.10,
// just refuse to store unencrypted to older ones.
_state.replyTimeout(to);
getContext().jobQueue().addJob(new WaitJob(getContext()));
return;
}
SendSuccessJob onReply = new SendSuccessJob(getContext(), peer, outTunnel, sent.getMessageSize());
FailedJob onFail = new FailedJob(getContext(), peer, getContext().clock().now());
StoreMessageSelector selector = new StoreMessageSelector(getContext(), getJobId(), peer, token, expiration);
if (_log.shouldLog(Log.DEBUG)) {
if (shouldEncrypt)
_log.debug("sending encrypted store to " + peer.getIdentity().getHash() + " through " + outTunnel + ": " + sent);
else
_log.debug("sending store to " + peer.getIdentity().getHash() + " through " + outTunnel + ": " + sent);
// _log.debug("Expiration is " + new Date(sent.getMessageExpiration()));
}
getContext().messageRegistry().registerPending(selector, onReply, onFail);
getContext().tunnelDispatcher().dispatchOutbound(sent, outTunnel.getSendTunnelId(0), null, to);
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("No outbound tunnels to send a dbStore out - delaying...");
// continueSending() above did an addPending() so remove it here.
// This means we will skip the peer next time, can't be helped for now
// without modding StoreState
_state.replyTimeout(to);
Job waiter = new WaitJob(getContext());
waiter.getTiming().setStartAfter(getContext().clock().now() + 3 * 1000);
getContext().jobQueue().addJob(waiter);
// fail();
}
}
use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class EstablishmentManager method sendInboundComplete.
/**
* dont send our info immediately, just send a small data packet, and 5-10s later,
* if the peer isnt banlisted, *then* send them our info. this will help kick off
* the oldnet
* The "oldnet" was < 0.6.1.10, it is long gone.
* The delay really slows down the network.
* The peer is unbanlisted and marked reachable by addRemotePeerState() which calls markReachable()
* so the check below is fairly pointless.
* If for some strange reason an oldnet router (NETWORK_ID == 1) does show up,
* it's handled in UDPTransport.messageReceived()
* (where it will get dropped, marked unreachable and banlisted at that time).
*/
private void sendInboundComplete(PeerState peer) {
// SimpleTimer.getInstance().addEvent(new PublishToNewInbound(peer), 10*1000);
if (_log.shouldLog(Log.INFO))
_log.info("Completing to the peer after IB confirm: " + peer);
DeliveryStatusMessage dsm = new DeliveryStatusMessage(_context);
// overloaded, sure, but future versions can check this
dsm.setArrival(_networkID);
// This causes huge values in the inNetPool.droppedDeliveryStatusDelay stat
// so it needs to be caught in InNetMessagePool.
dsm.setMessageExpiration(_context.clock().now() + DATA_MESSAGE_TIMEOUT);
dsm.setMessageId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
// sent below
// just do this inline
// _context.simpleTimer2().addEvent(new PublishToNewInbound(peer), 0);
Hash hash = peer.getRemotePeer();
if ((hash != null) && (!_context.banlist().isBanlisted(hash)) && (!_transport.isUnreachable(hash))) {
// ok, we are fine with them, send them our latest info
// if (_log.shouldLog(Log.INFO))
// _log.info("Publishing to the peer after confirm plus delay (without banlist): " + peer);
// bundle the two messages together for efficiency
DatabaseStoreMessage dbsm = getOurInfo();
List<I2NPMessage> msgs = new ArrayList<I2NPMessage>(2);
msgs.add(dsm);
msgs.add(dbsm);
_transport.send(msgs, peer);
} else {
_transport.send(dsm, peer);
// nuh uh.
if (_log.shouldLog(Log.WARN))
_log.warn("NOT publishing to the peer after confirm plus delay (WITH banlist): " + (hash != null ? hash.toString() : "unknown"));
}
}
use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class TunnelGatewayZeroHop method add.
/**
* Add a message to be sent down the tunnel, where we are the inbound gateway.
* This requires converting the message included in the TGM from an
* UnknownI2NPMessage to the correct message class.
* See TunnelGatewayMessage for details.
*
* @param msg message received to be sent through the tunnel
*/
@Override
public void add(TunnelGatewayMessage msg) {
I2NPMessage imsg = msg.getMessage();
if (_config.isInbound()) {
if (imsg instanceof UnknownI2NPMessage) {
// Do the delayed deserializing - convert to a standard message class
try {
UnknownI2NPMessage umsg = (UnknownI2NPMessage) imsg;
imsg = umsg.convert();
} catch (I2NPMessageException ime) {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to convert to std. msg. class at zero-hop IBGW", ime);
return;
}
}
}
add(imsg, null, null);
}
use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class NTCPTransport method outboundMessageReady.
protected void outboundMessageReady() {
OutNetMessage msg = getNextMessage();
if (msg != null) {
RouterInfo target = msg.getTarget();
RouterIdentity ident = target.getIdentity();
Hash ih = ident.calculateHash();
NTCPConnection con = null;
boolean isNew = false;
boolean fail = false;
synchronized (_conLock) {
con = _conByIdent.get(ih);
if (con == null) {
isNew = true;
RouterAddress addr = getTargetAddress(target);
if (addr != null) {
con = new NTCPConnection(_context, this, ident, addr);
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("Send on a new con: " + con + " at " + addr + " for " + ih);
// Note that outbound conns go in the map BEFORE establishment
_conByIdent.put(ih, con);
} else {
// race, RI changed out from under us
// call afterSend below outside of conLock
fail = true;
}
}
}
if (fail) {
// race, RI changed out from under us, maybe SSU can handle it
if (_log.shouldLog(Log.WARN))
_log.warn("we bid on a peer who doesn't have an ntcp address? " + target);
afterSend(msg, false);
return;
}
if (isNew) {
// doesn't do anything yet, just enqueues it
con.send(msg);
// As of 0.9.12, don't send our info if the first message is
// doing the same (common when connecting to a floodfill).
// Also, put the info message after whatever we are trying to send
// (it's a priority queue anyway and the info is low priority)
// Prior to 0.9.12, Bob would not send his RI unless he had ours,
// but that's fixed in 0.9.12.
boolean shouldSkipInfo = false;
I2NPMessage m = msg.getMessage();
if (m.getType() == DatabaseStoreMessage.MESSAGE_TYPE) {
DatabaseStoreMessage dsm = (DatabaseStoreMessage) m;
if (dsm.getKey().equals(_context.routerHash())) {
shouldSkipInfo = true;
}
}
if (!shouldSkipInfo) {
con.enqueueInfoMessage();
} else if (_log.shouldLog(Log.INFO)) {
_log.info("SKIPPING INFO message: " + con);
}
try {
SocketChannel channel = SocketChannel.open();
con.setChannel(channel);
channel.configureBlocking(false);
_pumper.registerConnect(con);
con.getEstablishState().prepareOutbound();
} catch (IOException ioe) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error opening a channel", ioe);
_context.statManager().addRateData("ntcp.outboundFailedIOEImmediate", 1);
con.close();
}
} else {
con.send(msg);
}
/*
NTCPConnection con = getCon(ident);
remove the race here
if (con != null) {
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Send on an existing con: " + con);
con.send(msg);
} else {
RouterAddress addr = msg.getTarget().getTargetAddress(STYLE);
if (addr != null) {
NTCPAddress naddr = new NTCPAddress(addr);
con = new NTCPConnection(_context, this, ident, naddr);
Hash ih = ident.calculateHash();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Send on a new con: " + con + " at " + addr + " for " + ih.toBase64());
NTCPConnection old = null;
synchronized (_conLock) {
old = (NTCPConnection)_conByIdent.put(ih, con);
}
if (old != null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Multiple connections on out ready, closing " + old + " and keeping " + con);
old.close();
}
con.enqueueInfoMessage(); // enqueues a netDb store of our own info
con.send(msg); // doesn't do anything yet, just enqueues it
try {
SocketChannel channel = SocketChannel.open();
con.setChannel(channel);
channel.configureBlocking(false);
_pumper.registerConnect(con);
} catch (IOException ioe) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error opening a channel", ioe);
con.close();
}
} else {
con.close();
}
}
*/
}
}
use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class SearchJob method sendLeaseSearch.
/**
* we're (probably) searching for a LeaseSet, so to be (overly) cautious, we're sending
* the request out through a tunnel w/ reply back through another tunnel.
*/
protected void sendLeaseSearch(RouterInfo router) {
Hash to = router.getIdentity().getHash();
TunnelInfo inTunnel = getContext().tunnelManager().selectInboundExploratoryTunnel(to);
if (inTunnel == null) {
_log.warn("No tunnels to get search replies through!");
getContext().jobQueue().addJob(new FailedJob(getContext(), router));
return;
}
TunnelId inTunnelId = inTunnel.getReceiveTunnelId(0);
// this will fail if we've banlisted our inbound gateway, but the gw may not necessarily
// be banlisted by whomever needs to contact them, so we don't need to check this
// RouterInfo inGateway = getContext().netDb().lookupRouterInfoLocally(inTunnel.getPeer(0));
// if (inGateway == null) {
// _log.error("We can't find the gateway to our inbound tunnel?!");
// getContext().jobQueue().addJob(new FailedJob(getContext(), router));
// return;
// }
int timeout = getPerPeerTimeoutMs(to);
long expiration = getContext().clock().now() + timeout;
I2NPMessage msg = buildMessage(inTunnelId, inTunnel.getPeer(0), expiration, router);
if (msg == null) {
getContext().jobQueue().addJob(new FailedJob(getContext(), router));
return;
}
TunnelInfo outTunnel = getContext().tunnelManager().selectOutboundExploratoryTunnel(to);
if (outTunnel == null) {
_log.warn("No tunnels to send search out through! Impossible?");
getContext().jobQueue().addJob(new FailedJob(getContext(), router));
return;
}
TunnelId outTunnelId = outTunnel.getSendTunnelId(0);
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": Sending search to " + to + " for " + getState().getTarget() + " w/ replies through " + inTunnel.getPeer(0) + " via tunnel " + inTunnelId);
SearchMessageSelector sel = new SearchMessageSelector(getContext(), router, _expiration, _state);
SearchUpdateReplyFoundJob reply = new SearchUpdateReplyFoundJob(getContext(), router, _state, _facade, this, outTunnel, inTunnel);
if (FloodfillNetworkDatabaseFacade.isFloodfill(router))
_floodfillSearchesOutstanding++;
getContext().messageRegistry().registerPending(sel, reply, new FailedJob(getContext(), router));
// TODO pass a priority to the dispatcher
getContext().tunnelDispatcher().dispatchOutbound(msg, outTunnelId, to);
}
Aggregations