MTSC  1.0.5
Build TCP servers out of modules with handlers for communication, exception and logging.
WebsocketMessage.cs
1 using MTSC.Exceptions;
2 using System;
3 using System.Collections.Generic;
4 using System.Text;
5 
7 {
11  public class WebsocketMessage
12  {
13  public enum Opcodes
14  {
15  Text = 1,
16  Binary = 2,
17  Close = 8,
18  Ping = 9,
19  Pong = 10
20  }
21 
22  byte controlByte = new byte();
23  byte[] lengthBytes;
24  byte[] data;
28  public bool FIN { get => (controlByte & 0x80) == 0x80; set => controlByte = (byte)(value? controlByte | 0x80 : controlByte & 0x7F);}
33  public Opcodes Opcode { get => (Opcodes)(controlByte & 0xF);
34  set => controlByte = (byte)((controlByte & 0xF0) | ((int)value & 0xF)); }
38  public bool Masked { get => (lengthBytes[0] & 0x80) == 0x80; set => lengthBytes[0] = (byte)(value ? lengthBytes[0] | 0x80 : lengthBytes[0] & 0x7F); }
42  public ulong MessageLength
43  {
44  get
45  {
46  if ((lengthBytes[0] & 0x7F) <= 125)
47  {
48  return (ulong)(lengthBytes[0] & 0x7F);
49  }
50  else if ((lengthBytes[0] & 0x7F) == 126)
51  {
52  return (ulong)((lengthBytes[2] << 8) + lengthBytes[1]);
53  }
54  else if ((lengthBytes[0] & 0x7F) == 127)
55  {
56  return (ulong)((lengthBytes[8] << 56) + (lengthBytes[7] << 48) + (lengthBytes[6] << 40) + (lengthBytes[5] << 32) +
57  (lengthBytes[4] << 24) + (lengthBytes[3] << 16) + (lengthBytes[2] << 8) + lengthBytes[1]);
58  }
59  else
60  {
61  return 0;
62  }
63  }
64  set
65  {
66  if(value <= 125)
67  {
68  if(lengthBytes.Length != 1)
69  {
70  byte[] newLengthBytes = new byte[1];
71  newLengthBytes[0] = lengthBytes[0];
72  lengthBytes = newLengthBytes;
73  }
74  lengthBytes[0] = (byte)((lengthBytes[0] & 0x80) | ((byte)value & 0x7F));
75  }
76  else if(value <= UInt16.MaxValue)
77  {
78  if (lengthBytes.Length != 3)
79  {
80  byte[] newLengthBytes = new byte[3];
81  newLengthBytes[0] = (byte)(lengthBytes[0] & 0x80);
82  newLengthBytes[0] += 126;
83  lengthBytes = newLengthBytes;
84  }
85  for(int i = 1; i < 3; i++)
86  {
87  lengthBytes[i] = (byte)(value & 0xFF);
88  value >>= 8;
89  }
90  }
91  else if(value <= UInt64.MaxValue)
92  {
93  if (lengthBytes.Length != 8)
94  {
95  byte[] newLengthBytes = new byte[9];
96  newLengthBytes[0] = (byte)(lengthBytes[0] & 0x80);
97  newLengthBytes[0] += 127;
98  lengthBytes = newLengthBytes;
99  }
100  for (int i = 1; i < 9; i++)
101  {
102  lengthBytes[i] = (byte)(value & 0xFF);
103  value >>= 8;
104  }
105  }
106  else
107  {
108 
109  }
110  }
111  }
115  public byte[] Mask { get; set; }
119  public byte[] Data
120  {
121  get => data;
122  set
123  {
124  MessageLength = (ulong)value.Length;
125  data = value;
126  }
127  }
128 
133  public WebsocketMessage(byte[] messageBytes)
134  {
135  controlByte = messageBytes[0];
136  Mask = new byte[4];
137  ulong dataLength = 0;
138  int dataIndex = 0;
139  if ((messageBytes[1] & 0x7F) <= 125)
140  {
141  lengthBytes = new byte[1];
142  lengthBytes[0] = messageBytes[1];
143  dataLength = (ulong)(messageBytes[1] & 0x7F);
144  dataIndex = 2;
145  }
146  else if ((messageBytes[1] & 0x7F) == 126)
147  {
148  dataLength = (ulong)((messageBytes[3] << 8) + messageBytes[2]);
149  lengthBytes = new byte[3];
150  Array.Copy(messageBytes, 1, lengthBytes, 0, 3);
151  dataIndex = 4;
152  }
153  else if ((messageBytes[1] & 0x7F) == 127)
154  {
155  dataLength = (ulong)((messageBytes[9] << 56) + (messageBytes[8] << 48) + (messageBytes[7] << 40) + (messageBytes[6] << 32) +
156  (messageBytes[5] << 24) + (messageBytes[4] << 16) + (messageBytes[3] << 8) + messageBytes[2]);
157  dataIndex = 10;
158  lengthBytes = new byte[9];
159  Array.Copy(messageBytes, 1, lengthBytes, 0, 9);
160  }
161  else
162  {
163  lengthBytes = new byte[0];
164  throw new InvalidWebsocketFormatException("Length formatting is wrong");
165  }
166  if ((messageBytes[1] & 0x80) > 0)
167  {
168  Array.Copy(messageBytes, dataIndex, Mask, 0, 4);
169  dataIndex += 4;
170  }
171  data = new byte[dataLength];
172  for(ulong i = 0; i < dataLength; i++)
173  {
174  data[i] = (byte)(messageBytes[(ulong)dataIndex + i] ^ Mask[i % 4]);
175  }
176  }
181  {
182  controlByte = new byte();
183  Mask = new byte[4];
184  data = new byte[0];
185  lengthBytes = new byte[1];
186  }
191  public byte[] GetMessageBytes()
192  {
193  if(data == null)
194  {
195  throw new NoDataException("There is no data in the message");
196  }
197  byte[] messageBytes = new byte[1 + lengthBytes.Length + (Masked ? 4 : 0) + data.Length];
198  messageBytes[0] = controlByte;
199  Array.Copy(lengthBytes, 0, messageBytes, 1, lengthBytes.Length);
200  if (Masked)
201  {
202  Array.Copy(Mask, 0, messageBytes, 1 + lengthBytes.Length, Mask.Length);
203  }
204  for(int i = 0; i < data.Length; i++)
205  {
206  messageBytes[1 + lengthBytes.Length + (Masked ? 4 : 0) + i] = (byte)(Masked ? data[i] ^ Mask[i % 4] : data[i]);
207  }
208  return messageBytes;
209  }
210  }
211 }
Class containing the bytes of a websocket received message.
WebsocketMessage()
Creates a new instance of websocket message.
byte [] GetMessageBytes()
Get the packed message bytes.
WebsocketMessage(byte[] messageBytes)
Creates a new instance of websocket message containing the given message.
Definition: Client.cs:14