Browse Source

Merge pull request #131 from sshnet/develop

Prepare for 2016.1.0-beta.
Gert Driesen 8 năm trước cách đây
mục cha
commit
35ab7a98af
25 tập tin đã thay đổi với 338 bổ sung455 xóa
  1. 33 4
      build/build.proj
  2. 71 0
      build/sandcastle/new.shfbproj
  3. 6 3
      src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj
  4. 0 12
      src/Renci.SshNet.Silverlight/Session.SilverlightBrowser.cs
  5. 0 14
      src/Renci.SshNet.Silverlight/Session.SilverlightShared.cs
  6. 1 2
      src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj
  7. 1 17
      src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortDisposed.cs
  8. 1 17
      src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortDisposed.cs
  9. 1 17
      src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortDisposed.cs
  10. 0 1
      src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj
  11. 6 4
      src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj
  12. 0 206
      src/Renci.SshNet.WindowsPhone/Session.WP.cs
  13. 2 1
      src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs
  14. 43 7
      src/Renci.SshNet/Abstractions/SocketAbstraction.cs
  15. 2 2
      src/Renci.SshNet/BaseClient.cs
  16. 0 18
      src/Renci.SshNet/Common/SshData.cs
  17. 0 2
      src/Renci.SshNet/ForwardedPort.cs
  18. 72 60
      src/Renci.SshNet/ForwardedPortDynamic.NET.cs
  19. 3 3
      src/Renci.SshNet/Properties/CommonAssemblyInfo.cs
  20. 0 1
      src/Renci.SshNet/Renci.SshNet.csproj
  21. 6 3
      src/Renci.SshNet/ScpClient.NET.cs
  22. 4 0
      src/Renci.SshNet/ScpClient.cs
  23. 61 61
      src/Renci.SshNet/Session.cs
  24. 24 0
      test/Renci.SshNet.Shared.Tests/Abstractions/SocketAbstraction_CanWrite.cs
  25. 1 0
      test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.projitems

+ 33 - 4
build/build.proj

@@ -1,9 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Clean;CreatePackage;GenerateHelpFile" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project ToolsVersion="4.0" DefaultTargets="Clean;CreateNuGetPackage;CreateBinPackage;GenerateHelpFile" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+	<UsingTask TaskName="Zip" AssemblyFile="$(MSBuildThisFileDirectory)target\nuget\packages\$(MSBuildTasksPackageId).$(MSBuildTasksPackageVersion)\tools\MSBuild.Community.Tasks.dll"/>
 	<PropertyGroup>
 		<Configuration Condition="'$(Configuration)' == ''">Release</Configuration>
 		<BuildRoot>$(MSBuildThisFileDirectory)</BuildRoot>
 		<NuGetExe>$(BuildRoot)target\nuget\nuget.exe</NuGetExe>
+		<MSBuildTasksPackageId>MSBuildTasks</MSBuildTasksPackageId>
+		<MSBuildTasksPackageVersion>1.5.0.214</MSBuildTasksPackageVersion>
 	</PropertyGroup>
 	<ItemGroup>
 		<VisualStudioVersion Include="2012">
@@ -76,7 +79,7 @@
 		</ItemGroup>
 		<MSBuild Projects="@(ProjectToBuild)" Targets="Rebuild"/>
 	</Target>
-	<Target Name="CreatePackage" DependsOnTargets="CopyBuildOutputToPackage">
+	<Target Name="CreateNuGetPackage" DependsOnTargets="CopyBuildOutputToPackage">
 		<Exec Command="$(NuGetExe) pack $(MSBuildThisFileDirectory)nuget\SSH.NET.nuspec -OutputDirectory &quot;$(MSBuildThisFileDirectory)target&quot; -BasePath &quot;$(MSBuildThisFileDirectory)target\package&quot; -NonInteractive"/>
 	</Target>
 	<Target Name="CopyBuildOutputToPackage" DependsOnTargets="Build" Outputs="%(TargetFramework.Identity)">
@@ -87,11 +90,37 @@
 		</ItemGroup>
 		<Copy SourceFiles="@(BuildOutput)" DestinationFolder="$(MSBuildThisFileDirectory)target\package\lib\%(TargetFramework.Moniker)"/>
 	</Target>
-	<Target Name="GenerateHelpFile" DependsOnTargets="Build">
+	<Target Name="GenerateHelpFile" DependsOnTargets="Build;CheckReleaseVersion">
 		<Error Text="Please install Sandcastle, and ensure the SHFBFolder environment variable is set." Condition="'$(SHFBFolder)'==''"/>
 		<MSBuild Projects="$(MSBuildThisFileDirectory)sandcastle\SSH.NET.shfbproj"/>
+		<Move SourceFiles="$(MSBuildThisFileDirectory)target\help\SshNet.Help.chm" DestinationFiles="$(MSBuildThisFileDirectory)target\SSH.NET-$(ReleaseVersion)-help.chm"/>
+	</Target>
+	<Target Name="CopyBuildOutputToBin" DependsOnTargets="Build" Outputs="%(TargetFramework.Identity)">
+		<ItemGroup>
+			<BuildOutput Remove="@(BuildOutput)"/>
+			<BuildOutput Include="$(MSBuildThisFileDirectory)..\src\%(TargetFramework.OutputDirectory)\*.dll"/>
+			<BuildOutput Include="$(MSBuildThisFileDirectory)..\src\%(TargetFramework.OutputDirectory)\*.xml"/>
+		</ItemGroup>
+		<Copy SourceFiles="@(BuildOutput)" DestinationFolder="$(MSBuildThisFileDirectory)target\bin\lib\%(TargetFramework.Moniker)"/>
+	</Target>
+	<Target Name="CreateBinPackage" DependsOnTargets="PrepareMSBuildTasksPackage;CopyBuildOutputToBin;CheckReleaseVersion">
+		<ItemGroup>
+			<Files Remove="@(Files)"/>
+			<Files Include="$(MSBuildThisFileDirectory)..\LICENSE"/>
+		</ItemGroup>
+		<Copy SourceFiles="@(Files)" DestinationFolder="$(MSBuildThisFileDirectory)target\bin\%(RecursiveDir)"/>
+		<ItemGroup>
+			<Files Remove="@(Files)"/>
+			<Files Include="$(MSBuildThisFileDirectory)target\bin\**"/>
+		</ItemGroup>
+		<Zip ZipFileName="$(MSBuildThisFileDirectory)target\SSH.NET-$(ReleaseVersion)-bin.zip" Files="@(Files)" WorkingDirectory="$(MSBuildThisFileDirectory)target\bin"/>
+	</Target>
+	<Target Name="PrepareMSBuildTasksPackage" DependsOnTargets="DownloadNuGet">
+		<Exec Command="$(NuGetExe) install $(MSBuildTasksPackageId) -Version $(MSBuildTasksPackageVersion) -OutputDirectory &quot;$(MSBuildThisFileDirectory)target\nuget\packages&quot; -Verbosity quiet"/>
+	</Target>
+	<Target Name="CheckReleaseVersion" Condition="'$(ReleaseVersion)'==''">
+		<Error Text= "Please specify the version number of the release (using the &quot;ReleaseVersion&quot; property)."/>
 	</Target>
