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

com.lafaspot.icap.client.session.IcapSession Maven / Gradle / Ivy

There is a newer version: 0.0.13
Show newest version
/**
 *
 */
package com.lafaspot.icap.client.session;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.util.concurrent.GenericFutureListener;

import java.net.URI;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import javax.annotation.Nonnull;

import com.lafaspot.icap.client.IcapResult;
import com.lafaspot.icap.client.codec.IcapMessage;
import com.lafaspot.icap.client.codec.IcapMessageDecoder;
import com.lafaspot.icap.client.codec.IcapOptions;
import com.lafaspot.icap.client.codec.IcapRespmod;
import com.lafaspot.icap.client.exception.IcapException;
import com.lafaspot.logfast.logging.LogContext;
import com.lafaspot.logfast.logging.LogManager;
import com.lafaspot.logfast.logging.Logger;

/**
 * IcapSession - identifies a session that represents one scan request.
 *
 * @author kraman
 *
 */
public class IcapSession {

    /**
     * Creates a ICAP session.
     *
     * @param sessionId identifier for the session
     * @param uri remote ICAP server URI
     * @param connectTimeout timeout for socket connection
     * @param inactivityTimeout channel inactivity timeout
     * @param bootstrap the bootstrap
     * @param logManager the LogManager instance
     * @throws IcapException on failure
     */
    public IcapSession(@Nonnull final String sessionId, @Nonnull final URI uri, final long connectTimeout, final long inactivityTimeout,
            @Nonnull final Bootstrap bootstrap, @Nonnull final LogManager logManager) throws IcapException {
        this.serverUri = uri;
        this.bootstrap = bootstrap;
        this.connectTimeout = connectTimeout;
        this.inactivityTimeout = inactivityTimeout;

        LogContext context = new SessionLogContext("IcapSession-" + uri.toASCIIString(), sessionId);
        this.logger = logManager.getLogger(context);
    }

    /**
     * Request to scan an file, a request will be sent to the Symantec AV server to scan the request to clean/determine if the file is clean.
     *
     * @param filename name of the file to be scanned
     * @param fileToScan byte stream of the file to be scanned
     * @return the future object
     * @throws IcapException on failure
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Future scanFile(@Nonnull final String filename, @Nonnull final byte[] fileToScan)
            throws IcapException {

        if (!isUsed.compareAndSet(false, true)) {
            throw new IcapException(IcapException.FailureType.SESSION_IN_USE);
        }

        this.filename = filename;
        this.fileToScan = fileToScan;

        try {
            // sync wait for connect to complete todo make this async
            channel = bootstrap.connect(serverUri.getHost(), serverUri.getPort()).sync().channel();
            channel.pipeline().addLast("inactivityHandler", new IcapInactivityHandler(this, inactivityTimeout, logger));
            channel.pipeline().addLast(new IcapMessageDecoder(logger));
            channel.pipeline().addLast(new IcapChannelHandler(this));
            final IcapSession thisSession = this;
            channel.closeFuture().addListener(new GenericFutureListener() {
                @Override
                public void operationComplete(final io.netty.util.concurrent.Future future) throws Exception {
                    thisSession.onDisconnect();
                }
            });

            if (!channel.isActive()) {
                throw new IcapException(IcapException.FailureType.NOT_CONNECTED);
            } else {
                logger.debug("connected, sending", null);
                stateRef.set(IcapSessionState.INIT.OPTIONS);
                Future writeFuture = channel.writeAndFlush(new IcapOptions(serverUri).getMessage());

            }

        } catch (final Exception e) {
            throw new IcapException(IcapException.FailureType.NOT_CONNECTED, e);
        }

        futureRef.set(new IcapFuture(this));
        return futureRef.get();
    }

    /**
     * Callback from netty on receiving a message from the network.
     *
     * @param msg incoming message
     */
    public void processResponse(@Nonnull final IcapMessage msg) {
        logger.debug("<- messageReceived in " + stateRef.get() + ", [\r\n" + msg.toString() + "\r\n]", null);
        switch (stateRef.get()) {
        case OPTIONS:
            if (null != msg.getCause()) {
                logger.debug("options failed " + msg.getCause(), null);
                futureRef.get().done(msg.getCause());
            } else {
                stateRef.set(IcapSessionState.SCAN);
                final IcapRespmod scanReq = new IcapRespmod(serverUri, false, filename, fileToScan);

                logger.debug(" sending scan req [\r\n" + scanReq.getIcapMessage() + "\r\n]", null);

                msg.reset();
                channel.writeAndFlush(scanReq.getIcapMessage());
                channel.writeAndFlush(scanReq.getInStream());
                channel.writeAndFlush(scanReq.getTrailerBytes());
                logger.debug(" written payload -> ", null);
                channel.flush();
            }
            break;
        case SCAN:
            stateRef.set(IcapSessionState.SCAN_DONE);
            if (msg.getCause() != null) {
                logger.debug(" SCAN state - failed " + msg.getCause(), null);
                futureRef.get().done(msg.getCause());
            } else {
                logger.debug(" SCAN state - success " + msg.getResult(), null);
                futureRef.get().done(msg.getResult());
            }
            break;
        case SCAN_DONE:
        default:
        }
    }

    /**
     * Callback from netty on channel inactivity.
     */
    public void onTimeout() {
        logger.debug("**channel timeout** TH " + Thread.currentThread().getId(), null);
        stateRef.set(IcapSessionState.NULL);
        if (null != futureRef.get()) {
            futureRef.get().done(new IcapException("inactivity timeout"));
            futureRef.set(null);
        }
    }

    /**
     * Callback from netty on channel closure.
     */
    public void onDisconnect() {
        logger.debug("**channel disconnected (not-ignored)** TH " + Thread.currentThread().getId(), null);
        stateRef.set(IcapSessionState.NULL);
        if (futureRef.get() != null) {
            futureRef.get().done(new IcapException("channel disconnected"));
            futureRef.set(null);
        }

    }

    /**
     * Return the logger object.
     *
     * @return the logger
     */
    public Logger getLogger() {
        return logger;
    }

    /** Reference to the current IcapFuture object. */
    private final AtomicReference futureRef = new AtomicReference();

    /** pointer to the byte stream of the file to be scanned. */
    private byte[] fileToScan;

    /** filename of the input file to be scanned. */
    private String filename;

    /** Server to connect to. */
    private final URI serverUri;

    /** Bootstrap. */
    private final Bootstrap bootstrap;

    /** channel inactivity timeout. */
    private final long inactivityTimeout;

    /** socket connect timeout. */
    private final long connectTimeout;

    /** Is this session being used? */
    private final AtomicBoolean isUsed = new AtomicBoolean(false);

    /** Reference to the current state of the session. */
    private AtomicReference stateRef = new AtomicReference(IcapSessionState.NULL);

    /** The channel associated with this session. */
    private Channel channel;

    /** The logger. */
    private final Logger logger;

    /** Enum identifying the session states. */
    enum IcapSessionState {
        /** Session not started. */
        NULL,
        /** Session initialized. */
        INIT,
        /** connected. */
        CONNECTED,
        /** options request sent. */
        OPTIONS,
        /** options response received. */
        OPTIONS_DONE,
        /** scan request sent. */
        SCAN,
        /** scan complete. */
        SCAN_DONE
    };

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy