private void Channel_Closed(object sender, ChannelEventArgs e) { var outputStream = OutputStream; if (outputStream != null) { outputStream.Flush(); } var extendedOutputStream = ExtendedOutputStream; if (extendedOutputStream != null) { extendedOutputStream.Flush(); } _asyncResult.IsCompleted = true; if (_callback != null) { // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => _callback(_asyncResult)); } ((EventWaitHandle)_asyncResult.AsyncWaitHandle).Set(); }
/// <summary> /// Waits for pending requests to finish, and channels to close. /// </summary> /// <param name="timeout">The maximum time to wait for the forwarded port to stop.</param> partial void InternalStop(TimeSpan timeout) { if (timeout == TimeSpan.Zero) { return; } var stopWatch = new Stopwatch(); stopWatch.Start(); // break out of loop when one of the following conditions are met: // * the forwarded port is restarted // * all pending requests have been processed and corresponding channel are closed // * the specified timeout has elapsed while (!IsStarted) { // break out of loop when all pending requests have been processed if (Interlocked.CompareExchange(ref _pendingRequests, 0, 0) == 0) { break; } // break out of loop when specified timeout has elapsed if (stopWatch.Elapsed >= timeout && timeout != SshNet.Session.InfiniteTimeSpan) { break; } // give channels time to process pending requests ThreadAbstraction.Sleep(50); } stopWatch.Stop(); }
partial void InternalStop(TimeSpan timeout) { if (timeout == TimeSpan.Zero) { return; } var stopWatch = new Stopwatch(); stopWatch.Start(); while (true) { // break out of loop when all pending requests have been processed if (Interlocked.CompareExchange(ref _pendingRequests, 0, 0) == 0) { break; } // break out of loop when specified timeout has elapsed if (stopWatch.Elapsed >= timeout && timeout != SshNet.Session.InfiniteTimeSpan) { break; } // give channels time to process pending requests ThreadAbstraction.Sleep(50); } stopWatch.Stop(); }
private void Session_ChannelOpening(object sender, MessageEventArgs <ChannelOpenMessage> e) { var channelOpenMessage = e.Message; var info = channelOpenMessage.Info as ForwardedTcpipChannelInfo; if (info != null) { // Ensure this is the corresponding request if (info.ConnectedAddress == BoundHost && info.ConnectedPort == BoundPort) { if (!IsStarted) { Session.SendMessage(new ChannelOpenFailureMessage(channelOpenMessage.LocalChannelNumber, "", ChannelOpenFailureMessage.AdministrativelyProhibited)); return; } ThreadAbstraction.ExecuteThread(() => { // capture the countdown event that we're adding a count to, as we need to make sure that we'll be signaling // that same instance; the instance field for the countdown event is re-initialize when the port is restarted // and that time there may still be pending requests var pendingChannelCountdown = _pendingChannelCountdown; pendingChannelCountdown.AddCount(); try { RaiseRequestReceived(info.OriginatorAddress, info.OriginatorPort); using ( var channel = Session.CreateChannelForwardedTcpip(channelOpenMessage.LocalChannelNumber, channelOpenMessage.InitialWindowSize, channelOpenMessage.MaximumPacketSize)) { channel.Exception += Channel_Exception; channel.Bind(new IPEndPoint(HostAddress, (int)Port), this); channel.Close(); } } catch (Exception exp) { RaiseExceptionEvent(exp); } finally { // take into account that CountdownEvent has since been disposed; when stopping the port we // wait for a given time for the channels to close, but once that timeout period has elapsed // the CountdownEvent will be disposed try { pendingChannelCountdown.Signal(); } catch (ObjectDisposedException) { } } }); } } }
public void ShouldExecuteActionOnSeparateThread() { DateTime? executionTime = null; int executionCount = 0; EventWaitHandle waitHandle = new ManualResetEvent(false); Action action = () => { ThreadAbstraction.Sleep(500); executionCount++; executionTime = DateTime.Now; waitHandle.Set(); }; DateTime start = DateTime.Now; ThreadAbstraction.ExecuteThread(action); Assert.AreEqual(0, executionCount); Assert.IsNull(executionTime); Assert.IsTrue(waitHandle.WaitOne(2000)); Assert.AreEqual(1, executionCount); Assert.IsNotNull(executionTime); var elapsedTime = executionTime.Value - start; Assert.IsTrue(elapsedTime > TimeSpan.Zero); Assert.IsTrue(elapsedTime > TimeSpan.FromMilliseconds(500)); Assert.IsTrue(elapsedTime < TimeSpan.FromMilliseconds(1000)); }
private void Channel_Closed(object sender, ChannelEventArgs e) { if (Stopping != null) { // Handle event on different thread ThreadAbstraction.ExecuteThread(() => Stopping(this, new EventArgs())); } _channel.Dispose(); _channelClosedWaitHandle.Set(); _input.Dispose(); _input = null; _dataReaderTaskCompleted.WaitOne(_session.ConnectionInfo.Timeout); _dataReaderTaskCompleted.Dispose(); _dataReaderTaskCompleted = null; _channel.DataReceived -= Channel_DataReceived; _channel.ExtendedDataReceived -= Channel_ExtendedDataReceived; _channel.Closed -= Channel_Closed; UnsubscribeFromSessionEvents(_session); if (Stopped != null) { // Handle event on different thread ThreadAbstraction.ExecuteThread(() => Stopped(this, new EventArgs())); } _channel = null; }
private void Session_MessageReceived(object sender, MessageEventArgs <Message> e) { if (e.Message is PasswordChangeRequiredMessage) { _session.UnRegisterMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); ThreadAbstraction.ExecuteThread(() => { try { var eventArgs = new AuthenticationPasswordChangeEventArgs(Username); // Raise an event to allow user to supply a new password if (PasswordExpired != null) { PasswordExpired(this, eventArgs); } // Send new authentication request with new password _session.SendMessage(new RequestMessagePassword(ServiceName.Connection, Username, _password, eventArgs.NewPassword)); } catch (Exception exp) { _exception = exp; _authenticationCompleted.Set(); } }); } }
private void Session_UserAuthenticationInformationRequestReceived(object sender, MessageEventArgs <InformationRequestMessage> e) { var informationRequestMessage = e.Message; var eventArgs = new AuthenticationPromptEventArgs(Username, informationRequestMessage.Instruction, informationRequestMessage.Language, informationRequestMessage.Prompts); ThreadAbstraction.ExecuteThread(() => { try { if (AuthenticationPrompt != null) { AuthenticationPrompt(this, eventArgs); } var informationResponse = new InformationResponseMessage(); foreach (var response in from r in eventArgs.Prompts orderby r.Id ascending select r.Response) { informationResponse.Responses.Add(response); } // Send information response message _session.SendMessage(informationResponse); } catch (Exception exp) { _exception = exp; _authenticationCompleted.Set(); } }); }
partial void InternalStart() { var addr = DnsAbstraction.GetHostAddresses(BoundHost)[0]; var ep = new IPEndPoint(addr, (int)BoundPort); _listener = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // TODO: decide if we want to have blocking socket #if FEATURE_SOCKET_SETSOCKETOPTION _listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true); #endif // FEATURE_SOCKET_SETSOCKETOPTION _listener.Bind(ep); _listener.Listen(1); // update bound port (in case original was passed as zero) BoundPort = (uint)((IPEndPoint)_listener.LocalEndPoint).Port; Session.ErrorOccured += Session_ErrorOccured; Session.Disconnected += Session_Disconnected; _listenerTaskCompleted = new ManualResetEvent(false); ThreadAbstraction.ExecuteThread(() => { try { #if FEATURE_SOCKET_EAP _stoppingListener = new ManualResetEvent(false); StartAccept(); _stoppingListener.WaitOne(); #elif FEATURE_SOCKET_APM while (true) { // accept new inbound connection var asyncResult = _listener.BeginAccept(AcceptCallback, _listener); // wait for the connection to be established asyncResult.AsyncWaitHandle.WaitOne(); } #elif FEATURE_SOCKET_TAP #error Accepting new socket connections is not implemented. #else #error Accepting new socket connections is not implemented. #endif } catch (ObjectDisposedException) { // BeginAccept will throw an ObjectDisposedException when the // socket is closed } catch (Exception ex) { RaiseExceptionEvent(ex); } finally { // mark listener stopped _listenerTaskCompleted.Set(); } }); }
/// <summary> /// Called when channel is closed by the server. /// </summary> protected override void OnClose() { base.OnClose(); // This timeout needed since when channel is closed it does not immediately becomes available // but it takes time for the server to clean up resource and allow new channels to be created. ThreadAbstraction.Sleep(100); }
private void StartReadAhead() { ThreadAbstraction.ExecuteThread(() => { while (!_endOfFileReceived && _exception == null) { // check if we should continue with the read-ahead loop // note that the EOF and exception check are not included // in this check as they do not require Read() to be // unblocked (or have already done this) if (!ContinueReadAhead()) { // unblock the Read() lock (_readLock) { Monitor.PulseAll(_readLock); } // break the read-ahead loop break; } // attempt to obtain the semaphore; this may time out when all semaphores are // in use due to pending read-aheads (which in turn can happen when the server // is slow to respond or when the session is broken) if (!_semaphore.Wait(ReadAheadWaitTimeoutInMilliseconds)) { // re-evaluate whether an exception occurred, and - if not - wait again continue; } // don't bother reading any more chunks if we received EOF, or an exception has occurred // while processing a chunk if (_endOfFileReceived || _exception != null) { break; } // start reading next chunk try { _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, ReadCompleted, new BufferedRead(_readAheadChunkIndex, _readAheadOffset)); } catch (Exception ex) { HandleFailure(ex); break; } // advance read-ahead offset _readAheadOffset += _chunkSize; _readAheadChunkIndex++; } _readAheadCompleted.Set(); }); }
private static int ReadByte(Stream stream) { var b = stream.ReadByte(); while (b < 0) { ThreadAbstraction.Sleep(100); b = stream.ReadByte(); } return(b); }
protected override void SetupMocks() { _seq = new MockSequence(); SftpSessionMock.InSequence(_seq) .Setup(p => p.CreateWaitHandleArray(It.IsNotNull <WaitHandle>(), It.IsNotNull <WaitHandle>())) .Returns <WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) => { _waitHandleArray[0] = disposingWaitHandle; _waitHandleArray[1] = semaphoreAvailableWaitHandle; return(_waitHandleArray); }); SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); SftpSessionMock.InSequence(_seq) .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); SftpSessionMock.InSequence(_seq) .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull <AsyncCallback>(), It.IsAny <BufferedRead>())) .Callback <byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) => { var asyncResult = new SftpReadAsyncResult(callback, state); asyncResult.SetAsCompleted(_chunk1, false); }) .Returns((SftpReadAsyncResult)null); SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); SftpSessionMock.InSequence(_seq) .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); SftpSessionMock.InSequence(_seq) .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull <AsyncCallback>(), It.IsAny <BufferedRead>())) .Callback <byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) => { ThreadAbstraction.ExecuteThread(() => { // signal that we're in the read-ahead for chunk2 _readAheadChunk2.Set(); // wait for client to start reading this chunk _readChunk2.WaitOne(TimeSpan.FromSeconds(5)); // sleep a short time to make sure the client is in the blocking wait Thread.Sleep(500); // complete async read of chunk2 with exception var asyncResult = new SftpReadAsyncResult(callback, state); asyncResult.SetAsCompleted(_exception, false); }); }) .Returns((SftpReadAsyncResult)null); SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); SftpSessionMock.InSequence(_seq) .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); }
public void ShouldThrowArgumentNullExceptionWhenActionIsNull() { const Action action = null; try { ThreadAbstraction.ExecuteThread(action); Assert.Fail(); } catch (ArgumentNullException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual("action", ex.ParamName); } }
/// <summary> /// Stops remote port forwarding. /// </summary> /// <param name="timeout">The maximum amount of time to wait for pending requests to finish processing.</param> protected override void StopPort(TimeSpan timeout) { // if the port not started, then there's nothing to stop if (!IsStarted) { return; } // mark forwarded port stopped, this also causes open of new channels to be rejected _isStarted = false; base.StopPort(timeout); // send global request to cancel direct tcpip Session.SendMessage(new GlobalRequestMessage(GlobalRequestName.CancelTcpIpForward, true, BoundHost, BoundPort)); // wait for response on global request to cancel direct tcpip or completion of message // listener loop (in which case response on global request can never be received) WaitHandle.WaitAny(new[] { _globalRequestResponse, Session.MessageListenerCompleted }, timeout); // unsubscribe from session events as either the tcpip forward is cancelled at the // server, or our session message loop has completed Session.RequestSuccessReceived -= Session_RequestSuccess; Session.RequestFailureReceived -= Session_RequestFailure; Session.ChannelOpenReceived -= Session_ChannelOpening; var startWaiting = DateTime.Now; while (true) { // break out of loop when all pending requests have been processed if (Interlocked.CompareExchange(ref _pendingRequests, 0, 0) == 0) { break; } // determine time elapsed since waiting for pending requests to finish var elapsed = DateTime.Now - startWaiting; // break out of loop when specified timeout has elapsed if (elapsed >= timeout && timeout != SshNet.Session.InfiniteTimeSpan) { break; } // give channels time to process pending requests ThreadAbstraction.Sleep(50); } }
private void Session_ChannelOpening(object sender, MessageEventArgs <ChannelOpenMessage> e) { var channelOpenMessage = e.Message; var info = channelOpenMessage.Info as ForwardedTcpipChannelInfo; if (info != null) { // Ensure this is the corresponding request if (info.ConnectedAddress == BoundHost && info.ConnectedPort == BoundPort) { if (!_isStarted) { Session.SendMessage(new ChannelOpenFailureMessage(channelOpenMessage.LocalChannelNumber, "", ChannelOpenFailureMessage.AdministrativelyProhibited)); return; } ThreadAbstraction.ExecuteThread(() => { Interlocked.Increment(ref _pendingRequests); try { RaiseRequestReceived(info.OriginatorAddress, info.OriginatorPort); using (var channel = Session.CreateChannelForwardedTcpip(channelOpenMessage.LocalChannelNumber, channelOpenMessage.InitialWindowSize, channelOpenMessage.MaximumPacketSize)) { channel.Exception += Channel_Exception; channel.Bind(new IPEndPoint(HostAddress, (int)Port), this); channel.Close(); } } catch (Exception exp) { RaiseExceptionEvent(exp); } finally { Interlocked.Decrement(ref _pendingRequests); } }); } } }
protected override void Act() { ThreadAbstraction.ExecuteThread(() => { Thread.Sleep(500); _reader.Dispose(); _disposeCompleted.Set(); }); try { _reader.Read(); Assert.Fail(); } catch (ObjectDisposedException ex) { _actualException = ex; } // Dispose may unblock Read() before the dispose has fully completed, so // let's wait until it has completed _disposeCompleted.WaitOne(500); }
protected override void SetupMocks() { _seq = new MockSequence(); SftpSessionMock.InSequence(_seq) .Setup(p => p.CreateWaitHandleArray(It.IsNotNull <WaitHandle>(), It.IsNotNull <WaitHandle>())) .Returns <WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) => { _waitHandleArray[0] = disposingWaitHandle; _waitHandleArray[1] = semaphoreAvailableWaitHandle; return(_waitHandleArray); }); SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); SftpSessionMock.InSequence(_seq) .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); SftpSessionMock.InSequence(_seq) .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull <AsyncCallback>(), It.IsAny <BufferedRead>())) .Callback <byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) => { var asyncResult = new SftpReadAsyncResult(callback, state); asyncResult.SetAsCompleted(_chunk1, false); }) .Returns((SftpReadAsyncResult)null); SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); SftpSessionMock.InSequence(_seq) .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); SftpSessionMock.InSequence(_seq) .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull <AsyncCallback>(), It.IsAny <BufferedRead>())) .Callback <byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) => { ThreadAbstraction.ExecuteThread(() => { // wait until the read-ahead for chunk3 has completed; this should allow // the read-ahead of chunk4 to start _readAheadChunk3Completed.WaitOne(TimeSpan.FromSeconds(3)); // wait until the semaphore wait to start with chunk4 has started _waitingForSemaphoreAfterCompletingChunk3.WaitOne(TimeSpan.FromSeconds(7)); // complete async read of chunk2 with exception var asyncResult = new SftpReadAsyncResult(callback, state); asyncResult.SetAsCompleted(_exception, false); // signal that read-ahead of chunk 2 has completed _readAheadChunk2Completed.Set(); }); }) .Returns((SftpReadAsyncResult)null); SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); SftpSessionMock.InSequence(_seq) .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); SftpSessionMock.InSequence(_seq) .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull <AsyncCallback>(), It.IsAny <BufferedRead>())) .Callback <byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) => { var asyncResult = new SftpReadAsyncResult(callback, state); asyncResult.SetAsCompleted(_chunk3, false); // signal that we've completed the read-ahead for chunk3 _readAheadChunk3Completed.Set(); }) .Returns((SftpReadAsyncResult)null); SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); SftpSessionMock.InSequence(_seq) .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) .Callback(() => _waitingForSemaphoreAfterCompletingChunk3.Set()) .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); }
partial void InternalStart() { var ip = IPAddress.Any; if (!string.IsNullOrEmpty(BoundHost)) { ip = DnsAbstraction.GetHostAddresses(BoundHost)[0]; } var ep = new IPEndPoint(ip, (int)BoundPort); _listener = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // TODO: decide if we want to have blocking socket #if FEATURE_SOCKET_SETSOCKETOPTION _listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); _listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true); #endif //FEATURE_SOCKET_SETSOCKETOPTION _listener.Bind(ep); _listener.Listen(5); Session.ErrorOccured += Session_ErrorOccured; Session.Disconnected += Session_Disconnected; _listenerCompleted = new ManualResetEvent(false); ThreadAbstraction.ExecuteThread(() => { try { #if FEATURE_SOCKET_EAP _stoppingListener = new ManualResetEvent(false); StartAccept(); _stoppingListener.WaitOne(); #elif FEATURE_SOCKET_APM while (true) { // accept new inbound connection var asyncResult = _listener.BeginAccept(AcceptCallback, _listener); // wait for the connection to be established asyncResult.AsyncWaitHandle.WaitOne(); } } catch (ObjectDisposedException) { // BeginAccept will throw an ObjectDisposedException when the // socket is closed #elif FEATURE_SOCKET_TAP #error Accepting new socket connections is not implemented. #else #error Accepting new socket connections is not implemented. #endif } catch (Exception ex) { RaiseExceptionEvent(ex); } finally { if (Session != null) { Session.ErrorOccured -= Session_ErrorOccured; Session.Disconnected -= Session_Disconnected; } // mark listener stopped _listenerCompleted.Set(); } }); }
/// <summary> /// Starts this shell. /// </summary> /// <exception cref="SshException">Shell is started.</exception> public void Start() { if (IsStarted) { throw new SshException("Shell is started."); } if (Starting != null) { Starting(this, new EventArgs()); } _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.ExtendedDataReceived += Channel_ExtendedDataReceived; _channel.Closed += Channel_Closed; _session.Disconnected += Session_Disconnected; _session.ErrorOccured += Session_ErrorOccured; _channel.Open(); _channel.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModes); _channel.SendShellRequest(); _channelClosedWaitHandle = new AutoResetEvent(false); // Start input stream listener _dataReaderTaskCompleted = new ManualResetEvent(false); ThreadAbstraction.ExecuteThread(() => { try { var buffer = new byte[_bufferSize]; while (_channel.IsOpen) { #if FEATURE_STREAM_TAP var readTask = _input.ReadAsync(buffer, 0, buffer.Length); var readWaitHandle = ((IAsyncResult)readTask).AsyncWaitHandle; if (WaitHandle.WaitAny(new[] { readWaitHandle, _channelClosedWaitHandle }) == 0) { var read = readTask.Result; _channel.SendData(buffer, 0, read); continue; } #elif FEATURE_STREAM_APM var asyncResult = _input.BeginRead(buffer, 0, buffer.Length, result => { // If input stream is closed and disposed already don't finish reading the stream if (_input == null) { return; } var read = _input.EndRead(result); _channel.SendData(buffer, 0, read); }, null); WaitHandle.WaitAny(new[] { asyncResult.AsyncWaitHandle, _channelClosedWaitHandle }); if (asyncResult.IsCompleted) { continue; } #else #error Async receive is not implemented. #endif break; } } catch (Exception exp) { RaiseError(new ExceptionEventArgs(exp)); } finally { _dataReaderTaskCompleted.Set(); } }); IsStarted = true; if (Started != null) { Started(this, new EventArgs()); } }
/// <summary> /// Begins the expect. /// </summary> /// <param name="timeout">The timeout.</param> /// <param name="callback">The callback.</param> /// <param name="state">The state.</param> /// <param name="expectActions">The expect actions.</param> /// <returns> /// An <see cref="IAsyncResult" /> that references the asynchronous operation. /// </returns> public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object state, params ExpectAction[] expectActions) { var text = string.Empty; // Create new AsyncResult object var asyncResult = new ExpectAsyncResult(callback, state); // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => { string expectActionResult = null; try { do { lock (_incoming) { if (_incoming.Count > 0) { text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); } if (text.Length > 0) { foreach (var expectAction in expectActions) { var match = expectAction.Expect.Match(text); if (match.Success) { var result = text.Substring(0, match.Index + match.Length); for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++) { // Remove processed items from the queue _incoming.Dequeue(); } expectAction.Action(result); if (callback != null) { callback(asyncResult); } expectActionResult = result; } } } } if (expectActionResult != null) { break; } if (timeout.Ticks > 0) { if (!_dataReceived.WaitOne(timeout)) { if (callback != null) { callback(asyncResult); } break; } } else { _dataReceived.WaitOne(); } } while (true); asyncResult.SetAsCompleted(expectActionResult, true); } catch (Exception exp) { asyncResult.SetAsCompleted(exp, true); } }); return(asyncResult); }
private void StartReadAhead() { ThreadAbstraction.ExecuteThread(() => { while (!_endOfFileReceived && _exception == null) { // check if we should continue with the read-ahead loop // note that the EOF and exception check are not included // in this check as they do not require Read() to be // unblocked (or have already done this) if (!ContinueReadAhead()) { // unblock the Read() lock (_readLock) { Monitor.PulseAll(_readLock); } // break the read-ahead loop break; } // attempt to obtain the semaphore; this may time out when all semaphores are // in use due to pending read-aheads (which in turn can happen when the server // is slow to respond or when the session is broken) if (!_semaphore.Wait(ReadAheadWaitTimeoutInMilliseconds)) { // re-evaluate whether an exception occurred, and - if not - wait again continue; } // don't bother reading any more chunks if we received EOF, an exception has occurred // or the current instance is disposed if (_endOfFileReceived || _exception != null) { break; } // start reading next chunk var bufferedRead = new BufferedRead(_readAheadChunkIndex, _readAheadOffset); try { // even if we know the size of the file and have read up to EOF, we still want // to keep reading (ahead) until we receive zero bytes from the remote host as // we do not want to rely purely on the reported file size // // if the offset of the read-ahead chunk is greater than that file size, then // we can expect to be reading the last (zero-byte) chunk and switch to synchronous // mode to avoid having multiple read-aheads that read beyond EOF if (_fileSize != null && (long)_readAheadOffset > _fileSize.Value) { var asyncResult = _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, null, bufferedRead); var data = _sftpSession.EndRead(asyncResult); ReadCompletedCore(bufferedRead, data); } else { _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, ReadCompleted, bufferedRead); } } catch (Exception ex) { HandleFailure(ex); break; } // advance read-ahead offset _readAheadOffset += _chunkSize; // increment index of read-ahead chunk _readAheadChunkIndex++; } _readAheadCompleted.Set(); }); }
partial void InternalStart() { var ip = IPAddress.Any; if (!string.IsNullOrEmpty(BoundHost)) { ip = DnsAbstraction.GetHostAddresses(BoundHost)[0]; } var ep = new IPEndPoint(ip, (int)BoundPort); _listener = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // TODO: decide if we want to have blocking socket #if FEATURE_SOCKET_SETSOCKETOPTION _listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); _listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true); #endif //FEATURE_SOCKET_SETSOCKETOPTION _listener.Bind(ep); _listener.Listen(5); Session.ErrorOccured += Session_ErrorOccured; Session.Disconnected += Session_Disconnected; _listenerCompleted = new ManualResetEvent(false); ThreadAbstraction.ExecuteThread(() => { try { #if FEATURE_SOCKET_EAP StartAccept(); #elif FEATURE_SOCKET_APM _listener.BeginAccept(AcceptCallback, _listener); #elif FEATURE_SOCKET_TAP #error Accepting new socket connections is not implemented. #else #error Accepting new socket connections is not implemented. #endif // wait until listener is stopped _listenerCompleted.WaitOne(); } catch (ObjectDisposedException) { // BeginAccept / AcceptAsync will throw an ObjectDisposedException when the // server is closed before the listener has started accepting connections. // // As we start accepting connection on a separate thread, this is possible // when the listener is stopped right after it was started. // mark listener stopped _listenerCompleted.Set(); } catch (Exception ex) { RaiseExceptionEvent(ex); // mark listener stopped _listenerCompleted.Set(); } finally { if (Session != null) { Session.ErrorOccured -= Session_ErrorOccured; Session.Disconnected -= Session_Disconnected; } } }); }