package net.i2p.sam;
/*
* free (adj.): unencumbered; not under the control of others
* Written by human in 2004 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.IOException;
import java.io.InputStream;
import java.util.Properties;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.datagram.I2PDatagramDissector;
import net.i2p.client.datagram.I2PDatagramMaker;
import net.i2p.client.datagram.I2PInvalidDatagramException;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.util.Log;
/**
* SAM DATAGRAM session class.
*
* @author human
*/
class SAMDatagramSession extends SAMMessageSession {
public static final int DGRAM_SIZE_MAX = 31*1024;
// FIXME make final after fixing SAMv3DatagramSession override
protected SAMDatagramReceiver recv;
private final I2PDatagramMaker dgramMaker;
private final I2PDatagramDissector dgramDissector = new I2PDatagramDissector();
/**
* Create a new SAM DATAGRAM session.
*
* @param dest Base64-encoded destination (private key)
* @param props Properties to setup the I2P session
* @param recv Object that will receive incoming data
* @throws IOException
* @throws DataFormatException
* @throws I2PSessionException
*/
protected SAMDatagramSession(String dest, Properties props,
SAMDatagramReceiver recv) throws IOException,
DataFormatException, I2PSessionException {
super(dest, props);
this.recv = recv;
dgramMaker = new I2PDatagramMaker(getI2PSession());
}
/**
* Create a new SAM DATAGRAM session.
*
* Caller MUST call start().
*
* @param destStream Input stream containing the destination keys
* @param props Properties to setup the I2P session
* @param recv Object that will receive incoming data
* @throws IOException
* @throws DataFormatException
* @throws I2PSessionException
*/
public SAMDatagramSession(InputStream destStream, Properties props,
SAMDatagramReceiver recv) throws IOException,
DataFormatException, I2PSessionException {
super(destStream, props);
this.recv = recv;
dgramMaker = new I2PDatagramMaker(getI2PSession());
}
/**
* Create a new SAM DATAGRAM session on an existing I2P session.
*
* @param props unused for now
* @since 0.9.25
*/
protected SAMDatagramSession(I2PSession sess, Properties props, int listenPort,
SAMDatagramReceiver recv) throws IOException,
DataFormatException, I2PSessionException {
super(sess, I2PSession.PROTO_DATAGRAM, listenPort);
this.recv = recv;
dgramMaker = new I2PDatagramMaker(getI2PSession());
}
/**
* Send bytes through a SAM DATAGRAM session.
*
* @param dest Destination
* @param data Bytes to be sent
* @param proto ignored, will always use PROTO_DATAGRAM (17)
*
* @return True if the data was sent, false otherwise
* @throws DataFormatException on unknown / bad dest
* @throws I2PSessionException on serious error, probably session closed
*/
public boolean sendBytes(String dest, byte[] data, int proto,
int fromPort, int toPort) throws DataFormatException, I2PSessionException {
if (data.length > DGRAM_SIZE_MAX)
throw new DataFormatException("Datagram size exceeded (" + data.length + ")");
byte[] dgram ;
synchronized (dgramMaker) {
dgram = dgramMaker.makeI2PDatagram(data);
}
return sendBytesThroughMessageSession(dest, dgram, I2PSession.PROTO_DATAGRAM, fromPort, toPort);
}
/**
* Send bytes through a SAM DATAGRAM session.
*
* @since 0.9.25
*/
public boolean sendBytes(String dest, byte[] data, int proto,
int fromPort, int toPort,
boolean sendLeaseSet, int sendTags,
int tagThreshold, int expiration)
throws DataFormatException, I2PSessionException {
if (data.length > DGRAM_SIZE_MAX)
throw new DataFormatException("Datagram size exceeded (" + data.length + ")");
byte[] dgram ;
synchronized (dgramMaker) {
dgram = dgramMaker.makeI2PDatagram(data);
}
return sendBytesThroughMessageSession(dest, dgram, I2PSession.PROTO_DATAGRAM, fromPort, toPort,
sendLeaseSet, sendTags,tagThreshold, expiration);
}
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();
}
}
protected void shutDown() {
recv.stopDatagramReceiving();
}
}