Exemple #1
0
 /// <summary>
 /// 結合されたフレームデータからメッセージを作成
 /// </summary>
 /// <param name="handshakeSession"></param>
 /// <param name="opcode"></param>
 /// <param name="payloadData"></param>
 /// <param name="isCompressed"></param>
 public WebSocketMessage(IReadOnlySession handshakeSession, WebSocketOpcode opcode, byte[] payloadData, bool isCompressed)
 {
     this.HandshakeSession = handshakeSession;
     this.Opcode           = opcode;
     this.PayloadData      = payloadData;
     this.IsCompressed     = isCompressed;
 }
        public WebSocketContent(IWebSocketMessage message, WebSocketOpcode opcode)
        {
            if (message == null) throw new ArgumentNullException("message");
            if (message == null) throw new ArgumentNullException("opcode");

            _message = new WebSocketMessage(opcode);
        }
        public WebSocketFrame(
            WebSocketFin fin,
            WebSocketRsv rsv1,
            WebSocketRsv rsv2,
            WebSocketRsv rsv3,
            WebSocketOpcode opcode,
            WebSocketMask mask,
            byte[] maskingKey,
            byte payloadLength,
            byte[] extPayloadLength,
            Stream payload
        )
        {
            if (mask == WebSocketMask.Mask && (maskingKey == null || maskingKey.Length != 4))
                throw new ArgumentOutOfRangeException("maskingKey", "must by 4 bytes long");

            _fin = fin;
            _rsv1 = rsv1;
            _rsv2 = rsv2;
            _rsv3 = rsv3;
            _opcode = opcode;
            _mask = mask;
            _maskingKey = maskingKey;
            _payloadLength = payloadLength;
            _extPayloadLength = extPayloadLength;
            _payload = payload;
        }
Exemple #4
0
        internal WebSocketFrameHeader(Stream networkStream)
        {
            byte[] head = ByteUtil.ReadNBytes(networkStream, 2);
            fin    = (head[0] & 0b10000000) > 0;          // The FIN bit tells whether this is the last message in a series. If it's 0, then the server will keep listening for more parts of the message; otherwise, the server should consider the message delivered.
            opcode = (WebSocketOpcode)(head[0] & 0b00001111);
            mask   = (head[1] & 0b10000000) > 0;          // The MASK bit simply tells whether the message is encoded.
            if (!mask)
            {
                throw new WebSocketException(WebSocketCloseCode.ProtocolError, "Client must mask all outgoing frames.");                 // TODO: Send a "Close frame" with a status code of 1002 (protocol error) // Clients MUST mask all frames they send.
            }
            payloadLength = (ulong)(head[1] & 0b01111111);
            if (payloadLength == 126)
            {
                payloadLength = ByteUtil.ReadUInt16(networkStream);
            }
            if (payloadLength == 127)
            {
                payloadLength = ByteUtil.ReadUInt64(networkStream);
            }

            if (isControlFrame && !fin)
            {
                throw new WebSocketException(WebSocketCloseCode.ProtocolError, "Control frame was fragmented");
            }
            if (isControlFrame && payloadLength > 125)
            {
                throw new WebSocketException(WebSocketCloseCode.ProtocolError, "Control frame exceeded maximum payload length");
            }

            maskBytes = ByteUtil.ReadNBytes(networkStream, 4);
        }
Exemple #5
0
 public void SendData(WebSocketOpcode opcode)
 {
     SendData(new WebMessageData()
     {
         OpCode = opcode
     });
 }
        /// <summary>
        /// Create a new WebSocket message with predefined payload
        /// </summary>
        /// <param name="opcode">opcode</param>
        /// <param name="payload">payload</param>
        public WebSocketMessage(WebSocketOpcode opcode, Stream payload)
        {
            if (payload == null) throw new ArgumentNullException("payload");

            Opcode = opcode;
            Payload = payload;
        }
