2014-04-11 19:13:09 +00:00
|
|
|
package eu.siacs.conversations.xmpp.jingle;
|
|
|
|
|
2014-04-11 20:49:26 +00:00
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.FileNotFoundException;
|
2014-04-13 19:10:36 +00:00
|
|
|
import java.io.FileOutputStream;
|
2014-04-11 19:13:09 +00:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
2014-06-20 17:28:47 +00:00
|
|
|
import java.io.ObjectInputStream.GetField;
|
2014-04-11 19:13:09 +00:00
|
|
|
import java.net.Socket;
|
|
|
|
import java.net.UnknownHostException;
|
|
|
|
import java.security.MessageDigest;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
2014-06-20 15:30:19 +00:00
|
|
|
import android.util.Log;
|
2014-04-11 19:13:09 +00:00
|
|
|
import eu.siacs.conversations.utils.CryptoHelper;
|
|
|
|
|
2014-04-22 11:11:53 +00:00
|
|
|
public class JingleSocks5Transport extends JingleTransport {
|
2014-04-17 12:52:10 +00:00
|
|
|
private JingleCandidate candidate;
|
2014-04-11 19:13:09 +00:00
|
|
|
private String destination;
|
2014-04-11 20:49:26 +00:00
|
|
|
private OutputStream outputStream;
|
2014-04-13 19:10:36 +00:00
|
|
|
private InputStream inputStream;
|
2014-04-13 16:09:40 +00:00
|
|
|
private boolean isEstablished = false;
|
2014-04-23 19:19:56 +00:00
|
|
|
private boolean activated = false;
|
2014-04-17 12:52:10 +00:00
|
|
|
protected Socket socket;
|
2014-04-13 09:32:45 +00:00
|
|
|
|
2014-04-22 11:11:53 +00:00
|
|
|
public JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) {
|
2014-04-17 12:52:10 +00:00
|
|
|
this.candidate = candidate;
|
2014-04-11 19:13:09 +00:00
|
|
|
try {
|
|
|
|
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
|
|
|
|
StringBuilder destBuilder = new StringBuilder();
|
|
|
|
destBuilder.append(jingleConnection.getSessionId());
|
2014-04-17 12:52:10 +00:00
|
|
|
if (candidate.isOurs()) {
|
2014-04-16 21:11:37 +00:00
|
|
|
destBuilder.append(jingleConnection.getAccountJid());
|
|
|
|
destBuilder.append(jingleConnection.getCounterPart());
|
|
|
|
} else {
|
|
|
|
destBuilder.append(jingleConnection.getCounterPart());
|
|
|
|
destBuilder.append(jingleConnection.getAccountJid());
|
|
|
|
}
|
2014-04-11 19:13:09 +00:00
|
|
|
mDigest.reset();
|
2014-04-13 09:32:45 +00:00
|
|
|
this.destination = CryptoHelper.bytesToHex(mDigest
|
|
|
|
.digest(destBuilder.toString().getBytes()));
|
2014-04-11 19:13:09 +00:00
|
|
|
} catch (NoSuchAlgorithmException e) {
|
2014-04-13 09:32:45 +00:00
|
|
|
|
2014-04-11 19:13:09 +00:00
|
|
|
}
|
|
|
|
}
|
2014-04-13 09:32:45 +00:00
|
|
|
|
2014-04-22 11:11:53 +00:00
|
|
|
public void connect(final OnTransportConnected callback) {
|
2014-04-13 16:09:40 +00:00
|
|
|
new Thread(new Runnable() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
try {
|
2014-04-17 12:52:10 +00:00
|
|
|
socket = new Socket(candidate.getHost(), candidate.getPort());
|
2014-04-13 19:10:36 +00:00
|
|
|
inputStream = socket.getInputStream();
|
2014-04-13 16:09:40 +00:00
|
|
|
outputStream = socket.getOutputStream();
|
|
|
|
byte[] login = { 0x05, 0x01, 0x00 };
|
|
|
|
byte[] expectedReply = { 0x05, 0x00 };
|
|
|
|
byte[] reply = new byte[2];
|
|
|
|
outputStream.write(login);
|
2014-04-13 19:10:36 +00:00
|
|
|
inputStream.read(reply);
|
2014-04-13 16:09:40 +00:00
|
|
|
if (Arrays.equals(reply, expectedReply)) {
|
|
|
|
String connect = "" + '\u0005' + '\u0001' + '\u0000' + '\u0003'
|
|
|
|
+ '\u0028' + destination + '\u0000' + '\u0000';
|
|
|
|
outputStream.write(connect.getBytes());
|
|
|
|
byte[] result = new byte[2];
|
2014-04-13 19:10:36 +00:00
|
|
|
inputStream.read(result);
|
2014-04-13 16:09:40 +00:00
|
|
|
int status = result[1];
|
|
|
|
if (status == 0) {
|
|
|
|
isEstablished = true;
|
|
|
|
callback.established();
|
|
|
|
} else {
|
|
|
|
callback.failed();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
socket.close();
|
|
|
|
callback.failed();
|
|
|
|
}
|
|
|
|
} catch (UnknownHostException e) {
|
|
|
|
callback.failed();
|
|
|
|
} catch (IOException e) {
|
|
|
|
callback.failed();
|
|
|
|
}
|
2014-04-11 19:13:09 +00:00
|
|
|
}
|
2014-04-13 16:09:40 +00:00
|
|
|
}).start();
|
|
|
|
|
2014-04-11 19:13:09 +00:00
|
|
|
}
|
2014-04-11 20:49:26 +00:00
|
|
|
|
2014-04-13 09:32:45 +00:00
|
|
|
public void send(final JingleFile file, final OnFileTransmitted callback) {
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2014-06-20 15:30:19 +00:00
|
|
|
InputStream fileInputStream = null;
|
2014-04-13 09:32:45 +00:00
|
|
|
try {
|
|
|
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
|
|
|
digest.reset();
|
2014-06-20 15:30:19 +00:00
|
|
|
fileInputStream = getInputStream(file);
|
2014-04-13 09:32:45 +00:00
|
|
|
int count;
|
2014-06-20 17:28:47 +00:00
|
|
|
long txBytes = 0;
|
2014-04-13 09:32:45 +00:00
|
|
|
byte[] buffer = new byte[8192];
|
2014-06-20 17:28:47 +00:00
|
|
|
while ((count = fileInputStream.read(buffer)) > 0) {
|
|
|
|
txBytes += count;
|
2014-04-13 09:32:45 +00:00
|
|
|
outputStream.write(buffer, 0, count);
|
|
|
|
digest.update(buffer, 0, count);
|
|
|
|
}
|
2014-06-20 17:28:47 +00:00
|
|
|
Log.d("xmppService","txBytes="+txBytes);
|
2014-04-13 09:32:45 +00:00
|
|
|
outputStream.flush();
|
|
|
|
file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
|
|
|
|
if (callback!=null) {
|
|
|
|
callback.onFileTransmitted(file);
|
|
|
|
}
|
|
|
|
} catch (FileNotFoundException e) {
|
|
|
|
// TODO Auto-generated catch block
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (IOException e) {
|
2014-06-20 17:28:47 +00:00
|
|
|
// TODO Auto-generated catch block
|
|
|
|
e.printStackTrace();
|
2014-04-13 09:32:45 +00:00
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
// TODO Auto-generated catch block
|
|
|
|
e.printStackTrace();
|
|
|
|
} finally {
|
|
|
|
try {
|
|
|
|
if (fileInputStream != null) {
|
|
|
|
fileInputStream.close();
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
// TODO Auto-generated catch block
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2014-04-11 20:49:26 +00:00
|
|
|
}
|
|
|
|
}
|
2014-04-13 09:32:45 +00:00
|
|
|
}).start();
|
|
|
|
|
2014-04-11 20:49:26 +00:00
|
|
|
}
|
2014-04-13 19:10:36 +00:00
|
|
|
|
|
|
|
public void receive(final JingleFile file, final OnFileTransmitted callback) {
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
try {
|
|
|
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
|
|
|
digest.reset();
|
|
|
|
inputStream.skip(45);
|
|
|
|
file.getParentFile().mkdirs();
|
|
|
|
file.createNewFile();
|
2014-06-20 15:30:19 +00:00
|
|
|
OutputStream fileOutputStream = getOutputStream(file);
|
2014-04-13 19:10:36 +00:00
|
|
|
long remainingSize = file.getExpectedSize();
|
|
|
|
byte[] buffer = new byte[8192];
|
|
|
|
int count = buffer.length;
|
2014-06-20 17:28:47 +00:00
|
|
|
long rxBytes = 0;
|
|
|
|
while(remainingSize > 0) {
|
2014-06-20 15:30:19 +00:00
|
|
|
count = inputStream.read(buffer);
|
2014-06-20 17:28:47 +00:00
|
|
|
if (count==-1) {
|
|
|
|
Log.d("xmppService","read end");
|
|
|
|
} else {
|
|
|
|
rxBytes += count;
|
2014-04-14 18:35:11 +00:00
|
|
|
fileOutputStream.write(buffer, 0, count);
|
|
|
|
digest.update(buffer, 0, count);
|
2014-06-20 17:28:47 +00:00
|
|
|
remainingSize-=count;
|
2014-04-14 18:35:11 +00:00
|
|
|
}
|
2014-04-13 19:10:36 +00:00
|
|
|
}
|
2014-06-20 17:28:47 +00:00
|
|
|
Log.d("xmppService","rx bytes="+rxBytes);
|
2014-04-13 19:10:36 +00:00
|
|
|
fileOutputStream.flush();
|
|
|
|
fileOutputStream.close();
|
|
|
|
file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
|
|
|
|
callback.onFileTransmitted(file);
|
|
|
|
} catch (FileNotFoundException e) {
|
2014-06-20 17:28:47 +00:00
|
|
|
// TODO Auto-generated catch block
|
|
|
|
e.printStackTrace();
|
2014-04-13 19:10:36 +00:00
|
|
|
} catch (IOException e) {
|
2014-06-20 17:28:47 +00:00
|
|
|
// TODO Auto-generated catch block
|
|
|
|
e.printStackTrace();
|
2014-04-13 19:10:36 +00:00
|
|
|
} catch (NoSuchAlgorithmException e) {
|
2014-06-20 17:28:47 +00:00
|
|
|
// TODO Auto-generated catch block
|
|
|
|
e.printStackTrace();
|
2014-04-13 19:10:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}).start();
|
|
|
|
}
|
2014-04-13 09:32:45 +00:00
|
|
|
|
2014-04-11 20:49:26 +00:00
|
|
|
public boolean isProxy() {
|
2014-04-17 12:52:10 +00:00
|
|
|
return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
|
2014-04-13 19:10:36 +00:00
|
|
|
}
|
2014-04-23 19:19:56 +00:00
|
|
|
|
|
|
|
public boolean needsActivation() {
|
|
|
|
return (this.isProxy() && !this.activated);
|
|
|
|
}
|
2014-04-13 09:32:45 +00:00
|
|
|
|
|
|
|
public void disconnect() {
|
|
|
|
if (this.socket!=null) {
|
|
|
|
try {
|
|
|
|
this.socket.close();
|
|
|
|
} catch (IOException e) {
|
2014-06-16 10:18:04 +00:00
|
|
|
|
2014-04-13 09:32:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-04-13 16:09:40 +00:00
|
|
|
|
|
|
|
public boolean isEstablished() {
|
|
|
|
return this.isEstablished;
|
|
|
|
}
|
2014-04-17 12:52:10 +00:00
|
|
|
|
|
|
|
public JingleCandidate getCandidate() {
|
|
|
|
return this.candidate;
|
|
|
|
}
|
2014-04-23 19:19:56 +00:00
|
|
|
|
|
|
|
public void setActivated(boolean activated) {
|
|
|
|
this.activated = activated;
|
|
|
|
}
|
2014-04-11 19:13:09 +00:00
|
|
|
}
|