Procházet zdrojové kódy

Reduce partial methods/classes and streamline API surface across target frameworks

* Make Extensions.DebugPrint(this IEnumerable<byte>) available on all
target frameworks.
* Moved the following extension methods from Extensions.<target
framework>.cs to Extensions.cs:
- IsNullOrWhiteSpace(this string)
- CanRead(this Socket)
- CanWrite(this Socket)
* Removed GetIPAddress(this string) from Extensions.cs, and use
DnsAbstraction.GetHostAddresses(string) instead.
* Make ForwardedPortRemote(uint boundPort, string host, uint port) and
ForwardedPortRemote(string boundHost, uint boundPort, string host, uint
port) constructors available on all target frameworks.
* Eliminated SendData(IChannelSession channel, string command) partial
method from ScpClient.cs.

* Make the following methods on SftpClient available on all target
frameworks:
- SynchronizeDirectories(string, string, string)
- BeginSynchronizeDirectories(string, string, string, AsyncCallback,
object)
- EndSynchronizeDirectories(IAsyncResult)
* Make DnsAbstraction.GetHostAddresses(string) available on all target
frameworks.
* Added SocketAbstraction class.
Gert Driesen před 9 roky
rodič
revize
b5c7066bde
34 změnil soubory, kde provedl 361 přidání a 542 odebrání
  1. 0 2
      src/Renci.SshNet.NET35/Common/Extensions.NET35.cs
  2. 6 12
      src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj
  3. 2 0
      src/Renci.SshNet.Silverlight/Channels/ChannelDirectTcpip.SilverlightShared.cs
  4. 0 36
      src/Renci.SshNet.Silverlight/Common/Extensions.SilverlightShared.cs
  5. 0 16
      src/Renci.SshNet.Silverlight/ForwardedPortRemote.SilverlightShared.cs
  6. 0 14
      src/Renci.SshNet.Silverlight/KeyboardInteractiveAuthenticationMethod.SilverlightShared.cs
  7. 0 13
      src/Renci.SshNet.Silverlight/PasswordAuthenticationMethod.SilverlightShared.cs
  8. 15 11
      src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj
  9. 0 16
      src/Renci.SshNet.Silverlight/ScpClient.SilverlightShared.cs
  10. 2 1
      src/Renci.SshNet.Silverlight/Session.SilverlightShared.cs
  11. 0 16
      src/Renci.SshNet.Silverlight/SftpClient.SilverlightShared.cs
  12. 0 16
      src/Renci.SshNet.Silverlight/Shell.SilverlightShared.cs
  13. 0 16
      src/Renci.SshNet.Silverlight/ShellStream.SilverlightShared.cs
  14. 0 16
      src/Renci.SshNet.Silverlight/SshCommand.SilverlightShared.cs
  15. 9 6
      src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj
  16. 18 23
      src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj
  17. 0 20
      src/Renci.SshNet.WindowsPhone8/ForwardedPortLocal.SilverlightShared.cs
  18. 13 8
      src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj
  19. 32 19
      src/Renci.SshNet/Abstractions/DnsAbstraction.cs
  20. 2 0
      src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs
  21. 32 0
      src/Renci.SshNet/Abstractions/SocketAbstraction.cs
  22. 0 46
      src/Renci.SshNet/Common/Extensions.NET.cs
  23. 32 8
      src/Renci.SshNet/Common/Extensions.cs
  24. 1 1
      src/Renci.SshNet/ForwardedPortDynamic.NET.cs
  25. 1 1
      src/Renci.SshNet/ForwardedPortLocal.NET.cs
  26. 0 39
      src/Renci.SshNet/ForwardedPortRemote.NET.cs
  27. 30 1
      src/Renci.SshNet/ForwardedPortRemote.cs
  28. 3 5
      src/Renci.SshNet/Renci.SshNet.csproj
  29. 0 6
      src/Renci.SshNet/ScpClient.NET.cs
  30. 4 1
      src/Renci.SshNet/ScpClient.cs
  31. 1 1
      src/Renci.SshNet/Session.NET.cs
  32. 2 2
      src/Renci.SshNet/Session.cs
  33. 0 167
      src/Renci.SshNet/SftpClient.NET.cs
  34. 156 3
      src/Renci.SshNet/SftpClient.cs

+ 0 - 2
src/Renci.SshNet.NET35/Common/Extensions.NET35.cs

@@ -1,6 +1,4 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
 using System.Text;
 using System.Net.Sockets;
 using System.Threading;

+ 6 - 12
src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj

@@ -18,7 +18,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>TRACE;DEBUG;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HASH_SHA384;FEATURE_HASH_SHA512;FEATURE_HASH_RIPEMD160;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HASH_SHA384;FEATURE_HASH_SHA512;FEATURE_HASH_RIPEMD160;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
@@ -26,7 +26,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HASH_SHA384;FEATURE_HASH_SHA512;FEATURE_HASH_RIPEMD160;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
+    <DefineConstants>TRACE;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HASH_SHA384;FEATURE_HASH_SHA512;FEATURE_HASH_RIPEMD160;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Renci.SshNet.xml</DocumentationFile>
@@ -53,6 +53,9 @@
     <Compile Include="..\Renci.SshNet\Abstractions\ReflectionAbstraction.cs">
       <Link>Abstractions\ReflectionAbstraction.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\SocketAbstraction.cs">
+      <Link>Abstractions\SocketAbstraction.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Abstractions\ThreadAbstraction.cs">
       <Link>Abstractions\ThreadAbstraction.cs</Link>
     </Compile>
@@ -161,9 +164,6 @@
     <Compile Include="..\Renci.SshNet\Common\Extensions.cs">
       <Link>Common\Extensions.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet\Common\Extensions.NET.cs">
-      <Link>Common\Extensions.NET.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\Common\HostKeyEventArgs.cs">
       <Link>Common\HostKeyEventArgs.cs</Link>
     </Compile>
@@ -296,9 +296,6 @@
     <Compile Include="..\Renci.SshNet\ForwardedPortRemote.cs">
       <Link>ForwardedPortRemote.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet\ForwardedPortRemote.NET.cs">
-      <Link>ForwardedPortRemote.NET.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\HashInfo.cs">
       <Link>HashInfo.cs</Link>
     </Compile>
@@ -749,9 +746,6 @@
     <Compile Include="..\Renci.SshNet\SftpClient.cs">
       <Link>SftpClient.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet\SftpClient.NET.cs">
-      <Link>SftpClient.NET.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\Flags.cs">
       <Link>Sftp\Flags.cs</Link>
     </Compile>
@@ -942,7 +936,7 @@
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
     <VisualStudio>
