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).
|