-	
 	<UsingTask TaskName="DownloadFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
 		<ParameterGroup>
 			<Address ParameterType="System.String" Required="true"/>

+ 71 - 0
build/sandcastle/new.shfbproj

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <!-- The configuration and platform will be used to determine which assemblies to include from solution and
+				 project documentation sources -->
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{6c35cd41-3f6e-47c1-a805-1aab0ac88b36}</ProjectGuid>
+    <SHFBSchemaVersion>2015.6.5.0</SHFBSchemaVersion>
+    <!-- AssemblyName, Name, and RootNamespace are not used by SHFB but Visual Studio adds them anyway -->
+    <AssemblyName>Documentation</AssemblyName>
+    <RootNamespace>Documentation</RootNamespace>
+    <Name>Documentation</Name>
+    <!-- SHFB properties -->
+    <FrameworkVersion>.NET Framework 4.0</FrameworkVersion>
+    <OutputPath>D:\development\SSH.NET\build\target\help\</OutputPath>
+    <HtmlHelpName>Documentation</HtmlHelpName>
+    <Language>en-US</Language>
+    <SaveComponentCacheCapacity>100</SaveComponentCacheCapacity>
+    <BuildAssemblerVerbosity>OnlyWarningsAndErrors</BuildAssemblerVerbosity>
+    <HelpFileFormat>Markdown</HelpFileFormat>
+    <IndentHtml>False</IndentHtml>
+    <KeepLogFile>False</KeepLogFile>
+    <DisableCodeBlockComponent>False</DisableCodeBlockComponent>
+    <CleanIntermediates>True</CleanIntermediates>
+    <DocumentationSources>
+      <DocumentationSource sourceFile="D:\development\SSH.NET\src\Renci.SshNet\bin\Debug\Renci.SshNet.dll" />
+<DocumentationSource sourceFile="D:\development\SSH.NET\src\Renci.SshNet\bin\Debug\Renci.SshNet.xml" /></DocumentationSources>
+    <HelpFileVersion>1.0.0.0</HelpFileVersion>
+    <MaximumGroupParts>2</MaximumGroupParts>
+    <NamespaceGrouping>False</NamespaceGrouping>
+    <SyntaxFilters>Standard</SyntaxFilters>
+    <SdkLinkTarget>Blank</SdkLinkTarget>
+    <RootNamespaceContainer>False</RootNamespaceContainer>
+    <PresentationStyle>Markdown</PresentationStyle>
+    <Preliminary>False</Preliminary>
+    <NamingMethod>Guid</NamingMethod>
+    <HelpTitle>A Sandcastle Documented Class Library</HelpTitle>
+    <ContentPlacement>AboveNamespaces</ContentPlacement>
+  </PropertyGroup>
+  <!-- There are no properties for these groups.  AnyCPU needs to appear in order for Visual Studio to perform
+			 the build.  The others are optional common platform types that may appear. -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Win32' ">
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Win32' ">
+  </PropertyGroup>
+  <!-- Import the SHFB build targets -->
+  <Import Project="$(SHFBROOT)\SandcastleHelpFileBuilder.targets" />
+  <!-- The pre-build and post-build event properties must appear *after* the targets file import in order to be
+			 evaluated correctly. -->
+  <PropertyGroup>
+    <PreBuildEvent>
+    </PreBuildEvent>
+    <PostBuildEvent>
+    </PostBuildEvent>
+    <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+  </PropertyGroup>
+</Project>

+ 6 - 3
src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj

@@ -55,7 +55,6 @@
     <AssemblyOriginatorKeyFile>..\Renci.SshNet.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Microsoft.CSharp, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
     <Reference Include="mscorlib" />
     <Reference Include="SshNet.Security.Cryptography">
       <HintPath>..\..\packages\SshNet.Security.Cryptography.1.2.0\lib\sl4\SshNet.Security.Cryptography.dll</HintPath>
@@ -366,6 +365,9 @@
     <Compile Include="..\Renci.SshNet\Messages\Authentication\SuccessMessage.cs">
       <Link>Messages\Authentication\SuccessMessage.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs">
+      <Link>Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Messages\Connection\ChannelCloseMessage.cs">
       <Link>Messages\Connection\ChannelCloseMessage.cs</Link>
     </Compile>
@@ -477,6 +479,9 @@
     <Compile Include="..\Renci.SshNet\Messages\Connection\RequestSuccessMessage.cs">
       <Link>Messages\Connection\RequestSuccessMessage.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Messages\Connection\TcpIpForwardGlobalRequestMessage.cs">
+      <Link>Messages\Connection\TcpIpForwardGlobalRequestMessage.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Messages\Message.cs">
       <Link>Messages\Message.cs</Link>
     </Compile>
@@ -896,8 +901,6 @@
     <Compile Include="..\Renci.SshNet\Properties\CommonAssemblyInfo.cs">
       <Link>Properties\CommonAssemblyInfo.cs</Link>
     </Compile>
-    <Compile Include="Session.SilverlightBrowser.cs" />
-    <Compile Include="Session.SilverlightShared.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="..\Renci.SshNet.snk">

+ 0 - 12
src/Renci.SshNet.Silverlight/Session.SilverlightBrowser.cs

@@ -1,12 +0,0 @@
-using Renci.SshNet.Messages;
-
-namespace Renci.SshNet
-{
-    public partial class Session
-    {
-        partial void HandleMessageCore(Message message)
-        {
-            this.HandleMessage((dynamic) message);
-        }
-    }
-}

+ 0 - 14
src/Renci.SshNet.Silverlight/Session.SilverlightShared.cs

@@ -1,14 +0,0 @@
-namespace Renci.SshNet
-{
-    public partial class Session
-    {
-        /// <summary>
-        /// Gets a value indicating whether the socket is connected.
-        /// </summary>
-        /// <param name="isConnected"><c>true</c> if the socket is connected; otherwise, <c>false</c></param>
-        partial void IsSocketConnected(ref bool isConnected)
-        {
-            isConnected = (_socket != null && _socket.Connected);
-        }
-    }
-}

+ 1 - 2
src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj

