All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.veraxsystems.vxipmi.api.sol.SerialOverLan Maven / Gradle / Ivy

The newest version!
/*
 * SerialOverLan.java
 * Created on 31.05.2017
 *
 * Copyright (c) Sonalake 2017.
 * All rights reserved.
 *
 * This software is furnished under a license. Use, duplication,
 * disclosure and all other uses are restricted to the rights
 * specified in the written license agreement.
 */
package com.veraxsystems.vxipmi.api.sol;

import com.veraxsystems.vxipmi.api.async.ConnectionHandle;
import com.veraxsystems.vxipmi.api.async.InboundSolMessageListener;
import com.veraxsystems.vxipmi.api.sync.IpmiConnector;
import com.veraxsystems.vxipmi.coding.PayloadCoder;
import com.veraxsystems.vxipmi.coding.commands.IpmiVersion;
import com.veraxsystems.vxipmi.coding.commands.PrivilegeLevel;
import com.veraxsystems.vxipmi.coding.commands.payload.ActivateSolPayload;
import com.veraxsystems.vxipmi.coding.commands.payload.ActivateSolPayloadResponseData;
import com.veraxsystems.vxipmi.coding.commands.payload.DeactivatePayload;
import com.veraxsystems.vxipmi.coding.commands.payload.GetPayloadActivationStatus;
import com.veraxsystems.vxipmi.coding.commands.payload.GetPayloadActivationStatusResponseData;
import com.veraxsystems.vxipmi.coding.commands.session.SetSessionPrivilegeLevel;
import com.veraxsystems.vxipmi.coding.payload.CompletionCode;
import com.veraxsystems.vxipmi.coding.payload.lan.IPMIException;
import com.veraxsystems.vxipmi.coding.payload.sol.SolAckState;
import com.veraxsystems.vxipmi.coding.payload.sol.SolMessage;
import com.veraxsystems.vxipmi.coding.payload.sol.SolOperation;
import com.veraxsystems.vxipmi.coding.protocol.AuthenticationType;
import com.veraxsystems.vxipmi.coding.protocol.PayloadType;
import com.veraxsystems.vxipmi.coding.security.CipherSuite;
import com.veraxsystems.vxipmi.coding.sol.SolCoder;
import com.veraxsystems.vxipmi.coding.sol.SolResponseData;
import com.veraxsystems.vxipmi.common.Constants;
import com.veraxsystems.vxipmi.common.TypeConverter;
import com.veraxsystems.vxipmi.connection.Session;
import com.veraxsystems.vxipmi.connection.SessionException;
import com.veraxsystems.vxipmi.connection.SessionManager;
import org.apache.log4j.Logger;

import java.io.Closeable;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * Entry point for the Serial Over LAN (SOL) communication. Use all SOL operations through this class.
 */
public class SerialOverLan implements Closeable {

    private static final Logger logger = Logger.getLogger(SerialOverLan.class);

    private final IpmiConnector connector;
    private final Session session;
    private final InboundSolMessageListener inboundMessageListener;
    private final List eventListeners;

    private boolean isSessionInternal;
    private int payloadInstance;
    private int maxPayloadSize;
    private boolean closed;

    /**
     * Creates connection with IPMI using given {@link IpmiConnector}, connected to remote machine on given address and port,
     * and opens a new {@link Session} for SOL communication.
     * This constructor should be used only when you have no other connection opened on this port.
     *
     * @param connector
     *          {@link IpmiConnector} that will be used for communication
     * @param remoteHost
     *          IP address of the remote server
     * @param remotePort
     *          UDP port number of the remote server
     * @param user
     *          IPMI user name
     * @param password
     *          IPMI password
     * @param cipherSuiteSelectionHandler
     *          {@link CipherSuiteSelectionHandler} that will allow to select {@link CipherSuite} among available ones.
     *
     * @throws SOLException when any problem occur during establishing session or activating SOL payload.
     */
    public SerialOverLan(IpmiConnector connector, String remoteHost, int remotePort, String user, String password,
                         CipherSuiteSelectionHandler cipherSuiteSelectionHandler) throws SOLException, SessionException {
        this(connector, SessionManager.establishSession(connector, remoteHost, remotePort, user, password, cipherSuiteSelectionHandler));

        this.isSessionInternal = true;
    }

