From fcad87f94c3d7703bb059e1a3383057d76a914b6 Mon Sep 17 00:00:00 2001 From: Martin Paljak Date: Fri, 22 Jan 2016 12:50:15 +0200 Subject: [PATCH] Do not use transactions on Windows, if exclusive mode has been specified. https://msdn.microsoft.com/en-us/library/windows/desktop/aa379469%28v=vs.85%29.aspx --- src/apdu4j/SCTool.java | 11 ++++++++++- src/apdu4j/remote/CmdlineRemoteTerminal.java | 4 ++-- src/apdu4j/remote/JSONCardTerminalClient.java | 7 +++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/apdu4j/SCTool.java b/src/apdu4j/SCTool.java index f384427..0ff5e42 100644 --- a/src/apdu4j/SCTool.java +++ b/src/apdu4j/SCTool.java @@ -429,8 +429,17 @@ private static void work(CardTerminal reader, OptionSet args) throws CardExcepti transport = SocketTransport.connect(string2socket(remote), null); } + // Windows 8+ have the "5 seconds of transaction" limit. Because we want reliability + // and don't have access to arbitrary SCard* calls via javax.smartcardio, we rely on + // JNA interface and its EXCLUSIVE access instead and do NOT use the SCardBeginTransaction + // capability of the JNA interface. + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa379469%28v=vs.85%29.aspx + boolean transact = true; + if (System.getProperty("os.name").toLowerCase().contains("windows") && args.has(OPT_EXCLUSIVE)) { + transact = false; + } // Connect the transport and the terminal - CmdlineRemoteTerminal c = new CmdlineRemoteTerminal(transport, reader); + CmdlineRemoteTerminal c = new CmdlineRemoteTerminal(transport, reader, transact); c.forceProtocol(protocol); // Run c.run(); diff --git a/src/apdu4j/remote/CmdlineRemoteTerminal.java b/src/apdu4j/remote/CmdlineRemoteTerminal.java index b3d444a..3cd0cd4 100644 --- a/src/apdu4j/remote/CmdlineRemoteTerminal.java +++ b/src/apdu4j/remote/CmdlineRemoteTerminal.java @@ -46,9 +46,9 @@ public class CmdlineRemoteTerminal implements Runnable { // The terminal that is tunneled private JSONCardTerminalClient jsonterminal; - public CmdlineRemoteTerminal(JSONMessagePipe pipe, CardTerminal terminal) { + public CmdlineRemoteTerminal(JSONMessagePipe pipe, CardTerminal terminal, boolean transact) { this.pipe = pipe; - this.jsonterminal = new JSONCardTerminalClient(terminal, pipe); + this.jsonterminal = new JSONCardTerminalClient(terminal, pipe, transact); } @Override diff --git a/src/apdu4j/remote/JSONCardTerminalClient.java b/src/apdu4j/remote/JSONCardTerminalClient.java index 469fa77..cdbc7bf 100644 --- a/src/apdu4j/remote/JSONCardTerminalClient.java +++ b/src/apdu4j/remote/JSONCardTerminalClient.java @@ -40,10 +40,12 @@ class JSONCardTerminalClient { private final JSONMessagePipe pipe; protected Card card = null; // There can be several connects-disconnects private String protocol = null; // Local protocol to use, overriding the other side + private boolean transact = true; - public JSONCardTerminalClient(CardTerminal terminal, JSONMessagePipe pipe) { + public JSONCardTerminalClient(CardTerminal terminal, JSONMessagePipe pipe, boolean transact) { this.terminal = terminal; this.pipe = pipe; + this.transact = transact; } public void forceProtocol(String protocol) { @@ -59,7 +61,8 @@ public boolean processMessage(Map msg) throws IOException, CardE protocol = (String) msg.get("protocol"); } card = terminal.connect(protocol); - card.beginExclusive(); + if (transact) + card.beginExclusive(); Map m = JSONProtocol.ok(msg); m.put("atr", HexUtils.encodeHexString(card.getATR().getBytes())); m.put("reader", terminal.getName());