• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps Desperately need help in building a Proxy Server for Android

anishuq

Lurker
I am building a Proxy Server for android and I have hit a wall. I need help desperately. I am quite new to Android. So, at first, I made the Proxy server in Java SE. The Proxy Server works as following:


  1. It listens to a local port,
  2. When the client connects, a new thread is created. Each thread is also given a name.
  3. The HOST is extracted from the request.
  4. Client's request is then forwarded to the Remote address (acquired from HOST).
  5. The Proxy then reads the remote server's address until -1 is found.
  6. This response is then forwarded to the client.

The proxy server is run in the Laptop. The client is Youtube APP of an android phone. The phone is rooted and I have installed ProxyDroid to tell the client where the Proxy Server is. "Global Proxy" option of ProxyDroid is used.

The code in Java SE:

Code:
class clientThread implements Runnable
    {
        Socket clientSocket = null;//each client socket.

        Socket connectYoutubeServerSock = null;//This socket is used to write client's request to the 
                                        //YouTube Server.
        int videoFlag = 0;//this flag determines whether the GET request is a video request or not. 

        final int BufferSize = 8019;
        public String hostURL;
        int youtubePort = 80;
        //public DataOutputStream sendClientResponse = null;

        public clientThread(Socket clientSocket)
        {
            this.clientSocket = clientSocket;
        }


        public void run()
        {
            System.out.println("Client connected: "+clientSocket.toString());
            System.out.println("Current Thread Name: "+Thread.currentThread().getName());

            try
            {
                byte youtubeAppReqArray[] = new byte[BufferSize];//this byte array will house youtube app's request!
                InputStream youtubeAppReq = clientSocket.getInputStream();

                // reading the request and put it into youtubeAppReqArray.
                int bytesRead = youtubeAppReq.read(youtubeAppReqArray,0,BufferSize);
                String youtubeAppReqString = new String(youtubeAppReqArray, 0, bytesRead);
                System.out.println(youtubeAppReqString);

                // extract the url of the GET request!
                int gStart = youtubeAppReqString.indexOf("GET: ") + 4;
                int gEnd = youtubeAppReqString.indexOf('\n', gStart);
                String gURL = youtubeAppReqString.substring(gStart, gEnd - 9);
                System.out.println("URL of GET: " + gURL);
                //test if videoplayback is there or not?
                if(gURL.indexOf("videoplayback") > -1  )
                {
                    System.out.println("This is a video request!");
                    videoFlag = 1;
                }


                // extract the host to connect to
                int hStart = youtubeAppReqString.indexOf("Host: ") + 6;
                int hEnd = youtubeAppReqString.indexOf('\n', hStart);
                String host = youtubeAppReqString.substring(hStart, hEnd - 1);
                System.out.println("Connecting to host " + host);

                //forward the youtube app request from proxy to the youtube server
                Socket youtubeServerSocket = new Socket(host, 80);
                OutputStream writeToYoutubeServerStream = youtubeServerSocket.getOutputStream();
                System.out.println("Forwarding request to server");
                writeToYoutubeServerStream.write(youtubeAppReqArray, 0, bytesRead);
                writeToYoutubeServerStream.flush(); 

                // forward the response from the server to the browser
                byte youtubeServerResArray[] = new byte[BufferSize];//this byte array will house youtube server's response.

                InputStream readFromYoutubeServerStream = youtubeServerSocket.getInputStream();
                OutputStream writeToYoutubeAppStream = clientSocket.getOutputStream();

                System.out.println("Forwarding request from server");

                int remoteBytesRead;
                do 
                {
                    remoteBytesRead = readFromYoutubeServerStream.read(youtubeServerResArray,0,BufferSize);
                    System.out.println("Receiving " + remoteBytesRead + " bytes");
                    if (remoteBytesRead > 0) 
                    {
                        writeToYoutubeAppStream.write(youtubeServerResArray, 0, remoteBytesRead);
                        String rData = new String(youtubeServerResArray,0,remoteBytesRead);
                        System.out.println("Remote data:  "+rData);
                    }
                } while (remoteBytesRead > 0); 

                writeToYoutubeAppStream.flush();
                youtubeServerSocket.close();
                clientSocket.close();
                System.out.println("End of communication");
            }
            catch(IOException ioe)
            {
                System.out.println("Error"+ioe.getMessage());
            }
        }
    }

    public class ChallengeProxy extends IOException 
    {
        public static final int SERVERPORT = 4447;
        public static int threadName = 0;
        public static void main(String[] args) 
        {
            ChallengeProxy proxyObj = new ChallengeProxy();
            proxyObj.knowIP();//get the IP address of the local machine!

             try 
             {
                 ServerSocket serverSocket = new ServerSocket(SERVERPORT);
                 System.out.println("Started on: "+SERVERPORT);

                 while(true)//Non stop listen for clients!
                 {
                     Socket clientSocket = serverSocket.accept();//blocks until client is connected!
                     System.out.println("Client connected: "+clientSocket.toString());

                     Thread t = new Thread(new clientThread(clientSocket), Integer.toString(threadName));
                     t.start();

                     threadName++;
                 }
             } 
             catch (IOException ioe) 
             {
                System.out.println("Could not listen on port: "+SERVERPORT);
                System.out.println("Error"+ioe.getMessage());
             }
             catch(Exception e)
             {
                 System.out.println("Error"+e.getMessage());
             }
        }

        public void knowIP()
        {
           Just gets IP of the local machine.
        }

}
It does is exactly what I want. Now, I transform the code a little, so that, it runs in Android. However, the logic underneath is the same. Here also, when a new client connects, a new thread is created. The Youtube APP is still the client. So now, the YouTube APP would request a proxy server residing in the same Android machine. As before, ProxyDroid is configured so that, YouTube APP knows where my Proxy server is running.
The code for Android looks like:

