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; } } }); }
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)); }