<commit_before>package org.genivi.rvi;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 * Copyright (c) 2015 <NAME>.
 *
 * This program is licensed under the terms and conditions of the
 * Mozilla Public License, version 2.0. The full text of the
 * Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
 *
 * File:    ServerConnection.java
 * Project: RVI
 *
 * Created by <NAME> on 5/19/15.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

import android.os.AsyncTask;
import android.util.Log;

import javax.net.SocketFactory;
import javax.net.ssl.*;
import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.util.Enumeration;

/**
 * The TCP/IP server @RemoteConnectionInterface implementation
 */
class ServerConnection implements RemoteConnectionInterface
{
    private final static String TAG = "RVI/ServerConnection___";
    private RemoteConnectionListener mRemoteConnectionListener;

    private String  mServerUrl;
    private Integer mServerPort;

    private java.security.cert.Certificate mRemoteDeviceCertificate;

    private KeyStore mServerKeyStore = null;
    private KeyStore mLocalDeviceKeyStore = null;
    private String   mLocalDeviceKeyStorePassword = null;

    private SSLSocket mSocket;

    @Override
    public void sendRviRequest(DlinkPacket dlinkPacket) {
        if (!isConfigured())
            mRemoteConnectionListener.onDidFailToSendDataToRemoteConnection(new Throwable("RVI node is not configured."));
        else if (!isConnected())
            mRemoteConnectionListener.onDidFailToSendDataToRemoteConnection(new Throwable("RVI node is not connected."));
        else
            new SendDataTask(dlinkPacket).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
    }

    @Override
    public boolean isConnected() {
        return mSocket != null && mSocket.isConnected();
    }

    @Override
    public boolean isConfigured() {
        return !(mServerUrl == null || mServerUrl.isEmpty() || mServerPort == 0 || mServerKeyStore == null || mLocalDeviceKeyStore == null);
    }

    @Override
    public void connect() {
        if (isConnected()) disconnect(null);

        connectSocket();
    }

    @Override
    public void disconnect(Throwable trigger) {

        try {
            if (mSocket != null)
                mSocket.close();

        } catch (Exception e) {
            if (e.getLocalizedMessage() != null)
                Log.d(TAG, e.getLocalizedMessage());
        }

        mRemoteDeviceCertificate = null;
        mSocket                  = null;

        if (mRemoteConnectionListener != null) mRemoteConnectionListener.onRemoteConnectionDidDisconnect(trigger);
    }

    @Override
    public void setRemoteConnectionListener(RemoteConnectionListener remoteConnectionListener) {
        mRemoteConnectionListener = remoteConnectionListener;
    }