Code:
public class ChallengeAndroidProxyActivity extends Activity 
{
    public static final int SERVERPORT = 4453;
    public static int threadName = 0;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        (new Thread(new Runnable() 
                                 {
                                    public void run() 
                                    {
                                        startSocketServer();
                                    }
                                 }
                     )).start();
    }

    /*
     * Here we will create an infinite loop that will listen
     * for client connections.
     * 
     * */
    public void startSocketServer() 
    {
        knowIP();// Now we find the IP address of the native machine.
        String LOG_TAG = "SocketServerThread";
        Log.i(LOG_TAG,"Inside the server thread! ");

        try 
        {
            ServerSocket serverSocket = new ServerSocket(SERVERPORT);
            Log.i(LOG_TAG, "Started on : " + SERVERPORT);

            threadName = 0;
            while (true)// Non stop listen for clients!
            {
                Socket clientSocket = serverSocket.accept();
                Log.d(LOG_TAG , "Client connected : " + clientSocket.toString());

                Thread t = new Thread(new clientThread(clientSocket), Integer.toString(threadName));
                t.start();

                threadName++;
            }
        }
        catch (IOException ioe) 
        {
            Log.i(LOG_TAG, "Could not listen on port: " + SERVERPORT);
            Log.i(LOG_TAG, "Error : " + ioe.getMessage());
        } 
        catch (Exception e) 
        {
            Log.i(LOG_TAG, "Error : " + e.getMessage());
        }
    }