Exemple #7
0
 public WebSocketFrame(
     WebSocketFin fin,
     WebSocketRsv rsv1,
     WebSocketRsv rsv2,
     WebSocketRsv rsv3,
     WebSocketOpcode opcode,
     WebSocketMask mask,
     byte[] maskingKey,
     Stream payload
     )
     : this(fin, rsv1, rsv2, rsv3, opcode, mask, maskingKey, 0, new byte[0], payload)
 {
     if (payload != null)
     {
         var len = payload.Length;
         if (len < 126)
         {
             _payloadLength    = (byte)len;
             _extPayloadLength = new byte[0];
         }
         else if (len < 0x010000)
         {
             _payloadLength    = (byte)126;
             _extPayloadLength = WebSocketUtils.GetBigEndianBytes((ushort)len);
         }
         else
         {
             _payloadLength    = (byte)127;
             _extPayloadLength = WebSocketUtils.GetBigEndianBytes((ulong)len);
         }
     }
 }
        public void Write(WebSocketOpcode opcode, byte[] data)
        {
            using (MemoryStream ms = new MemoryStream()) {
                byte bitFin = 0x80;
                byte first  = (byte)(bitFin | (byte)opcode);

                ms.WriteByte(first);
                byte second;

                if (data.Length <= 125)
                {
                    second = (byte)data.Length;
                    ms.WriteByte(second);
                }
                else if (data.Length <= 65535)
                {
                    second = 126;
                    ms.WriteByte(second);
                    WebSocketReaderWriter.WriteNumber(ms, (ushort)data.Length, false);
                }
                else
                {
                    second = 127;
                    ms.WriteByte(second);
                    WebSocketReaderWriter.WriteNumber(ms, (ulong)data.Length, false);
                }

                ms.Write(data, 0, data.Length);
                byte[] buffer = ms.ToArray();
                Stream.Write(buffer, 0, buffer.Length);
            }
        }
 public async Task Broadcast(WebSocketOpcode code, byte[] data)
 {
     foreach (var keypair in Users)
     {
         await keypair.Value.Writer.Write(code, data);
     }
 }
Exemple #10
0
        /// <summary>
        /// 异步发送字节数组并指定内容类型
        /// </summary>
        /// <param name="data"></param>
        /// <param name="opcode"></param>
        /// <param name="userState"></param>
        /// <exception cref="ArgumentNullException">message is null</exception>
        /// <exception cref="IOException">network is closed</exception>
        public void SendAsync(byte[] data, WebSocketOpcode opcode, object userState)
        {
            //协议要求,客户端向服务端发送数据是mask必需为true

            if (!this.isConnectioned)
            {
                throw new IOException("WebSocket Closed");
            }

            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            var df     = new WebSocketDataFrame(data, true, opcode);
            var buffer = df.GetFrameBytes();

            try
            {
                lock (this.sendLockObject)
                {
                    this.stream.BeginWrite(buffer, 0, buffer.Length, this.SendCallback, userState);
                }
            }
            catch (Exception exception)
            {
                this.OnError(exception);
                this.Close(WebSocketCloseReason.IOError);
                throw;
            }
        }
Exemple #11
0
        public WebSocketFrame(
            WebSocketFin fin,
            WebSocketRsv rsv1,
            WebSocketRsv rsv2,
            WebSocketRsv rsv3,
            WebSocketOpcode opcode,
            WebSocketMask mask,
            byte[] maskingKey,
            byte payloadLength,
            byte[] extPayloadLength,
            Stream payload
            )
        {
            if (mask == WebSocketMask.Mask && (maskingKey == null || maskingKey.Length != 4))
            {
                throw new ArgumentOutOfRangeException("maskingKey", "must by 4 bytes long");
            }

            _fin              = fin;
            _rsv1             = rsv1;
            _rsv2             = rsv2;
            _rsv3             = rsv3;
            _opcode           = opcode;
            _mask             = mask;
            _maskingKey       = maskingKey;
            _payloadLength    = payloadLength;
            _extPayloadLength = extPayloadLength;
            _payload          = payload;
        }