    /**
     * Creates connection with IPMI using given {@link IpmiConnector}, connected to remote machine on given address and default IPMI port,
     * and opens a new {@link Session} for SOL communication.
     * This constructor should be used only when you have no other connection opened on this port.
     *
     * @param connector
     *          {@link IpmiConnector} that will be used for communication
     * @param remoteHost
     *          IP address of the remote server
     * @param user
     *          IPMI user name
     * @param password
     *          IPMI password
     * @param cipherSuiteSelectionHandler
     *          {@link CipherSuiteSelectionHandler} that will allow to select {@link CipherSuite} among available ones.
     *
     * @throws SOLException when any problem occur during establishing session or activating SOL payload.
     */
    public SerialOverLan(IpmiConnector connector, String remoteHost, String user, String password,
                         CipherSuiteSelectionHandler cipherSuiteSelectionHandler) throws SOLException, SessionException {
        this(connector, remoteHost, Constants.IPMI_PORT, user, password, cipherSuiteSelectionHandler);
    }

    /**
     * Tries to open SOL communication on given existing session. When it appears that separate session must be opened
     * to handle SOL messages (for example SOL payload must be activated on separate port), the new connection and session
     * are automatically established.
     *
     * @param connector
     *          {@link IpmiConnector} that will be used for communication
     * @param session
     *          Existing session that should be reused (if possible) for SOL communication.
     */
    public SerialOverLan(IpmiConnector connector, Session session) throws SOLException, SessionException {
        this.connector = connector;

        int solPayloadPort = activatePayload(connector, session.getConnectionHandle());

        this.session = resolveSession(connector, session.getConnectionHandle(), session, solPayloadPort);

        this.eventListeners = new LinkedList();
        this.inboundMessageListener = new InboundSolMessageListener(connector,
                this.session.getConnectionHandle(), eventListeners);

        connector.registerIncomingMessageListener(inboundMessageListener);
        this.closed = false;
    }

    /**
     * Given potential session object, connection data and port on which SOL should be activated,
     * decides what session should be finally used to SOL communication.
     *
     * @param connector
     *          {@link IpmiConnector} that will be used for communication
     * @param connectionHandle
     *          {@link ConnectionHandle} representing single connection to managed system.
     * @param session
     *          Existing session that should be reused (if possible) for SOL communication.
     * @param solPayloadPort
     *          UDP port on which managed system listens for SOL communication.
     * @return Actual session (existing or newly established), that should be used for SOL communication.
     * @throws SOLException
     *          If any unrecoverable error occurs.
     * @throws SessionException
     *          If new session could not be established.
     */
    private Session resolveSession(IpmiConnector connector, ConnectionHandle connectionHandle, Session session, int solPayloadPort) throws SOLException, SessionException {
        if (solPayloadPort != connectionHandle.getRemotePort()) {
            Session alternativeSession = connector.getExistingSessionForCriteria(connectionHandle.getRemoteAddress(),
                    solPayloadPort, connectionHandle.getUser());

            if (alternativeSession == null) {
                CipherSuiteSelectionHandler cipherSuiteSelector = new SpecificCipherSuiteSelector(connectionHandle.getCipherSuite());

                alternativeSession = SessionManager.establishSession(connector, connectionHandle.getRemoteAddress().getHostAddress(),
                        solPayloadPort, connectionHandle.getUser(), connectionHandle.getPassword(), cipherSuiteSelector);
                this.isSessionInternal = true;

            } else {
                this.isSessionInternal = false;
            }

            activatePayload(connector, alternativeSession.getConnectionHandle());

            return alternativeSession;
        } else {
            this.isSessionInternal = false;
            return session;
        }
    }

    /**
     * Tries to activate SOL payload in the session associated to given {@link ConnectionHandle}.
     * If first activation try fails due to insufficient privileges, raises the session privileges
     * to maximum available and tries to activate payload once again.
     *
     * @param connector
     *          {@link IpmiConnector} that will be used for communication
     * @param connectionHandle
     *          {@link ConnectionHandle} representing single connection to managed system.
     * @return UDP port number on which managed system listenes for SOL messages.
     * @throws SOLException
     *          when any unrecoverable error occurred.
     */
    private int activatePayload(IpmiConnector connector, ConnectionHandle connectionHandle) throws SOLException {
        try {
            this.payloadInstance = getFirstAvailablePayloadInstance(connector, connectionHandle);

            ActivateSolPayload activatePayload = new ActivateSolPayload(connectionHandle.getCipherSuite(), payloadInstance);
            ActivateSolPayloadResponseData activatePayloadResponseData = getActivatePayloadResponse(connector,
                    connectionHandle, activatePayload);

            this.maxPayloadSize = activatePayloadResponseData.getInboundPayloadSize();

            return activatePayloadResponseData.getPayloadUdpPortNumber();

        } catch (Exception e) {
            throw new SOLException("Cannot activate SOL payload due to exception during activation process", e);
        }
    }

