Пример #1
0
        async Task <Result <int> > ReceiveLengthOfIncomingRequest()
        {
            EventOccurred?.Invoke(this,
                                  new ServerEvent {
                EventType = EventType.ReceiveRequestLengthStarted
            });

            var readFromSocket = await
                                 _socket.ReceiveWithTimeoutAsync(
                _buffer,
                0,
                _bufferSize,
                SocketFlags.None,
                _timeoutMs)
                                 .ConfigureAwait(false);

            if (readFromSocket.Failure)
            {
                return(readFromSocket);
            }

            var lastBytesReceivedCount = readFromSocket.Value;
            var unreadBytesCount       = lastBytesReceivedCount - Constants.SizeOfInt32InBytes;
            var requestLength          = BitConverter.ToInt32(_buffer, 0);

            var requestLengthBytes = new byte[Constants.SizeOfInt32InBytes];

            _buffer.ToList().CopyTo(0, requestLengthBytes, 0, Constants.SizeOfInt32InBytes);

            SocketEventOccurred?.Invoke(this, new ServerEvent
            {
                EventType            = EventType.ReceivedRequestLengthBytesFromSocket,
                BytesReceivedCount   = lastBytesReceivedCount,
                RequestLengthInBytes = Constants.SizeOfInt32InBytes,
                UnreadBytesCount     = unreadBytesCount
            });

            if (lastBytesReceivedCount > Constants.SizeOfInt32InBytes)
            {
                var unreadBytes = new byte[unreadBytesCount];
                _buffer.ToList().CopyTo(Constants.SizeOfInt32InBytes, unreadBytes, 0, unreadBytesCount);
                _unreadBytes = unreadBytes.ToList();

                EventOccurred?.Invoke(this, new ServerEvent
                {
                    EventType        = EventType.SaveUnreadBytesAfterRequestLengthReceived,
                    UnreadBytesCount = unreadBytesCount
                });
            }

            EventOccurred?.Invoke(this, new ServerEvent
            {
                EventType            = EventType.ReceiveRequestLengthComplete,
                RequestLengthInBytes = requestLength,
                RequestLengthBytes   = requestLengthBytes
            });

            return(Result.Ok(requestLength));
        }