Exemple #12
0
 /// <summary>
 /// Constructs a non-fragmented WebSocketFrameHeader for the purpose of serializing it to a stream with <see cref="Write(Stream)"/>.
 /// </summary>
 /// <param name="opcode">The opcode to include in the header.</param>
 /// <param name="payloadLength">The payload length to include in the header.</param>
 internal WebSocketFrameHeader(WebSocketOpcode opcode, int payloadLength)
 {
     this.fin           = true;
     this.opcode        = opcode;
     this.mask          = false;
     this.payloadLength = (ulong)payloadLength;
 }
 public WebSocketFrame(
     WebSocketFin fin,
     WebSocketRsv rsv1,
     WebSocketRsv rsv2,
     WebSocketRsv rsv3,
     WebSocketOpcode opcode,
     WebSocketMask mask,
     byte[] maskingKey,
     Stream payload
 )
     : this(fin, rsv1, rsv2, rsv3, opcode, mask, maskingKey, 0, new byte[0], payload)
 {
     if (payload != null)
     {
         var len = payload.Length;
         if (len < 126)
         {
             _payloadLength = (byte)len;
             _extPayloadLength = new byte[0];
         }
         else if (len < 0x010000)
         {
             _payloadLength = (byte)126;
             _extPayloadLength = WebSocketUtils.GetBigEndianBytes((ushort)len);
         }
         else
         {
             _payloadLength = (byte)127;
             _extPayloadLength = WebSocketUtils.GetBigEndianBytes((ulong)len);
         }
     }
 }
Exemple #14
0
 internal WebSocketFrameHeader(WebSocketFrameHeader other)
 {
     fin           = other.fin;
     opcode        = other.opcode;
     mask          = other.mask;
     maskBytes     = other.maskBytes;
     payloadLength = other.payloadLength;
 }
 // Control frames can't have fin=false
 public Task ReadBinaryFormattedFrames(byte[] rawFrame, byte[] payload, WebSocketOpcode opcode, bool endOfMessage)
 {
     return(RunSingleFrameTest(
                rawFrame,
                endOfMessage,
                opcode,
                b => Assert.Equal(payload, b)));
 }
Exemple #16
0
 /// <summary>
 /// Creates an instance of a WebSocketHeader.
 /// </summary>
 /// <param name="fin">Whether or not this is the final frame in the message.</param>
 /// <param name="opcode">The opcode of the frame.</param>
 /// <param name="masked">Whether the frame payload is masked.</param>
 /// <param name="payloadLength">The length of the frame payload.</param>
 /// <param name="maskingKey">The masking key used to unmask the payload, if masked. This mask must be a cryptographically random value.</param>
 public WebSocketHeader(bool fin, WebSocketOpcode opcode, bool masked, ulong payloadLength, int maskingKey)
 {
     Fin           = fin;
     Opcode        = opcode;
     Masked        = masked;
     PayloadLength = payloadLength;
     MaskingKey    = maskingKey;
 }
Exemple #17
0
            private void SendData(WebSocketOpcode opcode)
            {
                var sendData = PacketResponseData(new WebMessageData()
                {
                    Data = new byte[1], OpCode = opcode
                });

                _session?.SendDataToServer(sendData);
            }
Exemple #18
0
 public WebSocketFrame(
     WebSocketFin fin,
     WebSocketOpcode opcode,
     WebSocketMask mask,
     Stream payload
     )
     : this(fin, WebSocketRsv.Off, WebSocketRsv.Off, WebSocketRsv.Off, opcode, mask, mask == WebSocketMask.Mask ? WebSocketUtils.CreateMaskingKey() : new byte[0], payload)
 {
 }
Exemple #19
0
        /// <summary>
        /// Create a new WebSocket message with predefined payload
        /// </summary>
        /// <param name="opcode">opcode</param>
        /// <param name="payload">payload</param>
        public WebSocketMessage(WebSocketOpcode opcode, Stream payload)
        {
            if (payload == null)
            {
                throw new ArgumentNullException("payload");
            }

            Opcode  = opcode;
            Payload = payload;
        }
Exemple #20
0
        public WebSocketFrame Read(Stream stream, WebSocketClient client)
        {
            byte first;

            try {
                first = (byte)stream.ReadByte();
            } catch (Exception e) {
                return(null);
            }

            if (!WebSocketUtils.IsClientConnected(client))
            {
                return(null);
            }

            byte bitFinFlag = 0x80;
            byte opcodeFlag = 0x0F;

            bool            bitFinSet = (first & bitFinFlag) == bitFinFlag;
            WebSocketOpcode opcode    = (WebSocketOpcode)(first & opcodeFlag);

            byte bitMaskFlag = 0x80;
            byte second      = (byte)stream.ReadByte();

            bool bitMaskSet = (second & bitMaskFlag) == bitMaskFlag;
            uint length     = ReadLength(stream, second);

            if (length != 0)
            {
                byte[] decoded;

                if (bitMaskSet)
                {
                    byte[] key     = WebSocketReaderWriter.Read(stream, 4);
                    byte[] encoded = WebSocketReaderWriter.Read(stream, length);

                    decoded = new byte[length];

                    for (int i = 0; i < encoded.Length; i++)
                    {
                        decoded[i] = (byte)(encoded[i] ^ key[i % 4]);
                    }
                }
                else
                {
                    decoded = WebSocketReaderWriter.Read(stream, length);
                }

                WebSocketFrame frame = new WebSocketFrame(opcode, decoded);

                return(frame);
            }

            return(null);
        }
