//******************************************************************************************************
// FtpDataStream.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 05/22/2003 - J. Ritchie Carroll
// Generated original version of source code.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 12/17/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
#region [ Contributor License Agreements ]
//*******************************************************************************************************
//
// Code based on the following project:
// http://www.codeproject.com/KB/IP/net_ftp_upload.aspx
//
// Copyright Alex Kwok & Uwe Keim
//
// The Code Project Open License (CPOL):
// http://www.codeproject.com/info/cpol10.aspx
//
//*******************************************************************************************************
#endregion
using System.IO;
using System.Net.Sockets;
namespace GSF.Net.Ftp
{
///
/// FTP data stream.
///
public class FtpDataStream : Stream
{
#region [ Members ]
// Fields
private readonly FtpSessionConnected m_session;
private TcpClient m_tcpClient;
private readonly Stream m_stream;
private bool m_userAbort;
#endregion
#region [ Constructors ]
internal FtpDataStream(FtpControlChannel ctrl, TcpClient client)
{
m_session = ctrl.Session;
ControlChannel = ctrl;
m_tcpClient = client;
m_stream = client.GetStream();
m_stream.ReadTimeout = ctrl.Timeout;
m_stream.WriteTimeout = ctrl.Timeout;
TryBeginDataTransfer();
}
#endregion
#region [ Properties ]
internal bool IsClosed => m_tcpClient == null;
internal FtpControlChannel ControlChannel { get; }
///
/// Gets a value indicating whether the current stream supports reading.
///
///
/// true if the stream supports reading; otherwise, false.
///
public override bool CanRead => m_stream.CanRead;
///
/// Gets a value indicating whether the current stream supports seeking.
///
///
/// true if the stream supports seeking; otherwise, false.
///
public override bool CanSeek => m_stream.CanSeek;
///
/// Gets a value indicating whether the current stream supports writing.
///
///
/// true if the stream supports writing; otherwise, false.
///
public override bool CanWrite => m_stream.CanWrite;
///
/// Gets the length in bytes of the stream.
///
///
/// A long value representing the length of the stream in bytes.
///
/// Stream does not support seeking.
/// Methods were called after the stream was closed.
public override long Length => m_stream.Length;
///
/// Gets or sets the position within the current stream.
///
///
/// The current position within the stream.
///
/// An I/O error occurs.
/// Stream does not support seeking.
/// Methods were called after the stream was closed.
public override long Position
{
get => m_stream.Position;
set => m_stream.Position = value;
}
#endregion
#region [ Methods ]
///
/// Closes the FTP stream and releases any resources associated with the stream.
///
public override void Close()
{
Close(false);
}
internal void Close(bool error)
{
if (IsClosed)
return;
CloseConnection();
if (!error)
ControlChannel.RefreshResponse();
ControlChannel.Session.EndDataTransfer();
}
internal void Abort()
{
m_userAbort = true;
}
private void CloseConnection()
{
m_stream.Close();
m_tcpClient.Close();
m_tcpClient = null;
}
///
/// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
///
/// An I/O error occurs.
public override void Flush()
{
m_stream.Flush();
}
///
/// Sets the position within the current stream.
///
/// A byte offset relative to the origin parameter.
///
/// A value of type indicating the reference
/// point used to obtain the new position.
///
/// The new position within the current stream.
/// An I/O error occurs.
/// Stream does not support seeking.
/// Methods were called after the stream was closed.
public override long Seek(long offset, SeekOrigin origin)
{
return m_stream.Seek(offset, origin);
}
///
/// Reads a sequence of bytes from the current stream and advances the
/// position within the stream by the number of bytes read.
///
///
/// An array of bytes. When this method returns, the
/// contains the specified byte array with the values between
/// and ( + - 1)
/// replaced by the bytes read from the current source.
///
/// The zero-based byte offset in at which to begin
/// storing the data read from the current stream.
///
///
/// The maximum number of bytes to be read from the current stream.
///
///
/// The total number of bytes read into the . This can be less than the
/// number of bytes requested if that many bytes are not currently available, or zero (0) if the
/// end of the stream has been reached.
///
public override int Read(byte[] buffer, int offset, int count)
{
if (m_userAbort)
throw new FtpUserAbortException();
return m_stream.Read(buffer, offset, count);
}
///
/// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position
/// within this stream by the number of bytes written.
///
///
/// An array of bytes. When this method returns, the
/// contains the specified byte array with the values between
/// and ( + - 1)
/// replaced by the bytes read from the current source.
///
/// The zero-based byte offset in at which to begin
/// storing the data read from the current stream.
///
///
/// The maximum number of bytes to be read from the current stream.
///
public override void Write(byte[] buffer, int offset, int count)
{
if (m_userAbort)
throw new FtpUserAbortException();
m_stream.Write(buffer, offset, count);
}
///
/// Reads a byte from the stream and advances the position within the stream
/// by one byte, or returns -1 if at the end of the stream.
///
///
/// The unsigned byte cast to an Int32, or -1 if at the end of the stream.
///
public override int ReadByte()
{
if (m_userAbort)
throw new FtpUserAbortException();
return m_stream.ReadByte();
}
///
/// Writes a byte to the current position in the stream and advances the position
/// within the stream by one byte.
///
/// The byte to write to the stream.
public override void WriteByte(byte b)
{
if (m_userAbort)
throw new FtpUserAbortException();
m_stream.WriteByte(b);
}
///
/// Sets the length of the current stream.
///
/// The desired length of the current stream in bytes.
public override void SetLength(long len)
{
m_stream.SetLength(len);
}
private void TryBeginDataTransfer()
{
try
{
m_session.BeginDataTransfer(this);
}
catch
{
CloseConnection();
throw;
}
}
#endregion
}
}