summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTarun Gupta <tarun1995gupta@gmail.com>2015-07-15 23:49:56 (GMT)
committerNick Hudson <nick.hudson@isode.com>2015-07-28 15:42:52 (GMT)
commit251813ccca9404d8d4122b2848f9fec86a451bf5 (patch)
treea1ebb0f6a04547ef6b588ea85c1a50ea5d8e4997 /src/com/isode/stroke/component/ComponentSession.java
parent673655830b0325d964e67fa835ea83f485e9beeb (diff)
downloadstroke-251813ccca9404d8d4122b2848f9fec86a451bf5.zip
stroke-251813ccca9404d8d4122b2848f9fec86a451bf5.tar.bz2
Completes Components and AdHoc.
Adds Component, ComponentConnector, ComponentError, ComponentSession, ComponentXMLTracer, CoreComponent, ComponentSessionStanzaChannel, ComponentXMTracer, CoreComponent. Updates CoreClient, StrokeGUI, BasicSessionStream and SessionStream and Client, so that signal definition can be changed. Updates ComponentHandshake element, Entity. Updates OutgoingAdHocCommandSession to have feature parity with Swiften. This patch does not port Client or Session fully, which will be done in separate future patches. License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details. Test-Information: Test added for ComponentSession, which passes. Test for ComponentConnector cannot be ported right now and will be done in future patches, as it requires some bits of Network to be ported. Change-Id: I7138a2041fe28a2be7ac57cb47b15365f9334b24
Diffstat (limited to 'src/com/isode/stroke/component/ComponentSession.java')
-rw-r--r--src/com/isode/stroke/component/ComponentSession.java200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/com/isode/stroke/component/ComponentSession.java b/src/com/isode/stroke/component/ComponentSession.java
new file mode 100644
index 0000000..40bb391
--- /dev/null
+++ b/src/com/isode/stroke/component/ComponentSession.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2010-2014 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.component;
+
+import com.isode.stroke.jid.JID;
+import com.isode.stroke.elements.Stanza;
+import com.isode.stroke.elements.Element;
+import com.isode.stroke.elements.ProtocolHeader;
+import com.isode.stroke.elements.ComponentHandshake;
+import com.isode.stroke.elements.StreamFeatures;
+import com.isode.stroke.session.SessionStream;
+import com.isode.stroke.crypto.CryptoProvider;
+import com.isode.stroke.crypto.JavaCryptoProvider;
+import com.isode.stroke.signals.Signal1;
+import com.isode.stroke.signals.Signal;
+import com.isode.stroke.signals.SignalConnection;
+import com.isode.stroke.signals.Slot1;
+
+public class ComponentSession {
+
+ public enum State {
+ Initial,
+ WaitingForStreamStart,
+ Authenticating,
+ Initialized,
+ Finishing,
+ Finished
+ };
+
+ public static class Error implements com.isode.stroke.base.Error {
+ public enum Type {
+ AuthenticationFailedError,
+ UnexpectedElementError
+ }
+ public Type type;
+ public Error(Type type) {
+ if (type == null) {
+ throw new IllegalStateException();
+ }
+ this.type = type;
+ }
+ };
+
+ private JID jid = new JID();
+ private String secret = "";
+ private SessionStream stream;
+ private CryptoProvider crypto;
+ private com.isode.stroke.base.Error error;
+ private State state;
+ public final Signal onInitialized = new Signal();
+ public final Signal1<com.isode.stroke.base.Error> onFinished = new Signal1<com.isode.stroke.base.Error>();
+ public final Signal1<Stanza> onStanzaReceived = new Signal1<Stanza>();
+ private SignalConnection onStreamStartReceivedConnection;
+ private SignalConnection onElementReceivedConnection;
+ private SignalConnection onClosedConnection;
+
+ public static ComponentSession create(final JID jid, final String secret, SessionStream stream, CryptoProvider crypto) {
+ return new ComponentSession(jid, secret, stream, crypto);
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public void start() {
+ onStreamStartReceivedConnection = stream.onStreamStartReceived.connect(new Slot1<ProtocolHeader>() {
+ @Override
+ public void call(ProtocolHeader p1) {
+ handleStreamStart(p1);
+ }
+ });
+ onElementReceivedConnection = stream.onElementReceived.connect(new Slot1<Element>() {
+ @Override
+ public void call(Element e1) {
+ handleElement(e1);
+ }
+ });
+ onClosedConnection = stream.onClosed.connect(new Slot1<SessionStream.Error>() {
+ @Override
+ public void call(SessionStream.Error e1) {
+ handleStreamClosed(e1);
+ }
+ });
+
+ assert(State.Initial.equals(state));
+ state = State.WaitingForStreamStart;
+ sendStreamHeader();
+ }
+
+ public void finish() {
+ finishSession((Error.Type)null);
+ }
+
+ public void sendStanza(Stanza stanza) {
+ stream.writeElement(stanza);
+ }
+
+ private ComponentSession(final JID jid, final String secret, SessionStream stream, CryptoProvider crypto) {
+ this.jid = jid;
+ this.secret = secret;
+ this.stream = stream;
+ this.crypto = crypto;
+ this.state = State.Initial;
+ }
+
+ private void finishSession(Error.Type error) {
+ Error localError = null;
+ if (error != null) {
+ localError = new Error(error);
+ }
+ finishSession(localError);
+ }
+
+ private void finishSession(com.isode.stroke.base.Error finishError) {
+ state = State.Finishing;
+ error = finishError;
+ assert(stream.isOpen() == true);
+ stream.writeFooter();
+ stream.close();
+ }
+
+ private void sendStreamHeader() {
+ ProtocolHeader header = new ProtocolHeader();
+ header.setTo(jid.toString());
+ stream.writeHeader(header);
+ }
+
+ private void handleElement(Element element) {
+ if(element instanceof Stanza) {
+ Stanza stanza = (Stanza)element;
+ if (State.Initialized.equals(getState())) {
+ onStanzaReceived.emit(stanza);
+ }
+ else {
+ finishSession(Error.Type.UnexpectedElementError);
+ }
+ }
+ else if (element instanceof ComponentHandshake) {
+ if (!checkState(State.Authenticating)) {
+ return;
+ }
+ stream.setWhitespacePingEnabled(true);
+ state = State.Initialized;
+ onInitialized.emit();
+ }
+ else if (State.Authenticating.equals(getState())) {
+ if (element instanceof StreamFeatures) {
+ // M-Link sends stream features, so swallow that.
+ }
+ else {
+ // FIXME: We should actually check the element received
+ finishSession(Error.Type.AuthenticationFailedError);
+ }
+ }
+ else {
+ finishSession(Error.Type.UnexpectedElementError);
+ }
+ }
+
+ private void handleStreamStart(final ProtocolHeader header) {
+ checkState(State.WaitingForStreamStart);
+ state = State.Authenticating;
+ stream.writeElement(new ComponentHandshake(ComponentHandshakeGenerator.getHandshake(header.getID(), secret, crypto)));
+ }
+
+ private void handleStreamClosed(SessionStream.Error streamError) {
+ State oldState = state;
+ state = State.Finished;
+ stream.setWhitespacePingEnabled(false);
+ onStreamStartReceivedConnection.disconnect();
+ onElementReceivedConnection.disconnect();
+ onClosedConnection.disconnect();
+ if (State.Finishing.equals(oldState)) {
+ onFinished.emit(error);
+ }
+ else {
+ onFinished.emit(streamError);
+ }
+ }
+
+ private boolean checkState(State state) {
+ if (!(this.state.equals(state))) {
+ finishSession(Error.Type.UnexpectedElementError);
+ return false;
+ }
+ return true;
+ }
+}
+
+
+