lot of cleanup in jingle part
This commit is contained in:
parent
8006931f80
commit
07cf07ad58
|
@ -0,0 +1,138 @@
|
||||||
|
package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Element;
|
||||||
|
|
||||||
|
public class JingleCandidate {
|
||||||
|
|
||||||
|
public static int TYPE_UNKNOWN;
|
||||||
|
public static int TYPE_DIRECT = 0;
|
||||||
|
public static int TYPE_PROXY = 1;
|
||||||
|
|
||||||
|
private boolean ours;
|
||||||
|
private boolean usedByCounterpart = false;
|
||||||
|
private String cid;
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private int type;
|
||||||
|
private String jid;
|
||||||
|
private int priority;
|
||||||
|
|
||||||
|
public JingleCandidate(String cid,boolean ours) {
|
||||||
|
this.ours = ours;
|
||||||
|
this.cid = cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCid() {
|
||||||
|
return cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return this.host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJid(String jid) {
|
||||||
|
this.jid = jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJid() {
|
||||||
|
return this.jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return this.port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(int type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
if ("proxy".equals(type)) {
|
||||||
|
this.type = TYPE_PROXY;
|
||||||
|
} else if ("direct".equals(type)) {
|
||||||
|
this.type = TYPE_DIRECT;
|
||||||
|
} else {
|
||||||
|
this.type = TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPriority(int i) {
|
||||||
|
this.priority = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPriority() {
|
||||||
|
return this.priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(JingleCandidate other) {
|
||||||
|
return this.getCid().equals(other.getCid());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equalValues(JingleCandidate other) {
|
||||||
|
return other.getHost().equals(this.getHost())&&(other.getPort()==this.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOurs() {
|
||||||
|
return ours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<JingleCandidate> parse(List<Element> canditates) {
|
||||||
|
List<JingleCandidate> parsedCandidates = new ArrayList<JingleCandidate>();
|
||||||
|
for(Element c : canditates) {
|
||||||
|
parsedCandidates.add(JingleCandidate.parse(c));
|
||||||
|
}
|
||||||
|
return parsedCandidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JingleCandidate parse(Element candidate) {
|
||||||
|
JingleCandidate parsedCandidate = new JingleCandidate(candidate.getAttribute("cid"), false);
|
||||||
|
parsedCandidate.setHost(candidate.getAttribute("host"));
|
||||||
|
parsedCandidate.setJid(candidate.getAttribute("jid"));
|
||||||
|
parsedCandidate.setType(candidate.getAttribute("type"));
|
||||||
|
parsedCandidate.setPriority(Integer.parseInt(candidate.getAttribute("priority")));
|
||||||
|
parsedCandidate.setPort(Integer.parseInt(candidate.getAttribute("port")));
|
||||||
|
return parsedCandidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element toElement() {
|
||||||
|
Element element = new Element("candidate");
|
||||||
|
element.setAttribute("cid", this.getCid());
|
||||||
|
element.setAttribute("host", this.getHost());
|
||||||
|
element.setAttribute("port", ""+this.getPort());
|
||||||
|
element.setAttribute("jid", this.getJid());
|
||||||
|
element.setAttribute("priority",""+this.getPriority());
|
||||||
|
if (this.getType()==TYPE_DIRECT) {
|
||||||
|
element.setAttribute("type","direct");
|
||||||
|
} else if (this.getType()==TYPE_PROXY) {
|
||||||
|
element.setAttribute("type","proxy");
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flagAsUsedByCounterpart() {
|
||||||
|
this.usedByCounterpart = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUsedByCounterpart() {
|
||||||
|
return this.usedByCounterpart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return this.getHost()+":"+this.getPort()+" (prio="+this.getPriority()+")";
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,12 +38,15 @@ public class JingleConnection {
|
||||||
private Account account;
|
private Account account;
|
||||||
private String initiator;
|
private String initiator;
|
||||||
private String responder;
|
private String responder;
|
||||||
private List<Element> candidates = new ArrayList<Element>();
|
private List<JingleCandidate> candidates = new ArrayList<JingleCandidate>();
|
||||||
private List<String> candidatesUsedByCounterpart = new ArrayList<String>();
|
|
||||||
private HashMap<String, SocksConnection> connections = new HashMap<String, SocksConnection>();
|
private HashMap<String, SocksConnection> connections = new HashMap<String, SocksConnection>();
|
||||||
private Content content = new Content();
|
|
||||||
|
private String transportId;
|
||||||
|
private Element fileOffer;
|
||||||
private JingleFile file = null;
|
private JingleFile file = null;
|
||||||
|
|
||||||
|
private boolean receivedCandidateError = false;
|
||||||
|
|
||||||
private OnIqPacketReceived responseListener = new OnIqPacketReceived() {
|
private OnIqPacketReceived responseListener = new OnIqPacketReceived() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,10 +110,11 @@ public class JingleConnection {
|
||||||
this.mJingleConnectionManager.getPrimaryCandidate(account, new OnPrimaryCandidateFound() {
|
this.mJingleConnectionManager.getPrimaryCandidate(account, new OnPrimaryCandidateFound() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrimaryCandidateFound(boolean success, Element candidate) {
|
public void onPrimaryCandidateFound(boolean success, JingleCandidate candidate) {
|
||||||
if (success) {
|
if (success) {
|
||||||
mergeCandidate(candidate);
|
mergeCandidate(candidate);
|
||||||
}
|
}
|
||||||
|
openOurCandidates();
|
||||||
sendInitRequest();
|
sendInitRequest();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -130,9 +134,10 @@ public class JingleConnection {
|
||||||
this.initiator = packet.getFrom();
|
this.initiator = packet.getFrom();
|
||||||
this.responder = this.account.getFullJid();
|
this.responder = this.account.getFullJid();
|
||||||
this.sessionId = packet.getSessionId();
|
this.sessionId = packet.getSessionId();
|
||||||
this.content = packet.getJingleContent();
|
Content content = packet.getJingleContent();
|
||||||
this.mergeCandidates(this.content.getCanditates());
|
this.transportId = content.getTransportId();
|
||||||
Element fileOffer = packet.getJingleContent().getFileOffer();
|
this.mergeCandidates(JingleCandidate.parse(content.getCanditates()));
|
||||||
|
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);
|
||||||
Element fileSize = fileOffer.findChild("size");
|
Element fileSize = fileOffer.findChild("size");
|
||||||
|
@ -156,13 +161,14 @@ public class JingleConnection {
|
||||||
|
|
||||||
private void sendInitRequest() {
|
private void sendInitRequest() {
|
||||||
JinglePacket packet = this.bootstrapPacket("session-initiate");
|
JinglePacket packet = this.bootstrapPacket("session-initiate");
|
||||||
this.content = new Content();
|
Content content = new Content();
|
||||||
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");
|
||||||
this.file = this.mXmppConnectionService.getFileBackend().getJingleFile(message);
|
this.file = this.mXmppConnectionService.getFileBackend().getJingleFile(message);
|
||||||
content.setFileOffer(this.file);
|
content.setFileOffer(this.file);
|
||||||
content.setCandidates(this.mJingleConnectionManager.nextRandomId(),this.candidates);
|
this.transportId = this.mJingleConnectionManager.nextRandomId();
|
||||||
|
content.setCandidates(this.transportId,getCandidatesAsElements());
|
||||||
packet.setContent(content);
|
packet.setContent(content);
|
||||||
Log.d("xmppService",packet.toString());
|
Log.d("xmppService",packet.toString());
|
||||||
account.getXmppConnection().sendIqPacket(packet, this.responseListener);
|
account.getXmppConnection().sendIqPacket(packet, this.responseListener);
|
||||||
|
@ -170,17 +176,28 @@ public class JingleConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Element> getCandidatesAsElements() {
|
||||||
|
List<Element> elements = new ArrayList<Element>();
|
||||||
|
for(JingleCandidate c : this.candidates) {
|
||||||
|
elements.add(c.toElement());
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
private void sendAccept() {
|
private void sendAccept() {
|
||||||
this.mJingleConnectionManager.getPrimaryCandidate(this.account, new OnPrimaryCandidateFound() {
|
this.mJingleConnectionManager.getPrimaryCandidate(this.account, new OnPrimaryCandidateFound() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrimaryCandidateFound(boolean success, Element candidate) {
|
public void onPrimaryCandidateFound(boolean success, JingleCandidate candidate) {
|
||||||
|
Content content = new Content();
|
||||||
|
content.setFileOffer(fileOffer);
|
||||||
if (success) {
|
if (success) {
|
||||||
if (!equalCandidateExists(candidate)) {
|
if (!equalCandidateExists(candidate)) {
|
||||||
mergeCandidate(candidate);
|
mergeCandidate(candidate);
|
||||||
content.addCandidate(candidate);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
openOurCandidates();
|
||||||
|
content.setCandidates(transportId, getCandidatesAsElements());
|
||||||
JinglePacket packet = bootstrapPacket("session-accept");
|
JinglePacket packet = bootstrapPacket("session-accept");
|
||||||
packet.setContent(content);
|
packet.setContent(content);
|
||||||
account.getXmppConnection().sendIqPacket(packet, new OnIqPacketReceived() {
|
account.getXmppConnection().sendIqPacket(packet, new OnIqPacketReceived() {
|
||||||
|
@ -211,7 +228,7 @@ public class JingleConnection {
|
||||||
private void accept(JinglePacket packet) {
|
private void accept(JinglePacket packet) {
|
||||||
Log.d("xmppService","session-accept: "+packet.toString());
|
Log.d("xmppService","session-accept: "+packet.toString());
|
||||||
Content content = packet.getJingleContent();
|
Content content = packet.getJingleContent();
|
||||||
mergeCandidates(content.getCanditates());
|
mergeCandidates(JingleCandidate.parse(content.getCanditates()));
|
||||||
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);
|
||||||
|
@ -224,26 +241,25 @@ public class JingleConnection {
|
||||||
IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT);
|
IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT);
|
||||||
if (cid!=null) {
|
if (cid!=null) {
|
||||||
Log.d("xmppService","candidate used by counterpart:"+cid);
|
Log.d("xmppService","candidate used by counterpart:"+cid);
|
||||||
this.candidatesUsedByCounterpart.add(cid);
|
JingleCandidate candidate = getCandidate(cid);
|
||||||
if (this.connections.containsKey(cid)) {
|
candidate.flagAsUsedByCounterpart();
|
||||||
SocksConnection connection = this.connections.get(cid);
|
if (status == STATUS_ACCEPTED) {
|
||||||
if (connection.isEstablished()) {
|
this.connect();
|
||||||
if (status==STATUS_ACCEPTED) {
|
|
||||||
this.connect(connection);
|
|
||||||
} else {
|
|
||||||
Log.d("xmppService","ignoring canditate used because we are already transmitting");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d("xmppService","not yet connected. check when callback comes back");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Log.d("xmppService","candidate not yet in list of connections");
|
Log.d("xmppService","ignoring because file is already in transmission");
|
||||||
|
}
|
||||||
|
} else if (content.hasCandidateError()) {
|
||||||
|
Log.d("xmppService","received candidate error");
|
||||||
|
this.receivedCandidateError = true;
|
||||||
|
if (status == STATUS_ACCEPTED) {
|
||||||
|
this.connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
account.getXmppConnection().sendIqPacket(response, null);
|
account.getXmppConnection().sendIqPacket(response, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connect(final SocksConnection connection) {
|
private void connect() {
|
||||||
|
final SocksConnection connection = chooseConnection();
|
||||||
this.status = STATUS_TRANSMITTING;
|
this.status = STATUS_TRANSMITTING;
|
||||||
final OnFileTransmitted callback = new OnFileTransmitted() {
|
final OnFileTransmitted callback = new OnFileTransmitted() {
|
||||||
|
|
||||||
|
@ -256,10 +272,10 @@ public class JingleConnection {
|
||||||
Log.d("xmppService","sucessfully transmitted file. sha1:"+file.getSha1Sum());
|
Log.d("xmppService","sucessfully transmitted file. sha1:"+file.getSha1Sum());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if ((connection.isProxy()&&(connection.getCid().equals(mJingleConnectionManager.getPrimaryCandidateId(account))))) {
|
if (connection.isProxy()&&(connection.getCandidate().isOurs())) {
|
||||||
Log.d("xmppService","candidate "+connection.getCid()+" was our proxy and needs activation");
|
Log.d("xmppService","candidate "+connection.getCandidate().getCid()+" was our proxy and needs activation");
|
||||||
IqPacket activation = new IqPacket(IqPacket.TYPE_SET);
|
IqPacket activation = new IqPacket(IqPacket.TYPE_SET);
|
||||||
activation.setTo(connection.getJid());
|
activation.setTo(connection.getCandidate().getJid());
|
||||||
activation.query("http://jabber.org/protocol/bytestreams").setAttribute("sid", this.getSessionId());
|
activation.query("http://jabber.org/protocol/bytestreams").setAttribute("sid", this.getSessionId());
|
||||||
activation.query().addChild("activate").setContent(this.getCounterPart());
|
activation.query().addChild("activate").setContent(this.getCounterPart());
|
||||||
this.account.getXmppConnection().sendIqPacket(activation, new OnIqPacketReceived() {
|
this.account.getXmppConnection().sendIqPacket(activation, new OnIqPacketReceived() {
|
||||||
|
@ -287,6 +303,41 @@ public class JingleConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SocksConnection chooseConnection() {
|
||||||
|
Log.d("xmppService","choosing connection from "+this.connections.size()+" possibilties");
|
||||||
|
SocksConnection connection = null;
|
||||||
|
Iterator<Entry<String, SocksConnection>> it = this.connections.entrySet().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Entry<String, SocksConnection> pairs = it.next();
|
||||||
|
SocksConnection 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");
|
||||||
|
if (connection==null) {
|
||||||
|
connection = currentConnection;
|
||||||
|
} else {
|
||||||
|
if (connection.getCandidate().getPriority()<currentConnection.getCandidate().getPriority()) {
|
||||||
|
connection = currentConnection;
|
||||||
|
} else if (connection.getCandidate().getPriority()==currentConnection.getCandidate().getPriority()) {
|
||||||
|
Log.d("xmppService","found two candidates with same priority");
|
||||||
|
if (initiator.equals(account.getFullJid())) {
|
||||||
|
if (currentConnection.getCandidate().isOurs()) {
|
||||||
|
connection = currentConnection;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!currentConnection.getCandidate().isOurs()) {
|
||||||
|
connection = currentConnection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
Log.d("xmppService","chose candidate: "+connection.getCandidate().getHost());
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
private void sendSuccess() {
|
private void sendSuccess() {
|
||||||
JinglePacket packet = bootstrapPacket("session-terminate");
|
JinglePacket packet = bootstrapPacket("session-terminate");
|
||||||
Reason reason = new Reason();
|
Reason reason = new Reason();
|
||||||
|
@ -311,20 +362,40 @@ public class JingleConnection {
|
||||||
this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_REJECTED);
|
this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_REJECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectNextCandidate() {
|
private void openOurCandidates() {
|
||||||
for(Element candidate : this.candidates) {
|
for(JingleCandidate candidate : this.candidates) {
|
||||||
String cid = candidate.getAttribute("cid");
|
if (candidate.isOurs()) {
|
||||||
if (!connections.containsKey(cid)) {
|
final SocksConnection socksConnection = new SocksConnection(this,candidate);
|
||||||
this.connectWithCandidate(candidate);
|
connections.put(candidate.getCid(), socksConnection);
|
||||||
break;
|
socksConnection.connect(new OnSocksConnection() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed() {
|
||||||
|
Log.d("xmppService","connection to our candidate failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void established() {
|
||||||
|
Log.d("xmppService","connection to our candidate was successful");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectWithCandidate(Element candidate) {
|
private void connectNextCandidate() {
|
||||||
boolean initating = candidate.getAttribute("cid").equals(mJingleConnectionManager.getPrimaryCandidateId(account));
|
for(JingleCandidate candidate : this.candidates) {
|
||||||
final SocksConnection socksConnection = new SocksConnection(this,candidate,initating);
|
if ((!connections.containsKey(candidate.getCid())&&(!candidate.isOurs()))) {
|
||||||
connections.put(socksConnection.getCid(), socksConnection);
|
this.connectWithCandidate(candidate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.sendCandidateError();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectWithCandidate(final JingleCandidate candidate) {
|
||||||
|
final SocksConnection socksConnection = new SocksConnection(this,candidate);
|
||||||
|
connections.put(candidate.getCid(), socksConnection);
|
||||||
socksConnection.connect(new OnSocksConnection() {
|
socksConnection.connect(new OnSocksConnection() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -334,14 +405,10 @@ public class JingleConnection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void established() {
|
public void established() {
|
||||||
if (candidatesUsedByCounterpart.contains(socksConnection.getCid())) {
|
sendCandidateUsed(candidate.getCid());
|
||||||
if (status==STATUS_ACCEPTED) {
|
if ((receivedCandidateError)&&(status == STATUS_ACCEPTED)) {
|
||||||
connect(socksConnection);
|
Log.d("xmppService","received candidate error before. trying to connect");
|
||||||
} else {
|
connect();
|
||||||
Log.d("xmppService","ignoring cuz already transmitting");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendCandidateUsed(socksConnection.getCid());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -359,21 +426,25 @@ public class JingleConnection {
|
||||||
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();
|
||||||
content.setUsedCandidate(this.content.getTransportId(), cid);
|
//TODO: put these into actual variables
|
||||||
|
content.setAttribute("creator", "initiator");
|
||||||
|
content.setAttribute("name", "a-file-offer");
|
||||||
|
content.setUsedCandidate(this.transportId, cid);
|
||||||
packet.setContent(content);
|
packet.setContent(content);
|
||||||
Log.d("xmppService","send using candidate: "+cid);
|
Log.d("xmppService","send using candidate: "+cid);
|
||||||
this.account.getXmppConnection().sendIqPacket(packet, new OnIqPacketReceived() {
|
this.account.getXmppConnection().sendIqPacket(packet,responseListener);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private void sendCandidateError() {
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
JinglePacket packet = bootstrapPacket("transport-info");
|
||||||
Log.d("xmppService","got ack for our candidate used");
|
Content content = new Content();
|
||||||
if (status==STATUS_ACCEPTED) {
|
//TODO: put these into actual variables
|
||||||
connect(connections.get(cid));
|
content.setAttribute("creator", "initiator");
|
||||||
} else {
|
content.setAttribute("name", "a-file-offer");
|
||||||
Log.d("xmppService","ignoring cuz already transmitting");
|
content.setCandidateError(this.transportId);
|
||||||
}
|
packet.setContent(content);
|
||||||
}
|
Log.d("xmppService","send candidate error");
|
||||||
});
|
this.account.getXmppConnection().sendIqPacket(packet,responseListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInitiator() {
|
public String getInitiator() {
|
||||||
|
@ -388,33 +459,33 @@ public class JingleConnection {
|
||||||
return this.status;
|
return this.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean equalCandidateExists(Element candidate) {
|
private boolean equalCandidateExists(JingleCandidate candidate) {
|
||||||
for(Element c : this.candidates) {
|
for(JingleCandidate c : this.candidates) {
|
||||||
if (c.getAttribute("host").equals(candidate.getAttribute("host"))&&(c.getAttribute("port").equals(candidate.getAttribute("port")))) {
|
if (c.equalValues(candidate)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mergeCandidate(Element candidate) {
|
private void mergeCandidate(JingleCandidate candidate) {
|
||||||
for(Element c : this.candidates) {
|
for(JingleCandidate c : this.candidates) {
|
||||||
if (c.getAttribute("cid").equals(candidate.getAttribute("cid"))) {
|
if (c.equals(candidate)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.candidates.add(candidate);
|
this.candidates.add(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mergeCandidates(List<Element> candidates) {
|
private void mergeCandidates(List<JingleCandidate> candidates) {
|
||||||
for(Element c : candidates) {
|
for(JingleCandidate c : candidates) {
|
||||||
mergeCandidate(c);
|
mergeCandidate(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Element getCandidate(String cid) {
|
private JingleCandidate getCandidate(String cid) {
|
||||||
for(Element c : this.candidates) {
|
for(JingleCandidate c : this.candidates) {
|
||||||
if (c.getAttribute("cid").equals(cid)) {
|
if (c.getCid().equals(cid)) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ public class JingleConnectionManager {
|
||||||
private List<JingleConnection> connections = new ArrayList<JingleConnection>(); // make
|
private List<JingleConnection> connections = new ArrayList<JingleConnection>(); // make
|
||||||
// concurrent
|
// concurrent
|
||||||
|
|
||||||
private ConcurrentHashMap<String, Element> primaryCandidates = new ConcurrentHashMap<String, Element>();
|
private ConcurrentHashMap<String, JingleCandidate> primaryCandidates = new ConcurrentHashMap<String, JingleCandidate>();
|
||||||
|
|
||||||
private SecureRandom random = new SecureRandom();
|
private SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
|
@ -89,17 +89,12 @@ public class JingleConnectionManager {
|
||||||
if (streamhost != null) {
|
if (streamhost != null) {
|
||||||
Log.d("xmppService", "streamhost found "
|
Log.d("xmppService", "streamhost found "
|
||||||
+ streamhost.toString());
|
+ streamhost.toString());
|
||||||
Element candidate = new Element("candidate");
|
JingleCandidate candidate = new JingleCandidate(nextRandomId(),true);
|
||||||
candidate.setAttribute("cid",
|
candidate.setHost(streamhost.getAttribute("host"));
|
||||||
nextRandomId());
|
candidate.setPort(Integer.parseInt(streamhost.getAttribute("port")));
|
||||||
candidate.setAttribute("host",
|
candidate.setType(JingleCandidate.TYPE_PROXY);
|
||||||
streamhost.getAttribute("host"));
|
candidate.setJid(proxy);
|
||||||
candidate.setAttribute("port",
|
candidate.setPriority(655360+65535);
|
||||||
streamhost.getAttribute("port"));
|
|
||||||
candidate.setAttribute("type", "proxy");
|
|
||||||
candidate.setAttribute("jid", proxy);
|
|
||||||
candidate
|
|
||||||
.setAttribute("priority", "655360");
|
|
||||||
primaryCandidates.put(account.getJid(),
|
primaryCandidates.put(account.getJid(),
|
||||||
candidate);
|
candidate);
|
||||||
listener.onPrimaryCandidateFound(true,
|
listener.onPrimaryCandidateFound(true,
|
||||||
|
@ -120,14 +115,6 @@ public class JingleConnectionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPrimaryCandidateId(Account account) {
|
|
||||||
if (this.primaryCandidates.containsKey(account.getJid())) {
|
|
||||||
return this.primaryCandidates.get(account.getJid()).getAttribute("cid");
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String nextRandomId() {
|
public String nextRandomId() {
|
||||||
return new BigInteger(50, random).toString(32);
|
return new BigInteger(50, random).toString(32);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package eu.siacs.conversations.xmpp.jingle;
|
package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
import eu.siacs.conversations.xml.Element;
|
|
||||||
|
|
||||||
public interface OnPrimaryCandidateFound {
|
public interface OnPrimaryCandidateFound {
|
||||||
public void onPrimaryCandidateFound(boolean success, Element canditate);
|
public void onPrimaryCandidateFound(boolean success, JingleCandidate canditate);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,29 +19,20 @@ import android.util.Log;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
public class SocksConnection {
|
public class SocksConnection {
|
||||||
private Socket socket;
|
private JingleCandidate candidate;
|
||||||
private String host;
|
|
||||||
private String jid;
|
|
||||||
private String cid;
|
|
||||||
private int port;
|
|
||||||
private boolean isProxy = false;
|
|
||||||
private String destination;
|
private String destination;
|
||||||
private OutputStream outputStream;
|
private OutputStream outputStream;
|
||||||
private InputStream inputStream;
|
private InputStream inputStream;
|
||||||
private boolean isEstablished = false;
|
private boolean isEstablished = false;
|
||||||
|
protected Socket socket;
|
||||||
|
|
||||||
public SocksConnection(JingleConnection jingleConnection, Element candidate, boolean initating) {
|
public SocksConnection(JingleConnection jingleConnection, JingleCandidate candidate) {
|
||||||
this.cid = candidate.getAttribute("cid");
|
this.candidate = candidate;
|
||||||
this.host = candidate.getAttribute("host");
|
|
||||||
this.port = Integer.parseInt(candidate.getAttribute("port"));
|
|
||||||
String type = candidate.getAttribute("type");
|
|
||||||
this.jid = candidate.getAttribute("jid");
|
|
||||||
this.isProxy = "proxy".equalsIgnoreCase(type);
|
|
||||||
try {
|
try {
|
||||||
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
|
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
|
||||||
StringBuilder destBuilder = new StringBuilder();
|
StringBuilder destBuilder = new StringBuilder();
|
||||||
destBuilder.append(jingleConnection.getSessionId());
|
destBuilder.append(jingleConnection.getSessionId());
|
||||||
if (initating) {
|
if (candidate.isOurs()) {
|
||||||
destBuilder.append(jingleConnection.getAccountJid());
|
destBuilder.append(jingleConnection.getAccountJid());
|
||||||
destBuilder.append(jingleConnection.getCounterPart());
|
destBuilder.append(jingleConnection.getCounterPart());
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,7 +53,7 @@ public class SocksConnection {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
socket = new Socket(host, port);
|
socket = new Socket(candidate.getHost(), candidate.getPort());
|
||||||
inputStream = socket.getInputStream();
|
inputStream = socket.getInputStream();
|
||||||
outputStream = socket.getOutputStream();
|
outputStream = socket.getOutputStream();
|
||||||
byte[] login = { 0x05, 0x01, 0x00 };
|
byte[] login = { 0x05, 0x01, 0x00 };
|
||||||
|
@ -78,8 +69,7 @@ public class SocksConnection {
|
||||||
inputStream.read(result);
|
inputStream.read(result);
|
||||||
int status = result[1];
|
int status = result[1];
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
Log.d("xmppService", "established connection with "+host + ":" + port
|
Log.d("xmppService", "established connection with "+candidate.getHost()+":"+candidate.getPort()+ "/" + destination);
|
||||||
+ "/" + destination);
|
|
||||||
isEstablished = true;
|
isEstablished = true;
|
||||||
callback.established();
|
callback.established();
|
||||||
} else {
|
} else {
|
||||||
|
@ -193,24 +183,16 @@ public class SocksConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isProxy() {
|
public boolean isProxy() {
|
||||||
return this.isProxy;
|
return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
|
||||||
}
|
|
||||||
|
|
||||||
public String getJid() {
|
|
||||||
return this.jid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCid() {
|
|
||||||
return this.cid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
if (this.socket!=null) {
|
if (this.socket!=null) {
|
||||||
try {
|
try {
|
||||||
this.socket.close();
|
this.socket.close();
|
||||||
Log.d("xmppService","cloesd socket with "+this.host);
|
Log.d("xmppService","cloesd socket with "+candidate.getHost()+":"+candidate.getPort());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d("xmppService","error closing socket with "+this.host);
|
Log.d("xmppService","error closing socket with "+candidate.getHost()+":"+candidate.getPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,4 +200,8 @@ public class SocksConnection {
|
||||||
public boolean isEstablished() {
|
public boolean isEstablished() {
|
||||||
return this.isEstablished;
|
return this.isEstablished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JingleCandidate getCandidate() {
|
||||||
|
return this.candidate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,14 @@ public class Content extends Element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
public void setUsedCandidate(String transportId, String cid) {
|
||||||
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) {
|
||||||
|
@ -95,4 +103,22 @@ public class Content extends Element {
|
||||||
}
|
}
|
||||||
transport.addChild(candidate);
|
transport.addChild(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFileOffer(Element fileOffer) {
|
||||||
|
Element description = this.findChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
|
||||||
|
if (description==null) {
|
||||||
|
description = this.addChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
|
||||||
|
}
|
||||||
|
description.addChild(fileOffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCandidateError(String transportId) {
|
||||||
|
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();
|
||||||
|
transport.addChild("candidate-error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue