* Added DATAGRAM supprt;
* refactoring of SAMRawSession.java, to make it derive from SAMMessageSession.java (parent class for SAMDatagramSession.java, too); * removed unuseful cruft; * some fixes; * M-x untabify. (human)
This commit is contained in:
32
apps/sam/java/src/net/i2p/sam/SAMDatagramReceiver.java
Normal file
32
apps/sam/java/src/net/i2p/sam/SAMDatagramReceiver.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
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 net.i2p.data.Destination;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for sending raw data to a SAM client
|
||||||
|
*/
|
||||||
|
public interface SAMDatagramReceiver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a byte array to a SAM client.
|
||||||
|
*
|
||||||
|
* @param data Byte array to be received
|
||||||
|
*/
|
||||||
|
public void receiveDatagramBytes(Destination sender, byte data[]) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop receiving data.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void stopDatagramReceiving();
|
||||||
|
}
|
111
apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java
Normal file
111
apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
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.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import net.i2p.client.datagram.I2PDatagramDissector;
|
||||||
|
import net.i2p.client.datagram.I2PDatagramMaker;
|
||||||
|
import net.i2p.client.datagram.I2PInvalidDatagramException;
|
||||||
|
import net.i2p.client.I2PSessionException;
|
||||||
|
import net.i2p.data.DataFormatException;
|
||||||
|
import net.i2p.data.Destination;
|
||||||
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SAM DATAGRAM session class.
|
||||||
|
*
|
||||||
|
* @author human
|
||||||
|
*/
|
||||||
|
public class SAMDatagramSession extends SAMMessageSession {
|
||||||
|
|
||||||
|
private final static Log _log = new Log(SAMDatagramSession.class);
|
||||||
|
|
||||||
|
private SAMDatagramReceiver recv = null;
|
||||||
|
|
||||||
|
private I2PDatagramMaker dgramMaker;
|
||||||
|
private 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
|
||||||
|
*/
|
||||||
|
public 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.
|
||||||
|
*
|
||||||
|
* @param destStream Input stream containing the destination keys
|
||||||
|
* @param props Properties to setup the I2P session
|
||||||
|
* @param recv Object that will receive incoming data
|
||||||
|
*/
|
||||||
|
public SAMDatagramSession(InputStream destStream, Properties props,
|
||||||
|
SAMDatagramReceiver recv) throws IOException, DataFormatException, I2PSessionException {
|
||||||
|
super(destStream, props);
|
||||||
|
|
||||||
|
this.recv = recv;
|
||||||
|
dgramMaker = new I2PDatagramMaker(getI2PSession());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send bytes through a SAM DATAGRAM session.
|
||||||
|
*
|
||||||
|
* @param data Bytes to be sent
|
||||||
|
*
|
||||||
|
* @return True if the data was sent, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean sendBytes(String dest, byte[] data) throws DataFormatException {
|
||||||
|
byte[] dgram = dgramMaker.makeI2PDatagram(data);
|
||||||
|
|
||||||
|
return sendBytesThroughMessageSession(dest, dgram);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void messageReceived(byte[] msg) {
|
||||||
|
byte[] payload;
|
||||||
|
Destination sender;
|
||||||
|
try {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} catch (I2PInvalidDatagramException e) {
|
||||||
|
if (_log.shouldLog(Log.DEBUG)) {
|
||||||
|
_log.debug("Dropping ill-signed I2P repliable datagram");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
recv.receiveDatagramBytes(sender, payload);
|
||||||
|
} catch (IOException e) {
|
||||||
|
_log.error("Error forwarding message to receiver", e);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void shutDown() {
|
||||||
|
recv.stopDatagramReceiving();
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ package net.i2p.sam;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
@ -29,20 +30,36 @@ public abstract class SAMHandler implements Runnable {
|
|||||||
protected I2PThread thread = null;
|
protected I2PThread thread = null;
|
||||||
|
|
||||||
private Object socketWLock = new Object(); // Guards writings on socket
|
private Object socketWLock = new Object(); // Guards writings on socket
|
||||||
|
private Socket socket = null;
|
||||||
private OutputStream socketOS = null; // Stream associated to socket
|
private OutputStream socketOS = null; // Stream associated to socket
|
||||||
protected Socket socket = null;
|
|
||||||
|
|
||||||
protected int verMajor = 0;
|
protected int verMajor = 0;
|
||||||
protected int verMinor = 0;
|
protected int verMinor = 0;
|
||||||
|
|
||||||
private boolean stopHandler = false;
|
|
||||||
private Object stopLock = new Object();
|
private Object stopLock = new Object();
|
||||||
|
private boolean stopHandler = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SAMHandler constructor (to be called by subclasses)
|
||||||
|
*
|
||||||
|
* @param s Socket attached to a SAM client
|
||||||
|
* @param verMajor SAM major version to manage
|
||||||
|
* @param verMinor SAM minor version to manage
|
||||||
|
*/
|
||||||
|
protected SAMHandler(Socket s,
|
||||||
|
int verMajor, int verMinor) throws IOException {
|
||||||
|
socket = s;
|
||||||
|
socketOS = socket.getOutputStream();
|
||||||
|
|
||||||
|
this.verMajor = verMajor;
|
||||||
|
this.verMinor = verMinor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start handling the SAM connection, detaching an handling thread.
|
* Start handling the SAM connection, detaching an handling thread.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void startHandling() {
|
public final void startHandling() {
|
||||||
thread = new I2PThread(this, "SAMHandler");
|
thread = new I2PThread(this, "SAMHandler");
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
@ -53,6 +70,14 @@ public abstract class SAMHandler implements Runnable {
|
|||||||
*/
|
*/
|
||||||
protected abstract void handle();
|
protected abstract void handle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the input stream of the socket connected to the SAM client
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected final InputStream getClientSocketInputStream() throws IOException {
|
||||||
|
return socket.getInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a byte array on the handler's socket. This method must
|
* Write a byte array on the handler's socket. This method must
|
||||||
* always be used when writing data, unless you really know what
|
* always be used when writing data, unless you really know what
|
||||||
@ -60,11 +85,8 @@ public abstract class SAMHandler implements Runnable {
|
|||||||
*
|
*
|
||||||
* @param data A byte array to be written
|
* @param data A byte array to be written
|
||||||
*/
|
*/
|
||||||
protected void writeBytes(byte[] data) throws IOException {
|
protected final void writeBytes(byte[] data) throws IOException {
|
||||||
synchronized (socketWLock) {
|
synchronized (socketWLock) {
|
||||||
if (socketOS == null) {
|
|
||||||
socketOS = socket.getOutputStream();
|
|
||||||
}
|
|
||||||
socketOS.write(data);
|
socketOS.write(data);
|
||||||
socketOS.flush();
|
socketOS.flush();
|
||||||
}
|
}
|
||||||
@ -79,7 +101,7 @@ public abstract class SAMHandler implements Runnable {
|
|||||||
*
|
*
|
||||||
* @return True is the string was successfully written, false otherwise
|
* @return True is the string was successfully written, false otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean writeString(String str) {
|
protected final boolean writeString(String str) {
|
||||||
try {
|
try {
|
||||||
writeBytes(str.getBytes("ISO-8859-1"));
|
writeBytes(str.getBytes("ISO-8859-1"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -90,11 +112,19 @@ public abstract class SAMHandler implements Runnable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the socket connected to the SAM client.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected final void closeClientSocket() throws IOException {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the SAM handler
|
* Stop the SAM handler
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void stopHandling() {
|
public final void stopHandling() {
|
||||||
synchronized (stopLock) {
|
synchronized (stopLock) {
|
||||||
stopHandler = true;
|
stopHandler = true;
|
||||||
}
|
}
|
||||||
@ -105,7 +135,7 @@ public abstract class SAMHandler implements Runnable {
|
|||||||
*
|
*
|
||||||
* @return True if the handler should be stopped, false otherwise
|
* @return True if the handler should be stopped, false otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean shouldStop() {
|
protected final boolean shouldStop() {
|
||||||
synchronized (stopLock) {
|
synchronized (stopLock) {
|
||||||
return stopHandler;
|
return stopHandler;
|
||||||
}
|
}
|
||||||
@ -116,7 +146,13 @@ public abstract class SAMHandler implements Runnable {
|
|||||||
*
|
*
|
||||||
* @return A String describing the handler;
|
* @return A String describing the handler;
|
||||||
*/
|
*/
|
||||||
public abstract String toString();
|
public final String toString() {
|
||||||
|
return ("SAM handler (class: " + this.getClass().getName()
|
||||||
|
+ "; SAM version: " + verMajor + "." + verMinor
|
||||||
|
+ "; client: "
|
||||||
|
+ this.socket.getInetAddress().toString() + ":"
|
||||||
|
+ this.socket.getPort() + ")");
|
||||||
|
}
|
||||||
|
|
||||||
public final void run() {
|
public final void run() {
|
||||||
handle();
|
handle();
|
||||||
|
@ -36,18 +36,23 @@ public class SAMHandlerFactory {
|
|||||||
*/
|
*/
|
||||||
public static SAMHandler createSAMHandler(Socket s) throws SAMException {
|
public static SAMHandler createSAMHandler(Socket s) throws SAMException {
|
||||||
BufferedReader br;
|
BufferedReader br;
|
||||||
|
String line;
|
||||||
StringTokenizer tok;
|
StringTokenizer tok;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
br = new BufferedReader(new InputStreamReader(s.getInputStream(),
|
br = new BufferedReader(new InputStreamReader(s.getInputStream(),
|
||||||
"ISO-8859-1"));
|
"ISO-8859-1"));
|
||||||
tok = new StringTokenizer(br.readLine(), " ");
|
line = br.readLine();
|
||||||
|
if (line == null) {
|
||||||
|
_log.debug("Connection closed by client");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
tok = new StringTokenizer(line, " ");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new SAMException("Error reading from socket: "
|
throw new SAMException("Error reading from socket: "
|
||||||
+ e.getMessage());
|
+ e.getMessage());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new SAMException("Unexpected error: "
|
throw new SAMException("Unexpected error: " + e.getMessage());
|
||||||
+ e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message format: HELLO VERSION MIN=v1 MAX=v2
|
// Message format: HELLO VERSION MIN=v1 MAX=v2
|
||||||
@ -118,15 +123,20 @@ public class SAMHandlerFactory {
|
|||||||
int verMajor = getMajor(ver);
|
int verMajor = getMajor(ver);
|
||||||
int verMinor = getMinor(ver);
|
int verMinor = getMinor(ver);
|
||||||
SAMHandler handler;
|
SAMHandler handler;
|
||||||
|
|
||||||
|
try {
|
||||||
switch (verMajor) {
|
switch (verMajor) {
|
||||||
case 1:
|
case 1:
|
||||||
handler = new SAMv1Handler(s, verMajor, verMinor);
|
handler = new SAMv1Handler(s, verMajor, verMinor);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_log.error("BUG! Trying to initialize the wrong SAM version!");
|
_log.error("BUG! Trying to initialize the wrong SAM version!");
|
||||||
throw new SAMException("BUG triggered! (handler instantiation)");
|
throw new SAMException("BUG! (in handler instantiation)");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
_log.error("IOException caught during SAM handler instantiation");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
246
apps/sam/java/src/net/i2p/sam/SAMMessageSession.java
Normal file
246
apps/sam/java/src/net/i2p/sam/SAMMessageSession.java
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
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.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import net.i2p.client.I2PClient;
|
||||||
|
import net.i2p.client.I2PClientFactory;
|
||||||
|
import net.i2p.client.I2PSession;
|
||||||
|
import net.i2p.client.I2PSessionException;
|
||||||
|
import net.i2p.client.I2PSessionListener;
|
||||||
|
import net.i2p.data.Base64;
|
||||||
|
import net.i2p.data.DataFormatException;
|
||||||
|
import net.i2p.data.Destination;
|
||||||
|
import net.i2p.util.HexDump;
|
||||||
|
import net.i2p.util.I2PThread;
|
||||||
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base abstract class for SAM message-based sessions.
|
||||||
|
*
|
||||||
|
* @author human
|
||||||
|
*/
|
||||||
|
public abstract class SAMMessageSession {
|
||||||
|
|
||||||
|
private final static Log _log = new Log(SAMMessageSession.class);
|
||||||
|
|
||||||
|
private I2PSession session = null;
|
||||||
|
|
||||||
|
private SAMMessageSessionHandler handler = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new SAM message-based session.
|
||||||
|
*
|
||||||
|
* @param dest Base64-encoded destination (private key)
|
||||||
|
* @param props Properties to setup the I2P session
|
||||||
|
*/
|
||||||
|
protected SAMMessageSession(String dest, Properties props) throws IOException, DataFormatException, I2PSessionException {
|
||||||
|
ByteArrayInputStream bais;
|
||||||
|
|
||||||
|
bais = new ByteArrayInputStream(Base64.decode(dest));
|
||||||
|
|
||||||
|
initSAMMessageSession(bais, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new SAM message-based session.
|
||||||
|
*
|
||||||
|
* @param destStream Input stream containing the destination keys
|
||||||
|
* @param props Properties to setup the I2P session
|
||||||
|
*/
|
||||||
|
protected SAMMessageSession(InputStream destStream, Properties props) throws IOException, DataFormatException, I2PSessionException {
|
||||||
|
initSAMMessageSession(destStream, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initSAMMessageSession (InputStream destStream, Properties props) throws IOException, DataFormatException, I2PSessionException {
|
||||||
|
|
||||||
|
_log.debug("Initializing SAM message-based session");
|
||||||
|
|
||||||
|
handler = new SAMMessageSessionHandler(destStream, props);
|
||||||
|
|
||||||
|
Thread t = new I2PThread(handler, "SAMMessageSessionHandler");
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the SAM message-based session Destination.
|
||||||
|
*
|
||||||
|
* @return The SAM message-based session Destination.
|
||||||
|
*/
|
||||||
|
public Destination getDestination() {
|
||||||
|
return session.getMyDestination();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send bytes through a SAM message-based session.
|
||||||
|
*
|
||||||
|
* @param data Bytes to be sent
|
||||||
|
*
|
||||||
|
* @return True if the data was sent, false otherwise
|
||||||
|
*/
|
||||||
|
public abstract boolean sendBytes(String dest, byte[] data) throws DataFormatException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actually send bytes through the SAM message-based session I2PSession
|
||||||
|
* (er...).
|
||||||
|
*
|
||||||
|
* @param data Bytes to be sent
|
||||||
|
*
|
||||||
|
* @return True if the data was sent, false otherwise
|
||||||
|
*/
|
||||||
|
protected boolean sendBytesThroughMessageSession(String dest, byte[] data) throws DataFormatException {
|
||||||
|
Destination d = new Destination();
|
||||||
|
d.fromBase64(dest);
|
||||||
|
|
||||||
|
if (_log.shouldLog(Log.DEBUG)) {
|
||||||
|
_log.debug("Sending " + data.length + " bytes to " + dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return session.sendMessage(d, data);
|
||||||
|
} catch (I2PSessionException e) {
|
||||||
|
_log.error("I2PSessionException while sending data", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a SAM message-based session.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void close() {
|
||||||
|
handler.stopRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a new received message
|
||||||
|
*/
|
||||||
|
protected abstract void messageReceived(byte[] msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do whatever is needed to shutdown the SAM session
|
||||||
|
*/
|
||||||
|
protected abstract void shutDown();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the I2PSession object used by the SAM message-based session.
|
||||||
|
*
|
||||||
|
* @return The I2PSession of the SAM message-based session
|
||||||
|
*/
|
||||||
|
protected I2PSession getI2PSession() {
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SAM message-based session handler, running in its own thread
|
||||||
|
*
|
||||||
|
* @author human
|
||||||
|
*/
|
||||||
|
public class SAMMessageSessionHandler implements Runnable, I2PSessionListener {
|
||||||
|
|
||||||
|
private Object runningLock = new Object();
|
||||||
|
private boolean stillRunning = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new SAM message-based session handler
|
||||||
|
*
|
||||||
|
* @param destStream Input stream containing the destination keys
|
||||||
|
* @param props Properties to setup the I2P session
|
||||||
|
*/
|
||||||
|
public SAMMessageSessionHandler(InputStream destStream, Properties props) throws I2PSessionException {
|
||||||
|
_log.debug("Instantiating new SAM message-based session handler");
|
||||||
|
|
||||||
|
I2PClient client = I2PClientFactory.createClient();
|
||||||
|
session = client.createSession(destStream, props);
|
||||||
|
|
||||||
|
_log.debug("Connecting I2P session...");
|
||||||
|
session.connect();
|
||||||
|
_log.debug("I2P session connected");
|
||||||
|
|
||||||
|
session.setSessionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop a SAM message-based session handling thread
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final void stopRunning() {
|
||||||
|
synchronized (runningLock) {
|
||||||
|
stillRunning = false;
|
||||||
|
runningLock.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
_log.debug("SAM message-based session handler running");
|
||||||
|
|
||||||
|
synchronized (runningLock) {
|
||||||
|
while (stillRunning) {
|
||||||
|
try {
|
||||||
|
runningLock.wait();
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.debug("Shutting down SAM message-based session handler");
|
||||||
|
|
||||||
|
shutDown();
|
||||||
|
|
||||||
|
try {
|
||||||
|
_log.debug("Destroying I2P session...");
|
||||||
|
session.destroySession();
|
||||||
|
_log.debug("I2P session destroyed");
|
||||||
|
} catch (I2PSessionException e) {
|
||||||
|
_log.error("Error destroying I2P session", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnected(I2PSession session) {
|
||||||
|
_log.debug("I2P session disconnected");
|
||||||
|
stopRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void errorOccurred(I2PSession session, String message,
|
||||||
|
Throwable error) {
|
||||||
|
_log.debug("I2P error: " + message, error);
|
||||||
|
stopRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void messageAvailable(I2PSession session, int msgId, long size){
|
||||||
|
if (_log.shouldLog(Log.DEBUG)) {
|
||||||
|
_log.debug("I2P message available (id: " + msgId
|
||||||
|
+ "; size: " + size + ")");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
byte msg[] = session.receiveMessage(msgId);
|
||||||
|
if (_log.shouldLog(Log.DEBUG)) {
|
||||||
|
_log.debug("Content of message " + msgId + ":\n"
|
||||||
|
+ HexDump.dump(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
messageReceived(msg);
|
||||||
|
} catch (I2PSessionException e) {
|
||||||
|
_log.error("Error fetching I2P message", e);
|
||||||
|
stopRunning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportAbuse(I2PSession session, int severity) {
|
||||||
|
_log.warn("Abuse reported (severity: " + severity + ")");
|
||||||
|
stopRunning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,16 +14,8 @@ import java.io.InputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import net.i2p.client.I2PClient;
|
|
||||||
import net.i2p.client.I2PClientFactory;
|
|
||||||
import net.i2p.client.I2PSession;
|
|
||||||
import net.i2p.client.I2PSessionException;
|
import net.i2p.client.I2PSessionException;
|
||||||
import net.i2p.client.I2PSessionListener;
|
|
||||||
import net.i2p.data.Base64;
|
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
import net.i2p.data.Destination;
|
|
||||||
import net.i2p.util.HexDump;
|
|
||||||
import net.i2p.util.I2PThread;
|
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,16 +23,11 @@ import net.i2p.util.Log;
|
|||||||
*
|
*
|
||||||
* @author human
|
* @author human
|
||||||
*/
|
*/
|
||||||
public class SAMRawSession {
|
public class SAMRawSession extends SAMMessageSession {
|
||||||
|
|
||||||
private final static Log _log = new Log(SAMRawSession.class);
|
private final static Log _log = new Log(SAMRawSession.class);
|
||||||
|
|
||||||
private I2PSession session = null;
|
|
||||||
|
|
||||||
private SAMRawReceiver recv = null;
|
private SAMRawReceiver recv = null;
|
||||||
|
|
||||||
private SAMRawSessionHandler handler = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new SAM RAW session.
|
* Create a new SAM RAW session.
|
||||||
*
|
*
|
||||||
@ -50,11 +37,9 @@ public class SAMRawSession {
|
|||||||
*/
|
*/
|
||||||
public SAMRawSession(String dest, Properties props,
|
public SAMRawSession(String dest, Properties props,
|
||||||
SAMRawReceiver recv) throws IOException, DataFormatException, I2PSessionException {
|
SAMRawReceiver recv) throws IOException, DataFormatException, I2PSessionException {
|
||||||
ByteArrayInputStream bais;
|
super(dest, props);
|
||||||
|
|
||||||
bais = new ByteArrayInputStream(Base64.decode(dest));
|
this.recv = recv;
|
||||||
|
|
||||||
initSAMRawSession(bais, props, recv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,28 +51,9 @@ public class SAMRawSession {
|
|||||||
*/
|
*/
|
||||||
public SAMRawSession(InputStream destStream, Properties props,
|
public SAMRawSession(InputStream destStream, Properties props,
|
||||||
SAMRawReceiver recv) throws IOException, DataFormatException, I2PSessionException {
|
SAMRawReceiver recv) throws IOException, DataFormatException, I2PSessionException {
|
||||||
initSAMRawSession(destStream, props, recv);
|
super(destStream, props);
|
||||||
}
|
|
||||||
|
|
||||||
private void initSAMRawSession(InputStream destStream, Properties props,
|
|
||||||
SAMRawReceiver recv) throws IOException, DataFormatException, I2PSessionException {
|
|
||||||
this.recv = recv;
|
this.recv = recv;
|
||||||
|
|
||||||
_log.debug("SAM RAW session instantiated");
|
|
||||||
|
|
||||||
handler = new SAMRawSessionHandler(destStream, props);
|
|
||||||
|
|
||||||
Thread t = new I2PThread(handler, "SAMRawSessionHandler");
|
|
||||||
t.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the SAM RAW session Destination.
|
|
||||||
*
|
|
||||||
* @return The SAM RAW session Destination.
|
|
||||||
*/
|
|
||||||
public Destination getDestination() {
|
|
||||||
return session.getMyDestination();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,130 +64,19 @@ public class SAMRawSession {
|
|||||||
* @return True if the data was sent, false otherwise
|
* @return True if the data was sent, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean sendBytes(String dest, byte[] data) throws DataFormatException {
|
public boolean sendBytes(String dest, byte[] data) throws DataFormatException {
|
||||||
Destination d = new Destination();
|
return sendBytesThroughMessageSession(dest, data);
|
||||||
d.fromBase64(dest);
|
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG)) {
|
|
||||||
_log.debug("Sending " + data.length + " bytes to " + dest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void messageReceived(byte[] msg) {
|
||||||
try {
|
try {
|
||||||
return session.sendMessage(d, data);
|
|
||||||
} catch (I2PSessionException e) {
|
|
||||||
_log.error("I2PSessionException while sending data", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close a SAM RAW session.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void close() {
|
|
||||||
handler.stopRunning();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SAM RAW session handler, running in its own thread
|
|
||||||
*
|
|
||||||
* @author human
|
|
||||||
*/
|
|
||||||
public class SAMRawSessionHandler implements Runnable, I2PSessionListener {
|
|
||||||
|
|
||||||
private Object runningLock = new Object();
|
|
||||||
private boolean stillRunning = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new SAM RAW session handler
|
|
||||||
*
|
|
||||||
* @param destStream Input stream containing the destination keys
|
|
||||||
* @param props Properties to setup the I2P session
|
|
||||||
*/
|
|
||||||
public SAMRawSessionHandler(InputStream destStream, Properties props) throws I2PSessionException {
|
|
||||||
_log.debug("Instantiating new SAM RAW session handler");
|
|
||||||
|
|
||||||
I2PClient client = I2PClientFactory.createClient();
|
|
||||||
session = client.createSession(destStream, props);
|
|
||||||
|
|
||||||
_log.debug("Connecting I2P session...");
|
|
||||||
session.connect();
|
|
||||||
_log.debug("I2P session connected");
|
|
||||||
|
|
||||||
session.setSessionListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop a SAM RAW session handling thread
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void stopRunning() {
|
|
||||||
synchronized (runningLock) {
|
|
||||||
stillRunning = false;
|
|
||||||
runningLock.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
_log.debug("SAM RAW session handler running");
|
|
||||||
|
|
||||||
synchronized (runningLock) {
|
|
||||||
while (stillRunning) {
|
|
||||||
try {
|
|
||||||
runningLock.wait();
|
|
||||||
} catch (InterruptedException ie) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_log.debug("Shutting down SAM RAW session handler");
|
|
||||||
|
|
||||||
recv.stopRawReceiving();
|
|
||||||
|
|
||||||
try {
|
|
||||||
_log.debug("Destroying I2P session...");
|
|
||||||
session.destroySession();
|
|
||||||
_log.debug("I2P session destroyed");
|
|
||||||
} catch (I2PSessionException e) {
|
|
||||||
_log.error("Error destroying I2P session", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnected(I2PSession session) {
|
|
||||||
_log.debug("I2P session disconnected");
|
|
||||||
stopRunning();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void errorOccurred(I2PSession session, String message,
|
|
||||||
Throwable error) {
|
|
||||||
_log.debug("I2P error: " + message, error);
|
|
||||||
stopRunning();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void messageAvailable(I2PSession session, int msgId, long size){
|
|
||||||
_log.debug("I2P message available (id: " + msgId
|
|
||||||
+ "; size: " + size + ")");
|
|
||||||
try {
|
|
||||||
byte msg[] = session.receiveMessage(msgId);
|
|
||||||
if (_log.shouldLog(Log.DEBUG)) {
|
|
||||||
_log.debug("Content of message " + msgId + ":\n"
|
|
||||||
+ HexDump.dump(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
recv.receiveRawBytes(msg);
|
recv.receiveRawBytes(msg);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
_log.error("Error forwarding message to receiver", e);
|
_log.error("Error forwarding message to receiver", e);
|
||||||
stopRunning();
|
close();
|
||||||
} catch (I2PSessionException e) {
|
}
|
||||||
_log.error("Error fetching I2P message", e);
|
|
||||||
stopRunning();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
protected void shutDown() {
|
||||||
|
recv.stopRawReceiving();
|
||||||
public void reportAbuse(I2PSession session, int severity) {
|
|
||||||
_log.warn("Abuse reported (severity: " + severity + ")");
|
|
||||||
stopRunning();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,28 +57,6 @@ public class SAMUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Base64 representation of a Destination public key
|
|
||||||
*
|
|
||||||
* @param d A Destination
|
|
||||||
*
|
|
||||||
* @return A String representing the Destination public key
|
|
||||||
*/
|
|
||||||
public static String getBase64DestinationPubKey(Destination d) {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
try {
|
|
||||||
d.writeBytes(baos);
|
|
||||||
return Base64.encode(baos.toByteArray());
|
|
||||||
} catch (IOException e) {
|
|
||||||
_log.error("getDestinationPubKey(): caught IOException", e);
|
|
||||||
return null;
|
|
||||||
} catch (DataFormatException e) {
|
|
||||||
_log.error("getDestinationPubKey(): caught DataFormatException",e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether a base64-encoded dest is valid
|
* Check whether a base64-encoded dest is valid
|
||||||
*
|
*
|
||||||
|
@ -33,14 +33,14 @@ import net.i2p.util.Log;
|
|||||||
*
|
*
|
||||||
* @author human
|
* @author human
|
||||||
*/
|
*/
|
||||||
public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStreamReceiver {
|
public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramReceiver, SAMStreamReceiver {
|
||||||
|
|
||||||
private final static Log _log = new Log(SAMv1Handler.class);
|
private final static Log _log = new Log(SAMv1Handler.class);
|
||||||
|
|
||||||
private final static int IN_BUFSIZE = 2048;
|
private final static int IN_BUFSIZE = 2048;
|
||||||
|
|
||||||
private SAMRawSession rawSession = null;
|
private SAMRawSession rawSession = null;
|
||||||
private SAMRawSession datagramSession = null;
|
private SAMDatagramSession datagramSession = null;
|
||||||
private SAMStreamSession streamSession = null;
|
private SAMStreamSession streamSession = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,20 +49,16 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
* stripped) from the socket input stream.
|
* stripped) from the socket input stream.
|
||||||
*
|
*
|
||||||
* @param s Socket attached to a SAM client
|
* @param s Socket attached to a SAM client
|
||||||
|
* @param verMajor SAM major version to manage (should be 1)
|
||||||
|
* @param verMinor SAM minor version to manage
|
||||||
*/
|
*/
|
||||||
public SAMv1Handler(Socket s, int verMajor, int verMinor) throws SAMException{
|
public SAMv1Handler(Socket s, int verMajor, int verMinor) throws SAMException, IOException {
|
||||||
|
super(s, verMajor, verMinor);
|
||||||
_log.debug("SAM version 1 handler instantiated");
|
_log.debug("SAM version 1 handler instantiated");
|
||||||
|
|
||||||
this.verMajor = verMajor;
|
|
||||||
this.verMinor = verMinor;
|
|
||||||
|
|
||||||
if ((this.verMajor != 1) || (this.verMinor != 0)) {
|
if ((this.verMajor != 1) || (this.verMinor != 0)) {
|
||||||
throw new SAMException("BUG! Wrong protocol version!");
|
throw new SAMException("BUG! Wrong protocol version!");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.socket = s;
|
|
||||||
this.verMajor = verMajor;
|
|
||||||
this.verMinor = verMinor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handle() {
|
public void handle() {
|
||||||
@ -76,7 +72,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
_log.debug("SAM handling started");
|
_log.debug("SAM handling started");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
InputStream in = socket.getInputStream();
|
InputStream in = getClientSocketInputStream();
|
||||||
int b = -1;
|
int b = -1;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -118,6 +114,8 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
|
|
||||||
if (domain.equals("STREAM")) {
|
if (domain.equals("STREAM")) {
|
||||||
canContinue = execStreamMessage(opcode, props);
|
canContinue = execStreamMessage(opcode, props);
|
||||||
|
} else if (domain.equals("DATAGRAM")) {
|
||||||
|
canContinue = execDatagramMessage(opcode, props);
|
||||||
} else if (domain.equals("RAW")) {
|
} else if (domain.equals("RAW")) {
|
||||||
canContinue = execRawMessage(opcode, props);
|
canContinue = execRawMessage(opcode, props);
|
||||||
} else if (domain.equals("SESSION")) {
|
} else if (domain.equals("SESSION")) {
|
||||||
@ -147,7 +145,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
} finally {
|
} finally {
|
||||||
_log.debug("Stopping handler");
|
_log.debug("Stopping handler");
|
||||||
try {
|
try {
|
||||||
this.socket.close();
|
closeClientSocket();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
_log.error("Error closing socket: " + e.getMessage());
|
_log.error("Error closing socket: " + e.getMessage());
|
||||||
}
|
}
|
||||||
@ -204,6 +202,8 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
|
|
||||||
if (style.equals("RAW")) {
|
if (style.equals("RAW")) {
|
||||||
rawSession = new SAMRawSession(dest, props, this);
|
rawSession = new SAMRawSession(dest, props, this);
|
||||||
|
} else if (style.equals("DATAGRAM")) {
|
||||||
|
datagramSession = new SAMDatagramSession(dest, props,this);
|
||||||
} else if (style.equals("STREAM")) {
|
} else if (style.equals("STREAM")) {
|
||||||
String dir = props.getProperty("DIRECTION");
|
String dir = props.getProperty("DIRECTION");
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
@ -305,7 +305,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
|
|
||||||
return writeString("NAMING REPLY RESULT=OK NAME=" + name
|
return writeString("NAMING REPLY RESULT=OK NAME=" + name
|
||||||
+ " VALUE="
|
+ " VALUE="
|
||||||
+ SAMUtils.getBase64DestinationPubKey(dest)
|
+ dest.toBase64()
|
||||||
+ "\n");
|
+ "\n");
|
||||||
} else {
|
} else {
|
||||||
_log.debug("Unrecognized NAMING message opcode: \""
|
_log.debug("Unrecognized NAMING message opcode: \""
|
||||||
@ -314,10 +314,82 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse and execute a DATAGRAM message */
|
||||||
|
private boolean execDatagramMessage(String opcode, Properties props) {
|
||||||
|
if (datagramSession == null) {
|
||||||
|
_log.error("DATAGRAM message received, but no DATAGRAM session exists");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opcode.equals("SEND")) {
|
||||||
|
if (props == null) {
|
||||||
|
_log.debug("No parameters specified in DATAGRAM SEND message");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String dest = props.getProperty("DESTINATION");
|
||||||
|
if (dest == null) {
|
||||||
|
_log.debug("Destination not specified in DATAGRAM SEND message");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size;
|
||||||
|
{
|
||||||
|
String strsize = props.getProperty("SIZE");
|
||||||
|
if (strsize == null) {
|
||||||
|
_log.debug("Size not specified in DATAGRAM SEND message");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
size = Integer.parseInt(strsize);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
_log.debug("Invalid DATAGRAM SEND size specified: " + strsize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!checkDatagramSize(size)) {
|
||||||
|
_log.debug("Specified size (" + size
|
||||||
|
+ ") is out of protocol limits");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DataInputStream in = new DataInputStream(getClientSocketInputStream());
|
||||||
|
byte[] data = new byte[size];
|
||||||
|
|
||||||
|
in.readFully(data);
|
||||||
|
|
||||||
|
if (!datagramSession.sendBytes(dest, data)) {
|
||||||
|
_log.error("DATAGRAM SEND failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (EOFException e) {
|
||||||
|
_log.debug("Too few bytes with DATAGRAM SEND message (expected: "
|
||||||
|
+ size);
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
_log.debug("Caught IOException while parsing DATAGRAM SEND message",
|
||||||
|
e);
|
||||||
|
return false;
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
_log.debug("Invalid key specified with DATAGRAM SEND message",
|
||||||
|
e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_log.debug("Unrecognized DATAGRAM message opcode: \""
|
||||||
|
+ opcode + "\"");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse and execute a RAW message */
|
/* Parse and execute a RAW message */
|
||||||
private boolean execRawMessage(String opcode, Properties props) {
|
private boolean execRawMessage(String opcode, Properties props) {
|
||||||
if (rawSession == null) {
|
if (rawSession == null) {
|
||||||
_log.debug("RAW message received, but no RAW session exists");
|
_log.error("RAW message received, but no RAW session exists");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +426,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DataInputStream in = new DataInputStream(socket.getInputStream());
|
DataInputStream in = new DataInputStream(getClientSocketInputStream());
|
||||||
byte[] data = new byte[size];
|
byte[] data = new byte[size];
|
||||||
|
|
||||||
in.readFully(data);
|
in.readFully(data);
|
||||||
@ -388,7 +460,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
/* Parse and execute a STREAM message */
|
/* Parse and execute a STREAM message */
|
||||||
private boolean execStreamMessage(String opcode, Properties props) {
|
private boolean execStreamMessage(String opcode, Properties props) {
|
||||||
if (streamSession == null) {
|
if (streamSession == null) {
|
||||||
_log.debug("STREAM message received, but no STREAM session exists");
|
_log.error("STREAM message received, but no STREAM session exists");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +506,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DataInputStream in = new DataInputStream(socket.getInputStream());
|
DataInputStream in = new DataInputStream(getClientSocketInputStream());
|
||||||
byte[] data = new byte[size];
|
byte[] data = new byte[size];
|
||||||
|
|
||||||
in.readFully(data);
|
in.readFully(data);
|
||||||
@ -535,17 +607,16 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "SAM v1 handler (client: "
|
|
||||||
+ this.socket.getInetAddress().toString() + ":"
|
|
||||||
+ this.socket.getPort() + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check whether a size is inside the limits allowed by this protocol */
|
/* Check whether a size is inside the limits allowed by this protocol */
|
||||||
private boolean checkSize(int size) {
|
private boolean checkSize(int size) {
|
||||||
return ((size >= 1) && (size <= 32768));
|
return ((size >= 1) && (size <= 32768));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check whether a size is inside the limits allowed by this protocol */
|
||||||
|
private boolean checkDatagramSize(int size) {
|
||||||
|
return ((size >= 1) && (size <= 31744));
|
||||||
|
}
|
||||||
|
|
||||||
// SAMRawReceiver implementation
|
// SAMRawReceiver implementation
|
||||||
public void receiveRawBytes(byte data[]) throws IOException {
|
public void receiveRawBytes(byte data[]) throws IOException {
|
||||||
if (rawSession == null) {
|
if (rawSession == null) {
|
||||||
@ -571,7 +642,39 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.socket.close();
|
closeClientSocket();
|
||||||
|
} catch (IOException e) {
|
||||||
|
_log.error("Error closing socket: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAMDatagramReceiver implementation
|
||||||
|
public void receiveDatagramBytes(Destination sender, byte data[]) throws IOException {
|
||||||
|
if (datagramSession == null) {
|
||||||
|
_log.error("BUG! Received datagram bytes, but session is null!");
|
||||||
|
throw new NullPointerException("BUG! DATAGRAM session is null!");
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayOutputStream msg = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
msg.write(("DATAGRAM RECEIVED DESTINATION=" + sender.toBase64()
|
||||||
|
+ " SIZE=" + data.length
|
||||||
|
+ "\n").getBytes("ISO-8859-1"));
|
||||||
|
msg.write(data);
|
||||||
|
|
||||||
|
writeBytes(msg.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopDatagramReceiving() {
|
||||||
|
_log.debug("stopDatagramReceiving() invoked");
|
||||||
|
|
||||||
|
if (datagramSession == null) {
|
||||||
|
_log.error("BUG! Got datagram receiving stop, but session is null!");
|
||||||
|
throw new NullPointerException("BUG! DATAGRAM session is null!");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
closeClientSocket();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
_log.error("Error closing socket: " + e.getMessage());
|
_log.error("Error closing socket: " + e.getMessage());
|
||||||
}
|
}
|
||||||
@ -585,7 +688,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!writeString("STREAM CONNECTED DESTINATION="
|
if (!writeString("STREAM CONNECTED DESTINATION="
|
||||||
+ SAMUtils.getBase64DestinationPubKey(d)
|
+ d.toBase64()
|
||||||
+ " ID=" + id + "\n")) {
|
+ " ID=" + id + "\n")) {
|
||||||
throw new IOException("Error notifying connection to SAM client");
|
throw new IOException("Error notifying connection to SAM client");
|
||||||
}
|
}
|
||||||
@ -629,7 +732,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMStrea
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.socket.close();
|
closeClientSocket();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
_log.error("Error closing socket: " + e.getMessage());
|
_log.error("Error closing socket: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user