@@ -60,7 +60,6 @@
     <AssemblyOriginatorKeyFile>..\Renci.SshNet.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Microsoft.CSharp, Version=5.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
     <Reference Include="mscorlib" />
     <Reference Include="SshNet.Security.Cryptography, Version=1.2.0.0, Culture=neutral, PublicKeyToken=2fa9220ff3eadda4, processorArchitecture=MSIL">
       <HintPath>..\..\packages\SshNet.Security.Cryptography.1.2.0\lib\sl5\SshNet.Security.Cryptography.dll</HintPath>
@@ -923,7 +922,7 @@
       <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
         <SilverlightProjectProperties />
       </FlavorProperties>
-      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
+      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 1 - 17
src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortDisposed.cs

@@ -13,7 +13,6 @@ namespace Renci.SshNet.Tests.Classes
         private ForwardedPortDynamic _forwardedPort;
         private IList<EventArgs> _closingRegister;
         private IList<ExceptionEventArgs> _exceptionRegister;
-        private ObjectDisposedException _actualException;
         private IPEndPoint _endpoint;
 
         [TestInitialize]
@@ -47,22 +46,7 @@ namespace Renci.SshNet.Tests.Classes
 
         protected void Act()
         {
-            try
-            {
-                _forwardedPort.Stop();
-                Assert.Fail();
-            }
-            catch (ObjectDisposedException ex)
-            {
-                _actualException = ex;
-            }
-        }
-
-        [TestMethod]
-        public void StopShouldThrowObjectDisposedException()
-        {
-            Assert.IsNotNull(_actualException);
-            Assert.AreEqual(_forwardedPort.GetType().FullName, _actualException.ObjectName);
+            _forwardedPort.Stop();
         }
 
         [TestMethod]

+ 1 - 17
src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortDisposed.cs

@@ -11,7 +11,6 @@ namespace Renci.SshNet.Tests.Classes
         private ForwardedPortLocal _forwardedPort;
         private IList<EventArgs> _closingRegister;
         private IList<ExceptionEventArgs> _exceptionRegister;
-        private ObjectDisposedException _actualException;
 
         [TestInitialize]
         public void Setup()
@@ -43,22 +42,7 @@ namespace Renci.SshNet.Tests.Classes
 
         protected void Act()
         {
-            try
-            {
-                _forwardedPort.Stop();
-                Assert.Fail();
-            }
-            catch (ObjectDisposedException ex)
-            {
-                _actualException = ex;
-            }
-        }
-
-        [TestMethod]
-        public void StopShouldThrowObjectDisposedException()
-        {
-            Assert.IsNotNull(_actualException);
-            Assert.AreEqual(_forwardedPort.GetType().FullName, _actualException.ObjectName);
+            _forwardedPort.Stop();
         }
 
         [TestMethod]

+ 1 - 17
src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortDisposed.cs

@@ -14,7 +14,6 @@ namespace Renci.SshNet.Tests.Classes
         private IPEndPoint _remoteEndpoint;
         private IList<EventArgs> _closingRegister;
         private IList<ExceptionEventArgs> _exceptionRegister;
-        private ObjectDisposedException _actualException;
 
         [TestInitialize]
         public void Setup()
@@ -49,22 +48,7 @@ namespace Renci.SshNet.Tests.Classes
 
         protected void Act()
         {
-            try
-            {
-                _forwardedPort.Stop();
-                Assert.Fail();
-            }
-            catch (ObjectDisposedException ex)
-            {
-                _actualException = ex;
-            }
-        }
-
-        [TestMethod]
-        public void StopShouldThrowObjectDisposedException()
-        {
-            Assert.IsNotNull(_actualException);
-            Assert.AreEqual(_forwardedPort.GetType().FullName, _actualException.ObjectName);
+            _forwardedPort.Stop();
         }
 
         [TestMethod]

+ 0 - 1
src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj

@@ -41,7 +41,6 @@
     <AssemblyOriginatorKeyFile>..\Renci.SshNet.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Microsoft.CSharp" />
     <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
     <Reference Include="Moq">
       <HintPath>..\..\packages\Moq.4.2.1409.1722\lib\net40\Moq.dll</HintPath>

+ 6 - 4
src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj

@@ -356,6 +356,9 @@
     <Compile Include="..\Renci.SshNet\Messages\Authentication\SuccessMessage.cs">
       <Link>Messages\Authentication\SuccessMessage.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs">
+      <Link>Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Messages\Connection\ChannelCloseMessage.cs">
       <Link>Messages\Connection\ChannelCloseMessage.cs</Link>
     </Compile>
@@ -467,6 +470,9 @@
     <Compile Include="..\Renci.SshNet\Messages\Connection\RequestSuccessMessage.cs">
       <Link>Messages\Connection\RequestSuccessMessage.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Messages\Connection\TcpIpForwardGlobalRequestMessage.cs">
+      <Link>Messages\Connection\TcpIpForwardGlobalRequestMessage.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Messages\Message.cs">
       <Link>Messages\Message.cs</Link>
     </Compile>
@@ -701,9 +707,6 @@
     <Compile Include="..\Renci.SshNet\Session.cs">
       <Link>Session.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\Session.SilverlightShared.cs">
-      <Link>Session.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\SftpClient.cs">
       <Link>SftpClient.cs</Link>
     </Compile>
@@ -885,7 +888,6 @@
     <Compile Include="..\Renci.SshNet\Properties\CommonAssemblyInfo.cs">
       <Link>Properties\CommonAssemblyInfo.cs</Link>
     </Compile>
-    <Compile Include="Session.WP.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config">

+ 0 - 206
src/Renci.SshNet.WindowsPhone/Session.WP.cs

