namespace SecurityManager {
-struct SignalService : public GenericSocketService {
- int GetDescriptor() {
- LogInfo("set up");
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, SIGTERM);
- sigaddset(&mask, SIGCHLD);
- if (-1 == pthread_sigmask(SIG_BLOCK, &mask, NULL))
- return -1;
- return signalfd(-1, &mask, 0);
- }
-
- ServiceDescriptionVector GetServiceDescription() {
- return ServiceDescriptionVector();
- }
-
- void Event(AcceptEvent &&) { } // not supported
- void Event(WriteEvent &&) { } // not supported
- void Event(CloseEvent &&) { } // not supported
-
- void Event(ReadEvent &&event) {
- LogDebug("Get signal information");
-
- if (sizeof(struct signalfd_siginfo) != event.rawBuffer.size()) {
- LogError("Wrong size of signalfd_siginfo struct. Expected: "
- << sizeof(signalfd_siginfo) << " Get: "
- << event.rawBuffer.size());
- return;
- }
-
- signalfd_siginfo *siginfo = (signalfd_siginfo*)(&(event.rawBuffer[0]));
-
- if (siginfo->ssi_signo == SIGTERM) {
- LogInfo("Got signal: SIGTERM");
- auto manager = dynamic_cast<SocketManager*>(m_serviceManager);
- if (manager)
- manager->MainLoopStop();
- return;
- } else if (siginfo->ssi_signo == SIGCHLD) {
- (void)waitpid(-1, nullptr, WNOHANG);
- return;
- }
-
- LogInfo("This should not happend. Got signal: " << siginfo->ssi_signo);
- }
-};
-
void SocketManager::RegisterFdForReading(int fd) {
FD_SET(fd, &m_readSet);
m_maxDesc = std::max(m_maxDesc, fd);
{
FD_ZERO(&m_readSet);
FD_ZERO(&m_writeSet);
+
+ // std::thread bases on pthread so this should work fine
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGTERM);
+ sigaddset(&set, SIGCHLD);
+ if (auto err = pthread_sigmask(SIG_BLOCK, &set, nullptr))
+ ThrowMsg(Exception::InitFailed, "Error in pthread_sigmask: " << err);
+
+ // add support for TERM signal (passed from systemd)
+ if ((m_signalFd = signalfd(-1, &set, 0)) < 0) {
+ int err = errno;
+ ThrowMsg(Exception::InitFailed, "Error in signalfd: " << GetErrnoString(err));
+ }
+ RegisterFdForReading(m_signalFd);
+
if ((m_notifyMe = eventfd(0, 0)) < 0) {
int err = errno;
ThrowMsg(Exception::InitFailed, "Error in eventfd: " << GetErrnoString(err));
}
LogInfo("Eventfd desc: " << m_notifyMe);
RegisterFdForReading(m_notifyMe);
-
- // add support for TERM signal (passed from systemd)
- auto *signalService = new SignalService;
- signalService->SetSocketManager(this);
- int filefd = signalService->GetDescriptor();
- if (-1 == filefd) {
- LogError("Error in SignalService.GetDescriptor()");
- delete signalService;
- } else {
- auto &desc2 = CreateDefaultReadSocketDescription(filefd, false);
- desc2.service = signalService;
- LogInfo("SignalService mounted on " << filefd << " descriptor");
- }
}
SocketManager::~SocketManager() {
close(i);
// All service sockets have been closed. Close internal descriptors.
+ close(m_signalFd);
close(m_notifyMe);
}
desc.service->Event(std::move(event));
}
+// true if quit mainloop
+bool SocketManager::GotSigTerm() const {
+ LogDebug("Get signal information");
+
+ struct signalfd_siginfo info;
+ const auto s = TEMP_FAILURE_RETRY(read(m_signalFd, &info, sizeof info));
+ if (s != sizeof info) {
+ LogError("Wrong signalfd read size. Expected: " << sizeof info << " Got: " << s);
+ return false;
+ }
+
+ switch (info.ssi_signo) {
+ case SIGTERM:
+ LogInfo("Got signal: SIGTERM");
+ return true;
+ case SIGCHLD:
+ (void)waitpid(-1, nullptr, WNOHANG);
+ break;
+ default:
+ LogError("This should not happen. Got signal: " << info.ssi_signo);
+ break;
+ }
+ return false;
+}
+
void SocketManager::ReadyForRead(int sock) {
if (m_socketDescriptionVector[sock].isListen) {
ReadyForAccept(sock);
// Daemon is ready to work.
sd_notify(0, "READY=1");
- m_working = true;
for (;;) {
fd_set readSet = m_readSet;
fd_set writeSet = m_writeSet;
continue;
}
- if (FD_ISSET(m_notifyMe, &readSet)) {
- if (!m_working)
+ if (FD_ISSET(m_signalFd, &readSet)) {
+ if (GotSigTerm())
return;
+ FD_CLR(m_signalFd, &readSet);
+ }
+ if (FD_ISSET(m_notifyMe, &readSet)) {
eventfd_t dummyValue;
TEMP_FAILURE_RETRY(eventfd_read(m_notifyMe, &dummyValue));
FD_CLR(m_notifyMe, &readSet);
}
}
-void SocketManager::MainLoopStop()
-{
- m_working = false;
- NotifyMe();
-}
-
int SocketManager::GetSocketFromSystemD(
const GenericSocketService::ServiceDescription &desc)
{
else
LogError("Critical! Service is NULL! This should never happend!");
- TEMP_FAILURE_RETRY(close(sock));
+ close(sock);
FD_CLR(sock, &m_readSet);
FD_CLR(sock, &m_writeSet);
LogDebug("Closing socket: " << sock << " finished..");