Conversations/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java

212 lines
5.6 KiB
Java
Raw Normal View History

package eu.siacs.conversations.xmpp.jingle;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import eu.siacs.conversations.utils.CryptoHelper;
2014-04-22 13:11:53 +02:00
public class JingleSocks5Transport extends JingleTransport {
2014-04-17 14:52:10 +02:00
private JingleCandidate candidate;
private String destination;
private OutputStream outputStream;
private InputStream inputStream;
private boolean isEstablished = false;
2014-04-23 21:19:56 +02:00
private boolean activated = false;
2014-04-17 14:52:10 +02:00
protected Socket socket;
2014-08-31 16:28:21 +02:00
public JingleSocks5Transport(JingleConnection jingleConnection,
JingleCandidate candidate) {
2014-04-17 14:52:10 +02:00
this.candidate = candidate;
try {
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
StringBuilder destBuilder = new StringBuilder();
destBuilder.append(jingleConnection.getSessionId());
2014-04-17 14:52:10 +02:00
if (candidate.isOurs()) {
2014-04-16 23:11:37 +02:00
destBuilder.append(jingleConnection.getAccountJid());
destBuilder.append(jingleConnection.getCounterPart());
} else {
destBuilder.append(jingleConnection.getCounterPart());
destBuilder.append(jingleConnection.getAccountJid());
}
mDigest.reset();
this.destination = CryptoHelper.bytesToHex(mDigest
.digest(destBuilder.toString().getBytes()));
} catch (NoSuchAlgorithmException e) {
}
}
2014-04-22 13:11:53 +02:00
public void connect(final OnTransportConnected callback) {
new Thread(new Runnable() {
2014-08-31 16:28:21 +02:00
@Override
public void run() {
try {
2014-08-31 16:28:21 +02:00
socket = new Socket(candidate.getHost(),
candidate.getPort());
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
byte[] login = { 0x05, 0x01, 0x00 };
byte[] expectedReply = { 0x05, 0x00 };
byte[] reply = new byte[2];
outputStream.write(login);
inputStream.read(reply);
if (Arrays.equals(reply, expectedReply)) {
2014-08-31 16:28:21 +02:00
String connect = "" + '\u0005' + '\u0001' + '\u0000'
+ '\u0003' + '\u0028' + destination + '\u0000'
+ '\u0000';
outputStream.write(connect.getBytes());
byte[] result = new byte[2];
inputStream.read(result);
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();
}
}
}).start();
2014-08-31 16:28:21 +02:00
}
2014-08-31 16:28:21 +02:00
public void send(final JingleFile file,
final OnFileTransmissionStatusChanged callback) {
new Thread(new Runnable() {
2014-08-31 16:28:21 +02:00
@Override
public void run() {
InputStream fileInputStream = null;
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
fileInputStream = getInputStream(file);
2014-08-31 16:28:21 +02:00
if (fileInputStream == null) {
callback.onFileTransferAborted();
return;
}
int count;
byte[] buffer = new byte[8192];
2014-06-20 19:28:47 +02:00
while ((count = fileInputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, count);
digest.update(buffer, 0, count);
}
outputStream.flush();
file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
2014-08-31 16:28:21 +02:00
if (callback != null) {
callback.onFileTransmitted(file);
}
} catch (FileNotFoundException e) {
callback.onFileTransferAborted();
} catch (IOException e) {
callback.onFileTransferAborted();
} catch (NoSuchAlgorithmException e) {
callback.onFileTransferAborted();
} finally {
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
callback.onFileTransferAborted();
}
}
}
}).start();
2014-08-31 16:28:21 +02:00
}
2014-08-31 16:28:21 +02:00
public void receive(final JingleFile file,
final OnFileTransmissionStatusChanged callback) {
new Thread(new Runnable() {
2014-08-31 16:28:21 +02:00
@Override
public void run() {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
inputStream.skip(45);
2014-07-03 22:55:20 +02:00
socket.setSoTimeout(30000);
file.getParentFile().mkdirs();
file.createNewFile();
OutputStream fileOutputStream = getOutputStream(file);
2014-08-31 16:28:21 +02:00
if (fileOutputStream == null) {
callback.onFileTransferAborted();
return;
}
long remainingSize = file.getExpectedSize();
byte[] buffer = new byte[8192];
int count = buffer.length;
2014-08-31 16:28:21 +02:00
while (remainingSize > 0) {
count = inputStream.read(buffer);
2014-08-31 16:28:21 +02:00
if (count == -1) {
callback.onFileTransferAborted();
return;
2014-06-20 19:28:47 +02:00
} else {
fileOutputStream.write(buffer, 0, count);
digest.update(buffer, 0, count);
2014-08-31 16:28:21 +02:00
remainingSize -= count;
}
}
fileOutputStream.flush();
fileOutputStream.close();
file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
callback.onFileTransmitted(file);
} catch (FileNotFoundException e) {
callback.onFileTransferAborted();
} catch (IOException e) {
callback.onFileTransferAborted();
} catch (NoSuchAlgorithmException e) {
callback.onFileTransferAborted();
}
}
}).start();
}
public boolean isProxy() {
2014-04-17 14:52:10 +02:00
return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
}
2014-08-31 16:28:21 +02:00
2014-04-23 21:19:56 +02:00
public boolean needsActivation() {
return (this.isProxy() && !this.activated);
}
public void disconnect() {
2014-08-31 16:28:21 +02:00
if (this.socket != null) {
try {
this.socket.close();
} catch (IOException e) {
2014-08-31 16:28:21 +02:00
}
}
}
2014-08-31 16:28:21 +02:00
public boolean isEstablished() {
return this.isEstablished;
}
2014-08-31 16:28:21 +02:00
2014-04-17 14:52:10 +02:00
public JingleCandidate getCandidate() {
return this.candidate;
}
2014-04-23 21:19:56 +02:00
public void setActivated(boolean activated) {
this.activated = activated;
}
}