@@ -1,206 +0,0 @@
-using System;
-using Renci.SshNet.Messages.Transport;
-using Renci.SshNet.Messages;
-using Renci.SshNet.Messages.Authentication;
-using Renci.SshNet.Messages.Connection;
-using System.Diagnostics;
-
-namespace Renci.SshNet
-{
-    public partial class Session
-    {
-        partial void HandleMessageCore(Message message)
-        {
-            if (message == null)
-                throw new ArgumentNullException("message");
-
-            var disconnectMessage = message as DisconnectMessage;
-            if (disconnectMessage != null)
-            {
-                HandleMessage(disconnectMessage);
-                return;
-            }
-
-            var serviceRequestMessage = message as ServiceRequestMessage;
-            if (serviceRequestMessage != null)
-            {
-                HandleMessage(serviceRequestMessage);
-                return;
-            }
-
-            var serviceAcceptMessage = message as ServiceAcceptMessage;
-            if (serviceAcceptMessage != null)
-            {
-                HandleMessage(serviceAcceptMessage);
-                return;
-            }
-
-            var keyExchangeInitMessage = message as KeyExchangeInitMessage;
-            if (keyExchangeInitMessage != null)
-            {
-                HandleMessage(keyExchangeInitMessage);
-                return;
-            }
-
-            var newKeysMessage = message as NewKeysMessage;
-            if (newKeysMessage != null)
-            {
-                HandleMessage(newKeysMessage);
-                return;
-            }
-
-            var requestMessage = message as RequestMessage;
-            if (requestMessage != null)
-            {
-                HandleMessage(requestMessage);
-                return;
-            }
-
-            var failureMessage = message as FailureMessage;
-            if (failureMessage != null)
-            {
-                HandleMessage(failureMessage);
-                return;
-            }
-
-            var successMessage = message as SuccessMessage;
-            if (successMessage != null)
-            {
-                HandleMessage(successMessage);
-                return;
-            }
-
-            var bannerMessage = message as BannerMessage;
-            if (bannerMessage != null)
-            {
-                HandleMessage(bannerMessage);
-                return;
-            }
-
-            var globalRequestMessage = message as GlobalRequestMessage;
-            if (globalRequestMessage != null)
-            {
-                HandleMessage(globalRequestMessage);
-                return;
-            }
-
-            var requestSuccessMessage = message as RequestSuccessMessage;
-            if (requestSuccessMessage != null)
-            {
-                HandleMessage(requestSuccessMessage);
-                return;
-            }
-
-            var requestFailureMessage = message as RequestFailureMessage;
-            if (requestFailureMessage != null)
-            {
-                HandleMessage(requestFailureMessage);
-                return;
-            }
-
-            var channelOpenMessage = message as ChannelOpenMessage;
-            if (channelOpenMessage != null)
-            {
-                HandleMessage(channelOpenMessage);
-                return;
-            }
-
-            var channelOpenConfirmationMessage = message as ChannelOpenConfirmationMessage;
-            if (channelOpenConfirmationMessage != null)
-            {
-                HandleMessage(channelOpenConfirmationMessage);
-                return;
-            }
-
-            var channelOpenFailureMessage = message as ChannelOpenFailureMessage;
-            if (channelOpenFailureMessage != null)
-            {
-                HandleMessage(channelOpenFailureMessage);
-                return;
-            }
-
-            var channelWindowAdjustMessage = message as ChannelWindowAdjustMessage;
-            if (channelWindowAdjustMessage != null)
-            {
-                HandleMessage(channelWindowAdjustMessage);
-                return;
-            }
-
-            var channelDataMessage = message as ChannelDataMessage;
-            if (channelDataMessage != null)
-            {
-                HandleMessage(channelDataMessage);
-                return;
-            }
-
-            var channelExtendedDataMessage = message as ChannelExtendedDataMessage;
-            if (channelExtendedDataMessage != null)
-            {
-                HandleMessage(channelExtendedDataMessage);
-                return;
-            }
-
-            var channelEofMessage = message as ChannelEofMessage;
-            if (channelEofMessage != null)
-            {
-                HandleMessage(channelEofMessage);
-                return;
-            }
-
-            var channelCloseMessage = message as ChannelCloseMessage;
-            if (channelCloseMessage != null)
-            {
-                HandleMessage(channelCloseMessage);
-                return;
-            }
-
-            var channelRequestMessage = message as ChannelRequestMessage;
-            if (channelRequestMessage != null)
-            {
-                HandleMessage(channelRequestMessage);
-                return;
-            }
-
-            var channelSuccessMessage = message as ChannelSuccessMessage;
-            if (channelSuccessMessage != null)
-            {
-                HandleMessage(channelSuccessMessage);
-                return;
-            }
-
-            var channelFailureMessage = message as ChannelFailureMessage;
-            if (channelFailureMessage != null)
-            {
-                HandleMessage(channelFailureMessage);
-                return;
-            }
-
-            var ignoreMessage = message as IgnoreMessage;
-            if (ignoreMessage != null)
-            {
-                HandleMessage(ignoreMessage);
-                return;
-            }
-
-            var unimplementedMessage = message as UnimplementedMessage;
-            if (unimplementedMessage != null)
-            {
-                HandleMessage(unimplementedMessage);
-                return;
-            }
-
-            var debugMessage = message as DebugMessage;
-            if (debugMessage != null)
-            {
-                HandleMessage(debugMessage);
-                return;
-            }
-
-            Debug.WriteLine(
-                "SSH.NET WARNING: unknown message type {0} - may need to add new type to Session.WP.cs, HandleMessageCore method",
-                message.GetType().FullName);
-
-            HandleMessage(message);
-        }
-    }
-}

+ 2 - 1
src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs

@@ -1,4 +1,5 @@
-using System.Diagnostics;
+using System;
+using System.Diagnostics;
 #if FEATURE_DIAGNOSTICS_TRACESOURCE
 using System.Threading;
 #endif // FEATURE_DIAGNOSTICS_TRACESOURCE

+ 43 - 7
src/Renci.SshNet/Abstractions/SocketAbstraction.cs

@@ -25,9 +25,17 @@ namespace Renci.SshNet.Abstractions
 
         }
 
+        /// <summary>
+        /// Returns a value indicating whether the specified <see cref="Socket"/> can be used
+        /// to send data.
+        /// </summary>
+        /// <param name="socket">The <see cref="Socket"/> to check.</param>
+        /// <returns>
+        /// <c>true</c> if <paramref name="socket"/> can be written to; otherwise, <c>false</c>.
+        /// </returns>
         public static bool CanWrite(Socket socket)
         {
-            if (socket.Connected)
+            if (socket != null && socket.Connected)
             {
 #if FEATURE_SOCKET_POLL
                 return socket.Poll(-1, SelectMode.SelectWrite);
@@ -46,21 +54,49 @@ namespace Renci.SshNet.Abstractions
 #if FEATURE_SOCKET_EAP
             var connectCompleted = new ManualResetEvent(false);
             var args = new SocketAsyncEventArgs
-            {
-                UserToken = connectCompleted,
-                RemoteEndPoint = remoteEndpoint
-            };
+                {
+                    UserToken = connectCompleted,
+                    RemoteEndPoint = remoteEndpoint
+                };
             args.Completed += ConnectCompleted;
 
             if (socket.ConnectAsync(args))
             {
                 if (!connectCompleted.WaitOne(connectTimeout))
+                {
+                    // avoid ObjectDisposedException in ConnectCompleted
+                    args.Completed -= ConnectCompleted;
+                    // dispose Socket
+                    socket.Dispose();
+                    // dispose ManualResetEvent
+                    connectCompleted.Dispose();
+                    // dispose SocketAsyncEventArgs
+                    args.Dispose();
+
                     throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
-                        "Connection failed to establish within {0:F0} milliseconds.", connectTimeout.TotalMilliseconds));
+                                                                         "Connection failed to establish within {0:F0} milliseconds.",
+                                                                         connectTimeout.TotalMilliseconds));
+                }
             }
 
