فهرست منبع

Refactor and remove usage of Network stream to make it compartible with Silverlight
Make silverlight project compilable (still cannot connect, signature fails)

olegkap_cp 14 سال پیش
والد
کامیت
83884c34aa

+ 29 - 0
Renci.SshClient/Renci.SshNet.Silverlight/ForwardedPortLocal.Silverlight.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Net.Sockets;
+using System.Net;
+using System.Threading;
+using Renci.SshNet.Channels;
+
+namespace Renci.SshNet
+{
+    /// <summary>
+    /// Provides functionality for local port forwarding
+    /// </summary>
+    public partial class ForwardedPortLocal
+    {
+        partial void ExecuteThread(Action action)
+        {
+            ThreadPool.QueueUserWorkItem((o) => { action(); });
+        }
+
+        partial void InternalStart()
+        {
+            throw new NotImplementedException();
+        }
+
+        partial void InternalStop()
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

+ 16 - 0
Renci.SshClient/Renci.SshNet.Silverlight/ForwardedPortRemote.Silverlight.cs

@@ -0,0 +1,16 @@
+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(); });
+        }
+    }
+}

+ 16 - 0
Renci.SshClient/Renci.SshNet.Silverlight/PasswordConnectionInfo.Silverlight.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Threading;
+
+namespace Renci.SshNet
+{
+    /// <summary>
+    /// Provides connection information when password authentication method is used
+    /// </summary>
+    public partial class PasswordConnectionInfo
+    {
+        partial void ExecuteThread(Action action)
+        {
+            ThreadPool.QueueUserWorkItem((o) => { action(); });
+        }
+    }
+}

+ 7 - 1
Renci.SshClient/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj

@@ -667,7 +667,13 @@
       <Link>SubsystemSession.cs</Link>
     </Compile>
     <Compile Include="Common\Extensions.Silverlight.cs" />
+    <Compile Include="ForwardedPortLocal.Silverlight.cs" />
+    <Compile Include="ForwardedPortRemote.Silverlight.cs" />
+    <Compile Include="PasswordConnectionInfo.Silverlight.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Session.Silverlight.cs" />
+    <Compile Include="SftpClient.Silverlight.cs" />
+    <Compile Include="SshCommand.Silverlight.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
   <ProjectExtensions>
@@ -675,7 +681,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. 

+ 190 - 0
Renci.SshClient/Renci.SshNet.Silverlight/Session.Silverlight.cs

