Package uk.co.nimp.scard

Source Code of uk.co.nimp.scard.RemoteTerminalManager

/**
*
* @author Sebastien Riou
*/
package uk.co.nimp.scard;

import com.atolsystems.atolutilities.ACommandLineUtilities;
import com.atolsystems.atolutilities.ACommandLineUtilities.Arg;
import com.atolsystems.atolutilities.ArgSpec;
import com.atolsystems.atolutilities.IoServer;
import com.atolsystems.atolutilities.MutableInteger;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.List;
import java.io.File;
import java.io.OutputStream;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import uk.co.nimp.smartcard.AnswerToReset;
import static uk.co.nimp.scard.MP300Exception.*;
import uk.co.nimp.smartcard.Apdu;

public class RemoteTerminalManager extends GenericTerminalManager {

    static transient Integer remoteReaders[];

    static final String ARG_HELP = "-help";
    static final int ARG_HELP_ID = 0;
    static final String ARG_ADD_REMOTE_TERMINAL = "-addRemoteTerminal:";
    static final int ARG_ADD_REMOTE_TERMINAL_ID = 1;
    static final String CONF_FILE_NAME="RemoteTerminalManager.conf";

    static {
        remoteReaders = new Integer[0];
        //for test
        remoteReaders = new Integer[1];
        remoteReaders[0]=42533;
        //GenericTerminalManager.registerTerminalManager(VirtualTerminalManager.class);
    }

    public RemoteTerminalManager() throws IOException{
    }
    protected String getConfFileName(){
        return CONF_FILE_NAME;
    }
    @Override
    protected void loadConfigurationImpl(File argFile) throws IOException {
        try{
            if(argFile.exists()){
                ArrayList<String> argList=ACommandLineUtilities.processArgFile(argFile);
                if((null==argList) || argList.isEmpty())
                    return;
                String args[] = new String[argList.size()];
                argList.toArray(args);
                Integer curArgIndex = null;
                Arg curArg = null;
                curArgIndex = 0;
                ArrayList<Integer> virtualTerminalList=new ArrayList<Integer>();

                ArgSpec argSpecs[] = {
                    new ArgSpec(ARG_HELP, ARG_HELP_ID),
                    new ArgSpec(ARG_ADD_REMOTE_TERMINAL, ARG_ADD_REMOTE_TERMINAL_ID, ArgSpec.UNLIMITED_OCCURENCE),
                    };
                Set<ArgSpec> specs=ACommandLineUtilities.addArgFileArgSpecs(argSpecs);
                argSpecs=new ArgSpec[specs.size()];
                specs.toArray(argSpecs);
                ACommandLineUtilities.checkArgs(args, argSpecs);

                while (curArgIndex < args.length) {
                    curArg = ACommandLineUtilities.getArg(args, argSpecs, curArgIndex, null);
                    if(null!=curArg){
                        switch (curArg.id) {
                            case ARG_HELP_ID:
                                StringBuilder sb=new StringBuilder();
                                sb.append("RemoteTerminalManager configuration file help\n\n");
                                sb.append(ARG_ADD_REMOTE_TERMINAL);
                                sb.append("<port of the reader>\n");
                                sb.append("Add a remote reader.\n");
                                System.out.println(sb.toString());
                                break;
                            case ARG_ADD_REMOTE_TERMINAL_ID:
                                virtualTerminalList.add(Integer.decode(curArg.value));
                                break;
                            /*default:
                                throw new RuntimeException("Internal error related to command line arguments");*/
                        }
                    }
                    curArgIndex++;
                }
                if(virtualTerminalList.size()>0){
                    remoteReaders = new Integer[virtualTerminalList.size()];
                    virtualTerminalList.toArray(remoteReaders);
                }
            }
        }catch(Throwable e){
            throw new RuntimeException("Exception occured during processing of configuration file below\n"+argFile.getAbsolutePath()+"\n", e);
        }
    }

    static public void initContext() throws ScardException {
        Runtime.getRuntime().addShutdownHook(new Thread() {

            @Override
            public void run() {
                {
                    //release all resources
                    //TODO: currently both calls return "bad argument"
                    int status = 0;
                    if (RET_OK != status) {
                        //throw new ScardException("MPOS_CloseResource returned " + status);
                        }
                   
                }
            }
        });
    }