-      <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. 

+ 2 - 0
src/Renci.SshNet.Silverlight/Channels/ChannelDirectTcpip.SilverlightShared.cs

@@ -46,6 +46,8 @@ namespace Renci.SshNet.Channels
                 }
                 break;
             } while (receivedTotal < bytesToRead);
+
+            read = receivedTotal;
         }
 
         partial void InternalSocketSend(byte[] data)

+ 0 - 36
src/Renci.SshNet.Silverlight/Common/Extensions.SilverlightShared.cs

@@ -1,10 +1,8 @@
 using System;
-using System.Linq;
 using System.Net.Sockets;
 using System.Threading;
 using System.Security.Cryptography;
 using System.Diagnostics;
-using System.Net;
 
 namespace Renci.SshNet.Common
 {
@@ -13,20 +11,6 @@ namespace Renci.SshNet.Common
     /// </summary>
     internal static partial class Extensions
     {
-        /// <summary>
-        /// Determines whether [is null or white space] [the specified value].
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <returns>
-        ///   <c>true</c> if [is null or white space] [the specified value]; otherwise, <c>false</c>.
-        /// </returns>
-        internal static bool IsNullOrWhiteSpace(this string value)
-        {
-            if (string.IsNullOrEmpty(value)) return true;
-
-            return value.All(char.IsWhiteSpace);
-        }
-
         /// <summary>
         /// Disposes the specified socket.
         /// </summary>
@@ -65,25 +49,5 @@ namespace Renci.SshNet.Common
 
             algorithm.Clear();
         }
-
-        internal static bool CanRead(this Socket socket)
-        {
-            return socket.Connected;
-        }
-
-        internal static bool CanWrite(this Socket socket)
-        {
-            return socket.Connected;
-        }
-
-        internal static IPAddress GetIPAddress(this string host)
-        {
-            IPAddress ipAddress;
-            if (!IPAddress.TryParse(host, out ipAddress))
-            {
-                throw new ProxyException("Silverlight supports only IP addresses.");
-            }
-            return ipAddress;
-        }
     }
 }

+ 0 - 16
src/Renci.SshNet.Silverlight/ForwardedPortRemote.SilverlightShared.cs

@@ -1,16 +0,0 @@
-using System;
-using System.Threading;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// Provides functionality for remote port forwarding
-    /// </summary>
-    public partial class ForwardedPortRemote
-    {
-        partial void ExecuteThread(Action action)
-        {
-            ThreadPool.QueueUserWorkItem(o => action());
-        }
-    }
-}

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

@@ -1,14 +0,0 @@
-using System;
-using System.Net;
-using System.Threading;
-
-namespace Renci.SshNet
-{
-    public partial class KeyboardInteractiveAuthenticationMethod
-    {
-        partial void ExecuteThread(Action action)
-        {
-            ThreadPool.QueueUserWorkItem((o) => { action(); });
-        }
-    }
-}

+ 0 - 13
src/Renci.SshNet.Silverlight/PasswordAuthenticationMethod.SilverlightShared.cs

@@ -1,13 +0,0 @@
-using System;
-using System.Threading;
-
-namespace Renci.SshNet
-{
-    public partial class PasswordAuthenticationMethod
-    {
-        partial void ExecuteThread(Action action)
-        {
-            ThreadPool.QueueUserWorkItem((o) => { action(); });
-        }
-    }
-}

+ 15 - 11
src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj

@@ -29,7 +29,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>Bin\Debug</OutputPath>
-    <DefineConstants>TRACE;DEBUG;SILVERLIGHT;TUNING;FEATURE_HASH_SHA1;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;SILVERLIGHT;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -40,7 +40,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>Bin\Release</OutputPath>
-    <DefineConstants>TRACE;SILVERLIGHT;TUNING;FEATURE_HASH_SHA1;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
+    <DefineConstants>TRACE;SILVERLIGHT;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -67,6 +67,18 @@
     <Reference Include="System.Net" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Renci.SshNet\Abstractions\DnsAbstraction.cs">
+      <Link>Abstractions\DnsAbstraction.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\ReflectionAbstraction.cs">
+      <Link>Abstractions\ReflectionAbstraction.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\SocketAbstraction.cs">
+      <Link>Abstractions\SocketAbstraction.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\ThreadAbstraction.cs">
+      <Link>Abstractions\ThreadAbstraction.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\AuthenticationMethod.cs">
       <Link>AuthenticationMethod.cs</Link>
     </Compile>
@@ -867,21 +879,13 @@
     </Compile>
     <Compile Include="Channels\ChannelDirectTcpip.SilverlightShared.cs" />
     <Compile Include="Common\Extensions.SilverlightShared.cs" />
-    <Compile Include="Shell.SilverlightShared.cs" />
-    <Compile Include="ShellStream.SilverlightShared.cs" />
     <Compile Include="ForwardedPortLocal.SilverlightShared.cs" />
-    <Compile Include="ForwardedPortRemote.SilverlightShared.cs" />
-    <Compile Include="KeyboardInteractiveAuthenticationMethod.SilverlightShared.cs" />
-    <Compile Include="PasswordAuthenticationMethod.SilverlightShared.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="..\Renci.SshNet\Properties\CommonAssemblyInfo.cs">
       <Link>Properties\CommonAssemblyInfo.cs</Link>
     </Compile>
-    <Compile Include="ScpClient.SilverlightShared.cs" />
     <Compile Include="Session.SilverlightBrowser.cs" />
     <Compile Include="Session.SilverlightShared.cs" />
-    <Compile Include="SftpClient.SilverlightShared.cs" />
-    <Compile Include="SshCommand.SilverlightShared.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="..\Renci.SshNet.snk">
@@ -895,7 +899,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. 

+ 0 - 16
src/Renci.SshNet.Silverlight/ScpClient.SilverlightShared.cs

@@ -1,16 +0,0 @@
-using System.Text;
-using Renci.SshNet.Channels;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// Provides SCP client functionality.
-    /// </summary>
-    public partial class ScpClient
-    {
-        partial void SendData(IChannelSession channel, string command)
-        {
-            channel.SendData(Encoding.UTF8.GetBytes(command));
-        }
-    }
-}

+ 2 - 1
src/Renci.SshNet.Silverlight/Session.SilverlightShared.cs

@@ -5,6 +5,7 @@ using System.Linq;
 using System.Net;
 using System.Net.Sockets;
 using System.Threading;
+using Renci.SshNet.Abstractions;
 using Renci.SshNet.Common;
 using Renci.SshNet.Messages.Transport;
 
