/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.tools.ldapdecoder;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Date;
import com.slamd.asn1.ASN1Element;
import com.slamd.asn1.ASN1Reader;
import com.slamd.asn1.ASN1Writer;
import com.slamd.tools.ldapdecoder.protocol.LDAPMessage;
/**
* This class defines a thread that may be used for handling all communication
* with an LDAP client.
*
*
* @author Neil A. Wilson
*/
public class LDAPDecoderClientThread
extends Thread
{
// The ASN.1 reader that may be used to read responses from the client.
private ASN1Reader clientReader;
// The ASN.1 writer that may be used to send requests to the client.
private ASN1Writer clientWriter;
// Indicates whether a request has been made to close the connection to the
// client.
private boolean closeRequested;
// Indicates whether the decoded information should be written to a SLAMD job
// script.
private boolean writeJobScript;
// The client connection with which this client thread is associated.
private LDAPClientConnection clientConnection;
// The LDAP decoder that created this client thread.
private LDAPDecoder decoder;
// The output writer that will be used to write information to the SLAMD job
// script that is being generated.
private PrintStream scriptWriter;
// The socket that will be used for communicating with the client.
private Socket clientSocket;
/**
* Creates a new thread for handling all interaction with an LDAP client.
*
* @param decoder The LDAP decoder with which this client thread is
* associated.
* @param clientConnection The client connection with which this client
* thread is associated.
*
* @throws LDAPDecoderException If a problem occurs while initializing the
* thread.
*/
public LDAPDecoderClientThread(LDAPDecoder decoder,
LDAPClientConnection clientConnection)
throws LDAPDecoderException
{
this.decoder = decoder;
this.clientConnection = clientConnection;
setName("Connection " +
clientConnection.clientSocket.getInetAddress().getHostAddress() +
':' + clientConnection.clientSocket.getPort() + " client thread");
writeJobScript = decoder.writeJobScript;
scriptWriter = decoder.scriptWriter;
try
{
clientSocket = clientConnection.clientSocket;
clientReader = new ASN1Reader(clientSocket);
clientWriter = new ASN1Writer(clientSocket);
clientSocket.setTcpNoDelay(true);
}
catch (Exception e)
{
throw new LDAPDecoderException("Unable to create reader and writer " +
"for client connection", e);
}
closeRequested = false;
}
/**
* Loops, reading information from the server, decoding it, and passing it on
* to the client.
*/
public void run()
{
boolean failedLastTime = false;
while (! closeRequested)
{
try
{
// Read an element from the client.
ASN1Element element = clientReader.readElement();
if (element == null)
{
// The client closed the connection.
closeRequested = true;
clientConnection.closeConnection();
return;
}
// Decode it as necessary and write information about it to the log.
synchronized (clientConnection.outputWriter)
{
clientConnection.outputWriter.println(
clientConnection.dateFormat.format(new Date()) +
" -- Read data from the client");
if (decoder.displayRawBytes)
{
byte[] elementBytes = element.encode();
clientConnection.outputWriter.println("Raw Data from Client:");
clientConnection.outputWriter.println(
LDAPMessage.byteArrayToString(elementBytes, 4));
}
try
{
LDAPMessage message = LDAPMessage.decode(element);
clientConnection.outputWriter.println("Decoded Data from Client:");
clientConnection.outputWriter.println(message.toString(4));
if (writeJobScript)
{
synchronized (scriptWriter)
{
message.toSLAMDScript(scriptWriter);
}
}
if (decoder.verboseMode)
{
System.err.println("Decoded an " +
message.getProtocolOp().getProtocolOpType() +
" message");
}
}
catch (Exception e)
{
clientConnection.outputWriter.println("Unable to Decode Data " +
"from Client:");
if (decoder.verboseMode)
{
e.printStackTrace(clientConnection.outputWriter);
}
}
clientConnection.outputWriter.println();
clientConnection.outputWriter.println();
}
// Forward the data on to the server.
clientConnection.writeToServer(element);
}
catch (Exception e)
{
if (failedLastTime)
{
synchronized (clientConnection.outputWriter)
{
clientConnection.outputWriter.println(
clientConnection.dateFormat.format(new Date()) +
" -- Error reading data from the client");
if (decoder.verboseMode)
{
e.printStackTrace(clientConnection.outputWriter);
}
}
clientConnection.closeConnection();
}
else
{
failedLastTime = true;
}
}
}
}
/**
* Writes the provided ASN.1 element to the server.
*
* @param element The ASN.1 element to write to the server.
*
* @throws IOException If a problem occurs while trying to write the element
* to the server.
*/
public void writeToClient(ASN1Element element)
throws IOException
{
clientWriter.writeElement(element);
}
/**
* Closes the connection to the server.
*/
public void closeConnection()
{
closeRequested = true;
try
{
clientReader.close();
clientWriter.close();
} catch (Exception e) {}
try
{
clientSocket.close();
} catch (Exception e) {}
}
}