From 8b9891afc85d114ff1e9c9a0291a4aaee8baeb09 Mon Sep 17 00:00:00 2001 From: Alex Clayton Date: Wed, 16 Mar 2016 13:48:37 +0000 Subject: Add FileWriteBytestream class and test. Adds a FileWriteBytestream class plus a test for it. These had been missed out previously. Also as per patch 'Fix crash when saving a received file to non-writable location' changed WriteBytestream.write() method to return a boolean indicating success or failure. Test-information: Tests pass ok. Change-Id: I0c3676db8b67573142e8628f439cecf54f3f8f1a diff --git a/src/com/isode/stroke/filetransfer/ByteArrayWriteBytestream.java b/src/com/isode/stroke/filetransfer/ByteArrayWriteBytestream.java index eb3a30f..d983e89 100644 --- a/src/com/isode/stroke/filetransfer/ByteArrayWriteBytestream.java +++ b/src/com/isode/stroke/filetransfer/ByteArrayWriteBytestream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -20,9 +20,11 @@ public class ByteArrayWriteBytestream extends WriteBytestream { public ByteArrayWriteBytestream() { } - public void write(final ByteArray bytes) { + @Override + public boolean write(final ByteArray bytes) { data.append(bytes); onWrite.emit(bytes); + return true; } public ByteArray getData() { diff --git a/src/com/isode/stroke/filetransfer/FileTransferError.java b/src/com/isode/stroke/filetransfer/FileTransferError.java index ac135d6..fbb5ec6 100644 --- a/src/com/isode/stroke/filetransfer/FileTransferError.java +++ b/src/com/isode/stroke/filetransfer/FileTransferError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -19,6 +19,7 @@ public class FileTransferError { UnknownError, PeerError, ReadError, + WriteError, ClosedError }; diff --git a/src/com/isode/stroke/filetransfer/FileWriteBytestream.java b/src/com/isode/stroke/filetransfer/FileWriteBytestream.java new file mode 100644 index 0000000..7fa068d --- /dev/null +++ b/src/com/isode/stroke/filetransfer/FileWriteBytestream.java @@ -0,0 +1,73 @@ +/* Copyright (c) 2016, Isode Limited, London, England. + * All rights reserved. + * + * Acquisition and use of this software and related materials for any + * purpose requires a written license agreement from Isode Limited, + * or a written license from an organisation licensed by Isode Limited + * to grant such a license. + * + */ +package com.isode.stroke.filetransfer; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import com.isode.stroke.base.ByteArray; + +public class FileWriteBytestream extends WriteBytestream { + + private final String filePath_; + + private FileOutputStream stream_ = null; + + public FileWriteBytestream(String filePath) { + filePath_ = filePath; + } + + @Override + protected void finalize() throws Throwable { + try { + close(); + } + finally { + super.finalize(); + } + } + + @Override + public boolean write(ByteArray data) { + if (data.isEmpty()) { + return true; + } + if (stream_ == null) { + try { + stream_ = new FileOutputStream(filePath_); + } catch (FileNotFoundException e) { + return false; + } + } + try { + stream_.write(data.getData()); + stream_.flush(); + } catch (IOException e) { + return false; + } + onWrite.emit(data); + return true; + } + + public void close() { + if (stream_ != null) { + try { + stream_.close(); + } catch (IOException e) { + // Ignore exception + } + stream_ = null; + } + } + + +} diff --git a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSession.java b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSession.java index 18e4484..982e3e9 100644 --- a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSession.java +++ b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSession.java @@ -116,7 +116,6 @@ public class SOCKS5BytestreamClientSession extends SOCKS5AbstractBytestreamSessi state = State.Reading; writeBytestream = writeStream; writeBytestream.write(unprocessedData); - //onBytesReceived(unprocessedData.size()); unprocessedData.clear(); } else { logger_.fine("Session isn't ready for transfer yet!\n"); diff --git a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerSession.java b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerSession.java index 8facca0..f9c1f95 100644 --- a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerSession.java +++ b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerSession.java @@ -82,7 +82,7 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess } public void stop() { - finish(false); + finish(); } public void startSending(ReadBytestream stream) { @@ -124,8 +124,12 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess return streamID; } - private void finish(boolean error) { - logger_.fine(error + " " + state + "\n"); + private void finish() { + finish(null); + } + + private void finish(FileTransferError error) { + logger_.fine("state: " + state + "\n"); if (State.Finished.equals(state)) { return; } @@ -140,11 +144,7 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess } readBytestream = null; state = State.Finished; - if (error) { - onFinished.emit(new FileTransferError(FileTransferError.Type.PeerError)); - } else { - onFinished.emit(null); - } + onFinished.emit(error); } private void process() { @@ -193,7 +193,7 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess if (!hasBytestream) { logger_.fine("Readstream or Wrtiestream with ID " + streamID + " not found!\n"); connection.write(result); - finish(true); + finish(new FileTransferError(FileTransferError.Type.PeerError)); } else { logger_.fine("Found stream. Sent OK.\n"); @@ -210,14 +210,15 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess unprocessedData.append(data); process(); } else { - writeBytestream.write(new ByteArray(data)); - // onBytesReceived(data.size()); + if (!writeBytestream.write(new ByteArray(data))) { + finish(new FileTransferError(FileTransferError.Type.WriteError)); + } } } private void handleDisconnected(final Connection.Error error) { logger_.fine((error != null ? (error.equals(Connection.Error.ReadError) ? "Read Error" : "Write Error") : "No Error") + "\n"); - finish(error != null ? true : false); + finish(error != null ? new FileTransferError(FileTransferError.Type.PeerError) : null); } private void handleDataAvailable() { @@ -244,7 +245,7 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess //} } else { - finish(false); + finish(); } } } \ No newline at end of file diff --git a/src/com/isode/stroke/filetransfer/WriteBytestream.java b/src/com/isode/stroke/filetransfer/WriteBytestream.java index c243bdc..81d2093 100644 --- a/src/com/isode/stroke/filetransfer/WriteBytestream.java +++ b/src/com/isode/stroke/filetransfer/WriteBytestream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -16,7 +16,14 @@ import com.isode.stroke.signals.Signal1; public abstract class WriteBytestream { - public abstract void write(final ByteArray b); + /** + * Write data from a {@link ByteArray} to the bytestream. On + * success {@code true} is returned and {@link #onWrite} is called. + * On failure {@code false} is returned. + * @param b The {@link ByteArray} to write. + * @return {@code true} on success, {@code false} on failure. + */ + public abstract boolean write(final ByteArray b); public final Signal1 onWrite = new Signal1(); } \ No newline at end of file diff --git a/test/com/isode/stroke/filetransfer/FileWriteBytestreamTest.java b/test/com/isode/stroke/filetransfer/FileWriteBytestreamTest.java new file mode 100644 index 0000000..3e06646 --- /dev/null +++ b/test/com/isode/stroke/filetransfer/FileWriteBytestreamTest.java @@ -0,0 +1,83 @@ +/* Copyright (c) 2016, Isode Limited, London, England. + * All rights reserved. + * + * Acquisition and use of this software and related materials for any + * purpose requires a written license agreement from Isode Limited, + * or a written license from an organisation licensed by Isode Limited + * to grant such a license. + * + */ +package com.isode.stroke.filetransfer; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; + +import org.junit.Test; + +import com.isode.stroke.base.ByteArray; +import com.isode.stroke.signals.Slot1; + +/** + * Tests for {@link FileWriteBytestream} + * + */ +public class FileWriteBytestreamTest { + + private boolean onWriteWasCalled = false; + + @Test + public void testSuccessfulWrite() { + File tempfile = null; + String filename = null; + try { + try { + tempfile = File.createTempFile("write_file_bytestream_test_", ".tmp"); + filename = tempfile.getAbsolutePath(); + } catch (IOException e) { + // Unable to create file exit test + return; + } + WriteBytestream writeBytestream = new FileWriteBytestream(filename); + writeBytestream.onWrite.connect(new Slot1() { + + @Override + public void call(ByteArray data) { + handleOnWrite(data); + } + + }); + + assertTrue(writeBytestream.write(new ByteArray("Some data."))); + assertTrue(onWriteWasCalled); + } + finally { + if (tempfile != null && tempfile.exists()) { + tempfile.delete(); + } + } + } + + @Test + public void testFailingWrite() { + WriteBytestream writeBytestream = new FileWriteBytestream(""); + writeBytestream.onWrite.connect(new Slot1() { + + @Override + public void call(ByteArray data) { + handleOnWrite(data); + } + + }); + + assertFalse(writeBytestream.write(new ByteArray("Some data."))); + assertFalse(onWriteWasCalled); + } + + private void handleOnWrite(ByteArray data) { + onWriteWasCalled = true; + } + +} -- cgit v0.10.2-6-g49f6