    @Override
    public List<GenericTerminal> list() throws ScardException {
        List<GenericTerminal> terminalsList = new ArrayList<GenericTerminal>();
        for(int i=0;i<remoteReaders.length;i++){
            try {
                GenericTerminal terminal = getTerminalImpl(remoteReaders[i]);
                terminalsList.add(terminal);
            } catch (MP300Exception e) {
            } catch (IOException e){
            }
        }

        return Collections.unmodifiableList(terminalsList);
    }
    private static final Map<Integer, Reference<GenericTerminal>> terminals = new HashMap<Integer, Reference<GenericTerminal>>();

    protected static GenericTerminal getTerminalImpl(int port) throws ScardException, IOException {
        Reference<GenericTerminal> ref = terminals.get(port);
        GenericTerminal terminal = (ref != null) ? ref.get() : null;
        if (terminal != null) {
            return terminal;
        }
        String name="RemoteTerminal on port "+port;
        IoServer context = new IoServer("RemoteTerminalManager", port);
        terminal = new RemoteTerminal(name, context);
        terminals.put(port, new WeakReference<GenericTerminal>(terminal));

        return terminal;
    }
    static AnswerToReset SCardConnect(IoServer context) throws ScardException {
        if(!context.isConnected()) throw new ScardException("card disconnected");
        byte atrBuf[] = new byte[2];
        atrBuf[0]=0x3F;
        atrBuf[1]=0;
        AnswerToReset out=new AnswerToReset(atrBuf);
        return out;
    }

    static void SCardTransmit(IoServer context, Apdu apdu) throws ScardException {
        if(!context.isConnected()) throw new ScardException("card disconnected");
        try {
            OutputStream out=context.getOutputStream();
            out.write(apdu.getT0Header());
            out.flush();
            DataInputStream in = new DataInputStream(context.getInputStream());
            byte pb;
            while(true){
                pb= in.readByte();
                if(0x60!=pb) break;
            }
            if(Apdu.isT0Sw1Byte(pb)){//we got status word right away
                apdu.setSw1(pb);
                pb= in.readByte();
                apdu.setSw2(pb);
            }else{
                if(apdu.getLc()+apdu.getExpectedLe()==0){
                    if(pb!=apdu.getIns()){
                    throw new ScardException("Card answered "+pb+" instead of a valid procedure byte");
                }else{
                    if(apdu.getLc()>0){
                        int nBytes = apdu.getLc();
                        int curByte = 0;
                        byte []data = apdu.getLcDataAsBytes();
                        while(nBytes>curByte){
                            if(pb==apdu.getIns()){//we got ACK byte
                                out.write(data, curByte, nBytes-curByte);
                                out.flush();
                                curByte=nBytes;
                            }else if((0xFF & pb)==(0xFF & ~apdu.getIns())){//we got NACK byte
                                out.write(data[curByte++]);
                                out.flush();
                                if(nBytes>curByte)
                                    pb=in.readByte();
                            }else{
                                throw new ScardException("Card answered "+pb+" instead of a valid procedure byte");
                            }
                        }
                        if(apdu.getExpectedLe()>0){
                            throw new RuntimeException("TODO: send get response command");
                        }
                    }
                    if(apdu.getExpectedLe()>0){
                        int nBytes = apdu.getExpectedLe();
                        int curByte = 0;
                        byte []data = new byte[nBytes];
                        while(nBytes>curByte){
                            if(pb==apdu.getIns()){//we got ACK byte
                                in.read(data, curByte, nBytes-curByte);
                                curByte=nBytes;
                            }else if((0xFF & pb)==(0xFF & ~apdu.getIns())){//we got NACK byte
                                data[curByte++]=in.readByte();
                                if(nBytes>curByte)
                                    pb=in.readByte();
                            }else{
                                throw new ScardException("Card answered "+pb+" instead of a valid procedure byte");
                            }
                        }
                        apdu.setLeData(data);
                        }
                    }
                    byte sw1 = in.readByte();
                    byte sw2 = in.readByte();
                    apdu.setSw1(sw1);
                    apdu.setSw2(sw2);
                }
            }
        } catch (IOException ex) {
            throw new ScardException(ex);
        }
    }

    static void SCardDisconnect(IoServer context, int disposition) throws ScardException {
        context.disconnect();
    }

    static GenericTerminal.State SCardIsPresent(IoServer context) throws ScardException {
        if(context.isConnected())
            return GenericTerminal.State.CARD_PRESENT;
        return GenericTerminal.State.CARD_ABSENT;
    }

}
TOP

Related Classes of uk.co.nimp.scard.RemoteTerminalManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.