diff options
Diffstat (limited to 'src/eu/siacs/conversations/xmpp/jingle')
7 files changed, 193 insertions, 58 deletions
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 31b643c0..c5b7b60c 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -1,19 +1,23 @@ package eu.siacs.conversations.xmpp.jingle; -import java.io.File; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import android.util.Log; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.jingle.stanzas.Content; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; +import eu.siacs.conversations.xmpp.jingle.stanzas.Reason; import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class JingleConnection { @@ -24,6 +28,8 @@ public class JingleConnection { public static final int STATUS_INITIATED = 0; public static final int STATUS_ACCEPTED = 1; public static final int STATUS_TERMINATED = 2; + public static final int STATUS_CANCELED = 3; + public static final int STATUS_FINISHED = 4; public static final int STATUS_FAILED = 99; private int status = -1; @@ -34,7 +40,7 @@ public class JingleConnection { private String responder; private List<Element> candidates = new ArrayList<Element>(); private HashMap<String, SocksConnection> connections = new HashMap<String, SocksConnection>(); - private File file = null; + private JingleFile file = null; private OnIqPacketReceived responseListener = new OnIqPacketReceived() { @@ -50,7 +56,6 @@ public class JingleConnection { public JingleConnection(JingleConnectionManager mJingleConnectionManager) { this.mJingleConnectionManager = mJingleConnectionManager; this.mXmppConnectionService = mJingleConnectionManager.getXmppConnectionService(); - this.sessionId = this.mJingleConnectionManager.nextRandomId(); } public String getSessionId() { @@ -68,10 +73,12 @@ public class JingleConnection { public void deliverPacket(JinglePacket packet) { if (packet.isAction("session-terminate")) { - if (status == STATUS_INITIATED) { - mXmppConnectionService.markMessage(message, Message.STATUS_SEND_REJECTED); + Reason reason = packet.getReason(); + if (reason.hasChild("cancel")) { + this.cancel(); + } else if (reason.hasChild("success")) { + this.finish(); } - status = STATUS_TERMINATED; } else if (packet.isAction("session-accept")) { accept(packet); } else if (packet.isAction("transport-info")) { @@ -86,6 +93,7 @@ public class JingleConnection { this.account = message.getConversation().getAccount(); this.initiator = this.account.getFullJid(); this.responder = this.message.getCounterpart(); + this.sessionId = this.mJingleConnectionManager.nextRandomId(); if (this.candidates.size() > 0) { this.sendInitRequest(); } else { @@ -103,6 +111,19 @@ public class JingleConnection { } + public void init(Account account, JinglePacket packet) { + Conversation conversation = this.mXmppConnectionService.findOrCreateConversation(account, packet.getFrom().split("/")[0], false); + this.message = new Message(conversation, "receiving image file", Message.ENCRYPTION_NONE); + this.message.setType(Message.TYPE_IMAGE); + this.message.setStatus(Message.STATUS_RECIEVING); + this.account = account; + this.initiator = packet.getFrom(); + this.responder = this.account.getFullJid(); + this.sessionId = packet.getSessionId(); + this.candidates.addAll(packet.getJingleContent().getCanditates()); + Log.d("xmppService","new incomming jingle session "+this.sessionId+" num canditaes:"+this.candidates.size()); + } + private void sendInitRequest() { JinglePacket packet = this.bootstrapPacket(); packet.setAction("session-initiate"); @@ -145,8 +166,16 @@ public class JingleConnection { Log.d("xmppService","transport info : "+content.toString()); String cid = content.getUsedCandidate(); if (cid!=null) { - final File file = this.mXmppConnectionService.getFileBackend().getImageFile(this.message); + final JingleFile file = this.mXmppConnectionService.getFileBackend().getImageFile(this.message); final SocksConnection connection = this.connections.get(cid); + final OnFileTransmitted callback = new OnFileTransmitted() { + + @Override + public void onFileTransmitted(JingleFile file) { + Log.d("xmppService","sucessfully transmitted file. sha1:"+file.getSha1Sum()); + } + }; + final IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT); if (connection.isProxy()) { IqPacket activation = new IqPacket(IqPacket.TYPE_SET); activation.setTo(connection.getJid()); @@ -157,16 +186,30 @@ public class JingleConnection { @Override public void onIqPacketReceived(Account account, IqPacket packet) { + account.getXmppConnection().sendIqPacket(response, null); Log.d("xmppService","activation result: "+packet.toString()); - connection.send(file); + connection.send(file,callback); } }); } else { - connection.send(file); + account.getXmppConnection().sendIqPacket(response, null); + connection.send(file,callback); } } } + private void finish() { + this.status = STATUS_FINISHED; + this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND); + this.disconnect(); + } + + public void cancel() { + this.disconnect(); + this.status = STATUS_CANCELED; + this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_REJECTED); + } + private void connectWithCandidates() { for(Element canditate : this.candidates) { String host = canditate.getAttribute("host"); @@ -179,6 +222,15 @@ public class JingleConnection { } } + private void disconnect() { + Iterator<Entry<String, SocksConnection>> it = this.connections.entrySet().iterator(); + while (it.hasNext()) { + Entry<String, SocksConnection> pairs = it.next(); + pairs.getValue().disconnect(); + it.remove(); + } + } + private void sendCandidateUsed(String cid) { } @@ -190,4 +242,8 @@ public class JingleConnection { public String getResponder() { return this.responder; } + + public int getStatus() { + return this.status; + } } diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index 89ff717d..45323e44 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -32,15 +32,20 @@ public class JingleConnectionManager { } public void deliverPacket(Account account, JinglePacket packet) { - for (JingleConnection connection : connections) { - if (connection.getAccountJid().equals(account.getJid()) && connection - .getSessionId().equals(packet.getSessionId()) && connection - .getCounterPart().equals(packet.getFrom())) { - connection.deliverPacket(packet); - return; + if (packet.isAction("session-initiate")) { + JingleConnection connection = new JingleConnection(this); + connection.init(account,packet); + } else { + for (JingleConnection connection : connections) { + if (connection.getAccountJid().equals(account.getJid()) && connection + .getSessionId().equals(packet.getSessionId()) && connection + .getCounterPart().equals(packet.getFrom())) { + connection.deliverPacket(packet); + return; + } } + Log.d("xmppService","delivering packet failed "+packet.toString()); } - Log.d("xmppService","delivering packet failed "+packet.toString()); } public JingleConnection createNewConnection(Message message) { diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java b/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java new file mode 100644 index 00000000..21cbd716 --- /dev/null +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java @@ -0,0 +1,35 @@ +package eu.siacs.conversations.xmpp.jingle; + +import java.io.File; + +public class JingleFile extends File { + + private static final long serialVersionUID = 2247012619505115863L; + + private long expectedSize = 0; + private String sha1sum; + + public JingleFile(String path) { + super(path); + } + + public long getSize() { + return super.length(); + } + + public long getExpectedSize() { + return this.expectedSize; + } + + public void setExpectedSize(long size) { + this.expectedSize = size; + } + + public String getSha1Sum() { + return this.sha1sum; + } + + public void setSha1Sum(String sum) { + this.sha1sum = sum; + } +} diff --git a/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmitted.java b/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmitted.java new file mode 100644 index 00000000..fd5fd2f7 --- /dev/null +++ b/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmitted.java @@ -0,0 +1,5 @@ +package eu.siacs.conversations.xmpp.jingle; + +public interface OnFileTransmitted { + public void onFileTransmitted(JingleFile file); +} diff --git a/src/eu/siacs/conversations/xmpp/jingle/SocksConnection.java b/src/eu/siacs/conversations/xmpp/jingle/SocksConnection.java index c1219ff7..6a3a3648 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/SocksConnection.java +++ b/src/eu/siacs/conversations/xmpp/jingle/SocksConnection.java @@ -1,6 +1,5 @@ package eu.siacs.conversations.xmpp.jingle; -import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -17,7 +16,7 @@ import eu.siacs.conversations.utils.CryptoHelper; import android.util.Log; public class SocksConnection { - + private JingleConnection jingleConnection; private Socket socket; private String host; @@ -26,8 +25,9 @@ public class SocksConnection { private boolean isProxy = false; private String destination; private OutputStream outputStream; - - public SocksConnection(JingleConnection jingleConnection, String host, String jid, int port, String type) { + + public SocksConnection(JingleConnection jingleConnection, String host, + String jid, int port, String type) { this.jingleConnection = jingleConnection; this.host = host; this.jid = jid; @@ -40,30 +40,33 @@ public class SocksConnection { destBuilder.append(jingleConnection.getInitiator()); destBuilder.append(jingleConnection.getResponder()); mDigest.reset(); - this.destination = CryptoHelper.bytesToHex(mDigest.digest(destBuilder.toString().getBytes())); - Log.d("xmppService","host="+host+", port="+port+", destination: "+destination); + this.destination = CryptoHelper.bytesToHex(mDigest + .digest(destBuilder.toString().getBytes())); + Log.d("xmppService", "host=" + host + ", port=" + port + + ", destination: " + destination); } catch (NoSuchAlgorithmException e) { - + } } - + public boolean connect() { try { this.socket = new Socket(this.host, this.port); InputStream is = socket.getInputStream(); this.outputStream = socket.getOutputStream(); - byte[] login = {0x05, 0x01, 0x00}; - byte[] expectedReply = {0x05,0x00}; + byte[] login = { 0x05, 0x01, 0x00 }; + byte[] expectedReply = { 0x05, 0x00 }; byte[] reply = new byte[2]; this.outputStream.write(login); is.read(reply); if (Arrays.equals(reply, expectedReply)) { - String connect = ""+'\u0005'+'\u0001'+'\u0000'+'\u0003'+'\u0028'+this.destination+'\u0000'+'\u0000'; + String connect = "" + '\u0005' + '\u0001' + '\u0000' + '\u0003' + + '\u0028' + this.destination + '\u0000' + '\u0000'; this.outputStream.write(connect.getBytes()); byte[] result = new byte[2]; is.read(result); int status = result[0]; - return (status==0); + return (status == 0); } else { socket.close(); return false; @@ -75,39 +78,67 @@ public class SocksConnection { } } - public void send(File file) { - FileInputStream fileInputStream = null; - try { - fileInputStream = new FileInputStream(file); - int count; - byte[] buffer = new byte[8192]; - while ((count = fileInputStream.read(buffer)) > 0) { - this.outputStream.write(buffer, 0, count); - } - - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } finally { - try { - if (fileInputStream!=null) { - fileInputStream.close(); + 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(); + } } - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } - } + }).start(); + } - + public boolean isProxy() { return this.isProxy; } - + public String getJid() { return this.jid; } + + public void disconnect() { + if (this.socket!=null) { + try { + this.socket.close(); + Log.d("xmppService","cloesd socket with "+this.host); + } catch (IOException e) { + Log.d("xmppService","error closing socket with "+this.host); + } + } + } } diff --git a/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java b/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java index 304656ee..cefcde36 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java +++ b/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java @@ -1,10 +1,10 @@ package eu.siacs.conversations.xmpp.jingle.stanzas; -import java.io.File; import java.util.ArrayList; import java.util.List; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.jingle.JingleFile; public class Content extends Element { private Content(String name) { @@ -15,13 +15,12 @@ public class Content extends Element { super("content"); } - public void offerFile(File actualFile, String hash) { + public void offerFile(JingleFile actualFile, String hash) { Element description = this.addChild("description", "urn:xmpp:jingle:apps:file-transfer:3"); Element offer = description.addChild("offer"); Element file = offer.addChild("file"); - file.addChild("size").setContent(""+actualFile.length()); + file.addChild("size").setContent(""+actualFile.getSize()); file.addChild("name").setContent(actualFile.getName()); - file.addChild("hash","urn:xmpp:hashes:1").setAttribute("algo", "sha-1").setContent(hash); } public void setCandidates(String transportId, List<Element> canditates) { diff --git a/src/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java b/src/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java index 83f0aec6..55700609 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java +++ b/src/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java @@ -45,6 +45,10 @@ public class JinglePacket extends IqPacket { return this; } + public Reason getReason() { + return this.reason; + } + private void build() { this.children.clear(); this.jingle.clearChildren(); |