package uk.ac.cam.cl.dtg.android.tor.TorProxyExample; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; import uk.ac.cam.cl.dtg.android.tor.TorProxyLib.ITorProxyControl; import uk.ac.cam.cl.dtg.android.tor.TorProxyLib.SocksProxy; import uk.ac.cam.cl.dtg.android.tor.TorProxyLib.TorProxyLib; import android.app.Activity; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class TorProxyExample extends Activity implements Runnable, OnClickListener { private static final String HOST = "www.something.com"; private static final int PORT = 80; private TextView mStatusView = null; private TextView mHttpResult = null; private Button mOpenTorProxy = null; private boolean mFetching = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mStatusView = (TextView)findViewById(R.id.statusView); mHttpResult = (TextView)findViewById(R.id.httpResult); mOpenTorProxy = (Button)findViewById(R.id.openTorProxy); mOpenTorProxy.setOnClickListener(this); } // Keep track of the control service private ITorProxyControl mControlService = null; private final IntentFilter torStatusFilter = new IntentFilter( TorProxyLib.STATUS_CHANGE_INTENT); // Service connection to TorProxy service private ServiceConnection mSvcConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mControlService = ITorProxyControl.Stub.asInterface(service); // Connected to Control Service // Perhaps check Tor status here updateTorStatus(); } @Override public void onServiceDisconnected(ComponentName name) { mControlService = null; // Connection to Control Service lost } }; @Override protected void onResume() { super.onResume(); // Register to receive Tor status update broadcasts registerReceiver(mBroadcastReceiver, torStatusFilter); // Bind to the TorProxy control service bindService(new Intent().setComponent(new ComponentName( TorProxyLib.CONTROL_SERVICE_PACKAGE, TorProxyLib.CONTROL_SERVICE_CLASS)), mSvcConn, BIND_AUTO_CREATE); } @Override protected void onPause() { // Registered in onResume so unregister here unregisterReceiver(mBroadcastReceiver); unbindService(mSvcConn); super.onPause(); } private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (TorProxyLib.STATUS_CHANGE_INTENT.equals(intent.getAction())) { // TorProxy has broadcast a Tor status update // Check Tor status here updateTorStatus(); } } }; private void updateTorStatus() { try { int torStatus = mControlService.getStatus(); int torProfile = mControlService.getProfile(); switch (torStatus) { case TorProxyLib.STATUS_ON: setStatus("available"); startHttpRequest(); break; case TorProxyLib.STATUS_REQUIRES_DEMAND: setStatus("requires demand"); mControlService.registerDemand(); break; case TorProxyLib.STATUS_CONNECTING: setStatus("connecting..."); break; case TorProxyLib.STATUS_UNAVAILABLE: if (torProfile == TorProxyLib.PROFILE_OFF) setStatus("anonymous connection is turned off"); else setStatus("anonymous connection is unavailable (no network?)"); break; } } catch (RemoteException e) { setStatus("Error communicating with control service"); } } private void setStatus(final String s) { // Update the UI with a status // Post to the view since we are probably being called from // another thread. mStatusView.post(new Runnable() { @Override public void run() { mStatusView.setText("Status: " + s); } }); } private void setHttpResult(final String s) { // Update the UI with an HttpResult // Post to the view since we are probably being called from // another thread. mHttpResult.post(new Runnable() { @Override public void run() { mHttpResult.setText(s); } }); } private void startHttpRequest() { new Thread(this).start(); } @Override public void run() { // Only allow one fetch at a time synchronized(this) { if (mFetching == true) return; mFetching = true; } try { // Get the proxy port int proxyPort = mControlService.getSOCKSPort(); SocksProxy proxy = new SocksProxy(proxyPort); try { setHttpResult("Getting " + HOST); // Create a socket to the destination through the // anonymous proxy Socket s = proxy.connectSocksProxy(null, HOST, PORT, 0); //Socket s = new Socket(HOST, PORT); PrintWriter writer = new PrintWriter(s.getOutputStream()); InputStreamReader reader = new InputStreamReader(s.getInputStream()); // Very simple HTTP GET writer.println("GET / HTTP/1.1"); writer.println("Host: " + HOST); writer.println("Connection: close"); writer.println(); writer.flush(); // Get the result StringBuilder result = new StringBuilder(); char[] buffer = new char[1024]; int read = 0; do { result.append(buffer, 0, read); read = reader.read(buffer, 0, buffer.length); } while (read > -1); // Update the UI setHttpResult(result.toString()); } catch (UnknownHostException e) { setHttpResult("Unknown host: " + HOST); } catch (IOException e) { setHttpResult("IOException"); } } catch (RemoteException e1) { setHttpResult("Unable to communicate with control service"); } synchronized(this) { mFetching = false; } } @Override public void onClick(View v) { if (v.getId() == R.id.openTorProxy) { try { Intent i = new Intent().setComponent(new ComponentName( TorProxyLib.SETTINGS_ACTIVITY_PACKAGE, TorProxyLib.SETTINGS_ACTIVITY_CLASS)); startActivity(i); } catch (ActivityNotFoundException a) { AlertDialog.Builder b = new AlertDialog.Builder(this); b.setMessage("TorProxy must be installed for this application to work"); b.setPositiveButton("OK", null); b.show(); } } } }