+            // dispose ManualResetEvent
+            connectCompleted.Dispose();
+
             if (args.SocketError != SocketError.Success)
-                throw new SocketException((int) args.SocketError);
+            {
+                var socketError = (int) args.SocketError;
+
+                // dispose Socket
+                socket.Dispose();
+                // dispose SocketAsyncEventArgs
+                args.Dispose();
+
+                throw new SocketException(socketError);
+            }
+
+            // dispose SocketAsyncEventArgs
+            args.Dispose();
+
             return socket;
 #elif FEATURE_SOCKET_APM
             var connectResult = socket.BeginConnect(remoteEndpoint, null, null);

+ 2 - 2
src/Renci.SshNet/BaseClient.cs

@@ -222,7 +222,7 @@ namespace Renci.SshNet
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
         public void Disconnect()
         {
-            DiagnosticAbstraction.Log(string.Format("{0} Disconnecting client", DateTime.Now.Ticks));
+            DiagnosticAbstraction.Log("Disconnecting client.");
 
             CheckDisposed();
 
@@ -319,7 +319,7 @@ namespace Renci.SshNet
         /// </summary>
         public void Dispose()
         {
-            DiagnosticAbstraction.Log(string.Format("{0} Disposing client", DateTime.Now.Ticks));
+            DiagnosticAbstraction.Log("Disposing client.");
 
             Dispose(true);
             GC.SuppressFinalize(this);

+ 0 - 18
src/Renci.SshNet/Common/SshData.cs

@@ -255,24 +255,6 @@ namespace Renci.SshNet.Common
             return _stream.ReadBinary();
         }
 
-        //protected byte[] ReadBinaryDebug()
-        //{
-        //    DiagnosticAbstraction.Log("Stream Position:" + _stream.Position);
-        //    var data = _stream.ReadBytes(4);
-        //    DiagnosticAbstraction.Log("Binary Length Bytes:" + Session.ToHex(data, 0));
-        //    var length = (uint)(data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]);
-        //    DiagnosticAbstraction.Log("Binary Length:" + length);
-
-        //    if (length > int.MaxValue)
-        //    {
-        //        throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Data longer than {0} is not supported.", int.MaxValue));
-        //    }
-
-        //    var binary = _stream.ReadBytes((int) length);
-        //    DiagnosticAbstraction.Log("Binary Bytes:" + Session.ToHex(binary, 0));
-        //    return binary;
-        //}
-
         /// <summary>
         /// Reads next name-list data type from internal buffer.
         /// </summary>

+ 0 - 2
src/Renci.SshNet/ForwardedPort.cs

@@ -71,8 +71,6 @@ namespace Renci.SshNet
         /// </summary>
         public virtual void Stop()
         {
-            CheckDisposed();
-
             if (IsStarted)
             {
                 StopPort(Session.ConnectionInfo.Timeout);

+ 72 - 60
src/Renci.SshNet/ForwardedPortDynamic.NET.cs

@@ -435,106 +435,118 @@ namespace Renci.SshNet
                 return false;
             }
 
-            IPAddress ipAddress;
-            byte[] addressBuffer;
+            var host = GetSocks5Host(addressType, socket, timeout);
+            if (host == null)
+            {
+                // SOCKS client closed connection
+                return false;
+            }
+
+            var portBuffer = new byte[2];
+            if (SocketAbstraction.Read(socket, portBuffer, 0, portBuffer.Length, timeout) == 0)
+            {
+                // SOCKS client closed connection
+                return false;
+            }
+
+            var port = (uint)(portBuffer[0] * 256 + portBuffer[1]);
+
+            RaiseRequestReceived(host, port);
+
+            channel.Open(host, port, this, socket);
+
+            var socksReply = CreateSocks5Reply(channel.IsOpen);
+
+            SocketAbstraction.Send(socket, socksReply, 0, socksReply.Length);
+
+            return true;
+        }
+
+        private static string GetSocks5Host(int addressType, Socket socket, TimeSpan timeout)
+        {
             switch (addressType)
             {
-                case 0x01:
+                case 0x01: // IPv4
                     {
-                        addressBuffer = new byte[4];
+                        var addressBuffer = new byte[4];
                         if (SocketAbstraction.Read(socket, addressBuffer, 0, 4, timeout) == 0)
                         {
                             // SOCKS client closed connection
-                            return false;
+                            return null;
                         }
 
-                        ipAddress = new IPAddress(addressBuffer);
+                        var ipv4 = new IPAddress(addressBuffer);
+                        return ipv4.ToString();
                     }
-                    break;
-                case 0x03:
+                case 0x03: // Domain name
                     {
                         var length = SocketAbstraction.ReadByte(socket, timeout);
                         if (length == -1)
                         {
                             // SOCKS client closed connection
-                            return false;
+                            return null;
                         }
-                        addressBuffer = new byte[length];
+                        var addressBuffer = new byte[length];
                         if (SocketAbstraction.Read(socket, addressBuffer, 0, addressBuffer.Length, timeout) == 0)
                         {
                             // SOCKS client closed connection
-                            return false;
+                            return null;
                         }
 
-                        ipAddress = IPAddress.Parse(SshData.Ascii.GetString(addressBuffer, 0, addressBuffer.Length));
-
-                        //var hostName = new Common.ASCIIEncoding().GetString(addressBuffer);
-
-                        //ipAddress = Dns.GetHostEntry(hostName).AddressList[0];
+                        var hostName = SshData.Ascii.GetString(addressBuffer, 0, addressBuffer.Length);
+                        return hostName;
                     }
-                    break;
-                case 0x04:
+                case 0x04: // IPv6
                     {
-                        addressBuffer = new byte[16];
+                        var addressBuffer = new byte[16];
                         if (SocketAbstraction.Read(socket, addressBuffer, 0, 16, timeout) == 0)
                         {
                             // SOCKS client closed connection
-                            return false;
+                            return null;
                         }
 
-                        ipAddress = new IPAddress(addressBuffer);
+                        var ipv6 = new IPAddress(addressBuffer);
+                        return ipv6.ToString();
                     }
-                    break;
                 default:
                     throw new ProxyException(string.Format("SOCKS5: Address type '{0}' is not supported.", addressType));
             }
+        }
 
-            var portBuffer = new byte[2];
-            if (SocketAbstraction.Read(socket, portBuffer, 0, portBuffer.Length, timeout) == 0)
-            {
-                // SOCKS client closed connection
-                return false;
-            }
-
-            var port = (uint)(portBuffer[0] * 256 + portBuffer[1]);
-            var host = ipAddress.ToString();
-
-            RaiseRequestReceived(host, port);
-
-            channel.Open(host, port, this, socket);
-
-            SocketAbstraction.SendByte(socket, 0x05);
-
-            if (channel.IsOpen)
-            {
-                SocketAbstraction.SendByte(socket, 0x00);
+        private static byte[] CreateSocks5Reply(bool channelOpen)
+        {
+            var socksReply = new byte[
+                // SOCKS version
+                1 +
+                // Reply field
+                1 +
+                // Reserved; fixed: 0x00
+                1 +
+                // Address type; fixed: 0x01
+                1 +
+                // IPv4 server bound address; fixed: {0x00, 0x00, 0x00, 0x00}
+                4 +
+                // server bound port; fixed: {0x00, 0x00}
+                2];
+
+            socksReply[0] = 0x05;
+
+            if (channelOpen)
+            {
+                socksReply[1] = 0x00; // succeeded
             }
             else
             {
-                SocketAbstraction.SendByte(socket, 0x01);
+                socksReply[1] = 0x01; // general SOCKS server failure
             }
 
             // reserved
-            SocketAbstraction.SendByte(socket, 0x00);
-
-            if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
-            {
-                SocketAbstraction.SendByte(socket, 0x01);
-            }
-            else if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
-            {
-                SocketAbstraction.SendByte(socket, 0x04);
-            }
-            else
-            {
-                throw new NotSupportedException("Not supported address family.");
-            }
+            socksReply[2] = 0x00;
 
-            var addressBytes = ipAddress.GetAddressBytes();
-            SocketAbstraction.Send(socket, addressBytes, 0, addressBytes.Length);
-            SocketAbstraction.Send(socket, portBuffer, 0, portBuffer.Length);
+            // IPv4 address type
+            socksReply[3] = 0x01;
 
-            return true;
+            return socksReply;
         }
 
         /// <summary>

+ 3 - 3
src/Renci.SshNet/Properties/CommonAssemblyInfo.cs

@@ -9,9 +9,9 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
-[assembly: AssemblyVersion("2016.0.0")]
-[assembly: AssemblyFileVersion("2016.0.0")]
-[assembly: AssemblyInformationalVersion("2016.0.0")]
+[assembly: AssemblyVersion("2016.1.9999")]
+[assembly: AssemblyFileVersion("2016.1.9999")]
+[assembly: AssemblyInformationalVersion("2016.1.9999-dev")]
 [assembly: CLSCompliant(false)]
 
 // Setting ComVisible to false makes the types in this assembly not visible 

+ 0 - 1
src/Renci.SshNet/Renci.SshNet.csproj

@@ -46,7 +46,6 @@
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Core" />
-    <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>

+ 6 - 3
src/Renci.SshNet/ScpClient.NET.cs

@@ -63,16 +63,19 @@ namespace Renci.SshNet
                 channel.DataReceived += (sender, e) => input.Write(e.Data, 0, e.Data.Length);
                 channel.Open();
 
-                //  Send channel command request
+                // start recursive upload
                 channel.SendExecRequest(string.Format("scp -rt \"{0}\"", path));
                 CheckReturnCode(input);
 
+                // set last write and last access time on specified remote path
                 InternalSetTimestamp(channel, input, directoryInfo.LastWriteTimeUtc, directoryInfo.LastAccessTimeUtc);
-                SendData(channel, string.Format("D0755 0 {0}\n", Path.GetFileName(path)));
+                SendData(channel, string.Format("D0755 0 {0}\n", "."));
                 CheckReturnCode(input);
 
+                // recursively upload files and directories in specified remote path
                 InternalUpload(channel, input, directoryInfo);
 
+                // terminate upload of specified remote path
                 SendData(channel, "E\n");
                 CheckReturnCode(input);
             }
@@ -156,7 +159,7 @@ namespace Renci.SshNet
             var directories = directoryInfo.GetDirectories();
             foreach (var directory in directories)
             {
-                InternalSetTimestamp(channel, input, directoryInfo.LastWriteTimeUtc, directoryInfo.LastAccessTimeUtc);
+                InternalSetTimestamp(channel, input, directory.LastWriteTimeUtc, directory.LastAccessTimeUtc);
                 SendData(channel, string.Format("D0755 0 {0}\n", directory.Name));
                 CheckReturnCode(input);
 

+ 4 - 0
src/Renci.SshNet/ScpClient.cs

@@ -12,6 +12,10 @@ namespace Renci.SshNet
     /// <summary>
     /// Provides SCP client functionality.
     /// </summary>
+    /// <remarks>
+    /// More information on the SCP protocol is available here:
+    /// https://github.com/net-ssh/net-scp/blob/master/lib/net/scp.rb
+    /// </remarks>
     public partial class ScpClient : BaseClient
     {
         private static readonly Regex FileInfoRe = new Regex(@"C(?<mode>\d{4}) (?<length>\d+) (?<filename>.+)");

+ 61 - 61
src/Renci.SshNet/Session.cs

@@ -300,20 +300,20 @@ namespace Renci.SshNet
                 if (_clientInitMessage == null)
                 {
                     _clientInitMessage = new KeyExchangeInitMessage
-                    {
-                        KeyExchangeAlgorithms = ConnectionInfo.KeyExchangeAlgorithms.Keys.ToArray(),
-                        ServerHostKeyAlgorithms = ConnectionInfo.HostKeyAlgorithms.Keys.ToArray(),
-                        EncryptionAlgorithmsClientToServer = ConnectionInfo.Encryptions.Keys.ToArray(),
-                        EncryptionAlgorithmsServerToClient = ConnectionInfo.Encryptions.Keys.ToArray(),
-                        MacAlgorithmsClientToServer = ConnectionInfo.HmacAlgorithms.Keys.ToArray(),
-                        MacAlgorithmsServerToClient = ConnectionInfo.HmacAlgorithms.Keys.ToArray(),
-                        CompressionAlgorithmsClientToServer = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(),
-                        CompressionAlgorithmsServerToClient = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(),
-                        LanguagesClientToServer = new[] {string.Empty},
-                        LanguagesServerToClient = new[] {string.Empty},
-                        FirstKexPacketFollows = false,
-                        Reserved = 0
-                    };
+                        {
+                            KeyExchangeAlgorithms = ConnectionInfo.KeyExchangeAlgorithms.Keys.ToArray(),
+                            ServerHostKeyAlgorithms = ConnectionInfo.HostKeyAlgorithms.Keys.ToArray(),
+                            EncryptionAlgorithmsClientToServer = ConnectionInfo.Encryptions.Keys.ToArray(),
+                            EncryptionAlgorithmsServerToClient = ConnectionInfo.Encryptions.Keys.ToArray(),
+                            MacAlgorithmsClientToServer = ConnectionInfo.HmacAlgorithms.Keys.ToArray(),
+                            MacAlgorithmsServerToClient = ConnectionInfo.HmacAlgorithms.Keys.ToArray(),
+                            CompressionAlgorithmsClientToServer = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(),
+                            CompressionAlgorithmsServerToClient = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(),
+                            LanguagesClientToServer = new[] {string.Empty},
+                            LanguagesServerToClient = new[] {string.Empty},
+                            FirstKexPacketFollows = false,
+                            Reserved = 0
+                        };
                 }
                 return _clientInitMessage;
             }
@@ -697,7 +697,7 @@ namespace Renci.SshNet
         /// </remarks>
         public void Disconnect()
         {
-            DiagnosticAbstraction.Log(string.Format("[{0}] {1} Disconnecting session", ToHex(SessionId), DateTime.Now.Ticks));
+            DiagnosticAbstraction.Log(string.Format("[{0}] Disconnecting session.", ToHex(SessionId)));
 
             // send SSH_MSG_DISCONNECT message, clear socket read buffer and dispose it
             Disconnect(DisconnectReason.ByApplication, "Connection terminated by the client.");
@@ -798,11 +798,11 @@ namespace Renci.SshNet
                 throw new ArgumentNullException("waitHandle");
 
             var waitHandles = new[]
-            {
-                _exceptionWaitHandle,
-                _messageListenerCompleted,
-                waitHandle
-            };
+                {
+                    _exceptionWaitHandle,
+                    _messageListenerCompleted,
+                    waitHandle
+                };
 
             switch (WaitHandle.WaitAny(waitHandles, timeout))
             {
@@ -834,7 +834,7 @@ namespace Renci.SshNet
         /// <exception cref="InvalidOperationException">The size of the packet exceeds the maximum size defined by the protocol.</exception>
         internal void SendMessage(Message message)
         {
-            if (_socket == null || !_socket.CanWrite())
+            if (!_socket.CanWrite())
                 throw new SshConnectionException("Client not connected.");
 
             if (_keyExchangeInProgress && !(message is IKeyExchangedAllowed))
@@ -843,7 +843,7 @@ namespace Renci.SshNet
                 WaitOnHandle(_keyExchangeCompletedWaitHandle);
             }
 
-            DiagnosticAbstraction.Log(string.Format("[{0}] SendMessage to server '{1}': '{2}'.", ToHex(SessionId), message.GetType().Name, message));
+            DiagnosticAbstraction.Log(string.Format("[{0}] Sending message '{1}' to server: '{2}'.", ToHex(SessionId), message.GetType().Name, message));
 
             var paddingMultiplier = _clientCipher == null ? (byte) 8 : Math.Max((byte) 8, _serverCipher.MinimumSize);
             var packetData = message.GetPacket(paddingMultiplier, _clientCompression);
@@ -852,9 +852,6 @@ namespace Renci.SshNet
             // atomically, and only after the packet has actually been sent
             lock (_socketWriteLock)
             {
-                if (!_socket.IsConnected())
-                    throw new SshConnectionException("Client not connected.");
-
                 byte[] hash = null;
                 var packetDataOffset = 4; // first four bytes are reserved for outbound packet sequence
 
@@ -881,19 +878,18 @@ namespace Renci.SshNet
                 var packetLength = packetData.Length - packetDataOffset;
                 if (hash == null)
                 {
-                    SocketAbstraction.Send(_socket, packetData, packetDataOffset, packetLength);
+                    SendPacket(packetData, packetDataOffset, packetLength);
                 }
                 else
                 {
                     var data = new byte[packetLength + (_clientMac.HashSize/8)];
                     Buffer.BlockCopy(packetData, packetDataOffset, data, 0, packetLength);
                     Buffer.BlockCopy(hash, 0, data, packetLength, hash.Length);
-
-                    SocketAbstraction.Send(_socket, data, 0, data.Length);
+                    SendPacket(data, 0, data.Length);
                 }
 
                 // increment the packet sequence number only after we're sure the packet has
-                // been sent; even though it's only used for the MAC, it need to be incremented
+                // been sent; even though it's only used for the MAC, it needs to be incremented
                 // for each package sent.
                 // 
                 // the server will use it to verify the data integrity, and as such the order in
@@ -902,6 +898,34 @@ namespace Renci.SshNet
             }
         }
 
+        /// <summary>
+        /// Sends an SSH packet to the server.
+        /// </summary>
+        /// <param name="packet">A byte array containing the packet to send.</param>
+        /// <param name="offset">The offset of the packet.</param>
+        /// <param name="length">The length of the packet.</param>
+        /// <exception cref="SshConnectionException">Client is not connected to the server.</exception>
+        /// <remarks>
+        /// <para>
+        /// The send is performed in a dispose lock to avoid <see cref="NullReferenceException"/>
+        /// and/or <see cref="ObjectDisposedException"/> when sending the packet.
+        /// </para>
+        /// <para>
+        /// This method is only to be used when the connection is established, as the locking
+        /// overhead is not required while establising the connection.
+        /// </para>
+        /// </remarks>
+        private void SendPacket(byte[] packet, int offset, int length)
+        {
+            lock (_socketDisposeLock)
+            {
+                if (!_socket.IsConnected())
+                    throw new SshConnectionException("Client not connected.");
+
+                SocketAbstraction.Send(_socket, packet, offset, length);
+            }
+        }
+
         /// <summary>
         /// Sends a message to the server.
         /// </summary>
@@ -923,12 +947,12 @@ namespace Renci.SshNet
             }
             catch (SshException ex)
             {
-                DiagnosticAbstraction.Log(string.Format("Failure sending message server '{0}': '{1}' => {2}", message.GetType().Name, message, ex));
+                DiagnosticAbstraction.Log(string.Format("Failure sending message '{0}' to server: '{1}' => {2}", message.GetType().Name, message, ex));
                 return false;
             }
             catch (SocketException ex)
             {
-                DiagnosticAbstraction.Log(string.Format("Failure sending message server '{0}': '{1}' => {2}", message.GetType().Name, message, ex));
+                DiagnosticAbstraction.Log(string.Format("Failure sending message '{0}' to server: '{1}' => {2}", message.GetType().Name, message, ex));
                 return false;
             }
         }
@@ -974,16 +998,9 @@ namespace Renci.SshNet
                     return null;
                 }
 
