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