@@ -39,7 +40,7 @@ namespace Renci.SshNet
         partial void SocketConnect(string host, int port)
         {
             var timeout = ConnectionInfo.Timeout;
-            var ipAddress = host.GetIPAddress();
+            var ipAddress = DnsAbstraction.GetHostAddresses(host)[0];
             var ep = new IPEndPoint(ipAddress, port);
 
             _socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

+ 0 - 16
src/Renci.SshNet.Silverlight/SftpClient.SilverlightShared.cs

@@ -1,16 +0,0 @@
-using System;
-using System.Threading;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// 
-    /// </summary>
-    public partial class SftpClient
-    {
-        partial void ExecuteThread(Action action)
-        {
-            ThreadPool.QueueUserWorkItem(o => action());
-        }
-    }
-}

+ 0 - 16
src/Renci.SshNet.Silverlight/Shell.SilverlightShared.cs

@@ -1,16 +0,0 @@
-using System;
-using System.Threading;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// 
-    /// </summary>
-    public partial class Shell
-    {
-        partial void ExecuteThread(Action action)
-        {
-            ThreadPool.QueueUserWorkItem(o => action());
-        }
-    }
-}

+ 0 - 16
src/Renci.SshNet.Silverlight/ShellStream.SilverlightShared.cs

@@ -1,16 +0,0 @@
-using System;
-using System.Threading;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// 
-    /// </summary>
-    public partial class ShellStream
-    {
-        partial void ExecuteThread(Action action)
-        {
-            ThreadPool.QueueUserWorkItem(o => action());
-        }
-    }
-}

+ 0 - 16
src/Renci.SshNet.Silverlight/SshCommand.SilverlightShared.cs

@@ -1,16 +0,0 @@
-using System;
-using System.Threading;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// Represents SSH command that can be executed.
-    /// </summary>
-    public partial class SshCommand
-    {
-        partial void ExecuteThread(Action action)
-        {
-            ThreadPool.QueueUserWorkItem(o => action());
-        }
-    }
-}

+ 9 - 6
src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj

@@ -29,7 +29,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>Bin\Debug</OutputPath>
-    <DefineConstants>TRACE;DEBUG;SILVERLIGHT;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;SILVERLIGHT;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -41,7 +41,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>Bin\Release</OutputPath>
-    <DefineConstants>TRACE;SILVERLIGHT;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;</DefineConstants>
+    <DefineConstants>TRACE;SILVERLIGHT;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_POLL;FEATURE_DNS_SYNC;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -75,18 +75,21 @@
     <Compile Include="..\Renci.SshNet.Silverlight\ForwardedPortLocal.SilverlightShared.cs">
       <Link>ForwardedPortLocal.SilverlightShared.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\ScpClient.SilverlightShared.cs">
-      <Link>ScpClient.SilverlightShared.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet.Silverlight\Session.SilverlightBrowser.cs">
       <Link>Session.SilverlightBrowser.cs</Link>
     </Compile>
     <Compile Include="..\Renci.SshNet.Silverlight\Session.SilverlightShared.cs">
       <Link>Session.SilverlightShared.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\DnsAbstraction.cs">
+      <Link>Abstractions\DnsAbstraction.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Abstractions\ReflectionAbstraction.cs">
       <Link>Abstractions\ReflectionAbstraction.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\SocketAbstraction.cs">
+      <Link>Abstractions\SocketAbstraction.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Abstractions\ThreadAbstraction.cs">
       <Link>Abstractions\ThreadAbstraction.cs</Link>
     </Compile>
@@ -908,7 +911,7 @@
       <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
         <SilverlightProjectProperties />
       </FlavorProperties>
-      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
+      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 18 - 23
src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj

@@ -24,7 +24,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>Bin\Debug</OutputPath>
-    <DefineConstants>TRACE;DEBUG;SILVERLIGHT;WINDOWS_PHONE;TUNING;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;WINDOWS_PHONE;TUNING;FEATURE_RNG_CSP;FEATURE_STREAM_APM;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -35,7 +35,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>Bin\Release</OutputPath>
-    <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE;TUNING;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
+    <DefineConstants>TRACE;WINDOWS_PHONE;TUNING;FEATURE_RNG_CSP;FEATURE_STREAM_APM;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -44,6 +44,7 @@
     <NoWarn>1591</NoWarn>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="Microsoft.Phone" />
     <Reference Include="Renci.Security.Cryptography, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <HintPath>..\..\packages\Renci.Security.Cryptography.1.0.0\lib\wp71\Renci.Security.Cryptography.dll</HintPath>
       <Private>True</Private>
@@ -52,6 +53,18 @@
     <Reference Include="System.Net" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Renci.SshNet\Abstractions\DnsAbstraction.cs">
+      <Link>Abstractions\DnsAbstraction.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\ReflectionAbstraction.cs">
+      <Link>Abstractions\ReflectionAbstraction.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\SocketAbstraction.cs">
+      <Link>Abstractions\SocketAbstraction.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\ThreadAbstraction.cs">
+      <Link>Abstractions\ThreadAbstraction.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\AuthenticationMethod.cs">
       <Link>AuthenticationMethod.cs</Link>
     </Compile>
@@ -280,9 +293,6 @@
     <Compile Include="..\Renci.SshNet\KeyboardInteractiveAuthenticationMethod.cs">
       <Link>KeyboardInteractiveAuthenticationMethod.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\KeyboardInteractiveAuthenticationMethod.SilverlightShared.cs">
-      <Link>PasswordAuthenticationMethod.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\KeyboardInteractiveConnectionInfo.cs">
       <Link>KeyboardInteractiveConnectionInfo.cs</Link>
     </Compile>
@@ -508,9 +518,6 @@
     <Compile Include="..\Renci.SshNet\PasswordAuthenticationMethod.cs">
       <Link>PasswordAuthenticationMethod.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\PasswordAuthenticationMethod.SilverlightShared.cs">
-      <Link>PasswordAuthenticationMethod.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\PasswordConnectionInfo.cs">
       <Link>PasswordConnectionInfo.cs</Link>
     </Compile>
@@ -529,9 +536,6 @@
     <Compile Include="..\Renci.SshNet\ScpClient.cs">
       <Link>ScpClient.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\ScpClient.SilverlightShared.cs">
-      <Link>ScpClient.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\Security\Algorithm.cs">
       <Link>Security\Algorithm.cs</Link>
     </Compile>
@@ -691,9 +695,6 @@
     <Compile Include="..\Renci.SshNet\SftpClient.cs">
       <Link>SftpClient.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\SftpClient.SilverlightShared.cs">
-      <Link>Session.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\Flags.cs">
       <Link>Sftp\Flags.cs</Link>
     </Compile>
