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			account.getXmppConnection().sendIqPacket(
 48					packet.generateRespone(IqPacket.TYPE_ERROR), null);
 49		}
 50	}
 51
 52	public JingleConnection createNewConnection(Message message) {
 53		JingleConnection connection = new JingleConnection(this);
 54		connection.init(message);
 55		this.connections.add(connection);
 56		return connection;
 57	}
 58
 59	public JingleConnection createNewConnection(JinglePacket packet) {
 60		JingleConnection connection = new JingleConnection(this);
 61		this.connections.add(connection);
 62		return connection;
 63	}
 64
 65	public void finishConnection(JingleConnection connection) {
 66		this.connections.remove(connection);
 67	}
 68
 69	public void getPrimaryCandidate(Account account,
 70			final OnPrimaryCandidateFound listener) {
 71		if (!this.primaryCandidates.containsKey(account.getJid())) {
 72			String xmlns = "http://jabber.org/protocol/bytestreams";
 73			final String proxy = account.getXmppConnection()
 74					.findDiscoItemByFeature(xmlns);
 75			if (proxy != null) {
 76				IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
 77				iq.setTo(proxy);
 78				iq.query(xmlns);
 79				account.getXmppConnection().sendIqPacket(iq,
 80						new OnIqPacketReceived() {
 81
 82							@Override
 83							public void onIqPacketReceived(Account account,
 84									IqPacket packet) {
 85								Element streamhost = packet
 86										.query()
 87										.findChild("streamhost",
 88												"http://jabber.org/protocol/bytestreams");
 89								if (streamhost != null) {
 90									JingleCandidate candidate = new JingleCandidate(
 91											nextRandomId(), true);
 92									candidate.setHost(streamhost
 93											.getAttribute("host"));
 94									candidate.setPort(Integer
 95											.parseInt(streamhost
 96													.getAttribute("port")));
 97									candidate
 98											.setType(JingleCandidate.TYPE_PROXY);
 99									candidate.setJid(proxy);
100									candidate.setPriority(655360 + 65535);
101									primaryCandidates.put(account.getJid(),
102											candidate);
103									listener.onPrimaryCandidateFound(true,
104											candidate);
105								} else {
106									listener.onPrimaryCandidateFound(false,
107											null);
108								}
109							}
110						});
111			} else {
112				listener.onPrimaryCandidateFound(false, null);
113			}
114
115		} else {
116			listener.onPrimaryCandidateFound(true,
117					this.primaryCandidates.get(account.getJid()));
118		}
119	}
120
121	public String nextRandomId() {
122		return new BigInteger(50, random).toString(32);
123	}
124
125	public void deliverIbbPacket(Account account, IqPacket packet) {
126		String sid = null;
127		Element payload = null;
128		if (packet.hasChild("open", "http://jabber.org/protocol/ibb")) {
129			payload = packet
130					.findChild("open", "http://jabber.org/protocol/ibb");
131			sid = payload.getAttribute("sid");
132		} else if (packet.hasChild("data", "http://jabber.org/protocol/ibb")) {
133			payload = packet
134					.findChild("data", "http://jabber.org/protocol/ibb");
135			sid = payload.getAttribute("sid");
136		}
137		if (sid != null) {
138			for (JingleConnection connection : connections) {
139				if (connection.getAccount() == account
140						&& connection.hasTransportId(sid)) {
141					JingleTransport transport = connection.getTransport();
142					if (transport instanceof JingleInbandTransport) {
143						JingleInbandTransport inbandTransport = (JingleInbandTransport) transport;
144						inbandTransport.deliverPayload(packet, payload);
145						return;
146					}
147				}
148			}
149			Log.d(Config.LOGTAG,
150					"couldnt deliver payload: " + payload.toString());
151		} else {
152			Log.d(Config.LOGTAG, "no sid found in incomming ibb packet");
153		}
154	}
155
156	public void cancelInTransmission() {
157		for (JingleConnection connection : this.connections) {
158			if (connection.getJingleStatus() == JingleConnection.JINGLE_STATUS_TRANSMITTING) {
159				connection.cancel();
160			}
161		}
162	}
163}