Пример #2
0
        public virtual async Task <Result> SendFileAsync(FileTransfer fileTransfer, Socket socket, CancellationToken token)
        {
            var bufferSize     = Settings.SocketSettings.BufferSize;
            var timeoutMs      = Settings.SocketSettings.SocketTimeoutInMilliseconds;
            var updateInterval = Settings.TransferUpdateInterval;

            fileTransfer.Status            = FileTransferStatus.InProgress;
            fileTransfer.TransferStartTime = DateTime.Now;

            EventOccurred?.Invoke(this, new ServerEvent
            {
                EventType              = EventType.SendFileBytesStarted,
                RemoteServerIpAddress  = fileTransfer.RemoteServerInfo.SessionIpAddress,
                RemoteServerPortNumber = fileTransfer.RemoteServerInfo.PortNumber,
                FileTransferId         = fileTransfer.Id
            });

            fileTransfer.BytesRemaining              = fileTransfer.FileSizeInBytes;
            fileTransfer.FileChunkSentCount          = 0;
            fileTransfer.OutboundFileTransferStalled = false;

            using (var file = File.OpenRead(fileTransfer.LocalFilePath))
            {
                while (fileTransfer.BytesRemaining > 0)
                {
                    if (token.IsCancellationRequested)
                    {
                        fileTransfer.Status = FileTransferStatus.Cancelled;
                        fileTransfer.TransferCompleteTime = DateTime.Now;
                        fileTransfer.ErrorMessage         = "Cancellation requested";

                        return(Result.Ok());
                    }

                    var fileChunkSize = (int)Math.Min(bufferSize, fileTransfer.BytesRemaining);
                    var buffer        = new byte[fileChunkSize];

                    var numberOfBytesToSend = file.Read(buffer, 0, fileChunkSize);
                    fileTransfer.BytesRemaining -= numberOfBytesToSend;

                    var offset          = 0;
                    var socketSendCount = 0;
                    while (numberOfBytesToSend > 0)
                    {
                        var sendFileChunkResult =
                            await socket.SendWithTimeoutAsync(
                                buffer,
                                offset,
                                fileChunkSize,
                                SocketFlags.None,
                                timeoutMs).ConfigureAwait(false);

                        if (fileTransfer.OutboundFileTransferStalled)
                        {
                            const string fileTransferStalledErrorMessage =
                                "Aborting file transfer, client says that data is no longer being received (SendFileBytesAsync)";

                            fileTransfer.Status = FileTransferStatus.Cancelled;
                            fileTransfer.TransferCompleteTime = DateTime.Now;
                            fileTransfer.ErrorMessage         = fileTransferStalledErrorMessage;

                            return(Result.Ok());
                        }

                        if (sendFileChunkResult.Failure)
                        {
                            return(sendFileChunkResult);
                        }

                        fileTransfer.CurrentBytesSent = sendFileChunkResult.Value;
                        numberOfBytesToSend          -= fileTransfer.CurrentBytesSent;
                        offset += fileTransfer.CurrentBytesSent;
                        socketSendCount++;
                    }

                    fileTransfer.CurrentBytesSent = fileChunkSize;
                    fileTransfer.FileChunkSentCount++;

                    var checkPercentRemaining = fileTransfer.BytesRemaining / (float)fileTransfer.FileSizeInBytes;
                    var checkPercentComplete  = 1 - checkPercentRemaining;
                    var changeSinceLastUpdate = checkPercentComplete - fileTransfer.PercentComplete;

                    // this event fires on every file chunk sent event, which could be hurdreds of thousands
                    // of times depending on the file size and buffer size. Since this  event is only used
                    // by myself when debugging small test files, I limited this event to only fire when
                    // the size of the file will result in 10 file chunk sent events at most.
                    if (fileTransfer.FileSizeInBytes <= 10 * bufferSize)
                    {
                        SocketEventOccurred?.Invoke(this, new ServerEvent
                        {
                            EventType            = EventType.SentFileChunkToRemoteServer,
                            FileSizeInBytes      = fileTransfer.FileSizeInBytes,
                            CurrentFileBytesSent = fileChunkSize,
                            FileBytesRemaining   = fileTransfer.BytesRemaining,
                            FileChunkSentCount   = fileTransfer.FileChunkSentCount,
                            SocketSendCount      = socketSendCount,
                            FileTransferId       = fileTransfer.Id
                        });
                    }

                    // Report progress in intervals which are set by the user in the settings file
                    if (changeSinceLastUpdate < updateInterval)
                    {
                        continue;
                    }
                    fileTransfer.PercentComplete = checkPercentComplete;

                    FileTransferProgress?.Invoke(this, new ServerEvent
                    {
                        EventType = EventType.UpdateFileTransferProgress,
                        TotalFileBytesReceived = fileTransfer.TotalBytesReceived,
                        PercentComplete        = fileTransfer.PercentComplete,
                        FileTransferId         = fileTransfer.Id
                    });
                }

                fileTransfer.Status = FileTransferStatus.TransferComplete;
                fileTransfer.TransferCompleteTime = DateTime.Now;
                fileTransfer.PercentComplete      = 1;
                fileTransfer.CurrentBytesSent     = 0;
                fileTransfer.BytesRemaining       = 0;

                EventOccurred?.Invoke(this, new ServerEvent
                {
                    EventType              = EventType.SendFileBytesComplete,
                    RemoteServerIpAddress  = fileTransfer.RemoteServerInfo.SessionIpAddress,
                    RemoteServerPortNumber = fileTransfer.RemoteServerInfo.PortNumber,
                    FileTransferId         = fileTransfer.Id,
                });

                return(Result.Ok());
            }
        }
Пример #3
0
 void HandleSocketEvent(object sender, ServerEvent e)
 {
     SocketEventOccurred?.Invoke(sender, e);
 }
