252 lines · 8.1 KB · C#
RawDownload
//******************************************************************************************************//  TFtpTransfer.cs - Gbtc////  Copyright © 2020, 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://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/12/2020 - J. Ritchie Carroll//       Generated original version of source code.////****************************************************************************************************** #region [ Contributor License Agreements ] //*******************************************************************************************************////   Code based on the following project://        https://github.com/Callisto82/tftp.net//  //   Copyright © 2011, Michael Baer////******************************************************************************************************* #endregion using System;using System.IO;using System.Net;using System.Threading;using GSF.Net.TFtp.Channel;using GSF.Net.TFtp.Commands;using GSF.Net.TFtp.Trace;using GSF.Net.TFtp.Transfer.States; // ReSharper disable InconsistentNaming// ReSharper disable VirtualMemberCallInConstructornamespace GSF.Net.TFtp.Transfer{    internal class TFtpTransfer : ITFtpTransfer    {        protected ITransferState State;        protected readonly ITransferChannel Connection;        protected Timer Timer;         public TransferOptionSet ProposedOptions { get; set; }        public TransferOptionSet NegotiatedOptions { get; private set; }        public bool WasStarted { get; private set; }        public Stream InputOutputStream { get; protected set; }         public TFtpTransfer(ITransferChannel connection, string filename, ITransferState initialState)        {            ProposedOptions = TransferOptionSet.NewDefaultSet();            Filename = filename;            RetryCount = 5;            Timer = new Timer(Timer_OnTimer, null, 500, 500);            SetState(initialState);            Connection = connection;            Connection.OnCommandReceived += Connection_OnCommandReceived;            Connection.OnError += Connection_OnError;            Connection.Open();        }         private void Timer_OnTimer(object context)        {            lock (this)            {                State.OnTimer();            }        }         private void Connection_OnCommandReceived(ITFtpCommand command, EndPoint endpoint)        {            lock (this)            {                State.OnCommand(command, endpoint);            }        }         private void Connection_OnError(TFtpTransferError error)        {            lock (this)            {                RaiseOnError(error);            }        }         internal virtual void SetState(ITransferState newState)        {            lock (this)            {                State = DecorateForLogging(newState);                State.Context = this;                State.OnStateEnter();            }        }         protected virtual ITransferState DecorateForLogging(ITransferState state)        {            return TFtpTrace.Enabled ? new LoggingStateDecorator(state, this) : state;        }         internal ITransferChannel GetConnection()        {            return Connection;        }         internal void RaiseOnProgress(long bytesTransferred)        {            OnProgress?.Invoke(this, new TFtpTransferProgress(bytesTransferred, ExpectedSize));        }         internal void RaiseOnError(TFtpTransferError error)        {            OnError?.Invoke(this, error);        }         internal void RaiseOnFinished()        {            OnFinished?.Invoke(this);        }         internal void FinishOptionNegotiation(TransferOptionSet negotiated)        {            NegotiatedOptions = negotiated;             if (!NegotiatedOptions.IncludesBlockSizeOption)                NegotiatedOptions.BlockSize = TransferOptionSet.DefaultBlocksize;             if (!NegotiatedOptions.IncludesTimeoutOption)                NegotiatedOptions.Timeout = TransferOptionSet.DefaultTimeoutSecs;        }         public override string ToString()        {            return $"{GetHashCode()} ({Filename})";        }         internal void FillOrDisableTransferSizeOption()        {            try            {                ProposedOptions.TransferSize = (int)InputOutputStream.Length;            }            catch (NotSupportedException)            {            }            finally            {                if (ProposedOptions.TransferSize <= 0)                    ProposedOptions.IncludesTransferSizeOption = false;            }        }         #region ITFtpTransfer         public event TFtpProgressHandler OnProgress;        public event TFtpEventHandler OnFinished;        public event TFtpErrorHandler OnError;         public string Filename { get; }        public int RetryCount { get; set; }        public virtual TFtpTransferMode TransferMode { get; set; }        public object UserContext { get; set; }         public virtual TimeSpan RetryTimeout         {            get => TimeSpan.FromSeconds(NegotiatedOptions?.Timeout ?? ProposedOptions.Timeout);            set { ThrowExceptionIfTransferAlreadyStarted(); ProposedOptions.Timeout = value.Seconds; }        }         public virtual long ExpectedSize         {            get => NegotiatedOptions?.TransferSize ?? ProposedOptions.TransferSize;            set { ThrowExceptionIfTransferAlreadyStarted(); ProposedOptions.TransferSize = value; }        }         public virtual int BlockSize         {            get => NegotiatedOptions?.BlockSize ?? ProposedOptions.BlockSize;            set { ThrowExceptionIfTransferAlreadyStarted(); ProposedOptions.BlockSize = value; }        }         private BlockCounterWrapAround m_wrapping = BlockCounterWrapAround.ToZero;                public virtual BlockCounterWrapAround BlockCounterWrapping        {            get => m_wrapping;            set { ThrowExceptionIfTransferAlreadyStarted(); m_wrapping = value; }        }         private void ThrowExceptionIfTransferAlreadyStarted()        {            if (WasStarted)                throw new InvalidOperationException("You cannot change TFTP transfer options after the transfer has been started.");        }         public void Start(Stream data)        {            if (WasStarted)                throw new InvalidOperationException("This transfer has already been started.");             WasStarted = true;            InputOutputStream = data ?? throw new ArgumentNullException(nameof(data));             lock (this)            {                State.OnStart();            }        }         public void Cancel(TFtpErrorPacket reason)        {            if (reason == null)                throw new ArgumentNullException(nameof(reason));             lock (this)            {                State.OnCancel(reason);            }        }         public virtual void Dispose()        {            lock (this)            {                Timer.Dispose();                Cancel(new TFtpErrorPacket(0, "ITFtpTransfer has been disposed."));                 if (InputOutputStream != null)                {                    InputOutputStream.Close();                    InputOutputStream = null;                }                 Connection.Dispose();            }        }         #endregion    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t