mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 13:49:53 +01:00
First pass at a modem plugin (unfinished).
This commit is contained in:
@@ -6,7 +6,7 @@ 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. If the modem or its input or output streams throw an exception it
|
* calls. If the modem or its input or output streams throw any exceptions they
|
||||||
* cannot continue to be used.
|
* cannot continue to be used.
|
||||||
*/
|
*/
|
||||||
interface Modem {
|
interface Modem {
|
||||||
|
|||||||
6
src/net/sf/briar/plugins/modem/ModemFactory.java
Normal file
6
src/net/sf/briar/plugins/modem/ModemFactory.java
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package net.sf.briar.plugins.modem;
|
||||||
|
|
||||||
|
interface ModemFactory {
|
||||||
|
|
||||||
|
Modem createModem(Modem.Callback callback, String portName);
|
||||||
|
}
|
||||||
16
src/net/sf/briar/plugins/modem/ModemFactoryImpl.java
Normal file
16
src/net/sf/briar/plugins/modem/ModemFactoryImpl.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package net.sf.briar.plugins.modem;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
class ModemFactoryImpl implements ModemFactory {
|
||||||
|
|
||||||
|
private final Executor executor;
|
||||||
|
|
||||||
|
ModemFactoryImpl(Executor executor) {
|
||||||
|
this.executor = executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Modem createModem(Modem.Callback callback, String portName) {
|
||||||
|
return new ModemImpl(executor, callback, portName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,34 @@
|
|||||||
package net.sf.briar.plugins.modem;
|
package net.sf.briar.plugins.modem;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import jssc.SerialPortList;
|
||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
|
import net.sf.briar.api.TransportProperties;
|
||||||
import net.sf.briar.api.crypto.PseudoRandom;
|
import net.sf.briar.api.crypto.PseudoRandom;
|
||||||
import net.sf.briar.api.plugins.PluginCallback;
|
|
||||||
import net.sf.briar.api.plugins.PluginExecutor;
|
import net.sf.briar.api.plugins.PluginExecutor;
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
|
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
|
||||||
|
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
||||||
import net.sf.briar.api.protocol.TransportId;
|
import net.sf.briar.api.protocol.TransportId;
|
||||||
import net.sf.briar.util.StringUtils;
|
import net.sf.briar.util.StringUtils;
|
||||||
|
|
||||||
class ModemPlugin implements DuplexPlugin {
|
class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
||||||
|
|
||||||
static final byte[] TRANSPORT_ID =
|
static final byte[] TRANSPORT_ID =
|
||||||
StringUtils.fromHexString("8f573867bedf54884b5868ee5d902832" +
|
StringUtils.fromHexString("8f573867bedf54884b5868ee5d902832" +
|
||||||
@@ -26,14 +40,22 @@ class ModemPlugin implements DuplexPlugin {
|
|||||||
Logger.getLogger(ModemPlugin.class.getName());
|
Logger.getLogger(ModemPlugin.class.getName());
|
||||||
|
|
||||||
private final Executor pluginExecutor;
|
private final Executor pluginExecutor;
|
||||||
private final PluginCallback callback;
|
private final ModemFactory modemFactory;
|
||||||
|
private final DuplexPluginCallback callback;
|
||||||
private final long pollingInterval;
|
private final long pollingInterval;
|
||||||
|
private final Semaphore polling;
|
||||||
|
|
||||||
|
private volatile boolean running = false;
|
||||||
|
private volatile Modem modem = null;
|
||||||
|
|
||||||
ModemPlugin(@PluginExecutor Executor pluginExecutor,
|
ModemPlugin(@PluginExecutor Executor pluginExecutor,
|
||||||
PluginCallback callback, long pollingInterval) {
|
ModemFactory modemFactory, DuplexPluginCallback callback,
|
||||||
|
long pollingInterval) {
|
||||||
this.pluginExecutor = pluginExecutor;
|
this.pluginExecutor = pluginExecutor;
|
||||||
|
this.modemFactory = modemFactory;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.pollingInterval = pollingInterval;
|
this.pollingInterval = pollingInterval;
|
||||||
|
polling = new Semaphore(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
@@ -44,13 +66,22 @@ class ModemPlugin implements DuplexPlugin {
|
|||||||
return "MODEM_PLUGIN_NAME";
|
return "MODEM_PLUGIN_NAME";
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean start() throws IOException {
|
public boolean start() {
|
||||||
// FIXME
|
for(String portName : SerialPortList.getPortNames()) {
|
||||||
|
modem = modemFactory.createModem(this, portName);
|
||||||
|
try {
|
||||||
|
modem.init();
|
||||||
|
running = true;
|
||||||
|
return true;
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() throws IOException {
|
public void stop() {
|
||||||
// FIXME
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldPoll() {
|
public boolean shouldPoll() {
|
||||||
@@ -62,12 +93,68 @@ class ModemPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
// FIXME
|
if(!connected.isEmpty()) return; // One at a time please
|
||||||
|
pluginExecutor.execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
poll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void poll() {
|
||||||
|
if(!running) return;
|
||||||
|
if(!polling.tryAcquire()) {
|
||||||
|
if(LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Previous poll still in progress");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Call contacts one at a time in a random order
|
||||||
|
Map<ContactId, TransportProperties> remote =
|
||||||
|
callback.getRemoteProperties();
|
||||||
|
List<ContactId> contacts = new ArrayList<ContactId>(remote.keySet());
|
||||||
|
Collections.shuffle(contacts);
|
||||||
|
Iterator<ContactId> it = contacts.iterator();
|
||||||
|
while(it.hasNext() && running) {
|
||||||
|
ContactId c = it.next();
|
||||||
|
String number = remote.get(c).get("number");
|
||||||
|
if(number == null) continue;
|
||||||
|
try {
|
||||||
|
if(!modem.dial(number)) continue;
|
||||||
|
} catch(IOException e) {
|
||||||
|
// FIXME: Race condition with stop()
|
||||||
|
running = false;
|
||||||
|
if(start()) continue;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
ModemTransportConnection conn = new ModemTransportConnection();
|
||||||
|
callback.outgoingConnectionCreated(c, conn);
|
||||||
|
try {
|
||||||
|
conn.waitForDisposal();
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.warning("Interrupted while polling");
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
polling.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
// FIXME
|
if(!running) return null;
|
||||||
return null;
|
final Map<ContactId, TransportProperties> remote =
|
||||||
|
callback.getRemoteProperties();
|
||||||
|
String number = remote.get(c).get("number");
|
||||||
|
if(number == null) return null;
|
||||||
|
try {
|
||||||
|
if(!modem.dial(number)) return null;
|
||||||
|
} catch(IOException e) {
|
||||||
|
// FIXME: Race condition with stop()
|
||||||
|
running = false;
|
||||||
|
start();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ModemTransportConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean supportsInvitations() {
|
public boolean supportsInvitations() {
|
||||||
@@ -83,4 +170,45 @@ class ModemPlugin implements DuplexPlugin {
|
|||||||
long timeout) {
|
long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void incomingCallConnected() {
|
||||||
|
callback.incomingConnectionCreated(new ModemTransportConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ModemTransportConnection
|
||||||
|
implements DuplexTransportConnection {
|
||||||
|
|
||||||
|
private final CountDownLatch finished = new CountDownLatch(1);
|
||||||
|
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return modem.getInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getOutputStream() {
|
||||||
|
return modem.getOutputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldFlush() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose(boolean exception, boolean recognised) {
|
||||||
|
try {
|
||||||
|
modem.hangUp();
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
exception = true;
|
||||||
|
}
|
||||||
|
if(exception) {
|
||||||
|
// FIXME: Race condition with stop()
|
||||||
|
running = false;
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
finished.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitForDisposal() throws InterruptedException {
|
||||||
|
finished.await();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ public class ModemPluginFactory implements DuplexPluginFactory {
|
|||||||
// This plugin is not enabled by default
|
// This plugin is not enabled by default
|
||||||
String enabled = callback.getConfig().get("enabled");
|
String enabled = callback.getConfig().get("enabled");
|
||||||
if(StringUtils.isNullOrEmpty(enabled)) return null;
|
if(StringUtils.isNullOrEmpty(enabled)) return null;
|
||||||
return new ModemPlugin(pluginExecutor, callback, POLLING_INTERVAL);
|
ModemFactory modemFactory = new ModemFactoryImpl(pluginExecutor);
|
||||||
|
return new ModemPlugin(pluginExecutor, modemFactory, callback,
|
||||||
|
POLLING_INTERVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user