1+ using UnityEngine ;
2+
3+ using System ;
4+ using System . Net ;
5+ using System . Net . Sockets ;
6+ using System . Collections . Concurrent ;
7+ // For parsing the client websocket requests
8+ using System . Text ;
9+ using System . Text . RegularExpressions ;
10+ // For creating a thread
11+ using System . Threading ;
12+
13+
14+ namespace WebSocketServer {
15+
16+ public struct WebSocketMessage {
17+ public WebSocketMessage ( WebSocketConnection connection , string data ) {
18+ this . id = Guid . NewGuid ( ) . ToString ( ) ;
19+ this . connection = connection ;
20+ this . data = data ;
21+ }
22+
23+ public string id { get ; }
24+ public WebSocketConnection connection { get ; }
25+ public string data { get ; }
26+ }
27+
28+ public class WebSocketConnection {
29+
30+ private string id ;
31+ private TcpClient client ;
32+ private NetworkStream stream ;
33+ private WebSocketServer server ;
34+ private Thread connectionHandler ;
35+
36+ public WebSocketConnection ( TcpClient client , WebSocketServer server ) {
37+ this . id = Guid . NewGuid ( ) . ToString ( ) ;
38+ this . client = client ;
39+ this . stream = client . GetStream ( ) ;
40+ this . server = server ;
41+ }
42+
43+ public bool Establish ( ) {
44+ // Wait for enough bytes to be available
45+ while ( ! stream . DataAvailable ) ;
46+ while ( client . Available < 3 ) ;
47+ // Translate bytes of request to a RequestHeader object
48+ Byte [ ] bytes = new Byte [ client . Available ] ;
49+ stream . Read ( bytes , 0 , bytes . Length ) ;
50+ RequestHeader request = new RequestHeader ( Encoding . UTF8 . GetString ( bytes ) ) ;
51+
52+ // Check if the request complies with WebSocket protocol.
53+ if ( WebSocketProtocol . CheckConnectionHandshake ( request ) ) {
54+ // If so, initiate the connection by sending a reply according to protocol.
55+ Byte [ ] response = WebSocketProtocol . CreateHandshakeReply ( request ) ;
56+ stream . Write ( response , 0 , response . Length ) ;
57+
58+ Debug . Log ( "WebSocket client connected." ) ;
59+
60+ // Start message handling
61+ connectionHandler = new Thread ( new ThreadStart ( HandleConnection ) ) ;
62+ connectionHandler . IsBackground = true ;
63+ connectionHandler . Start ( ) ;
64+
65+ // Call the server callback.
66+ server . OnOpen ( this ) ;
67+ return true ;
68+ } else {
69+ return false ;
70+ }
71+ }
72+
73+ private void HandleConnection ( ) {
74+ while ( true ) {
75+ WebSocketDataFrame dataframe = ReadDataFrame ( ) ;
76+
77+ if ( dataframe . fin ) {
78+ if ( ( WebSocketOpCode ) dataframe . opcode == WebSocketOpCode . Text ) {
79+ // Let the server know of the message.
80+ string data = WebSocketProtocol . DecodeText ( dataframe ) ;
81+ WebSocketMessage message = new WebSocketMessage ( this , data ) ;
82+ server . messages . Enqueue ( message ) ;
83+ } else if ( ( WebSocketOpCode ) dataframe . opcode == WebSocketOpCode . Close ) {
84+ // Handle closing the connection
85+ Debug . Log ( "Client closed the connection." ) ;
86+ stream . Close ( ) ;
87+ client . Close ( ) ;
88+ server . OnClose ( this ) ;
89+ break ;
90+ }
91+ } else {
92+ Debug . Log ( "Framentation encoutered." ) ;
93+ }
94+ }
95+ }
96+
97+
98+ private WebSocketDataFrame ReadDataFrame ( ) {
99+ const int DataframeHead = 2 ; // Length of dataframe head
100+ const int ShortPayloadLength = 2 ; // Length of a short payload length field
101+ const int LongPayloadLength = 8 ; // Length of a long payload length field
102+ const int Mask = 4 ; // Length of the payload mask
103+
104+ // Wait for a dataframe head to be available, then read the data.
105+ while ( ! stream . DataAvailable && client . Available < DataframeHead ) ;
106+ Byte [ ] bytes = new Byte [ DataframeHead ] ;
107+ stream . Read ( bytes , 0 , DataframeHead ) ;
108+
109+ // Decode the message head, including FIN, OpCode, and initial byte of the payload length.
110+ WebSocketDataFrame dataframe = WebSocketProtocol . CreateDataFrame ( ) ;
111+ WebSocketProtocol . ParseDataFrameHead ( bytes , ref dataframe ) ;
112+
113+ // Depending on the dataframe length, read & decode the next bytes for payload length
114+ if ( dataframe . length == 126 ) {
115+ while ( client . Available < ShortPayloadLength ) ; // Wait until data is available
116+ Array . Resize ( ref bytes , bytes . Length + ShortPayloadLength ) ;
117+ stream . Read ( bytes , bytes . Length - ShortPayloadLength , ShortPayloadLength ) ; // Read the next two bytes for length
118+ } else if ( dataframe . length == 127 ) {
119+ while ( client . Available < LongPayloadLength ) ; // Wait until data is available
120+ Array . Resize ( ref bytes , bytes . Length + LongPayloadLength ) ;
121+ stream . Read ( bytes , bytes . Length - LongPayloadLength , LongPayloadLength ) ; // Read the next two bytes for length
122+ }
123+ WebSocketProtocol . ParseDataFrameLength ( bytes , ref dataframe ) ; // Parse the length
124+
125+ if ( dataframe . mask ) {
126+ while ( client . Available < Mask ) ; // Wait until data is available
127+ Array . Resize ( ref bytes , bytes . Length + Mask ) ;
128+ stream . Read ( bytes , bytes . Length - Mask , Mask ) ; // Read the next four bytes for mask
129+ }
130+
131+ while ( client . Available < dataframe . length ) ; // Wait until data is available
132+ Array . Resize ( ref bytes , bytes . Length + dataframe . length ) ;
133+ stream . Read ( bytes , bytes . Length - dataframe . length , dataframe . length ) ; // Read the payload
134+ dataframe . data = bytes ;
135+
136+ return dataframe ;
137+ }
138+ }
139+
140+ }
0 commit comments