    private ActivateSolPayloadResponseData getActivatePayloadResponse(IpmiConnector connector, ConnectionHandle connectionHandle, ActivateSolPayload activatePayload) throws Exception {
        ActivateSolPayloadResponseData activatePayloadResponseData;

        try {
            activatePayloadResponseData = (ActivateSolPayloadResponseData) connector.sendMessage(connectionHandle,
                    activatePayload);
        } catch (IPMIException e) {
            if (e.getCompletionCode() == CompletionCode.InsufficentPrivilege) {
                raiseSessionPrivileges(connector, connectionHandle);

                activatePayloadResponseData = (ActivateSolPayloadResponseData) connector.sendMessage(
                        connectionHandle, activatePayload);
            } else {
                throw e;
            }
        }

        return activatePayloadResponseData;
    }

    /**
     * Checks for available SOL payload instances and, if any, returns first available.
     *
     * @param connector
     *          {@link IpmiConnector} that will be used for communication
     * @param connectionHandle
     *          {@link ConnectionHandle} representing single connection to managed system.
     * @return number of first available SOL payload instance.
     * @throws Exception
     *          If any exception occurred during communication or if no available instances were found.
     */
    private int getFirstAvailablePayloadInstance(IpmiConnector connector, ConnectionHandle connectionHandle) throws Exception {
        GetPayloadActivationStatus getPayloadActivationStatus = new GetPayloadActivationStatus(connectionHandle.getCipherSuite(),
                PayloadType.Sol);
        GetPayloadActivationStatusResponseData getActivationResponseData = (GetPayloadActivationStatusResponseData) connector.sendMessage(
                connectionHandle, getPayloadActivationStatus);

        if (getActivationResponseData.getInstanceCapacity() <= 0 || getActivationResponseData.getAvailableInstances().isEmpty()) {
            throw new SOLException("Cannot activate SOL payload, as there are no available payload instances.");
        }

        return TypeConverter.byteToInt(getActivationResponseData.getAvailableInstances().get(0));
    }

    /**
     * Sends proper command to managed system in order to raise user privileges in given session to maximum available level.
     *
     * @param connector
     *          {@link IpmiConnector} that will be used for communication
     * @param connectionHandle
     *          {@link ConnectionHandle} representing single connection to managed system.
     * @throws Exception
     *           If any exception occurred during communication.
     */
    private void raiseSessionPrivileges(IpmiConnector connector, ConnectionHandle connectionHandle) throws Exception {
        SetSessionPrivilegeLevel setSessionPrivilegeLevel = new SetSessionPrivilegeLevel(IpmiVersion.V20,
                connectionHandle.getCipherSuite(), AuthenticationType.RMCPPlus, PrivilegeLevel.Administrator);
        connector.sendMessage(connectionHandle, setSessionPrivilegeLevel);
    }


    /**
     * Writes single byte to the port.
     * This operation blocks until all data can be sent to remote server and is either accepted or rejected by the server.
     *
     * @param singleByte
     *          a byte to write
     * @return true if byte was successfully sent and acknowledged by remote server, false otherwise.
     */
    public boolean writeByte(byte singleByte) {
       return writeBytes(new byte[] {singleByte});
    }

    /**
     * Writes bytes array to the port.
     * This operation blocks until all data can be sent to remote server and is either accepted or rejected by the server.
     *
     * @param buffer
     *          an array of bytes to write
     * @return true if all bytes were successfully sent and acknowledged by remote server, false otherwise.
     */
    public boolean writeBytes(byte[] buffer) {
        boolean result = true;

        int maxBufferSize = maxPayloadSize - SolMessage.PAYLOAD_HEADER_LENGTH;
        byte[] remainingBytes = buffer;
        int currentIndex = 0;

        while (remainingBytes.length - currentIndex > maxBufferSize) {
            byte[] bufferChunk = Arrays.copyOfRange(remainingBytes, currentIndex, maxBufferSize);
            currentIndex += maxBufferSize;

            result &= sendMessage(bufferChunk);

            if (!result) {
                return false;
            }
        }

        if (remainingBytes.length - currentIndex > 0) {
            remainingBytes = Arrays.copyOfRange(remainingBytes, currentIndex, remainingBytes.length);
            result &= sendMessage(remainingBytes);
        }

        return result;
    }