@@ -0,0 +1,190 @@
+using System;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Net.Sockets;
+using System.Threading;
+using Renci.SshNet.Common;
+using Renci.SshNet.Messages.Transport;
+using System.Text;
+using Renci.SshNet.Messages;
+
+namespace Renci.SshNet
+{
+    public partial class Session
+    {
+        private AutoResetEvent autoEvent = new AutoResetEvent(false);
+        private AutoResetEvent sendEvent = new AutoResetEvent(false);
+        private AutoResetEvent receiveEvent = new AutoResetEvent(false);
+
+        private bool isConnected = false;
+
+        partial void SocketConnect()
+        {
+            var ep = new DnsEndPoint(this.ConnectionInfo.Host, this.ConnectionInfo.Port);
+            this._socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+
+            SocketAsyncEventArgs args = new SocketAsyncEventArgs();
+
+            args.UserToken = this._socket;
+            args.RemoteEndPoint = ep;
+            args.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnect);
+
+            this._socket.ConnectAsync(args);
+            autoEvent.WaitOne(this.ConnectionInfo.Timeout);
+
+            if (args.SocketError != SocketError.Success)
+                throw new SocketException((int)args.SocketError);
+        }
+
+        partial void SocketDisconnect()
+        {
+            this._socket.Close(10000);
+        }
+
+        partial void SocketReadLine(ref string response)
+        {
+            var buffer = new byte[1024];
+            StringBuilder sb = new StringBuilder();
+
+            do
+            {
+                SocketAsyncEventArgs args = new SocketAsyncEventArgs();
+                args.SetBuffer(buffer, 0, buffer.Length);
+                args.UserToken = this._socket;
+                args.RemoteEndPoint = this._socket.RemoteEndPoint;
+                args.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceive);
+                this._socket.ReceiveAsync(args);
+
+                this.receiveEvent.WaitOne(this.ConnectionInfo.Timeout);
+
+                sb.Append(Encoding.UTF8.GetString(buffer, 0, args.BytesTransferred));
+
+                if (args.BytesTransferred < buffer.Length)
+                    break;
+
+            } while (true);
+
+            response = sb.ToString();
+
+        }
+
+        partial void SocketRead(int length, ref byte[] buffer)
+        {
+            var offset = 0;
+            int receivedTotal = 0;  // how many bytes is already received
+
+            do
+            {
+                    SocketAsyncEventArgs args = new SocketAsyncEventArgs();
+                    args.SetBuffer(buffer, offset + receivedTotal, length - receivedTotal);
+                    args.UserToken = this._socket;
+                    args.RemoteEndPoint = this._socket.RemoteEndPoint;
+                    args.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceive);
+                    this._socket.ReceiveAsync(args);
+
+                    this.receiveEvent.WaitOne(this.ConnectionInfo.Timeout);
+
+                    if (args.SocketError == SocketError.WouldBlock ||
+                        args.SocketError == SocketError.IOPending ||
+                        args.SocketError == SocketError.NoBufferSpaceAvailable)
+                    {
+                        // socket buffer is probably empty, wait and try again
+                        Thread.Sleep(30);
+                        continue;
+                    }
+                    else if (args.SocketError != SocketError.Success)
+                    {
+                        throw new SocketException((int)args.SocketError);
+                    }
+
+                    var receivedBytes = args.BytesTransferred;
+
+                    if (receivedBytes > 0)
+                    {
+                        receivedTotal += receivedBytes;
+                        continue;
+                    }
+                    else
+                    {
+                        throw new SshConnectionException("An established connection was aborted by the software in your host machine.", DisconnectReason.ConnectionLost);
+                    }
+            } while (receivedTotal < length);
+        }
+
+        partial void SocketWrite(byte[] data)
+        {
+            if (isConnected)
+            {
+                SocketAsyncEventArgs args = new SocketAsyncEventArgs();
+                args.SetBuffer(data, 0, data.Length);
+                args.UserToken = this._socket;
+                args.RemoteEndPoint = this._socket.RemoteEndPoint;
+                args.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);
+
+                this._socket.SendAsync(args);
+            }
+            else
+                throw new SocketException((int)SocketError.NotConnected);
+
+        }
+
+        private void OnConnect(object sender, SocketAsyncEventArgs e)
+        {
+            autoEvent.Set();
+            isConnected = (e.SocketError == SocketError.Success);
+        }
+
+        private void OnSend(object sender, SocketAsyncEventArgs e)
+        {
+            this.sendEvent.Set();
+        }
+
+        private void OnReceive(object sender, SocketAsyncEventArgs e)
+        {
+            this.receiveEvent.Set();
+        }
+
+        partial void HandleMessageCore(Message message)
+        {
+            this.HandleMessage((dynamic)message);
+        }
+
+        partial void ExecuteThread(Action action)
+        {
+            ThreadPool.QueueUserWorkItem((o) => { action(); });
+        }
+
+        partial void InternalRegisterMessage(string messageName)
+        {
+            lock (this._messagesMetadata)
+            {
+                foreach (var item in from m in this._messagesMetadata where m.Name == messageName select m)
+                {
+                    item.Enabled = true; 
+                    item.Activated = true; 
+                }
+            }
+        }
+
+        partial void InternalUnRegisterMessage(string messageName)
+        {
+            lock (this._messagesMetadata)
+            {
+                foreach (var item in from m in this._messagesMetadata where m.Name == messageName select m)
+                {
+                    item.Enabled = false;
+                    item.Activated = false;
+                }
+            }
+        }
+
+    }
+}

+ 16 - 0
Renci.SshClient/Renci.SshNet.Silverlight/SftpClient.Silverlight.cs

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

+ 16 - 0
Renci.SshClient/Renci.SshNet.Silverlight/SshCommand.Silverlight.cs

@@ -0,0 +1,16 @@
+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(); });
+        }
+    }
+}

+ 2 - 3
Renci.SshClient/Renci.SshNet/Common/SshData.cs

@@ -219,8 +219,7 @@ namespace Renci.SshNet.Common
             {
                 throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Strings longer than {0} is not supported.", int.MaxValue));
             }
