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