1 #region Copyright notice and license 2 3 // Copyright 2021 The gRPC Authors 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #endregion 18 19 using System; 20 using System.Runtime.CompilerServices; 21 using System.Runtime.InteropServices; 22 23 namespace Grpc.Core.Internal 24 { 25 /// <summary> 26 /// This source file is shared by both Grpc.Core and Grpc.Tools to avoid duplication 27 /// of platform detection code. 28 /// </summary> 29 internal static class CommonPlatformDetection 30 { 31 public enum OSKind { Unknown, Windows, Linux, MacOSX }; 32 public enum CpuArchitecture { Unknown, X86, X64, Arm64 }; 33 GetOSKind()34 public static OSKind GetOSKind() 35 { 36 #if NETSTANDARD || NETCORE 37 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 38 { 39 return OSKind.Windows; 40 } 41 else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 42 { 43 return OSKind.Linux; 44 } 45 else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 46 { 47 return OSKind.MacOSX; 48 } 49 else 50 { 51 return OSKind.Unknown; 52 } 53 #else 54 var platform = Environment.OSVersion.Platform; 55 if (platform == PlatformID.Win32NT || platform == PlatformID.Win32S || platform == PlatformID.Win32Windows) 56 { 57 return OSKind.Windows; 58 } 59 else if (platform == PlatformID.Unix && GetUname() == "Darwin") 60 { 61 // PlatformID.MacOSX is never returned, commonly used trick is to identify Mac is by using uname. 62 return OSKind.MacOSX; 63 } 64 else if (platform == PlatformID.Unix) 65 { 66 // on legacy .NET Framework, our detection options are limited, so we treat 67 // all other unix systems as Linux. 68 return OSKind.Linux; 69 } 70 else 71 { 72 return OSKind.Unknown; 73 } 74 #endif 75 } 76 GetProcessArchitecture()77 public static CpuArchitecture GetProcessArchitecture() 78 { 79 #if NETSTANDARD || NETCORE 80 switch (RuntimeInformation.ProcessArchitecture) 81 { 82 case Architecture.X86: 83 return CpuArchitecture.X86; 84 case Architecture.X64: 85 return CpuArchitecture.X64; 86 case Architecture.Arm64: 87 return CpuArchitecture.Arm64; 88 // We do not support other architectures, 89 // so we simply return "unrecognized". 90 default: 91 return CpuArchitecture.Unknown; 92 } 93 #else 94 // on legacy .NET Framework, RuntimeInformation is not available 95 // but our choice of supported architectures there 96 // is also very limited, so we simply take our best guess. 97 return Environment.Is64BitProcess ? CpuArchitecture.X64 : CpuArchitecture.X86; 98 #endif 99 } 100 101 [DllImport("libc")] uname(IntPtr buf)102 static extern int uname(IntPtr buf); 103 104 // This code is copied from Grpc.Core/PlatformApis.cs GetUname()105 static string GetUname() 106 { 107 var buffer = Marshal.AllocHGlobal(8192); 108 try 109 { 110 if (uname(buffer) == 0) 111 { 112 return Marshal.PtrToStringAnsi(buffer); 113 } 114 return string.Empty; 115 } 116 catch 117 { 118 return string.Empty; 119 } 120 finally 121 { 122 if (buffer != IntPtr.Zero) 123 { 124 Marshal.FreeHGlobal(buffer); 125 } 126 } 127 } 128 } 129 } 130