-
-            return Encoding.UTF8.GetString(this.ReadBytes((int)length));
+            return Encoding.UTF8.GetString(this.ReadBytes((int)length), 0, (int)length);
         }
 
         /// <summary>
@@ -238,7 +237,7 @@ namespace Renci.SshNet.Common
 
             return this.ReadBytes((int)length);
         }
-        
+
         /// <summary>
         /// Reads next mpint data type from internal buffer.
         /// </summary>

+ 25 - 19
Renci.SshClient/Renci.SshNet/Session.NET.cs

@@ -6,12 +6,13 @@ using Renci.SshNet.Messages;
 using Renci.SshNet.Common;
 using System.Threading;
 using Renci.SshNet.Messages.Transport;
+using System.IO;
 
 namespace Renci.SshNet
 {
-	public partial class Session
-	{
-        partial void OpenSocket()
+    public partial class Session
+    {
+        partial void SocketConnect()
         {
             var ep = new IPEndPoint(Dns.GetHostAddresses(this.ConnectionInfo.Host)[0], this.ConnectionInfo.Port);
             this._socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
@@ -22,28 +23,33 @@ namespace Renci.SshNet
             this._socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, socketBufferSize);
             this._socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, socketBufferSize);
 
-
-            //  Connect socket with 5 seconds timeout
+            //  Connect socket with specified timeout
             var connectResult = this._socket.BeginConnect(ep, null, null);
 
             connectResult.AsyncWaitHandle.WaitOne(this.ConnectionInfo.Timeout);
 
-            //  Build list of available messages while connecting
-            this._messagesMetadata = (from type in this.GetType().Assembly.GetTypes()
-                                      from messageAttribute in type.GetCustomAttributes(false).OfType<MessageAttribute>()
-                                      select new MessageMetadata
-                                      {
-                                          Name = messageAttribute.Name,
-                                          Number = messageAttribute.Number,
-                                          Enabled = false,
-                                          Activated = false,
-                                          Type = type,
-                                      }).ToList();
-
             this._socket.EndConnect(connectResult);
         }
 
-        partial void InternalRead(int length, ref byte[] buffer)
+        partial void SocketDisconnect()
+        {
+            this._socket.Disconnect(true);
+        }
+
+        partial void SocketReadLine(ref string response)
+        {
+            //  Get server version from the server,
+            //  ignore text lines which are sent before if any
+            using (var ns = new NetworkStream(this._socket))
+            {
+                using (var sr = new StreamReader(ns))
+                {
+                    response = sr.ReadLine();
+                }
+            }
+        }
+
+        partial void SocketRead(int length, ref byte[] buffer)
         {
             var offset = 0;
             int receivedTotal = 0;  // how many bytes is already received
@@ -78,7 +84,7 @@ namespace Renci.SshNet
             } while (receivedTotal < length);
         }
 
-        partial void Write(byte[] data)
+        partial void SocketWrite(byte[] data)
         {
             int sent = 0;  // how many bytes is already sent
             int length = data.Length;

+ 48 - 37
Renci.SshClient/Renci.SshNet/Session.cs

@@ -393,7 +393,8 @@ namespace Renci.SshNet
         internal Session(ConnectionInfo connectionInfo)
         {
             this.ConnectionInfo = connectionInfo;
-            this.ClientVersion = string.Format(CultureInfo.CurrentCulture, "SSH-2.0-Renci.SshNet.SshClient.{0}", this.GetType().Assembly.GetName().Version);
+            //this.ClientVersion = string.Format(CultureInfo.CurrentCulture, "SSH-2.0-Renci.SshNet.SshClient.{0}", this.GetType().Assembly.GetName().Version);
+            this.ClientVersion = string.Format(CultureInfo.CurrentCulture, "SSH-2.0-Renci.SshNet.SshClient.0.0.1");
         }
 
         /// <summary>
@@ -422,30 +423,40 @@ namespace Renci.SshNet
                     if (this.IsConnected)
                         return;
 
-                    this.OpenSocket();
+                    //  Build list of available messages while connecting
+                    this._messagesMetadata = (from type in this.GetType().Assembly.GetTypes()
+                                              from messageAttribute in type.GetCustomAttributes(false).OfType<MessageAttribute>()
+                                              select new MessageMetadata
+                                              {
+                                                  Name = messageAttribute.Name,
+                                                  Number = messageAttribute.Number,
+                                                  Enabled = false,
+                                                  Activated = false,
+                                                  Type = type,
+                                              }).ToList();
+
+                    this.SocketConnect();
 
                     Match versionMatch = null;
+
                     //  Get server version from the server,
                     //  ignore text lines which are sent before if any
-                    using (var ns = new NetworkStream(this._socket))
+                    while (true)
                     {
-                        using (var sr = new StreamReader(ns))
+                        string serverVersion = string.Empty;
+                        this.SocketReadLine(ref serverVersion);
+
+                        this.ServerVersion = serverVersion;
+                        if (string.IsNullOrEmpty(this.ServerVersion))
                         {
-                            while (true)
-                            {
-                                this.ServerVersion = sr.ReadLine();
-                                if (string.IsNullOrEmpty(this.ServerVersion))
-                                {
-                                    throw new InvalidOperationException("Server string is null or empty.");
-                                }
-
-                                versionMatch = _serverVersionRe.Match(this.ServerVersion);
-
-                                if (versionMatch.Success)
-                                {
-                                    break;
-                                }
-                            }
+                            throw new InvalidOperationException("Server string is null or empty.");
+                        }
+
+                        versionMatch = _serverVersionRe.Match(this.ServerVersion);
+
+                        if (versionMatch.Success)
+                        {
+                            break;
                         }
                     }
 
@@ -457,7 +468,7 @@ namespace Renci.SshNet
                         throw new SshConnectionException(string.Format(CultureInfo.CurrentCulture, "Server version '{0}' is not supported.", version), DisconnectReason.ProtocolVersionNotSupported);
                     }
 