Пример #4
0
        public virtual async Task <Result> ReceiveFileAsync(
            FileTransfer fileTransfer,
            Socket socket,
            byte[] unreadBytes,
            CancellationToken token)
        {
            var bufferSize     = Settings.SocketSettings.BufferSize;
            var timeoutMs      = Settings.SocketSettings.SocketTimeoutInMilliseconds;
            var updateInterval = Settings.TransferUpdateInterval;
            var buffer         = new byte[bufferSize];

            fileTransfer.Status            = FileTransferStatus.InProgress;
            fileTransfer.TransferStartTime = DateTime.Now;

            EventOccurred?.Invoke(this, new ServerEvent
            {
                EventType              = EventType.ReceiveFileBytesStarted,
                FileTransferId         = fileTransfer.Id,
                RemoteServerIpAddress  = fileTransfer.RemoteServerInfo.SessionIpAddress,
                RemoteServerPortNumber = fileTransfer.RemoteServerInfo.PortNumber,
                FileTransferStartTime  = fileTransfer.TransferStartTime,
                FileName               = fileTransfer.FileName,
                FileSizeInBytes        = fileTransfer.FileSizeInBytes,
                LocalFolder            = fileTransfer.LocalFolderPath,
                RetryCounter           = fileTransfer.RetryCounter,
                RemoteServerRetryLimit = fileTransfer.RemoteServerRetryLimit
            });

            var receiveCount = 0;

            fileTransfer.TotalBytesReceived         = 0;
            fileTransfer.BytesRemaining             = fileTransfer.FileSizeInBytes;
            fileTransfer.PercentComplete            = 0;
            fileTransfer.InboundFileTransferStalled = false;

            if (unreadBytes.Length > 0)
            {
                fileTransfer.TotalBytesReceived += unreadBytes.Length;
                fileTransfer.BytesRemaining     -= unreadBytes.Length;

                lock (FileLock)
                {
                    var writeBytesToFile =
                        FileHelper.WriteBytesToFile(
                            fileTransfer.LocalFilePath,
                            unreadBytes,
                            unreadBytes.Length,
                            10);

                    if (writeBytesToFile.Failure)
                    {
                        return(writeBytesToFile);
                    }
                }

                EventOccurred?.Invoke(this, new ServerEvent
                {
                    EventType = EventType.CopySavedBytesToIncomingFile,
                    CurrentFileBytesReceived = unreadBytes.Length,
                    TotalFileBytesReceived   = fileTransfer.TotalBytesReceived,
                    FileSizeInBytes          = fileTransfer.FileSizeInBytes,
                    FileBytesRemaining       = fileTransfer.BytesRemaining,
                    FileTransferId           = fileTransfer.Id,
                });
            }

            // Read file bytes from transfer socket until
            //      1. the entire file has been received OR
            //      2. Data is no longer being received OR
            //      3, Transfer is canceled
            var receivedZeroBytesFromSocket = false;

            while (!receivedZeroBytesFromSocket)
            {
                if (token.IsCancellationRequested)
                {
                    fileTransfer.Status = FileTransferStatus.Cancelled;
                    fileTransfer.TransferCompleteTime = DateTime.Now;
                    fileTransfer.ErrorMessage         = "Cancellation requested";

                    return(Result.Ok());
                }

                var readFromSocket =
                    await socket.ReceiveWithTimeoutAsync(
                        buffer,
                        0,
                        bufferSize,
                        SocketFlags.None,
                        timeoutMs)
                    .ConfigureAwait(false);

                if (readFromSocket.Failure)
                {
                    return(readFromSocket);
                }

                fileTransfer.CurrentBytesReceived = readFromSocket.Value;
                if (fileTransfer.CurrentBytesReceived == 0)
                {
                    receivedZeroBytesFromSocket = true;
                    continue;
                }

                var receivedBytes = new byte[fileTransfer.CurrentBytesReceived];
                buffer.ToList().CopyTo(0, receivedBytes, 0, fileTransfer.CurrentBytesReceived);

                int fileWriteAttempts;
                lock (FileLock)
                {
                    var writeBytesToFile = FileHelper.WriteBytesToFile(
                        fileTransfer.LocalFilePath,
                        receivedBytes,
                        fileTransfer.CurrentBytesReceived,
                        999);

                    if (writeBytesToFile.Failure)
                    {
                        return(writeBytesToFile);
                    }

                    fileWriteAttempts = writeBytesToFile.Value + 1;
                }

                receiveCount++;
                fileTransfer.TotalBytesReceived += fileTransfer.CurrentBytesReceived;
                fileTransfer.BytesRemaining     -= fileTransfer.CurrentBytesReceived;
                var checkPercentComplete  = fileTransfer.TotalBytesReceived / (float)fileTransfer.FileSizeInBytes;
                var changeSinceLastUpdate = checkPercentComplete - fileTransfer.PercentComplete;

                if (fileWriteAttempts > 1)
                {
                    EventOccurred?.Invoke(this, new ServerEvent
                    {
                        EventType         = EventType.MultipleFileWriteAttemptsNeeded,
                        FileWriteAttempts = fileWriteAttempts,
                        PercentComplete   = fileTransfer.PercentComplete,
                        FileTransferId    = fileTransfer.Id,
                    });
                }

                // this event fires on every socket read event, which could be hurdreds of thousands
                // of times depending on the file size and buffer size. Since this  event is only used
                // by myself when debugging small test files, I limited this event to only fire when
                // the size of the file will result in 10 socket read events at most.
                if (fileTransfer.FileSizeInBytes <= 10 * bufferSize)
                {
                    SocketEventOccurred?.Invoke(this, new ServerEvent
                    {
                        EventType                = EventType.ReceivedFileBytesFromSocket,
                        SocketReadCount          = receiveCount,
                        BytesReceivedCount       = fileTransfer.CurrentBytesReceived,
                        CurrentFileBytesReceived = fileTransfer.CurrentBytesReceived,
                        TotalFileBytesReceived   = fileTransfer.TotalBytesReceived,
                        FileSizeInBytes          = fileTransfer.FileSizeInBytes,
                        FileBytesRemaining       = fileTransfer.BytesRemaining,
                        PercentComplete          = fileTransfer.PercentComplete,
                        FileTransferId           = fileTransfer.Id
                    });
                }

                // Report progress in intervals which are set by the user in the settings file
                if (changeSinceLastUpdate < updateInterval)
                {
                    continue;
                }

                fileTransfer.PercentComplete = checkPercentComplete;

                FileTransferProgress?.Invoke(this, new ServerEvent
                {
                    EventType = EventType.UpdateFileTransferProgress,
                    TotalFileBytesReceived = fileTransfer.TotalBytesReceived,
                    PercentComplete        = fileTransfer.PercentComplete,
                    FileTransferId         = fileTransfer.Id
                });
            }

            var fileTransferIsIncomplete = (fileTransfer.TotalBytesReceived / (float)fileTransfer.FileSizeInBytes) < 1;

            if (fileTransfer.InboundFileTransferStalled || fileTransferIsIncomplete)
            {
                const string fileTransferStalledErrorMessage =
                    "Data is no longer bring received from remote client, file transfer has been canceled (ReceiveFileAsync)";

                fileTransfer.Status       = FileTransferStatus.Stalled;
                fileTransfer.ErrorMessage = fileTransferStalledErrorMessage;

                return(Result.Ok());
            }

            fileTransfer.Status = FileTransferStatus.ConfirmedComplete;
            fileTransfer.TransferCompleteTime = DateTime.Now;
            fileTransfer.PercentComplete      = 1;
            fileTransfer.CurrentBytesReceived = 0;
            fileTransfer.BytesRemaining       = 0;

            EventOccurred?.Invoke(this, new ServerEvent
            {
                EventType                = EventType.ReceiveFileBytesComplete,
                FileTransferStartTime    = fileTransfer.TransferStartTime,
                FileTransferCompleteTime = DateTime.Now,
                FileSizeInBytes          = fileTransfer.FileSizeInBytes,
                FileTransferRate         = fileTransfer.TransferRate,
                RemoteServerIpAddress    = fileTransfer.RemoteServerInfo.SessionIpAddress,
                RemoteServerPortNumber   = fileTransfer.RemoteServerInfo.PortNumber,
                FileTransferId           = fileTransfer.Id
            });

            return(Result.Ok());
        }
