/****************************************************************************
* Copyright (C) 2014-2015 TU Darmstadt.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file is part of the Open eCard App.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License version 3.0 as published by the Free Software Foundation
* and appearing in the file LICENSE.GPL included in the packaging of
* this file. Please review the following information to ensure the
* GNU General Public License version 3.0 requirements will be met:
* http://www.gnu.org/copyleft/gpl.html.
*
* Other Usage
* Alternatively, this file may be used in accordance with the terms
* and conditions contained in a signed written agreement between
* you and ecsec GmbH.
*
***************************************************************************/
package org.openecard.scio;
import javax.smartcardio.Card;
import javax.smartcardio.CardException;
import javax.smartcardio.CardNotPresentException;
import javax.smartcardio.CardTerminal;
import org.openecard.common.ifd.scio.SCIOCard;
import org.openecard.common.ifd.scio.SCIOErrorCode;
import org.openecard.common.ifd.scio.SCIOException;
import org.openecard.common.ifd.scio.SCIOProtocol;
import org.openecard.common.ifd.scio.SCIOTerminal;
import static org.openecard.scio.PCSCExceptionExtractor.getCode;
/**
* PC/SC terminal implementation of the SCIOTerminal.
*
* @author Wael Alkhatib
* @author Tobias Wich
*/
public class PCSCTerminal implements SCIOTerminal {
private final CardTerminal terminal;
PCSCTerminal(CardTerminal terminal) {
this.terminal = terminal;
}
@Override
public String getName() {
return terminal.getName();
}
// method is synchronized only to prevent JVM crashes on linux which happens after nPA authentication
// C [libpthread.so.0+0xb513] __pthread_mutex_unlock_usercnt+0x3
// j sun.security.smartcardio.PCSC.SCardStatus(J[B)[B+0
// j sun.security.smartcardio.CardImpl.isValid()Z+19
// j sun.security.smartcardio.TerminalImpl.connect(Ljava/lang/String;)Ljavax/smartcardio/Card;+36
// j org.openecard.scio.PCSCTerminal.connect(Lorg/openecard/common/ifd/scio/SCIOProtocol;)Lorg/openecard/common/ifd/scio/SCIOCard;+8
@Override
public SCIOCard connect(SCIOProtocol protocol) throws SCIOException, IllegalStateException {
synchronized (CardTerminal.class) {
try {
Card c = terminal.connect(protocol.identifier);
return new PCSCCard(this, c);
} catch (CardNotPresentException ex) {
String msg = "Card has been removed before connect could be finished for terminal '%s'.";
throw new SCIOException(String.format(msg, getName()), SCIOErrorCode.SCARD_W_REMOVED_CARD);
} catch (CardException ex) {
String msg = "Failed to connect the card in terminal '%s'.";
throw new SCIOException(String.format(msg, getName()), getCode(ex), ex);
}
}
}
@Override
public boolean isCardPresent() throws SCIOException {
try {
return terminal.isCardPresent();
} catch (CardException ex) {
throw new SCIOException("Failed to determine whether card is present or not.", getCode(ex), ex);
}
}
@Override
public boolean waitForCardPresent(long timeout) throws SCIOException {
try {
return terminal.waitForCardPresent(timeout);
} catch (CardException ex) {
String msg = "Failed to wait for card present event in terminal '%s'.";
throw new SCIOException(String.format(msg, getName()), getCode(ex), ex);
}
}
@Override
public boolean waitForCardAbsent(long timeout) throws SCIOException {
try {
return terminal.waitForCardAbsent(timeout);
} catch (CardException ex) {
String msg = "Failed to wait for card absent event in terminal '%s'.";
throw new SCIOException(String.format(msg, getName()), getCode(ex), ex);
}
}
}