    private void connectSocket() {
        Log.d(TAG, "Connecting the socket: " + mServerUrl + ":" + mServerPort);

        ConnectTask connectAndAuthorizeTask = new ConnectTask(mServerUrl, mServerPort, mServerKeyStore, mLocalDeviceKeyStore, mLocalDeviceKeyStorePassword);
        connectAndAuthorizeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    private class ConnectTask extends AsyncTask<Void, String, Throwable>
    {
        /**
         * The destination address.
         */
        String   dstAddress;
        /**
         * The destination port.
         */
        int      dstPort;
        /**
         * The key store of the server certs.
         */
        KeyStore serverKeyStore;
        /**
         * The key store of the client certs.
         */
        KeyStore clientKeyStore;
        /**
         * The key store password of the client certs.
         */
        String   clientKeyStorePassword;

        /**
         * Instantiates a new Connect task.
         * @param addr the addr
         * @param port the port
         * @param sks the server key store
         * @param cks the client key store
         * @param cksPass the client key store password
         */
        ConnectTask(String addr, int port, KeyStore sks, KeyStore cks, String cksPass) {
            dstAddress = addr;
            dstPort = port;
            clientKeyStore = cks;
            serverKeyStore = sks;
            clientKeyStorePassword = <PASSWORD>;
        }

        @Override
        protected Throwable doInBackground(Void... params) {

            try {

                try {
                    KeyStore keyStore = KeyStore.getInstance("BKS", "BC");
                    keyStore.load(null, null);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                Log.d(TAG, "Creating socket factory");

                String trustManagerAlgorithm = "X509";
                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(trustManagerAlgorithm);
                trustManagerFactory.init(serverKeyStore);

                String keyManagerAlgorithm = "X509";
                KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(keyManagerAlgorithm);
                keyManagerFactory.init(clientKeyStore, clientKeyStorePassword != null ? clientKeyStorePassword.toCharArray() : null);

                SSLContext context = SSLContext.getInstance("TLS");
                context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);

                SocketFactory sf = context.getSocketFactory();

                Log.d(TAG, "Creating ssl socket");

                mSocket = (SSLSocket) sf.createSocket(dstAddress, dstPort);

                SSLSession session  = mSocket.getSession();

                java.security.cert.Certificate[] peerCertificates = session.getPeerCertificates();

//                if (peerCertificates == null || peerCertificates.length != 1) {
//                    throw new Exception("Remote certificate chain is null or contains more than 1 certificate");
//                }

                mRemoteDeviceCertificate = peerCertificates[0];

                Log.d(TAG, "Creating ssl socket complete");

            } catch (Exception e) {
                e.printStackTrace();

                return e;
            }

            return null;
        }

        @Override
        protected void onPostExecute(Throwable result) {
            super.onPostExecute(result);

            if (result == null) {
                // TODO: Does the input buffer stream cache data in the case that my async thread sends the auth command before the listener is set up?
                ListenTask listenTask = new ListenTask();
                listenTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

                if (mRemoteConnectionListener != null)
                    mRemoteConnectionListener.onRemoteConnectionDidConnect();
            } else {
                if (mRemoteConnectionListener != null)
                    mRemoteConnectionListener.onRemoteConnectionDidFailToConnect(result);

                mSocket = null;
            }
        }
    }

    private class ListenTask extends AsyncTask<Void, String, Throwable>
    {
        @Override
        protected Throwable doInBackground(Void... params) {<commit_msg>[RCA-51] Just added a comment here instead of digging in the meat of this task.<commit_after>package org.genivi.rvi;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 * Copyright (c) 2015 <NAME>.
 *
 * This program is licensed under the terms and conditions of the
 * Mozilla Public License, version 2.0. The full text of the
 * Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
 *
 * File:    ServerConnection.java
 * Project: RVI
 *
 * Created by <NAME> on 5/19/15.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

import android.os.AsyncTask;
import android.util.Log;

import javax.net.SocketFactory;
import javax.net.ssl.*;
import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.util.Enumeration;

/**
 * The TCP/IP server @RemoteConnectionInterface implementation
 */
class ServerConnection implements RemoteConnectionInterface
{
    private final static String TAG = "RVI/ServerConnection___";
    private RemoteConnectionListener mRemoteConnectionListener;

    private String  mServerUrl;
    private Integer mServerPort;

    private java.security.cert.Certificate mRemoteDeviceCertificate;

    private KeyStore mServerKeyStore = null;
    private KeyStore mLocalDeviceKeyStore = null;
    private String   mLocalDeviceKeyStorePassword = null;

    private SSLSocket mSocket;

    @Override
    public void sendRviRequest(DlinkPacket dlinkPacket) {
        if (!isConfigured())
            mRemoteConnectionListener.onDidFailToSendDataToRemoteConnection(new Throwable("RVI node is not configured."));
        else if (!isConnected())
            mRemoteConnectionListener.onDidFailToSendDataToRemoteConnection(new Throwable("RVI node is not connected."));
        else
            new SendDataTask(dlinkPacket).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
    }

    @Override
    public boolean isConnected() {
        return mSocket != null && mSocket.isConnected();
    }

    @Override
    public boolean isConfigured() {
        return !(mServerUrl == null || mServerUrl.isEmpty() || mServerPort == 0 || mServerKeyStore == null || mLocalDeviceKeyStore == null);
    }

    @Override
    public void connect() {
        if (isConnected()) disconnect(null);

        connectSocket();
    }

    @Override
    public void disconnect(Throwable trigger) {

        try {
            if (mSocket != null)
                mSocket.close();

        } catch (Exception e) {
            if (e.getLocalizedMessage() != null)
                Log.d(TAG, e.getLocalizedMessage());
        }

        mRemoteDeviceCertificate = null;
        mSocket                  = null;

        if (mRemoteConnectionListener != null) mRemoteConnectionListener.onRemoteConnectionDidDisconnect(trigger);
    }

    @Override
    public void setRemoteConnectionListener(RemoteConnectionListener remoteConnectionListener) {
        mRemoteConnectionListener = remoteConnectionListener;
    }

    private void connectSocket() {
        Log.d(TAG, "Connecting the socket: " + mServerUrl + ":" + mServerPort);

        ConnectTask connectAndAuthorizeTask = new ConnectTask(mServerUrl, mServerPort, mServerKeyStore, mLocalDeviceKeyStore, mLocalDeviceKeyStorePassword);
        connectAndAuthorizeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    private class ConnectTask extends AsyncTask<Void, String, Throwable>
    {
        /**
         * The destination address.
         */
        String   dstAddress;
        /**
         * The destination port.
         */
        int      dstPort;
        /**
         * The key store of the server certs.
         */
        KeyStore serverKeyStore;
        /**
         * The key store of the client certs.
         */
        KeyStore clientKeyStore;
        /**
         * The key store password of the client certs.
         */
        String   clientKeyStorePassword;

        /**
         * Instantiates a new Connect task.
         * @param addr the addr
         * @param port the port
         * @param sks the server key store
         * @param cks the client key store
         * @param cksPass the client key store password
         */
        ConnectTask(String addr, int port, KeyStore sks, KeyStore cks, String cksPass) {
            dstAddress = addr;
            dstPort = port;
            clientKeyStore = cks;
            serverKeyStore = sks;
            clientKeyStorePassword = <PASSWORD>;
        }

        @Override
        protected Throwable doInBackground(Void... params) {

            try {

                try {
                    KeyStore keyStore = KeyStore.getInstance("BKS", "BC");
                    keyStore.load(null, null);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                Log.d(TAG, "Creating socket factory");

                String trustManagerAlgorithm = "X509";
                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(trustManagerAlgorithm);
                trustManagerFactory.init(serverKeyStore);

                String keyManagerAlgorithm = "X509";
                KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(keyManagerAlgorithm);
                keyManagerFactory.init(clientKeyStore, clientKeyStorePassword != null ? clientKeyStorePassword.toCharArray() : null);

                SSLContext context = SSLContext.getInstance("TLS");
                context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);

                SocketFactory sf = context.getSocketFactory();

                Log.d(TAG, "Creating ssl socket");

                mSocket = (SSLSocket) sf.createSocket(dstAddress, dstPort);

                SSLSession session  = mSocket.getSession();

                java.security.cert.Certificate[] peerCertificates = session.getPeerCertificates();

                if (peerCertificates == null || peerCertificates.length == 0 || peerCertificates.length > 2) {
                    throw new Exception("Remote certificate chain is null, empty, or contains more than 2 certificates.");
                }

                mRemoteDeviceCertificate = peerCertificates[0];

                /* If there is 1 certificate, then probably the remote device certificate is the same as the server certificate (e.g., I'm connected to the server).
                   If there are 2 certificates, then probably the first certificate is the device certificate and the second certificate is the servers. This
                   should match my server certificate, right? I'm assuming this array is ordered as such, but the documentation doesn't say. */

                Log.d(TAG, "Creating ssl socket complete");

            } catch (Exception e) {
                e.printStackTrace();

                return e;   
            }

            return null;
        }

        @Override
        protected void onPostExecute(Throwable result) {
            super.onPostExecute(result);

            if (result == null) {
                // TODO: Does the input buffer stream cache data in the case that my async thread sends the auth command before the listener is set up?
                ListenTask listenTask = new ListenTask();
                listenTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

                if (mRemoteConnectionListener != null)
                    mRemoteConnectionListener.onRemoteConnectionDidConnect();
            } else {
                if (mRemoteConnectionListener != null)
                    mRemoteConnectionListener.onRemoteConnectionDidFailToConnect(result);

                mSocket = null;
            }
        }
    }

    private class ListenTask extends AsyncTask<Void, String, Throwable>
    {
        @Override
        protected Throwable doInBackground(Void... params) {
{'fraction_non_alphanumeric': 0.09123657322504584, 'fraction_numerical': 0.003340319622740372, 'mean_word_length': 2.189014202172097, 'pattern_counts': {'":': 2, '<': 13, '<?xml version=': 0, '>': 14, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6882878', 'n_tokens_mistral': 3956, 'n_tokens_neox': 3738, 'n_words': 1002}