1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.Diagnostics; 8 using System.Net.Security; 9 using System.Runtime.InteropServices; 10 11 internal static partial class Interop 12 { 13 [StructLayout(LayoutKind.Sequential, Pack = 1)] 14 internal struct Sec_Application_Protocols 15 { 16 private static readonly int ProtocolListOffset = Marshal.SizeOf<Sec_Application_Protocols>(); 17 private static readonly int ProtocolListConstSize = ProtocolListOffset - (int)Marshal.OffsetOf<Sec_Application_Protocols>(nameof(ProtocolExtenstionType)); 18 public uint ProtocolListsSize; 19 public ApplicationProtocolNegotiationExt ProtocolExtenstionType; 20 public short ProtocolListSize; 21 ToByteArrayInterop.Sec_Application_Protocols22 public static unsafe byte[] ToByteArray(List<SslApplicationProtocol> applicationProtocols) 23 { 24 long protocolListSize = 0; 25 for (int i = 0; i < applicationProtocols.Count; i++) 26 { 27 if (applicationProtocols[i].Protocol.Length == 0 || applicationProtocols[i].Protocol.Length > byte.MaxValue) 28 { 29 throw new ArgumentException(SR.net_ssl_app_protocols_invalid, nameof(applicationProtocols)); 30 } 31 32 protocolListSize += applicationProtocols[i].Protocol.Length + 1; 33 34 if (protocolListSize > short.MaxValue) 35 { 36 throw new ArgumentException(SR.net_ssl_app_protocols_invalid, nameof(applicationProtocols)); 37 } 38 } 39 40 Sec_Application_Protocols protocols = new Sec_Application_Protocols(); 41 protocols.ProtocolListsSize = (uint)(ProtocolListConstSize + protocolListSize); 42 protocols.ProtocolExtenstionType = ApplicationProtocolNegotiationExt.ALPN; 43 protocols.ProtocolListSize = (short)protocolListSize; 44 45 Span<byte> pBuffer = new byte[protocolListSize]; 46 int index = 0; 47 for (int i = 0; i < applicationProtocols.Count; i++) 48 { 49 pBuffer[index++] = (byte)applicationProtocols[i].Protocol.Length; 50 applicationProtocols[i].Protocol.Span.CopyTo(pBuffer.Slice(index)); 51 index += applicationProtocols[i].Protocol.Length; 52 } 53 54 byte[] buffer = new byte[ProtocolListOffset + protocolListSize]; 55 fixed (byte* bufferPtr = buffer) 56 { 57 Marshal.StructureToPtr(protocols, new IntPtr(bufferPtr), false); 58 byte* pList = bufferPtr + ProtocolListOffset; 59 pBuffer.CopyTo(new Span<byte>(pList, index)); 60 } 61 62 return buffer; 63 } 64 } 65 } 66