Exemple #21
0
        private void LogFrame(ILogger logger, WebSocketOpcode lastFrameOpcode, ref WebSocketFrame frame)
        {
            var opcode = frame.Opcode;

            if (opcode == WebSocketOpcode.Continuation)
            {
                opcode = lastFrameOpcode;
            }

            logger.LogDebug($"Received {frame.Opcode} frame (FIN={frame.EndOfMessage}, LEN={frame.Payload.Length})");
        }
Exemple #22
0
 private Task SendCoreAsync <T>(bool fin, WebSocketOpcode opcode, int payloadAllocLength, int payloadLength, Action <WritableBuffer, Span <byte>, int, T> payloadWriter, T payload, CancellationToken cancellationToken)
 {
     if (_sendLock.Wait(0))
     {
         return(SendCoreLockAcquiredAsync(fin, opcode, payloadAllocLength, payloadLength, payloadWriter, payload, cancellationToken));
     }
     else
     {
         return(SendCoreWaitForLockAsync(fin, opcode, payloadAllocLength, payloadLength, payloadWriter, payload, cancellationToken));
     }
 }
Exemple #23
0
 internal void SendFrame(WebSocketOpcode opcode, byte[] data)
 {
     lock (sendLock)
     {
         // Write frame header
         WebSocketFrameHeader head = new WebSocketFrameHeader(opcode, data.Length);
         head.Write(tcpStream);
         // Write payload
         tcpStream.Write(data, 0, data.Length);
     }
 }
Exemple #24
0
 /// <summary>
 /// 引发消息事件
 /// </summary>
 /// <param name="data"></param>
 /// <param name="opcode"></param>
 protected void OnMessage(byte[] data, WebSocketOpcode opcode)
 {
     if (this.Message != null)
     {
         var args = new WebSocketMessageEventArgs(opcode);
         args.Buffer = data;
         if (opcode == WebSocketOpcode.Text)
         {
             args.Message = this.encoding.GetString(data);
         }
         this.Message(this, args);
     }
 }
Exemple #25
0
        public WebSocketContent(IWebSocketMessage message, WebSocketOpcode opcode)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            if (message == null)
            {
                throw new ArgumentNullException("opcode");
            }

            _message = new WebSocketMessage(opcode);
        }
Exemple #26
0
            public async Task WriteBinaryFormattedFrames(byte[] payload, WebSocketOpcode opcode, bool endOfMessage, byte[] expectedRawFrame)
            {
                var data = await RunSendTest(
                    producer : async(socket) =>
                {
                    await socket.SendAsync(CreateFrame(
                                               endOfMessage,
                                               opcode,
                                               payload: payload)).OrTimeout();
                }, options : DefaultTestOptions);

                Assert.Equal(expectedRawFrame, data);
            }
Exemple #27
0
        public void SendData(WebSocketOpcode opcode, byte[] buffer, int offset, int count)
        {
            if (buffer.Length == count && offset == 0)
            {
                SendData(opcode, buffer);
                return;
            }

            var data = new byte[count];

            System.Buffer.BlockCopy(buffer, offset, data, 0, count);
            SendData(opcode, data);
        }