-#if DEBUG_GERT
-                DiagnosticAbstraction.Log(string.Format("[{0}] FirstBlock [{1}]: {2}", ToHex(SessionId), blockSize, ToHex(firstBlock)));
-#endif // DEBUG_GERT
-
                 if (_serverCipher != null)
                 {
                     firstBlock = _serverCipher.Decrypt(firstBlock);
-#if DEBUG_GERT
-                    DiagnosticAbstraction.Log(string.Format("[{0}] FirstBlock decrypted [{1}]: {2}", ToHex(SessionId), firstBlock.Length, ToHex(firstBlock)));
-#endif // DEBUG_GERT
                 }
 
                 packetLength = (uint) (firstBlock[0] << 24 | firstBlock[1] << 16 | firstBlock[2] << 8 | firstBlock[3]);
@@ -1029,16 +1046,8 @@ namespace Renci.SshNet
                 var numberOfBytesToDecrypt = data.Length - (blockSize + inboundPacketSequenceLength + serverMacLength);
                 if (numberOfBytesToDecrypt > 0)
                 {
-#if DEBUG_GERT
-                    DiagnosticAbstraction.Log(string.Format("[{0}] NextBlocks [{1}]: {2}", ToHex(SessionId), bytesToRead, ToHex(nextBlocks)));
-#endif // DEBUG_GERT
-
                     var decryptedData = _serverCipher.Decrypt(data, blockSize + inboundPacketSequenceLength, numberOfBytesToDecrypt);
                     Buffer.BlockCopy(decryptedData, 0, data, blockSize + inboundPacketSequenceLength, decryptedData.Length);
-
-#if DEBUG_GERT
-                    DiagnosticAbstraction.Log(string.Format("[{0}] NextBlocks decrypted [{1}]: {2}", ToHex(SessionId), decryptedData.Length, ToHex(decryptedData)));
-#endif // DEBUG_GERT
                 }
             }
 