    /**
     * Writes single integer (in range from 0 to 255) to the port.
     * This operation blocks until all data can be sent to remote server and is either accepted or rejected by the server.
     *
     * @param singleInt
     *          an integer value to write (must be in range from 0 to 255)
     * @return true if integer was successfully sent and acknowledged by remote server, false otherwise.
     */
    public boolean writeInt(int singleInt) {
        return writeBytes(new byte[] {TypeConverter.intToByte(singleInt)});
    }

    /**
     * Writes integers (in range from 0 to 255) array to the port.
     * This operation blocks until all data can be sent to remote server and is either accepted or rejected by the server.
     *
     * @param buffer
     *          an array of integer values to write (each must be in range from 0 to 255)
     * @return true if all integers were successfully sent and acknowledged by remote server, false otherwise.
     */
    public boolean writeIntArray(int[] buffer) {
        byte[] byteBuffer = new byte[buffer.length];

        for (int i = 0; i < buffer.length; i++) {
            byteBuffer[i] = TypeConverter.intToByte(buffer[i]);
        }

        return writeBytes(byteBuffer);
    }

    /**
     * Writes {@link String} to port, using platform's default {@link Charset} when converting {@link String} to byte array.
     * This operation blocks until all data can be sent to remote server and is either accepted or rejected by the server.
     *
     * @param string
     *          a string to write to the port.
     * @return true if whole string was successfully sent and acknowledged by remote server, false otherwise.
     */
    public boolean writeString(String string) {
        return writeBytes(string.getBytes());
    }

    /**
     * Writes {@link String} to port, using given {@link Charset} when converting {@link String} to byte array.
     * This operation blocks until all data can be sent to remote server and is either accepted or rejected by the server.
     *
     * @param string
     *          a string to write to port
     * @param charset
     *          {@link Charset} that the string is encoded in
     * @return true if whole string was successfully sent and acknowledged by remote server, false otherwise.
     */
    public boolean writeString(String string, Charset charset) {
        return writeBytes(string.getBytes(charset));
    }

    /**
     * Read all available bytes from the port.
     * Returns immediately, without waiting for data to be available.
     *
     * @return all bytes that could be read or empty array if no bytes were available.
     */
    public byte[] readBytes() {
        return readBytes(inboundMessageListener.getAvailableBytesCount());
    }

    /**
     * Reads at max given number of bytes from the port.
     * Returns immediately, without waiting for data to be available.
     *
     * @param byteCount
     *          maximum number of bytes that should be read
     * @return byte array containing bytes that could be read, but no more than given byteCount.
     * Returns empty array if no bytes were available.
     */
    public byte[] readBytes(int byteCount) {
        return inboundMessageListener.readBytes(byteCount);
    }

    /**
     * Reads at max given number of bytes from the port.
     * This operation blocks until given number of bytes is available to be read or until given timeout is hit.
     *
     * @param byteCount
     *          maximum number of bytes that should be read.
     * @param timeout
     *          maximum time in milliseconds that we want to wait for all available bytes
     * @return byte array containing bytes that could be read, but no more than byteCount.
     * When the timeout is hit, returns just bytes that were available or empty array if no bytes were available.
     */
    public byte[] readBytes(int byteCount, int timeout) {
        waitForData(byteCount, timeout);

        return readBytes(byteCount);
    }

    /**
     * Reads all available bytes from the port as integer (in range from 0 to 255) values array.
     * Returns immediately, without waiting for data to be available.
     *
     * @return all bytes that could be read as int array (each value in range from 0 to 255) or empty array if no data was available.
     */
    public int[] readIntArray() {
        return readIntArray(inboundMessageListener.getAvailableBytesCount());
    }

    /**
     * Reads at max given number of integer values (in range from 0 to 255) from the port.
     * Returns immediately, without waiting for data to be available.
     *
     * @param byteCount
     *          maximum number of bytes that should be read
     * @return integer array containing integer values that could be read, but no more than given byteCount (each value in range from 0 to 255).
     * Returns empty array if no data was available.
     */
    public int[] readIntArray(int byteCount) {
        byte[] bytesArray = readBytes(byteCount);
        int[] intArray = new int[bytesArray.length];

        for (int i = 0; i < bytesArray.length; i++) {
            intArray[i] = TypeConverter.byteToInt(bytesArray[i]);
        }

        return intArray;
    }