Exemple #28
0
        private async Task SendCoreLockAcquiredAsync <T>(bool fin, WebSocketOpcode opcode, int payloadAllocLength, int payloadLength, Action <WritableBuffer, Span <byte>, int, T> payloadWriter, T payload, CancellationToken cancellationToken)
        {
            try
            {
                // Ensure the lock is held
                Debug.Assert(_sendLock.CurrentCount == 0);

                // Base header size is 2 bytes.
                WritableBuffer buffer;
                var            allocSize = CalculateAllocSize(payloadAllocLength, payloadLength);

                // Allocate a buffer
                buffer = _outbound.Alloc(minimumSize: allocSize);
                Debug.Assert(buffer.Memory.Length >= allocSize);

                // Write the opcode and FIN flag
                var opcodeByte = (byte)opcode;
                if (fin)
                {
                    opcodeByte |= 0x80;
                }
                buffer.WriteBigEndian(opcodeByte);

                // Write the length and mask flag
                WritePayloadLength(payloadLength, buffer);

                var maskingKey = Span <byte> .Empty;
                if (_maskingKeyBuffer != null)
                {
                    // Get a span of the output buffer for the masking key, write it there, then advance the write head.
                    maskingKey = buffer.Memory.Slice(0, 4).Span;
                    WriteMaskingKey(maskingKey);
                    buffer.Advance(4);
                }

                // Write the payload
                payloadWriter(buffer, maskingKey, payloadLength, payload);

                // Flush.
                await buffer.FlushAsync();
            }
            finally
            {
                // Unlock.
                _sendLock.Release();
            }
        }
Exemple #29
0
        /// <summary>
        /// 初始一个输出内容帧
        /// </summary>
        /// <param name="content"></param>
        /// <param name="isMask"></param>
        /// <param name="opcode"></param>
        public WebSocketDataFrame(byte[] content, bool isMask, WebSocketOpcode opcode = WebSocketOpcode.Text)
        {
            this.Content = content;
            int length = this.Content.Length;

            if (length < 126)
            {
                _extend = new byte[0];
                _header = new WebSocketDataFrameHeader(true, false, false, false, (sbyte)opcode, isMask, length);
            }
            else if (length < 65536)
            {
                _extend    = new byte[2];
                _header    = new WebSocketDataFrameHeader(true, false, false, false, (sbyte)opcode, isMask, 126);
                _extend[0] = (byte)(length / 256);
                _extend[1] = (byte)(length % 256);
            }
            else
            {
                _extend = new byte[8];
                _header = new WebSocketDataFrameHeader(true, false, false, false, (sbyte)opcode, isMask, 127);

                int left = length;
                int unit = 256;

                for (int i = 7; i > 1; i--)
                {
                    _extend[i] = (byte)(left % unit);
                    left       = left / unit;

                    if (left == 0)
                    {
                        break;
                    }
                }
            }
            //
            if (_header.HasMask)
            {
                _mask = Adf.BaseDataConverter.ToBytes(Environment.TickCount + content.GetHashCode());
                Mask(this.Content, _mask);
            }
        }
        /// <summary>
        /// 发送一组数据,并指定消息类型
        /// </summary>
        /// <param name="data"></param>
        /// <param name="opcode"></param>
        /// <exception cref="System.Net.Sockets.SocketException"></exception>
        /// <exception cref="System.ObjectDisposedException"></exception>
        public void Send(byte[] data, WebSocketOpcode opcode)
        {
            //协议原因,一些客户端不支持服务器端的 mask ,因此此值必需为  false

            var df     = new WebSocketDataFrame(data, false, opcode);
            var buffer = df.GetFrameBytes();

            try
            {
                lock (this.sendLockObject)
                {
                    this.socket.Send(buffer);
                }
            }
            catch (Exception exception)
            {
                this.Close("IO Error on send," + exception.Message, WebSocketCloseReason.IOError);
                throw;
            }
        }
        /// <summary>
        /// 发送一组数据,并指定消息类型
        /// </summary>
        /// <param name="data"></param>
        /// <param name="opcode"></param>
        /// <param name="userSate"></param>
        /// <exception cref="System.Net.Sockets.SocketException"></exception>
        /// <exception cref="System.ObjectDisposedException"></exception>
        public void SendAsync(byte[] data, WebSocketOpcode opcode, object userSate)
        {
            //协议原因,一些客户端不支持服务器端的 mask ,因此此值必需为  false

            var df     = new WebSocketDataFrame(data, false, opcode);
            var buffer = df.GetFrameBytes();

            try
            {
                lock (this.sendLockObject)
                {
                    this.socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, this.SendCallback, userSate);
                }
            }
            catch (Exception exception)
            {
                this.Close("IO Error on send," + exception.Message, WebSocketCloseReason.IOError);
                throw;
            }
        }
