JingleConnectionManager.java

  1package eu.siacs.conversations.xmpp.jingle;
  2
  3import java.math.BigInteger;
  4import java.security.SecureRandom;
  5import java.util.HashMap;
  6import java.util.List;
  7import java.util.concurrent.CopyOnWriteArrayList;
  8import android.annotation.SuppressLint;
  9import android.util.Log;
 10import eu.siacs.conversations.Config;
 11import eu.siacs.conversations.entities.Account;
 12import eu.siacs.conversations.entities.Message;
 13import eu.siacs.conversations.services.AbstractConnectionManager;
 14import eu.siacs.conversations.services.XmppConnectionService;
 15import eu.siacs.conversations.xml.Element;
 16import eu.siacs.conversations.xmpp.OnIqPacketReceived;
 17import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 18import eu.siacs.conversations.xmpp.jid.Jid;
 19import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
 20import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 21
 22public class JingleConnectionManager extends AbstractConnectionManager {
 23	private List<JingleConnection> connections = new CopyOnWriteArrayList<>();
 24
 25	private HashMap<Jid, JingleCandidate> primaryCandidates = new HashMap<>();
 26
 27	@SuppressLint("TrulyRandom")
 28	private SecureRandom random = new SecureRandom();
 29
 30	public JingleConnectionManager(XmppConnectionService service) {
 31		super(service);
 32	}
 33
 34	public void deliverPacket(Account account, JinglePacket packet) {
 35		if (packet.isAction("session-initiate")) {
 36			JingleConnection connection = new JingleConnection(this);
 37			connection.init(account, packet);
 38			connections.add(connection);
 39		} else {
 40			for (JingleConnection connection : connections) {
 41				if (connection.getAccount() == account
 42						&& connection.getSessionId().equals(
 43								packet.getSessionId())
 44						&& connection.getCounterPart().equals(packet.getFrom())) {
 45					connection.deliverPacket(packet);
 46					return;
 47				}
 48			}
 49			IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR);
 50			Element error = response.addChild("error");
 51			error.setAttribute("type", "cancel");
 52			error.addChild("item-not-found",
 53					"urn:ietf:params:xml:ns:xmpp-stanzas");
 54			error.addChild("unknown-session", "urn:xmpp:jingle:errors:1");
 55			account.getXmppConnection().sendIqPacket(response, null);
 56		}
 57	}
 58
 59	public JingleConnection createNewConnection(Message message) {
 60		JingleConnection connection = new JingleConnection(this);
 61		connection.init(message);
 62		this.connections.add(connection);
 63		return connection;
 64	}
 65
 66	public JingleConnection createNewConnection(final JinglePacket packet) {
 67		JingleConnection connection = new JingleConnection(this);
 68		this.connections.add(connection);
 69		return connection;
 70	}
 71
 72	public void finishConnection(JingleConnection connection) {
 73		this.connections.remove(connection);
 74	}
 75
 76	public void getPrimaryCandidate(Account account,
 77			final OnPrimaryCandidateFound listener) {
 78		if (!this.primaryCandidates.containsKey(account.getJid().toBareJid())) {
 79			String xmlns = "http://jabber.org/protocol/bytestreams";
 80			final String proxy = account.getXmppConnection()
 81					.findDiscoItemByFeature(xmlns);
 82			if (proxy != null) {
 83				IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
 84				iq.setAttribute("to", proxy);
 85				iq.query(xmlns);
 86				account.getXmppConnection().sendIqPacket(iq,
 87						new OnIqPacketReceived() {
 88
 89							@Override
 90							public void onIqPacketReceived(Account account,
 91									IqPacket packet) {
 92								Element streamhost = packet
 93										.query()
 94										.findChild("streamhost",
 95												"http://jabber.org/protocol/bytestreams");
 96								if (streamhost != null) {
 97									JingleCandidate candidate = new JingleCandidate(
 98											nextRandomId(), true);
 99									candidate.setHost(streamhost
100											.getAttribute("host"));
101									candidate.setPort(Integer
102											.parseInt(streamhost
103													.getAttribute("port")));
104									candidate
105											.setType(JingleCandidate.TYPE_PROXY);
106                                    try {
107                                        candidate.setJid(Jid.fromString(proxy));
108                                    } catch (final InvalidJidException e) {
109                                        candidate.setJid(null);
110                                    }
111                                    candidate.setPriority(655360 + 65535);
112									primaryCandidates.put(account.getJid().toBareJid(),
113											candidate);
114									listener.onPrimaryCandidateFound(true,
115											candidate);
116								} else {
117									listener.onPrimaryCandidateFound(false,
118											null);
119								}
120							}
121						});
122			} else {
123				listener.onPrimaryCandidateFound(false, null);
124			}
125
126		} else {
127			listener.onPrimaryCandidateFound(true,
128					this.primaryCandidates.get(account.getJid().toBareJid()));
129		}
130	}
131
132	public String nextRandomId() {
133		return new BigInteger(50, random).toString(32);
134	}
135
136	public void deliverIbbPacket(Account account, IqPacket packet) {
137		String sid = null;
138		Element payload = null;
139		if (packet.hasChild("open", "http://jabber.org/protocol/ibb")) {
140			payload = packet
141					.findChild("open", "http://jabber.org/protocol/ibb");
142			sid = payload.getAttribute("sid");
143		} else if (packet.hasChild("data", "http://jabber.org/protocol/ibb")) {
144			payload = packet
145					.findChild("data", "http://jabber.org/protocol/ibb");
146			sid = payload.getAttribute("sid");
147		}
148		if (sid != null) {
149			for (JingleConnection connection : connections) {
150				if (connection.getAccount() == account
151						&& connection.hasTransportId(sid)) {
152					JingleTransport transport = connection.getTransport();
153					if (transport instanceof JingleInbandTransport) {
154						JingleInbandTransport inbandTransport = (JingleInbandTransport) transport;
155						inbandTransport.deliverPayload(packet, payload);
156						return;
157					}
158				}
159			}
160			Log.d(Config.LOGTAG,
161					"couldnt deliver payload: " + payload.toString());
162		} else {
163			Log.d(Config.LOGTAG, "no sid found in incomming ibb packet");
164		}
165	}
166
167	public void cancelInTransmission() {
168		for (JingleConnection connection : this.connections) {
169			if (connection.getJingleStatus() == JingleConnection.JINGLE_STATUS_TRANSMITTING) {
170				connection.cancel();
171			}
172		}
173	}
174}