为什么此TLS代码仅在调试模式下运行?

时间:2011-10-01 18:14:32

标签: c# sockets exception-handling tcpclient ssl

我收到一个奇怪的错误:

  

由于意外的数据包格式而导致握手失败

如果我没有调试直接运行我的代码。

如果我设置了一个断点,然后逐行调试代码,它可以正常工作。

以下是详细例外

The handshake failed due to an unexpected packet format.

   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
   at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost)
   at Searock_IM.Facebook.LoginForm.StartTls() in D:\Projects\Searock IM\Facebook\LoginForm.cs:line 456
   at Searock_IM.Facebook.LoginForm.button2_Click(Object sender, EventArgs e) in D:\Projects\Searock IM\Facebook\LoginForm.cs:line 137
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at Searock_IM.Program.Main() in D:\Projects\Searock IM\Program.cs:line 18
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

这是代码:

class Connection : IDisposable
{
    private readonly Socket _socket;
    private NetworkStream _networkStream;
    private SslStream _sslStream;

    private int _bufferStartIndex;
    private readonly byte[] _buffer = new byte[0x8000];
    private StringBuilder _recievedText = new StringBuilder();

        public StringBuilder Debug { get; private set; }

    public bool UseSecure { get; set;  }

    public void StartTls()
    {
        UseSecure = true;

        if (_networkStream == null)
            _networkStream = new NetworkStream( _socket );

        if (_sslStream != null) 
            return;

        _sslStream = new SslStream(_networkStream);
        _sslStream.AuthenticateAsClient("chat.facebook.com");

        lock (Debug)
            Debug.AppendFormat( "** Started TLS **<br/>" );
    }

    public Connection()
    {
        Debug = new StringBuilder();

        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _socket.Connect("chat.facebook.com", 5222);
    }

    public void Dispose()
    {
        if (_sslStream != null)
            _sslStream.Dispose();

        if (_networkStream != null)
            _networkStream.Dispose();
    }

    public void Send(string text)
    {
        if (String.IsNullOrEmpty( text ))
            return;

        lock (Debug)
            Debug.AppendFormat( "Out: {0} <br/>", HttpUtility.HtmlEncode(text) );

        byte[] outp = Encoding.UTF8.GetBytes(text);

        if (UseSecure)
            _sslStream.Write(outp);
        else
            _socket.Send(outp);
    }

    public string Recieve()
    {
        if (_socket.Available == 0)
            return null;

        int bytesRead = 0;
        if (UseSecure)
            bytesRead = _sslStream.Read(_buffer, _bufferStartIndex, _buffer.Length - _bufferStartIndex);
        else
            bytesRead = _socket.Receive(_buffer, _bufferStartIndex, _buffer.Length - _bufferStartIndex, SocketFlags.None);

        ReadBytes( bytesRead );

        var incomming = ClearStringBuffer();

        lock (Debug)
            Debug.AppendFormat( "In: {0}<br/> ", HttpUtility.HtmlEncode( incomming ));

        return incomming;
    }

    private void ReadBytes( int bytesRead )
    {
        // http://en.wikipedia.org/wiki/UTF-8#Design
        // Top 2 bits are either;
        //   00xx xxxx => 6 bit ASCII mapped character
        //   11xx xxxx => multi byte chatacter Start
        //   10xx xxxx => multi byte chatacter Middle of definition
        // So while last character in buffer is 'middle of definition' rewind end buffer pointer
        int endOfBuffer = bytesRead + _bufferStartIndex;
        if (endOfBuffer == 0)
            return;

        int end = endOfBuffer;
        while ((_buffer[end - 1] & 0xC0) == 0x80) --end;

        string part = Encoding.UTF8.GetString( _buffer, 0, end ).TrimEnd( '\0' );

        if (end != endOfBuffer)
        {
            _bufferStartIndex = endOfBuffer - end;
            for (int i = 0; i < _bufferStartIndex; i++)
                _buffer[i] = _buffer[i + end];
        }

        lock (_recievedText)
            _recievedText.Append( part );
    }


    private string ClearStringBuffer()
    {
        string result;

        lock (_recievedText)
        {
            result = _recievedText.ToString();
            _recievedText = new StringBuilder();
        }

        return result;
    }
}

我收到错误由于行处的意外数据包格式而导致握手失败:

_sslStream.AuthenticateAsClient("chat.facebook.com");

我从Windows窗体调用此类,并且我没有使用此窗体中的任何线程。

有人能指出我正确的方向吗?感谢。

1 个答案:

答案 0 :(得分:2)

http://chat.facebook.com:5222是否可能不需要安全连接?请参阅this Facebook help article

如果您telnet到该地址并发送一些虚拟数据,您将获得xml响应

<?xml version="1.0"?>
<stream:stream id="none" from="chat.facebook.com" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
<stream:error>
    <xml-not-well-formed xmlns="urn:ietf:params:xml:ns:xmpp-streams"/>
</stream:error>

相关问题