From aa5f775fc79ca7b1912c9d7fba759e7efb09fa2b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 22 Apr 2014 13:11:53 +0200 Subject: added support for ibb --- .../xmpp/jingle/JingleConnection.java | 113 +++++++++-- .../xmpp/jingle/JingleConnectionManager.java | 27 +++ .../xmpp/jingle/JingleInbandTransport.java | 183 ++++++++++++++++++ .../xmpp/jingle/JingleSocks5Transport.java | 206 +++++++++++++++++++++ .../conversations/xmpp/jingle/JingleTransport.java | 3 + .../xmpp/jingle/OnSocksConnection.java | 6 - .../xmpp/jingle/OnTransportConnected.java | 6 + .../conversations/xmpp/jingle/SocksConnection.java | 206 --------------------- 8 files changed, 519 insertions(+), 231 deletions(-) create mode 100644 src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java create mode 100644 src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java delete mode 100644 src/eu/siacs/conversations/xmpp/jingle/OnSocksConnection.java create mode 100644 src/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java delete mode 100644 src/eu/siacs/conversations/xmpp/jingle/SocksConnection.java (limited to 'src/eu/siacs/conversations/xmpp') diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 75cc94e1..81c17d4c 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -32,6 +32,8 @@ public class JingleConnection { public static final int STATUS_TRANSMITTING = 5; public static final int STATUS_FAILED = 99; + private int ibbBlockSize = 4096; + private int status = -1; private Message message; private String sessionId; @@ -39,7 +41,7 @@ public class JingleConnection { private String initiator; private String responder; private List candidates = new ArrayList(); - private HashMap connections = new HashMap(); + private HashMap connections = new HashMap(); private String transportId; private Element fileOffer; @@ -126,7 +128,15 @@ public class JingleConnection { } else if (packet.isAction("session-accept")) { accept(packet); } else if (packet.isAction("transport-info")) { - transportInfo(packet); + receiveTransportInfo(packet); + } else if (packet.isAction("transport-replace")) { + if (packet.getJingleContent().hasIbbTransport()) { + this.receiveFallbackToIbb(packet); + } else { + Log.d("xmppService","trying to fallback to something unknown"+packet.toString()); + } + } else if (packet.isAction("transport-accept")) { + this.receiveTransportAccept(packet); } else { Log.d("xmppService","packet arrived in connection. action was "+packet.getAction()); } @@ -146,9 +156,9 @@ public class JingleConnection { @Override public void onPrimaryCandidateFound(boolean success, final JingleCandidate candidate) { if (success) { - final SocksConnection socksConnection = new SocksConnection(JingleConnection.this, candidate); + final JingleSocks5Transport socksConnection = new JingleSocks5Transport(JingleConnection.this, candidate); connections.put(candidate.getCid(), socksConnection); - socksConnection.connect(new OnSocksConnection() { + socksConnection.connect(new OnTransportConnected() { @Override public void failed() { @@ -248,9 +258,9 @@ public class JingleConnection { content.setFileOffer(fileOffer); content.setTransportId(transportId); if ((success)&&(!equalCandidateExists(candidate))) { - final SocksConnection socksConnection = new SocksConnection(JingleConnection.this, candidate); + final JingleSocks5Transport socksConnection = new JingleSocks5Transport(JingleConnection.this, candidate); connections.put(candidate.getCid(), socksConnection); - socksConnection.connect(new OnSocksConnection() { + socksConnection.connect(new OnTransportConnected() { @Override public void failed() { @@ -307,7 +317,7 @@ public class JingleConnection { account.getXmppConnection().sendIqPacket(response, null); } - private void transportInfo(JinglePacket packet) { + private void receiveTransportInfo(JinglePacket packet) { Content content = packet.getJingleContent(); if (content.hasSocks5Transport()) { if (content.socks5transport().hasChild("activated")) { @@ -345,13 +355,14 @@ public class JingleConnection { } private void connect() { - final SocksConnection connection = chooseConnection(); + final JingleSocks5Transport connection = chooseConnection(); this.transport = connection; if (connection==null) { Log.d("xmppService","could not find suitable candidate"); this.disconnect(); - this.status = STATUS_FAILED; - this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_FAILED); + if (this.initiator.equals(account.getFullJid())) { + this.sendFallbackToIbb(); + } } else { this.status = STATUS_TRANSMITTING; if (connection.isProxy()) { @@ -386,12 +397,12 @@ public class JingleConnection { } } - private SocksConnection chooseConnection() { - SocksConnection connection = null; - Iterator> it = this.connections.entrySet().iterator(); + private JingleSocks5Transport chooseConnection() { + JingleSocks5Transport connection = null; + Iterator> it = this.connections.entrySet().iterator(); while (it.hasNext()) { - Entry pairs = it.next(); - SocksConnection currentConnection = pairs.getValue(); + Entry pairs = it.next(); + JingleSocks5Transport currentConnection = pairs.getValue(); //Log.d("xmppService","comparing candidate: "+currentConnection.getCandidate().toString()); if (currentConnection.isEstablished()&&(currentConnection.getCandidate().isUsedByCounterpart()||(!currentConnection.getCandidate().isOurs()))) { //Log.d("xmppService","is usable"); @@ -430,6 +441,62 @@ public class JingleConnection { this.mXmppConnectionService.markMessage(this.message, Message.STATUS_RECIEVED); } + private void sendFallbackToIbb() { + JinglePacket packet = this.bootstrapPacket("transport-replace"); + Content content = new Content("initiator","a-file-offer"); + this.transportId = this.mJingleConnectionManager.nextRandomId(); + content.setTransportId(this.transportId); + content.ibbTransport().setAttribute("block-size",""+this.ibbBlockSize); + packet.setContent(content); + this.sendJinglePacket(packet); + } + + private void receiveFallbackToIbb(JinglePacket packet) { + String receivedBlockSize = packet.getJingleContent().ibbTransport().getAttribute("block-size"); + if (receivedBlockSize!=null) { + int bs = Integer.parseInt(receivedBlockSize); + if (bs>this.ibbBlockSize) { + this.ibbBlockSize = bs; + } + } + this.transportId = packet.getJingleContent().getTransportId(); + this.transport = new JingleInbandTransport(this.account,this.responder,this.transportId,this.ibbBlockSize); + this.transport.receive(file, onFileTransmitted); + JinglePacket answer = bootstrapPacket("transport-accept"); + Content content = new Content("initiator", "a-file-offer"); + content.setTransportId(this.transportId); + content.ibbTransport().setAttribute("block-size", ""+this.ibbBlockSize); + answer.setContent(content); + this.sendJinglePacket(answer); + } + + private void receiveTransportAccept(JinglePacket packet) { + if (packet.getJingleContent().hasIbbTransport()) { + String receivedBlockSize = packet.getJingleContent().ibbTransport().getAttribute("block-size"); + if (receivedBlockSize!=null) { + int bs = Integer.parseInt(receivedBlockSize); + if (bs>this.ibbBlockSize) { + this.ibbBlockSize = bs; + } + } + this.transport = new JingleInbandTransport(this.account,this.responder,this.transportId,this.ibbBlockSize); + this.transport.connect(new OnTransportConnected() { + + @Override + public void failed() { + Log.d("xmppService","ibb open failed"); + } + + @Override + public void established() { + JingleConnection.this.transport.send(file, onFileTransmitted); + } + }); + } else { + Log.d("xmppService","invalid transport accept"); + } + } + private void finish() { this.status = STATUS_FINISHED; this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND); @@ -453,9 +520,9 @@ public class JingleConnection { } private void connectWithCandidate(final JingleCandidate candidate) { - final SocksConnection socksConnection = new SocksConnection(this,candidate); + final JingleSocks5Transport socksConnection = new JingleSocks5Transport(this,candidate); connections.put(candidate.getCid(), socksConnection); - socksConnection.connect(new OnSocksConnection() { + socksConnection.connect(new OnTransportConnected() { @Override public void failed() { @@ -472,9 +539,9 @@ public class JingleConnection { } private void disconnect() { - Iterator> it = this.connections.entrySet().iterator(); + Iterator> it = this.connections.entrySet().iterator(); while (it.hasNext()) { - Entry pairs = it.next(); + Entry pairs = it.next(); pairs.getValue().disconnect(); it.remove(); } @@ -564,4 +631,12 @@ public class JingleConnection { public void success(); public void failed(); } + + public boolean hasTransportId(String sid) { + return sid.equals(this.transportId); + } + + public JingleTransport getTransport() { + return this.transport; + } } diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index b5b92554..0a805afd 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -124,4 +124,31 @@ public class JingleConnectionManager { return 524288; } } + + public void deliverIbbPacket(Account account, IqPacket packet) { + String sid = null; + Element payload = null; + if (packet.hasChild("open","http://jabber.org/protocol/ibb")) { + payload = packet.findChild("open","http://jabber.org/protocol/ibb"); + sid = payload.getAttribute("sid"); + } else if (packet.hasChild("data","http://jabber.org/protocol/ibb")) { + payload = packet.findChild("data","http://jabber.org/protocol/ibb"); + sid = payload.getAttribute("sid"); + } + if (sid!=null) { + for (JingleConnection connection : connections) { + if (connection.hasTransportId(sid)) { + JingleTransport transport = connection.getTransport(); + if (transport instanceof JingleInbandTransport) { + JingleInbandTransport inbandTransport = (JingleInbandTransport) transport; + inbandTransport.deliverPayload(packet,payload); + return; + } + } + } + Log.d("xmppService","couldnt deliver payload: "+payload.toString()); + } else { + Log.d("xmppService","no sid found in incomming ibb packet"); + } + } } diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java new file mode 100644 index 00000000..c963136d --- /dev/null +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -0,0 +1,183 @@ +package eu.siacs.conversations.xmpp.jingle; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import android.util.Base64; +import android.util.Log; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.utils.CryptoHelper; +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.OnIqPacketReceived; +import eu.siacs.conversations.xmpp.PacketReceived; +import eu.siacs.conversations.xmpp.stanzas.IqPacket; + +public class JingleInbandTransport extends JingleTransport { + + private Account account; + private String counterpart; + private int blockSize; + private int bufferSize; + private int seq = 0; + private String sessionId; + + private boolean established = false; + + private JingleFile file; + + private FileInputStream fileInputStream = null; + private FileOutputStream fileOutputStream; + private long remainingSize; + private MessageDigest digest; + + private OnFileTransmitted onFileTransmitted; + + private OnIqPacketReceived onAckReceived = new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + Log.d("xmppService", "on ack received"); + if (packet.getType() == IqPacket.TYPE_RESULT) { + sendNextBlock(); + } + } + }; + + public JingleInbandTransport(Account account, String counterpart, + String sid, int blocksize) { + this.account = account; + this.counterpart = counterpart; + this.blockSize = blocksize; + this.bufferSize = blocksize / 4; + this.sessionId = sid; + } + + public void connect(final OnTransportConnected callback) { + IqPacket iq = new IqPacket(IqPacket.TYPE_SET); + iq.setTo(this.counterpart); + Element open = iq.addChild("open", "http://jabber.org/protocol/ibb"); + open.setAttribute("sid", this.sessionId); + open.setAttribute("stanza", "iq"); + open.setAttribute("block-size", "" + this.blockSize); + + this.account.getXmppConnection().sendIqPacket(iq, + new OnIqPacketReceived() { + + @Override + public void onIqPacketReceived(Account account, + IqPacket packet) { + if (packet.getType() == IqPacket.TYPE_ERROR) { + callback.failed(); + } else { + callback.established(); + } + } + }); + } + + @Override + public void receive(JingleFile file, OnFileTransmitted callback) { + this.onFileTransmitted = callback; + this.file = file; + Log.d("xmppService", "receiving file over ibb"); + try { + this.digest = MessageDigest.getInstance("SHA-1"); + digest.reset(); + file.getParentFile().mkdirs(); + file.createNewFile(); + this.fileOutputStream = new FileOutputStream(file); + this.remainingSize = file.getExpectedSize(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void send(JingleFile file, OnFileTransmitted callback) { + this.onFileTransmitted = callback; + this.file = file; + Log.d("xmppService", "sending file over ibb"); + try { + this.digest = MessageDigest.getInstance("SHA-1"); + this.digest.reset(); + fileInputStream = new FileInputStream(file); + this.sendNextBlock(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + + private void sendNextBlock() { + byte[] buffer = new byte[this.bufferSize]; + try { + int count = fileInputStream.read(buffer); + if (count==-1) { + file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); + this.onFileTransmitted.onFileTransmitted(file); + } else { + this.digest.update(buffer); + String base64 = Base64.encodeToString(buffer, Base64.DEFAULT); + IqPacket iq = new IqPacket(IqPacket.TYPE_SET); + iq.setTo(this.counterpart); + Element data = iq + .addChild("data", "http://jabber.org/protocol/ibb"); + data.setAttribute("seq", "" + this.seq); + data.setAttribute("block-size", "" + this.blockSize); + data.setAttribute("sid", this.sessionId); + data.setContent(base64); + this.account.getXmppConnection().sendIqPacket(iq, + this.onAckReceived); + this.seq++; + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private void receiveNextBlock(String data) { + try { + byte[] buffer = Base64.decode(data, Base64.DEFAULT); + this.remainingSize -= buffer.length; + + this.fileOutputStream.write(buffer); + + this.digest.update(buffer); + Log.d("xmppService", "remaining file size:" + this.remainingSize); + if (this.remainingSize <= 0) { + file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); + Log.d("xmppService","file name: "+file.getAbsolutePath()); + fileOutputStream.flush(); + this.onFileTransmitted.onFileTransmitted(file); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void deliverPayload(IqPacket packet, Element payload) { + if (payload.getName().equals("open")) { + if (!established) { + established = true; + this.account.getXmppConnection().sendIqPacket( + packet.generateRespone(IqPacket.TYPE_RESULT), null); + } else { + this.account.getXmppConnection().sendIqPacket( + packet.generateRespone(IqPacket.TYPE_ERROR), null); + } + } else if (payload.getName().equals("data")) { + this.receiveNextBlock(payload.getContent()); + this.account.getXmppConnection().sendIqPacket( + packet.generateRespone(IqPacket.TYPE_RESULT), null); + } else { + Log.d("xmppServic","couldnt deliver payload "+packet.toString()); + } + } +} diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java new file mode 100644 index 00000000..f37d5a71 --- /dev/null +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -0,0 +1,206 @@ +package eu.siacs.conversations.xmpp.jingle; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +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; +import eu.siacs.conversations.xml.Element; + +import android.util.Log; +import android.widget.Button; + +public class JingleSocks5Transport extends JingleTransport { + private JingleCandidate candidate; + private String destination; + private OutputStream outputStream; + private InputStream inputStream; + private boolean isEstablished = false; + protected Socket socket; + + public JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) { + this.candidate = candidate; + try { + MessageDigest mDigest = MessageDigest.getInstance("SHA-1"); + StringBuilder destBuilder = new StringBuilder(); + destBuilder.append(jingleConnection.getSessionId()); + if (candidate.isOurs()) { + 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) { + + } + } + + public void connect(final OnTransportConnected callback) { + new Thread(new Runnable() { + + @Override + public void run() { + try { + 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)) { + 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(); + + } + + public void send(final JingleFile file, final OnFileTransmitted callback) { + new Thread(new Runnable() { + + @Override + public void run() { + FileInputStream fileInputStream = null; + try { + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + digest.reset(); + fileInputStream = new FileInputStream(file); + int count; + byte[] buffer = new byte[8192]; + while ((count = fileInputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, count); + digest.update(buffer, 0, count); + } + 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) { + // TODO Auto-generated catch block + e.printStackTrace(); + } 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(); + } + } + } + }).start(); + + } + + 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(); + FileOutputStream fileOutputStream = new FileOutputStream(file); + long remainingSize = file.getExpectedSize(); + byte[] buffer = new byte[8192]; + int count = buffer.length; + while(remainingSize > 0) { + Log.d("xmppService","remaning size:"+remainingSize); + if (remainingSize<=count) { + count = (int) remainingSize; + } + count = inputStream.read(buffer, 0, count); + if (count==-1) { + Log.d("xmppService","end of stream"); + } else { + fileOutputStream.write(buffer, 0, count); + digest.update(buffer, 0, count); + remainingSize-=count; + } + } + fileOutputStream.flush(); + fileOutputStream.close(); + file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); + Log.d("xmppService","transmitted filename was: "+file.getAbsolutePath()); + callback.onFileTransmitted(file); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }).start(); + } + + public boolean isProxy() { + return this.candidate.getType() == JingleCandidate.TYPE_PROXY; + } + + public void disconnect() { + if (this.socket!=null) { + try { + this.socket.close(); + Log.d("xmppService","cloesd socket with "+candidate.getHost()+":"+candidate.getPort()); + } catch (IOException e) { + Log.d("xmppService","error closing socket with "+candidate.getHost()+":"+candidate.getPort()); + } + } + } + + public boolean isEstablished() { + return this.isEstablished; + } + + public JingleCandidate getCandidate() { + return this.candidate; + } +} diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java index 347824f1..6e9482a9 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java @@ -1,6 +1,9 @@ package eu.siacs.conversations.xmpp.jingle; +import eu.siacs.conversations.xml.Element; + public abstract class JingleTransport { + public abstract void connect(final OnTransportConnected callback); public abstract void receive(final JingleFile file, final OnFileTransmitted callback); public abstract void send(final JingleFile file, final OnFileTransmitted callback); } diff --git a/src/eu/siacs/conversations/xmpp/jingle/OnSocksConnection.java b/src/eu/siacs/conversations/xmpp/jingle/OnSocksConnection.java deleted file mode 100644 index 88771997..00000000 --- a/src/eu/siacs/conversations/xmpp/jingle/OnSocksConnection.java +++ /dev/null @@ -1,6 +0,0 @@ -package eu.siacs.conversations.xmpp.jingle; - -public interface OnSocksConnection { - public void failed(); - public void established(); -} diff --git a/src/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java b/src/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java new file mode 100644 index 00000000..7d9a084a --- /dev/null +++ b/src/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java @@ -0,0 +1,6 @@ +package eu.siacs.conversations.xmpp.jingle; + +public interface OnTransportConnected { + public void failed(); + public void established(); +} diff --git a/src/eu/siacs/conversations/xmpp/jingle/SocksConnection.java b/src/eu/siacs/conversations/xmpp/jingle/SocksConnection.java deleted file mode 100644 index 1a945a65..00000000 --- a/src/eu/siacs/conversations/xmpp/jingle/SocksConnection.java +++ /dev/null @@ -1,206 +0,0 @@ -package eu.siacs.conversations.xmpp.jingle; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -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; -import eu.siacs.conversations.xml.Element; - -import android.util.Log; -import android.widget.Button; - -public class SocksConnection extends JingleTransport { - private JingleCandidate candidate; - private String destination; - private OutputStream outputStream; - private InputStream inputStream; - private boolean isEstablished = false; - protected Socket socket; - - public SocksConnection(JingleConnection jingleConnection, JingleCandidate candidate) { - this.candidate = candidate; - try { - MessageDigest mDigest = MessageDigest.getInstance("SHA-1"); - StringBuilder destBuilder = new StringBuilder(); - destBuilder.append(jingleConnection.getSessionId()); - if (candidate.isOurs()) { - 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) { - - } - } - - public void connect(final OnSocksConnection callback) { - new Thread(new Runnable() { - - @Override - public void run() { - try { - 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)) { - 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(); - - } - - public void send(final JingleFile file, final OnFileTransmitted callback) { - new Thread(new Runnable() { - - @Override - public void run() { - FileInputStream fileInputStream = null; - try { - MessageDigest digest = MessageDigest.getInstance("SHA-1"); - digest.reset(); - fileInputStream = new FileInputStream(file); - int count; - byte[] buffer = new byte[8192]; - while ((count = fileInputStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, count); - digest.update(buffer, 0, count); - } - 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) { - // TODO Auto-generated catch block - e.printStackTrace(); - } 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(); - } - } - } - }).start(); - - } - - 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(); - FileOutputStream fileOutputStream = new FileOutputStream(file); - long remainingSize = file.getExpectedSize(); - byte[] buffer = new byte[8192]; - int count = buffer.length; - while(remainingSize > 0) { - Log.d("xmppService","remaning size:"+remainingSize); - if (remainingSize<=count) { - count = (int) remainingSize; - } - count = inputStream.read(buffer, 0, count); - if (count==-1) { - Log.d("xmppService","end of stream"); - } else { - fileOutputStream.write(buffer, 0, count); - digest.update(buffer, 0, count); - remainingSize-=count; - } - } - fileOutputStream.flush(); - fileOutputStream.close(); - file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); - Log.d("xmppService","transmitted filename was: "+file.getAbsolutePath()); - callback.onFileTransmitted(file); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - }).start(); - } - - public boolean isProxy() { - return this.candidate.getType() == JingleCandidate.TYPE_PROXY; - } - - public void disconnect() { - if (this.socket!=null) { - try { - this.socket.close(); - Log.d("xmppService","cloesd socket with "+candidate.getHost()+":"+candidate.getPort()); - } catch (IOException e) { - Log.d("xmppService","error closing socket with "+candidate.getHost()+":"+candidate.getPort()); - } - } - } - - public boolean isEstablished() { - return this.isEstablished; - } - - public JingleCandidate getCandidate() { - return this.candidate; - } -} -- cgit v1.2.3