@@ -841,6 +842,9 @@
     <Compile Include="..\Renci.SshNet\Sftp\SftpSession.cs">
       <Link>Sftp\SftpSession.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpSynchronizeDirectoriesAsyncResult.cs">
+      <Link>Sftp\SftpSynchronizeDirectoriesAsyncResult.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpUploadAsyncResult.cs">
       <Link>Sftp\SftpUploadAsyncResult.cs</Link>
     </Compile>
@@ -850,24 +854,15 @@
     <Compile Include="..\Renci.SshNet\Shell.cs">
       <Link>Shell.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\Shell.SilverlightShared.cs">
-      <Link>Shell.SilverlightShared.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\ShellStream.cs">
       <Link>ShellStream.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\ShellStream.SilverlightShared.cs">
-      <Link>ShellStream.SilverlightShared.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\SshClient.cs">
       <Link>SshClient.cs</Link>
     </Compile>
     <Compile Include="..\Renci.SshNet\SshCommand.cs">
       <Link>SshCommand.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\SshCommand.SilverlightShared.cs">
-      <Link>SshCommand.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\SubsystemSession.cs">
       <Link>SubsystemSession.cs</Link>
     </Compile>

+ 0 - 20
src/Renci.SshNet.WindowsPhone8/ForwardedPortLocal.SilverlightShared.cs

@@ -1,20 +0,0 @@
-using System;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// Provides functionality for local port forwarding
-    /// </summary>
-    public partial class ForwardedPortLocal
-    {
-        partial void InternalStart()
-        {
-            throw new NotImplementedException();
-        }
-
-        partial void InternalStop(TimeSpan timeout)
-        {
-            throw new NotImplementedException();
-        }
-    }
-}

+ 13 - 8
src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj

@@ -23,7 +23,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>Bin\Debug</OutputPath>
-    <DefineConstants>TRACE;DEBUG;SILVERLIGHT;WINDOWS_PHONE;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;WINDOWS_PHONE;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_STREAM_APM;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -35,7 +35,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>Bin\Release</OutputPath>
-    <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;</DefineConstants>
+    <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -92,14 +92,20 @@
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="..\Renci.SshNet.Silverlight\Channels\ChannelDirectTcpip.SilverlightShared.cs">
-      <Link>ChannelDirectTcpip.SilverlightShared.cs</Link>
+      <Link>Channels\ChannelDirectTcpip.SilverlightShared.cs</Link>
     </Compile>
     <Compile Include="..\Renci.SshNet.WindowsPhone\Common\Extensions.WP.cs">
       <Link>Common\Extensions.WP.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\DnsAbstraction.cs">
+      <Link>Abstractions\DnsAbstraction.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Abstractions\ReflectionAbstraction.cs">
       <Link>Abstractions\ReflectionAbstraction.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Abstractions\SocketAbstraction.cs">
+      <Link>Abstractions\SocketAbstraction.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Abstractions\ThreadAbstraction.cs">
       <Link>Abstractions\ThreadAbstraction.cs</Link>
     </Compile>
@@ -574,9 +580,6 @@
     <Compile Include="..\Renci.SshNet\ScpClient.cs">
       <Link>ScpClient.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Silverlight\ScpClient.SilverlightShared.cs">
-      <Link>ScpClient.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet\Security\Algorithm.cs">
       <Link>Security\Algorithm.cs</Link>
     </Compile>
@@ -883,6 +886,9 @@
     <Compile Include="..\Renci.SshNet\Sftp\SftpSession.cs">
       <Link>Sftp\SftpSession.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpSynchronizeDirectoriesAsyncResult.cs">
+      <Link>Sftp\SftpSynchronizeDirectoriesAsyncResult.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpUploadAsyncResult.cs">
       <Link>Sftp\SftpUploadAsyncResult.cs</Link>
     </Compile>
@@ -904,7 +910,6 @@
     <Compile Include="..\Renci.SshNet\SubsystemSession.cs">
       <Link>SubsystemSession.cs</Link>
     </Compile>
-    <Compile Include="ForwardedPortLocal.SilverlightShared.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="..\Renci.SshNet\Properties\CommonAssemblyInfo.cs">
       <Link>Properties\CommonAssemblyInfo.cs</Link>
@@ -924,7 +929,7 @@
   <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
   <ProjectExtensions>
     <VisualStudio>
-      <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. 

+ 32 - 19
src/Renci.SshNet/Abstractions/DnsAbstraction.cs

@@ -1,4 +1,12 @@
-using System.Net;
+using System;
+using System.Net;
+#if FEATURE_DEVICEINFORMATION_APM
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Sockets;
+using System.Threading;
+using Microsoft.Phone.Net.NetworkInformation;
+#endif // FEATURE_DEVICEINFORMATION_APM
 
 namespace Renci.SshNet.Abstractions
 {
@@ -19,26 +27,31 @@ namespace Renci.SshNet.Abstractions
 #elif FEATURE_DNS_TAP
             return Dns.GetHostAddressesAsync(hostNameOrAddress).Result;
 #else
-            #error Retrieving IP addresses for a given host is not implemented.
-#endif
-        }
+            IPAddress address;
+            if (IPAddress.TryParse(hostNameOrAddress, out address))
+                return new [] { address};
 
-        /// <summary>
-        /// Resolves a host name or IP address to an <see cref="IPHostEntry"/> instance.
-        /// </summary>
-        /// <param name="hostNameOrAddress">The host name or IP address to resolve.</param>
-        /// <returns>
-        /// An <see cref="IPHostEntry"/> instance that contains address information about the host
-        /// specified in <paramref name="hostNameOrAddress"/>.
-        /// </returns>
-        public static IPHostEntry GetHostEntry(string hostNameOrAddress)
-        {
-#if FEATURE_DNS_SYNC
-            return Dns.GetHostEntry(hostNameOrAddress);
-#elif FEATURE_DNS_TAP
-            return Dns.GetHostEntryAsync(hostNameOrAddress).Result;
+#if FEATURE_DEVICEINFORMATION_APM
+            var resolveCompleted = new ManualResetEvent(false);
+            NameResolutionResult nameResolutionResult = null;
+            DeviceNetworkInformation.ResolveHostNameAsync(new DnsEndPoint(hostNameOrAddress, 0), result =>
+            {
+                nameResolutionResult = result;
+                resolveCompleted.Set();
+            }, null);
+
+            // wait until address is resolved
+            resolveCompleted.WaitOne();
+
+            if (nameResolutionResult.NetworkErrorCode == NetworkError.Success)
+            {
+                var addresses = new List<IPAddress>(nameResolutionResult.IPEndPoints.Select(p => p.Address).Distinct());
+                return addresses.ToArray();
+            }
+            throw new SocketException((int)nameResolutionResult.NetworkErrorCode);
 #else
-            #error Resolving host name or IP address to an IPHostEntry is not implemented.
+            throw new NotSupportedException("Resolving hostname to IP address is not supported.");
+#endif // FEATURE_DEVICEINFORMATION_APM
 #endif
         }
     }

