Use whole buffers for reads and writes.

This commit is contained in:
akwizgran
2012-11-27 15:16:56 +00:00
parent 705b87b97c
commit 80543984be
12 changed files with 80 additions and 103 deletions

View File

@@ -7,20 +7,21 @@ class Ack extends Frame {
static final int LENGTH = 12;
Ack() {
super(new byte[LENGTH], LENGTH);
b[0] = (byte) Frame.ACK_FLAG;
super(new byte[LENGTH]);
buf[0] = (byte) Frame.ACK_FLAG;
}
Ack(byte[] b) {
super(b, LENGTH);
b[0] = (byte) Frame.ACK_FLAG;
Ack(byte[] buf) {
super(buf);
if(buf.length != LENGTH) throw new IllegalArgumentException();
buf[0] = (byte) Frame.ACK_FLAG;
}
int getWindowSize() {
return ByteUtils.readUint24(b, 5);
return ByteUtils.readUint24(buf, 5);
}
void setWindowSize(int windowSize) {
ByteUtils.writeUint24(windowSize, b, 5);
ByteUtils.writeUint24(windowSize, buf, 5);
}
}

View File

@@ -7,21 +7,21 @@ class Data extends Frame {
static final int MAX_PAYLOAD_LENGTH = 1024;
static final int MAX_LENGTH = MIN_LENGTH + MAX_PAYLOAD_LENGTH;
Data(byte[] b, int length) {
super(b, length);
if(length < MIN_LENGTH || length > MAX_LENGTH)
Data(byte[] buf) {
super(buf);
if(buf.length < MIN_LENGTH || buf.length > MAX_LENGTH)
throw new IllegalArgumentException();
}
boolean isLastFrame() {
return b[0] == Frame.FIN_FLAG;
return buf[0] == Frame.FIN_FLAG;
}
void setLastFrame(boolean lastFrame) {
if(lastFrame) b[0] = (byte) Frame.FIN_FLAG;
if(lastFrame) buf[0] = (byte) Frame.FIN_FLAG;
}
int getPayloadLength() {
return length - MIN_LENGTH;
return buf.length - MIN_LENGTH;
}
}

View File

@@ -6,40 +6,38 @@ abstract class Frame {
static final byte ACK_FLAG = (byte) 128, FIN_FLAG = 64;
protected final byte[] b;
protected final int length;
protected final byte[] buf;
Frame(byte[] b, int length) {
this.b = b;
this.length = length;
Frame(byte[] buf) {
this.buf = buf;
}
byte[] getBuffer() {
return b;
return buf;
}
int getLength() {
return length;
return buf.length;
}
long getChecksum() {
return ByteUtils.readUint32(b, length - 4);
return ByteUtils.readUint32(buf, buf.length - 4);
}
void setChecksum(long checksum) {
ByteUtils.writeUint32(checksum, b, length - 4);
ByteUtils.writeUint32(checksum, buf, buf.length - 4);
}
long calculateChecksum() {
return Crc32.crc(b, 0, length - 4);
return Crc32.crc(buf, 0, buf.length - 4);
}
long getSequenceNumber() {
return ByteUtils.readUint32(b, 1);
return ByteUtils.readUint32(buf, 1);
}
void setSequenceNumber(long sequenceNumber) {
ByteUtils.writeUint32(sequenceNumber, b, 1);
ByteUtils.writeUint32(sequenceNumber, buf, 1);
}
@Override
@@ -51,7 +49,7 @@ abstract class Frame {
public boolean equals(Object o) {
if(o instanceof Frame) {
Frame f = (Frame) o;
if(b[0] != f.b[0]) return false;
if(buf[0] != f.buf[0]) return false;
return getSequenceNumber() == f.getSequenceNumber();
}
return false;

View File

@@ -135,12 +135,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
offHook.release();
}
public void handleWrite(byte[] b, int length) throws IOException {
if(length < b.length) {
byte[] copy = new byte[length];
System.arraycopy(b, 0, copy, 0, length);
b = copy;
}
public void handleWrite(byte[] b) throws IOException {
try {
port.writeBytes(b);
} catch(SerialPortException e) {
@@ -153,7 +148,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
try {
if(ev.isRXCHAR()) {
byte[] b = port.readBytes();
if(connected.get()) reliabilityLayer.handleRead(b, b.length);
if(connected.get()) reliabilityLayer.handleRead(b);
else handleText(b);
} else if(ev.isDSR() && ev.getEventValue() == 0) {
if(LOG.isLoggable(INFO)) LOG.info("Remote end hung up");
@@ -188,7 +183,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
if(off < b.length) {
byte[] data = new byte[b.length - off];
System.arraycopy(b, off, data, 0, data.length);
reliabilityLayer.handleRead(data, data.length);
reliabilityLayer.handleRead(data);
}
return;
} else if(s.equals("OK")) {

View File

@@ -4,5 +4,5 @@ import java.io.IOException;
interface ReadHandler {
void handleRead(byte[] b, int length) throws IOException;
void handleRead(byte[] b) throws IOException;
}

View File

@@ -65,20 +65,15 @@ class Receiver implements ReadHandler {
}
}
public void handleRead(byte[] b, int length) throws IOException {
public void handleRead(byte[] b) throws IOException {
if(!valid) throw new IOException("Connection closed");
if(length < Data.MIN_LENGTH || length > Data.MAX_LENGTH) {
if(LOG.isLoggable(FINE))
LOG.fine("Ignoring frame with invalid length");
return;
}
switch(b[0]) {
case 0:
case Frame.FIN_FLAG:
handleData(b, length);
handleData(b);
break;
case Frame.ACK_FLAG:
sender.handleAck(b, length);
sender.handleAck(b);
break;
default:
if(LOG.isLoggable(FINE)) LOG.fine("Ignoring unknown frame type");
@@ -86,9 +81,13 @@ class Receiver implements ReadHandler {
}
}
private synchronized void handleData(byte[] b, int length)
throws IOException {
Data d = new Data(b, length);
private synchronized void handleData(byte[] b) throws IOException {
if(b.length < Data.MIN_LENGTH || b.length > Data.MAX_LENGTH) {
if(LOG.isLoggable(FINE))
LOG.fine("Ignoring data frame with invalid length");
return;
}
Data d = new Data(b);
int payloadLength = d.getPayloadLength();
if(payloadLength > windowSize) {
if(LOG.isLoggable(FINE)) LOG.fine("No space in the window");

View File

@@ -42,7 +42,7 @@ class ReliabilityLayer implements ReadHandler, WriteHandler {
while(valid) {
byte[] b = writes.take();
if(b.length == 0) return; // Poison pill
writeHandler.handleWrite(b, b.length);
writeHandler.handleWrite(b);
}
} catch(InterruptedException e) {
if(LOG.isLoggable(WARNING))
@@ -73,20 +73,14 @@ class ReliabilityLayer implements ReadHandler, WriteHandler {
}
// The modem calls this method to pass data up to the SLIP decoder
public void handleRead(byte[] b, int length) throws IOException {
public void handleRead(byte[] b) throws IOException {
if(!valid) throw new IOException("Connection closed");
decoder.handleRead(b, length);
decoder.handleRead(b);
}
// The SLIP encoder calls this method to pass data down to the modem
public void handleWrite(byte[] b, int length) throws IOException {
public void handleWrite(byte[] b) throws IOException {
if(!valid) throw new IOException("Connection closed");
if(length == 0) return;
if(length < b.length) {
byte[] copy = new byte[length];
System.arraycopy(b, 0, copy, 0, length);
b = copy;
}
writes.add(b);
if(b.length > 0) writes.add(b);
}
}

View File

@@ -47,13 +47,13 @@ class Sender {
if(LOG.isLoggable(FINE))
LOG.fine("Acknowledging #" + sequenceNumber);
}
writeHandler.handleWrite(a.getBuffer(), a.getLength());
writeHandler.handleWrite(a.getBuffer());
}
void handleAck(byte[] b, int length) {
if(length != Ack.LENGTH) {
void handleAck(byte[] b) {
if(b.length != Ack.LENGTH) {
if(LOG.isLoggable(FINE))
LOG.fine("Ignoring ack frame with wrong length");
LOG.fine("Ignoring ack frame with invalid length");
return;
}
Ack a = new Ack(b);
@@ -115,7 +115,7 @@ class Sender {
if(fastRetransmit != null) {
Data d = fastRetransmit.data;
try {
writeHandler.handleWrite(d.getBuffer(), d.getLength());
writeHandler.handleWrite(d.getBuffer());
} catch(IOException e) {
// FIXME: Do something more meaningful
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
@@ -169,16 +169,14 @@ class Sender {
// Send a window probe if necessary
if(sendProbe) {
byte[] buf = new byte[Data.MIN_LENGTH];
Data probe = new Data(buf, Data.MIN_LENGTH);
Data probe = new Data(buf);
probe.setChecksum(probe.calculateChecksum());
writeHandler.handleWrite(buf, Data.MIN_LENGTH);
writeHandler.handleWrite(buf);
}
// Retransmit any lost data frames
if(retransmit != null) {
for(Outstanding o : retransmit) {
Data d = o.data;
writeHandler.handleWrite(d.getBuffer(), d.getLength());
}
for(Outstanding o : retransmit)
writeHandler.handleWrite(o.data.getBuffer());
}
} catch(IOException e) {
// FIXME: Do something more meaningful
@@ -202,7 +200,7 @@ class Sender {
}
if(LOG.isLoggable(FINE))
LOG.fine("Transmitting #" + d.getSequenceNumber());
writeHandler.handleWrite(d.getBuffer(), d.getLength());
writeHandler.handleWrite(d.getBuffer());
}
private static class Outstanding {

View File

@@ -6,8 +6,8 @@ import java.io.OutputStream;
class SenderOutputStream extends OutputStream {
private final Sender sender;
private final byte[] buf = new byte[Data.MAX_LENGTH];
private byte[] buf = null;
private int offset = 0;
private long sequenceNumber = 1L;
@@ -17,18 +17,16 @@ class SenderOutputStream extends OutputStream {
@Override
public void close() throws IOException {
if(buf == null) assignBuffer();
send(true);
}
@Override
public void flush() throws IOException {
if(buf != null) send(false);
if(offset > Data.HEADER_LENGTH) send(false);
}
@Override
public void write(int b) throws IOException {
if(buf == null) assignBuffer();
buf[offset] = (byte) b;
offset++;
if(offset == Data.HEADER_LENGTH + Data.MAX_PAYLOAD_LENGTH) send(false);
@@ -41,13 +39,11 @@ class SenderOutputStream extends OutputStream {
@Override
public void write(byte[] b, int off, int len) throws IOException {
if(buf == null) assignBuffer();
int available = Data.MAX_LENGTH - offset - Data.FOOTER_LENGTH;
while(available <= len) {
System.arraycopy(b, off, buf, offset, available);
offset += available;
send(false);
assignBuffer();
off += available;
len -= available;
available = Data.MAX_LENGTH - offset - Data.FOOTER_LENGTH;
@@ -56,13 +52,10 @@ class SenderOutputStream extends OutputStream {
offset += len;
}
private void assignBuffer() {
buf = new byte[Data.MAX_LENGTH];
offset = Data.HEADER_LENGTH;
}
private void send(boolean lastFrame) throws IOException {
Data d = new Data(buf, offset + Data.FOOTER_LENGTH);
byte[] frame = new byte[offset + Data.FOOTER_LENGTH];
System.arraycopy(buf, 0, frame, 0, frame.length);
Data d = new Data(frame);
d.setLastFrame(lastFrame);
d.setSequenceNumber(sequenceNumber++);
d.setChecksum(d.calculateChecksum());
@@ -72,7 +65,6 @@ class SenderOutputStream extends OutputStream {
Thread.currentThread().interrupt();
throw new IOException("Interrupted while writing");
}
buf = null;
offset = 0;
offset = Data.HEADER_LENGTH;
}
}

View File

@@ -24,16 +24,17 @@ class SlipDecoder implements ReadHandler {
this.readHandler = readHandler;
}
public void handleRead(byte[] b, int length) throws IOException {
for(int i = 0; i < length; i++) {
public void handleRead(byte[] b) throws IOException {
for(int i = 0; i < b.length; i++) {
switch(b[i]) {
case END:
if(escape) {
reset(true);
} else {
if(decodedLength > 0) {
readHandler.handleRead(buf, decodedLength);
buf = new byte[Data.MAX_LENGTH];
byte[] decoded = new byte[decodedLength];
System.arraycopy(buf, 0, decoded, 0, decodedLength);
readHandler.handleRead(decoded);
}
reset(false);
}

View File

@@ -14,26 +14,25 @@ class SlipEncoder implements WriteHandler {
this.writeHandler = writeHandler;
}
public void handleWrite(byte[] b, int length) throws IOException {
if(length > Data.MAX_LENGTH) throw new IllegalArgumentException();
int encodedLength = length + 2;
for(int i = 0; i < length; i++) {
public void handleWrite(byte[] b) throws IOException {
if(b.length > Data.MAX_LENGTH) throw new IllegalArgumentException();
int encodedLength = b.length + 2;
for(int i = 0; i < b.length; i++)
if(b[i] == END || b[i] == ESC) encodedLength++;
}
byte[] buf = new byte[encodedLength];
buf[0] = END;
for(int i = 0, j = 1; i < length; i++) {
byte[] encoded = new byte[encodedLength];
encoded[0] = END;
for(int i = 0, j = 1; i < b.length; i++) {
if(b[i] == END) {
buf[j++] = ESC;
buf[j++] = TEND;
encoded[j++] = ESC;
encoded[j++] = TEND;
} else if(b[i] == ESC) {
buf[j++] = ESC;
buf[j++] = TESC;
encoded[j++] = ESC;
encoded[j++] = TESC;
} else {
buf[j++] = b[i];
encoded[j++] = b[i];
}
}
buf[encodedLength - 1] = END;
writeHandler.handleWrite(buf, encodedLength);
encoded[encodedLength - 1] = END;
writeHandler.handleWrite(encoded);
}
}

View File

@@ -4,5 +4,5 @@ import java.io.IOException;
interface WriteHandler {
void handleWrite(byte[] b, int length) throws IOException;
void handleWrite(byte[] b) throws IOException;
}