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; } }
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(); }
// 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); }
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); } }
// 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)); }
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."); } }