File: SystemdNotifier.cs
Web Access
Project: src\src\libraries\Microsoft.Extensions.Hosting.Systemd\src\Microsoft.Extensions.Hosting.Systemd.csproj (Microsoft.Extensions.Hosting.Systemd)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Net.Sockets;
using System.Runtime.Versioning;
 
namespace Microsoft.Extensions.Hosting.Systemd
{
    /// <summary>
    /// Provides support to notify systemd about the service status.
    /// </summary>
    [UnsupportedOSPlatform("browser")]
    public class SystemdNotifier : ISystemdNotifier
    {
        private const string NOTIFY_SOCKET = "NOTIFY_SOCKET";
 
        private readonly string? _socketPath;
 
        /// <summary>
        /// Instantiates a new <see cref="SystemdNotifier"/> and sets the notify socket path.
        /// </summary>
        public SystemdNotifier() :
            this(GetNotifySocketPath())
        { }
 
        // For testing
        internal SystemdNotifier(string? socketPath)
        {
            _socketPath = socketPath;
        }
 
        /// <inheritdoc />
        public bool IsEnabled => _socketPath != null;
 
        /// <inheritdoc />
        public void Notify(ServiceState state)
        {
            if (!IsEnabled)
            {
                return;
            }
 
#if !NETSTANDARD2_1 && !NETSTANDARD2_0 && !NETFRAMEWORK // TODO remove with https://github.com/dotnet/runtime/pull/107185
            if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException();
#else
            #pragma warning disable CA1416
#endif
 
            using (var socket = new Socket(AddressFamily.Unix, SocketType.Dgram, ProtocolType.Unspecified))
            {
                var endPoint = new UnixDomainSocketEndPoint(_socketPath!);
                socket.Connect(endPoint);
 
                // It's safe to do a non-blocking call here: messages sent here are much
                // smaller than kernel buffers so we won't get blocked.
                socket.Send(state.GetData());
            }
        }
 
        private static string? GetNotifySocketPath()
        {
            string? socketPath = Environment.GetEnvironmentVariable(NOTIFY_SOCKET);
 
            if (string.IsNullOrEmpty(socketPath))
            {
                return null;
            }
 
            // Support abstract socket paths.
            if (socketPath[0] == '@')
            {
                socketPath = string.Create(socketPath.Length, socketPath, (buffer, state) =>
                {
                    buffer[0] = '\0';
                    state.AsSpan(1).CopyTo(buffer.Slice(1));
                });
            }
 
            return socketPath;
        }
    }
}