JingleSocks5Transport.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 JingleSocks5Transport extends JingleTransport {
 22	private JingleCandidate candidate;
 23	private String destination;
 24	private OutputStream outputStream;
 25	private InputStream inputStream;
 26	private boolean isEstablished = false;
 27	private boolean activated = false;
 28	protected Socket socket;
 29
 30	public JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) {
 31		this.candidate = candidate;
 32		try {
 33			MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
 34			StringBuilder destBuilder = new StringBuilder();
 35			destBuilder.append(jingleConnection.getSessionId());
 36			if (candidate.isOurs()) {
 37				destBuilder.append(jingleConnection.getAccountJid());
 38				destBuilder.append(jingleConnection.getCounterPart());
 39			} else {
 40				destBuilder.append(jingleConnection.getCounterPart());
 41				destBuilder.append(jingleConnection.getAccountJid());
 42			}
 43			mDigest.reset();
 44			this.destination = CryptoHelper.bytesToHex(mDigest
 45					.digest(destBuilder.toString().getBytes()));
 46		} catch (NoSuchAlgorithmException e) {
 47
 48		}
 49	}
 50
 51	public void connect(final OnTransportConnected callback) {
 52		new Thread(new Runnable() {
 53			
 54			@Override
 55			public void run() {
 56				try {
 57					socket = new Socket(candidate.getHost(), candidate.getPort());
 58					inputStream = socket.getInputStream();
 59					outputStream = socket.getOutputStream();
 60					byte[] login = { 0x05, 0x01, 0x00 };
 61					byte[] expectedReply = { 0x05, 0x00 };
 62					byte[] reply = new byte[2];
 63					outputStream.write(login);
 64					inputStream.read(reply);
 65					if (Arrays.equals(reply, expectedReply)) {
 66						String connect = "" + '\u0005' + '\u0001' + '\u0000' + '\u0003'
 67								+ '\u0028' + destination + '\u0000' + '\u0000';
 68						outputStream.write(connect.getBytes());
 69						byte[] result = new byte[2];
 70						inputStream.read(result);
 71						int status = result[1];
 72						if (status == 0) {
 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 boolean needsActivation() {
190		return (this.isProxy() && !this.activated);
191	}
192
193	public void disconnect() {
194		if (this.socket!=null) {
195			try {
196				this.socket.close();
197				Log.d("xmppService","cloesd socket with "+candidate.getHost()+":"+candidate.getPort());
198			} catch (IOException e) {
199				Log.d("xmppService","error closing socket with "+candidate.getHost()+":"+candidate.getPort());
200			}
201		}
202	}
203	
204	public boolean isEstablished() {
205		return this.isEstablished;
206	}
207	
208	public JingleCandidate getCandidate() {
209		return this.candidate;
210	}
211
212	public void setActivated(boolean activated) {
213		this.activated = activated;
214	}
215}