    /**
     * Reads at max given number of integer values (in range from 0 to 255) from the port.
     * This operation blocks until given number of bytes is available to be read or until given timeout is hit.
     *
     * @param byteCount
     *          maximum number of bytes that should be read.
     * @param timeout
     *          maximum time in milliseconds that we want to wait for all available data
     * @return integer array containing integer values that could be read, but no more than byteCount (each value in range from 0 to 255).
     * When the timeout is hit, returns just data that was available or empty array if no data was available.
     */
    public int[] readIntArray(int byteCount, int timeout) {
        waitForData(byteCount, timeout);

        return readIntArray(byteCount);
    }

    /**
     * Read all available bytes from the port and converts them to {@link String} using platform's default {@link Charset}.
     * Returns immediately, without waiting for data to be available.
     *
     * @return all bytes that could be read as {@link String}.
     */
    public String readString() {
        return readString(inboundMessageListener.getAvailableBytesCount());
    }

    /**
     * Reads at max given number of bytes from the port, converting them to {@link String} using platform's default {@link Charset}.
     * Returns immediately, without waiting for data to be available.
     *
     * @param byteCount
     *          maximum number of bytes that should be read
     * @return all bytes that could be read as {@link String}, but no more than given byteCount.
     */
    public String readString(int byteCount) {
        return new String(readBytes(byteCount));
    }

    /**
     * Reads at max given number of bytes from the port, converting them to {@link String} using platform's default {@link Charset}.
     * This operation blocks until given number of bytes is available to be read or until given timeout is hit.
     *
     * @param byteCount
     *          maximum number of bytes that should be read.
     * @param timeout
     *          maximum time in milliseconds that we want to wait for all available bytes
     * @return all bytes that could be read as {@link String}, but no more than given byteCount.
     * When the timeout is hit, returns just bytes that were available.
     */
    public String readString(int byteCount, int timeout) {
        waitForData(byteCount, timeout);

        return readString(byteCount);
    }

    /**
     * Read all available bytes from the port and converts them to {@link String} using given {@link Charset}.
     * Returns immediately, without waiting for data to be available.
     *
     * @param charset
     *          {@link Charset} that will be used when converting bytes to {@link String}
     * 
     * @return all bytes that could be read as {@link String}.
     */
    public String readString(Charset charset) {
        return readString(charset, inboundMessageListener.getAvailableBytesCount());
    }

    /**
     * Reads at max given number of bytes from the port, converting them to {@link String} using given {@link Charset}.
     * Returns immediately, without waiting for data to be available.
     *
     * @param charset
     *          {@link Charset} that will be used when converting bytes to {@link String}
     * @param byteCount
     *          maximum number of bytes that should be read
     * @return all bytes that could be read as {@link String}, but no more than given byteCount.
     */
    public String readString(Charset charset, int byteCount) {
        return new String(readBytes(byteCount), charset);
    }

    /**
     * Reads at max given number of bytes from the port, converting them to {@link String} using given {@link Charset}.
     * This operation blocks until given number of bytes is available to be read or until given timeout is hit.
     *
     * @param charset
     *          {@link Charset} that will be used when converting bytes to {@link String}
     * @param byteCount
     *          maximum number of bytes that should be read.
     * @param timeout
     *          maximum time in milliseconds that we want to wait for all available bytes
     * @return all bytes that could be read as {@link String}, but no more than given byteCount.
     * When the timeout is hit, returns just bytes that were available.
     */
    public String readString(Charset charset, int byteCount, int timeout) {
        waitForData(byteCount, timeout);

        return readString(charset, byteCount);
    }

    private void waitForData(int wantedByteCount, int timeout) {
        long startTime = System.currentTimeMillis();

        while (isTooFewBytesAvailable(wantedByteCount) && timeoutNotHit(timeout, startTime)) {
            // NOP, just waiting
        }
    }

    private boolean isTooFewBytesAvailable(int wantedByteCount) {
        return inboundMessageListener.getAvailableBytesCount() < wantedByteCount;
    }

    private boolean timeoutNotHit(int timeout, long startTime) {
        return System.currentTimeMillis() - startTime < timeout;
    }

