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