diff --git a/include/oatpp-authkit/systemd/Notify.hpp b/include/oatpp-authkit/systemd/Notify.hpp new file mode 100644 index 0000000..1d2d61d --- /dev/null +++ b/include/oatpp-authkit/systemd/Notify.hpp @@ -0,0 +1,54 @@ +#ifndef OATPP_AUTHKIT_SYSTEMD_NOTIFY_HPP +#define OATPP_AUTHKIT_SYSTEMD_NOTIFY_HPP + +#include +#include +#include +#include +#include + +namespace oatpp_authkit::systemd { + +/** + * @brief Protocol-level sd_notify(3) implementation. + * + * Speaks the systemd notification protocol by writing a datagram to + * $NOTIFY_SOCKET — no libsystemd dependency. Used to signal + * `Type=notify` services with `READY=1`, `STATUS=...`, `WATCHDOG=1`. + * + * No-op (silent return) when NOTIFY_SOCKET is unset — the same binary + * can run under systemd or as a plain background process without + * conditional logic at the call site. + * + * Supports Linux abstract-namespace sockets (leading '@' in the env + * var, mapped to a leading NUL byte in the sockaddr path). + * + * Example: + * @code + * oatpp_authkit::systemd::notify("READY=1\nSTATUS=Accepting connections"); + * // … later, from a watchdog thread: + * oatpp_authkit::systemd::notify("WATCHDOG=1"); + * @endcode + */ +inline void notify(const char* state) { + const char* sock = std::getenv("NOTIFY_SOCKET"); + if (!sock || !*sock) return; + int fd = ::socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (fd < 0) return; + struct sockaddr_un addr{}; + addr.sun_family = AF_UNIX; + if (sock[0] == '@') { + // Linux abstract namespace: leading '@' maps to a NUL byte. + addr.sun_path[0] = '\0'; + std::strncpy(addr.sun_path + 1, sock + 1, sizeof(addr.sun_path) - 2); + } else { + std::strncpy(addr.sun_path, sock, sizeof(addr.sun_path) - 1); + } + ::sendto(fd, state, std::strlen(state), MSG_NOSIGNAL, + (struct sockaddr*)&addr, sizeof(addr)); + ::close(fd); +} + +} // namespace oatpp_authkit::systemd + +#endif