@@ -1068,10 +1077,6 @@ namespace Renci.SshNet
                 messagePayloadLength = data.Length;
             }
 
-#if DEBUG_GERT
-            DiagnosticAbstraction.Log(string.Format("[{0}] Message info (Sequence:{1},MessagePayloadLength:{2})", ToHex(SessionId), _inboundPacketSequence, messagePayloadLength));
-#endif // DEBUG_GERT
-
             _inboundPacketSequence++;
 
             return LoadMessage(data, messagePayloadOffset, messagePayloadLength);
@@ -1096,7 +1101,7 @@ namespace Renci.SshNet
         /// <param name="message"><see cref="DisconnectMessage"/> message.</param>
         internal void OnDisconnectReceived(DisconnectMessage message)
         {
-            DiagnosticAbstraction.Log(string.Format("[{0}] {1} Disconnect received: {2} {3}", ToHex(SessionId), DateTime.Now.Ticks, message.ReasonCode, message.Description));
+            DiagnosticAbstraction.Log(string.Format("[{0}] Disconnect received: {1} {2}.", ToHex(SessionId), message.ReasonCode, message.Description));
 
             // transition to disconnecting state to avoid throwing exceptions while cleaning up, and to
             // ensure any exceptions that are raised do not overwrite the SshConnectionException that we
@@ -1554,14 +1559,9 @@ namespace Renci.SshNet
             var messageType = data[offset];
 
             var message = _sshMessageFactory.Create(messageType);
-
-#if DEBUG_GERT
-            DiagnosticAbstraction.Log(string.Format("[{0}] Loading message with offset '{1}': {2}", ToHex(SessionId), offset, ToHex(data, 0)));
-#endif // DEBUG_GERT
-
             message.Load(data, offset + 1, count - 1);
 
-            DiagnosticAbstraction.Log(string.Format("[{0}] ReceiveMessage from server: '{1}': '{2}'.", ToHex(SessionId), message.GetType().Name, message));
+            DiagnosticAbstraction.Log(string.Format("[{0}] Received message '{1}' from server: '{2}'.", ToHex(SessionId), message.GetType().Name, message));
 
             return message;
         }