+ 2 - 0
src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs

@@ -1,7 +1,9 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+#if FEATURE_REFLECTION_TYPEINFO
 using System.Reflection;
+#endif // FEATURE_REFLECTION_TYPEINFO
 
 namespace Renci.SshNet.Abstractions
 {

+ 32 - 0
src/Renci.SshNet/Abstractions/SocketAbstraction.cs

@@ -0,0 +1,32 @@
+using System.Net.Sockets;
+
+namespace Renci.SshNet.Abstractions
+{
+    internal static class SocketAbstraction
+    {
+        public static bool CanRead(Socket socket)
+        {
+            if (socket.Connected)
+            {
+#if FEATURE_SOCKET_POLL
+                return socket.Poll(-1, SelectMode.SelectRead) && socket.Available > 0;
+#endif // FEATURE_SOCKET_POLL
+            }
+
+            return false;
+
+        }
+
+        public static bool CanWrite(Socket socket)
+        {
+            if (socket.Connected)
+            {
+#if FEATURE_SOCKET_POLL
+                return socket.Poll(-1, SelectMode.SelectWrite);
+#endif // FEATURE_SOCKET_POLL
+            }
+
+            return false;
+        }
+    }
+}

+ 0 - 46
src/Renci.SshNet/Common/Extensions.NET.cs

@@ -1,46 +0,0 @@
-using System.Linq;
-using System.Net;
-using System.Net.Sockets;
-using Renci.SshNet.Abstractions;
-
-namespace Renci.SshNet.Common
-{
-    /// <summary>
-    /// Collection of different extension method specific for .NET 4.0
-    /// </summary>
-    internal static partial class Extensions
-    {
-        /// <summary>
-        /// Determines whether [is null or white space] [the specified value].
-        /// </summary>
-        /// <param name="value">The value.</param>
-        /// <returns>
-        ///   <c>true</c> if [is null or white space] [the specified value]; otherwise, <c>false</c>.
-        /// </returns>
-        internal static bool IsNullOrWhiteSpace(this string value)
-        {
-            if (string.IsNullOrEmpty(value)) return true;
-
-            return value.All(char.IsWhiteSpace);
-        }
-        
-        internal static bool CanRead(this Socket socket)
-        {
-            return socket.Connected && socket.Poll(-1, SelectMode.SelectRead) && socket.Available > 0;
-        }
-
-        internal static bool CanWrite(this Socket socket)
-        {
-            return socket.Connected && socket.Poll(-1, SelectMode.SelectWrite);
-        }
-
-        internal static IPAddress GetIPAddress(this string host)
-        {
-            IPAddress ipAddress;
-            if (!IPAddress.TryParse(host, out ipAddress))
-                ipAddress = DnsAbstraction.GetHostAddresses(host).First();
-
-            return ipAddress;
-        }
-    }
-}

+ 32 - 8
src/Renci.SshNet/Common/Extensions.cs

@@ -1,10 +1,12 @@
 using System;
 using System.Collections.Generic;
-#if !SILVERLIGHT
 using System.Diagnostics;
-#endif
 using System.Globalization;
+using System.Linq;
 using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using Renci.SshNet.Abstractions;
 using Renci.SshNet.Messages;
 using Renci.SshNet.Messages.Connection;
 
@@ -15,6 +17,20 @@ namespace Renci.SshNet.Common
     /// </summary>
     internal static partial class Extensions
     {
+        /// <summary>
+        /// Determines whether [is null or white space] [the specified value].
+        /// </summary>
+        /// <param name="value">The value.</param>
+        /// <returns>
+        ///   <c>true</c> if [is null or white space] [the specified value]; otherwise, <c>false</c>.
+        /// </returns>
+        internal static bool IsNullOrWhiteSpace(this string value)
+        {
+            if (string.IsNullOrEmpty(value)) return true;
+
+            return value.All(char.IsWhiteSpace);
+        }
+
         internal static byte[] ToArray(this GlobalRequestName globalRequestName)
         {
             switch (globalRequestName)
@@ -150,22 +166,20 @@ namespace Renci.SshNet.Common
             return IsEqualTo(value, compareList, null);
         }
 
-#if SILVERLIGHT
-#else
-
         /// <summary>
         /// Prints out 
         /// </summary>
         /// <param name="bytes">The bytes.</param>
         internal static void DebugPrint(this IEnumerable<byte> bytes)
         {
+            var sb = new StringBuilder();
+
             foreach (var b in bytes)
             {
-                Debug.Write(string.Format(CultureInfo.CurrentCulture, "0x{0:x2}, ", b));
+                sb.AppendFormat(CultureInfo.CurrentCulture, "0x{0:x2}, ", b);
             }
-            Debug.WriteLine(string.Empty);
+            Debug.WriteLine(sb.ToString());
         }
-#endif
 
         /// <summary>
         /// Trims the leading zero from bytes array.
@@ -305,5 +319,15 @@ namespace Renci.SshNet.Common
             Buffer.BlockCopy(data, offset, taken, 0, length);
             return taken;
         }
+
+        internal static bool CanRead(this Socket socket)
+        {
+            return SocketAbstraction.CanRead(socket);
+        }
+
+        internal static bool CanWrite(this Socket socket)
+        {
+            return SocketAbstraction.CanWrite(socket);
+        }
     }
 }

+ 1 - 1
src/Renci.SshNet/ForwardedPortDynamic.NET.cs

@@ -26,7 +26,7 @@ namespace Renci.SshNet
             var ip = IPAddress.Any;
             if (!string.IsNullOrEmpty(BoundHost))
             {
-                ip = BoundHost.GetIPAddress();
+                ip = DnsAbstraction.GetHostAddresses(BoundHost)[0];
             }
 
             var ep = new IPEndPoint(ip, (int) BoundPort);

+ 1 - 1
src/Renci.SshNet/ForwardedPortLocal.NET.cs

@@ -22,7 +22,7 @@ namespace Renci.SshNet
 
         partial void InternalStart()
         {
-            var addr = BoundHost.GetIPAddress();
+            var addr = DnsAbstraction.GetHostAddresses(BoundHost)[0];
             var ep = new IPEndPoint(addr, (int) BoundPort);
 
             _listener = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp) {Blocking = true};

