package com.netifera.platform.net.internal.sniffing.stream;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import com.netifera.platform.net.sniffing.stream.IBlockSnifferHandle;
import com.netifera.platform.net.sniffing.stream.ISessionKey;
public class TCPBlockManager {
private final Collection<IBlockSnifferHandle> handles;
private final ISessionKey key;
private ByteBuffer clientBuffer;
private ByteBuffer serverBuffer;
private final Object sessionTag;
private boolean closed;
TCPBlockManager(ISessionKey key, Object sessionTag, Collection<IBlockSnifferHandle> handles) {
this.handles = new HashSet<IBlockSnifferHandle>(handles);
this.key = key;
this.sessionTag = sessionTag;
if(handles.size() > 0) {
allocateBuffers();
} else {
closed = true;
}
}
void unregisterHandle(IBlockSnifferHandle handle) {
synchronized(handles) {
handles.remove(handle);
}
}
void addClientData(ByteBuffer data) {
addData(clientBuffer, data);
}
void addServerData(ByteBuffer data) {
addData(serverBuffer, data);
}
private void addData(ByteBuffer targetBuffer, ByteBuffer dataBuffer) {
dataBuffer.remaining();
if(!targetBuffer.hasRemaining()) {
return;
} else if(targetBuffer.remaining() >= dataBuffer.remaining()) {
targetBuffer.put(dataBuffer);
} else {
final int saveLimit = dataBuffer.limit();
dataBuffer.limit(targetBuffer.remaining());
targetBuffer.put(dataBuffer);
dataBuffer.limit(saveLimit);
}
dataBuffer.rewind();
for(Iterator<IBlockSnifferHandle> itr = handles.iterator(); itr.hasNext(); ) {
IBlockSnifferHandle h = itr.next();
if(isOverLimit(h)) {
processHandle(h);
itr.remove();
}
}
}
private boolean isOverLimit(IBlockSnifferHandle handle) {
final int clientSize = clientBuffer.position();
final int serverSize = serverBuffer.position();
final int totalSize = clientSize + serverSize;
return checkLimit(clientSize, handle.getClientLimit()) ||
checkLimit(serverSize, handle.getServerLimit()) ||
checkLimit(totalSize, handle.getTotalLimit());
}
private boolean checkLimit(int current, int limit) {
return (limit > 0 && current >= limit);
}
private void processHandle(IBlockSnifferHandle handle) {
handle.getSniffer().handleBlock(new TCPSessionContext(key, sessionTag),
(ByteBuffer) clientBuffer.asReadOnlyBuffer().flip(),
(ByteBuffer) serverBuffer.asReadOnlyBuffer().flip());
}
boolean isClosed() {
return closed;
}
void shutdown() {
closed = true;
if(handles.size() > 0 && (clientBuffer.position() > 0 || serverBuffer.position() > 0)) {
synchronized(handles) {
for(IBlockSnifferHandle h : handles) {
processHandle(h);
}
}
}
clientBuffer = null;
serverBuffer = null;
handles.clear();
}
private static int max(int a, int b) {
return (a > b) ? (a) : (b);
}
private void allocateBuffers() {
int maxClientLimit = 0;
int maxServerLimit = 0;
int maxTotalLimit = 0;
for(IBlockSnifferHandle h : handles) {
maxClientLimit = max(maxClientLimit, h.getClientLimit());
maxServerLimit = max(maxServerLimit, h.getServerLimit());
maxTotalLimit = max(maxTotalLimit, h.getTotalLimit());
}
final int clientBufferSize = max(maxClientLimit, maxTotalLimit);
final int serverBufferSize = max(maxServerLimit, maxTotalLimit);
clientBuffer = ByteBuffer.allocate(clientBufferSize);
serverBuffer = ByteBuffer.allocate(serverBufferSize);
}
}