Granados.Poderosa.SFTP.SFTPClient.UploadFile C# (CSharp) Method

UploadFile() public method

Upload a file.
Operation failed. Timeout has occured. Invalid status. Error. Error.
public UploadFile ( string localPath, string remotePath, Granados.Poderosa.FileTransfer.Cancellation cancellation, SFTPFileTransferProgressDelegate progressDelegate ) : void
localPath string Local file path to upload.
remotePath string Remote file path to write.
cancellation Granados.Poderosa.FileTransfer.Cancellation An object to request the cancellation. Set null if the cancellation is not needed.
progressDelegate SFTPFileTransferProgressDelegate Delegate to notify progress. Set null if notification is not needed.
return void
        public void UploadFile(string localPath, string remotePath, Cancellation cancellation, SFTPFileTransferProgressDelegate progressDelegate)
        {
            CheckStatus();

            uint requestId = ++_requestId;

            ulong transmitted = 0;

            Exception pendingException = null;

            bool hasError = false;
            bool dataFinished = false;
            byte[] handle = null;
            try {
                using (FileStream fileStream = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {

                    if (progressDelegate != null) {
                        progressDelegate(SFTPFileTransferStatus.Open, transmitted);
                    }

                    handle = OpenFile(requestId, remotePath, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC);

                    var dataToSend = new AtomicBox<DataFragment>();
                    var cancelTask = new CancellationTokenSource();
                    var cancelToken = cancelTask.Token;

                    Task readFileTask = Task.Run(() => {
                        // SSH_FXP_WRITE header part
                        //   4 bytes : packet length
                        //   1 byte  : message type (SSH_FXP_WRITE)
                        //   4 bytes : request id
                        //   4 bytes : handle length
                        //   n bytes : handle
                        //   8 bytes : offset
                        //   4 bytes : length of the datagram
                        int buffSize = _channel.MaxChannelDatagramSize - 25 - handle.Length;
                        // use multiple buffers cyclically.
                        // at least 3 buffers are required.
                        DataFragment[] dataFrags =
                            {
                                new DataFragment(new byte[buffSize], 0, buffSize),
                                new DataFragment(new byte[buffSize], 0, buffSize),
                                new DataFragment(new byte[buffSize], 0, buffSize),
                            };
                        int buffIndex = 0;

                        while (true) {
                            if (cancelToken.IsCancellationRequested) {
                                return;
                            }

                            DataFragment df = dataFrags[buffIndex];
                            buffIndex = (buffIndex + 1) % 3;

                            int length = fileStream.Read(df.Data, 0, df.Data.Length);
                            if (length == 0) {
                                df = null;  // end of file
                            }
                            else {
                                df.SetLength(0, length);
                            }

                            // pass to the sending loop
                            while (true) {
                                if (dataToSend.TrySet(df, 500)) {
                                    break;
                                }
                                if (cancelToken.IsCancellationRequested) {
                                    return;
                                }
                            }

                            if (length == 0) {
                                return; // end of file
                            }
                        }
                    }, cancelToken);

                    try {
                        while (true) {
                            if (cancellation != null && cancellation.IsRequested) {
                                break;
                            }

                            DataFragment dataFrag = null;
                            if (!dataToSend.TryGet(ref dataFrag, 1000)) {
                                throw new Exception("read error");
                            }

                            if (dataFrag == null) {
                                dataFinished = true;
                                break;
                            }

                            WriteFile(requestId, handle, transmitted, dataFrag.Data, dataFrag.Length);

                            transmitted += (ulong)dataFrag.Length;

                            if (progressDelegate != null) {
                                progressDelegate(SFTPFileTransferStatus.Transmitting, transmitted);
                            }
                        }
                    }
                    finally {
                        if (!readFileTask.IsCompleted) {
                            cancelTask.Cancel();
                        }
                        readFileTask.Wait();
                    }
                }   // using
            }
            catch (Exception e) {
                if (e is AggregateException) {
                    pendingException = ((AggregateException)e).InnerExceptions[0];
                }
                else {
                    pendingException = e;
                }

                hasError = true;
            }

            try {
                if (handle != null) {
                    if (progressDelegate != null)
                        progressDelegate(SFTPFileTransferStatus.Close, transmitted);

                    CloseHandle(requestId, handle);
                }

                if (progressDelegate != null) {
                    SFTPFileTransferStatus status =
                        hasError ? SFTPFileTransferStatus.CompletedError :
                        dataFinished ? SFTPFileTransferStatus.CompletedSuccess : SFTPFileTransferStatus.CompletedAbort;
                    progressDelegate(status, transmitted);
                }
            }
            catch (Exception) {
                if (progressDelegate != null) {
                    progressDelegate(SFTPFileTransferStatus.CompletedError, transmitted);
                }
                throw;
            }

            if (pendingException != null) {
                throw new SFTPClientException(pendingException.Message, pendingException);
            }
        }