Beispiel #1
0
        internal static void UnwrapWebSocketBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer,
                                                   UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType,
                                                   out IntPtr bufferData,
                                                   out uint bufferLength)
        {
            bufferData   = IntPtr.Zero;
            bufferLength = 0;

            switch (bufferType)
            {
            case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close:
                bufferData   = buffer.CloseStatus.ReasonData;
                bufferLength = buffer.CloseStatus.ReasonLength;
                break;

            case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.None:
            case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment:
            case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage:
            case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment:
            case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message:
            case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.PingPong:
            case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UnsolicitedPong:
                bufferData   = buffer.Data.BufferData;
                bufferLength = buffer.Data.BufferLength;
                break;

            default:
                Contract.Assert(false,
                                string.Format(CultureInfo.InvariantCulture,
                                              "BufferType '{0}' is invalid/unknown.",
                                              bufferType));
                break;
            }
        }
Beispiel #2
0
        internal ArraySegment <byte> ConvertNativeBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Action action,
                                                         UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer,
                                                         UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType)
        {
            ThrowIfDisposed();

            IntPtr bufferData;
            uint   bufferLength;

            UnwrapWebSocketBuffer(buffer, bufferType, out bufferData, out bufferLength);

            if (bufferData == IntPtr.Zero)
            {
                return(WebSocketHelpers.EmptyPayload);
            }

            if (this.IsNativeBuffer(bufferData, bufferLength))
            {
                return(new ArraySegment <byte>(_InternalBuffer.Array,
                                               this.GetOffset(bufferData),
                                               (int)bufferLength));
            }

            Contract.Assert(false, "'buffer' MUST reference a memory segment within the pinned InternalBuffer.");
            // Indicates a violation in the contract with native Websocket.dll and could indicate
            // memory corruption because the internal buffer is shared between managed and native code
            throw new AccessViolationException();
        }
Beispiel #3
0
        // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation
        private bool IsPinnedSendPayloadBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer,
                                               UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType)
        {
            if (_SendBufferState != SendBufferState.SendPayloadSpecified)
            {
                return(false);
            }

            IntPtr bufferData;
            uint   bufferSize;

            UnwrapWebSocketBuffer(buffer, bufferType, out bufferData, out bufferSize);

            long nativeBufferStartAddress = bufferData.ToInt64();
            long nativeBufferEndAddress   = nativeBufferStartAddress + bufferSize;

            return(nativeBufferStartAddress >= _PinnedSendBufferStartAddress &&
                   nativeBufferEndAddress >= _PinnedSendBufferStartAddress &&
                   nativeBufferStartAddress <= _PinnedSendBufferEndAddress &&
                   nativeBufferEndAddress <= _PinnedSendBufferEndAddress);
        }
Beispiel #4
0
        internal void ConvertCloseBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Action action,
                                         UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer,
                                         out WebSocketCloseStatus closeStatus,
                                         out string reason)
        {
            ThrowIfDisposed();
            IntPtr bufferData;
            uint   bufferLength;

            closeStatus = (WebSocketCloseStatus)buffer.CloseStatus.CloseStatus;

            UnwrapWebSocketBuffer(buffer, UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close, out bufferData, out bufferLength);

            if (bufferData == IntPtr.Zero)
            {
                reason = null;
            }
            else
            {
                ArraySegment <byte> reasonBlob;
                if (this.IsNativeBuffer(bufferData, bufferLength))
                {
                    reasonBlob = new ArraySegment <byte>(_InternalBuffer.Array,
                                                         this.GetOffset(bufferData),
                                                         (int)bufferLength);
                }
                else
                {
                    Contract.Assert(false, "'buffer' MUST reference a memory segment within the pinned InternalBuffer.");
                    // Indicates a violation in the contract with native Websocket.dll and could indicate
                    // memory corruption because the internal buffer is shared between managed and native code
                    throw new AccessViolationException();
                }

                // No need to wrap DecoderFallbackException for invalid UTF8 chacters, because
                // Encoding.UTF8 will not throw but replace invalid characters instead.
                reason = Encoding.UTF8.GetString(reasonBlob.Array, reasonBlob.Offset, reasonBlob.Count);
            }
        }