+ 0 - 39
src/Renci.SshNet/ForwardedPortRemote.NET.cs

@@ -1,39 +0,0 @@
-using Renci.SshNet.Abstractions;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// Provides functionality for remote port forwarding
-    /// </summary>
-    public partial class ForwardedPortRemote
-    {
-        /// <summary>
-        /// Initializes a new instance of the <see cref="ForwardedPortRemote"/> class.
-        /// </summary>
-        /// <param name="boundPort">The bound port.</param>
-        /// <param name="host">The host.</param>
-        /// <param name="port">The port.</param>
-        /// <example>
-        ///     <code source="..\..\Renci.SshNet.Tests\Classes\ForwardedPortRemoteTest.cs" region="Example SshClient AddForwardedPort Start Stop ForwardedPortRemote" language="C#" title="Remote port forwarding" />
-        /// </example>
-        public ForwardedPortRemote(uint boundPort, string host, uint port)
-            : this(string.Empty, boundPort, host, port)
-        {
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="ForwardedPortRemote"/> class.
-        /// </summary>
-        /// <param name="boundHost">The bound host.</param>
-        /// <param name="boundPort">The bound port.</param>
-        /// <param name="host">The host.</param>
-        /// <param name="port">The port.</param>
-        public ForwardedPortRemote(string boundHost, uint boundPort, string host, uint port)
-            : this(DnsAbstraction.GetHostEntry(boundHost).AddressList[0],
-                   boundPort,
-                   DnsAbstraction.GetHostEntry(host).AddressList[0],
-                   port)
-        {
-        }
-    }
-}

+ 30 - 1
src/Renci.SshNet/ForwardedPortRemote.cs

@@ -11,7 +11,7 @@ namespace Renci.SshNet
     /// <summary>
     /// Provides functionality for remote port forwarding
     /// </summary>
-    public partial class ForwardedPortRemote : ForwardedPort, IDisposable
+    public class ForwardedPortRemote : ForwardedPort, IDisposable
     {
         private bool _requestStatus;
 
@@ -99,6 +99,35 @@ namespace Renci.SshNet
             Port = port;
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ForwardedPortRemote"/> class.
+        /// </summary>
+        /// <param name="boundPort">The bound port.</param>
+        /// <param name="host">The host.</param>
+        /// <param name="port">The port.</param>
+        /// <example>
+        ///     <code source="..\..\Renci.SshNet.Tests\Classes\ForwardedPortRemoteTest.cs" region="Example SshClient AddForwardedPort Start Stop ForwardedPortRemote" language="C#" title="Remote port forwarding" />
+        /// </example>
+        public ForwardedPortRemote(uint boundPort, string host, uint port)
+            : this(string.Empty, boundPort, host, port)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ForwardedPortRemote"/> class.
+        /// </summary>
+        /// <param name="boundHost">The bound host.</param>
+        /// <param name="boundPort">The bound port.</param>
+        /// <param name="host">The host.</param>
+        /// <param name="port">The port.</param>
+        public ForwardedPortRemote(string boundHost, uint boundPort, string host, uint port)
+            : this(DnsAbstraction.GetHostAddresses(boundHost)[0],
+                   boundPort,
+                   DnsAbstraction.GetHostAddresses(host)[0],
+                   port)
+        {
+        }
+
         /// <summary>
         /// Starts remote port forwarding.
         /// </summary>

+ 3 - 5
src/Renci.SshNet/Renci.SshNet.csproj

@@ -18,7 +18,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>TRACE;DEBUG;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HASH_SHA384;FEATURE_HASH_SHA512;FEATURE_HASH_RIPEMD160;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HASH_SHA384;FEATURE_HASH_SHA512;FEATURE_HASH_RIPEMD160;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Debug\Renci.SshNet.xml</DocumentationFile>
@@ -27,7 +27,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HASH_SHA384;FEATURE_HASH_SHA512;FEATURE_HASH_RIPEMD160;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
+    <DefineConstants>TUNING;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HASH_SHA384;FEATURE_HASH_SHA512;FEATURE_HASH_RIPEMD160;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Renci.SshNet.xml</DocumentationFile>
@@ -48,6 +48,7 @@
   <ItemGroup>
     <Compile Include="Abstractions\DnsAbstraction.cs" />
     <Compile Include="Abstractions\ReflectionAbstraction.cs" />
+    <Compile Include="Abstractions\SocketAbstraction.cs" />
     <Compile Include="Abstractions\ThreadAbstraction.cs" />
     <Compile Include="AuthenticationMethod.cs">
       <SubType>Code</SubType>
@@ -88,7 +89,6 @@
     <Compile Include="Common\ChannelOpenConfirmedEventArgs.cs" />
     <Compile Include="Common\ChannelOpenFailedEventArgs.cs" />
     <Compile Include="Common\ChannelRequestEventArgs.cs" />
-    <Compile Include="Common\Extensions.NET.cs" />
     <Compile Include="Common\ProxyException.cs">
       <SubType>Code</SubType>
     </Compile>
@@ -148,7 +148,6 @@
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="ConnectionInfo.cs" />
-    <Compile Include="ForwardedPortRemote.NET.cs" />
     <Compile Include="HashInfo.cs">
       <SubType>Code</SubType>
     </Compile>
@@ -179,7 +178,6 @@
     <Compile Include="Common\SshDataStream.cs" />
     <Compile Include="ExpectAsyncResult.cs" />
     <Compile Include="Security\KeyExchangeDiffieHellmanGroupSha1.cs" />
-    <Compile Include="SftpClient.NET.cs" />
     <Compile Include="KeyboardInteractiveAuthenticationMethod.cs">
       <SubType>Code</SubType>
     </Compile>

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

@@ -1,5 +1,4 @@
 using System;
-using System.Text;
 using Renci.SshNet.Channels;
 using System.IO;
 using Renci.SshNet.Common;
@@ -296,10 +295,5 @@ namespace Renci.SshNet
                 SendConfirmation(channel, 1, string.Format("\"{0}\" is not valid protocol message.", message));
             }
         }
-
-        partial void SendData(IChannelSession channel, string command)
-        {
-            channel.SendData(SshData.Utf8.GetBytes(command));
-        }
     }
 }

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

@@ -359,7 +359,10 @@ namespace Renci.SshNet
             }
         }
 