@@ -1603,7 +1603,7 @@ namespace Renci.SshNet
             var ipAddress = DnsAbstraction.GetHostAddresses(host)[0];
             var ep = new IPEndPoint(ipAddress, port);
 
-            DiagnosticAbstraction.Log(string.Format("Initiating connect to '{0}:{1}'.", host, port));
+            DiagnosticAbstraction.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port));
 
             _socket = SocketAbstraction.Connect(ep, ConnectionInfo.Timeout);
 
@@ -2185,7 +2185,7 @@ namespace Renci.SshNet
         {
             var connectionException = exp as SshConnectionException;
 
-            DiagnosticAbstraction.Log(string.Format("[{0}] {1} Raised exception: {2}", ToHex(SessionId), DateTime.Now.Ticks, exp));
+            DiagnosticAbstraction.Log(string.Format("[{0}] Raised exception: {1}", ToHex(SessionId), exp));
 
             if (_isDisconnecting)
             {
@@ -2210,7 +2210,7 @@ namespace Renci.SshNet
 
             if (connectionException != null)
             {
-                DiagnosticAbstraction.Log(string.Format("[{0}] {1} Disconnecting after exception: {2}", ToHex(SessionId), DateTime.Now.Ticks, exp));
+                DiagnosticAbstraction.Log(string.Format("[{0}] Disconnecting after exception: {1}", ToHex(SessionId), exp));
                 Disconnect(connectionException.DisconnectReason, exp.ToString());
             }
         }
@@ -2266,7 +2266,7 @@ namespace Renci.SshNet
 
             if (disposing)
             {
-                DiagnosticAbstraction.Log(string.Format("[{0}] Disposing session", ToHex(SessionId)));
+                DiagnosticAbstraction.Log(string.Format("[{0}] Disposing session.", ToHex(SessionId)));
 
                 Disconnect();
 

+ 24 - 0
test/Renci.SshNet.Shared.Tests/Abstractions/SocketAbstraction_CanWrite.cs

@@ -0,0 +1,24 @@
+using System.Net.Sockets;
+using Renci.SshNet.Abstractions;
+#if SILVERLIGHT
+using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
+#else
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+#endif
+
+namespace Renci.SshNet.Tests.Abstractions
+{
+    [TestClass]
+    public class SocketAbstraction_CanWrite
+    {
+        [TestMethod]
+        public void ShouldReturnFalseWhenSocketIsNull()
+        {
+            const Socket socket = null;
+
+            var actual = SocketAbstraction.CanWrite(socket);
+
+            Assert.IsFalse(actual);
+        }
+    }
+}

+ 1 - 0
test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.projitems

@@ -12,6 +12,7 @@
     <Compile Include="$(MSBuildThisFileDirectory)Abstractions\CryptoAbstraction_GenerateRandom.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Abstractions\DnsAbstraction_GetHostAddresses.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Abstractions\FileSystemAbstraction_EnumerateFiles.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Abstractions\SocketAbstraction_CanWrite.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Abstractions\ThreadAbstraction_ExecuteThread.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Started.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Starting.cs" />