com.lafaspot.icap.client.session.IcapSession Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of icapclient Show documentation
Show all versions of icapclient Show documentation
Icap client to talk to Symantec server.
/**
*
*/
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