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)); }
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()); } }
void HandleSocketEvent(object sender, ServerEvent e) { SocketEventOccurred?.Invoke(sender, e); }
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()); }
void HandleSocketEvent(object sender, ServerEvent serverEvent) { _eventLog.Add(serverEvent); SocketEventOccurred?.Invoke(sender, serverEvent); }
void HandleSocketEventOccurred(object sender, ServerEvent serverEvent) { SocketEventOccurred?.Invoke(sender, serverEvent); }
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())); }