JingleSocks5Transport.java

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