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