Welcome Guest Search | Active Topics | Members | Log In | Register

SSL with XF.Server Options
admin
Posted: Sunday, October 12, 2008 6:26:09 PM
Rank: Administration
Groups: Administration

Joined: 2/15/2008
Posts: 130
Points: 835
Here is an example of a simple http server that works with SSL.
SslStream class in .NET is not good for asynchronous processing, but this example demonstrates how it can be used.

Even with this implementation SSL with XF.Server has higher performance than SSL with native NetworkStream class

NetworkAsyncStream and SslAsyncStream are planned for the future development. These streams will allow to process encrypted network I/O with higher performance.

Code:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using XF;

namespace SslServer
{
    class Program
    {
        static X509Certificate serverCertificate;
        // The certificate parameter specifies the name of the file
        // containing the machine certificate.
        public static void RunServer(string certificate)
        {
            serverCertificate = X509Certificate.CreateFromCertFile(certificate);
            using (Network.AcceptAsync(new IPEndPoint(IPAddress.Any, 443), ProcessClient))
            {
                Console.WriteLine("Secure XF.Server is ready.");
                Console.WriteLine("Press any key to exit.");
                Console.ReadKey(true);
            }
        }

        private const string responseFormat =
            "HTTP/1.1 200 OK\r\n" +
            "Server: HTTPS Server using XF.Server\r\n" +
            "Content-Type: text/plain\r\n" +
            "Content-Length: {0}\r\n" +
            "Connection: Close\r\n\r\n{1}";

        static void ProcessClient(IConnection connection)
        {
            // A client has connected. Create the
            // SslStream using the client's network stream.
            var sslStream = new SslStream(new NetworkStream(connection), false);
            // Authenticate the server but don't require the client to authenticate.
            try
            {
                sslStream.AuthenticateAsServer(serverCertificate,
                    false, SslProtocols.Tls, true);

                // Read a message from the client.   
                var request = ReadMessage(sslStream);
                var responseContent = String.Format("REQUESTED:\r\n{0}\r\nCIPHER: {1} STRENGTH {2}",
                                          request, sslStream.CipherAlgorithm, sslStream.CipherStrength);
                var response = String.Format(responseFormat, responseContent.Length, responseContent);
                sslStream.Write(Encoding.UTF8.GetBytes(response));
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
                if (e.InnerException != null)
                {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                Console.WriteLine("Authentication failed - closing the connection.");
            }
            catch(Exception e)
            {
                Console.WriteLine("Unknown error: {0}", e);
            }
            finally
            {
                // The client stream will be closed with the sslStream
                // because we specified this behavior when creating
                // the sslStream.
                sslStream.Close();
                connection.Close();
            }
        }

        static string ReadMessage(Stream sslStream)
        {
            var buffer = new byte[2048];
            var messageData = new StringBuilder();
            int bytes;
            do
            {
                // Read the client's test message.
                bytes = sslStream.Read(buffer, 0, buffer.Length);
                messageData.Append(Encoding.UTF8.GetString(buffer, 0, bytes));
                if (messageData.ToString().IndexOf(Environment.NewLine) != -1)
                {
                    break;
                }
            } while (bytes != 0);
            return messageData.ToString();
        }

        //specify path to cer file
        static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Specify path to a certificate file(.cer)");
                return;
            }
            RunServer(args[0]);
        }
    }
}

namespace XF
{
    internal class NetworkStream : Stream
    {
        private readonly IConnection connection;
        private readonly ManualResetEvent readEvent = new ManualResetEvent(false);
        private readonly Queue<KeyValuePair<IMemoryBuffer, int>> buffers = new Queue<KeyValuePair<IMemoryBuffer, int>>();
        private bool disconnected;

        public NetworkStream(IConnection connection)
        {
            this.connection = connection;
            connection.ReadAsync((ignore, memoryBuffer, bytesReceived) =>
            {
                if (bytesReceived > 0)
                {
                    lock (buffers)
                    {
                        memoryBuffer.Acquire();
                        buffers.Enqueue(new KeyValuePair<IMemoryBuffer, int>(memoryBuffer, bytesReceived));
                    }
                }
                else disconnected = true;
                readEvent.Set();
            });
        }

        private int currentOffset;
        private KeyValuePair<IMemoryBuffer, int>? currentBufferData;

        public override int Read(byte[] buffer, int offset, int count)
        {
            readEvent.WaitOne();
            if (disconnected) return 0;

            if (currentBufferData == null)
            {
                lock(buffers)
                {
                    if (buffers.Count > 0)
                        currentBufferData = buffers.Dequeue();
                }
            }

            var memoryBuffer = currentBufferData.Value.Key;
            var dataSize = currentBufferData.Value.Value;
            var x = dataSize - currentOffset;
            if (x > count)
            {
                Buffer.BlockCopy(memoryBuffer.Data, memoryBuffer.Offset + currentOffset, buffer, offset, count);
                currentOffset += count;
                return count;
            }

            Buffer.BlockCopy(memoryBuffer.Data, memoryBuffer.Offset + currentOffset, buffer, offset, x);
            currentOffset = 0;
            memoryBuffer.Release();
            currentBufferData = null;
            if (buffers.Count == 0) readEvent.Reset();
            return x;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            connection.WriteAsync(buffer, offset, count);
        }

        public override bool CanRead
        {
            get { return true; }
        }

        public override bool CanWrite
        {
            get { return true; }
        }

        public override long Length
        {
            get { throw new System.NotSupportedException(); }
        }
        public override long Position
        {
            get { throw new System.NotSupportedException(); }
            set { throw new System.NotSupportedException(); }
        }
        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new System.NotSupportedException();
        }
        public override bool CanSeek
        {
            get { return false; }
        }
        public override void Flush()
        {
            throw new System.NotSupportedException();
        }
        public override void SetLength(long value)
        {
            throw new System.NotSupportedException();
        }
    }
}

File Attachment(s):
SslServer.zip (5kb) downloaded 40 time(s).


Users browsing this topic
Guest


Forum Jump
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Main Forum RSS : RSS

YAFPro Theme Created by Jaben Cargman (Tiny Gecko)
Powered by Yet Another Forum.net version 1.9.1.6 (NET v2.0) - 11/14/2007
Copyright © 2003-2006 Yet Another Forum.net. All rights reserved.
This page was generated in 0.087 seconds.
11 queries (0.038 seconds, 43.68%).

yaf_pageload: 0.014
yaf_replace_words_list: 0.001
yaf_topic_info: 0.001
yaf_forum_list: 0.003
yaf_category_simplelist: 0.001
yaf_forum_listpath: 0.001
yaf_forum_listpath: 0.001
yaf_post_list: 0.012
yaf_usergroup_list: 0.001
yaf_attachment_list: 0.002
yaf_active_listtopic: 0.001