Skip to content

Commit e64354a

Browse files
committed
Get the host name from uname method to avoid read the file
1 parent 486f46e commit e64354a

File tree

2 files changed

+120
-8
lines changed

2 files changed

+120
-8
lines changed

src/Avalonia.X11/UtsName.cs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Runtime.InteropServices;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace Avalonia.X11;
9+
10+
internal struct UtsName : IDisposable
11+
{
12+
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/utsname.h
13+
/*
14+
#define __NEW_UTS_LEN 64
15+
16+
struct new_utsname
17+
{
18+
char sysname[__NEW_UTS_LEN + 1];
19+
char nodename[__NEW_UTS_LEN + 1];
20+
char release[__NEW_UTS_LEN + 1];
21+
char version[__NEW_UTS_LEN + 1];
22+
char machine[__NEW_UTS_LEN + 1];
23+
char domainname[__NEW_UTS_LEN + 1];
24+
};
25+
*/
26+
27+
private UtsName(IntPtr buffer)
28+
{
29+
_buffer = buffer;
30+
}
31+
32+
public static UtsName GetUtsName()
33+
{
34+
var ntsNameStructSize = (UtsLength + 1) * FieldCount;
35+
36+
IntPtr buffer = Marshal.AllocHGlobal(ntsNameStructSize);
37+
try
38+
{
39+
if (uname(buffer) != 0)
40+
{
41+
throw new InvalidOperationException("uname failed");
42+
}
43+
44+
return new UtsName(buffer);
45+
}
46+
catch
47+
{
48+
Marshal.FreeHGlobal(buffer);
49+
throw;
50+
}
51+
}
52+
53+
private const int SystemNameFieldIndex = 0;
54+
public Span<byte> SystemNameSpan => GetValue(SystemNameFieldIndex);
55+
public string SystemName => Encoding.UTF8.GetString(SystemNameSpan);
56+
57+
private const int NodeNameFieldIndex = 1;
58+
public Span<byte> NodeNameSpan => GetValue(NodeNameFieldIndex);
59+
public string NodeName => Encoding.UTF8.GetString(NodeNameSpan);
60+
61+
private const int ReleaseFieldIndex = 2;
62+
public Span<byte> ReleaseSpan => GetValue(ReleaseFieldIndex);
63+
public string Release => Encoding.UTF8.GetString(ReleaseSpan);
64+
65+
private const int VersionFieldIndex = 3;
66+
public Span<byte> VersionSpan => GetValue(VersionFieldIndex);
67+
public string Version => Encoding.UTF8.GetString(VersionSpan);
68+
69+
private const int MachineFieldIndex = 4;
70+
public Span<byte> MachineSpan => GetValue(MachineFieldIndex);
71+
public string Machine => Encoding.UTF8.GetString(MachineSpan);
72+
73+
private const int DomainNameFieldIndex = 5;
74+
public Span<byte> DomainNameSpan => GetValue(DomainNameFieldIndex);
75+
public string DomainName => Encoding.UTF8.GetString(DomainNameSpan);
76+
77+
private const int UtsLength = 64;
78+
79+
private const int FieldCount = 6;
80+
81+
private Span<byte> GetValue(int fieldIndex)
82+
{
83+
var startOffset = (UtsLength + 1) * fieldIndex;
84+
var length = 0;
85+
while (Marshal.ReadByte(_buffer, startOffset + length) != 0)
86+
{
87+
length++;
88+
}
89+
90+
unsafe
91+
{
92+
return new Span<byte>((byte*)_buffer + startOffset, length);
93+
}
94+
}
95+
96+
[DllImport("libc")]
97+
private static extern int uname(IntPtr buf);
98+
99+
private readonly IntPtr _buffer;
100+
101+
public void Dispose()
102+
{
103+
Marshal.FreeHGlobal(_buffer);
104+
}
105+
}

src/Avalonia.X11/X11Window.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
using System.Runtime.InteropServices;
2828
using Avalonia.Dialogs;
2929
using Avalonia.Platform.Storage.FileIO;
30+
using System.Reflection.Metadata;
3031

3132
// ReSharper disable IdentifierTypo
3233
// ReSharper disable StringLiteralTypo
@@ -343,20 +344,26 @@ private void AppendPid(IntPtr windowXId)
343344
_x11.Atoms._NET_WM_PID, _x11.Atoms.XA_CARDINAL, 32,
344345
PropertyMode.Replace, ref pid, 1);
345346

346-
// If _NET_WM_PID is set, the ICCCM-specified property WM_CLIENT_MACHINE MUST also be set.
347-
var hostNameFilePath = "cat /proc/sys/kernel/hostname";
348-
if (File.Exists(hostNameFilePath))
349-
{
350-
var WM_CLIENT_MACHINE = XInternAtom(_x11.Display, "WM_CLIENT_MACHINE", false);
351-
var hostName = File.ReadAllText(hostNameFilePath);
352-
var stringToHGlobalAnsi = Marshal.StringToHGlobalAnsi(hostName);
347+
// If _NET_WM_PID is set, the ICCCM-specified property WM_CLIENT_MACHINE MUST also be set.
348+
// the hostname can change, so we can't cache it
349+
// gethostname(3) on Linux just calls uname(2), so do it ourselves
350+
// and avoid a memcpy
351+
using var utsName = UtsName.GetUtsName();
352+
353+
var WM_CLIENT_MACHINE = XInternAtom(_x11.Display, "WM_CLIENT_MACHINE", false);
353354

355+
var nodeNameSpan = utsName.NodeNameSpan;
356+
fixed (byte* pNodeName = &nodeNameSpan.GetPinnableReference())
357+
{
354358
XChangeProperty(_x11.Display, windowXId,
355359
WM_CLIENT_MACHINE, _x11.Atoms.XA_STRING, 8,
356-
PropertyMode.Replace, ref stringToHGlobalAnsi, (int)hostName.Length);
360+
PropertyMode.Replace, pNodeName, nodeNameSpan.Length);
357361
}
358362
}
359363

364+
[DllImport("libc")]
365+
static extern int uname(IntPtr buf);
366+
360367
private static readonly int s_pid = GetProcessId();
361368

362369
private static int GetProcessId()

0 commit comments

Comments
 (0)