diff options
Diffstat (limited to 'src/com/isode/stroke/session/BasicSessionStream.java')
-rw-r--r-- | src/com/isode/stroke/session/BasicSessionStream.java | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/src/com/isode/stroke/session/BasicSessionStream.java b/src/com/isode/stroke/session/BasicSessionStream.java new file mode 100644 index 0000000..c7c98cf --- /dev/null +++ b/src/com/isode/stroke/session/BasicSessionStream.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2010 Remko Tron¨on + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ +/* + * Copyright (c) 2010, Isode Limited, London, England. + * All rights reserved. + */ +package com.isode.stroke.session; + +import com.isode.stroke.base.ByteArray; +import com.isode.stroke.elements.Element; +import com.isode.stroke.elements.ProtocolHeader; +import com.isode.stroke.elements.StreamType; +import com.isode.stroke.eventloop.EventLoop; +import com.isode.stroke.network.Connection; +import com.isode.stroke.network.TimerFactory; +import com.isode.stroke.parser.PayloadParserFactoryCollection; +import com.isode.stroke.serializer.PayloadSerializerCollection; +import com.isode.stroke.signals.Slot; +import com.isode.stroke.signals.Slot1; +import com.isode.stroke.streamstack.CompressionLayer; +import com.isode.stroke.streamstack.ConnectionLayer; +import com.isode.stroke.streamstack.StreamStack; +import com.isode.stroke.streamstack.TLSLayer; +import com.isode.stroke.streamstack.WhitespacePingLayer; +import com.isode.stroke.tls.TLSContextFactory; +import com.isode.stroke.streamstack.XMPPLayer; +import com.isode.stroke.tls.Certificate; +import com.isode.stroke.tls.CertificateVerificationError; + +public class BasicSessionStream extends SessionStream { + + public BasicSessionStream( + StreamType streamType, + Connection connection, + PayloadParserFactoryCollection payloadParserFactories, + PayloadSerializerCollection payloadSerializers, + TLSContextFactory tlsContextFactory, + TimerFactory timerFactory, + EventLoop eventLoop) { + available = false; + this.connection = connection; + this.payloadParserFactories = payloadParserFactories; + this.payloadSerializers = payloadSerializers; + this.tlsContextFactory = tlsContextFactory; + this.timerFactory = timerFactory; + if (timerFactory == null) { + throw new IllegalStateException(); //FIXME: remove conditional, debugging only. + } + this.streamType = streamType; + this.compressionLayer = null; + this.tlsLayer = null; + this.whitespacePingLayer = null; + + xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, streamType, eventLoop); + xmppLayer.onStreamStart.connect(new Slot1<ProtocolHeader>() { + + public void call(ProtocolHeader p1) { + handleStreamStartReceived(p1); + } + }); + xmppLayer.onElement.connect(new Slot1<Element>() { + + public void call(Element p1) { + handleElementReceived(p1); + } + }); + xmppLayer.onError.connect(new Slot() { + + public void call() { + handleXMPPError(); + } + }); + xmppLayer.onDataRead.connect(new Slot1<ByteArray>() { + + public void call(ByteArray p1) { + handleDataRead(p1); + } + }); + xmppLayer.onWriteData.connect(new Slot1<ByteArray>() { + + public void call(ByteArray p1) { + handleDataWritten(p1); + } + }); + + connection.onDisconnected.connect(new Slot1<Connection.Error>() { + + public void call(Connection.Error p1) { + handleConnectionFinished(p1); + } + }); + connectionLayer = new ConnectionLayer(connection); + + streamStack = new StreamStack(xmppLayer, connectionLayer); + + available = true; + + } + + public void writeHeader(ProtocolHeader header) { + assert available; + xmppLayer.writeHeader(header); + } + + public void writeElement(Element element) { + assert available; + xmppLayer.writeElement(element); + } + + public void writeFooter() { + assert available; + xmppLayer.writeFooter(); + } + + public void writeData(String data) { + assert available; + xmppLayer.writeData(data); + } + + public void close() { + connection.disconnect(); + } + + public boolean isOpen() { + return available; + } + + public boolean supportsTLSEncryption() { + return tlsContextFactory != null && tlsContextFactory.canCreate(); + } + + public void addTLSEncryption() { + assert available; + tlsLayer = new TLSLayer(tlsContextFactory); + if (hasTLSCertificate() && !tlsLayer.setClientCertificate(getTLSCertificate())) { + onClosed.emit(new Error(Error.Type.InvalidTLSCertificateError)); + } else { + streamStack.addLayer(tlsLayer); + tlsLayer.onError.connect(new Slot() { + + public void call() { + handleTLSError(); + } + }); + tlsLayer.onConnected.connect(new Slot() { + + public void call() { + handleTLSConnected(); + } + }); + tlsLayer.connect(); + } + } + + public boolean isTLSEncrypted() { + return tlsLayer != null; + } + + public Certificate getPeerCertificate() { + return tlsLayer.getPeerCertificate(); + } + + public CertificateVerificationError getPeerCertificateVerificationError() { + return tlsLayer.getPeerCertificateVerificationError(); + } + + public ByteArray getTLSFinishMessage() { + return tlsLayer.getContext().getFinishMessage(); + } + + public void addZLibCompression() { + compressionLayer = new CompressionLayer(); + streamStack.addLayer(compressionLayer); + } + + public void setWhitespacePingEnabled(boolean enabled) { + if (enabled) { + if (whitespacePingLayer == null) { + whitespacePingLayer = new WhitespacePingLayer(timerFactory); + streamStack.addLayer(whitespacePingLayer); + } + whitespacePingLayer.setActive(); + } + else if (whitespacePingLayer != null) { + whitespacePingLayer.setInactive(); + } + } + + public void resetXMPPParser() { + xmppLayer.resetParser(); + } + + private void handleStreamStartReceived(ProtocolHeader header) { + onStreamStartReceived.emit(header); + } + + private void handleElementReceived(Element element) { + onElementReceived.emit(element); + } + + private void handleXMPPError() { + available = false; + onClosed.emit(new Error(Error.Type.ParseError)); + } + + private void handleTLSConnected() { + onTLSEncrypted.emit(); + } + + private void handleTLSError() { + available = false; + onClosed.emit(new Error(Error.Type.TLSError)); + } + + private void handleConnectionFinished(Connection.Error error) { + available = false; + if (Connection.Error.ReadError.equals(error)) { + onClosed.emit(new Error(Error.Type.ConnectionReadError)); + } + else if (error != null) { + onClosed.emit(new Error(Error.Type.ConnectionWriteError)); + } + else { + onClosed.emit(null); + } + } + + private void handleDataRead(ByteArray data) { + onDataRead.emit(data.toString()); + } + + private void handleDataWritten(ByteArray data) { + onDataWritten.emit(data.toString()); + } + private boolean available; + private Connection connection; + private PayloadParserFactoryCollection payloadParserFactories; + private PayloadSerializerCollection payloadSerializers; + private TLSContextFactory tlsContextFactory; + private TimerFactory timerFactory; + private StreamType streamType; + private XMPPLayer xmppLayer; + private ConnectionLayer connectionLayer; + private CompressionLayer compressionLayer; + private TLSLayer tlsLayer; + private WhitespacePingLayer whitespacePingLayer; + private StreamStack streamStack; + +} |