add listening mode to the reader
This commit is contained in:
@@ -198,11 +198,12 @@ public class MainActivity extends AppCompatActivity implements NfcAdapter.Reader
|
||||
}
|
||||
|
||||
private void vpcdConnect(SCReader scReader) {
|
||||
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
int port = Integer.parseInt(SP.getString("port", Integer.toString(VPCDWorker.DEFAULT_PORT)));
|
||||
String hostname = SP.getString("hostname", VPCDWorker.DEFAULT_HOSTNAME);
|
||||
final SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
final int port = Integer.parseInt(SP.getString("port", Integer.toString(VPCDWorker.DEFAULT_PORT)));
|
||||
final String hostname = SP.getString("hostname", VPCDWorker.DEFAULT_HOSTNAME);
|
||||
final boolean listen = SP.getBoolean("listen", VPCDWorker.DEFAULT_LISTEN);
|
||||
vpcdTest = new VPCDWorker();
|
||||
vpcdTest.execute(new VPCDWorker.VPCDWorkerParams(hostname, port, scReader));
|
||||
vpcdTest.execute(new VPCDWorker.VPCDWorkerParams(hostname, port, scReader, listen));
|
||||
}
|
||||
|
||||
private void vpcdDisconnect() {
|
||||
|
||||
@@ -29,8 +29,17 @@ import com.vsmartcard.remotesmartcardreader.app.screaders.SCReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InterfaceAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class VPCDWorker extends AsyncTask<VPCDWorker.VPCDWorkerParams, Void, Void> {
|
||||
|
||||
@@ -38,18 +47,22 @@ class VPCDWorker extends AsyncTask<VPCDWorker.VPCDWorkerParams, Void, Void> {
|
||||
final String hostname;
|
||||
final int port;
|
||||
final SCReader reader;
|
||||
VPCDWorkerParams(String hostname, int port, SCReader reader) {
|
||||
final boolean listen;
|
||||
VPCDWorkerParams(String hostname, int port, SCReader reader, boolean listen) {
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
this.reader = reader;
|
||||
this.listen = listen;
|
||||
}
|
||||
}
|
||||
|
||||
public static final int DEFAULT_PORT = 35963;
|
||||
// default URI when used in emulator
|
||||
public static final String DEFAULT_HOSTNAME = "10.0.2.2";
|
||||
public static final boolean DEFAULT_LISTEN = false;
|
||||
|
||||
private SCReader reader;
|
||||
private ServerSocket listenSocket;
|
||||
private Socket socket;
|
||||
private InputStream inputStream;
|
||||
private OutputStream outputStream;
|
||||
@@ -75,15 +88,22 @@ class VPCDWorker extends AsyncTask<VPCDWorker.VPCDWorkerParams, Void, Void> {
|
||||
public Void doInBackground(VPCDWorkerParams... params) {
|
||||
try {
|
||||
reader = params[0].reader;
|
||||
Log.i(this.getClass().getName(), "Connecting to " + params[0].hostname + ":" + Integer.toString(params[0].port) + "...");
|
||||
vpcdConnect(params[0].hostname, params[0].port);
|
||||
Log.i(this.getClass().getName(), "Connected to VPCD");
|
||||
vpcdConnection(params[0]);
|
||||
|
||||
while (!isCancelled()) {
|
||||
vpcdAccept();
|
||||
byte[] out = null;
|
||||
byte[] in = receiveFromVPCD();
|
||||
if (in == null)
|
||||
break;
|
||||
if (in == null) {
|
||||
if (listenSocket == null) {
|
||||
Log.i(this.getClass().getName(), "End of stream, finishing");
|
||||
break;
|
||||
} else {
|
||||
Log.i(this.getClass().getName(), "End of stream, closing connection");
|
||||
vpcdCloseClient();
|
||||
continue; // back to accept
|
||||
}
|
||||
}
|
||||
|
||||
if (in.length == VPCD_CTRL_LEN) {
|
||||
switch (in[0]) {
|
||||
@@ -169,7 +189,79 @@ class VPCDWorker extends AsyncTask<VPCDWorker.VPCDWorkerParams, Void, Void> {
|
||||
outputStream.flush();
|
||||
}
|
||||
|
||||
private void vpcdConnection(VPCDWorkerParams params) throws IOException {
|
||||
if (params.listen){
|
||||
vpcdListen(params.port);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(this.getClass().getName(), "Connecting to " + params.hostname + ":" + Integer.toString(params.port) + "...");
|
||||
vpcdConnect(params.hostname, params.port);
|
||||
Log.i(this.getClass().getName(), "Connected to VPCD");
|
||||
}
|
||||
|
||||
private void vpcdListen(int port) throws IOException {
|
||||
listenSocket = new ServerSocket(port);
|
||||
|
||||
final List<String> ifaceAddresses = new LinkedList<>();
|
||||
final Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
|
||||
while(ifaces.hasMoreElements()){
|
||||
final NetworkInterface iface = ifaces.nextElement();
|
||||
if (!iface.isUp() || iface.isLoopback() || iface.isVirtual()) {
|
||||
continue;
|
||||
}
|
||||
for(InterfaceAddress addr : iface.getInterfaceAddresses()){
|
||||
final InetAddress inetAddr = addr.getAddress();
|
||||
ifaceAddresses.add(inetAddr.getHostAddress());
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(this.getClass().getName(), "Listening on port " + port + ". Local addresses: " + join(", ", ifaceAddresses));
|
||||
}
|
||||
|
||||
private void vpcdAccept() throws IOException {
|
||||
if(listenSocket == null){
|
||||
return;
|
||||
}
|
||||
|
||||
if (socket != null){
|
||||
return; // Already accepted, only one client allowed
|
||||
}
|
||||
|
||||
Log.i(this.getClass().getName(),"Waiting for connections...");
|
||||
while(!isCancelled()) {
|
||||
listenSocket.setSoTimeout(1000);
|
||||
try {
|
||||
socket = listenSocket.accept();
|
||||
} catch (SocketTimeoutException ignored){}
|
||||
if (socket != null){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(this.getClass().getName(),"Connected, " + socket.getInetAddress());
|
||||
listenSocket.setSoTimeout(0);
|
||||
outputStream = socket.getOutputStream();
|
||||
inputStream = socket.getInputStream();
|
||||
}
|
||||
|
||||
private void vpcdCloseClient(){
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException ignored) { }
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException ignored) { }
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ignored) { }
|
||||
outputStream = null;
|
||||
inputStream = null;
|
||||
socket = null;
|
||||
}
|
||||
|
||||
private void vpcdConnect(String hostname, int port) throws IOException {
|
||||
listenSocket = null;
|
||||
socket = new Socket(InetAddress.getByName(hostname), port);
|
||||
outputStream = socket.getOutputStream();
|
||||
inputStream = socket.getInputStream();
|
||||
@@ -183,5 +275,25 @@ class VPCDWorker extends AsyncTask<VPCDWorker.VPCDWorkerParams, Void, Void> {
|
||||
socket.close();
|
||||
Log.i(this.getClass().getName(), "Disconnected from VPCD");
|
||||
}
|
||||
if (listenSocket != null) {
|
||||
Log.i(this.getClass().getName(), "Closing listening socket");
|
||||
listenSocket.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Usage of API level 24+ would allow streams(), join can be removed.
|
||||
*/
|
||||
private static String join(String separator, List<String> input) {
|
||||
if (input == null || input.size() <= 0) return "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < input.size(); i++) {
|
||||
sb.append(input.get(i));
|
||||
if (i != input.size() - 1) {
|
||||
sb.append(separator);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -55,5 +55,6 @@
|
||||
<string name="action_delete">Clear Log</string>
|
||||
|
||||
<string name="title_activity_settings">Settings</string>
|
||||
<string name="hint_vpcd_listen">Listen for connections</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
android:inputType="number"
|
||||
android:hint="Default: 35963" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="listen"
|
||||
android:defaultValue="false"
|
||||
android:title="@string/hint_vpcd_listen"
|
||||
android:hint="Default: false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
|
||||
Reference in New Issue
Block a user