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							Log.d("xmppService", "established connection with "+candidate.getHost()+":"+candidate.getPort()+ "/" + destination);
 73							isEstablished = true;
 74							callback.established();
 75						} else {
 76							callback.failed();
 77						}
 78					} else {
 79						socket.close();
 80						callback.failed();
 81					}
 82				} catch (UnknownHostException e) {
 83					callback.failed();
 84				} catch (IOException e) {
 85					callback.failed();
 86				}
 87			}
 88		}).start();
 89		
 90	}
 91
 92	public void send(final JingleFile file, final OnFileTransmitted callback) {
 93		new Thread(new Runnable() {
 94			
 95			@Override
 96			public void run() {
 97				FileInputStream fileInputStream = null;
 98				try {
 99					MessageDigest digest = MessageDigest.getInstance("SHA-1");
100					digest.reset();
101					fileInputStream = new FileInputStream(file);
102					int count;
103					byte[] buffer = new byte[8192];
104					while ((count = fileInputStream.read(buffer)) > 0) {
105						outputStream.write(buffer, 0, count);
106						digest.update(buffer, 0, count);
107					}
108					outputStream.flush();
109					file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
110					if (callback!=null) {
111						callback.onFileTransmitted(file);
112					}
113				} catch (FileNotFoundException e) {
114					// TODO Auto-generated catch block
115					e.printStackTrace();
116				} catch (IOException e) {
117					// TODO Auto-generated catch block
118					e.printStackTrace();
119				} catch (NoSuchAlgorithmException e) {
120					// TODO Auto-generated catch block
121					e.printStackTrace();
122				} finally {
123					try {
124						if (fileInputStream != null) {
125							fileInputStream.close();
126						}
127					} catch (IOException e) {
128						// TODO Auto-generated catch block
129						e.printStackTrace();
130					}
131				}
132			}
133		}).start();
134		
135	}
136	
137	public void receive(final JingleFile file, final OnFileTransmitted callback) {
138		new Thread(new Runnable() {
139			
140			@Override
141			public void run() {
142				try {
143					MessageDigest digest = MessageDigest.getInstance("SHA-1");
144					digest.reset();
145					inputStream.skip(45);
146					file.getParentFile().mkdirs();
147					file.createNewFile();
148					FileOutputStream fileOutputStream = new FileOutputStream(file);
149					long remainingSize = file.getExpectedSize();
150					byte[] buffer = new byte[8192];
151					int count = buffer.length;
152					while(remainingSize > 0) {
153						Log.d("xmppService","remaning size:"+remainingSize);
154						if (remainingSize<=count) {
155							count = (int) remainingSize;
156						}
157						count = inputStream.read(buffer, 0, count);
158						if (count==-1) {
159							Log.d("xmppService","end of stream");
160						} else {
161							fileOutputStream.write(buffer, 0, count);
162							digest.update(buffer, 0, count);
163							remainingSize-=count;
164						}
165					}
166					fileOutputStream.flush();
167					fileOutputStream.close();
168					file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
169					Log.d("xmppService","transmitted filename was: "+file.getAbsolutePath());
170					callback.onFileTransmitted(file);
171				} catch (FileNotFoundException e) {
172					// TODO Auto-generated catch block
173					e.printStackTrace();
174				} catch (IOException e) {
175					// TODO Auto-generated catch block
176					e.printStackTrace();
177				} catch (NoSuchAlgorithmException e) {
178					// TODO Auto-generated catch block
179					e.printStackTrace();
180				}
181			}
182		}).start();
183	}
184
185	public boolean isProxy() {
186		return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
187	}
188
189	public void disconnect() {
190		if (this.socket!=null) {
191			try {
192				this.socket.close();
193				Log.d("xmppService","cloesd socket with "+candidate.getHost()+":"+candidate.getPort());
194			} catch (IOException e) {
195				Log.d("xmppService","error closing socket with "+candidate.getHost()+":"+candidate.getPort());
196			}
197		}
198	}
199	
200	public boolean isEstablished() {
201		return this.isEstablished;
202	}
203	
204	public JingleCandidate getCandidate() {
205		return this.candidate;
206	}
207}