diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs index 534db841c7e383..44dc1822589a05 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs @@ -26,84 +26,65 @@ private MsQuicApi(NativeApi* vtable) uint status; SetParamDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->SetParam); + new SetParamDelegate(new DelegateHelper(vtable->SetParam).SetParam); GetParamDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->GetParam); + new GetParamDelegate(new DelegateHelper(vtable->GetParam).GetParam); SetCallbackHandlerDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->SetCallbackHandler); + new SetCallbackHandlerDelegate(new DelegateHelper(vtable->SetCallbackHandler).SetCallbackHandler); RegistrationOpenDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->RegistrationOpen); + new RegistrationOpenDelegate(new DelegateHelper(vtable->RegistrationOpen).RegistrationOpen); RegistrationCloseDelegate = Marshal.GetDelegateForFunctionPointer( vtable->RegistrationClose); ConfigurationOpenDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->ConfigurationOpen); + new ConfigurationOpenDelegate(new DelegateHelper(vtable->ConfigurationOpen).ConfigurationOpen); ConfigurationCloseDelegate = Marshal.GetDelegateForFunctionPointer( vtable->ConfigurationClose); ConfigurationLoadCredentialDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->ConfigurationLoadCredential); + new ConfigurationLoadCredentialDelegate(new DelegateHelper(vtable->ConfigurationLoadCredential).ConfigurationLoadCredential); ListenerOpenDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->ListenerOpen); + new ListenerOpenDelegate(new DelegateHelper(vtable->ListenerOpen).ListenerOpen); ListenerCloseDelegate = Marshal.GetDelegateForFunctionPointer( vtable->ListenerClose); ListenerStartDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->ListenerStart); + new ListenerStartDelegate(new DelegateHelper(vtable->ListenerStart).ListenerStart); ListenerStopDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->ListenerStop); + new ListenerStopDelegate(new DelegateHelper(vtable->ListenerStop).ListenerStop); ConnectionOpenDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->ConnectionOpen); + new ConnectionOpenDelegate(new DelegateHelper(vtable->ConnectionOpen).ConnectionOpen); ConnectionCloseDelegate = Marshal.GetDelegateForFunctionPointer( vtable->ConnectionClose); ConnectionSetConfigurationDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->ConnectionSetConfiguration); + new ConnectionSetConfigurationDelegate(new DelegateHelper(vtable->ConnectionSetConfiguration).ConnectionSetConfiguration); ConnectionShutdownDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->ConnectionShutdown); + new ConnectionShutdownDelegate(new DelegateHelper(vtable->ConnectionShutdown).ConnectionShutdown); ConnectionStartDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->ConnectionStart); + new ConnectionStartDelegate(new DelegateHelper(vtable->ConnectionStart).ConnectionStart); StreamOpenDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->StreamOpen); + new StreamOpenDelegate(new DelegateHelper(vtable->StreamOpen).StreamOpen); StreamCloseDelegate = Marshal.GetDelegateForFunctionPointer( vtable->StreamClose); StreamStartDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->StreamStart); + new StreamStartDelegate(new DelegateHelper(vtable->StreamStart).StreamStart); StreamShutdownDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->StreamShutdown); + new StreamShutdownDelegate(new DelegateHelper(vtable->StreamShutdown).StreamShutdown); StreamSendDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->StreamSend); + new StreamSendDelegate(new DelegateHelper(vtable->StreamSend).StreamSend); StreamReceiveCompleteDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->StreamReceiveComplete); + new StreamReceiveCompleteDelegate(new DelegateHelper(vtable->StreamReceiveComplete).StreamReceiveComplete); StreamReceiveSetEnabledDelegate = - Marshal.GetDelegateForFunctionPointer( - vtable->StreamReceiveSetEnabled); + new StreamReceiveSetEnabledDelegate(new DelegateHelper(vtable->StreamReceiveSetEnabled).StreamReceiveSetEnabled); var cfg = new RegistrationConfig { @@ -142,9 +123,10 @@ static MsQuicApi() { if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) { - delegate* unmanaged[Cdecl] msQuicOpenVersion = - (delegate* unmanaged[Cdecl])msQuicOpenVersionAddress; - uint status = msQuicOpenVersion(MsQuicVersion, out NativeApi* vtable); + NativeApi* vtable; + delegate* unmanaged[Cdecl] msQuicOpenVersion = + (delegate* unmanaged[Cdecl])msQuicOpenVersionAddress; + uint status = msQuicOpenVersion(MsQuicVersion, &vtable); if (MsQuicStatusHelper.SuccessfulStatusCode(status)) { IsQuicSupported = true; diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs index 9f974eb702b4a2..7b894cb803f04e 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs @@ -8,7 +8,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal /// /// Contains all native delegates and structs that are used with MsQuic. /// - internal static unsafe class MsQuicNativeMethods + internal static unsafe partial class MsQuicNativeMethods { [StructLayout(LayoutKind.Sequential)] internal struct NativeApi @@ -91,12 +91,38 @@ internal delegate uint RegistrationOpenDelegate( internal delegate void RegistrationCloseDelegate( IntPtr registrationContext); - [StructLayout(LayoutKind.Sequential)] + [NativeMarshalling(typeof(Native))] internal struct RegistrationConfig { - [MarshalAs(UnmanagedType.LPUTF8Str)] internal string AppName; internal QUIC_EXECUTION_PROFILE ExecutionProfile; + + [StructLayout(LayoutKind.Sequential)] + public struct Native + { + private IntPtr AppName; + private QUIC_EXECUTION_PROFILE ExecutionProfile; + + public Native(RegistrationConfig managed) + { + AppName = Marshal.StringToCoTaskMemUTF8(managed.AppName); + ExecutionProfile = managed.ExecutionProfile; + } + + public RegistrationConfig ToManaged() + { + return new RegistrationConfig() + { + AppName = Marshal.PtrToStringUTF8(AppName)!, + ExecutionProfile = ExecutionProfile + }; + } + + public void FreeNative() + { + Marshal.FreeCoTaskMem(AppName); + } + } } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] @@ -118,6 +144,24 @@ internal delegate uint ConfigurationLoadCredentialDelegate( SafeMsQuicConfigurationHandle configuration, ref CredentialConfig credConfig); + internal struct AnyDelegateMarshaller + { + private readonly Delegate _managed; + + public AnyDelegateMarshaller(Delegate managed) + { + _managed = managed; + Value = Marshal.GetFunctionPointerForDelegate(_managed); + } + + public IntPtr Value { get; } + + public void FreeNative() + { + GC.KeepAlive(_managed); + } + } + [StructLayout(LayoutKind.Sequential)] internal struct QuicSettings { @@ -193,18 +237,58 @@ internal enum QuicSettingsEnabledFlagsFlags : byte VersionNegotiationExtEnabled = 1 << 6, } - [StructLayout(LayoutKind.Sequential)] + [NativeMarshalling(typeof(Native))] internal struct CredentialConfig { internal QUIC_CREDENTIAL_TYPE Type; internal QUIC_CREDENTIAL_FLAGS Flags; // CredentialConfigCertificateUnion* internal IntPtr Certificate; - [MarshalAs(UnmanagedType.LPUTF8Str)] + internal string Principal; internal IntPtr Reserved; // Currently unused // TODO: define delegate for AsyncHandler and make proper use of it. internal IntPtr AsyncHandler; + + [StructLayout(LayoutKind.Sequential)] + public struct Native + { + internal QUIC_CREDENTIAL_TYPE Type; + internal QUIC_CREDENTIAL_FLAGS Flags; + // CredentialConfigCertificateUnion* + internal IntPtr Certificate; + internal IntPtr Principal; + internal IntPtr Reserved; + internal IntPtr AsyncHandler; + + public Native(CredentialConfig managed) + { + Type = managed.Type; + Flags = managed.Flags; + Certificate = managed.Certificate; + Principal = Marshal.StringToCoTaskMemUTF8(managed.Principal); + Reserved = managed.Reserved; + AsyncHandler = managed.AsyncHandler; + } + + public CredentialConfig ToManaged() + { + return new CredentialConfig + { + Type = Type, + Flags = Flags, + Certificate = Certificate, + Principal = Marshal.PtrToStringUTF8(Principal)!, + Reserved = Reserved, + AsyncHandler = AsyncHandler + }; + } + + public void FreeNative() + { + Marshal.FreeCoTaskMem(Principal); + } + } } [StructLayout(LayoutKind.Explicit)] @@ -328,7 +412,7 @@ internal struct NewConnectionInfo internal delegate uint ListenerCallbackDelegate( IntPtr listener, IntPtr context, - ref ListenerEvent evt); + ListenerEvent* evt); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate uint ListenerOpenDelegate( @@ -469,7 +553,7 @@ internal struct ConnectionEvent internal delegate uint ConnectionCallbackDelegate( IntPtr connection, IntPtr context, - ref ConnectionEvent connectionEvent); + ConnectionEvent* connectionEvent); // TODO: order is Open, Close, Shutdown, Start, SetConfiguration, SendResumptionTicket [UnmanagedFunctionPointer(CallingConvention.Cdecl)] @@ -624,7 +708,7 @@ internal struct SOCKADDR_INET internal delegate uint StreamCallbackDelegate( IntPtr stream, IntPtr context, - ref StreamEvent streamEvent); + StreamEvent* streamEvent); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate uint StreamOpenDelegate( @@ -676,5 +760,728 @@ internal struct QuicBuffer } // TODO: DatagramSend missing + + internal struct DelegateHelper + { + private IntPtr _functionPointer; + + public DelegateHelper(IntPtr functionPointer) + { + _functionPointer = functionPointer; + } + internal uint SetContext(SafeHandle handle, IntPtr context) + { + IntPtr __handle_gen_native; + uint __retVal; + // + // Setup + // + bool handle__addRefd = false; + try + { + // + // Marshal + // + handle.DangerousAddRef(ref handle__addRefd); + __handle_gen_native = handle.DangerousGetHandle(); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__handle_gen_native, context); + } + finally + { + // + // Cleanup + // + if (handle__addRefd) + handle.DangerousRelease(); + } + + return __retVal; + } + internal IntPtr GetContext(SafeHandle handle) + { + IntPtr __handle_gen_native; + IntPtr __retVal; + // + // Setup + // + bool handle__addRefd = false; + try + { + // + // Marshal + // + handle.DangerousAddRef(ref handle__addRefd); + __handle_gen_native = handle.DangerousGetHandle(); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__handle_gen_native); + } + finally + { + // + // Cleanup + // + if (handle__addRefd) + handle.DangerousRelease(); + } + + return __retVal; + } + internal void SetCallbackHandler(SafeHandle handle, Delegate del, IntPtr context) + { + // + // Setup + // + bool handle__addRefd = false; + AnyDelegateMarshaller __del_gen_native__marshaller = default; + try + { + // + // Marshal + // + handle.DangerousAddRef(ref handle__addRefd); + IntPtr __handle_gen_native = handle.DangerousGetHandle(); + __del_gen_native__marshaller = new(del); + IntPtr __del_gen_native = __del_gen_native__marshaller.Value; + ((delegate* unmanaged[Cdecl])_functionPointer)(__handle_gen_native, __del_gen_native, context); + } + finally + { + // + // Cleanup + // + if (handle__addRefd) + handle.DangerousRelease(); + __del_gen_native__marshaller.FreeNative(); + } + } + internal uint SetParam(SafeHandle handle, QUIC_PARAM_LEVEL level, uint param, uint bufferLength, byte* buffer) + { + uint __retVal; + // + // Setup + // + bool handle__addRefd = false; + try + { + // + // Marshal + // + handle.DangerousAddRef(ref handle__addRefd); + IntPtr __handle_gen_native = handle.DangerousGetHandle(); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__handle_gen_native, level, param, bufferLength, buffer); + } + finally + { + // + // Cleanup + // + if (handle__addRefd) + handle.DangerousRelease(); + } + + return __retVal; + } + internal uint GetParam(SafeHandle handle, QUIC_PARAM_LEVEL level, uint param, ref uint bufferLength, byte* buffer) + { + IntPtr __handle_gen_native = default; + uint __retVal; + // + // Setup + // + bool handle__addRefd = false; + try + { + // + // Marshal + // + handle.DangerousAddRef(ref handle__addRefd); + __handle_gen_native = handle.DangerousGetHandle(); + fixed (uint* __bufferLength_gen_native = &bufferLength) + { + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__handle_gen_native, level, param, __bufferLength_gen_native, buffer); + } + } + finally + { + // + // Cleanup + // + if (handle__addRefd) + handle.DangerousRelease(); + } + + return __retVal; + } + internal uint RegistrationOpen(ref RegistrationConfig config, out SafeMsQuicRegistrationHandle registrationContext) + { + RegistrationConfig.Native __config_gen_native = default; + registrationContext = default!; + IntPtr __registrationContext_gen_native = default; + uint __retVal; + bool __invokeSucceeded = default; + // + // Setup + // + SafeMsQuicRegistrationHandle registrationContext__newHandle = new SafeMsQuicRegistrationHandle(); + try + { + // + // Marshal + // + __config_gen_native = new(config); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(&__config_gen_native, &__registrationContext_gen_native); + __invokeSucceeded = true; + // + // Unmarshal + // + config = __config_gen_native.ToManaged(); + } + finally + { + if (__invokeSucceeded) + { + // + // GuaranteedUnmarshal + // + Marshal.InitHandle(registrationContext__newHandle, __registrationContext_gen_native); + registrationContext = registrationContext__newHandle; + } + + // + // Cleanup + // + __config_gen_native.FreeNative(); + } + + return __retVal; + } + internal uint ConfigurationOpen(SafeMsQuicRegistrationHandle registrationContext, QuicBuffer* alpnBuffers, uint alpnBufferCount, ref QuicSettings settings, uint settingsSize, IntPtr context, out SafeMsQuicConfigurationHandle configuration) + { + IntPtr __registrationContext_gen_native = default; + configuration = default!; + IntPtr __configuration_gen_native = default; + uint __retVal; + bool __invokeSucceeded = default; + // + // Setup + // + bool registrationContext__addRefd = false; + SafeMsQuicConfigurationHandle configuration__newHandle = new SafeMsQuicConfigurationHandle(); + try + { + // + // Marshal + // + registrationContext.DangerousAddRef(ref registrationContext__addRefd); + __registrationContext_gen_native = registrationContext.DangerousGetHandle(); + fixed (QuicSettings* __settings_gen_native = &settings) + { + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__registrationContext_gen_native, alpnBuffers, alpnBufferCount, __settings_gen_native, settingsSize, context, &__configuration_gen_native); + } + + __invokeSucceeded = true; + } + finally + { + if (__invokeSucceeded) + { + // + // GuaranteedUnmarshal + // + Marshal.InitHandle(configuration__newHandle, __configuration_gen_native); + configuration = configuration__newHandle; + } + + // + // Cleanup + // + if (registrationContext__addRefd) + registrationContext.DangerousRelease(); + } + + return __retVal; + } + internal uint ConfigurationLoadCredential(SafeMsQuicConfigurationHandle configuration, ref CredentialConfig credConfig) + { + CredentialConfig.Native __credConfig_gen_native = default; + uint __retVal; + // + // Setup + // + bool configuration__addRefd = false; + try + { + // + // Marshal + // + configuration.DangerousAddRef(ref configuration__addRefd); + IntPtr __configuration_gen_native = configuration.DangerousGetHandle(); + __credConfig_gen_native = new(credConfig); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__configuration_gen_native, &__credConfig_gen_native); + // + // Unmarshal + // + credConfig = __credConfig_gen_native.ToManaged(); + } + finally + { + // + // Cleanup + // + if (configuration__addRefd) + configuration.DangerousRelease(); + __credConfig_gen_native.FreeNative(); + } + + return __retVal; + } + internal uint ListenerOpen(SafeMsQuicRegistrationHandle registration, ListenerCallbackDelegate handler, IntPtr context, out SafeMsQuicListenerHandle listener) + { + IntPtr __handler_gen_native = default; + listener = default!; + IntPtr __listener_gen_native = default; + uint __retVal; + bool __invokeSucceeded = default; + // + // Setup + // + bool registration__addRefd = false; + SafeMsQuicListenerHandle listener__newHandle = new SafeMsQuicListenerHandle(); + try + { + // + // Marshal + // + registration.DangerousAddRef(ref registration__addRefd); + IntPtr __registration_gen_native = registration.DangerousGetHandle(); + __handler_gen_native = handler != null ? Marshal.GetFunctionPointerForDelegate(handler) : default; + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__registration_gen_native, __handler_gen_native, context, &__listener_gen_native); + __invokeSucceeded = true; + // + // KeepAlive + // + GC.KeepAlive(handler); + } + finally + { + if (__invokeSucceeded) + { + // + // GuaranteedUnmarshal + // + Marshal.InitHandle(listener__newHandle, __listener_gen_native); + listener = listener__newHandle; + } + + // + // Cleanup + // + if (registration__addRefd) + registration.DangerousRelease(); + } + + return __retVal; + } + internal uint ListenerStart(SafeMsQuicListenerHandle listener, QuicBuffer* alpnBuffers, uint alpnBufferCount, ref SOCKADDR_INET localAddress) + { + IntPtr __listener_gen_native = default; + uint __retVal; + // + // Setup + // + bool listener__addRefd = false; + try + { + // + // Marshal + // + listener.DangerousAddRef(ref listener__addRefd); + __listener_gen_native = listener.DangerousGetHandle(); + fixed (SOCKADDR_INET* __localAddress_gen_native = &localAddress) + { + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__listener_gen_native, alpnBuffers, alpnBufferCount, __localAddress_gen_native); + } + } + finally + { + // + // Cleanup + // + if (listener__addRefd) + listener.DangerousRelease(); + } + + return __retVal; + } + internal void ListenerStop(SafeMsQuicListenerHandle listener) + { + // + // Setup + // + bool listener__addRefd = false; + try + { + // + // Marshal + // + listener.DangerousAddRef(ref listener__addRefd); + IntPtr __listener_gen_native = listener.DangerousGetHandle(); + ((delegate* unmanaged[Cdecl])_functionPointer)(__listener_gen_native); + } + finally + { + // + // Cleanup + // + if (listener__addRefd) + listener.DangerousRelease(); + } + } + internal uint ConnectionOpen(SafeMsQuicRegistrationHandle registration, ConnectionCallbackDelegate handler, IntPtr context, out SafeMsQuicConnectionHandle connection) + { + IntPtr __handler_gen_native = default; + connection = default!; + IntPtr __connection_gen_native = default; + uint __retVal; + bool __invokeSucceeded = default; + // + // Setup + // + bool registration__addRefd = false; + SafeMsQuicConnectionHandle connection__newHandle = new SafeMsQuicConnectionHandle(); + try + { + // + // Marshal + // + registration.DangerousAddRef(ref registration__addRefd); + IntPtr __registration_gen_native = registration.DangerousGetHandle(); + __handler_gen_native = handler != null ? Marshal.GetFunctionPointerForDelegate(handler) : default; + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__registration_gen_native, __handler_gen_native, context, &__connection_gen_native); + __invokeSucceeded = true; + // + // KeepAlive + // + GC.KeepAlive(handler); + } + finally + { + if (__invokeSucceeded) + { + // + // GuaranteedUnmarshal + // + Marshal.InitHandle(connection__newHandle, __connection_gen_native); + connection = connection__newHandle; + } + + // + // Cleanup + // + if (registration__addRefd) + registration.DangerousRelease(); + } + + return __retVal; + } + internal uint ConnectionSetConfiguration(SafeMsQuicConnectionHandle connection, SafeMsQuicConfigurationHandle configuration) + { + uint __retVal; + // + // Setup + // + bool connection__addRefd = false; + bool configuration__addRefd = false; + try + { + // + // Marshal + // + connection.DangerousAddRef(ref connection__addRefd); + IntPtr __connection_gen_native = connection.DangerousGetHandle(); + configuration.DangerousAddRef(ref configuration__addRefd); + IntPtr __configuration_gen_native = configuration.DangerousGetHandle(); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__connection_gen_native, __configuration_gen_native); + } + finally + { + // + // Cleanup + // + if (connection__addRefd) + connection.DangerousRelease(); + if (configuration__addRefd) + configuration.DangerousRelease(); + } + + return __retVal; + } + internal uint ConnectionStart(SafeMsQuicConnectionHandle connection, SafeMsQuicConfigurationHandle configuration, QUIC_ADDRESS_FAMILY family, string serverName, ushort serverPort) + { + IntPtr __connection_gen_native = default; + IntPtr __configuration_gen_native = default; + byte* __serverName_gen_native = default; + uint __retVal; + // + // Setup + // + bool connection__addRefd = false; + bool configuration__addRefd = false; + bool __serverName_gen_native__allocated = false; + try + { + // + // Marshal + // + connection.DangerousAddRef(ref connection__addRefd); + __connection_gen_native = connection.DangerousGetHandle(); + configuration.DangerousAddRef(ref configuration__addRefd); + __configuration_gen_native = configuration.DangerousGetHandle(); + if (serverName != null) + { + int __serverName_gen_native__bytelen = (serverName.Length + 1) * 3 + 1; + if (__serverName_gen_native__bytelen > 260) + { + __serverName_gen_native = (byte*)Marshal.StringToCoTaskMemUTF8(serverName); + __serverName_gen_native__allocated = true; + } + else + { + byte* __serverName_gen_native__stackptr = stackalloc byte[__serverName_gen_native__bytelen]; + { + __serverName_gen_native__bytelen = Text.Encoding.UTF8.GetBytes(serverName, new Span(__serverName_gen_native__stackptr, __serverName_gen_native__bytelen)); + __serverName_gen_native__stackptr[__serverName_gen_native__bytelen] = 0; + } + + __serverName_gen_native = (byte*)__serverName_gen_native__stackptr; + } + } + + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__connection_gen_native, __configuration_gen_native, family, __serverName_gen_native, serverPort); + } + finally + { + // + // Cleanup + // + if (connection__addRefd) + connection.DangerousRelease(); + if (configuration__addRefd) + configuration.DangerousRelease(); + if (__serverName_gen_native__allocated) + { + Marshal.FreeCoTaskMem((IntPtr)__serverName_gen_native); + } + } + + return __retVal; + } + internal void ConnectionShutdown(SafeMsQuicConnectionHandle connection, QUIC_CONNECTION_SHUTDOWN_FLAGS flags, long errorCode) + { + // + // Setup + // + bool connection__addRefd = false; + try + { + // + // Marshal + // + connection.DangerousAddRef(ref connection__addRefd); + IntPtr __connection_gen_native = connection.DangerousGetHandle(); + ((delegate* unmanaged[Cdecl])_functionPointer)(__connection_gen_native, flags, errorCode); + } + finally + { + // + // Cleanup + // + if (connection__addRefd) + connection.DangerousRelease(); + } + } + internal uint StreamOpen(SafeMsQuicConnectionHandle connection, QUIC_STREAM_OPEN_FLAGS flags, StreamCallbackDelegate handler, IntPtr context, out SafeMsQuicStreamHandle stream) + { + IntPtr __handler_gen_native = default; + stream = default!; + IntPtr __stream_gen_native = default; + uint __retVal; + bool __invokeSucceeded = default; + // + // Setup + // + bool connection__addRefd = false; + SafeMsQuicStreamHandle stream__newHandle = new SafeMsQuicStreamHandle(); + try + { + // + // Marshal + // + connection.DangerousAddRef(ref connection__addRefd); + IntPtr __connection_gen_native = connection.DangerousGetHandle(); + __handler_gen_native = handler != null ? Marshal.GetFunctionPointerForDelegate(handler) : default; + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__connection_gen_native, flags, __handler_gen_native, context, &__stream_gen_native); + __invokeSucceeded = true; + // + // KeepAlive + // + GC.KeepAlive(handler); + } + finally + { + if (__invokeSucceeded) + { + // + // GuaranteedUnmarshal + // + Marshal.InitHandle(stream__newHandle, __stream_gen_native); + stream = stream__newHandle; + } + + // + // Cleanup + // + if (connection__addRefd) + connection.DangerousRelease(); + } + + return __retVal; + } + internal uint StreamStart(SafeMsQuicStreamHandle stream, QUIC_STREAM_START_FLAGS flags) + { + uint __retVal; + // + // Setup + // + bool stream__addRefd = false; + try + { + // + // Marshal + // + stream.DangerousAddRef(ref stream__addRefd); + IntPtr __stream_gen_native = stream.DangerousGetHandle(); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__stream_gen_native, flags); + } + finally + { + // + // Cleanup + // + if (stream__addRefd) + stream.DangerousRelease(); + } + + return __retVal; + } + internal uint StreamShutdown(SafeMsQuicStreamHandle stream, QUIC_STREAM_SHUTDOWN_FLAGS flags, long errorCode) + { + uint __retVal; + // + // Setup + // + bool stream__addRefd = false; + try + { + // + // Marshal + // + stream.DangerousAddRef(ref stream__addRefd); + IntPtr __stream_gen_native = stream.DangerousGetHandle(); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__stream_gen_native, flags, errorCode); + } + finally + { + // + // Cleanup + // + if (stream__addRefd) + stream.DangerousRelease(); + } + + return __retVal; + } + internal uint StreamSend(SafeMsQuicStreamHandle stream, QuicBuffer* buffers, uint bufferCount, QUIC_SEND_FLAGS flags, IntPtr clientSendContext) + { + uint __retVal; + // + // Setup + // + bool stream__addRefd = false; + try + { + // + // Marshal + // + stream.DangerousAddRef(ref stream__addRefd); + IntPtr __stream_gen_native = stream.DangerousGetHandle(); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__stream_gen_native, buffers, bufferCount, flags, clientSendContext); + } + finally + { + // + // Cleanup + // + if (stream__addRefd) + stream.DangerousRelease(); + } + + return __retVal; + } + internal uint StreamReceiveComplete(SafeMsQuicStreamHandle stream, ulong bufferLength) + { + uint __retVal; + // + // Setup + // + bool stream__addRefd = false; + try + { + // + // Marshal + // + stream.DangerousAddRef(ref stream__addRefd); + IntPtr __stream_gen_native = stream.DangerousGetHandle(); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__stream_gen_native, bufferLength); + } + finally + { + // + // Cleanup + // + if (stream__addRefd) + stream.DangerousRelease(); + } + + return __retVal; + } + internal uint StreamReceiveSetEnabled(SafeMsQuicStreamHandle stream, bool enabled) + { + uint __retVal; + // + // Setup + // + bool stream__addRefd = false; + try + { + // + // Marshal + // + stream.DangerousAddRef(ref stream__addRefd); + IntPtr __stream_gen_native = stream.DangerousGetHandle(); + byte __enabled_gen_native = (byte)(enabled ? 1 : 0); + __retVal = ((delegate* unmanaged[Cdecl])_functionPointer)(__stream_gen_native, __enabled_gen_native); + } + finally + { + // + // Cleanup + // + if (stream__addRefd) + stream.DangerousRelease(); + } + + return __retVal; + } + } } } diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs index 421ce00f13a1c2..c8f4bb9361939e 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs @@ -24,7 +24,7 @@ internal sealed class MsQuicConnection : QuicConnectionProvider private const uint DefaultResetValue = 0xffffffff; // Arbitrary value unlikely to conflict with application protocols. // Delegate that wraps the static function that will be called when receiving an event. - private static readonly ConnectionCallbackDelegate s_connectionDelegate = new ConnectionCallbackDelegate(NativeCallbackHandler); + private static unsafe readonly ConnectionCallbackDelegate s_connectionDelegate = new ConnectionCallbackDelegate(NativeCallbackHandler); // TODO: remove this. // This is only used for client-initiated connections, and isn't needed even then once Connect() has been called. @@ -748,10 +748,10 @@ internal void SetNegotiatedAlpn(IntPtr alpn, int alpnLength) } } - private static uint NativeCallbackHandler( + private static unsafe uint NativeCallbackHandler( IntPtr connection, IntPtr context, - ref ConnectionEvent connectionEvent) + ConnectionEvent* connectionEvent) { GCHandle gcHandle = GCHandle.FromIntPtr(context); Debug.Assert(gcHandle.IsAllocated); @@ -760,27 +760,27 @@ private static uint NativeCallbackHandler( if (NetEventSource.Log.IsEnabled()) { - NetEventSource.Info(state, $"{state.TraceId} Connection received event {connectionEvent.Type}"); + NetEventSource.Info(state, $"{state.TraceId} Connection received event {connectionEvent->Type}"); } try { - switch (connectionEvent.Type) + switch (connectionEvent->Type) { case QUIC_CONNECTION_EVENT_TYPE.CONNECTED: - return HandleEventConnected(state, ref connectionEvent); + return HandleEventConnected(state, ref *connectionEvent); case QUIC_CONNECTION_EVENT_TYPE.SHUTDOWN_INITIATED_BY_TRANSPORT: - return HandleEventShutdownInitiatedByTransport(state, ref connectionEvent); + return HandleEventShutdownInitiatedByTransport(state, ref *connectionEvent); case QUIC_CONNECTION_EVENT_TYPE.SHUTDOWN_INITIATED_BY_PEER: - return HandleEventShutdownInitiatedByPeer(state, ref connectionEvent); + return HandleEventShutdownInitiatedByPeer(state, ref *connectionEvent); case QUIC_CONNECTION_EVENT_TYPE.SHUTDOWN_COMPLETE: - return HandleEventShutdownComplete(state, ref connectionEvent); + return HandleEventShutdownComplete(state, ref *connectionEvent); case QUIC_CONNECTION_EVENT_TYPE.PEER_STREAM_STARTED: - return HandleEventNewStream(state, ref connectionEvent); + return HandleEventNewStream(state, ref *connectionEvent); case QUIC_CONNECTION_EVENT_TYPE.STREAMS_AVAILABLE: - return HandleEventStreamsAvailable(state, ref connectionEvent); + return HandleEventStreamsAvailable(state, ref *connectionEvent); case QUIC_CONNECTION_EVENT_TYPE.PEER_CERTIFICATE_RECEIVED: - return HandleEventPeerCertificateReceived(state, ref connectionEvent); + return HandleEventPeerCertificateReceived(state, ref *connectionEvent); default: return MsQuicStatusCodes.Success; } @@ -789,7 +789,7 @@ private static uint NativeCallbackHandler( { if (NetEventSource.Log.IsEnabled()) { - NetEventSource.Error(state, $"{state.TraceId} Exception occurred during handling {connectionEvent.Type} connection callback: {ex}"); + NetEventSource.Error(state, $"{state.TraceId} Exception occurred during handling {connectionEvent->Type} connection callback: {ex}"); } if (state.ConnectTcs != null) @@ -801,7 +801,7 @@ private static uint NativeCallbackHandler( } else { - Debug.Fail($"{state.TraceId} Exception occurred during handling {connectionEvent.Type} connection callback: {ex}"); + Debug.Fail($"{state.TraceId} Exception occurred during handling {connectionEvent->Type} connection callback: {ex}"); } // TODO: trigger an exception on any outstanding async calls. diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicListener.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicListener.cs index aadd9f1e247582..71f19c29c29986 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicListener.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicListener.cs @@ -18,7 +18,7 @@ namespace System.Net.Quic.Implementations.MsQuic { internal sealed class MsQuicListener : QuicListenerProvider, IDisposable { - private static readonly ListenerCallbackDelegate s_listenerDelegate = new ListenerCallbackDelegate(NativeCallbackHandler); + private static unsafe readonly ListenerCallbackDelegate s_listenerDelegate = new ListenerCallbackDelegate(NativeCallbackHandler); private readonly State _state; private GCHandle _stateHandle; @@ -223,13 +223,13 @@ private void Stop() private static unsafe uint NativeCallbackHandler( IntPtr listener, IntPtr context, - ref ListenerEvent evt) + ListenerEvent* evt) { GCHandle gcHandle = GCHandle.FromIntPtr(context); Debug.Assert(gcHandle.IsAllocated); Debug.Assert(gcHandle.Target is not null); var state = (State)gcHandle.Target; - if (evt.Type != QUIC_LISTENER_EVENT.NEW_CONNECTION) + if (evt->Type != QUIC_LISTENER_EVENT.NEW_CONNECTION) { return MsQuicStatusCodes.InternalError; } @@ -238,7 +238,7 @@ private static unsafe uint NativeCallbackHandler( MsQuicConnection? msQuicConnection = null; try { - ref NewConnectionInfo connectionInfo = ref *evt.Data.NewConnection.Info; + ref NewConnectionInfo connectionInfo = ref *evt->Data.NewConnection.Info; IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET*)connectionInfo.LocalAddress); IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET*)connectionInfo.RemoteAddress); @@ -274,7 +274,7 @@ private static unsafe uint NativeCallbackHandler( } } - connectionHandle = new SafeMsQuicConnectionHandle(evt.Data.NewConnection.Connection); + connectionHandle = new SafeMsQuicConnectionHandle(evt->Data.NewConnection.Connection); uint status = MsQuicApi.Api.ConnectionSetConfigurationDelegate(connectionHandle, connectionConfiguration); if (MsQuicStatusHelper.SuccessfulStatusCode(status)) @@ -296,7 +296,7 @@ private static unsafe uint NativeCallbackHandler( { if (NetEventSource.Log.IsEnabled()) { - NetEventSource.Error(state, $"[Listener#{state.GetHashCode()}] Exception occurred during handling {(QUIC_LISTENER_EVENT)evt.Type} connection callback: {ex}"); + NetEventSource.Error(state, $"[Listener#{state.GetHashCode()}] Exception occurred during handling {(QUIC_LISTENER_EVENT)evt->Type} connection callback: {ex}"); } } diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicStream.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicStream.cs index d2130779a7b87b..1a1df28b699a88 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicStream.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicStream.cs @@ -16,7 +16,7 @@ namespace System.Net.Quic.Implementations.MsQuic internal sealed class MsQuicStream : QuicStreamProvider { // Delegate that wraps the static function that will be called when receiving an event. - internal static readonly StreamCallbackDelegate s_streamDelegate = new StreamCallbackDelegate(NativeCallbackHandler); + internal static unsafe readonly StreamCallbackDelegate s_streamDelegate = new StreamCallbackDelegate(NativeCallbackHandler); // The state is passed to msquic and then it's passed back by msquic to the callback handler. private readonly State _state = new State(); @@ -853,17 +853,17 @@ private void EnableReceive() /// Callback calls for a single instance of a stream are serialized by msquic. /// They happen on a msquic thread and shouldn't take too long to not to block msquic. /// - private static uint NativeCallbackHandler( + private static unsafe uint NativeCallbackHandler( IntPtr stream, IntPtr context, - ref StreamEvent streamEvent) + StreamEvent* streamEvent) { GCHandle gcHandle = GCHandle.FromIntPtr(context); Debug.Assert(gcHandle.IsAllocated); Debug.Assert(gcHandle.Target is not null); var state = (State)gcHandle.Target; - return HandleEvent(state, ref streamEvent); + return HandleEvent(state, ref *streamEvent); } private static uint HandleEvent(State state, ref StreamEvent evt)