package net.i2p.client;
/*
* 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.InputStream;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.PrivateKey;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.data.SigningPrivateKey;
/**
* <p>Define the standard means of sending and receiving messages on the
* I2P network by using the I2CP (the client protocol). This is done over a
* bidirectional TCP socket.
*
* End to end encryption in I2PSession was disabled in release 0.6.
*
* Periodically the router will ask the client to authorize a new set of
* tunnels to be allocated to the client, which the client can accept by sending a
* {@link net.i2p.data.LeaseSet} signed by the {@link net.i2p.data.Destination}.
* In addition, the router may on occasion provide the client with an updated
* clock offset so that the client can stay in sync with the network (even if
* the host computer's clock is off).</p>
*
*/
public interface I2PSession {
/** Send a new message to the given destination, containing the specified
* payload, returning true if the router feels confident that the message
* was delivered.
*
* WARNING: It is recommended that you use a method that specifies the protocol and ports.
*
* @param dest location to send the message
* @param payload body of the message to be sent (unencrypted)
* @return whether it was accepted by the router for delivery or not
*/
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException;
/** Send a new message to the given destination, containing the specified
* payload, returning true if the router feels confident that the message
* was delivered.
*
* WARNING: It is recommended that you use a method that specifies the protocol and ports.
*
* @param dest location to send the message
* @param payload body of the message to be sent (unencrypted)
* @return success
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size) throws I2PSessionException;
/**
* See I2PSessionMuxedImpl for proto/port details.
* @return success
* @since 0.7.1
*/
public boolean sendMessage(Destination dest, byte[] payload, int proto, int fromport, int toport) throws I2PSessionException;
/**
* End-to-End Crypto is disabled, tags and keys are ignored!
*
* Like sendMessage above, except the key used and the tags sent are exposed to the
* application. <p>
*
* If some application layer message delivery confirmation is used,
* rather than i2p's (slow) built in confirmation via guaranteed delivery mode, the
* application can update the SessionKeyManager, ala:
* <pre>
* SessionKeyManager.getInstance().tagsDelivered(dest.getPublicKey(), keyUsed, tagsSent);
* </pre>
* If an application is using guaranteed delivery mode, this is not useful, but for
* applications using best effort delivery mode, if they can know with certainty that a message
* was delivered and can update the SessionKeyManager appropriately, a significant performance
* boost will occur (subsequent message encryption and decryption will be done via AES and a SessionTag,
* rather than ElGamal+AES, which is 1000x slower).
*
* @param dest location to send the message
* @param payload body of the message to be sent (unencrypted)
* @param keyUsed UNUSED, IGNORED. Session key delivered to the destination for association with the tags sent. This is essentially
* an output parameter - keyUsed.getData() is ignored during this call, but after the call completes,
* it will be filled with the bytes of the session key delivered. Typically the key delivered is the
* same one as the key encrypted with, but not always. If this is null then the key data will not be
* exposed.
* @param tagsSent UNUSED, IGNORED. Set of tags delivered to the peer and associated with the keyUsed. This is also an output parameter -
* the contents of the set is ignored during the call, but afterwards it contains a set of SessionTag
* objects that were sent along side the given keyUsed.
* @return success
*/
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set<SessionTag> tagsSent) throws I2PSessionException;
/**
* End-to-End Crypto is disabled, tags and keys are ignored.
* @param keyUsed UNUSED, IGNORED.
* @param tagsSent UNUSED, IGNORED.
* @return success
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent) throws I2PSessionException;
/**
* End-to-End Crypto is disabled, tags and keys are ignored.
* @param keyUsed UNUSED, IGNORED.
* @param tagsSent UNUSED, IGNORED.
* @param expire absolute expiration timestamp, NOT interval from now
* @return success
* @since 0.7.1
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire) throws I2PSessionException;
/**
* See I2PSessionMuxedImpl for proto/port details.
* End-to-End Crypto is disabled, tags and keys are ignored.
* @param keyUsed UNUSED, IGNORED.
* @param tagsSent UNUSED, IGNORED.
* @param proto 1-254 or 0 for unset; recommended:
* I2PSession.PROTO_UNSPECIFIED
* I2PSession.PROTO_STREAMING
* I2PSession.PROTO_DATAGRAM
* 255 disallowed
* @param fromPort 1-65535 or 0 for unset
* @param toPort 1-65535 or 0 for unset
* @return success
* @since 0.7.1
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent,
int proto, int fromPort, int toPort) throws I2PSessionException;
/**
* See I2PSessionMuxedImpl for proto/port details.
* End-to-End Crypto is disabled, tags and keys are ignored.
* @param keyUsed UNUSED, IGNORED.
* @param tagsSent UNUSED, IGNORED.
* @param expire absolute expiration timestamp, NOT interval from now
* @param proto 1-254 or 0 for unset; recommended:
* I2PSession.PROTO_UNSPECIFIED
* I2PSession.PROTO_STREAMING
* I2PSession.PROTO_DATAGRAM
* 255 disallowed
* @param fromPort 1-65535 or 0 for unset
* @param toPort 1-65535 or 0 for unset
* @return success
* @since 0.7.1
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
int proto, int fromPort, int toPort) throws I2PSessionException;
/**
* See I2PSessionMuxedImpl for proto/port details.
* End-to-End Crypto is disabled, tags and keys are ignored.
* @param keyUsed UNUSED, IGNORED.
* @param tagsSent UNUSED, IGNORED.
* @param expire absolute expiration timestamp, NOT interval from now
* @param proto 1-254 or 0 for unset; recommended:
* I2PSession.PROTO_UNSPECIFIED
* I2PSession.PROTO_STREAMING
* I2PSession.PROTO_DATAGRAM
* 255 disallowed
* @param fromPort 1-65535 or 0 for unset
* @param toPort 1-65535 or 0 for unset
* @return success
* @since 0.8.4
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
int proto, int fromPort, int toPort, int flags) throws I2PSessionException;
/**
* See I2PSessionMuxedImpl for proto/port details.
* See SendMessageOptions for option details.
*
* @param proto 1-254 or 0 for unset; recommended:
* I2PSession.PROTO_UNSPECIFIED
* I2PSession.PROTO_STREAMING
* I2PSession.PROTO_DATAGRAM
* 255 disallowed
* @param fromPort 1-65535 or 0 for unset
* @param toPort 1-65535 or 0 for unset
* @param options to be passed to the router
* @return success
* @since 0.9.2
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
int proto, int fromPort, int toPort, SendMessageOptions options) throws I2PSessionException;
/**
* Send a message and request an asynchronous notification of delivery status.
* Notifications will be delivered at least up to the expiration specified in the options,
* or 60 seconds if not specified.
*
* See I2PSessionMuxedImpl for proto/port details.
* See SendMessageOptions for option details.
*
* @param proto 1-254 or 0 for unset; recommended:
* I2PSession.PROTO_UNSPECIFIED
* I2PSession.PROTO_STREAMING
* I2PSession.PROTO_DATAGRAM
* 255 disallowed
* @param fromPort 1-65535 or 0 for unset
* @param toPort 1-65535 or 0 for unset
* @param options to be passed to the router
* @return the message ID to be used for later notification to the listener
* @throws I2PSessionException on all errors
* @since 0.9.14
*/
public long sendMessage(Destination dest, byte[] payload, int offset, int size,
int proto, int fromPort, int toPort,
SendMessageOptions options, SendMessageStatusListener listener) throws I2PSessionException;
/** Receive a message that the router has notified the client about, returning
* the payload.
* This may only be called once for a given msgId (until the counter wraps)
*
* @param msgId message to fetch
* @return unencrypted body of the message, or null if not found
*/
public byte[] receiveMessage(int msgId) throws I2PSessionException;
/** Instruct the router that the message received was abusive (including how
* abusive on a 1-100 scale) in the hopes the router can do something to
* minimize receiving abusive messages like that in the future.
*
* Unused. Not fully implemented.
*
* @param msgId message that was abusive (or -1 for not message related)
* @param severity how abusive
*/
public void reportAbuse(int msgId, int severity) throws I2PSessionException;
/** Instruct the I2PSession where it should send event notifications
*
* WARNING: It is recommended that you use a method that specifies the protocol and ports.
*
* @param lsnr listener to retrieve events
*/
public void setSessionListener(I2PSessionListener lsnr);
/**
* Tear down the session and release any resources.
*
*/
public void destroySession() throws I2PSessionException;
/**
* @return a new subsession, non-null
* @param privateKeyStream null for transient, if non-null must have same encryption keys as primary session
* and different signing keys
* @param opts subsession options if any, may be null
* @since 0.9.21
*/
public I2PSession addSubsession(InputStream privateKeyStream, Properties opts) throws I2PSessionException;
/**
* @since 0.9.21
*/
public void removeSubsession(I2PSession session);
/**
* @return a list of subsessions, non-null, does not include the primary session
* @since 0.9.21
*/
public List<I2PSession> getSubsessions();
/**
* Actually connect the session and start receiving/sending messages.
* Connecting a primary session will not automatically connect subsessions.
* Connecting a subsession will automatically connect the primary session
* if not previously connected.
*/
public void connect() throws I2PSessionException;
/**
* Have we closed the session?
*
* @return true if the session is closed, OR connect() has not been called yet
*/
public boolean isClosed();
/**
* Retrieve the Destination this session serves as the endpoint for.
* Returns null if no destination is available.
*
*/
public Destination getMyDestination();
/**
* Retrieve the decryption PrivateKey associated with the Destination
*
*/
public PrivateKey getDecryptionKey();
/**
* Retrieve the signing SigningPrivateKey associated with the Destination
*/
public SigningPrivateKey getPrivateKey();
/**
* Lookup a Destination by Hash.
* Blocking. Waits a max of 10 seconds by default.
*/
public Destination lookupDest(Hash h) throws I2PSessionException;
/**
* Lookup a Destination by Hash.
* Blocking.
* @param maxWait ms
* @since 0.8.3
* @return null on failure
*/
public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException;
/**
* Ask the router to lookup a Destination by host name.
* Blocking. Waits a max of 10 seconds by default.
*
* This only makes sense for a b32 hostname, OR outside router context.
* Inside router context, just query the naming service.
* Outside router context, this does NOT query the context naming service.
* Do that first if you expect a local addressbook.
*
* This will log a warning for non-b32 in router context.
*
* Suggested implementation:
*
*<pre>
* if (name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
* if (session != null)
* return session.lookup(Hash.create(Base32.decode(name.toLowerCase(Locale.US).substring(0, 52))));
* else
* return ctx.namingService().lookup(name); // simple session for xxx.b32.i2p handled by naming service (optional if you need lookup w/o an existing session)
* } else if (ctx.isRouterContext()) {
* return ctx.namingService().lookup(name); // hostname from router's naming service
* } else {
* Destination d = ctx.namingService().lookup(name); // local naming svc, optional
* if (d != null)
* return d;
* if (session != null)
* return session.lookup(name);
* // simple session (optional if you need lookup w/o an existing session)
* Destination rv = null;
* I2PClient client = new I2PSimpleClient();
* Properties opts = new Properties();
* opts.put(I2PClient.PROP_TCP_HOST, host);
* opts.put(I2PClient.PROP_TCP_PORT, port);
* I2PSession session = null;
* try {
* session = client.createSession(null, opts);
* session.connect();
* rv = session.lookupDest(name);
* } finally {
* if (session != null)
* session.destroySession();
* }
* return rv;
* }
*</pre>
*
* Requires router side to be 0.9.11 or higher. If the router is older,
* this will return null immediately.
*
* @since 0.9.11
*/
public Destination lookupDest(String name) throws I2PSessionException;
/**
* Ask the router to lookup a Destination by host name.
* Blocking. See above for details.
* @param maxWait ms
* @since 0.9.11
* @return null on failure
*/
public Destination lookupDest(String name, long maxWait) throws I2PSessionException;
/**
* Pass updated options to the router.
* Does not remove properties previously present but missing from this options parameter.
* Fails silently if session is not connected.
*
* @param options non-null
* @since 0.8.4
*/
public void updateOptions(Properties options);
/**
* Get the current bandwidth limits. Blocking.
* @since 0.8.3
*/
public int[] bandwidthLimits() throws I2PSessionException;
/**
* Listen on specified protocol and port.
*
* An existing listener with the same proto and port is replaced.
* Only the listener with the best match is called back for each message.
*
* @param proto 1-254 or PROTO_ANY (0) for all; recommended:
* I2PSession.PROTO_STREAMING
* I2PSession.PROTO_DATAGRAM
* 255 disallowed
* @param port 1-65535 or PORT_ANY (0) for all
* @since 0.7.1
*/
public void addSessionListener(I2PSessionListener lsnr, int proto, int port);
/**
* Listen on specified protocol and port, and receive notification
* of proto, fromPort, and toPort for every message.
* @param proto 1-254 or PROTO_ANY (0) for all; 255 disallowed
* @param port 1-65535 or PORT_ANY (0) for all
* @since 0.7.1
*/
public void addMuxedSessionListener(I2PSessionMuxedListener l, int proto, int port);
/**
* removes the specified listener (only)
* @since 0.7.1
*/
public void removeListener(int proto, int port);
public static final int PORT_ANY = 0;
public static final int PORT_UNSPECIFIED = 0;
public static final int PROTO_ANY = 0;
public static final int PROTO_UNSPECIFIED = 0;
public static final int PROTO_STREAMING = 6;
/**
* Generally a signed datagram, but could
* also be a raw datagram, depending on the application
*/
public static final int PROTO_DATAGRAM = 17;
/**
* A raw (unsigned) datagram
* @since 0.9.2
*/
public static final int PROTO_DATAGRAM_RAW = 18;
}