class clientThread implements Runnable
    {
        String LOG_TAG = "clientSocketThread";
        Socket clientSocket = null;//each client socket.

        Socket connectYoutubeServerSock = null;//This socket is used to write client's request to the 
                                        //YouTube Server.
        int videoFlag = 0;//this flag determines whether the GET request is a video request or not. 

        final int BufferSize = 8019;
        public String hostURL;
        int youtubePort = 80;

        public clientThread(Socket clientSocket)
        {
            this.clientSocket = clientSocket;
        }

        public void run()
        {
            Log.i(LOG_TAG,"Client connected: "+clientSocket.toString());
            Log.i(LOG_TAG,"Current Thread Name: "+Thread.currentThread().getName());


            try
            {//1
                byte youtubeAppReqArray[] = new byte[BufferSize];//this byte array will house youtube app's request!
                InputStream youtubeAppReq = clientSocket.getInputStream();

                // reading the request and put it into youtubeAppReqArray.
                int bytesRead = youtubeAppReq.read(youtubeAppReqArray,0,BufferSize);
                String youtubeAppReqString = new String(youtubeAppReqArray, 0, bytesRead);
                Log.i("Youtube App Request: ",youtubeAppReqString);

                // extract the host to connect to
                int hStart = youtubeAppReqString.indexOf("Host: ") + 6;
                int hEnd = youtubeAppReqString.indexOf('\n', hStart);
                String host = youtubeAppReqString.substring(hStart, hEnd - 1);
                Log.i("Connecting to host ",host);

                InetAddress addr = InetAddress.getByName(host);
                int port = 80;
                SocketAddress sockaddr = new InetSocketAddress(addr, port);

                Socket youtubeServerSocket = new Socket();
                youtubeServerSocket.connect(sockaddr);

                OutputStream writeToYoutubeServerStream = youtubeServerSocket.getOutputStream();
                //writeToYoutubeServerStream.write(youtubeAppReqArray, 0, bytesRead);

            }//1
            catch(IOException ioe)
            {//1
                Log.i("Error",ioe.getMessage());
            }//1
        }
    }   


    /************************************************************************************/
    public void knowIP()
    {
            This function just gets the IP of the native machine.
    }
}
When the line of code

