package cz.vut.jmeter.ddos.httpsflood;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.net.InetAddress;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestStateListener;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.params.HttpParams;

import org.apache.jmeter.samplers.AbstractSampler;
import org.apache.jmeter.samplers.Entry;
import org.apache.jmeter.samplers.SampleResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class creates HTTPS requests using Apache HttpClient and sends them to set IP address
 * 
 * @author Karel Lanzhotsky
 *
 */

public class HttpsFloodSampler extends AbstractSampler{
	private static final long serialVersionUID = 240L;

    private static final Logger log = LoggerFactory.getLogger(HttpsFloodSampler.class);

 
    public static final String TARGETIP = "HttpsFloodSampler.targetIP";
    public static final String SOURCEIPMIN = "HttpsFloodSampler.sourceIPMIN";
    public static final String SOURCEIPMAX = "HttpsFloodSampler.sourceIPMAX";
    public static final String APPlYSETTINGS = "HttpsFloodSampler.applySettings";
    public static final String RESETSETTINGS = "HttpsFloodSampler.resetSettings";
    public static final String INTERFACE = "HttpsFloodSampler.interface";
    private static AtomicInteger classCount = new AtomicInteger(0); // keep track of classes created


    public HttpsFloodSampler() {
        classCount.incrementAndGet();
        trace("HttpsFloodSampler()");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public SampleResult sample(Entry e) {
        trace("sample()");
        SampleResult res = new SampleResult();
        boolean isOK = false; 
        String response = null;

        res.setSampleLabel(getTitle());
        /*
         * Perform the sampling
         */
        res.sampleStart(); // Start timing
        //
        //
        String target = "https://"+this.getPropertyAsString(TARGETIP);
	    String ipMin = this.getPropertyAsString(SOURCEIPMIN);
	    String ipMax = this.getPropertyAsString(SOURCEIPMAX);
        try {
        	long[] ipRange = HttpsFloodGui.generateIpRange(HttpsFloodGui.ipToDec(ipMin), HttpsFloodGui.ipToDec(ipMax));
            String randomIp = HttpsFloodGui.decToIp(getRandomIp(ipRange));
            response = Thread.currentThread().getName();           
        /*
         * Following code was necessary to test the sampler on self-signed certificate
         * to bypass exception thrown by SSL.    
         */	
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[] { new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                        return null;
                }

                public void checkClientTrusted(X509Certificate[] certs,
                                String authType) {
                }

                public void checkServerTrusted(X509Certificate[] certs,
                                String authType) {
                }
            } }, new SecureRandom());            
            SSLSocketFactory sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            Scheme httpsScheme = new Scheme("https", 443, sf);
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(httpsScheme);
            ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
            
            
            DefaultHttpClient httpClient = new DefaultHttpClient(cm);
            HttpGet request = new HttpGet(target); 
            HttpParams params = httpClient.getParams();
            
            params.setParameter(ConnRoutePNames.LOCAL_ADDRESS, InetAddress.getByName(randomIp));
            httpClient.execute(request);
            request.releaseConnection();
            
            

   	     	/*
             * Set up the sample result details
             */
            res.setResponseData(response, null);
            res.setDataType(SampleResult.TEXT);

            res.setResponseCodeOK();
            res.setResponseMessage("OK");// $NON-NLS-1$
            isOK = true;
            //
        } catch (Exception ex) {
            log.debug("", ex);
            res.setResponseCode("500");// $NON-NLS-1$
            res.setResponseMessage(ex.toString());
        }
        res.sampleEnd(); // End timing

        res.setSuccessful(isOK);

        return res;
    }
    //picks random number from array
  	public static long getRandomIp(long[] ipRange) {
  		int rnd = new Random().nextInt(ipRange.length);
  		return ipRange[rnd];
  	}

    /**
     * @return a string for the sampleResult Title
     */
    private String getTitle() {
        return this.getName();
    }

    private void trace(String s) {
        if (log.isDebugEnabled()) {
            log.debug("{} ({}) {} {} {}", Thread.currentThread().getName(), classCount.get(),
                    getTitle(), s, this.toString());
        }
    }
    
    
}
