SocksConnection.java

  1package eu.siacs.conversations.xmpp.jingle;
  2
  3import java.io.FileInputStream;
  4import java.io.FileNotFoundException;
  5import java.io.FileOutputStream;
  6import java.io.IOException;
  7import java.io.InputStream;
  8import java.io.OutputStream;
  9import java.net.Socket;
 10import java.net.UnknownHostException;
 11import java.security.MessageDigest;
 12import java.security.NoSuchAlgorithmException;
 13import java.util.Arrays;
 14
 15import eu.siacs.conversations.utils.CryptoHelper;
 16import eu.siacs.conversations.xml.Element;
 17
 18import android.util.Log;
 19import android.widget.Button;
 20
 21public class SocksConnection {
 22	private JingleCandidate candidate;
 23	private String destination;
 24	private OutputStream outputStream;
 25	private InputStream inputStream;
 26	private boolean isEstablished = false;
 27	protected Socket socket;
 28
 29	public SocksConnection(JingleConnection jingleConnection, JingleCandidate candidate) {
 30		this.candidate = candidate;
 31		try {
 32			MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
 33			StringBuilder destBuilder = new StringBuilder();
 34			destBuilder.append(jingleConnection.getSessionId());
 35			if (candidate.isOurs()) {
 36				destBuilder.append(jingleConnection.getAccountJid());
 37				destBuilder.append(jingleConnection.getCounterPart());
 38			} else {
 39				destBuilder.append(jingleConnection.getCounterPart());
 40				destBuilder.append(jingleConnection.getAccountJid());
 41			}
 42			mDigest.reset();
 43			this.destination = CryptoHelper.bytesToHex(mDigest
 44					.digest(destBuilder.toString().getBytes()));
 45		} catch (NoSuchAlgorithmException e) {
 46
 47		}
 48	}
 49
 50	public void connect(final OnSocksConnection callback) {
 51		new Thread(new Runnable() {
 52			
 53			@Override
 54			public void run() {
 55				try {
 56					socket = new Socket(candidate.getHost(), candidate.getPort());
 57					inputStream = socket.getInputStream();
 58					outputStream = socket.getOutputStream();
 59					byte[] login = { 0x05, 0x01, 0x00 };
 60					byte[] expectedReply = { 0x05, 0x00 };
 61					byte[] reply = new byte[2];
 62					outputStream.write(login);
 63					inputStream.read(reply);
 64					if (Arrays.equals(reply, expectedReply)) {
 65						String connect = "" + '\u0005' + '\u0001' + '\u0000' + '\u0003'
 66								+ '\u0028' + destination + '\u0000' + '\u0000';
 67						outputStream.write(connect.getBytes());
 68						byte[] result = new byte[2];
 69						inputStream.read(result);
 70						int status = result[1];
 71						if (status == 0) {
 72							isEstablished = true;
 73							callback.established();
 74						} else {
 75							callback.failed();
 76						}
 77					} else {
 78						socket.close();
 79						callback.failed();
 80					}
 81				} catch (UnknownHostException e) {
 82					callback.failed();
 83				} catch (IOException e) {
 84					callback.failed();
 85				}
 86			}
 87		}).start();
 88		
 89	}
 90
 91	public void send(final JingleFile file, final OnFileTransmitted callback) {
 92		new Thread(new Runnable() {
 93			
 94			@Override
 95			public void run() {
 96				FileInputStream fileInputStream = null;
 97				try {
 98					MessageDigest digest = MessageDigest.getInstance("SHA-1");
 99					digest.reset();
100					fileInputStream = new FileInputStream(file);
101					int count;
102					byte[] buffer = new byte[8192];
103					while ((count = fileInputStream.read(buffer)) > 0) {
104						outputStream.write(buffer, 0, count);
105						digest.update(buffer, 0, count);
106					}
107					outputStream.flush();
108					file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
109					if (callback!=null) {
110						callback.onFileTransmitted(file);
111					}
112				} catch (FileNotFoundException e) {
113					// TODO Auto-generated catch block
114					e.printStackTrace();
115				} catch (IOException e) {
116					// TODO Auto-generated catch block
117					e.printStackTrace();
118				} catch (NoSuchAlgorithmException e) {
119					// TODO Auto-generated catch block
120					e.printStackTrace();
121				} finally {
122					try {
123						if (fileInputStream != null) {
124							fileInputStream.close();
125						}
126					} catch (IOException e) {
127						// TODO Auto-generated catch block
128						e.printStackTrace();
129					}
130				}
131			}
132		}).start();
133		
134	}
135	
136	public void receive(final JingleFile file, final OnFileTransmitted callback) {
137		new Thread(new Runnable() {
138			
139			@Override
140			public void run() {
141				try {
142					MessageDigest digest = MessageDigest.getInstance("SHA-1");
143					digest.reset();
144					inputStream.skip(45);
145					file.getParentFile().mkdirs();
146					file.createNewFile();
147					FileOutputStream fileOutputStream = new FileOutputStream(file);
148					long remainingSize = file.getExpectedSize();
149					byte[] buffer = new byte[8192];
150					int count = buffer.length;
151					while(remainingSize > 0) {
152						Log.d("xmppService","remaning size:"+remainingSize);
153						if (remainingSize<=count) {
154							count = (int) remainingSize;
155						}
156						count = inputStream.read(buffer, 0, count);
157						if (count==-1) {
158							Log.d("xmppService","end of stream");
159						} else {
160							fileOutputStream.write(buffer, 0, count);
161							digest.update(buffer, 0, count);
162							remainingSize-=count;
163						}
164					}
165					fileOutputStream.flush();
166					fileOutputStream.close();
167					file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
168					Log.d("xmppService","transmitted filename was: "+file.getAbsolutePath());
169					callback.onFileTransmitted(file);
170				} catch (FileNotFoundException e) {
171					// TODO Auto-generated catch block
172					e.printStackTrace();
173				} catch (IOException e) {
174					// TODO Auto-generated catch block
175					e.printStackTrace();
176				} catch (NoSuchAlgorithmException e) {
177					// TODO Auto-generated catch block
178					e.printStackTrace();
179				}
180			}
181		}).start();
182	}
183
184	public boolean isProxy() {
185		return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
186	}
187
188	public void disconnect() {
189		if (this.socket!=null) {
190			try {
191				this.socket.close();
192				Log.d("xmppService","cloesd socket with "+candidate.getHost()+":"+candidate.getPort());
193			} catch (IOException e) {
194				Log.d("xmppService","error closing socket with "+candidate.getHost()+":"+candidate.getPort());
195			}
196		}
197	}
198	
199	public boolean isEstablished() {
200		return this.isEstablished;
201	}
202	
203	public JingleCandidate getCandidate() {
204		return this.candidate;
205	}
206}