-        partial void SendData(IChannelSession channel, string command);
+        private void SendData(IChannelSession channel, string command)
+        {
+            channel.SendData(SshData.Utf8.GetBytes(command));
+        }
 
         private void SendData(IChannelSession channel, byte[] buffer, int length)
         {

+ 1 - 1
src/Renci.SshNet/Session.NET.cs

@@ -103,7 +103,7 @@ namespace Renci.SshNet
         {
             const int socketBufferSize = 2 * MaximumSshPacketSize;
 
-            var ipAddress = host.GetIPAddress();
+            var ipAddress = DnsAbstraction.GetHostAddresses(host)[0];
             var timeout = ConnectionInfo.Timeout;
             var ep = new IPEndPoint(ipAddress, port);
 

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

@@ -1875,7 +1875,7 @@ namespace Renci.SshNet
             SocketWriteByte((byte)(ConnectionInfo.Port % 0xFF));
 
             //  Send IP
-            var ipAddress = ConnectionInfo.Host.GetIPAddress();
+            var ipAddress = DnsAbstraction.GetHostAddresses(ConnectionInfo.Host)[0];
             SocketWrite(ipAddress.GetAddressBytes());
 
             //  Send username
@@ -1986,7 +1986,7 @@ namespace Renci.SshNet
             //  Send reserved, must be 0x00
             SocketWriteByte(0x00);
 
-            var ip = ConnectionInfo.Host.GetIPAddress();
+            var ip = DnsAbstraction.GetHostAddresses(ConnectionInfo.Host)[0];
 
             //  Send address type and address
             if (ip.AddressFamily == AddressFamily.InterNetwork)

+ 0 - 167
src/Renci.SshNet/SftpClient.NET.cs

@@ -1,167 +0,0 @@
-using System;
-using System.Linq;
-using System.Collections.Generic;
-using System.IO;
-using Renci.SshNet.Common;
-using Renci.SshNet.Sftp;
-using System.Globalization;
-using Renci.SshNet.Abstractions;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH.
-    /// </summary>
-    public partial class SftpClient
-    {
-        #region SynchronizeDirectories
-
-        /// <summary>
-        /// Synchronizes the directories.
-        /// </summary>
-        /// <param name="sourcePath">The source path.</param>
-        /// <param name="destinationPath">The destination path.</param>
-        /// <param name="searchPattern">The search pattern.</param>
-        /// <returns>List of uploaded files.</returns>
-        public IEnumerable<FileInfo> SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern)
-        {
-            return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, null);
-        }
-
-        /// <summary>
-        /// Begins the synchronize directories.
-        /// </summary>
-        /// <param name="sourcePath">The source path.</param>
-        /// <param name="destinationPath">The destination path.</param>
-        /// <param name="searchPattern">The search pattern.</param>
-        /// <param name="asyncCallback">The async callback.</param>
-        /// <param name="state">The state.</param>
-        /// <returns>
-        /// An <see cref="System.IAsyncResult" /> that represents the asynchronous directory synchronization.
-        /// </returns>
-        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> is <c>null</c>.</exception>
-        /// <exception cref="System.ArgumentException"><paramref name="destinationPath"/> is <c>null</c> or contains only whitespace.</exception>
-        public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state)
-        {
-            if (sourcePath == null)
-                throw new ArgumentNullException("sourcePath");
-            if (destinationPath.IsNullOrWhiteSpace())
-                throw new ArgumentException("destDir");
-
-            var asyncResult = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state);
-
-            ThreadAbstraction.ExecuteThread(() =>
-            {
-                try
-                {
-                    var result = InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asyncResult);
-
-                    asyncResult.SetAsCompleted(result, false);
-                }
-                catch (Exception exp)
-                {
-                    asyncResult.SetAsCompleted(exp, false);
-                }
-            });
-
-            return asyncResult;
-        }
-
-        /// <summary>
-        /// Ends the synchronize directories.
-        /// </summary>
-        /// <param name="asyncResult">The async result.</param>
-        /// <returns>List of uploaded files.</returns>
-        /// <exception cref="System.ArgumentException">Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult.</exception>
-        public IEnumerable<FileInfo> EndSynchronizeDirectories(IAsyncResult asyncResult)
-        {
-            var ar = asyncResult as SftpSynchronizeDirectoriesAsyncResult;
-
-            if (ar == null || ar.EndInvokeCalled)
-                throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult.");
-
-            // Wait for operation to complete, then return result or throw exception
-            return ar.EndInvoke();
-        }
-
-        private IEnumerable<FileInfo> InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, SftpSynchronizeDirectoriesAsyncResult asynchResult)
-        {
-            if (destinationPath.IsNullOrWhiteSpace())
-                throw new ArgumentException("destinationPath");
-
-            if (!Directory.Exists(sourcePath))
-                throw new FileNotFoundException(string.Format("Source directory not found: {0}", sourcePath));
-
-            var uploadedFiles = new List<FileInfo>();
-
-            var sourceDirectory = new DirectoryInfo(sourcePath);
-
-#if SILVERLIGHT
-            var sourceFiles = sourceDirectory.EnumerateFiles(searchPattern);
-#else
-            var sourceFiles = sourceDirectory.GetFiles(searchPattern);
-#endif
-
-            if (sourceFiles == null || !sourceFiles.Any())
-                return uploadedFiles;
-
-            #region Existing Files at The Destination
-
-            var destFiles = InternalListDirectory(destinationPath, null);
-            var destDict = new Dictionary<string, SftpFile>();
-            foreach (var destFile in destFiles)
-            {
-                if (destFile.IsDirectory)
-                    continue;
-                destDict.Add(destFile.Name, destFile);
-            }
-
-            #endregion
-
-            #region Upload the difference
-
-            const Flags uploadFlag = Flags.Write | Flags.Truncate | Flags.CreateNewOrOpen;
-            foreach (var localFile in sourceFiles)
-            {
-                var isDifferent = !destDict.ContainsKey(localFile.Name);
-
-                if (!isDifferent)
-                {
-                    var temp = destDict[localFile.Name];
-                    //  TODO:   Use md5 to detect a difference
-                    //ltang: File exists at the destination => Using filesize to detect the difference
-                    isDifferent = localFile.Length != temp.Length;
-                }
-
-                if (isDifferent)
-                {
-                    var remoteFileName = string.Format(CultureInfo.InvariantCulture, @"{0}/{1}", destinationPath, localFile.Name);
-                    try
-                    {
-                        using (var file = File.OpenRead(localFile.FullName))
-                        {
-                            InternalUploadFile(file, remoteFileName, uploadFlag, null, null);
-                        }
-
-                        uploadedFiles.Add(localFile);
-
-                        if (asynchResult != null)
-                        {
-                            asynchResult.Update(uploadedFiles.Count);
-                        }
-                    }
-                    catch (Exception ex)
-                    {
-                        throw new Exception(string.Format("Failed to upload {0} to {1}", localFile.FullName, remoteFileName), ex);
-                    }
-                }
-            }
-
-            #endregion
-
-            return uploadedFiles;
-        }
-
-        #endregion
-    }
-}