-                    this.Write(Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "{0}\x0D\x0A", this.ClientVersion)));
+                    this.SocketWrite(Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "{0}\x0D\x0A", this.ClientVersion)));
 
                     //  Register Transport response messages
                     this.RegisterMessage("SSH_MSG_DISCONNECT");
@@ -685,7 +696,7 @@ namespace Renci.SshNet
 
                 if (this._clientMac == null)
                 {
-                    this.Write(packetData);
+                    this.SocketWrite(packetData);
                 }
                 else
                 {
@@ -695,7 +706,7 @@ namespace Renci.SshNet
                     packetData.CopyTo(data, 0);
                     hash.CopyTo(data, packetData.Length);
 
-                    this.Write(data);
+                    this.SocketWrite(data);
                 }
 
                 this._outboundPacketSequence++;
@@ -835,7 +846,7 @@ namespace Renci.SshNet
                 {
                     if (this._socket != null)
                     {
-                        this._socket.Disconnect(true);
+                        this.SocketDisconnect();
 
                         //  When socket is disconnected wait for listener to finish
                         if (this._messageListenerCompleted != null)
@@ -1393,8 +1404,6 @@ namespace Renci.SshNet
 
         #endregion
 
-        #region Read & Write operations
-
         /// <summary>
         /// Reads the specified length of bytes from the server
         /// </summary>
@@ -1404,19 +1413,11 @@ namespace Renci.SshNet
         {
             byte[] buffer = new byte[length];
 
-            this.InternalRead(length, ref buffer);
+            this.SocketRead(length, ref buffer);
 
             return buffer;
         }
 
-        /// <summary>
-        /// Writes the specified data to the server.
-        /// </summary>
-        /// <param name="data">The data.</param>
-        partial void Write(byte[] data);
-
-        #endregion
-
         #region Message loading functions
 
         /// <summary>
@@ -1465,9 +1466,19 @@ namespace Renci.SshNet
 
         partial void ExecuteThread(Action action);
 
-        partial void OpenSocket();
+        partial void SocketConnect();
+
+        partial void SocketDisconnect();
+
+        partial void SocketRead(int length, ref byte[] buffer);
 
-        partial void InternalRead(int length, ref byte[] buffer);
+        partial void SocketReadLine(ref string response);
+
+        /// <summary>
+        /// Writes the specified data to the server.
+        /// </summary>
+        /// <param name="data">The data.</param>
+        partial void SocketWrite(byte[] data);
 
         /// <summary>
         /// Listens for incoming message from the server and handles them. This method run as a task on separate thread.
@@ -1484,7 +1495,7 @@ namespace Renci.SshNet
                     {
                         throw new NullReferenceException("The 'message' variable cannot be null");
                     }
-                    
+
                     this.HandleMessageCore(message);
                 }
             }