/* * Copyright (c) 2011 - 2013 United ID. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.unitedid.yhsm.internal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.unitedid.yhsm.internal.Defines.*; import static org.unitedid.yhsm.utility.Utils.*; public class CommandHandler { private static final Logger log = LoggerFactory.getLogger(CommandHandler.class); private CommandHandler() {} protected static synchronized byte[] execute(DeviceHandler device, byte command, byte[] data, boolean readResponse) throws YubiHSMErrorException { byte[] cmdBuffer; if (command != YSM_NULL) { cmdBuffer = new byte[]{(byte) (((data.length + 1) << 24) >> 24), command}; } else { cmdBuffer = new byte[]{command}; } log.debug("CMD BUFFER: {}", byteArrayToHex(concatAllArrays(cmdBuffer, data))); device.write(concatAllArrays(cmdBuffer, data)); try { if (!readResponse) { Thread.sleep(10); // We just sleep for safety since we cant check if we got any output return null; } int sleptTime = 0; int timeout = 100; // We enforce a default just in case (100 ms) if (device.getTimeout() > 0) { timeout = (int) (device.getTimeout() * 1000); // Need milliseconds } log.debug("CommandHandler ({}) timeout set to: {} ms ", getCommandString(command), timeout); while (sleptTime <= timeout) { Thread.sleep(1); sleptTime += 1; if (device.available() > 0) { break; } } log.debug("CommandHandler slept for: {} ms", sleptTime); } catch (InterruptedException e) { throw new RuntimeException(e); } return readDevice(device, command); } private static byte[] readDevice(DeviceHandler device, byte command) throws YubiHSMErrorException { byte[] result = new byte[0]; if (device.available() > 0) { result = device.read(2); } if (result.length == 0) { reset(device); throw new YubiHSMErrorException("No data received from the YubiHSM!"); } if ((result[1] & YSM_RESPONSE) != 0) { log.debug("Got response from ({}) {}", result[1], getCommandString((byte) (result[1] - YSM_RESPONSE))); } if (result[1] == (command | YSM_RESPONSE)) { int len = (int)result[0] - 1; return device.read(len); } else { reset(device); throw new YubiHSMErrorException("YubiHSM responded to the wrong command. Expected " + getCommandString(command) + " but got " + getCommandString((byte) (result[1] - YSM_RESPONSE))); } } public static void reset(DeviceHandler device) throws YubiHSMErrorException { log.debug("Sending reset command to device {}", device.getPortName()); byte[] reset = new byte[YSM_MAX_PKT_SIZE - 1]; for (int i=0; i < YSM_MAX_PKT_SIZE - 1; i++) { reset[i] = 0x00; } execute(device, YSM_NULL, reset, false); } }