blob: 66cedbb38c82cf9d42193169153066576fb18ad7 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.smartcardio;
27
28import java.util.*;
29
30import javax.smartcardio.*;
31
32import static sun.security.smartcardio.PCSC.*;
33
34/**
35 * CardTerminal implementation.
36 *
37 * @since 1.6
38 * @author Andreas Sterbenz
39 */
40final class TerminalImpl extends CardTerminal {
41
42 // native SCARDCONTEXT
43 final long contextId;
44
45 // the name of this terminal (native PC/SC name)
46 final String name;
47
48 private CardImpl card;
49
50 TerminalImpl(long contextId, String name) {
51 this.contextId = contextId;
52 this.name = name;
53 }
54
55 public String getName() {
56 return name;
57 }
58
59 public synchronized Card connect(String protocol) throws CardException {
60 SecurityManager sm = System.getSecurityManager();
61 if (sm != null) {
62 sm.checkPermission(new CardPermission(name, "connect"));
63 }
64 if (card != null) {
65 if (card.isValid()) {
66 String cardProto = card.getProtocol();
67 if (protocol.equals("*") || protocol.equalsIgnoreCase(cardProto)) {
68 return card;
69 } else {
70 throw new CardException("Cannot connect using " + protocol
71 + ", connection already established using " + cardProto);
72 }
73 } else {
74 card = null;
75 }
76 }
77 try {
78 card = new CardImpl(this, protocol);
79 return card;
80 } catch (PCSCException e) {
81 if (e.code == SCARD_W_REMOVED_CARD) {
82 throw new CardNotPresentException("No card present", e);
83 } else {
84 throw new CardException("connect() failed", e);
85 }
86 }
87 }
88
89 public boolean isCardPresent() throws CardException {
90 try {
91 int[] status = SCardGetStatusChange(contextId, 0,
92 new int[] {SCARD_STATE_UNAWARE}, new String[] {name});
93 return (status[0] & SCARD_STATE_PRESENT) != 0;
94 } catch (PCSCException e) {
95 throw new CardException("isCardPresent() failed", e);
96 }
97 }
98
99 private boolean waitForCard(boolean wantPresent, long timeout) throws CardException {
100 if (timeout < 0) {
101 throw new IllegalArgumentException("timeout must not be negative");
102 }
103 if (timeout == 0) {
104 timeout = TIMEOUT_INFINITE;
105 }
106 int[] status = new int[] {SCARD_STATE_UNAWARE};
107 String[] readers = new String[] {name};
108 try {
109 // check if card status already matches
110 status = SCardGetStatusChange(contextId, 0, status, readers);
111 boolean present = (status[0] & SCARD_STATE_PRESENT) != 0;
112 if (wantPresent == present) {
113 return true;
114 }
115 // no match, wait
116 status = SCardGetStatusChange(contextId, timeout, status, readers);
117 present = (status[0] & SCARD_STATE_PRESENT) != 0;
118 // should never happen
119 if (wantPresent != present) {
120 throw new CardException("wait mismatch");
121 }
122 return true;
123 } catch (PCSCException e) {
124 if (e.code == SCARD_E_TIMEOUT) {
125 return false;
126 } else {
127 throw new CardException("waitForCard() failed", e);
128 }
129 }
130 }
131
132 public boolean waitForCardPresent(long timeout) throws CardException {
133 return waitForCard(true, timeout);
134 }
135
136 public boolean waitForCardAbsent(long timeout) throws CardException {
137 return waitForCard(false, timeout);
138 }
139
140 public String toString() {
141 return "PC/SC terminal " + name;
142 }
143}