+ 156 - 3
src/Renci.SshNet/SftpClient.cs

@@ -15,7 +15,7 @@ namespace Renci.SshNet
     /// <summary>
     /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH.
     /// </summary>
-    public partial class SftpClient : BaseClient
+    public class SftpClient : BaseClient
     {
         /// <summary>
         /// Holds the <see cref="ISftpSession"/> instance that is used to communicate to the
@@ -233,7 +233,7 @@ namespace Renci.SshNet
             BufferSize = 1024 * 32;
         }
 
-        #endregion
+        #endregion Constructors
 
         /// <summary>
         /// Changes remote directory to path.
@@ -1566,6 +1566,156 @@ namespace Renci.SshNet
         //public void SetCreationTime(string path, DateTime creationTime);
         //public void SetCreationTimeUtc(string path, DateTime creationTimeUtc);
 
+        #endregion // File Methods
+
+        #region SynchronizeDirectories
+
+        /// <summary>
+        /// Synchronizes the directories.
+        /// </summary>
+        /// <param name="sourcePath">The source path.</param>
+        /// <param name="destinationPath">The destination path.</param>
+        /// <param name="searchPattern">The search pattern.</param>
+        /// <returns>List of uploaded files.</returns>
+        public IEnumerable<FileInfo> SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern)
+        {
+            return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, null);
+        }
+
+        /// <summary>
+        /// Begins the synchronize directories.
+        /// </summary>
+        /// <param name="sourcePath">The source path.</param>
+        /// <param name="destinationPath">The destination path.</param>
+        /// <param name="searchPattern">The search pattern.</param>
+        /// <param name="asyncCallback">The async callback.</param>
+        /// <param name="state">The state.</param>
+        /// <returns>
+        /// An <see cref="System.IAsyncResult" /> that represents the asynchronous directory synchronization.
+        /// </returns>
+        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> is <c>null</c>.</exception>
+        /// <exception cref="System.ArgumentException"><paramref name="destinationPath"/> is <c>null</c> or contains only whitespace.</exception>
+        public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state)
+        {
+            if (sourcePath == null)
+                throw new ArgumentNullException("sourcePath");
+            if (destinationPath.IsNullOrWhiteSpace())
+                throw new ArgumentException("destDir");
+
+            var asyncResult = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state);
+
+            ThreadAbstraction.ExecuteThread(() =>
+            {
+                try
+                {
+                    var result = InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asyncResult);
+
+                    asyncResult.SetAsCompleted(result, false);
+                }
+                catch (Exception exp)
+                {
+                    asyncResult.SetAsCompleted(exp, false);
+                }
+            });
+
+            return asyncResult;
+        }
+
+        /// <summary>
+        /// Ends the synchronize directories.
+        /// </summary>
+        /// <param name="asyncResult">The async result.</param>
+        /// <returns>List of uploaded files.</returns>
+        /// <exception cref="System.ArgumentException">Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult.</exception>
+        public IEnumerable<FileInfo> EndSynchronizeDirectories(IAsyncResult asyncResult)
+        {
+            var ar = asyncResult as SftpSynchronizeDirectoriesAsyncResult;
+
+            if (ar == null || ar.EndInvokeCalled)
+                throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult.");
+
+            // Wait for operation to complete, then return result or throw exception
+            return ar.EndInvoke();
+        }
+
+        private IEnumerable<FileInfo> InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, SftpSynchronizeDirectoriesAsyncResult asynchResult)
+        {
+            if (destinationPath.IsNullOrWhiteSpace())
+                throw new ArgumentException("destinationPath");
+
+            if (!Directory.Exists(sourcePath))
+                throw new FileNotFoundException(string.Format("Source directory not found: {0}", sourcePath));
+
+            var uploadedFiles = new List<FileInfo>();
+
+            var sourceDirectory = new DirectoryInfo(sourcePath);
+
+#if SILVERLIGHT
+            var sourceFiles = sourceDirectory.EnumerateFiles(searchPattern);
+#else
+            var sourceFiles = sourceDirectory.GetFiles(searchPattern);
+#endif
+
+            if (sourceFiles == null || !sourceFiles.Any())
+                return uploadedFiles;
+
+            #region Existing Files at The Destination
+
+            var destFiles = InternalListDirectory(destinationPath, null);
+            var destDict = new Dictionary<string, SftpFile>();
+            foreach (var destFile in destFiles)
+            {
+                if (destFile.IsDirectory)
+                    continue;
+                destDict.Add(destFile.Name, destFile);
+            }
+
+            #endregion
+
+            #region Upload the difference
+
+            const Flags uploadFlag = Flags.Write | Flags.Truncate | Flags.CreateNewOrOpen;
+            foreach (var localFile in sourceFiles)
+            {
+                var isDifferent = !destDict.ContainsKey(localFile.Name);
+
+                if (!isDifferent)
+                {
+                    var temp = destDict[localFile.Name];
+                    //  TODO:   Use md5 to detect a difference
+                    //ltang: File exists at the destination => Using filesize to detect the difference
+                    isDifferent = localFile.Length != temp.Length;
+                }
+
+                if (isDifferent)
+                {
+                    var remoteFileName = string.Format(CultureInfo.InvariantCulture, @"{0}/{1}", destinationPath, localFile.Name);
+                    try
+                    {
+                        using (var file = File.OpenRead(localFile.FullName))
+                        {
+                            InternalUploadFile(file, remoteFileName, uploadFlag, null, null);
+                        }
+
+                        uploadedFiles.Add(localFile);
+
+                        if (asynchResult != null)
+                        {
+                            asynchResult.Update(uploadedFiles.Count);
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        throw new Exception(string.Format("Failed to upload {0} to {1}", localFile.FullName, remoteFileName), ex);
+                    }
+                }
+            }
+
+            #endregion
+
+            return uploadedFiles;
+        }
+
         #endregion
 
         /// <summary>
@@ -1665,8 +1815,11 @@ namespace Renci.SshNet
                 //  Call callback to report number of bytes read
                 if (downloadCallback != null)
                 {
+                    // copy offset to ensure it's not modified between now and execution of callback
+                    var downloadOffset = offset;
+
                     //  Execute callback on different thread
-                    ThreadAbstraction.ExecuteThread(() => { downloadCallback(offset); });
+                    ThreadAbstraction.ExecuteThread(() => { downloadCallback(downloadOffset); });
                 }
 
                 data = _sftpSession.RequestRead(handle, offset, optimalReadLength);