Socket.cs
上传用户:szltgg
上传日期:2019-05-16
资源大小:604k
文件大小:8k
- /*
- Copyright (c) 2005 Poderosa Project, All Rights Reserved.
- This file is a part of the Granados SSH Client Library that is subject to
- the license included in the distributed package.
- You may not use this file except in compliance with the license.
- $Id: Socket.cs,v 1.2 2005/04/20 08:58:56 okajima Exp $
- */
- using System;
- using System.Text;
- using System.IO;
- using System.Net.Sockets;
- using System.Threading;
- using System.Diagnostics;
- namespace Granados.SSHC
- {
- internal enum ReceiverState {
- Ready,
- Closed,
- Error
- }
- internal interface IHandlerBase {
- void OnClosed();
- void OnError(Exception error, string msg);
- }
- internal interface IByteArrayHandler : IHandlerBase {
- void OnData(byte[] data, int offset, int length);
- }
- internal interface IStringHandler : IHandlerBase {
- void OnString(string data);
- }
- internal abstract class SynchronizedHandlerBase {
- public virtual void SetClosed() {
- _state = ReceiverState.Closed;
- _event.Set();
- }
- public virtual void SetError(string msg) {
- _errorMessage = msg;
- _state = ReceiverState.Error;
- _event.Set();
- }
- public virtual void SetReady() {
- _state = ReceiverState.Ready;
- _event.Set();
- }
- protected ManualResetEvent _event;
- protected ReceiverState _state;
- protected string _errorMessage;
- public WaitHandle WaitHandle {
- get {
- return _event;
- }
- }
- public ReceiverState State {
- get {
- return _state;
- }
- }
- public string ErrorMessage {
- get {
- return _errorMessage;
- }
- }
- public void Wait() {
- _event.WaitOne();
- _event.Reset();
- }
- protected SynchronizedHandlerBase() {
- _event = new ManualResetEvent(false);
- }
- }
- internal class ProtocolNegotiationHandler : SynchronizedHandlerBase, IByteArrayHandler {
- protected string _serverVersion;
- protected SSHConnectionParameter _param;
- protected string _endOfLine;
- public ProtocolNegotiationHandler(SSHConnectionParameter param) {
- _param = param;
- _errorMessage = Strings.GetString("NotSSHServer");
- }
- public string ServerVersion {
- get {
- return _serverVersion;
- }
- }
- public string EOL {
- get {
- return _endOfLine;
- }
- }
- public void OnData(byte[] buf, int offset, int length) {
- try {
- //the specification claims the version string ends with CRLF, however some servers send LF only
- if(length<=2 || buf[offset+length-1]!=0x0A) throw new SSHException(Strings.GetString("NotSSHServer"));
- //Debug.WriteLine(String.Format("receiveServerVersion len={0}",len));
- string sv = Encoding.ASCII.GetString(buf, offset, length);
- _serverVersion = sv.Trim();
- _endOfLine = sv.EndsWith("rn")? "rn" : "n"; //quick hack
- //check compatibility
- int a = _serverVersion.IndexOf('-');
- if(a==-1) throw new SSHException("Format of server version is invalid");
- int b = _serverVersion.IndexOf('-', a+1);
- if(b==-1) throw new SSHException("Format of server version is invalid");
- int comma = _serverVersion.IndexOf('.', a, b-a);
- if(comma==-1) throw new SSHException("Format of server version is invalid");
- int major = Int32.Parse(_serverVersion.Substring(a+1, comma-a-1));
- int minor = Int32.Parse(_serverVersion.Substring(comma+1, b-comma-1));
- if(_param.Protocol==SSHProtocol.SSH1) {
- if(major!=1) throw new SSHException("The protocol version of server is not compatible for SSH1");
- }
- else {
- if(major>=3 || major<=0 || (major==1 && minor!=99)) throw new SSHException("The protocol version of server is not compatible with SSH2");
- }
- this.SetReady();
- }
- catch(Exception ex) {
- OnError(ex, ex.Message);
- }
- }
- public void OnError(Exception error, string msg) {
- base.SetError(msg);
- }
- public void OnClosed() {
- base.SetClosed();
- }
- }
- //System.IO.Socket偲IChannelEventReceiver傪拪徾壔偡傞
- internal abstract class AbstractSocket {
-
- protected IByteArrayHandler _handler;
- protected AbstractSocket(IByteArrayHandler h) {
- _handler = h;
- }
- public void SetHandler(IByteArrayHandler h) {
- _handler = h;
- }
- internal abstract void Write(byte[] data, int offset, int length);
- internal abstract void WriteByte(byte data);
- internal abstract void Flush();
- internal abstract void Close();
- internal abstract bool DataAvailable { get; }
- }
- internal class PlainSocket : AbstractSocket {
- private Socket _socket;
- private byte[] _buf;
- private bool _closed;
- internal PlainSocket(Socket s, IByteArrayHandler h) : base(h) {
- _socket = s;
- _buf = new byte[0x1000];
- _closed = false;
- }
-
- internal override void Write(byte[] data, int offset, int length) {
- _socket.Send(data, offset, length, SocketFlags.None);
- }
- internal override void WriteByte(byte data) {
- byte[] t = new byte[1];
- t[0] = data;
- _socket.Send(t, 0, 1, SocketFlags.None);
- }
- internal override void Flush() {
- }
- internal override void Close() {
- _socket.Close();
- _closed = true;
- }
-
- internal void RepeatAsyncRead() {
- _socket.BeginReceive(_buf, 0, _buf.Length, SocketFlags.None, new AsyncCallback(RepeatCallback), null);
- }
- internal override bool DataAvailable {
- get {
- return _socket.Available>0;
- }
- }
- private void RepeatCallback(IAsyncResult result) {
- try {
- int n = _socket.EndReceive(result);
- //GUtil.WriteDebugLog(String.Format("t={0}, n={1} cr={2} cw={3}", DateTime.Now.ToString(), n, _socket.CanRead, _socket.CanWrite));
- //Debug.WriteLine(String.Format("r={0}, n={1} cr={2} cw={3}", result.IsCompleted, n, _socket.CanRead, _socket.CanWrite));
- if(n > 0) {
- _handler.OnData(_buf, 0, n);
- _socket.BeginReceive(_buf, 0, _buf.Length, SocketFlags.None, new AsyncCallback(RepeatCallback), null);
- }
- else if(n < 0) {
- //in case of Win9x, EndReceive() returns 0 every 288 seconds even if no data is available
- _socket.BeginReceive(_buf, 0, _buf.Length, SocketFlags.None, new AsyncCallback(RepeatCallback), null);
- }
- else
- _handler.OnClosed();
- }
- catch(Exception ex) {
- if((ex is SocketException) && ((SocketException)ex).ErrorCode==995) {
- //in case of .NET1.1 on Win9x, EndReceive() changes the behavior. it throws SocketException with an error code 995.
- _socket.BeginReceive(_buf, 0, _buf.Length, SocketFlags.None, new AsyncCallback(RepeatCallback), null);
- }
- else if(!_closed)
- _handler.OnError(ex, ex.Message);
- else
- _handler.OnClosed();
- }
- }
- }
- internal class ChannelSocket : AbstractSocket, ISSHChannelEventReceiver {
- private SSHChannel _channel;
- private bool _ready;
- internal ChannelSocket(IByteArrayHandler h) : base(h) {
- _ready = false;
- }
- internal SSHChannel SSHChennal {
- get {
- return _channel;
- }
- set {
- _channel = value;
- }
- }
- internal override void Write(byte[] data, int offset, int length) {
- if(!_ready || _channel==null) throw new SSHException("channel not ready");
- _channel.Transmit(data, offset, length);
- }
- internal override void WriteByte(byte data) {
- if(!_ready || _channel==null) throw new SSHException("channel not ready");
- byte[] t = new byte[1];
- t[0] = data;
- _channel.Transmit(t);
- }
- internal override bool DataAvailable {
- get {
- return _channel.Connection.Available;
- }
- }
- internal override void Flush() {
- }
- internal override void Close() {
- if(!_ready || _channel==null) throw new SSHException("channel not ready");
- _channel.Close();
- if(_channel.Connection.ChannelCount<=1) //close last channel
- _channel.Connection.Close();
- }
- public void OnData(byte[] data, int offset, int length) {
- _handler.OnData(data, offset, length);
- }
- public void OnChannelEOF() {
- _handler.OnClosed();
- }
- public void OnChannelError(Exception error, string msg) {
- _handler.OnError(error, msg);
- }
- public void OnChannelClosed() {
- _handler.OnClosed();
- }
- public void OnChannelReady() {
- _ready = true;
- }
- public void OnExtendedData(int type, byte[] data) {
- //!!handle data
- }
- public void OnMiscPacket(byte type, byte[] data, int offset, int length) {
- }
- }
- }