websocket-server – Rev 1
?pathlinks?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Threading;
using WebSockets.Common;
using WebSockets.Exceptions;
using WebSockets.Server.Http;
using System.IO;
using WebSockets.Events;
namespace WebSockets.Server.WebSocket
{
public class WebSocketService : WebSocketBase, IService
{
private readonly Stream _stream;
private readonly string _header;
private readonly IWebSocketLogger _logger;
private readonly TcpClient _tcpClient;
private bool _isDisposed = false;
public WebSocketService(Stream stream, TcpClient tcpClient, string header, bool noDelay, IWebSocketLogger logger)
: base(logger)
{
_stream = stream;
_header = header;
_logger = logger;
_tcpClient = tcpClient;
// send requests immediately if true (needed for small low latency packets but not a long stream).
// Basically, dont wait for the buffer to be full before before sending the packet
tcpClient.NoDelay = noDelay;
}
public void Respond()
{
base.OpenBlocking(_stream, _tcpClient.Client);
}
protected override void PerformHandshake(Stream stream)
{
string header = _header;
try
{
Regex webSocketKeyRegex = new Regex("Sec-WebSocket-Key: (.*)");
Regex webSocketVersionRegex = new Regex("Sec-WebSocket-Version: (.*)");
// check the version. Support version 13 and above
const int WebSocketVersion = 13;
int secWebSocketVersion = Convert.ToInt32(webSocketVersionRegex.Match(header).Groups[1].Value.Trim());
if (secWebSocketVersion < WebSocketVersion)
{
throw new WebSocketVersionNotSupportedException(string.Format("WebSocket Version {0} not suported. Must be {1} or above", secWebSocketVersion, WebSocketVersion));
}
string secWebSocketKey = webSocketKeyRegex.Match(header).Groups[1].Value.Trim();
string setWebSocketAccept = base.ComputeSocketAcceptString(secWebSocketKey);
string response = ("HTTP/1.1 101 Switching Protocols" + Environment.NewLine
+ "Connection: Upgrade" + Environment.NewLine
+ "Upgrade: websocket" + Environment.NewLine
+ "Sec-WebSocket-Accept: " + setWebSocketAccept);
HttpHelper.WriteHttpHeader(response, stream);
_logger.Information(this.GetType(), "Web Socket handshake sent");
}
catch (WebSocketVersionNotSupportedException ex)
{
string response = "HTTP/1.1 426 Upgrade Required" + Environment.NewLine + "Sec-WebSocket-Version: 13";
HttpHelper.WriteHttpHeader(response, stream);
throw;
}
catch (Exception ex)
{
HttpHelper.WriteHttpHeader("HTTP/1.1 400 Bad Request", stream);
throw;
}
}
private static void CloseConnection(Socket socket)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
public virtual void Dispose()
{
// send special web socket close message. Don't close the network stream, it will be disposed later
if (_stream.CanWrite && !_isDisposed)
{
using (MemoryStream stream = new MemoryStream())
{
// set the close reason to Normal
BinaryReaderWriter.WriteUShort((ushort) WebSocketCloseCode.Normal, stream, false);
// send close message to client to begin the close handshake
Send(WebSocketOpCode.ConnectionClose, stream.ToArray());
}
_isDisposed = true;
_logger.Information(this.GetType(), "Sent web socket close message to client");
CloseConnection(_tcpClient.Client);
}
}
protected override void OnConnectionClose(byte[] payload)
{
Send(WebSocketOpCode.ConnectionClose, payload);
_logger.Information(this.GetType(), "Sent response close message to client");
_isDisposed = true;
base.OnConnectionClose(payload);
}
}
}