Пример #5
0
 void HandleSocketEvent(object sender, ServerEvent serverEvent)
 {
     _eventLog.Add(serverEvent);
     SocketEventOccurred?.Invoke(sender, serverEvent);
 }
Пример #6
0
 void HandleSocketEventOccurred(object sender, ServerEvent serverEvent)
 {
     SocketEventOccurred?.Invoke(sender, serverEvent);
 }
Пример #7
0
        async Task <Result <byte[]> > ReceiveRequestBytesAsync(int totalBytes)
        {
            EventOccurred?.Invoke(this,
                                  new ServerEvent {
                EventType = EventType.ReceiveRequestBytesStarted
            });

            int currentRequestBytesReceived;
            var socketReadCount = 0;
            var bytesReceived   = 0;
            var bytesRemaining  = totalBytes;
            var requestBytes    = new List <byte>();
            var unreadByteCount = 0;

            if (_unreadBytes.Count > 0)
            {
                currentRequestBytesReceived = Math.Min(totalBytes, _unreadBytes.Count);
                var unreadRequestBytes = new byte[currentRequestBytesReceived];

                _unreadBytes.CopyTo(0, unreadRequestBytes, 0, currentRequestBytesReceived);
                requestBytes.AddRange(unreadRequestBytes.ToList());

                bytesReceived  += currentRequestBytesReceived;
                bytesRemaining -= currentRequestBytesReceived;

                EventOccurred?.Invoke(this, new ServerEvent
                {
                    EventType             = EventType.CopySavedBytesToRequestData,
                    UnreadBytesCount      = _unreadBytes.Count,
                    RequestLengthInBytes  = totalBytes,
                    RequestBytesRemaining = bytesRemaining
                });

                if (_unreadBytes.Count > totalBytes)
                {
                    var fileByteCount = _unreadBytes.Count - totalBytes;
                    var fileBytes     = new byte[fileByteCount];
                    _unreadBytes.CopyTo(totalBytes, fileBytes, 0, fileByteCount);
                    _unreadBytes = fileBytes.ToList();
                }
                else
                {
                    _unreadBytes = new List <byte>();
                }
            }

            currentRequestBytesReceived = 0;
            while (bytesRemaining > 0)
            {
                var readFromSocket =
                    await _socket.ReceiveWithTimeoutAsync(
                        _buffer,
                        0,
                        _bufferSize,
                        SocketFlags.None,
                        _timeoutMs)
                    .ConfigureAwait(false);

                if (readFromSocket.Failure)
                {
                    return(Result.Fail <byte[]>(readFromSocket.Error));
                }

                var lastBytesReceivedCount = readFromSocket.Value;
                currentRequestBytesReceived = Math.Min(bytesRemaining, lastBytesReceivedCount);

                var requestBytesFromSocket = new byte[currentRequestBytesReceived];
                _buffer.ToList().CopyTo(0, requestBytesFromSocket, 0, currentRequestBytesReceived);
                requestBytes.AddRange(requestBytesFromSocket.ToList());

                socketReadCount++;
                unreadByteCount = lastBytesReceivedCount - currentRequestBytesReceived;
                bytesReceived  += currentRequestBytesReceived;
                bytesRemaining -= currentRequestBytesReceived;

                SocketEventOccurred?.Invoke(this, new ServerEvent
                {
                    EventType                   = EventType.ReceivedRequestBytesFromSocket,
                    SocketReadCount             = socketReadCount,
                    BytesReceivedCount          = lastBytesReceivedCount,
                    CurrentRequestBytesReceived = currentRequestBytesReceived,
                    TotalRequestBytesReceived   = bytesReceived,
                    RequestLengthInBytes        = totalBytes,
                    RequestBytesRemaining       = bytesRemaining,
                    UnreadBytesCount            = unreadByteCount
                });
            }

            EventOccurred?.Invoke(this, new ServerEvent
            {
                EventType    = EventType.ReceiveRequestBytesComplete,
                RequestBytes = requestBytes.ToArray()
            });

            if (unreadByteCount == 0)
            {
                return(Result.Ok(requestBytes.ToArray()));
            }

            var unreadBytes = new byte[unreadByteCount];

            _buffer.ToList().CopyTo(currentRequestBytesReceived, unreadBytes, 0, unreadByteCount);
            _unreadBytes = unreadBytes.ToList();

            EventOccurred?.Invoke(this, new ServerEvent
            {
                EventType         = EventType.SaveUnreadBytesAfterAllRequestBytesReceived,
                ExpectedByteCount = currentRequestBytesReceived,
                UnreadBytesCount  = unreadByteCount
            });

            ReceivedFileBytes?.Invoke(this, _unreadBytes);
            return(Result.Ok(requestBytes.ToArray()));
        }