Beispiel #5
0
        // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation
        internal ArraySegment <byte> ConvertPinnedSendPayloadFromNative(UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer,
                                                                        UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType)
        {
            if (!IsPinnedSendPayloadBuffer(buffer, bufferType))
            {
                // Indicates a violation in the API contract that could indicate
                // memory corruption because the pinned sendbuffer is shared between managed and native code
                throw new AccessViolationException();
            }

            Contract.Assert(Marshal.UnsafeAddrOfPinnedArrayElement(_PinnedSendBuffer.Array,
                                                                   _PinnedSendBuffer.Offset).ToInt64() == _PinnedSendBufferStartAddress,
                            "'m_PinnedSendBuffer.Array' MUST be pinned during the entire send operation.");

            IntPtr bufferData;
            uint   bufferSize;

            UnwrapWebSocketBuffer(buffer, bufferType, out bufferData, out bufferSize);

            int internalOffset = (int)(bufferData.ToInt64() - _PinnedSendBufferStartAddress);

            return(new ArraySegment <byte>(_PinnedSendBuffer.Array, _PinnedSendBuffer.Offset + internalOffset, (int)bufferSize));
        }
Beispiel #6
0
        internal void ValidateNativeBuffers(UnsafeNativeMethods.WebSocketProtocolComponent.Action action,
                                            UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType,
                                            UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers,
                                            uint dataBufferCount)
        {
            Contract.Assert(dataBufferCount <= (uint)int.MaxValue,
                            "'dataBufferCount' MUST NOT be bigger than Int32.MaxValue.");
            Contract.Assert(dataBuffers != null, "'dataBuffers' MUST NOT be NULL.");

            ThrowIfDisposed();
            if (dataBufferCount > dataBuffers.Length)
            {
                Contract.Assert(false, "'dataBufferCount' MUST NOT be bigger than 'dataBuffers.Length'.");
                // Indicates a violation in the contract with native Websocket.dll and could indicate
                // memory corruption because the internal buffer is shared between managed and native code
                throw new AccessViolationException();
            }

            int  count          = dataBuffers.Length;
            bool isSendActivity = action == UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateSendComplete ||
                                  action == UnsafeNativeMethods.WebSocketProtocolComponent.Action.SendToNetwork;

            if (isSendActivity)
            {
                count = (int)dataBufferCount;
            }

            bool nonZeroBufferFound = false;

            for (int i = 0; i < count; i++)
            {
                UnsafeNativeMethods.WebSocketProtocolComponent.Buffer dataBuffer = dataBuffers[i];

                IntPtr bufferData;
                uint   bufferLength;
                UnwrapWebSocketBuffer(dataBuffer, bufferType, out bufferData, out bufferLength);

                if (bufferData == IntPtr.Zero)
                {
                    continue;
                }

                nonZeroBufferFound = true;

                bool isPinnedSendPayloadBuffer = IsPinnedSendPayloadBuffer(dataBuffer, bufferType);

                if (bufferLength > GetMaxBufferSize())
                {
                    if (!isSendActivity || !isPinnedSendPayloadBuffer)
                    {
                        Contract.Assert(false,
                                        "'dataBuffer.BufferLength' MUST NOT be bigger than 'm_ReceiveBufferSize' and 'm_SendBufferSize'.");
                        // Indicates a violation in the contract with native Websocket.dll and could indicate
                        // memory corruption because the internal buffer is shared between managed and native code
                        throw new AccessViolationException();
                    }
                }

                if (!isPinnedSendPayloadBuffer && !IsNativeBuffer(bufferData, bufferLength))
                {
                    Contract.Assert(false,
                                    "WebSocketGetAction MUST return a pointer within the pinned internal buffer.");
                    // Indicates a violation in the contract with native Websocket.dll and could indicate
                    // memory corruption because the internal buffer is shared between managed and native code
                    throw new AccessViolationException();
                }
            }

            if (!nonZeroBufferFound &&
                action != UnsafeNativeMethods.WebSocketProtocolComponent.Action.NoAction &&
                action != UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateReceiveComplete &&
                action != UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateSendComplete)
            {
                Contract.Assert(false, "At least one 'dataBuffer.Buffer' MUST NOT be NULL.");
            }
        }