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