Code:
//writeToYoutubeServerStream.write(youtubeAppReqArray, 0, bytesRead);
is commented out (by this line, my proxy writes client's request to the Remote server), the request that I get from the client looks like:



Code:
07-19 22:30:16.309: I/ApplicationPackageManager(2843): cscCountry is not German : NEE
07-19 22:30:16.399: I/Net interface:(2843): wlan0
07-19 22:30:16.429: I/IP address:(2843): /192.168.1.129
07-19 22:30:16.429: I/Net interface:(2843): lo
07-19 22:30:16.439: I/IP address:(2843): /127.0.0.1
07-19 22:30:16.439: I/SocketServerThread(2843): Inside the server thread! 
07-19 22:30:16.439: I/SocketServerThread(2843): Started on : 4453
07-19 22:30:20.929: D/SocketServerThread(2843): Client connected : Socket[addr=/192.168.1.129,port=44276,localport=4453]
07-19 22:30:20.959: I/clientSocketThread(2843): Client connected: Socket[addr=/192.168.1.129,port=44276,localport=4453]
07-19 22:30:20.959: I/clientSocketThread(2843): Current Thread Name: 0
07-19 22:30:20.969: I/Youtube App Request:(2843): GET http://gdata.youtube.com/feeds/api/users/asadfffx/newsubscriptionvideos?format=2%2C3%2C9&start-index=1&max-results=10&safeSearch=none HTTP/1.1

07-19 22:30:20.969: I/Youtube App Request:(2843): GData-Version: 2

07-19 22:30:20.969: I/Youtube App Request:(2843): X-GData-Device: device-id="AOuj_RqmoX-WkCNNaJKieF2mmwMlkOMFRk7sQsKP_wmdrL1BB1N9V_iVIJAUBkvvyzGdpxWVS83wE7UkGPYjWf0BWvbPa0Uoo0cmgKfxzEqOog8EC-Rm1Wg", data="H1NEdDZ+FuL4U9v3Bx1hlVIAm1s="

07-19 22:30:20.969: I/Youtube App Request:(2843): Authorization: GoogleLogin auth="DQAAAKcAAAC5aU6IN0t6yUkoiU9OmjU8fYjKm1m7MLKleHLhtR-uwCclnZGcKGm-6gYfkjvAGKGXK88dbKnB708CVCQkvJofL6smBXp7TEFj1FqGaRasdOx2iVYrbaTbWtIc8sBaga7v2P1BfctMiSTtEU2HWCqqCiubMvpfspnl9wS284SLgk-Se4jjFsZTo-84la_2wJy_Wmap8OSTdif7JoaxpxYLAWECByrJO50iMTj__6cN3A"

07-19 22:30:20.969: I/Youtube App Request:(2843): Host: gdata.youtube.com

07-19 22:30:20.969: I/Youtube App Request:(2843): User-Agent: Android-YouTube/2

07-19 22:30:20.969: I/Youtube App Request:(2843): Proxy-Connection: close

07-19 22:30:20.969: I/Youtube App Request:(2843): Connection: close

07-19 22:30:20.969: I/Youtube App Request:(2843): 

07-19 22:30:20.979: I/Connecting to host(2843): gdata.youtube.com
This is how the client's request should look like. But when I un-comment the following line (i.e. it gets executed):
Code:
writeToYoutubeServerStream.write(youtubeAppReqArray, 0, bytesRead);
everything falls apart. Specially, the request from the YouTube App does not make any sense. Hundreds of threads get created. And my GET request starts to look like:


Code:
07-19 22:36:21.969: I/Youtube App Request:(2916): GData-Version: 2

07-19 22:36:21.969: I/Youtube App Request:(2916): X-GData-Device: device-id="AOuj_RqmoX-WkCNNaJKieF2mmwMlkOMFRk7sQsKP_wmdrL1BB1N9V_iVIJAUBkvvyzGdpxWVS83wE7UkGPYjWf0BWvbPa0Uoo0cmgKfxzEqOog8EC-Rm1Wg", data="H1NEdDZ+FuL4U9v3Bx1hlVIAm1s="

07-19 22:36:21.969: I/Youtube App Request:(2916): Authorization: GoogleLogin auth="DQAAAKcAAAC5aU6IN0t6yUkoiU9OmjU8fYjKm1m7MLKleHLhtR-uwCclnZGcKGm-6gYfkjvAGKGXK88dbKnB708CVCQkvJofL6smBXp7TEFj1FqGaRasdOx2iVYrbaTbWtIc8sBaga7v2P1BfctMiSTtEU2HWCqqCiubMvpfspnl9wS284SLgk-Se4jjFsZTo-84la_2wJy_Wmap8OSTdif7JoaxpxYLAWECByrJO50iMTj__6cN3A"

07-19 22:36:21.969: I/Youtube App Request:(2916): Host: gdat
07-19 22:36:21.969: I/Connecting to host(2916): gdata.youtube.com
07-19 22:36:21.979: D/SocketServerThread(2916): Client connected : Socket[addr=/192.168.1.129,port=55126,localport=4453]
07-19 22:36:21.979: I/clientSocketThread(2916): Client connected: Socket[addr=/192.168.1.129,port=55125,localport=4453]
07-19 22:36:21.979: I/clientSocketThread(2916): Current Thread Name: 463
07-19 22:36:21.979: I/Youtube App Request:(2916): GET http://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.com/feeds/api/users/asadfffx/newsubscriptionvideos?format=2%2C3%2C9&start-index=1&max-results=10&safeSearch=none HTTP/1.1

07-19 22:36:21.979: I/Youtube App Request:(2916): GData-Version: 2

07-19 22:36:21.979: I/Youtube App Request:(2916): X-GData-Device: device-id="AOuj_RqmoX-WkCNNaJKieF2mmwMlkOMFRk7sQsKP_wmdrL1BB1N9V_iVIJAUBkvvyzGdpxWVS83wE7UkGPYjWf0BWvbPa0Uoo0cmgKfxzEqOog8EC-Rm1Wg", data="H1NEdDZ+FuL4U9v3Bx1hlVIAm1s="

07-19 22:36:21.979: I/Youtube App Request:(2916): Authorization: GoogleLogin auth="DQAAAKcAAAC5aU6IN0t6yUkoiU9OmjU8fYjKm1m7MLKleHLhtR-uwCclnZGcKGm-6gYfkjvAGKGXK88dbKnB708CVCQkvJofL6smBXp7TEFj1FqGaRasdOx2iVYrbaTbWtIc8sBaga7v2P1BfctMiSTtEU2HWCqqCiubMvpfspnl9wS284SLgk-Se4jjFsZTo-84la_2wJy_Wmap8OSTdif7JoaxpxYLAWECByrJO50iMTj__6cN3A"

07-19 22:36:21.979: I/Youtube App Request:(2916): Host: gdata.youtube.com
Why does the GET request look like this? My guess is that, something is wrong with the threads. Is creating socket, read/write thread safe? Is the code jumping between threads? What am I doing wrong? The same code works in Java SE; so why does it fall apart in Android?



Any suggestions, comments and code snippet will be appreciated.
 
Back
Top Bottom