Exemple #32
0
        public void SendData(WebSocketOpcode opcode, byte[] data)
        {
            if (Interlocked.Read(ref _isDisposed) != 0)
            {
                return;
            }
            if (data == null || data.Length == 0)
            {
                return;
            }
#if ADDMSGID
            var msgid = Interlocked.Increment(ref _curMsgId);
#endif
            SendData(new WebMessageData()
            {
#if ADDMSGID
                MessageId = (byte)msgid,
#endif
                Data   = data,
                OpCode = opcode
            });
        }
        public void SendData(WebSocketOpcode opcode, byte[] data, bool isFinalFrame)
        {
            var  buffer = new List <byte>();
            long len    = data.LongLength;
            var  b1     = (byte)(0x7F & (byte)opcode);

            if (isFinalFrame)
            {
                b1 = (byte)(b1 | 0x80);
            }
            buffer.Add(b1);
            if (len < 126)
            {
                var b2 = (byte)(0x7F & data.Length);
                buffer.Add(b2);
            }
            else if (len < 0xFFFF)
            {
                buffer.Add(0x7E);
                buffer.Add((byte)((len & 0xFF00) >> 8));
                buffer.Add((byte)((len & 0x00FF) >> 0));
            }
            else if (len < 0x7FFFFFFFFFFFFFFF)
            {
                buffer.Add(0x7F);
                buffer.Add((byte)((len & 0x7F00000000000000) >> 7 * 8));
                buffer.Add((byte)((len & 0x00FF000000000000) >> 6 * 8));
                buffer.Add((byte)((len & 0x0000FF0000000000) >> 5 * 8));
                buffer.Add((byte)((len & 0x000000FF00000000) >> 4 * 8));
                buffer.Add((byte)((len & 0x00000000FF000000) >> 3 * 8));
                buffer.Add((byte)((len & 0x0000000000FF0000) >> 2 * 8));
                buffer.Add((byte)((len & 0x000000000000FF00) >> 1 * 8));
                buffer.Add((byte)((len & 0x00000000000000FF) >> 0 * 8));
            }
            buffer.AddRange(data);

            Write(buffer.ToArray());
        }
        public async Task Write(WebSocketOpcode opcode, byte[] data)
        {
            using (MemoryStream ms = new MemoryStream()) {
                try {
                    byte bitFin = 0x80;
                    byte first  = (byte)(bitFin | (byte)opcode);

                    byte[] firstData = new byte[] { first };
                    await ms.WriteAsync(firstData, 0, firstData.Length);

                    if (data.Length <= 125)
                    {
                        byte[] secData = new byte[] { (byte)data.Length };
                        await ms.WriteAsync(secData, 0, secData.Length);
                    }
                    else if (data.Length <= 65535)
                    {
                        byte[] secData = new byte[] { 126 };
                        await ms.WriteAsync(secData, 0, secData.Length);

                        await WebSocketReaderWriter.WriteNumber(ms, (ushort)data.Length, false);
                    }
                    else
                    {
                        byte[] secData = new byte[] { 127 };
                        await ms.WriteAsync(secData, 0, secData.Length);

                        await WebSocketReaderWriter.WriteNumber(ms, (ulong)data.Length, false);
                    }

                    await ms.WriteAsync(data, 0, data.Length);

                    byte[] buffer = ms.ToArray();
                    await Stream.WriteAsync(buffer, 0, buffer.Length);
                } catch (Exception) {
                }
            }
        }
        public WebSocketFrame(
            WebSocketFin fin,
            WebSocketOpcode opcode,
            WebSocketMask mask,
            Stream payload
        )
            : this(fin, WebSocketRsv.Off, WebSocketRsv.Off, WebSocketRsv.Off, opcode, mask, mask == WebSocketMask.Mask ? WebSocketUtils.CreateMaskingKey() : new byte[0], payload)
        {

        }
 /// <summary>
 /// Creates a new WebSocket message with empty payload. This is useful for control messages such as PING, PONG and CLOSE
 /// </summary>
 /// <param name="opcode">opcode</param>
 public WebSocketMessage(WebSocketOpcode opcode)
     : this(opcode, Stream.Null)
 {
 }