Skip to content
Snippets Groups Projects
Commit f487d4f4 authored by akwizgran's avatar akwizgran
Browse files

Don't allow input or output streams to be used after hanging up.

parent 4f37cb08
No related branches found
No related tags found
No related merge requests found
...@@ -6,20 +6,18 @@ import java.io.OutputStream; ...@@ -6,20 +6,18 @@ import java.io.OutputStream;
/** /**
* A modem that can be used for multiple sequential incoming and outgoing * A modem that can be used for multiple sequential incoming and outgoing
* calls. * calls. If an exception is thrown, a new modem instance must be created.
*/ */
interface Modem { interface Modem {
/** /**
* Call this method after creating the modem and before making any calls. * Call this method after creating the modem and before making any calls.
* If an exception is thrown while using the modem, this method must be
* called again.
*/ */
void init() throws IOException; void init() throws IOException;
/** /**
* Initiates an outgoing call and returns true if the call connects. If the * Initiates an outgoing call and returns true if the call connects. If the
* call does not connect the modem is hung up and can continue to be used. * call does not connect the modem is hung up.
*/ */
boolean dial(String number) throws IOException; boolean dial(String number) throws IOException;
......
...@@ -40,7 +40,8 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -40,7 +40,8 @@ class ModemImpl implements Modem, SerialPortEventListener {
private int lineLen = 0; private int lineLen = 0;
private volatile BlockingQueue<byte[]> received = null; private volatile ModemInputStream inputStream = null;
private volatile ModemOutputStream outputStream = null;
ModemImpl(Executor executor, Callback callback, String portName) { ModemImpl(Executor executor, Callback callback, String portName) {
this.executor = executor; this.executor = executor;
...@@ -55,10 +56,8 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -55,10 +56,8 @@ class ModemImpl implements Modem, SerialPortEventListener {
public void init() throws IOException { public void init() throws IOException {
if(LOG.isLoggable(INFO)) LOG.info("Initialising"); if(LOG.isLoggable(INFO)) LOG.info("Initialising");
try { try {
// Open the serial port
if(!port.openPort()) if(!port.openPort())
throw new IOException("Failed to open serial port"); throw new IOException("Failed to open serial port");
// Find a suitable baud rate
boolean foundBaudRate = false; boolean foundBaudRate = false;
for(int baudRate : BAUD_RATES) { for(int baudRate : BAUD_RATES) {
if(port.setParams(baudRate, 8, 1, 0)) { if(port.setParams(baudRate, 8, 1, 0)) {
...@@ -68,9 +67,7 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -68,9 +67,7 @@ class ModemImpl implements Modem, SerialPortEventListener {
} }
if(!foundBaudRate) if(!foundBaudRate)
throw new IOException("Could not find a suitable baud rate"); throw new IOException("Could not find a suitable baud rate");
// Listen for incoming data and hangup events
port.addEventListener(this); port.addEventListener(this);
// Initialise the modem
port.purgePort(PURGE_RXCLEAR | PURGE_TXCLEAR); port.purgePort(PURGE_RXCLEAR | PURGE_TXCLEAR);
port.writeBytes("ATZ\r\n".getBytes("US-ASCII")); // Reset port.writeBytes("ATZ\r\n".getBytes("US-ASCII")); // Reset
port.writeBytes("ATE0\r\n".getBytes("US-ASCII")); // Echo off port.writeBytes("ATE0\r\n".getBytes("US-ASCII")); // Echo off
...@@ -79,11 +76,8 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -79,11 +76,8 @@ class ModemImpl implements Modem, SerialPortEventListener {
throw new IOException(e.toString()); throw new IOException(e.toString());
} }
try { try {
// Wait for the modem to respond "OK"
synchronized(initialised) { synchronized(initialised) {
if(!initialised.get()) initialised.wait(OK_TIMEOUT); if(!initialised.get()) initialised.wait(OK_TIMEOUT);
if(!initialised.get())
throw new IOException("Modem did not respond");
} }
} catch(InterruptedException e) { } catch(InterruptedException e) {
if(LOG.isLoggable(WARNING)) if(LOG.isLoggable(WARNING))
...@@ -92,7 +86,8 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -92,7 +86,8 @@ class ModemImpl implements Modem, SerialPortEventListener {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new IOException("Interrupted while initialising modem"); throw new IOException("Interrupted while initialising modem");
} }
received = new LinkedBlockingQueue<byte[]>(); if(!initialised.get())
throw new IOException("Modem did not respond");
} }
public boolean dial(String number) throws IOException { public boolean dial(String number) throws IOException {
...@@ -125,11 +120,11 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -125,11 +120,11 @@ class ModemImpl implements Modem, SerialPortEventListener {
} }
public InputStream getInputStream() { public InputStream getInputStream() {
return new ModemInputStream(received); return inputStream;
} }
public OutputStream getOutputStream() { public OutputStream getOutputStream() {
return new ModemOutputStream(); return outputStream;
} }
public void hangUp() throws IOException { public void hangUp() throws IOException {
...@@ -140,8 +135,9 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -140,8 +135,9 @@ class ModemImpl implements Modem, SerialPortEventListener {
tryToClose(port); tryToClose(port);
throw new IOException(e.toString()); throw new IOException(e.toString());
} }
received.add(new byte[0]); // Empty buffer indicates EOF inputStream.closed = true;
received = new LinkedBlockingQueue<byte[]>(); inputStream.received.add(new byte[0]); // Poison pill
outputStream.closed = true;
connected.set(false); connected.set(false);
offHook.release(); offHook.release();
} }
...@@ -150,7 +146,7 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -150,7 +146,7 @@ class ModemImpl implements Modem, SerialPortEventListener {
try { try {
if(ev.isRXCHAR()) { if(ev.isRXCHAR()) {
byte[] b = port.readBytes(); byte[] b = port.readBytes();
if(connected.get()) received.add(b); if(connected.get()) inputStream.received.add(b);
else handleText(b); else handleText(b);
} else if(ev.isDSR() && ev.getEventValue() == 0) { } else if(ev.isDSR() && ev.getEventValue() == 0) {
if(LOG.isLoggable(INFO)) LOG.info("Remote end hung up"); if(LOG.isLoggable(INFO)) LOG.info("Remote end hung up");
...@@ -175,22 +171,26 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -175,22 +171,26 @@ class ModemImpl implements Modem, SerialPortEventListener {
lineLen = 0; lineLen = 0;
if(LOG.isLoggable(INFO)) LOG.info("Modem status: " + s); if(LOG.isLoggable(INFO)) LOG.info("Modem status: " + s);
if(s.startsWith("CONNECT")) { if(s.startsWith("CONNECT")) {
inputStream = new ModemInputStream();
outputStream = new ModemOutputStream();
synchronized(connected) {
if(connected.getAndSet(true))
throw new IOException("Connected twice");
connected.notifyAll();
}
// There might be data in the buffer as well as text // There might be data in the buffer as well as text
int off = i + 1; int off = i + 1;
if(off < b.length) { if(off < b.length) {
byte[] data = new byte[b.length - off]; byte[] data = new byte[b.length - off];
System.arraycopy(b, off, data, 0, data.length); System.arraycopy(b, off, data, 0, data.length);
received.add(data); inputStream.received.add(data);
}
synchronized(connected) {
if(!connected.getAndSet(true))
connected.notifyAll();
} }
return; return;
} else if(s.equals("OK")) { } else if(s.equals("OK")) {
synchronized(initialised) { synchronized(initialised) {
if(!initialised.getAndSet(true)) if(initialised.getAndSet(true))
initialised.notifyAll(); throw new IOException("Initialised twice");
initialised.notifyAll();
} }
} else if(s.equals("RING")) { } else if(s.equals("RING")) {
executor.execute(new Runnable() { executor.execute(new Runnable() {
...@@ -253,21 +253,23 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -253,21 +253,23 @@ class ModemImpl implements Modem, SerialPortEventListener {
private byte[] buf = null; private byte[] buf = null;
private int offset = 0; private int offset = 0;
private ModemInputStream(BlockingQueue<byte[]> received) { private volatile boolean closed = false;
this.received = received;
private ModemInputStream() {
this.received = new LinkedBlockingQueue<byte[]>();
} }
@Override @Override
public int read() throws IOException { public int read() throws IOException {
if(closed) throw new IOException("Connection closed");
getBufferIfNecessary(); getBufferIfNecessary();
if(buf.length == 0) return -1;
return buf[offset++]; return buf[offset++];
} }
@Override @Override
public int read(byte[] b) throws IOException { public int read(byte[] b) throws IOException {
if(closed) throw new IOException("Connection closed");
getBufferIfNecessary(); getBufferIfNecessary();
if(buf.length == 0) return -1;
int len = Math.min(b.length, buf.length - offset); int len = Math.min(b.length, buf.length - offset);
System.arraycopy(buf, offset, b, 0, len); System.arraycopy(buf, offset, b, 0, len);
offset += len; offset += len;
...@@ -276,8 +278,8 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -276,8 +278,8 @@ class ModemImpl implements Modem, SerialPortEventListener {
@Override @Override
public int read(byte[] b, int off, int len) throws IOException { public int read(byte[] b, int off, int len) throws IOException {
if(closed) throw new IOException("Connection closed");
getBufferIfNecessary(); getBufferIfNecessary();
if(buf.length == 0) return -1;
len = Math.min(len, buf.length - offset); len = Math.min(len, buf.length - offset);
System.arraycopy(buf, offset, b, off, len); System.arraycopy(buf, offset, b, off, len);
offset += len; offset += len;
...@@ -295,6 +297,7 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -295,6 +297,7 @@ class ModemImpl implements Modem, SerialPortEventListener {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new IOException(e.toString()); throw new IOException(e.toString());
} }
if(buf.length == 0) throw new IOException("Connection closed");
offset = 0; offset = 0;
} }
} }
...@@ -302,8 +305,11 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -302,8 +305,11 @@ class ModemImpl implements Modem, SerialPortEventListener {
private class ModemOutputStream extends OutputStream { private class ModemOutputStream extends OutputStream {
private volatile boolean closed = false;
@Override @Override
public void write(int b) throws IOException { public void write(int b) throws IOException {
if(closed) throw new IOException("Connection closed");
try { try {
port.writeByte((byte) b); port.writeByte((byte) b);
} catch(SerialPortException e) { } catch(SerialPortException e) {
...@@ -314,6 +320,7 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -314,6 +320,7 @@ class ModemImpl implements Modem, SerialPortEventListener {
@Override @Override
public void write(byte[] b) throws IOException { public void write(byte[] b) throws IOException {
if(closed) throw new IOException("Connection closed");
try { try {
port.writeBytes(b); port.writeBytes(b);
} catch(SerialPortException e) { } catch(SerialPortException e) {
...@@ -324,6 +331,7 @@ class ModemImpl implements Modem, SerialPortEventListener { ...@@ -324,6 +331,7 @@ class ModemImpl implements Modem, SerialPortEventListener {
@Override @Override
public void write(byte[] b, int off, int len) throws IOException { public void write(byte[] b, int off, int len) throws IOException {
if(closed) throw new IOException("Connection closed");
if(len < b.length) { if(len < b.length) {
byte[] copy = new byte[len]; byte[] copy = new byte[len];
System.arraycopy(b, off, copy, 0, len); System.arraycopy(b, off, copy, 0, len);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment