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