forked from I2P_Developers/i2p.i2p
format (shendaras)
This commit is contained in:
@ -6,154 +6,152 @@ public class ByteCollector {
|
|||||||
int size;
|
int size;
|
||||||
|
|
||||||
public ByteCollector() {
|
public ByteCollector() {
|
||||||
contents=new byte[80];
|
contents = new byte[80];
|
||||||
size=0;
|
size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteCollector(byte[] b) {
|
public ByteCollector(byte[] b) {
|
||||||
this();
|
this();
|
||||||
append(b);
|
append(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteCollector(byte b) {
|
public ByteCollector(byte b) {
|
||||||
this();
|
this();
|
||||||
append(b);
|
append(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteCollector append (byte b) {
|
public ByteCollector append(byte b) {
|
||||||
ensureCapacity(size+1);
|
ensureCapacity(size + 1);
|
||||||
contents[size++]=b;
|
contents[size++] = b;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteCollector append (byte[] b) {
|
public ByteCollector append(byte[] b) {
|
||||||
ensureCapacity(size+b.length);
|
ensureCapacity(size + b.length);
|
||||||
System.arraycopy(b,0,contents,size,b.length);
|
System.arraycopy(b, 0, contents, size, b.length);
|
||||||
size+=b.length;
|
size += b.length;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteCollector append(byte[] b, int len) {
|
public ByteCollector append(byte[] b, int len) {
|
||||||
return append(b,0,len);
|
return append(b, 0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteCollector append(byte[] b, int off, int len) {
|
public ByteCollector append(byte[] b, int off, int len) {
|
||||||
ensureCapacity(size+len);
|
ensureCapacity(size + len);
|
||||||
System.arraycopy(b,off,contents,size,len);
|
System.arraycopy(b, off, contents, size, len);
|
||||||
size+=len;
|
size += len;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteCollector append(ByteCollector bc) {
|
public ByteCollector append(ByteCollector bc) {
|
||||||
// optimieren?
|
// optimieren?
|
||||||
return append(bc.toByteArray());
|
return append(bc.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toByteArray() {
|
public byte[] toByteArray() {
|
||||||
byte[] result=new byte[size];
|
byte[] result = new byte[size];
|
||||||
System.arraycopy(contents,0,result,0,size);
|
System.arraycopy(contents, 0, result, 0, size);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] startToByteArray(int maxlen) {
|
public byte[] startToByteArray(int maxlen) {
|
||||||
if (size < maxlen) {
|
if (size < maxlen) {
|
||||||
byte[] res = toByteArray();
|
byte[] res = toByteArray();
|
||||||
clear();
|
clear();
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
byte[] result = new byte[maxlen];
|
byte[] result = new byte[maxlen];
|
||||||
System.arraycopy(contents,0,result,0,maxlen);
|
System.arraycopy(contents, 0, result, 0, maxlen);
|
||||||
System.arraycopy(contents,maxlen,contents,0,size-maxlen);
|
System.arraycopy(contents, maxlen, contents, 0, size - maxlen);
|
||||||
size-=maxlen;
|
size -= maxlen;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentSize() {
|
public int getCurrentSize() {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean ensureCapacity(int cap) {
|
public boolean ensureCapacity(int cap) {
|
||||||
if (contents.length<cap) {
|
if (contents.length < cap) {
|
||||||
int l=contents.length;
|
int l = contents.length;
|
||||||
while (l<cap) {
|
while (l < cap) {
|
||||||
l=(l*3)/2+1;
|
l = (l * 3) / 2 + 1;
|
||||||
}
|
}
|
||||||
byte[] newcont=new byte[l];
|
byte[] newcont = new byte[l];
|
||||||
System.arraycopy(contents,0,newcont,0,size);
|
System.arraycopy(contents, 0, newcont, 0, size);
|
||||||
contents=newcont;
|
contents = newcont;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return size==0;
|
return size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int indexOf(ByteCollector bc) {
|
public int indexOf(ByteCollector bc) {
|
||||||
// optimieren?
|
// optimieren?
|
||||||
return indexOf(bc.toByteArray());
|
return indexOf(bc.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int indexOf(byte b) {
|
public int indexOf(byte b) {
|
||||||
// optimieren?
|
// optimieren?
|
||||||
return indexOf(new byte[] {b});
|
return indexOf(new byte[] { b});
|
||||||
}
|
}
|
||||||
|
|
||||||
public int indexOf(byte[] ba) {
|
public int indexOf(byte[] ba) {
|
||||||
loop:
|
loop: for (int i = 0; i < size - ba.length + 1; i++) {
|
||||||
for (int i=0;i<size-ba.length+1;i++) {
|
for (int j = 0; j < ba.length; j++) {
|
||||||
for (int j=0;j<ba.length;j++) {
|
if (contents[i + j] != ba[j]) continue loop;
|
||||||
if (contents[i+j]!=ba[j]) continue loop;
|
}
|
||||||
}
|
return i;
|
||||||
return i;
|
}
|
||||||
}
|
return -1;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
size=0;
|
size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearAndShorten() {
|
public void clearAndShorten() {
|
||||||
size=0;
|
size = 0;
|
||||||
contents=new byte[80];
|
contents = new byte[80];
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new String(toByteArray());
|
return new String(toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int h =0;
|
int h = 0;
|
||||||
for (int i=0;i<size;i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
h+=contents[i]*contents[i];
|
h += contents[i] * contents[i];
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (o instanceof ByteCollector) {
|
if (o instanceof ByteCollector) {
|
||||||
ByteCollector by=(ByteCollector)o;
|
ByteCollector by = (ByteCollector) o;
|
||||||
if (size!=by.size) return false;
|
if (size != by.size) return false;
|
||||||
for (int i=0;i<size;i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
if (contents[i]!=by.contents[i]) return false;
|
if (contents[i] != by.contents[i]) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte removeFirst() {
|
public byte removeFirst() {
|
||||||
byte bb=contents[0];
|
byte bb = contents[0];
|
||||||
if (size==0)
|
if (size == 0) throw new IllegalArgumentException("ByteCollector is empty");
|
||||||
throw new IllegalArgumentException("ByteCollector is empty");
|
if (size > 1)
|
||||||
if(size>1)
|
System.arraycopy(contents, 1, contents, 0, --size);
|
||||||
System.arraycopy(contents,1,contents,0,--size);
|
else
|
||||||
else
|
size = 0;
|
||||||
size=0;
|
return bb;
|
||||||
return bb;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ public interface I2PServerSocket {
|
|||||||
* Closes the socket.
|
* Closes the socket.
|
||||||
*/
|
*/
|
||||||
public void close() throws I2PException;
|
public void close() throws I2PException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for the next socket connecting. If a remote user tried to make a
|
* Waits for the next socket connecting. If a remote user tried to make a
|
||||||
* connection and the local application wasn't .accept()ing new connections,
|
* connection and the local application wasn't .accept()ing new connections,
|
||||||
@ -26,4 +26,4 @@ public interface I2PServerSocket {
|
|||||||
* Access the manager which is coordinating the server socket
|
* Access the manager which is coordinating the server socket
|
||||||
*/
|
*/
|
||||||
public I2PSocketManager getManager();
|
public I2PSocketManager getManager();
|
||||||
}
|
}
|
@ -10,41 +10,44 @@ import net.i2p.util.Log;
|
|||||||
class I2PServerSocketImpl implements I2PServerSocket {
|
class I2PServerSocketImpl implements I2PServerSocket {
|
||||||
private final static Log _log = new Log(I2PServerSocketImpl.class);
|
private final static Log _log = new Log(I2PServerSocketImpl.class);
|
||||||
private I2PSocketManager mgr;
|
private I2PSocketManager mgr;
|
||||||
private I2PSocket cached=null; // buffer one socket here
|
private I2PSocket cached = null; // buffer one socket here
|
||||||
|
|
||||||
public I2PServerSocketImpl(I2PSocketManager mgr) {
|
public I2PServerSocketImpl(I2PSocketManager mgr) {
|
||||||
this.mgr = mgr;
|
this.mgr = mgr;
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized I2PSocket accept() throws I2PException {
|
|
||||||
while(cached == null) {
|
|
||||||
myWait();
|
|
||||||
}
|
|
||||||
I2PSocket ret=cached;
|
|
||||||
cached=null;
|
|
||||||
notifyAll();
|
|
||||||
_log.debug("TIMING: handed out accept result "+ret.hashCode());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized boolean getNewSocket(I2PSocket s){
|
|
||||||
while(cached != null) {
|
|
||||||
myWait();
|
|
||||||
}
|
|
||||||
cached=s;
|
|
||||||
notifyAll();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws I2PException {
|
|
||||||
//noop
|
|
||||||
}
|
|
||||||
|
|
||||||
private void myWait() {
|
|
||||||
try{
|
|
||||||
wait();
|
|
||||||
} catch (InterruptedException ex) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public I2PSocketManager getManager() { return mgr; }
|
public synchronized I2PSocket accept() throws I2PException {
|
||||||
}
|
while (cached == null) {
|
||||||
|
myWait();
|
||||||
|
}
|
||||||
|
I2PSocket ret = cached;
|
||||||
|
cached = null;
|
||||||
|
notifyAll();
|
||||||
|
_log.debug("TIMING: handed out accept result " + ret.hashCode());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean getNewSocket(I2PSocket s) {
|
||||||
|
while (cached != null) {
|
||||||
|
myWait();
|
||||||
|
}
|
||||||
|
cached = s;
|
||||||
|
notifyAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws I2PException {
|
||||||
|
//noop
|
||||||
|
}
|
||||||
|
|
||||||
|
private void myWait() {
|
||||||
|
try {
|
||||||
|
wait();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public I2PSocketManager getManager() {
|
||||||
|
return mgr;
|
||||||
|
}
|
||||||
|
}
|
@ -36,4 +36,4 @@ public interface I2PSocket {
|
|||||||
* Closes the socket if not closed yet
|
* Closes the socket if not closed yet
|
||||||
*/
|
*/
|
||||||
public void close() throws IOException;
|
public void close() throws IOException;
|
||||||
}
|
}
|
@ -18,9 +18,9 @@ import net.i2p.util.Log;
|
|||||||
class I2PSocketImpl implements I2PSocket {
|
class I2PSocketImpl implements I2PSocket {
|
||||||
private final static Log _log = new Log(I2PSocketImpl.class);
|
private final static Log _log = new Log(I2PSocketImpl.class);
|
||||||
|
|
||||||
public static final int MAX_PACKET_SIZE = 1024*32;
|
public static final int MAX_PACKET_SIZE = 1024 * 32;
|
||||||
public static final int PACKET_DELAY=100;
|
public static final int PACKET_DELAY = 100;
|
||||||
|
|
||||||
private I2PSocketManager manager;
|
private I2PSocketManager manager;
|
||||||
private Destination local;
|
private Destination local;
|
||||||
private Destination remote;
|
private Destination remote;
|
||||||
@ -31,307 +31,306 @@ class I2PSocketImpl implements I2PSocket {
|
|||||||
private I2POutputStream out;
|
private I2POutputStream out;
|
||||||
private boolean outgoing;
|
private boolean outgoing;
|
||||||
private Object flagLock = new Object();
|
private Object flagLock = new Object();
|
||||||
private boolean closed = false, sendClose=true, closed2=false;
|
private boolean closed = false, sendClose = true, closed2 = false;
|
||||||
|
|
||||||
public I2PSocketImpl(Destination peer, I2PSocketManager mgr,
|
public I2PSocketImpl(Destination peer, I2PSocketManager mgr, boolean outgoing, String localID) {
|
||||||
boolean outgoing, String localID) {
|
this.outgoing = outgoing;
|
||||||
this.outgoing=outgoing;
|
manager = mgr;
|
||||||
manager = mgr;
|
remote = peer;
|
||||||
remote = peer;
|
local = mgr.getSession().getMyDestination();
|
||||||
local = mgr.getSession().getMyDestination();
|
in = new I2PInputStream();
|
||||||
in = new I2PInputStream();
|
I2PInputStream pin = new I2PInputStream();
|
||||||
I2PInputStream pin = new I2PInputStream();
|
out = new I2POutputStream(pin);
|
||||||
out = new I2POutputStream(pin);
|
new I2PSocketRunner(pin);
|
||||||
new I2PSocketRunner(pin);
|
this.localID = localID;
|
||||||
this.localID = localID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLocalID() {
|
public String getLocalID() {
|
||||||
return localID;
|
return localID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRemoteID(String id) {
|
public void setRemoteID(String id) {
|
||||||
synchronized(remoteIDWaiter) {
|
synchronized (remoteIDWaiter) {
|
||||||
remoteID=id;
|
remoteID = id;
|
||||||
remoteIDWaiter.notifyAll();
|
remoteIDWaiter.notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRemoteID(boolean wait) throws InterruptedIOException {
|
public String getRemoteID(boolean wait) throws InterruptedIOException {
|
||||||
return getRemoteID(wait, -1);
|
return getRemoteID(wait, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRemoteID(boolean wait, long maxWait) throws InterruptedIOException {
|
public String getRemoteID(boolean wait, long maxWait) throws InterruptedIOException {
|
||||||
long dieAfter = System.currentTimeMillis() + maxWait;
|
long dieAfter = System.currentTimeMillis() + maxWait;
|
||||||
synchronized(remoteIDWaiter) {
|
synchronized (remoteIDWaiter) {
|
||||||
while (wait && remoteID==null) {
|
while (wait && remoteID == null) {
|
||||||
try {
|
try {
|
||||||
if (maxWait > 0)
|
if (maxWait > 0)
|
||||||
remoteIDWaiter.wait(maxWait);
|
remoteIDWaiter.wait(maxWait);
|
||||||
else
|
else
|
||||||
remoteIDWaiter.wait();
|
remoteIDWaiter.wait();
|
||||||
} catch (InterruptedException ex) {}
|
} catch (InterruptedException ex) {
|
||||||
|
}
|
||||||
if ( (maxWait > 0) && (System.currentTimeMillis() > dieAfter) )
|
|
||||||
throw new InterruptedIOException("Timed out waiting for remote ID");
|
if ((maxWait > 0) && (System.currentTimeMillis() > dieAfter))
|
||||||
}
|
throw new InterruptedIOException("Timed out waiting for remote ID");
|
||||||
if (wait) {
|
}
|
||||||
_log.debug("TIMING: RemoteID set to " + I2PSocketManager.getReadableForm(remoteID) +" for "+this.hashCode());
|
if (wait) {
|
||||||
}
|
_log.debug("TIMING: RemoteID set to " + I2PSocketManager.getReadableForm(remoteID) + " for "
|
||||||
return remoteID;
|
+ this.hashCode());
|
||||||
}
|
}
|
||||||
|
return remoteID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRemoteID() throws InterruptedIOException {
|
public String getRemoteID() throws InterruptedIOException {
|
||||||
return getRemoteID(false);
|
return getRemoteID(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void queueData(byte[] data) {
|
public void queueData(byte[] data) {
|
||||||
in.queueData(data);
|
in.queueData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the Destination of this side of the socket.
|
* Return the Destination of this side of the socket.
|
||||||
*/
|
*/
|
||||||
public Destination getThisDestination() { return local; }
|
public Destination getThisDestination() {
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the destination of the peer.
|
* Return the destination of the peer.
|
||||||
*/
|
*/
|
||||||
public Destination getPeerDestination() { return remote; }
|
public Destination getPeerDestination() {
|
||||||
|
return remote;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an InputStream to read from the socket.
|
* Return an InputStream to read from the socket.
|
||||||
*/
|
*/
|
||||||
public InputStream getInputStream() throws IOException {
|
public InputStream getInputStream() throws IOException {
|
||||||
if ( (in == null) )
|
if ((in == null)) throw new IOException("Not connected");
|
||||||
throw new IOException("Not connected");
|
return in;
|
||||||
return in;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an OutputStream to write into the socket.
|
* Return an OutputStream to write into the socket.
|
||||||
*/
|
*/
|
||||||
public OutputStream getOutputStream() throws IOException {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
if ( (out == null) )
|
if ((out == null)) throw new IOException("Not connected");
|
||||||
throw new IOException("Not connected");
|
return out;
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the socket if not closed yet
|
* Closes the socket if not closed yet
|
||||||
*/
|
*/
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
synchronized(flagLock) {
|
synchronized (flagLock) {
|
||||||
_log.debug("Closing connection");
|
_log.debug("Closing connection");
|
||||||
closed=true;
|
closed = true;
|
||||||
}
|
}
|
||||||
out.close();
|
out.close();
|
||||||
in.notifyClosed();
|
in.notifyClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void internalClose() {
|
public void internalClose() {
|
||||||
synchronized(flagLock) {
|
synchronized (flagLock) {
|
||||||
closed=true;
|
closed = true;
|
||||||
closed2=true;
|
closed2 = true;
|
||||||
sendClose=false;
|
sendClose = false;
|
||||||
}
|
}
|
||||||
out.close();
|
out.close();
|
||||||
in.notifyClosed();
|
in.notifyClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private byte getMask(int add) {
|
private byte getMask(int add) {
|
||||||
return (byte)((outgoing?(byte)0xA0:(byte)0x50)+(byte)add);
|
return (byte) ((outgoing ? (byte) 0xA0 : (byte) 0x50) + (byte) add);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
public class I2PInputStream extends InputStream {
|
public class I2PInputStream extends InputStream {
|
||||||
|
|
||||||
private ByteCollector bc = new ByteCollector();
|
private ByteCollector bc = new ByteCollector();
|
||||||
|
|
||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
byte[] b = new byte[1];
|
byte[] b = new byte[1];
|
||||||
int res = read(b);
|
int res = read(b);
|
||||||
if (res == 1) return b[0] & 0xff;
|
if (res == 1) return b[0] & 0xff;
|
||||||
if (res == -1) return -1;
|
if (res == -1) return -1;
|
||||||
throw new RuntimeException("Incorrect read() result");
|
throw new RuntimeException("Incorrect read() result");
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized int read(byte[] b, int off, int len) throws IOException {
|
public synchronized int read(byte[] b, int off, int len) throws IOException {
|
||||||
_log.debug("Read called: "+this.hashCode());
|
_log.debug("Read called: " + this.hashCode());
|
||||||
if (len==0) return 0;
|
if (len == 0) return 0;
|
||||||
byte[] read = bc.startToByteArray(len);
|
byte[] read = bc.startToByteArray(len);
|
||||||
while (read.length==0) {
|
while (read.length == 0) {
|
||||||
synchronized(flagLock) {
|
synchronized (flagLock) {
|
||||||
if (closed){
|
if (closed) {
|
||||||
_log.debug("Closed is set, so closing stream: "+this.hashCode());
|
_log.debug("Closed is set, so closing stream: " + this.hashCode());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
wait();
|
wait();
|
||||||
} catch (InterruptedException ex) {}
|
} catch (InterruptedException ex) {
|
||||||
read = bc.startToByteArray(len);
|
}
|
||||||
}
|
read = bc.startToByteArray(len);
|
||||||
if (read.length>len) throw new RuntimeException("BUG");
|
}
|
||||||
System.arraycopy(read,0,b,off,read.length);
|
if (read.length > len) throw new RuntimeException("BUG");
|
||||||
|
System.arraycopy(read, 0, b, off, read.length);
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG)) {
|
if (_log.shouldLog(Log.DEBUG)) {
|
||||||
_log.debug("Read from I2PInputStream " + this.hashCode()
|
_log.debug("Read from I2PInputStream " + this.hashCode() + " returned " + read.length + " bytes");
|
||||||
+ " returned "+read.length+" bytes");
|
}
|
||||||
}
|
//if (_log.shouldLog(Log.DEBUG)) {
|
||||||
//if (_log.shouldLog(Log.DEBUG)) {
|
// _log.debug("Read from I2PInputStream " + this.hashCode()
|
||||||
// _log.debug("Read from I2PInputStream " + this.hashCode()
|
// + " returned "+read.length+" bytes:\n"
|
||||||
// + " returned "+read.length+" bytes:\n"
|
// + HexDump.dump(read));
|
||||||
// + HexDump.dump(read));
|
//}
|
||||||
//}
|
return read.length;
|
||||||
return read.length;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int available() {
|
public int available() {
|
||||||
return bc.getCurrentSize();
|
return bc.getCurrentSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void queueData(byte[] data) {
|
public void queueData(byte[] data) {
|
||||||
queueData(data,0,data.length);
|
queueData(data, 0, data.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void queueData(byte[] data, int off, int len) {
|
public synchronized void queueData(byte[] data, int off, int len) {
|
||||||
_log.debug("Insert "+len+" bytes into queue: "+this.hashCode());
|
_log.debug("Insert " + len + " bytes into queue: " + this.hashCode());
|
||||||
bc.append(data, off, len);
|
bc.append(data, off, len);
|
||||||
notifyAll();
|
notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void notifyClosed() {
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void notifyClosed() {
|
|
||||||
notifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class I2POutputStream extends OutputStream {
|
public class I2POutputStream extends OutputStream {
|
||||||
|
|
||||||
public I2PInputStream sendTo;
|
public I2PInputStream sendTo;
|
||||||
|
|
||||||
public I2POutputStream(I2PInputStream sendTo) {
|
|
||||||
this.sendTo=sendTo;
|
|
||||||
}
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
write(new byte[] {(byte)b});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write (byte[] b, int off, int len) throws IOException {
|
public I2POutputStream(I2PInputStream sendTo) {
|
||||||
sendTo.queueData(b,off,len);
|
this.sendTo = sendTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void write(int b) throws IOException {
|
||||||
sendTo.notifyClosed();
|
write(new byte[] { (byte) b});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
|
sendTo.queueData(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
sendTo.notifyClosed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class I2PSocketRunner extends I2PThread {
|
public class I2PSocketRunner extends I2PThread {
|
||||||
|
|
||||||
public InputStream in;
|
public InputStream in;
|
||||||
|
|
||||||
public I2PSocketRunner(InputStream in) {
|
public I2PSocketRunner(InputStream in) {
|
||||||
_log.debug("Runner's input stream is: "+in.hashCode());
|
_log.debug("Runner's input stream is: " + in.hashCode());
|
||||||
this.in=in;
|
this.in = in;
|
||||||
setName("SocketRunner from " + I2PSocketImpl.this.remote.calculateHash().toBase64().substring(0, 4));
|
setName("SocketRunner from " + I2PSocketImpl.this.remote.calculateHash().toBase64().substring(0, 4));
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
byte[] buffer = new byte[MAX_PACKET_SIZE];
|
byte[] buffer = new byte[MAX_PACKET_SIZE];
|
||||||
ByteCollector bc = new ByteCollector();
|
ByteCollector bc = new ByteCollector();
|
||||||
boolean sent = true;
|
boolean sent = true;
|
||||||
try {
|
try {
|
||||||
int len, bcsize;
|
int len, bcsize;
|
||||||
// try {
|
// try {
|
||||||
while (true) {
|
while (true) {
|
||||||
len = in.read(buffer);
|
len = in.read(buffer);
|
||||||
bcsize = bc.getCurrentSize();
|
bcsize = bc.getCurrentSize();
|
||||||
if (len != -1) {
|
if (len != -1) {
|
||||||
bc.append(buffer,len);
|
bc.append(buffer, len);
|
||||||
} else if (bcsize == 0) {
|
} else if (bcsize == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((bcsize < MAX_PACKET_SIZE)
|
if ((bcsize < MAX_PACKET_SIZE) && (in.available() == 0)) {
|
||||||
&& (in.available()==0)) {
|
_log.debug("Runner Point d: " + this.hashCode());
|
||||||
_log.debug("Runner Point d: "+this.hashCode());
|
|
||||||
|
try {
|
||||||
try {
|
Thread.sleep(PACKET_DELAY);
|
||||||
Thread.sleep(PACKET_DELAY);
|
} catch (InterruptedException e) {
|
||||||
} catch (InterruptedException e) {
|
e.printStackTrace();
|
||||||
e.printStackTrace();
|
}
|
||||||
}
|
}
|
||||||
}
|
if ((bcsize >= MAX_PACKET_SIZE) || (in.available() == 0)) {
|
||||||
if ((bcsize >= MAX_PACKET_SIZE)
|
byte[] data = bc.startToByteArray(MAX_PACKET_SIZE);
|
||||||
|| (in.available()==0) ) {
|
if (data.length > 0) {
|
||||||
byte[] data = bc.startToByteArray(MAX_PACKET_SIZE);
|
_log.debug("Message size is: " + data.length);
|
||||||
if (data.length > 0) {
|
sent = sendBlock(data);
|
||||||
_log.debug("Message size is: "+data.length);
|
if (!sent) {
|
||||||
sent = sendBlock(data);
|
_log.error("Error sending message to peer. Killing socket runner");
|
||||||
if (!sent) {
|
break;
|
||||||
_log.error("Error sending message to peer. Killing socket runner");
|
}
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if ((bc.getCurrentSize() > 0) && sent) {
|
||||||
}
|
_log.error("A SCARY MONSTER HAS EATEN SOME DATA! " + "(input stream: " + in.hashCode() + "; "
|
||||||
if ((bc.getCurrentSize() > 0) && sent) {
|
+ "queue size: " + bc.getCurrentSize() + ")");
|
||||||
_log.error("A SCARY MONSTER HAS EATEN SOME DATA! "
|
}
|
||||||
+ "(input stream: " + in.hashCode() + "; "
|
synchronized (flagLock) {
|
||||||
+ "queue size: " + bc.getCurrentSize() + ")");
|
closed2 = true;
|
||||||
}
|
}
|
||||||
synchronized(flagLock) {
|
// } catch (IOException ex) {
|
||||||
closed2=true;
|
// if (_log.shouldLog(Log.INFO))
|
||||||
}
|
// _log.info("Error reading and writing", ex);
|
||||||
// } catch (IOException ex) {
|
// }
|
||||||
// if (_log.shouldLog(Log.INFO))
|
boolean sc;
|
||||||
// _log.info("Error reading and writing", ex);
|
synchronized (flagLock) {
|
||||||
// }
|
sc = sendClose;
|
||||||
boolean sc;
|
} // FIXME: Race here?
|
||||||
synchronized(flagLock) {
|
if (sc) {
|
||||||
sc=sendClose;
|
_log.info("Sending close packet: " + outgoing);
|
||||||
} // FIXME: Race here?
|
byte[] packet = I2PSocketManager.makePacket((byte) (getMask(0x02)), remoteID, new byte[0]);
|
||||||
if (sc) {
|
synchronized (manager.getSession()) {
|
||||||
_log.info("Sending close packet: "+outgoing);
|
sent = manager.getSession().sendMessage(remote, packet);
|
||||||
byte[] packet = I2PSocketManager.makePacket
|
}
|
||||||
((byte)(getMask(0x02)),remoteID, new byte[0]);
|
if (!sent) {
|
||||||
synchronized(manager.getSession()) {
|
_log.error("Error sending close packet to peer");
|
||||||
sent = manager.getSession().sendMessage(remote, packet);
|
}
|
||||||
}
|
}
|
||||||
if (!sent) {
|
manager.removeSocket(I2PSocketImpl.this);
|
||||||
_log.error("Error sending close packet to peer");
|
} catch (IOException ex) {
|
||||||
}
|
// WHOEVER removes this event on inconsistent
|
||||||
}
|
// state before fixing the inconsistent state (a
|
||||||
manager.removeSocket(I2PSocketImpl.this);
|
// reference on the socket in the socket manager
|
||||||
} catch (IOException ex) {
|
// etc.) will get hanged by me personally -- mihi
|
||||||
// WHOEVER removes this event on inconsistent
|
_log.error("Error running - **INCONSISTENT STATE!!!**", ex);
|
||||||
// state before fixing the inconsistent state (a
|
} catch (I2PException ex) {
|
||||||
// reference on the socket in the socket manager
|
_log.error("Error running - **INCONSISTENT STATE!!!**", ex);
|
||||||
// etc.) will get hanged by me personally -- mihi
|
}
|
||||||
_log.error("Error running - **INCONSISTENT STATE!!!**", ex);
|
}
|
||||||
} catch (I2PException ex) {
|
|
||||||
_log.error("Error running - **INCONSISTENT STATE!!!**" , ex);
|
private boolean sendBlock(byte data[]) throws I2PSessionException {
|
||||||
}
|
_log.debug("TIMING: Block to send for " + I2PSocketImpl.this.hashCode());
|
||||||
}
|
if (remoteID == null) {
|
||||||
|
_log.error("NULL REMOTEID");
|
||||||
private boolean sendBlock(byte data[]) throws I2PSessionException {
|
return false;
|
||||||
_log.debug("TIMING: Block to send for "+I2PSocketImpl.this.hashCode());
|
}
|
||||||
if (remoteID==null) {
|
byte[] packet = I2PSocketManager.makePacket(getMask(0x00), remoteID, data);
|
||||||
_log.error("NULL REMOTEID");
|
boolean sent;
|
||||||
return false;
|
synchronized (flagLock) {
|
||||||
}
|
if (closed2) return false;
|
||||||
byte[] packet = I2PSocketManager.makePacket(getMask(0x00), remoteID,
|
}
|
||||||
data);
|
synchronized (manager.getSession()) {
|
||||||
boolean sent;
|
sent = manager.getSession().sendMessage(remote, packet);
|
||||||
synchronized(flagLock) {
|
}
|
||||||
if (closed2) return false;
|
return sent;
|
||||||
}
|
}
|
||||||
synchronized(manager.getSession()) {
|
|
||||||
sent = manager.getSession().sendMessage(remote, packet);
|
|
||||||
}
|
|
||||||
return sent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -37,201 +37,199 @@ public class I2PSocketManager implements I2PSessionListener {
|
|||||||
private HashMap _inSockets;
|
private HashMap _inSockets;
|
||||||
private I2PSocketOptions _defaultOptions;
|
private I2PSocketOptions _defaultOptions;
|
||||||
|
|
||||||
public static final int PUBKEY_LENGTH=387;
|
public static final int PUBKEY_LENGTH = 387;
|
||||||
|
|
||||||
|
|
||||||
public I2PSocketManager() {
|
public I2PSocketManager() {
|
||||||
_session=null;
|
_session = null;
|
||||||
_serverSocket = new I2PServerSocketImpl(this);
|
_serverSocket = new I2PServerSocketImpl(this);
|
||||||
_inSockets = new HashMap(16);
|
_inSockets = new HashMap(16);
|
||||||
_outSockets = new HashMap(16);
|
_outSockets = new HashMap(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
public I2PSession getSession() {
|
public I2PSession getSession() {
|
||||||
return _session;
|
return _session;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSession(I2PSession session) {
|
||||||
|
_session = session;
|
||||||
|
if (session != null) session.setSessionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnected(I2PSession session) {
|
||||||
|
_log.error("Disconnected from the session");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||||
|
_log.error("Error occurred: [" + message + "]", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void messageAvailable(I2PSession session, int msgId, long size) {
|
||||||
|
try {
|
||||||
|
I2PSocketImpl s;
|
||||||
|
byte msg[] = session.receiveMessage(msgId);
|
||||||
|
if (msg.length == 1 && msg[0] == -1) {
|
||||||
|
_log.debug("Ping received");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (msg.length < 4) {
|
||||||
|
_log.error("==== packet too short ====");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int type = msg[0] & 0xff;
|
||||||
|
String id = new String(new byte[] { msg[1], msg[2], msg[3]}, "ISO-8859-1");
|
||||||
|
byte[] payload = new byte[msg.length - 4];
|
||||||
|
System.arraycopy(msg, 4, payload, 0, payload.length);
|
||||||
|
_log.debug("Message read: type = [" + Integer.toHexString(type) + "] id = [" + getReadableForm(id)
|
||||||
|
+ "] payload length: " + payload.length + "]");
|
||||||
|
synchronized (lock) {
|
||||||
|
switch (type) {
|
||||||
|
case 0x51:
|
||||||
|
// ACK outgoing
|
||||||
|
s = (I2PSocketImpl) _outSockets.get(id);
|
||||||
|
if (s == null) {
|
||||||
|
_log.warn("No socket responsible for ACK packet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (payload.length == 3 && s.getRemoteID(false) == null) {
|
||||||
|
String newID = new String(payload, "ISO-8859-1");
|
||||||
|
s.setRemoteID(newID);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (payload.length != 3)
|
||||||
|
_log.warn("Ack packet had " + payload.length + " bytes");
|
||||||
|
else
|
||||||
|
_log.warn("Remote ID already exists? " + s.getRemoteID());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 0x52:
|
||||||
|
// disconnect outgoing
|
||||||
|
_log.debug("*Disconnect outgoing!");
|
||||||
|
try {
|
||||||
|
s = (I2PSocketImpl) _outSockets.get(id);
|
||||||
|
if (payload.length == 0 && s != null) {
|
||||||
|
s.internalClose();
|
||||||
|
_outSockets.remove(id);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (payload.length > 0) _log.warn("Disconnect packet had " + payload.length + " bytes");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (Exception t) {
|
||||||
|
_log.error("Ignoring error on disconnect", t);
|
||||||
|
}
|
||||||
|
case 0x50:
|
||||||
|
// packet send outgoing
|
||||||
|
_log.debug("*Packet send outgoing [" + payload.length + "]");
|
||||||
|
s = (I2PSocketImpl) _outSockets.get(id);
|
||||||
|
if (s != null) {
|
||||||
|
s.queueData(payload);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
_log.error("Null socket with data available");
|
||||||
|
throw new IllegalStateException("Null socket with data available");
|
||||||
|
}
|
||||||
|
case 0xA1:
|
||||||
|
// SYN incoming
|
||||||
|
_log.debug("*Syn!");
|
||||||
|
if (payload.length == PUBKEY_LENGTH) {
|
||||||
|
String newLocalID = makeID(_inSockets);
|
||||||
|
Destination d = new Destination();
|
||||||
|
d.readBytes(new ByteArrayInputStream(payload));
|
||||||
|
|
||||||
|
s = new I2PSocketImpl(d, this, false, newLocalID);
|
||||||
|
s.setRemoteID(id);
|
||||||
|
if (_serverSocket.getNewSocket(s)) {
|
||||||
|
_inSockets.put(newLocalID, s);
|
||||||
|
byte[] packet = makePacket((byte) 0x51, id, newLocalID.getBytes("ISO-8859-1"));
|
||||||
|
boolean replySentOk = false;
|
||||||
|
synchronized (_session) {
|
||||||
|
replySentOk = _session.sendMessage(d, packet);
|
||||||
|
}
|
||||||
|
if (!replySentOk) {
|
||||||
|
_log.error("Error sending reply to " + d.calculateHash().toBase64()
|
||||||
|
+ " in response to a new con message", new Exception("Failed creation"));
|
||||||
|
s.internalClose();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] packet = (" " + id).getBytes("ISO-8859-1");
|
||||||
|
packet[0] = 0x52;
|
||||||
|
boolean nackSent = session.sendMessage(d, packet);
|
||||||
|
if (!nackSent) {
|
||||||
|
_log.error("Error sending NACK for session creation");
|
||||||
|
}
|
||||||
|
s.internalClose();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
_log.error("Syn packet that has a payload not equal to the pubkey length (" + payload.length
|
||||||
|
+ " != " + PUBKEY_LENGTH + ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 0xA2:
|
||||||
|
// disconnect incoming
|
||||||
|
_log.debug("*Disconnect incoming!");
|
||||||
|
try {
|
||||||
|
s = (I2PSocketImpl) _inSockets.get(id);
|
||||||
|
if (payload.length == 0 && s != null) {
|
||||||
|
s.internalClose();
|
||||||
|
_inSockets.remove(id);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (payload.length > 0) _log.warn("Disconnect packet had " + payload.length + " bytes");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (Exception t) {
|
||||||
|
_log.error("Ignoring error on disconnect", t);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 0xA0:
|
||||||
|
// packet send incoming
|
||||||
|
_log.debug("*Packet send incoming [" + payload.length + "]");
|
||||||
|
s = (I2PSocketImpl) _inSockets.get(id);
|
||||||
|
if (s != null) {
|
||||||
|
s.queueData(payload);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
_log.error("Null socket with data available");
|
||||||
|
throw new IllegalStateException("Null socket with data available");
|
||||||
|
}
|
||||||
|
case 0xFF:
|
||||||
|
// ignore
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_log.error("\n\n=============== Unknown packet! " + "============" + "\nType: " + (int) type
|
||||||
|
+ "\nID: " + getReadableForm(id) + "\nBase64'ed Data: " + Base64.encode(payload)
|
||||||
|
+ "\n\n\n");
|
||||||
|
if (id != null) {
|
||||||
|
_inSockets.remove(id);
|
||||||
|
_outSockets.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (I2PException ise) {
|
||||||
|
_log.error("Error processing", ise);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
_log.error("Error processing", ioe);
|
||||||
|
} catch (IllegalStateException ise) {
|
||||||
|
_log.debug("Error processing", ise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportAbuse(I2PSession session, int severity) {
|
||||||
|
_log.error("Abuse reported [" + severity + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultOptions(I2PSocketOptions options) {
|
||||||
|
_defaultOptions = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public I2PSocketOptions getDefaultOptions() {
|
||||||
|
return _defaultOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public I2PServerSocket getServerSocket() {
|
||||||
|
return _serverSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSession(I2PSession session) {
|
|
||||||
_session = session;
|
|
||||||
if (session != null)
|
|
||||||
session.setSessionListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnected(I2PSession session) {
|
|
||||||
_log.error("Disconnected from the session");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
|
||||||
_log.error("Error occurred: [" + message + "]", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void messageAvailable(I2PSession session, int msgId, long size) {
|
|
||||||
try {
|
|
||||||
I2PSocketImpl s;
|
|
||||||
byte msg[] = session.receiveMessage(msgId);
|
|
||||||
if (msg.length == 1 && msg[0] == -1) {
|
|
||||||
_log.debug("Ping received");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (msg.length <4) {
|
|
||||||
_log.error("==== packet too short ====");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int type = msg[0] & 0xff;
|
|
||||||
String id = new String(new byte[] {msg[1], msg[2], msg[3]},
|
|
||||||
"ISO-8859-1");
|
|
||||||
byte[] payload = new byte[msg.length-4];
|
|
||||||
System.arraycopy(msg, 4, payload, 0, payload.length);
|
|
||||||
_log.debug("Message read: type = [" + Integer.toHexString(type) +
|
|
||||||
"] id = [" + getReadableForm(id)+
|
|
||||||
"] payload length: " + payload.length + "]");
|
|
||||||
synchronized(lock) {
|
|
||||||
switch(type) {
|
|
||||||
case 0x51: // ACK outgoing
|
|
||||||
s = (I2PSocketImpl) _outSockets.get(id);
|
|
||||||
if (s == null) {
|
|
||||||
_log.warn("No socket responsible for ACK packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (payload.length==3 && s.getRemoteID(false)==null) {
|
|
||||||
String newID = new String(payload,
|
|
||||||
"ISO-8859-1");
|
|
||||||
s.setRemoteID(newID);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (payload.length != 3)
|
|
||||||
_log.warn("Ack packet had " + payload.length + " bytes");
|
|
||||||
else
|
|
||||||
_log.warn("Remote ID already exists? " + s.getRemoteID());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0x52: // disconnect outgoing
|
|
||||||
_log.debug("*Disconnect outgoing!");
|
|
||||||
try {
|
|
||||||
s = (I2PSocketImpl) _outSockets.get(id);
|
|
||||||
if (payload.length==0 && s != null) {
|
|
||||||
s.internalClose();
|
|
||||||
_outSockets.remove(id);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (payload.length > 0)
|
|
||||||
_log.warn("Disconnect packet had " + payload.length + " bytes");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (Exception t) {
|
|
||||||
_log.error("Ignoring error on disconnect", t);
|
|
||||||
}
|
|
||||||
case 0x50: // packet send outgoing
|
|
||||||
_log.debug("*Packet send outgoing [" + payload.length + "]");
|
|
||||||
s = (I2PSocketImpl) _outSockets.get(id);
|
|
||||||
if (s != null) {
|
|
||||||
s.queueData(payload);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
_log.error("Null socket with data available");
|
|
||||||
throw new IllegalStateException("Null socket with data available");
|
|
||||||
}
|
|
||||||
case 0xA1: // SYN incoming
|
|
||||||
_log.debug("*Syn!");
|
|
||||||
if (payload.length==PUBKEY_LENGTH) {
|
|
||||||
String newLocalID = makeID(_inSockets);
|
|
||||||
Destination d = new Destination();
|
|
||||||
d.readBytes(new ByteArrayInputStream(payload));
|
|
||||||
|
|
||||||
s = new I2PSocketImpl(d, this, false,
|
|
||||||
newLocalID);
|
|
||||||
s.setRemoteID(id);
|
|
||||||
if (_serverSocket.getNewSocket(s)) {
|
|
||||||
_inSockets.put(newLocalID, s);
|
|
||||||
byte[] packet = makePacket
|
|
||||||
((byte)0x51, id,
|
|
||||||
newLocalID.getBytes("ISO-8859-1"));
|
|
||||||
boolean replySentOk = false;
|
|
||||||
synchronized(_session) {
|
|
||||||
replySentOk = _session.sendMessage(d, packet);
|
|
||||||
}
|
|
||||||
if (!replySentOk) {
|
|
||||||
_log.error("Error sending reply to " +
|
|
||||||
d.calculateHash().toBase64() +
|
|
||||||
" in response to a new con message",
|
|
||||||
new Exception("Failed creation"));
|
|
||||||
s.internalClose();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
byte[] packet =
|
|
||||||
(" "+id).getBytes("ISO-8859-1");
|
|
||||||
packet[0]=0x52;
|
|
||||||
boolean nackSent = session.sendMessage(d, packet);
|
|
||||||
if (!nackSent) {
|
|
||||||
_log.error("Error sending NACK for session creation");
|
|
||||||
}
|
|
||||||
s.internalClose();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
_log.error("Syn packet that has a payload not equal to the pubkey length (" + payload.length + " != " + PUBKEY_LENGTH + ")");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0xA2: // disconnect incoming
|
|
||||||
_log.debug("*Disconnect incoming!");
|
|
||||||
try {
|
|
||||||
s = (I2PSocketImpl) _inSockets.get(id);
|
|
||||||
if (payload.length==0 && s != null) {
|
|
||||||
s.internalClose();
|
|
||||||
_inSockets.remove(id);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (payload.length > 0)
|
|
||||||
_log.warn("Disconnect packet had " + payload.length + " bytes");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (Exception t) {
|
|
||||||
_log.error("Ignoring error on disconnect", t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 0xA0: // packet send incoming
|
|
||||||
_log.debug("*Packet send incoming [" + payload.length + "]");
|
|
||||||
s = (I2PSocketImpl) _inSockets.get(id);
|
|
||||||
if (s != null) {
|
|
||||||
s.queueData(payload);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
_log.error("Null socket with data available");
|
|
||||||
throw new IllegalStateException("Null socket with data available");
|
|
||||||
}
|
|
||||||
case 0xFF: // ignore
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_log.error("\n\n=============== Unknown packet! "+
|
|
||||||
"============"+
|
|
||||||
"\nType: "+(int)type+
|
|
||||||
"\nID: " + getReadableForm(id)+
|
|
||||||
"\nBase64'ed Data: "+Base64.encode(payload)+
|
|
||||||
"\n\n\n");
|
|
||||||
if (id != null) {
|
|
||||||
_inSockets.remove(id);
|
|
||||||
_outSockets.remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (I2PException ise) {
|
|
||||||
_log.error("Error processing", ise);
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
_log.error("Error processing", ioe);
|
|
||||||
} catch (IllegalStateException ise) {
|
|
||||||
_log.debug("Error processing", ise);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reportAbuse(I2PSession session, int severity) {
|
|
||||||
_log.error("Abuse reported [" + severity + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultOptions(I2PSocketOptions options) { _defaultOptions = options; }
|
|
||||||
|
|
||||||
public I2PSocketOptions getDefaultOptions() { return _defaultOptions ; }
|
|
||||||
|
|
||||||
public I2PServerSocket getServerSocket() { return _serverSocket; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new connected socket (block until the socket is created)
|
* Create a new connected socket (block until the socket is created)
|
||||||
*
|
*
|
||||||
@ -239,104 +237,101 @@ public class I2PSocketManager implements I2PSessionListener {
|
|||||||
*/
|
*/
|
||||||
public I2PSocket connect(Destination peer, I2PSocketOptions options) throws I2PException {
|
public I2PSocket connect(Destination peer, I2PSocketOptions options) throws I2PException {
|
||||||
|
|
||||||
String localID, lcID;
|
String localID, lcID;
|
||||||
I2PSocketImpl s;
|
I2PSocketImpl s;
|
||||||
synchronized(lock) {
|
synchronized (lock) {
|
||||||
localID=makeID(_outSockets);
|
localID = makeID(_outSockets);
|
||||||
lcID=getReadableForm(localID);
|
lcID = getReadableForm(localID);
|
||||||
s = new I2PSocketImpl(peer, this, true, localID);
|
s = new I2PSocketImpl(peer, this, true, localID);
|
||||||
_outSockets.put(s.getLocalID(),s);
|
_outSockets.put(s.getLocalID(), s);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ByteArrayOutputStream pubkey = new ByteArrayOutputStream();
|
ByteArrayOutputStream pubkey = new ByteArrayOutputStream();
|
||||||
_session.getMyDestination().writeBytes(pubkey);
|
_session.getMyDestination().writeBytes(pubkey);
|
||||||
String remoteID;
|
String remoteID;
|
||||||
byte[] packet = makePacket((byte)0xA1, localID,
|
byte[] packet = makePacket((byte) 0xA1, localID, pubkey.toByteArray());
|
||||||
pubkey.toByteArray());
|
boolean sent = false;
|
||||||
boolean sent = false;
|
synchronized (_session) {
|
||||||
synchronized(_session) {
|
sent = _session.sendMessage(peer, packet);
|
||||||
sent = _session.sendMessage(peer, packet);
|
}
|
||||||
}
|
if (!sent) {
|
||||||
if (!sent) {
|
_log.info("Unable to send & receive ack for SYN packet");
|
||||||
_log.info("Unable to send & receive ack for SYN packet");
|
synchronized (lock) {
|
||||||
synchronized(lock) {
|
_outSockets.remove(s.getLocalID());
|
||||||
_outSockets.remove(s.getLocalID());
|
}
|
||||||
}
|
throw new I2PException("Unable to reach peer");
|
||||||
throw new I2PException("Unable to reach peer");
|
}
|
||||||
}
|
remoteID = s.getRemoteID(true, options.getConnectTimeout());
|
||||||
remoteID = s.getRemoteID(true, options.getConnectTimeout());
|
if ("".equals(remoteID)) { throw new I2PException("Unable to reach peer"); }
|
||||||
if ("".equals(remoteID)) {
|
_log.debug("TIMING: s given out for remoteID " + getReadableForm(remoteID));
|
||||||
throw new I2PException("Unable to reach peer");
|
return s;
|
||||||
}
|
} catch (InterruptedIOException ioe) {
|
||||||
_log.debug("TIMING: s given out for remoteID "+getReadableForm(remoteID));
|
_log.error("Timeout waiting for ack from syn for id " + getReadableForm(lcID), ioe);
|
||||||
return s;
|
synchronized (lock) {
|
||||||
} catch (InterruptedIOException ioe) {
|
_outSockets.remove(s.getLocalID());
|
||||||
_log.error("Timeout waiting for ack from syn for id " + getReadableForm(lcID), ioe);
|
}
|
||||||
synchronized(lock) {
|
throw new I2PException("Timeout waiting for ack");
|
||||||
_outSockets.remove(s.getLocalID());
|
} catch (IOException ex) {
|
||||||
}
|
_log.error("Error sending syn on id " + getReadableForm(lcID), ex);
|
||||||
throw new I2PException("Timeout waiting for ack");
|
synchronized (lock) {
|
||||||
} catch (IOException ex) {
|
_outSockets.remove(s.getLocalID());
|
||||||
_log.error("Error sending syn on id " + getReadableForm(lcID), ex);
|
}
|
||||||
synchronized(lock) {
|
throw new I2PException("IOException occurred");
|
||||||
_outSockets.remove(s.getLocalID());
|
} catch (I2PException ex) {
|
||||||
}
|
_log.info("Error sending syn on id " + getReadableForm(lcID), ex);
|
||||||
throw new I2PException("IOException occurred");
|
synchronized (lock) {
|
||||||
} catch (I2PException ex) {
|
_outSockets.remove(s.getLocalID());
|
||||||
_log.info("Error sending syn on id " + getReadableForm(lcID), ex);
|
}
|
||||||
synchronized(lock) {
|
throw ex;
|
||||||
_outSockets.remove(s.getLocalID());
|
}
|
||||||
}
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public I2PSocket connect(Destination peer) throws I2PException {
|
public I2PSocket connect(Destination peer) throws I2PException {
|
||||||
return connect(peer, null);
|
return connect(peer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a set of currently connected I2PSockets, either initiated locally or remotely.
|
* Retrieve a set of currently connected I2PSockets, either initiated locally or remotely.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public Set listSockets() {
|
public Set listSockets() {
|
||||||
Set sockets = new HashSet(8);
|
Set sockets = new HashSet(8);
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
sockets.addAll(_inSockets.values());
|
sockets.addAll(_inSockets.values());
|
||||||
sockets.addAll(_outSockets.values());
|
sockets.addAll(_outSockets.values());
|
||||||
}
|
}
|
||||||
return sockets;
|
return sockets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ping the specified peer, returning true if they replied to the ping within
|
* Ping the specified peer, returning true if they replied to the ping within
|
||||||
* the timeout specified, false otherwise. This call blocks.
|
* the timeout specified, false otherwise. This call blocks.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public boolean ping(Destination peer, long timeoutMs) {
|
public boolean ping(Destination peer, long timeoutMs) {
|
||||||
try {
|
try {
|
||||||
return _session.sendMessage(peer, new byte[] {(byte)0xFF});
|
return _session.sendMessage(peer, new byte[] { (byte) 0xFF});
|
||||||
} catch (I2PException ex) {
|
} catch (I2PException ex) {
|
||||||
_log.error("I2PException:",ex);
|
_log.error("I2PException:", ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeSocket(I2PSocketImpl sock) {
|
public void removeSocket(I2PSocketImpl sock) {
|
||||||
synchronized(lock) {
|
synchronized (lock) {
|
||||||
_inSockets.remove(sock.getLocalID());
|
_inSockets.remove(sock.getLocalID());
|
||||||
_outSockets.remove(sock.getLocalID());
|
_outSockets.remove(sock.getLocalID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getReadableForm(String id) {
|
public static String getReadableForm(String id) {
|
||||||
try {
|
try {
|
||||||
if (id.length() != 3) return "Bogus";
|
if (id.length() != 3) return "Bogus";
|
||||||
return Base64.encode(id.getBytes("ISO-8859-1"));
|
return Base64.encode(id.getBytes("ISO-8859-1"));
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -345,21 +340,21 @@ public class I2PSocketManager implements I2PSessionListener {
|
|||||||
* @param uniqueIn map of already known local IDs so we don't collide. WARNING - NOT THREADSAFE!
|
* @param uniqueIn map of already known local IDs so we don't collide. WARNING - NOT THREADSAFE!
|
||||||
*/
|
*/
|
||||||
public static String makeID(HashMap uniqueIn) {
|
public static String makeID(HashMap uniqueIn) {
|
||||||
String newID;
|
String newID;
|
||||||
try {
|
try {
|
||||||
do {
|
do {
|
||||||
int id = (int)(Math.random()*16777215+1);
|
int id = (int) (Math.random() * 16777215 + 1);
|
||||||
byte[] nid = new byte[3];
|
byte[] nid = new byte[3];
|
||||||
nid[0]=(byte)(id / 65536);
|
nid[0] = (byte) (id / 65536);
|
||||||
nid[1] = (byte)((id/256) % 256);
|
nid[1] = (byte) ((id / 256) % 256);
|
||||||
nid[2]= (byte)(id %256);
|
nid[2] = (byte) (id % 256);
|
||||||
newID = new String(nid, "ISO-8859-1");
|
newID = new String(nid, "ISO-8859-1");
|
||||||
} while (uniqueIn.get(newID) != null);
|
} while (uniqueIn.get(newID) != null);
|
||||||
return newID;
|
return newID;
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -367,20 +362,17 @@ public class I2PSocketManager implements I2PSessionListener {
|
|||||||
* the given payload
|
* the given payload
|
||||||
*/
|
*/
|
||||||
public static byte[] makePacket(byte type, String id, byte[] payload) {
|
public static byte[] makePacket(byte type, String id, byte[] payload) {
|
||||||
try {
|
try {
|
||||||
byte[] packet = new byte[payload.length+4];
|
byte[] packet = new byte[payload.length + 4];
|
||||||
packet[0]=type;
|
packet[0] = type;
|
||||||
byte[] temp = id.getBytes("ISO-8859-1");
|
byte[] temp = id.getBytes("ISO-8859-1");
|
||||||
if (temp.length != 3)
|
if (temp.length != 3) throw new RuntimeException("Incorrect ID length: " + temp.length);
|
||||||
throw new RuntimeException("Incorrect ID length: "+
|
System.arraycopy(temp, 0, packet, 1, 3);
|
||||||
temp.length);
|
System.arraycopy(payload, 0, packet, 4, payload.length);
|
||||||
System.arraycopy(temp,0,packet,1,3);
|
return packet;
|
||||||
System.arraycopy(payload,0,packet,4,payload.length);
|
} catch (UnsupportedEncodingException ex) {
|
||||||
return packet;
|
if (_log.shouldLog(Log.ERROR)) _log.error("Error building the packet", ex);
|
||||||
} catch (UnsupportedEncodingException ex) {
|
return new byte[0];
|
||||||
if (_log.shouldLog(Log.ERROR))
|
}
|
||||||
_log.error("Error building the packet", ex);
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ import net.i2p.util.Log;
|
|||||||
*/
|
*/
|
||||||
public class I2PSocketManagerFactory {
|
public class I2PSocketManagerFactory {
|
||||||
private final static Log _log = new Log(I2PSocketManagerFactory.class);
|
private final static Log _log = new Log(I2PSocketManagerFactory.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a socket manager using a brand new destination connected to the
|
* Create a socket manager using a brand new destination connected to the
|
||||||
* I2CP router on the local machine on the default port (7654).
|
* I2CP router on the local machine on the default port (7654).
|
||||||
@ -30,9 +30,9 @@ public class I2PSocketManagerFactory {
|
|||||||
* @return the newly created socket manager, or null if there were errors
|
* @return the newly created socket manager, or null if there were errors
|
||||||
*/
|
*/
|
||||||
public static I2PSocketManager createManager() {
|
public static I2PSocketManager createManager() {
|
||||||
return createManager("localhost", 7654, new Properties());
|
return createManager("localhost", 7654, new Properties());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a socket manager using a brand new destination connected to the
|
* Create a socket manager using a brand new destination connected to the
|
||||||
* I2CP router on the given machine reachable through the given port.
|
* I2CP router on the given machine reachable through the given port.
|
||||||
@ -40,21 +40,21 @@ public class I2PSocketManagerFactory {
|
|||||||
* @return the newly created socket manager, or null if there were errors
|
* @return the newly created socket manager, or null if there were errors
|
||||||
*/
|
*/
|
||||||
public static I2PSocketManager createManager(String i2cpHost, int i2cpPort, Properties opts) {
|
public static I2PSocketManager createManager(String i2cpHost, int i2cpPort, Properties opts) {
|
||||||
I2PClient client = I2PClientFactory.createClient();
|
I2PClient client = I2PClientFactory.createClient();
|
||||||
ByteArrayOutputStream keyStream = new ByteArrayOutputStream(512);
|
ByteArrayOutputStream keyStream = new ByteArrayOutputStream(512);
|
||||||
try {
|
try {
|
||||||
Destination dest = client.createDestination(keyStream);
|
Destination dest = client.createDestination(keyStream);
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(keyStream.toByteArray());
|
ByteArrayInputStream in = new ByteArrayInputStream(keyStream.toByteArray());
|
||||||
return createManager(in, i2cpHost, i2cpPort, opts);
|
return createManager(in, i2cpHost, i2cpPort, opts);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
_log.error("Error creating the destination for socket manager", ioe);
|
_log.error("Error creating the destination for socket manager", ioe);
|
||||||
return null;
|
return null;
|
||||||
} catch (I2PException ie) {
|
} catch (I2PException ie) {
|
||||||
_log.error("Error creating the destination for socket manager", ie);
|
_log.error("Error creating the destination for socket manager", ie);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a socket manager using the destination loaded from the given private key
|
* Create a socket manager using the destination loaded from the given private key
|
||||||
* stream and connected to the I2CP router on the specified machine on the given
|
* stream and connected to the I2CP router on the specified machine on the given
|
||||||
@ -62,24 +62,25 @@ public class I2PSocketManagerFactory {
|
|||||||
*
|
*
|
||||||
* @return the newly created socket manager, or null if there were errors
|
* @return the newly created socket manager, or null if there were errors
|
||||||
*/
|
*/
|
||||||
public static I2PSocketManager createManager(InputStream myPrivateKeyStream, String i2cpHost, int i2cpPort, Properties opts) {
|
public static I2PSocketManager createManager(InputStream myPrivateKeyStream, String i2cpHost, int i2cpPort,
|
||||||
I2PClient client = I2PClientFactory.createClient();
|
Properties opts) {
|
||||||
opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED);
|
I2PClient client = I2PClientFactory.createClient();
|
||||||
opts.setProperty(I2PClient.PROP_TCP_HOST, i2cpHost);
|
opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED);
|
||||||
opts.setProperty(I2PClient.PROP_TCP_PORT, ""+i2cpPort);
|
opts.setProperty(I2PClient.PROP_TCP_HOST, i2cpHost);
|
||||||
try {
|
opts.setProperty(I2PClient.PROP_TCP_PORT, "" + i2cpPort);
|
||||||
I2PSession session = client.createSession(myPrivateKeyStream, opts);
|
try {
|
||||||
session.connect();
|
I2PSession session = client.createSession(myPrivateKeyStream, opts);
|
||||||
return createManager(session);
|
session.connect();
|
||||||
} catch (I2PSessionException ise) {
|
return createManager(session);
|
||||||
_log.error("Error creating session for socket manager", ise);
|
} catch (I2PSessionException ise) {
|
||||||
return null;
|
_log.error("Error creating session for socket manager", ise);
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static I2PSocketManager createManager(I2PSession session) {
|
private static I2PSocketManager createManager(I2PSession session) {
|
||||||
I2PSocketManager mgr = new I2PSocketManager();
|
I2PSocketManager mgr = new I2PSocketManager();
|
||||||
mgr.setSession(session);
|
mgr.setSession(session);
|
||||||
return mgr;
|
return mgr;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,15 +7,21 @@ package net.i2p.client.streaming;
|
|||||||
*/
|
*/
|
||||||
public class I2PSocketOptions {
|
public class I2PSocketOptions {
|
||||||
private long _connectTimeout;
|
private long _connectTimeout;
|
||||||
|
|
||||||
public I2PSocketOptions() {
|
public I2PSocketOptions() {
|
||||||
_connectTimeout = -1;
|
_connectTimeout = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How long we will wait for the ACK from a SYN, in milliseconds.
|
* How long we will wait for the ACK from a SYN, in milliseconds.
|
||||||
*
|
*
|
||||||
* @return milliseconds to wait, or -1 if we will wait indefinitely
|
* @return milliseconds to wait, or -1 if we will wait indefinitely
|
||||||
*/
|
*/
|
||||||
public long getConnectTimeout() { return _connectTimeout; }
|
public long getConnectTimeout() {
|
||||||
public void setConnectTimeout(long ms) { _connectTimeout = ms; }
|
return _connectTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setConnectTimeout(long ms) {
|
||||||
|
_connectTimeout = ms;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
package net.i2p.phttprelay;
|
package net.i2p.phttprelay;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free (adj.): unencumbered; not under the control of others
|
* free (adj.): unencumbered; not under the control of others
|
||||||
* Written by jrandom in 2003 and released into the public domain
|
* Written by jrandom in 2003 and released into the public domain
|
||||||
@ -44,70 +45,70 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
*/
|
*/
|
||||||
public class CheckSendStatusServlet extends PHTTPRelayServlet {
|
public class CheckSendStatusServlet extends PHTTPRelayServlet {
|
||||||
/* URL parameters on the check */
|
/* URL parameters on the check */
|
||||||
|
|
||||||
/** H(routerIdent).toBase64() of the target to receive the message */
|
/** H(routerIdent).toBase64() of the target to receive the message */
|
||||||
public final static String PARAM_SEND_TARGET = "target";
|
public final static String PARAM_SEND_TARGET = "target";
|
||||||
/** msgId parameter */
|
/** msgId parameter */
|
||||||
public final static String PARAM_MSG_ID = "msgId";
|
public final static String PARAM_MSG_ID = "msgId";
|
||||||
|
|
||||||
public final static String PROP_STATUS = "status";
|
public final static String PROP_STATUS = "status";
|
||||||
public final static String STATUS_PENDING = "pending";
|
public final static String STATUS_PENDING = "pending";
|
||||||
public final static String STATUS_UNKNOWN = "unknown";
|
public final static String STATUS_UNKNOWN = "unknown";
|
||||||
|
|
||||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
String target = req.getParameter(PARAM_SEND_TARGET);
|
String target = req.getParameter(PARAM_SEND_TARGET);
|
||||||
String msgIdStr = req.getParameter(PARAM_MSG_ID);
|
String msgIdStr = req.getParameter(PARAM_MSG_ID);
|
||||||
|
|
||||||
log("Checking status of [" + target + "] message [" + msgIdStr + "]");
|
log("Checking status of [" + target + "] message [" + msgIdStr + "]");
|
||||||
if (!isKnownMessage(target, msgIdStr)) {
|
if (!isKnownMessage(target, msgIdStr)) {
|
||||||
log("Not known - its not pending");
|
log("Not known - its not pending");
|
||||||
notPending(req, resp);
|
notPending(req, resp);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
log("Known - its still pending");
|
log("Known - its still pending");
|
||||||
pending(req, resp);
|
pending(req, resp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isKnownMessage(String target, String msgId) throws IOException {
|
private boolean isKnownMessage(String target, String msgId) throws IOException {
|
||||||
if ( (target == null) || (target.trim().length() <= 0) ) return false;
|
if ((target == null) || (target.trim().length() <= 0)) return false;
|
||||||
if ( (msgId == null) || (msgId.trim().length() <= 0) ) return false;
|
if ((msgId == null) || (msgId.trim().length() <= 0)) return false;
|
||||||
File identDir = getIdentDir(target);
|
File identDir = getIdentDir(target);
|
||||||
if (identDir.exists()) {
|
if (identDir.exists()) {
|
||||||
File identFile = new File(identDir, "identity.dat");
|
File identFile = new File(identDir, "identity.dat");
|
||||||
if (identFile.exists()) {
|
if (identFile.exists()) {
|
||||||
// known and valid (maybe we need to check the file format... naw, fuck it
|
// known and valid (maybe we need to check the file format... naw, fuck it
|
||||||
File msgFile = new File(identDir, "msg" + msgId + ".dat");
|
File msgFile = new File(identDir, "msg" + msgId + ".dat");
|
||||||
if (msgFile.exists())
|
if (msgFile.exists())
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pending(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
private void pending(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
resp.setStatus(HttpServletResponse.SC_OK);
|
resp.setStatus(HttpServletResponse.SC_OK);
|
||||||
ServletOutputStream out = resp.getOutputStream();
|
ServletOutputStream out = resp.getOutputStream();
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append(PROP_STATUS).append('=').append(STATUS_PENDING).append('\n');
|
buf.append(PROP_STATUS).append('=').append(STATUS_PENDING).append('\n');
|
||||||
out.write(buf.toString().getBytes());
|
out.write(buf.toString().getBytes());
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notPending(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
private void notPending(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
resp.setStatus(HttpServletResponse.SC_OK);
|
resp.setStatus(HttpServletResponse.SC_OK);
|
||||||
ServletOutputStream out = resp.getOutputStream();
|
ServletOutputStream out = resp.getOutputStream();
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append(PROP_STATUS).append('=').append(STATUS_UNKNOWN).append('\n');
|
buf.append(PROP_STATUS).append('=').append(STATUS_UNKNOWN).append('\n');
|
||||||
out.write(buf.toString().getBytes());
|
out.write(buf.toString().getBytes());
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
package net.i2p.phttprelay;
|
package net.i2p.phttprelay;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free (adj.): unencumbered; not under the control of others
|
* free (adj.): unencumbered; not under the control of others
|
||||||
* Written by jrandom in 2003 and released into the public domain
|
* Written by jrandom in 2003 and released into the public domain
|
||||||
@ -18,23 +19,26 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
class LockManager {
|
class LockManager {
|
||||||
private volatile static Set _locks = new HashSet(); // target
|
private volatile static Set _locks = new HashSet(); // target
|
||||||
|
|
||||||
public static void lockIdent(String target) {
|
public static void lockIdent(String target) {
|
||||||
while (true) {
|
while (true) {
|
||||||
synchronized (_locks) {
|
synchronized (_locks) {
|
||||||
if (!_locks.contains(target)) {
|
if (!_locks.contains(target)) {
|
||||||
_locks.add(target);
|
_locks.add(target);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try { _locks.wait(1000); } catch (InterruptedException ie) {}
|
try {
|
||||||
}
|
_locks.wait(1000);
|
||||||
}
|
} catch (InterruptedException ie) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void unlockIdent(String target) {
|
public static void unlockIdent(String target) {
|
||||||
synchronized (_locks) {
|
synchronized (_locks) {
|
||||||
_locks.remove(target);
|
_locks.remove(target);
|
||||||
_locks.notifyAll();
|
_locks.notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
package net.i2p.phttprelay;
|
package net.i2p.phttprelay;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free (adj.): unencumbered; not under the control of others
|
* free (adj.): unencumbered; not under the control of others
|
||||||
* Written by jrandom in 2003 and released into the public domain
|
* Written by jrandom in 2003 and released into the public domain
|
||||||
@ -25,49 +26,50 @@ abstract class PHTTPRelayServlet extends HttpServlet {
|
|||||||
/* config params */
|
/* config params */
|
||||||
/*public final static String PARAM_BASEDIR = "baseDir";*/
|
/*public final static String PARAM_BASEDIR = "baseDir";*/
|
||||||
public final static String ENV_BASEDIR = "phttpRelay.baseDir";
|
public final static String ENV_BASEDIR = "phttpRelay.baseDir";
|
||||||
|
|
||||||
/** match the clock fudge factor on the router, rather than importing the entire router cvs module */
|
/** match the clock fudge factor on the router, rather than importing the entire router cvs module */
|
||||||
public final static long CLOCK_FUDGE_FACTOR = 1*60*1000;
|
public final static long CLOCK_FUDGE_FACTOR = 1 * 60 * 1000;
|
||||||
|
|
||||||
protected String buildURL(HttpServletRequest req, String path) {
|
protected String buildURL(HttpServletRequest req, String path) {
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append(req.getScheme()).append("://");
|
buf.append(req.getScheme()).append("://");
|
||||||
buf.append(req.getServerName()).append(":").append(req.getServerPort());
|
buf.append(req.getServerName()).append(":").append(req.getServerPort());
|
||||||
buf.append(req.getContextPath());
|
buf.append(req.getContextPath());
|
||||||
buf.append(path);
|
buf.append(path);
|
||||||
log("URL built: " + buf.toString());
|
log("URL built: " + buf.toString());
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected File getIdentDir(String target) throws IOException {
|
protected File getIdentDir(String target) throws IOException {
|
||||||
if ( (_baseDir == null) || (target == null) ) throw new IOException("dir not specified to deal with");
|
if ((_baseDir == null) || (target == null)) throw new IOException("dir not specified to deal with");
|
||||||
File baseDir = new File(_baseDir);
|
File baseDir = new File(_baseDir);
|
||||||
if (!baseDir.exists()) {
|
if (!baseDir.exists()) {
|
||||||
boolean created = baseDir.mkdirs();
|
boolean created = baseDir.mkdirs();
|
||||||
log("Creating PHTTP Relay Base Directory: " + baseDir.getAbsolutePath() + " - ok? " + created);
|
log("Creating PHTTP Relay Base Directory: " + baseDir.getAbsolutePath() + " - ok? " + created);
|
||||||
}
|
}
|
||||||
File identDir = new File(baseDir, target);
|
File identDir = new File(baseDir, target);
|
||||||
log("Ident dir: " + identDir.getAbsolutePath());
|
log("Ident dir: " + identDir.getAbsolutePath());
|
||||||
return identDir;
|
return identDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(ServletConfig config) throws ServletException {
|
public void init(ServletConfig config) throws ServletException {
|
||||||
super.init(config);
|
super.init(config);
|
||||||
String dir = System.getProperty(ENV_BASEDIR);
|
String dir = System.getProperty(ENV_BASEDIR);
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
_log.warn("Base directory for the polling http relay system not in the environment [" + ENV_BASEDIR +"]");
|
_log.warn("Base directory for the polling http relay system not in the environment [" + ENV_BASEDIR + "]");
|
||||||
_log.warn("Setting the base directory to ./relayDir for " + getServletName());
|
_log.warn("Setting the base directory to ./relayDir for " + getServletName());
|
||||||
_baseDir = ".relayDir";
|
_baseDir = ".relayDir";
|
||||||
} else {
|
} else {
|
||||||
_baseDir = dir;
|
_baseDir = dir;
|
||||||
log("Loaded up " + getServletName() + " with base directory " + _baseDir);
|
log("Loaded up " + getServletName() + " with base directory " + _baseDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(String msg) {
|
public void log(String msg) {
|
||||||
_log.debug(msg);
|
_log.debug(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(String msg, Throwable t) {
|
public void log(String msg, Throwable t) {
|
||||||
_log.debug(msg, t);
|
_log.debug(msg, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
package net.i2p.phttprelay;
|
package net.i2p.phttprelay;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free (adj.): unencumbered; not under the control of others
|
* free (adj.): unencumbered; not under the control of others
|
||||||
* Written by jrandom in 2003 and released into the public domain
|
* Written by jrandom in 2003 and released into the public domain
|
||||||
@ -55,209 +56,208 @@ import net.i2p.util.Clock;
|
|||||||
* baseDir is the directory under which registrants and their pending messages are stored
|
* baseDir is the directory under which registrants and their pending messages are stored
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class PollServlet extends PHTTPRelayServlet {
|
public class PollServlet extends PHTTPRelayServlet {
|
||||||
/* URL parameters on the check */
|
/* URL parameters on the check */
|
||||||
|
|
||||||
/** H(routerIdent).toBase64() of the target to receive the message */
|
/** H(routerIdent).toBase64() of the target to receive the message */
|
||||||
public final static String PARAM_SEND_TARGET = "target";
|
public final static String PARAM_SEND_TARGET = "target";
|
||||||
|
|
||||||
/** HTTP error code if the target is not known*/
|
/** HTTP error code if the target is not known*/
|
||||||
public final static int CODE_UNKNOWN = HttpServletResponse.SC_NOT_FOUND;
|
public final static int CODE_UNKNOWN = HttpServletResponse.SC_NOT_FOUND;
|
||||||
/** HTTP error code if the signature failed */
|
/** HTTP error code if the signature failed */
|
||||||
public final static int CODE_UNAUTHORIZED = HttpServletResponse.SC_UNAUTHORIZED;
|
public final static int CODE_UNAUTHORIZED = HttpServletResponse.SC_UNAUTHORIZED;
|
||||||
/** HTTP error code if everything is ok */
|
/** HTTP error code if everything is ok */
|
||||||
public final static int CODE_OK = HttpServletResponse.SC_OK;
|
public final static int CODE_OK = HttpServletResponse.SC_OK;
|
||||||
|
|
||||||
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
byte data[] = getData(req);
|
byte data[] = getData(req);
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||||
String target = getTarget(bais);
|
String target = getTarget(bais);
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
log("Target not specified");
|
log("Target not specified");
|
||||||
resp.sendError(CODE_UNKNOWN);
|
resp.sendError(CODE_UNKNOWN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isKnown(target)) {
|
if (!isKnown(target)) {
|
||||||
resp.sendError(CODE_UNKNOWN);
|
resp.sendError(CODE_UNKNOWN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAuthorized(target, bais)) {
|
if (!isAuthorized(target, bais)) {
|
||||||
resp.sendError(CODE_UNAUTHORIZED);
|
resp.sendError(CODE_UNAUTHORIZED);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
log("Authorized access for target " + target);
|
log("Authorized access for target " + target);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessages(resp, target);
|
sendMessages(resp, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getData(HttpServletRequest req) throws ServletException, IOException {
|
private byte[] getData(HttpServletRequest req) throws ServletException, IOException {
|
||||||
ServletInputStream in = req.getInputStream();
|
ServletInputStream in = req.getInputStream();
|
||||||
int len = req.getContentLength();
|
int len = req.getContentLength();
|
||||||
byte data[] = new byte[len];
|
byte data[] = new byte[len];
|
||||||
int cur = 0;
|
int cur = 0;
|
||||||
int read = DataHelper.read(in, data);
|
int read = DataHelper.read(in, data);
|
||||||
if (read != len) {
|
if (read != len) {
|
||||||
log("Size read is incorrect [" + read + " instead of expected " + len + "]");
|
log("Size read is incorrect [" + read + " instead of expected " + len + "]");
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
log("Read data length: " + data.length + " in base64: " + Base64.encode(data));
|
log("Read data length: " + data.length + " in base64: " + Base64.encode(data));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTarget(InputStream in) throws IOException {
|
private String getTarget(InputStream in) throws IOException {
|
||||||
StringBuffer buf = new StringBuffer(64);
|
StringBuffer buf = new StringBuffer(64);
|
||||||
int numBytes = 0;
|
int numBytes = 0;
|
||||||
int c = 0;
|
int c = 0;
|
||||||
while ( (c = in.read()) != -1) {
|
while ((c = in.read()) != -1) {
|
||||||
if (c == (int)'&') break;
|
if (c == (int) '&') break;
|
||||||
buf.append((char)c);
|
buf.append((char) c);
|
||||||
numBytes++;
|
numBytes++;
|
||||||
if (numBytes > 128) {
|
if (numBytes > 128) {
|
||||||
log("Target didn't find the & after 128 bytes [" + buf.toString() + "]");
|
log("Target didn't find the & after 128 bytes [" + buf.toString() + "]");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (buf.toString().indexOf("target=") != 0) {
|
if (buf.toString().indexOf("target=") != 0) {
|
||||||
log("Did not start with target= [" + buf.toString() + "]");
|
log("Did not start with target= [" + buf.toString() + "]");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return buf.substring("target=".length());
|
return buf.substring("target=".length());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessages(HttpServletResponse resp, String target) throws IOException {
|
private void sendMessages(HttpServletResponse resp, String target) throws IOException {
|
||||||
log("Before lock " + target);
|
log("Before lock " + target);
|
||||||
LockManager.lockIdent(target);
|
LockManager.lockIdent(target);
|
||||||
log("Locked " + target);
|
log("Locked " + target);
|
||||||
try {
|
try {
|
||||||
File identDir = getIdentDir(target);
|
File identDir = getIdentDir(target);
|
||||||
expire(identDir);
|
expire(identDir);
|
||||||
File messageFiles[] = identDir.listFiles();
|
File messageFiles[] = identDir.listFiles();
|
||||||
resp.setStatus(CODE_OK);
|
resp.setStatus(CODE_OK);
|
||||||
log("Sending back " + (messageFiles.length -1) + " messages");
|
log("Sending back " + (messageFiles.length - 1) + " messages");
|
||||||
ServletOutputStream out = resp.getOutputStream();
|
ServletOutputStream out = resp.getOutputStream();
|
||||||
DataHelper.writeDate(out, new Date(Clock.getInstance().now()));
|
DataHelper.writeDate(out, new Date(Clock.getInstance().now()));
|
||||||
DataHelper.writeLong(out, 2, messageFiles.length -1);
|
DataHelper.writeLong(out, 2, messageFiles.length - 1);
|
||||||
for (int i = 0; i < messageFiles.length; i++) {
|
for (int i = 0; i < messageFiles.length; i++) {
|
||||||
if ("identity.dat".equals(messageFiles[i].getName())) {
|
if ("identity.dat".equals(messageFiles[i].getName())) {
|
||||||
// skip
|
// skip
|
||||||
} else {
|
} else {
|
||||||
log("Message file " + messageFiles[i].getName() + " is " + messageFiles[i].length() + " bytes");
|
log("Message file " + messageFiles[i].getName() + " is " + messageFiles[i].length() + " bytes");
|
||||||
DataHelper.writeLong(out, 4, messageFiles[i].length());
|
DataHelper.writeLong(out, 4, messageFiles[i].length());
|
||||||
writeFile(out, messageFiles[i]);
|
writeFile(out, messageFiles[i]);
|
||||||
boolean deleted = messageFiles[i].delete();
|
boolean deleted = messageFiles[i].delete();
|
||||||
if (!deleted) {
|
if (!deleted) {
|
||||||
log("!!!Error removing message file " + messageFiles[i].getAbsolutePath() + " - please delete!");
|
log("!!!Error removing message file " + messageFiles[i].getAbsolutePath() + " - please delete!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
log("Error sending message", dfe);
|
log("Error sending message", dfe);
|
||||||
} finally {
|
} finally {
|
||||||
LockManager.unlockIdent(target);
|
LockManager.unlockIdent(target);
|
||||||
log("Unlocked " + target);
|
log("Unlocked " + target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static long EXPIRE_DELAY = 60*1000; // expire messages every minute
|
private final static long EXPIRE_DELAY = 60 * 1000; // expire messages every minute
|
||||||
|
|
||||||
private void expire(File identDir) throws IOException {
|
private void expire(File identDir) throws IOException {
|
||||||
File files[] = identDir.listFiles();
|
File files[] = identDir.listFiles();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for (int i = 0 ; i < files.length; i++) {
|
for (int i = 0; i < files.length; i++) {
|
||||||
if ("identity.dat".equals(files[i].getName())) {
|
if ("identity.dat".equals(files[i].getName())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (files[i].lastModified() + EXPIRE_DELAY < now) {
|
if (files[i].lastModified() + EXPIRE_DELAY < now) {
|
||||||
log("Expiring " + files[i].getAbsolutePath());
|
log("Expiring " + files[i].getAbsolutePath());
|
||||||
files[i].delete();
|
files[i].delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeFile(ServletOutputStream out, File file) throws IOException {
|
private void writeFile(ServletOutputStream out, File file) throws IOException {
|
||||||
FileInputStream fis = new FileInputStream(file);
|
FileInputStream fis = new FileInputStream(file);
|
||||||
try {
|
try {
|
||||||
byte buf[] = new byte[4096];
|
byte buf[] = new byte[4096];
|
||||||
while (true) {
|
while (true) {
|
||||||
int read = DataHelper.read(fis, buf);
|
int read = DataHelper.read(fis, buf);
|
||||||
if (read > 0)
|
if (read > 0)
|
||||||
out.write(buf, 0, read);
|
out.write(buf, 0, read);
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
fis.close();
|
fis.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean isKnown(String target) throws IOException {
|
private boolean isKnown(String target) throws IOException {
|
||||||
File identDir = getIdentDir(target);
|
File identDir = getIdentDir(target);
|
||||||
if (identDir.exists()) {
|
if (identDir.exists()) {
|
||||||
File identFile = new File(identDir, "identity.dat");
|
File identFile = new File(identDir, "identity.dat");
|
||||||
if (identFile.exists()) {
|
if (identFile.exists()) {
|
||||||
// known and valid (maybe we need to check the file format... naw, fuck it
|
// known and valid (maybe we need to check the file format... naw, fuck it
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAuthorized(String target, InputStream in) throws IOException {
|
private boolean isAuthorized(String target, InputStream in) throws IOException {
|
||||||
RouterIdentity ident = null;
|
RouterIdentity ident = null;
|
||||||
try {
|
try {
|
||||||
ident = getRouterIdentity(target);
|
ident = getRouterIdentity(target);
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
log("Identity was not valid", dfe);
|
log("Identity was not valid", dfe);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ident == null) {
|
if (ident == null) {
|
||||||
log("Identity not registered");
|
log("Identity not registered");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long val = DataHelper.readLong(in, 4);
|
long val = DataHelper.readLong(in, 4);
|
||||||
Signature sig = new Signature();
|
Signature sig = new Signature();
|
||||||
sig.readBytes(in);
|
sig.readBytes(in);
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
DataHelper.writeLong(baos, 4, val);
|
DataHelper.writeLong(baos, 4, val);
|
||||||
if (DSAEngine.getInstance().verifySignature(sig, baos.toByteArray(), ident.getSigningPublicKey())) {
|
if (DSAEngine.getInstance().verifySignature(sig, baos.toByteArray(), ident.getSigningPublicKey())) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
log("Signature does NOT match");
|
log("Signature does NOT match");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
log("Format error reading the nonce and signature", dfe);
|
log("Format error reading the nonce and signature", dfe);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RouterIdentity getRouterIdentity(String target) throws IOException, DataFormatException {
|
private RouterIdentity getRouterIdentity(String target) throws IOException, DataFormatException {
|
||||||
File identDir = getIdentDir(target);
|
File identDir = getIdentDir(target);
|
||||||
if (identDir.exists()) {
|
if (identDir.exists()) {
|
||||||
File identFile = new File(identDir, "identity.dat");
|
File identFile = new File(identDir, "identity.dat");
|
||||||
if (identFile.exists()) {
|
if (identFile.exists()) {
|
||||||
// known and valid (maybe we need to check the file format... naw, fuck it
|
// known and valid (maybe we need to check the file format... naw, fuck it
|
||||||
RouterIdentity ident = new RouterIdentity();
|
RouterIdentity ident = new RouterIdentity();
|
||||||
ident.readBytes(new FileInputStream(identFile));
|
ident.readBytes(new FileInputStream(identFile));
|
||||||
return ident;
|
return ident;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
package net.i2p.phttprelay;
|
package net.i2p.phttprelay;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free (adj.): unencumbered; not under the control of others
|
* free (adj.): unencumbered; not under the control of others
|
||||||
* Written by jrandom in 2003 and released into the public domain
|
* Written by jrandom in 2003 and released into the public domain
|
||||||
@ -66,89 +67,92 @@ public class RegisterServlet extends PHTTPRelayServlet {
|
|||||||
/* config params */
|
/* config params */
|
||||||
public final static String PARAM_POLL_PATH = "pollPath";
|
public final static String PARAM_POLL_PATH = "pollPath";
|
||||||
public final static String PARAM_SEND_PATH = "sendPath";
|
public final static String PARAM_SEND_PATH = "sendPath";
|
||||||
|
|
||||||
/* key=val keys sent back on registration */
|
/* key=val keys sent back on registration */
|
||||||
public final static String PROP_STATUS = "status";
|
public final static String PROP_STATUS = "status";
|
||||||
public final static String PROP_POLL_URL = "pollURL";
|
public final static String PROP_POLL_URL = "pollURL";
|
||||||
public final static String PROP_SEND_URL = "sendURL";
|
public final static String PROP_SEND_URL = "sendURL";
|
||||||
public final static String PROP_TIME_OFFSET = "timeOffset"; // ms (local-remote)
|
public final static String PROP_TIME_OFFSET = "timeOffset"; // ms (local-remote)
|
||||||
|
|
||||||
/* values for the PROP_STATUS */
|
/* values for the PROP_STATUS */
|
||||||
public final static String STATUS_FAILED = "failed";
|
public final static String STATUS_FAILED = "failed";
|
||||||
public final static String STATUS_REGISTERED = "registered";
|
public final static String STATUS_REGISTERED = "registered";
|
||||||
|
|
||||||
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
|
||||||
ServletInputStream in = req.getInputStream();
|
|
||||||
RouterIdentity ident = new RouterIdentity();
|
|
||||||
try {
|
|
||||||
Date remoteTime = DataHelper.readDate(in);
|
|
||||||
long skew = getSkew(remoteTime);
|
|
||||||
ident.readBytes(in);
|
|
||||||
boolean ok = registerIdent(ident);
|
|
||||||
sendURLs(req, resp, skew, ok);
|
|
||||||
} catch (DataFormatException dfe) {
|
|
||||||
log("Invalid format for router identity posted", dfe);
|
|
||||||
} finally {
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getSkew(Date remoteDate) {
|
|
||||||
if (remoteDate == null) {
|
|
||||||
log("*ERROR: remote date was null");
|
|
||||||
return Long.MAX_VALUE;
|
|
||||||
} else {
|
|
||||||
long diff = Clock.getInstance().now() - remoteDate.getTime();
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean registerIdent(RouterIdentity ident) throws DataFormatException, IOException {
|
|
||||||
File identDir = getIdentDir(ident.getHash().toBase64());
|
|
||||||
boolean created = identDir.mkdirs();
|
|
||||||
File identFile = new File(identDir, "identity.dat");
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
try {
|
|
||||||
fos = new FileOutputStream(identFile);
|
|
||||||
ident.writeBytes(fos);
|
|
||||||
} finally {
|
|
||||||
if (fos != null) try { fos.close(); } catch (IOException ioe) {}
|
|
||||||
}
|
|
||||||
log("Identity registered into " + identFile.getAbsolutePath());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendURLs(HttpServletRequest req, HttpServletResponse resp, long skew, boolean ok) throws IOException {
|
|
||||||
ServletOutputStream out = resp.getOutputStream();
|
|
||||||
|
|
||||||
log("*Debug: clock skew of " + skew + "ms (local-remote)");
|
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
ServletInputStream in = req.getInputStream();
|
||||||
StringBuffer buf = new StringBuffer();
|
RouterIdentity ident = new RouterIdentity();
|
||||||
if (ok) {
|
try {
|
||||||
buf.append(PROP_POLL_URL).append("=").append(buildURL(req, _pollPath)).append("\n");
|
Date remoteTime = DataHelper.readDate(in);
|
||||||
buf.append(PROP_SEND_URL).append("=").append(buildURL(req, _sendPath)).append("\n");
|
long skew = getSkew(remoteTime);
|
||||||
buf.append(PROP_TIME_OFFSET).append("=").append(skew).append("\n");
|
ident.readBytes(in);
|
||||||
buf.append(PROP_STATUS).append("=").append(STATUS_REGISTERED).append("\n");
|
boolean ok = registerIdent(ident);
|
||||||
} else {
|
sendURLs(req, resp, skew, ok);
|
||||||
buf.append(PROP_TIME_OFFSET).append("=").append(skew).append("\n");
|
} catch (DataFormatException dfe) {
|
||||||
buf.append(PROP_STATUS).append("=").append(STATUS_FAILED).append("\n");
|
log("Invalid format for router identity posted", dfe);
|
||||||
}
|
} finally {
|
||||||
out.write(buf.toString().getBytes());
|
in.close();
|
||||||
out.close();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getSkew(Date remoteDate) {
|
||||||
|
if (remoteDate == null) {
|
||||||
|
log("*ERROR: remote date was null");
|
||||||
|
return Long.MAX_VALUE;
|
||||||
|
} else {
|
||||||
|
long diff = Clock.getInstance().now() - remoteDate.getTime();
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean registerIdent(RouterIdentity ident) throws DataFormatException, IOException {
|
||||||
|
File identDir = getIdentDir(ident.getHash().toBase64());
|
||||||
|
boolean created = identDir.mkdirs();
|
||||||
|
File identFile = new File(identDir, "identity.dat");
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fos = new FileOutputStream(identFile);
|
||||||
|
ident.writeBytes(fos);
|
||||||
|
} finally {
|
||||||
|
if (fos != null) try {
|
||||||
|
fos.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log("Identity registered into " + identFile.getAbsolutePath());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendURLs(HttpServletRequest req, HttpServletResponse resp, long skew, boolean ok) throws IOException {
|
||||||
|
ServletOutputStream out = resp.getOutputStream();
|
||||||
|
|
||||||
|
log("*Debug: clock skew of " + skew + "ms (local-remote)");
|
||||||
|
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
if (ok) {
|
||||||
|
buf.append(PROP_POLL_URL).append("=").append(buildURL(req, _pollPath)).append("\n");
|
||||||
|
buf.append(PROP_SEND_URL).append("=").append(buildURL(req, _sendPath)).append("\n");
|
||||||
|
buf.append(PROP_TIME_OFFSET).append("=").append(skew).append("\n");
|
||||||
|
buf.append(PROP_STATUS).append("=").append(STATUS_REGISTERED).append("\n");
|
||||||
|
} else {
|
||||||
|
buf.append(PROP_TIME_OFFSET).append("=").append(skew).append("\n");
|
||||||
|
buf.append(PROP_STATUS).append("=").append(STATUS_FAILED).append("\n");
|
||||||
|
}
|
||||||
|
out.write(buf.toString().getBytes());
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
public void init(ServletConfig config) throws ServletException {
|
public void init(ServletConfig config) throws ServletException {
|
||||||
super.init(config);
|
super.init(config);
|
||||||
|
|
||||||
String pollPath = config.getInitParameter(PARAM_POLL_PATH);
|
String pollPath = config.getInitParameter(PARAM_POLL_PATH);
|
||||||
if (pollPath == null)
|
if (pollPath == null)
|
||||||
throw new ServletException("Polling path for the registration servlet required [" + PARAM_POLL_PATH + "]");
|
throw new ServletException("Polling path for the registration servlet required [" + PARAM_POLL_PATH + "]");
|
||||||
else
|
else
|
||||||
_pollPath = pollPath;
|
_pollPath = pollPath;
|
||||||
String sendPath = config.getInitParameter(PARAM_SEND_PATH);
|
String sendPath = config.getInitParameter(PARAM_SEND_PATH);
|
||||||
if (sendPath == null)
|
if (sendPath == null)
|
||||||
throw new ServletException("Sending path for the registration servlet required [" + PARAM_SEND_PATH + "]");
|
throw new ServletException("Sending path for the registration servlet required [" + PARAM_SEND_PATH + "]");
|
||||||
else
|
else
|
||||||
_sendPath = sendPath;
|
_sendPath = sendPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
package net.i2p.phttprelay;
|
package net.i2p.phttprelay;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free (adj.): unencumbered; not under the control of others
|
* free (adj.): unencumbered; not under the control of others
|
||||||
* Written by jrandom in 2003 and released into the public domain
|
* Written by jrandom in 2003 and released into the public domain
|
||||||
@ -63,256 +64,261 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
public class SendServlet extends PHTTPRelayServlet {
|
public class SendServlet extends PHTTPRelayServlet {
|
||||||
private String _checkPath;
|
private String _checkPath;
|
||||||
private int _maxMessagesPerIdent;
|
private int _maxMessagesPerIdent;
|
||||||
|
|
||||||
/* config params */
|
/* config params */
|
||||||
public final static String PARAM_CHECK_PATH = "checkPath";
|
public final static String PARAM_CHECK_PATH = "checkPath";
|
||||||
public final static String PARAM_MAX_MESSAGES_PER_IDENT = "maxMessagesPerIdent";
|
public final static String PARAM_MAX_MESSAGES_PER_IDENT = "maxMessagesPerIdent";
|
||||||
|
|
||||||
/* URL parameters on the send */
|
/* URL parameters on the send */
|
||||||
|
|
||||||
/** H(routerIdent).toBase64() of the target to receive the message */
|
/** H(routerIdent).toBase64() of the target to receive the message */
|
||||||
public final static String PARAM_SEND_TARGET = "target";
|
public final static String PARAM_SEND_TARGET = "target";
|
||||||
/** # ms to wait for the message to be delivered before failing it */
|
/** # ms to wait for the message to be delivered before failing it */
|
||||||
public final static String PARAM_SEND_TIMEOUTMS = "timeoutMs";
|
public final static String PARAM_SEND_TIMEOUTMS = "timeoutMs";
|
||||||
/** # bytes to be sent in the message */
|
/** # bytes to be sent in the message */
|
||||||
public final static String PARAM_SEND_DATA_LENGTH = "dataLength";
|
public final static String PARAM_SEND_DATA_LENGTH = "dataLength";
|
||||||
/** sending router's time in ms */
|
/** sending router's time in ms */
|
||||||
public final static String PARAM_SEND_TIME = "localTime";
|
public final static String PARAM_SEND_TIME = "localTime";
|
||||||
|
|
||||||
/** msgId parameter to access the check path servlet with (along side PARAM_SEND_TARGET) */
|
/** msgId parameter to access the check path servlet with (along side PARAM_SEND_TARGET) */
|
||||||
public final static String PARAM_MSG_ID = "msgId";
|
public final static String PARAM_MSG_ID = "msgId";
|
||||||
|
|
||||||
|
|
||||||
/* key=val keys sent back on registration */
|
/* key=val keys sent back on registration */
|
||||||
public final static String PROP_CHECK_URL = "statusCheckURL";
|
public final static String PROP_CHECK_URL = "statusCheckURL";
|
||||||
public final static String PROP_STATUS = "status";
|
public final static String PROP_STATUS = "status";
|
||||||
public final static String STATUS_OK = "accepted";
|
public final static String STATUS_OK = "accepted";
|
||||||
public final static String STATUS_UNKNOWN = "unknown";
|
public final static String STATUS_UNKNOWN = "unknown";
|
||||||
private final static String STATUS_CLOCKSKEW = "clockSkew_"; /** prefix for (local-remote) */
|
private final static String STATUS_CLOCKSKEW = "clockSkew_";
|
||||||
|
|
||||||
|
/** prefix for (local-remote) */
|
||||||
|
|
||||||
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
ServletInputStream in = req.getInputStream();
|
ServletInputStream in = req.getInputStream();
|
||||||
try {
|
try {
|
||||||
int contentLen = req.getContentLength();
|
int contentLen = req.getContentLength();
|
||||||
String firstLine = getFirstLine(in, contentLen);
|
String firstLine = getFirstLine(in, contentLen);
|
||||||
if (firstLine == null) {
|
if (firstLine == null) { return; }
|
||||||
return;
|
Map params = getParameters(firstLine);
|
||||||
}
|
String target = (String) params.get(PARAM_SEND_TARGET);
|
||||||
Map params = getParameters(firstLine);
|
String timeoutStr = (String) params.get(PARAM_SEND_TIMEOUTMS);
|
||||||
String target = (String)params.get(PARAM_SEND_TARGET);
|
String lenStr = (String) params.get(PARAM_SEND_DATA_LENGTH);
|
||||||
String timeoutStr = (String)params.get(PARAM_SEND_TIMEOUTMS);
|
String remoteTimeStr = (String) params.get(PARAM_SEND_TIME);
|
||||||
String lenStr = (String)params.get(PARAM_SEND_DATA_LENGTH);
|
long skew = 0;
|
||||||
String remoteTimeStr = (String)params.get(PARAM_SEND_TIME);
|
try {
|
||||||
long skew = 0;
|
long remTime = Long.parseLong(remoteTimeStr);
|
||||||
try {
|
skew = System.currentTimeMillis() - remTime;
|
||||||
long remTime = Long.parseLong(remoteTimeStr);
|
} catch (Throwable t) {
|
||||||
skew = System.currentTimeMillis() - remTime;
|
skew = Long.MAX_VALUE;
|
||||||
} catch (Throwable t) {
|
log("*ERROR could not parse the remote time from [" + remoteTimeStr + "]");
|
||||||
skew = Long.MAX_VALUE;
|
}
|
||||||
log("*ERROR could not parse the remote time from [" + remoteTimeStr + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
log("Target [" + target + "] timeout [" + timeoutStr + "] length [" + lenStr + "] skew [" + skew + "]");
|
log("Target [" + target + "] timeout [" + timeoutStr + "] length [" + lenStr + "] skew [" + skew + "]");
|
||||||
|
|
||||||
if ( (skew > CLOCK_FUDGE_FACTOR) || (skew < 0 - CLOCK_FUDGE_FACTOR) ) {
|
if ((skew > CLOCK_FUDGE_FACTOR) || (skew < 0 - CLOCK_FUDGE_FACTOR)) {
|
||||||
log("Attempt to send by a skewed router: skew = " + skew + "ms (local-remote)");
|
log("Attempt to send by a skewed router: skew = " + skew + "ms (local-remote)");
|
||||||
failSkewed(req, resp, skew);
|
failSkewed(req, resp, skew);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isValidTarget(target)) {
|
|
||||||
log("Attempt to send to an invalid target [" + target + "]");
|
|
||||||
fail(req, resp, "Unknown or invalid target");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long len = -1;
|
if (!isValidTarget(target)) {
|
||||||
try {
|
log("Attempt to send to an invalid target [" + target + "]");
|
||||||
len = Long.parseLong(lenStr);
|
fail(req, resp, "Unknown or invalid target");
|
||||||
} catch (Throwable t) {
|
return;
|
||||||
log("Unable to parse length parameter [" + PARAM_SEND_DATA_LENGTH + "] (" + lenStr + ")");
|
}
|
||||||
fail(req, resp, "Invalid length parameter");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int msgId = saveFile(in, resp, target, len);
|
long len = -1;
|
||||||
if (msgId >= 0) {
|
try {
|
||||||
sendSuccess(req, resp, target, msgId);
|
len = Long.parseLong(lenStr);
|
||||||
} else {
|
} catch (Throwable t) {
|
||||||
fail(req, resp, "Unable to queue up the message for delivery");
|
log("Unable to parse length parameter [" + PARAM_SEND_DATA_LENGTH + "] (" + lenStr + ")");
|
||||||
}
|
fail(req, resp, "Invalid length parameter");
|
||||||
} finally {
|
return;
|
||||||
try { in.close(); } catch (IOException ioe) {}
|
}
|
||||||
}
|
|
||||||
|
int msgId = saveFile(in, resp, target, len);
|
||||||
|
if (msgId >= 0) {
|
||||||
|
sendSuccess(req, resp, target, msgId);
|
||||||
|
} else {
|
||||||
|
fail(req, resp, "Unable to queue up the message for delivery");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private String getFirstLine(ServletInputStream in, int len) throws ServletException, IOException {
|
private String getFirstLine(ServletInputStream in, int len) throws ServletException, IOException {
|
||||||
StringBuffer buf = new StringBuffer(128);
|
StringBuffer buf = new StringBuffer(128);
|
||||||
int numBytes = 0;
|
int numBytes = 0;
|
||||||
int c = 0;
|
int c = 0;
|
||||||
while ( (c = in.read()) != -1) {
|
while ((c = in.read()) != -1) {
|
||||||
if (c == (int)'\n') break;
|
if (c == (int) '\n') break;
|
||||||
buf.append((char)c);
|
buf.append((char) c);
|
||||||
numBytes++;
|
numBytes++;
|
||||||
if (numBytes > 512) {
|
if (numBytes > 512) {
|
||||||
log("First line is > 512 bytes [" + buf.toString() + "]");
|
log("First line is > 512 bytes [" + buf.toString() + "]");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log("First line: " + buf.toString());
|
log("First line: " + buf.toString());
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map getParameters(String line) {
|
private static Map getParameters(String line) {
|
||||||
//StringTokenizer tok = new StringTokenizer(line, "&=", true);
|
//StringTokenizer tok = new StringTokenizer(line, "&=", true);
|
||||||
Map params = new HashMap();
|
Map params = new HashMap();
|
||||||
while (line != null) {
|
while (line != null) {
|
||||||
String key = null;
|
String key = null;
|
||||||
String val = null;
|
String val = null;
|
||||||
int firstAmp = line.indexOf('&');
|
int firstAmp = line.indexOf('&');
|
||||||
int firstEq = line.indexOf('=');
|
int firstEq = line.indexOf('=');
|
||||||
if (firstAmp > 0) {
|
if (firstAmp > 0) {
|
||||||
key = line.substring(0, firstEq);
|
key = line.substring(0, firstEq);
|
||||||
val = line.substring(firstEq+1, firstAmp);
|
val = line.substring(firstEq + 1, firstAmp);
|
||||||
line = line.substring(firstAmp+1);
|
line = line.substring(firstAmp + 1);
|
||||||
params.put(key, val);
|
params.put(key, val);
|
||||||
} else {
|
} else {
|
||||||
line = null;
|
line = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidTarget(String target) throws IOException {
|
private boolean isValidTarget(String target) throws IOException {
|
||||||
File identDir = getIdentDir(target);
|
File identDir = getIdentDir(target);
|
||||||
if (identDir.exists()) {
|
if (identDir.exists()) {
|
||||||
File identFile = new File(identDir, "identity.dat");
|
File identFile = new File(identDir, "identity.dat");
|
||||||
if (identFile.exists()) {
|
if (identFile.exists()) {
|
||||||
// known and valid (maybe we need to check the file format... naw, fuck it
|
// known and valid (maybe we need to check the file format... naw, fuck it
|
||||||
String files[] = identDir.list();
|
String files[] = identDir.list();
|
||||||
// we skip 1 because of identity.dat
|
// we skip 1 because of identity.dat
|
||||||
if (files.length -1 > _maxMessagesPerIdent) {
|
if (files.length - 1 > _maxMessagesPerIdent) {
|
||||||
log("Too many messages pending for " + target + ": " + (files.length-1));
|
log("Too many messages pending for " + target + ": " + (files.length - 1));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log("Ident directory exists, but identity does not... corrupt for " + target);
|
log("Ident directory exists, but identity does not... corrupt for " + target);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log("Unknown ident " + target);
|
log("Unknown ident " + target);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int saveFile(InputStream in, HttpServletResponse resp, String target, long len) throws IOException {
|
private int saveFile(InputStream in, HttpServletResponse resp, String target, long len) throws IOException {
|
||||||
File identDir = getIdentDir(target);
|
File identDir = getIdentDir(target);
|
||||||
if (!identDir.exists()) return -1;
|
if (!identDir.exists()) return -1;
|
||||||
try {
|
try {
|
||||||
LockManager.lockIdent(target);
|
LockManager.lockIdent(target);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
File curFile = new File(identDir, "msg" + i + ".dat");
|
File curFile = new File(identDir, "msg" + i + ".dat");
|
||||||
if (!curFile.exists()) {
|
if (!curFile.exists()) {
|
||||||
boolean ok = writeFile(curFile, in, len);
|
boolean ok = writeFile(curFile, in, len);
|
||||||
if (ok)
|
if (ok)
|
||||||
return i;
|
return i;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
LockManager.unlockIdent(target);
|
LockManager.unlockIdent(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean writeFile(File file, InputStream in, long len) throws IOException {
|
private boolean writeFile(File file, InputStream in, long len) throws IOException {
|
||||||
long remaining = len;
|
long remaining = len;
|
||||||
FileOutputStream fos = null;
|
FileOutputStream fos = null;
|
||||||
try {
|
try {
|
||||||
fos = new FileOutputStream(file);
|
fos = new FileOutputStream(file);
|
||||||
byte buf[] = new byte[4096];
|
byte buf[] = new byte[4096];
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
int read = in.read(buf);
|
int read = in.read(buf);
|
||||||
if (read == -1)
|
if (read == -1) break;
|
||||||
break;
|
remaining -= read;
|
||||||
remaining -= read;
|
if (read > 0) fos.write(buf, 0, read);
|
||||||
if (read > 0)
|
}
|
||||||
fos.write(buf, 0, read);
|
} finally {
|
||||||
}
|
if (fos != null) {
|
||||||
} finally {
|
try {
|
||||||
if (fos != null) {
|
fos.close();
|
||||||
try { fos.close(); } catch (IOException ioe) {}
|
} catch (IOException ioe) {
|
||||||
}
|
}
|
||||||
if (remaining != 0) {
|
}
|
||||||
log("Invalid remaining bytes [" + remaining + " out of " + len + "] - perhaps message was cancelled partway through delivery? deleting " + file.getAbsolutePath());
|
if (remaining != 0) {
|
||||||
boolean deleted = file.delete();
|
log("Invalid remaining bytes [" + remaining + " out of " + len
|
||||||
if (!deleted)
|
+ "] - perhaps message was cancelled partway through delivery? deleting " + file.getAbsolutePath());
|
||||||
log("!!!Error deleting temporary file " + file.getAbsolutePath());
|
boolean deleted = file.delete();
|
||||||
return false;
|
if (!deleted) log("!!!Error deleting temporary file " + file.getAbsolutePath());
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendSuccess(HttpServletRequest req, HttpServletResponse resp, String target, int msgId) throws IOException {
|
private void sendSuccess(HttpServletRequest req, HttpServletResponse resp, String target, int msgId)
|
||||||
ServletOutputStream out = resp.getOutputStream();
|
throws IOException {
|
||||||
StringBuffer buf = new StringBuffer();
|
ServletOutputStream out = resp.getOutputStream();
|
||||||
buf.append(PROP_STATUS).append('=').append(STATUS_OK).append('\n');
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append(PROP_CHECK_URL).append('=').append(buildURL(req, _checkPath));
|
buf.append(PROP_STATUS).append('=').append(STATUS_OK).append('\n');
|
||||||
buf.append('?');
|
buf.append(PROP_CHECK_URL).append('=').append(buildURL(req, _checkPath));
|
||||||
buf.append(PARAM_SEND_TARGET).append('=').append(target).append("&");
|
buf.append('?');
|
||||||
buf.append(PARAM_MSG_ID).append('=').append(msgId).append("\n");
|
buf.append(PARAM_SEND_TARGET).append('=').append(target).append("&");
|
||||||
out.write(buf.toString().getBytes());
|
buf.append(PARAM_MSG_ID).append('=').append(msgId).append("\n");
|
||||||
out.flush();
|
out.write(buf.toString().getBytes());
|
||||||
|
out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fail(HttpServletRequest req, HttpServletResponse resp, String err) throws IOException {
|
private void fail(HttpServletRequest req, HttpServletResponse resp, String err) throws IOException {
|
||||||
ServletOutputStream out = resp.getOutputStream();
|
ServletOutputStream out = resp.getOutputStream();
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append(PROP_STATUS).append('=').append(STATUS_UNKNOWN).append('\n');
|
buf.append(PROP_STATUS).append('=').append(STATUS_UNKNOWN).append('\n');
|
||||||
out.write(buf.toString().getBytes());
|
out.write(buf.toString().getBytes());
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void failSkewed(HttpServletRequest req, HttpServletResponse resp, long skew) throws IOException {
|
private void failSkewed(HttpServletRequest req, HttpServletResponse resp, long skew) throws IOException {
|
||||||
ServletOutputStream out = resp.getOutputStream();
|
ServletOutputStream out = resp.getOutputStream();
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append(PROP_STATUS).append('=').append(STATUS_CLOCKSKEW).append(skew).append('\n');
|
buf.append(PROP_STATUS).append('=').append(STATUS_CLOCKSKEW).append(skew).append('\n');
|
||||||
out.write(buf.toString().getBytes());
|
out.write(buf.toString().getBytes());
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(ServletConfig config) throws ServletException {
|
public void init(ServletConfig config) throws ServletException {
|
||||||
super.init(config);
|
super.init(config);
|
||||||
|
|
||||||
String checkPath = config.getInitParameter(PARAM_CHECK_PATH);
|
String checkPath = config.getInitParameter(PARAM_CHECK_PATH);
|
||||||
if (checkPath == null)
|
if (checkPath == null)
|
||||||
throw new ServletException("Check status path for the sending servlet required [" + PARAM_CHECK_PATH + "]");
|
throw new ServletException("Check status path for the sending servlet required [" + PARAM_CHECK_PATH + "]");
|
||||||
else
|
else
|
||||||
_checkPath = checkPath;
|
_checkPath = checkPath;
|
||||||
|
|
||||||
String maxMessagesPerIdentStr = config.getInitParameter(PARAM_MAX_MESSAGES_PER_IDENT);
|
String maxMessagesPerIdentStr = config.getInitParameter(PARAM_MAX_MESSAGES_PER_IDENT);
|
||||||
if (maxMessagesPerIdentStr == null)
|
if (maxMessagesPerIdentStr == null)
|
||||||
throw new ServletException("Max messages per ident for the sending servlet required [" + PARAM_MAX_MESSAGES_PER_IDENT + "]");
|
throw new ServletException("Max messages per ident for the sending servlet required ["
|
||||||
try {
|
+ PARAM_MAX_MESSAGES_PER_IDENT + "]");
|
||||||
_maxMessagesPerIdent = Integer.parseInt(maxMessagesPerIdentStr);
|
try {
|
||||||
} catch (Throwable t) {
|
_maxMessagesPerIdent = Integer.parseInt(maxMessagesPerIdentStr);
|
||||||
throw new ServletException("Valid max messages per ident for the sending servlet required [" + PARAM_MAX_MESSAGES_PER_IDENT + "]");
|
} catch (Throwable t) {
|
||||||
}
|
throw new ServletException("Valid max messages per ident for the sending servlet required ["
|
||||||
|
+ PARAM_MAX_MESSAGES_PER_IDENT + "]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
String line = "target=pp0ARjQiB~IKC-0FsMUsPEMrwR3gxVBZGRYfEr1IzHI=&timeoutMs=52068&dataLength=2691&";
|
String line = "target=pp0ARjQiB~IKC-0FsMUsPEMrwR3gxVBZGRYfEr1IzHI=&timeoutMs=52068&dataLength=2691&";
|
||||||
Map props = getParameters(line);
|
Map props = getParameters(line);
|
||||||
for (java.util.Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
|
for (java.util.Iterator iter = props.keySet().iterator(); iter.hasNext();) {
|
||||||
String key = (String)iter.next();
|
String key = (String) iter.next();
|
||||||
String val = (String)props.get(key);
|
String val = (String) props.get(key);
|
||||||
System.out.println("[" + key + "] = [" + val + "]");
|
System.out.println("[" + key + "] = [" + val + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,87 +8,81 @@ public class BasicEchoTestAnalyzer implements EchoTestAnalyzer {
|
|||||||
* printed. Default is every 20 events.
|
* printed. Default is every 20 events.
|
||||||
*/
|
*/
|
||||||
private static int REPORT_DELAY = 20;
|
private static int REPORT_DELAY = 20;
|
||||||
|
|
||||||
private static int SUMMARY_SIZE = 100;
|
private static int SUMMARY_SIZE = 100;
|
||||||
|
|
||||||
public BasicEchoTestAnalyzer() {
|
public BasicEchoTestAnalyzer() {
|
||||||
this(20, 100);
|
this(20, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BasicEchoTestAnalyzer(int reportDelay, int summarySize) {
|
public BasicEchoTestAnalyzer(int reportDelay, int summarySize) {
|
||||||
REPORT_DELAY = reportDelay;
|
REPORT_DELAY = reportDelay;
|
||||||
SUMMARY_SIZE = summarySize;
|
SUMMARY_SIZE = summarySize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int events = 0,
|
private int events = 0, packetLosses = 0, packetLossesDisconnect = 0, disconnects = 0, disconnectsRefused = 0,
|
||||||
packetLosses = 0,
|
delayCount = 0, lastDelayPtr = 0;
|
||||||
packetLossesDisconnect=0,
|
private long minDelay = Long.MAX_VALUE, maxDelay = 0, delaySum = 0;
|
||||||
disconnects = 0,
|
|
||||||
disconnectsRefused = 0,
|
|
||||||
delayCount=0,
|
|
||||||
lastDelayPtr = 0;
|
|
||||||
private long minDelay=Long.MAX_VALUE, maxDelay = 0, delaySum=0;
|
|
||||||
private long[] lastDelays = new long[SUMMARY_SIZE];
|
private long[] lastDelays = new long[SUMMARY_SIZE];
|
||||||
|
|
||||||
|
|
||||||
public synchronized void packetLossOccurred(boolean beforeDisconnect) {
|
public synchronized void packetLossOccurred(boolean beforeDisconnect) {
|
||||||
System.out.println("1: Packet lost"+
|
System.out.println("1: Packet lost" + (beforeDisconnect ? " before disconnect" : "") + ".");
|
||||||
(beforeDisconnect?" before disconnect":"")+
|
packetLosses++;
|
||||||
".");
|
if (beforeDisconnect) packetLossesDisconnect++;
|
||||||
packetLosses++;
|
countEvent();
|
||||||
if (beforeDisconnect) packetLossesDisconnect++;
|
|
||||||
countEvent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void successOccurred(long delay) {
|
public synchronized void successOccurred(long delay) {
|
||||||
System.out.println("0: Delay = "+delay);
|
System.out.println("0: Delay = " + delay);
|
||||||
if (delay > maxDelay) maxDelay=delay;
|
if (delay > maxDelay) maxDelay = delay;
|
||||||
if (delay < minDelay) minDelay=delay;
|
if (delay < minDelay) minDelay = delay;
|
||||||
delaySum+=delay;
|
delaySum += delay;
|
||||||
delayCount++;
|
delayCount++;
|
||||||
lastDelays[lastDelayPtr++]=delay;
|
lastDelays[lastDelayPtr++] = delay;
|
||||||
lastDelayPtr%=SUMMARY_SIZE;
|
lastDelayPtr %= SUMMARY_SIZE;
|
||||||
countEvent();
|
countEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void disconnected(boolean refused) {
|
public synchronized void disconnected(boolean refused) {
|
||||||
System.out.println("2: Disconnected"+
|
System.out.println("2: Disconnected" + (refused ? " (connection refused)" : "") + ".");
|
||||||
(refused?" (connection refused)":"")+
|
disconnects++;
|
||||||
".");
|
if (refused) disconnectsRefused++;
|
||||||
disconnects++;
|
countEvent();
|
||||||
if (refused) disconnectsRefused++;
|
|
||||||
countEvent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void countEvent() {
|
private void countEvent() {
|
||||||
events++;
|
events++;
|
||||||
if (events % REPORT_DELAY == 0) {
|
if (events % REPORT_DELAY == 0) {
|
||||||
int packets = packetLosses+delayCount;
|
int packets = packetLosses + delayCount;
|
||||||
long delaySummary=0;
|
long delaySummary = 0;
|
||||||
for (int i=0;i<SUMMARY_SIZE;i++) {
|
for (int i = 0; i < SUMMARY_SIZE; i++) {
|
||||||
delaySummary+=lastDelays[i];
|
delaySummary += lastDelays[i];
|
||||||
}
|
}
|
||||||
System.out.println
|
System.out.println("++++++++++++++++ ECHO STATISTICS +++++++++++++++++++++++++"
|
||||||
("++++++++++++++++ ECHO STATISTICS +++++++++++++++++++++++++"+
|
+ "\n++ Number of total echo messages: "
|
||||||
"\n++ Number of total echo messages: "+packets+
|
+ packets
|
||||||
"\n++ No response for "+packetLosses+
|
+ "\n++ No response for "
|
||||||
"\n++ (of which "+ packetLossesDisconnect+
|
+ packetLosses
|
||||||
" due to a disconnect)"+
|
+ "\n++ (of which "
|
||||||
"\n++ Disconnects: "+disconnects+
|
+ packetLossesDisconnect
|
||||||
"\n++ (of which "+disconnectsRefused+
|
+ " due to a disconnect)"
|
||||||
" due to 'connection refused')"+
|
+ "\n++ Disconnects: "
|
||||||
(disconnects>0 || true
|
+ disconnects
|
||||||
?"\n++ Average lost packets per disconnect: "+
|
+ "\n++ (of which "
|
||||||
(packetLossesDisconnect/(float)disconnects)
|
+ disconnectsRefused
|
||||||
:"")+
|
+ " due to 'connection refused')"
|
||||||
"\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++"+
|
+ (disconnects > 0 || true ? "\n++ Average lost packets per disconnect: "
|
||||||
"\n++ Minimal delay: "+minDelay+
|
+ (packetLossesDisconnect / (float) disconnects) : "")
|
||||||
"\n++ Average delay: "+(delaySum/(float)delayCount)+
|
+ "\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
|
||||||
"\n++ Maximal delay: "+maxDelay+
|
+ "\n++ Minimal delay: "
|
||||||
(delayCount >=SUMMARY_SIZE
|
+ minDelay
|
||||||
?"\n++ Average delay over last " + SUMMARY_SIZE + ": "+(delaySummary/(float)SUMMARY_SIZE)
|
+ "\n++ Average delay: "
|
||||||
:"")+
|
+ (delaySum / (float) delayCount)
|
||||||
"\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
+ "\n++ Maximal delay: "
|
||||||
}
|
+ maxDelay
|
||||||
|
+ (delayCount >= SUMMARY_SIZE ? "\n++ Average delay over last " + SUMMARY_SIZE + ": "
|
||||||
|
+ (delaySummary / (float) SUMMARY_SIZE) : "")
|
||||||
|
+ "\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,5 +15,3 @@ public interface EchoTestAnalyzer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,152 +26,142 @@ public class EchoTester extends Thread {
|
|||||||
/**
|
/**
|
||||||
* How long to wait between packets. Default is 6 seconds.
|
* How long to wait between packets. Default is 6 seconds.
|
||||||
*/
|
*/
|
||||||
private static long PACKET_DELAY= 6000;
|
private static long PACKET_DELAY = 6000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many packets may be on the way before the connection is
|
* How many packets may be on the way before the connection is
|
||||||
* seen as "broken" and disconnected.
|
* seen as "broken" and disconnected.
|
||||||
*/
|
*/
|
||||||
private static final long MAX_PACKETS_QUEUED=50; // unused
|
private static final long MAX_PACKETS_QUEUED = 50; // unused
|
||||||
|
|
||||||
|
|
||||||
private EchoTestAnalyzer eta;
|
private EchoTestAnalyzer eta;
|
||||||
private String host;
|
private String host;
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
// the following vars are synchronized via the lock.
|
// the following vars are synchronized via the lock.
|
||||||
private Object lock = new Object();
|
private Object lock = new Object();
|
||||||
private long nextPacket=0;
|
private long nextPacket = 0;
|
||||||
private long nextUnreceived=0;
|
private long nextUnreceived = 0;
|
||||||
private boolean readerRunning=false;
|
private boolean readerRunning = false;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
if (args.length == 3)
|
if (args.length == 3) PACKET_DELAY = Long.parseLong(args[2]);
|
||||||
PACKET_DELAY = Long.parseLong(args[2]);
|
new EchoTester(args[0], Integer.parseInt(args[1]), new BasicEchoTestAnalyzer());
|
||||||
new EchoTester(args[0], Integer.parseInt(args[1]),
|
|
||||||
new BasicEchoTestAnalyzer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EchoTester(String host, int port, EchoTestAnalyzer eta) {
|
public EchoTester(String host, int port, EchoTestAnalyzer eta) {
|
||||||
this.eta=eta;
|
this.eta = eta;
|
||||||
this.host=host;
|
this.host = host;
|
||||||
this.port=port;
|
this.port = port;
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
Socket s;
|
Socket s;
|
||||||
try {
|
try {
|
||||||
s = new Socket(host, port);
|
s = new Socket(host, port);
|
||||||
} catch (ConnectException ex) {
|
} catch (ConnectException ex) {
|
||||||
eta.disconnected(true);
|
eta.disconnected(true);
|
||||||
Thread.sleep(PACKET_DELAY);
|
Thread.sleep(PACKET_DELAY);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
System.out.println("41: Connected to "+host+":"+port);
|
System.out.println("41: Connected to " + host + ":" + port);
|
||||||
synchronized(lock) {
|
synchronized (lock) {
|
||||||
nextUnreceived=nextPacket;
|
nextUnreceived = nextPacket;
|
||||||
}
|
}
|
||||||
Thread t = new ResponseReaderThread(s);
|
Thread t = new ResponseReaderThread(s);
|
||||||
Writer w = new BufferedWriter(new OutputStreamWriter
|
Writer w = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
|
||||||
(s.getOutputStream()));
|
while (true) {
|
||||||
while (true) {
|
long no;
|
||||||
long no;
|
synchronized (lock) {
|
||||||
synchronized(lock) {
|
no = nextPacket++;
|
||||||
no = nextPacket++;
|
}
|
||||||
}
|
try {
|
||||||
try {
|
w.write(no + " " + System.currentTimeMillis() + "\n");
|
||||||
w.write(no+" "+System.currentTimeMillis()+"\n");
|
w.flush();
|
||||||
w.flush();
|
} catch (SocketException ex) {
|
||||||
} catch (SocketException ex) {
|
break;
|
||||||
break;
|
}
|
||||||
}
|
Thread.sleep(PACKET_DELAY);
|
||||||
Thread.sleep(PACKET_DELAY);
|
}
|
||||||
}
|
s.close();
|
||||||
s.close();
|
t.join();
|
||||||
t.join();
|
synchronized (lock) {
|
||||||
synchronized(lock) {
|
if (readerRunning) {
|
||||||
if (readerRunning) {
|
System.out.println("*** WHY IS THIS THREAD STILL" + " RUNNING?");
|
||||||
System.out.println("*** WHY IS THIS THREAD STILL"+
|
}
|
||||||
" RUNNING?");
|
while (nextUnreceived < nextPacket) {
|
||||||
}
|
nextUnreceived++;
|
||||||
while (nextUnreceived < nextPacket) {
|
eta.packetLossOccurred(true);
|
||||||
nextUnreceived++;
|
}
|
||||||
eta.packetLossOccurred(true);
|
if (nextUnreceived > nextPacket) {
|
||||||
}
|
System.out.println("*** WTF? " + nextUnreceived + " > " + nextPacket);
|
||||||
if (nextUnreceived > nextPacket) {
|
}
|
||||||
System.out.println("*** WTF? "+nextUnreceived+" > "+
|
}
|
||||||
nextPacket);
|
eta.disconnected(false);
|
||||||
}
|
}
|
||||||
}
|
} catch (InterruptedException ex) {
|
||||||
eta.disconnected(false);
|
ex.printStackTrace();
|
||||||
}
|
System.exit(1); // treat these errors as fatal
|
||||||
} catch (InterruptedException ex) {
|
} catch (IOException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
System.exit(1); // treat these errors as fatal
|
System.exit(1); // treat these errors as fatal
|
||||||
} catch (IOException ex) {
|
}
|
||||||
ex.printStackTrace();
|
|
||||||
System.exit(1); // treat these errors as fatal
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ResponseReaderThread extends Thread {
|
private class ResponseReaderThread extends Thread {
|
||||||
|
|
||||||
private Socket s;
|
private Socket s;
|
||||||
|
|
||||||
public ResponseReaderThread(Socket s) {
|
public ResponseReaderThread(Socket s) {
|
||||||
this.s=s;
|
this.s = s;
|
||||||
synchronized(lock) {
|
synchronized (lock) {
|
||||||
readerRunning=true;
|
readerRunning = true;
|
||||||
}
|
}
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader
|
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
|
||||||
(s.getInputStream()));
|
String line;
|
||||||
String line;
|
int index;
|
||||||
int index;
|
while ((line = br.readLine()) != null) {
|
||||||
while ((line=br.readLine()) != null) {
|
if ((index = line.indexOf(" ")) == -1) continue;
|
||||||
if ((index=line.indexOf(" ")) == -1)
|
long now, packetNumber, packetTime;
|
||||||
continue;
|
now = System.currentTimeMillis();
|
||||||
long now, packetNumber, packetTime;
|
try {
|
||||||
now = System.currentTimeMillis();
|
packetNumber = Long.parseLong(line.substring(0, index));
|
||||||
try {
|
packetTime = Long.parseLong(line.substring(index + 1));
|
||||||
packetNumber = Long.parseLong
|
} catch (NumberFormatException ex) {
|
||||||
(line.substring(0,index));
|
System.out.println(ex.toString());
|
||||||
packetTime = Long.parseLong
|
continue;
|
||||||
(line.substring(index+1));
|
}
|
||||||
} catch (NumberFormatException ex) {
|
synchronized (lock) {
|
||||||
System.out.println(ex.toString());
|
while (packetNumber > nextUnreceived) {
|
||||||
continue;
|
nextUnreceived++;
|
||||||
}
|
eta.packetLossOccurred(false);
|
||||||
synchronized (lock) {
|
}
|
||||||
while (packetNumber > nextUnreceived) {
|
if (nextUnreceived > packetNumber) {
|
||||||
nextUnreceived++;
|
System.out.println("*** DOUBLE PACKET!");
|
||||||
eta.packetLossOccurred(false);
|
} else {
|
||||||
}
|
nextUnreceived++;
|
||||||
if (nextUnreceived > packetNumber) {
|
}
|
||||||
System.out.println("*** DOUBLE PACKET!");
|
}
|
||||||
} else {
|
eta.successOccurred(now - packetTime);
|
||||||
nextUnreceived++;
|
}
|
||||||
}
|
} catch (SocketException ex) {
|
||||||
}
|
// ignore
|
||||||
eta.successOccurred(now-packetTime);
|
} catch (IOException ex) {
|
||||||
}
|
ex.printStackTrace();
|
||||||
} catch (SocketException ex) {
|
System.exit(0);
|
||||||
// ignore
|
}
|
||||||
} catch (IOException ex) {
|
synchronized (lock) {
|
||||||
ex.printStackTrace();
|
readerRunning = false;
|
||||||
System.exit(0);
|
}
|
||||||
}
|
}
|
||||||
synchronized(lock) {
|
|
||||||
readerRunning=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user