    /**
     * Invokes given SOL-specific operations on remote serial port.
     *
     * @param operations
     *          a bunch of {@link SolOperation}s that should be invoked
     * @return true if operations were successfully sent and acknowledged by remote server, false otherwise.
     */
    public boolean invokeOperations(SolOperation... operations) {
        Set operationSet = new HashSet();

        for (SolOperation operation : operations) {
            operationSet.add(operation);
        }

        return sendMessage(operationSet);
    }

    /**
     * Registers new {@link SolEventListener} that will be informed about SOL events fired by remote system.
     *
     * @param listener
     *          listener to be registered
     */
    public void registerEventListener(SolEventListener listener) {
        eventListeners.add(listener);
    }

    /**
     * Unregister given {@link SolEventListener}, preventing it from receiving SOL events from remote server.
     *
     * @param listener
     *          listener to be unregistered
     */
    public void unregisterEventListener(SolEventListener listener) {
        eventListeners.remove(listener);
    }

    private boolean sendMessage(byte[] characterData) {
        SolCoder payloadCoder = new SolCoder(characterData, session.getConnectionHandle().getCipherSuite());

        SolResponseData responseData = sendPayload(payloadCoder);

        notifyResponseListeners(characterData, new HashSet(), responseData);

        byte[] remainingCharacterData = characterData;

        while (isNackForMessagePart(responseData, remainingCharacterData.length)) {
            remainingCharacterData = Arrays.copyOfRange(remainingCharacterData,
                    responseData.getAcceptedCharactersNumber(), remainingCharacterData.length);

            SolCoder partialPayloadCoder = new SolCoder(remainingCharacterData, session.getConnectionHandle().getCipherSuite());
            responseData = sendPayload(partialPayloadCoder);

            notifyResponseListeners(remainingCharacterData, new HashSet(), responseData);
        }

        return responseData != null && responseData.getAcknowledgeState() == SolAckState.ACK;
    }

    private boolean sendMessage(Set operations) {
        SolCoder payloadCoder = new SolCoder(operations, session.getConnectionHandle().getCipherSuite());

        SolResponseData responseData = sendPayload(payloadCoder);

        notifyResponseListeners(new byte[0], operations, responseData);

        return responseData != null && responseData.getAcknowledgeState() == SolAckState.ACK;
    }

    private void notifyResponseListeners(byte[] characterData, Set solOperations, SolResponseData responseData) {
        if (responseData != null && responseData.getStatuses() != null && !responseData.getStatuses().isEmpty()) {
            for (SolEventListener listener : eventListeners) {
                listener.processResponseEvent(responseData.getStatuses(), characterData, solOperations);
            }
        }
    }

    private SolResponseData sendPayload(PayloadCoder payloadCoder) {
        ConnectionHandle connectionHandle = session.getConnectionHandle();

        try {
            SolResponseData responseData = (SolResponseData) connector.sendMessage(connectionHandle, payloadCoder);

            int actualRetries = 0;

            while (isNackForWholeMessage(responseData) && actualRetries < connector.getRetries()) {
                actualRetries++;

                responseData = (SolResponseData) connector.retryMessage(connectionHandle,
                        responseData.getRequestSequenceNumber(), PayloadType.Sol);
            }

            return responseData;
        } catch (Exception e) {
            logger.error("Error while sending message", e);
            return null;
        }
    }

    @Override
    public synchronized void close() throws IOException {
        if (!closed) {
            try {
                ConnectionHandle connectionHandle = session.getConnectionHandle();

                DeactivatePayload deactivatePayload = new DeactivatePayload(connectionHandle.getCipherSuite(),
                        PayloadType.Sol, payloadInstance);

                connector.sendMessage(connectionHandle, deactivatePayload);

                if (isSessionInternal) {
                    connector.closeSession(connectionHandle);
                    connector.tearDown();
                }

                closed = true;
            } catch (Exception e) {
                throw new IOException("Error while closing Serial over LAN instance", e);
            }

        }
    }

    private boolean isNackForWholeMessage(SolResponseData responseData) {
        return responseData != null
                && responseData.getAcknowledgeState() == SolAckState.NACK
                && responseData.getAcceptedCharactersNumber() == 0;
    }

    private boolean isNackForMessagePart(SolResponseData responseData, int previousMessageDataLength) {
        return responseData != null
                && responseData.getAcknowledgeState() == SolAckState.NACK
                && responseData.getAcceptedCharactersNumber() > 0
                && responseData.getAcceptedCharactersNumber() < previousMessageDataLength;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy