added proxy activate and a lot of code clean up. totatly untested

This commit is contained in:
Daniel Gultsch 2014-04-20 22:34:27 +02:00
parent 04418484a2
commit 4d730fd1ed
5 changed files with 168 additions and 152 deletions

View file

@ -48,6 +48,8 @@ public class JingleConnection {
private boolean receivedCandidate = false; private boolean receivedCandidate = false;
private boolean sentCandidate = false; private boolean sentCandidate = false;
private JingleTransport transport = null;
private OnIqPacketReceived responseListener = new OnIqPacketReceived() { private OnIqPacketReceived responseListener = new OnIqPacketReceived() {
@Override @Override
@ -59,6 +61,37 @@ public class JingleConnection {
} }
}; };
final OnFileTransmitted onFileTransmitted = new OnFileTransmitted() {
@Override
public void onFileTransmitted(JingleFile file) {
if (responder.equals(account.getFullJid())) {
sendSuccess();
mXmppConnectionService.markMessage(message, Message.STATUS_RECIEVED);
}
Log.d("xmppService","sucessfully transmitted file. sha1:"+file.getSha1Sum());
}
};
private OnProxyActivated onProxyActivated = new OnProxyActivated() {
@Override
public void success() {
if (initiator.equals(account.getFullJid())) {
Log.d("xmppService","we were initiating. sending file");
transport.send(file,onFileTransmitted);
} else {
transport.receive(file,onFileTransmitted);
Log.d("xmppService","we were responding. receiving file");
}
}
@Override
public void failed() {
Log.d("xmppService","proxy activation failed");
}
};
public JingleConnection(JingleConnectionManager mJingleConnectionManager) { public JingleConnection(JingleConnectionManager mJingleConnectionManager) {
this.mJingleConnectionManager = mJingleConnectionManager; this.mJingleConnectionManager = mJingleConnectionManager;
this.mXmppConnectionService = mJingleConnectionManager.getXmppConnectionService(); this.mXmppConnectionService = mJingleConnectionManager.getXmppConnectionService();
@ -155,7 +188,7 @@ public class JingleConnection {
this.sessionId = packet.getSessionId(); this.sessionId = packet.getSessionId();
Content content = packet.getJingleContent(); Content content = packet.getJingleContent();
this.transportId = content.getTransportId(); this.transportId = content.getTransportId();
this.mergeCandidates(JingleCandidate.parse(content.getCanditates())); this.mergeCandidates(JingleCandidate.parse(content.socks5transport().getChildren()));
this.fileOffer = packet.getJingleContent().getFileOffer(); this.fileOffer = packet.getJingleContent().getFileOffer();
if (fileOffer!=null) { if (fileOffer!=null) {
this.file = this.mXmppConnectionService.getFileBackend().getJingleFile(message); this.file = this.mXmppConnectionService.getFileBackend().getJingleFile(message);
@ -184,10 +217,11 @@ public class JingleConnection {
if (message.getType() == Message.TYPE_IMAGE) { if (message.getType() == Message.TYPE_IMAGE) {
content.setAttribute("creator", "initiator"); content.setAttribute("creator", "initiator");
content.setAttribute("name", "a-file-offer"); content.setAttribute("name", "a-file-offer");
content.setTransportId(this.transportId);
this.file = this.mXmppConnectionService.getFileBackend().getJingleFile(message); this.file = this.mXmppConnectionService.getFileBackend().getJingleFile(message);
content.setFileOffer(this.file); content.setFileOffer(this.file);
this.transportId = this.mJingleConnectionManager.nextRandomId(); this.transportId = this.mJingleConnectionManager.nextRandomId();
content.setCandidates(this.transportId,getCandidatesAsElements()); content.socks5transport().setChildren(getCandidatesAsElements());
packet.setContent(content); packet.setContent(content);
this.sendJinglePacket(packet); this.sendJinglePacket(packet);
this.status = STATUS_INITIATED; this.status = STATUS_INITIATED;
@ -212,6 +246,7 @@ public class JingleConnection {
final JinglePacket packet = bootstrapPacket("session-accept"); final JinglePacket packet = bootstrapPacket("session-accept");
final Content content = new Content(); final Content content = new Content();
content.setFileOffer(fileOffer); content.setFileOffer(fileOffer);
content.setTransportId(transportId);
if ((success)&&(!equalCandidateExists(candidate))) { if ((success)&&(!equalCandidateExists(candidate))) {
final SocksConnection socksConnection = new SocksConnection(JingleConnection.this, candidate); final SocksConnection socksConnection = new SocksConnection(JingleConnection.this, candidate);
connections.put(candidate.getCid(), socksConnection); connections.put(candidate.getCid(), socksConnection);
@ -220,7 +255,7 @@ public class JingleConnection {
@Override @Override
public void failed() { public void failed() {
Log.d("xmppService","connection to our own primary candidate failed"); Log.d("xmppService","connection to our own primary candidate failed");
content.setCandidates(transportId, getCandidatesAsElements()); content.socks5transport().setChildren(getCandidatesAsElements());
packet.setContent(content); packet.setContent(content);
sendJinglePacket(packet); sendJinglePacket(packet);
} }
@ -229,14 +264,14 @@ public class JingleConnection {
public void established() { public void established() {
Log.d("xmppService","connected to primary candidate"); Log.d("xmppService","connected to primary candidate");
mergeCandidate(candidate); mergeCandidate(candidate);
content.setCandidates(transportId, getCandidatesAsElements()); content.socks5transport().setChildren(getCandidatesAsElements());
packet.setContent(content); packet.setContent(content);
sendJinglePacket(packet); sendJinglePacket(packet);
} }
}); });
} else { } else {
Log.d("xmppService","did not find a primary candidate for ourself"); Log.d("xmppService","did not find a primary candidate for ourself");
content.setCandidates(transportId, getCandidatesAsElements()); content.socks5transport().setChildren(getCandidatesAsElements());
packet.setContent(content); packet.setContent(content);
sendJinglePacket(packet); sendJinglePacket(packet);
} }
@ -256,13 +291,13 @@ public class JingleConnection {
} }
private void sendJinglePacket(JinglePacket packet) { private void sendJinglePacket(JinglePacket packet) {
Log.d("xmppService",packet.toPrettyString()); //Log.d("xmppService",packet.toString());
account.getXmppConnection().sendIqPacket(packet,responseListener); account.getXmppConnection().sendIqPacket(packet,responseListener);
} }
private void accept(JinglePacket packet) { private void accept(JinglePacket packet) {
Content content = packet.getJingleContent(); Content content = packet.getJingleContent();
mergeCandidates(JingleCandidate.parse(content.getCanditates())); mergeCandidates(JingleCandidate.parse(content.socks5transport().getChildren()));
this.status = STATUS_ACCEPTED; this.status = STATUS_ACCEPTED;
this.connectNextCandidate(); this.connectNextCandidate();
IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT); IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT);
@ -271,30 +306,44 @@ public class JingleConnection {
private void transportInfo(JinglePacket packet) { private void transportInfo(JinglePacket packet) {
Content content = packet.getJingleContent(); Content content = packet.getJingleContent();
String cid = content.getUsedCandidate(); if (content.hasSocks5Transport()) {
IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT); if (content.socks5transport().hasChild("activated")) {
if (cid!=null) { onProxyActivated.success();
Log.d("xmppService","candidate used by counterpart:"+cid); } else if (content.socks5transport().hasChild("activated")) {
JingleCandidate candidate = getCandidate(cid); onProxyActivated.failed();
candidate.flagAsUsedByCounterpart(); } else if (content.socks5transport().hasChild("candidate-error")) {
this.receivedCandidate = true; Log.d("xmppService","received candidate error");
if ((status == STATUS_ACCEPTED)&&(this.sentCandidate)) { this.receivedCandidate = true;
this.connect(); if (status == STATUS_ACCEPTED) {
this.connect();
}
} else if (content.socks5transport().hasChild("candidate-used")){
String cid = content.socks5transport().findChild("candidate-used").getAttribute("cid");
if (cid!=null) {
Log.d("xmppService","candidate used by counterpart:"+cid);
JingleCandidate candidate = getCandidate(cid);
candidate.flagAsUsedByCounterpart();
this.receivedCandidate = true;
if ((status == STATUS_ACCEPTED)&&(this.sentCandidate)) {
this.connect();
} else {
Log.d("xmppService","ignoring because file is already in transmission or we havent sent our candidate yet");
}
} else {
Log.d("xmppService","couldn't read used candidate");
}
} else { } else {
Log.d("xmppService","ignoring because file is already in transmission or we havent sent our candidate yet"); Log.d("xmppService","empty transport");
}
} else if (content.hasCandidateError()) {
Log.d("xmppService","received candidate error");
this.receivedCandidate = true;
if (status == STATUS_ACCEPTED) {
this.connect();
} }
} }
IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT);
account.getXmppConnection().sendIqPacket(response, null); account.getXmppConnection().sendIqPacket(response, null);
} }
private void connect() { private void connect() {
final SocksConnection connection = chooseConnection(); final SocksConnection connection = chooseConnection();
this.transport = connection;
if (connection==null) { if (connection==null) {
Log.d("xmppService","could not find suitable candidate"); Log.d("xmppService","could not find suitable candidate");
this.disconnect(); this.disconnect();
@ -302,44 +351,33 @@ public class JingleConnection {
this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_FAILED); this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_FAILED);
} else { } else {
this.status = STATUS_TRANSMITTING; this.status = STATUS_TRANSMITTING;
final OnFileTransmitted callback = new OnFileTransmitted() { if (connection.isProxy()) {
if (connection.getCandidate().isOurs()) {
@Override Log.d("xmppService","candidate "+connection.getCandidate().getCid()+" was our proxy and needs activation");
public void onFileTransmitted(JingleFile file) { IqPacket activation = new IqPacket(IqPacket.TYPE_SET);
if (responder.equals(account.getFullJid())) { activation.setTo(connection.getCandidate().getJid());
sendSuccess(); activation.query("http://jabber.org/protocol/bytestreams").setAttribute("sid", this.getSessionId());
mXmppConnectionService.markMessage(message, Message.STATUS_RECIEVED); activation.query().addChild("activate").setContent(this.getCounterPart());
} this.account.getXmppConnection().sendIqPacket(activation, new OnIqPacketReceived() {
Log.d("xmppService","sucessfully transmitted file. sha1:"+file.getSha1Sum());
} @Override
}; public void onIqPacketReceived(Account account, IqPacket packet) {
if (connection.isProxy()&&(connection.getCandidate().isOurs())) { if (packet.getType()==IqPacket.TYPE_ERROR) {
Log.d("xmppService","candidate "+connection.getCandidate().getCid()+" was our proxy and needs activation"); onProxyActivated.failed();
IqPacket activation = new IqPacket(IqPacket.TYPE_SET); } else {
activation.setTo(connection.getCandidate().getJid()); onProxyActivated.success();
activation.query("http://jabber.org/protocol/bytestreams").setAttribute("sid", this.getSessionId()); sendProxyActivated(connection.getCandidate().getCid());
activation.query().addChild("activate").setContent(this.getCounterPart()); }
this.account.getXmppConnection().sendIqPacket(activation, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
Log.d("xmppService","activation result: "+packet.toString());
if (initiator.equals(account.getFullJid())) {
Log.d("xmppService","we were initiating. sending file");
connection.send(file,callback);
} else {
connection.receive(file,callback);
Log.d("xmppService","we were responding. receiving file");
} }
} });
}); }
} else { } else {
if (initiator.equals(account.getFullJid())) { if (initiator.equals(account.getFullJid())) {
Log.d("xmppService","we were initiating. sending file"); Log.d("xmppService","we were initiating. sending file");
connection.send(file,callback); connection.send(file,onFileTransmitted);
} else { } else {
Log.d("xmppService","we were responding. receiving file"); Log.d("xmppService","we were responding. receiving file");
connection.receive(file,callback); connection.receive(file,onFileTransmitted);
} }
} }
} }
@ -439,13 +477,26 @@ public class JingleConnection {
} }
} }
private void sendProxyActivated(String cid) {
JinglePacket packet = bootstrapPacket("transport-info");
Content content = new Content();
//TODO: put these into actual variables
content.setAttribute("creator", "initiator");
content.setAttribute("name", "a-file-offer");
content.setTransportId(this.transportId);
content.socks5transport().addChild("activated").setAttribute("cid", cid);
packet.setContent(content);
this.sendJinglePacket(packet);
}
private void sendCandidateUsed(final String cid) { private void sendCandidateUsed(final String cid) {
JinglePacket packet = bootstrapPacket("transport-info"); JinglePacket packet = bootstrapPacket("transport-info");
Content content = new Content(); Content content = new Content();
//TODO: put these into actual variables //TODO: put these into actual variables
content.setAttribute("creator", "initiator"); content.setAttribute("creator", "initiator");
content.setAttribute("name", "a-file-offer"); content.setAttribute("name", "a-file-offer");
content.setUsedCandidate(this.transportId, cid); content.setTransportId(this.transportId);
content.setUsedCandidate(cid);
packet.setContent(content); packet.setContent(content);
this.sendJinglePacket(packet); this.sendJinglePacket(packet);
this.sentCandidate = true; this.sentCandidate = true;
@ -460,7 +511,8 @@ public class JingleConnection {
//TODO: put these into actual variables //TODO: put these into actual variables
content.setAttribute("creator", "initiator"); content.setAttribute("creator", "initiator");
content.setAttribute("name", "a-file-offer"); content.setAttribute("name", "a-file-offer");
content.setCandidateError(this.transportId); content.setTransportId(this.transportId);
content.setCandidateError();
packet.setContent(content); packet.setContent(content);
this.sendJinglePacket(packet); this.sendJinglePacket(packet);
this.sentCandidate = true; this.sentCandidate = true;
@ -513,4 +565,9 @@ public class JingleConnection {
} }
return null; return null;
} }
interface OnProxyActivated {
public void success();
public void failed();
}
} }

View file

@ -0,0 +1,6 @@
package eu.siacs.conversations.xmpp.jingle;
public abstract class JingleTransport {
public abstract void receive(final JingleFile file, final OnFileTransmitted callback);
public abstract void send(final JingleFile file, final OnFileTransmitted callback);
}

View file

@ -18,7 +18,7 @@ import eu.siacs.conversations.xml.Element;
import android.util.Log; import android.util.Log;
import android.widget.Button; import android.widget.Button;
public class SocksConnection { public class SocksConnection extends JingleTransport {
private JingleCandidate candidate; private JingleCandidate candidate;
private String destination; private String destination;
private OutputStream outputStream; private OutputStream outputStream;

View file

@ -1,12 +1,12 @@
package eu.siacs.conversations.xmpp.jingle.stanzas; package eu.siacs.conversations.xmpp.jingle.stanzas;
import java.util.ArrayList;
import java.util.List;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.jingle.JingleFile; import eu.siacs.conversations.xmpp.jingle.JingleFile;
public class Content extends Element { public class Content extends Element {
private String transportId;
private Content(String name) { private Content(String name) {
super(name); super(name);
} }
@ -15,6 +15,10 @@ public class Content extends Element {
super("content"); super("content");
} }
public void setTransportId(String sid) {
this.transportId = sid;
}
public void setFileOffer(JingleFile actualFile) { public void setFileOffer(JingleFile actualFile) {
Element description = this.addChild("description", "urn:xmpp:jingle:apps:file-transfer:3"); Element description = this.addChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
Element offer = description.addChild("offer"); Element offer = description.addChild("offer");
@ -34,76 +38,7 @@ public class Content extends Element {
} }
return offer.findChild("file"); return offer.findChild("file");
} }
public void setCandidates(String transportId, List<Element> canditates) {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
if (transport==null) {
transport = this.addChild("transport", "urn:xmpp:jingle:transports:s5b:1");
}
transport.setAttribute("sid", transportId);
transport.clearChildren();
for(Element canditate : canditates) {
transport.addChild(canditate);
}
}
public List<Element> getCanditates() {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
if (transport==null) {
return new ArrayList<Element>();
} else {
return transport.getChildren();
}
}
public String getTransportId() {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
if (transport==null) {
return null;
}
return transport.getAttribute("sid");
}
public String getUsedCandidate() {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
if (transport==null) {
return null;
}
Element usedCandidate = transport.findChild("candidate-used");
if (usedCandidate==null) {
return null;
} else {
return usedCandidate.getAttribute("cid");
}
}
public boolean hasCandidateError() {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
if (transport==null) {
return false;
}
return transport.hasChild("candidate-error");
}
public void setUsedCandidate(String transportId, String cid) {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
if (transport==null) {
transport = this.addChild("transport", "urn:xmpp:jingle:transports:s5b:1");
}
transport.setAttribute("sid", transportId);
transport.clearChildren();
Element usedCandidate = transport.addChild("candidate-used");
usedCandidate.setAttribute("cid",cid);
}
public void addCandidate(Element candidate) {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
if (transport==null) {
transport = this.addChild("transport", "urn:xmpp:jingle:transports:s5b:1");
}
transport.addChild(candidate);
}
public void setFileOffer(Element fileOffer) { public void setFileOffer(Element fileOffer) {
Element description = this.findChild("description", "urn:xmpp:jingle:apps:file-transfer:3"); Element description = this.findChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
if (description==null) { if (description==null) {
@ -111,14 +46,50 @@ public class Content extends Element {
} }
description.addChild(fileOffer); description.addChild(fileOffer);
} }
public String getTransportId() {
if (hasSocks5Transport()) {
this.transportId = socks5transport().getAttribute("sid");
} else if (hasIbbTransport()) {
this.transportId = ibbTransport().getAttribute("sid");
}
return this.transportId;
}
public void setUsedCandidate(String cid) {
socks5transport().clearChildren();
Element usedCandidate = socks5transport().addChild("candidate-used");
usedCandidate.setAttribute("cid",cid);
}
public void setCandidateError(String transportId) { public void setCandidateError() {
socks5transport().clearChildren();
socks5transport().addChild("candidate-error");
}
public Element socks5transport() {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1"); Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
if (transport==null) { if (transport==null) {
transport = this.addChild("transport", "urn:xmpp:jingle:transports:s5b:1"); transport = this.addChild("transport", "urn:xmpp:jingle:transports:s5b:1");
transport.setAttribute("sid", this.transportId);
} }
transport.setAttribute("sid", transportId); return transport;
transport.clearChildren(); }
transport.addChild("candidate-error");
public Element ibbTransport() {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:ibb:1");
if (transport==null) {
transport = this.addChild("transport", "urn:xmpp:jingle:transports:ibb:1");
transport.setAttribute("sid", this.transportId);
}
return transport;
}
public boolean hasSocks5Transport() {
return this.hasChild("transport", "urn:xmpp:jingle:transports:s5b:1");
}
public boolean hasIbbTransport() {
return this.hasChild("transport","urn:xmpp:jingle:transports:ibb:1");
} }
} }

View file

@ -92,22 +92,4 @@ public class JinglePacket extends IqPacket {
public boolean isAction(String action) { public boolean isAction(String action) {
return action.equalsIgnoreCase(this.getAction()); return action.equalsIgnoreCase(this.getAction());
} }
public String toPrettyString() {
StringBuilder output = new StringBuilder();
output.append("["+getAction()+ " to:"+getTo());
if (this.content!=null) {
if (this.content.getUsedCandidate()!=null) {
output.append(" [used-candidate="+this.content.getUsedCandidate()+"]");
} else if (this.content.hasCandidateError()) {
output.append(" [candidate-error]");
} else {
for(Element c : this.content.getCanditates()) {
output.append(" ["+c.getAttribute("host")+":"+c.getAttribute("port")+"]");
}
}
}
output.append("]");
return output.toString();
}
} }