diff options
Diffstat (limited to 'src/manager/main/socket-manager.cpp')
-rw-r--r-- | src/manager/main/socket-manager.cpp | 1270 |
1 files changed, 652 insertions, 618 deletions
diff --git a/src/manager/main/socket-manager.cpp b/src/manager/main/socket-manager.cpp index ab566cf2..9f20f62f 100644 --- a/src/manager/main/socket-manager.cpp +++ b/src/manager/main/socket-manager.cpp @@ -50,22 +50,22 @@ const time_t SOCKET_TIMEOUT = 1000; int getCredentialsFromSocket(int sock, CKM::Credentials &cred) { - static CKM::Socket2Id sock2id; - std::string ownerId; + static CKM::Socket2Id sock2id; + std::string ownerId; - if (0 > sock2id.translate(sock, ownerId)) - return -1; + if (0 > sock2id.translate(sock, ownerId)) + return -1; - ucred peerCred; - socklen_t length = sizeof(ucred); + ucred peerCred; + socklen_t length = sizeof(ucred); - if (0 > getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peerCred, &length)) { - LogError("getsockopt failed"); - return -1; - } + if (0 > getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peerCred, &length)) { + LogError("getsockopt failed"); + return -1; + } - cred = CKM::Credentials(peerCred.uid, std::move(ownerId)); - return 0; + cred = CKM::Credentials(peerCred.uid, std::move(ownerId)); + return 0; } } // namespace anonymous @@ -73,720 +73,754 @@ int getCredentialsFromSocket(int sock, CKM::Credentials &cred) namespace CKM { struct DummyService : public GenericSocketService { - ServiceDescriptionVector GetServiceDescription() - { - return ServiceDescriptionVector(); - } - - void Start() {} - void Stop() {} - - void Event(const AcceptEvent &) {} - void Event(const WriteEvent &) {} - void Event(const ReadEvent &) {} - void Event(const CloseEvent &) {} - void Event(const SecurityEvent &) {} + ServiceDescriptionVector GetServiceDescription() + { + return ServiceDescriptionVector(); + } + + void Start() {} + void Stop() {} + + void Event(const AcceptEvent &) {} + void Event(const WriteEvent &) {} + void Event(const ReadEvent &) {} + void Event(const CloseEvent &) {} + void Event(const SecurityEvent &) {} }; struct SignalService : public GenericSocketService { - int GetDescriptor() - { - LogInfo("set up"); - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGTERM); - if (-1 == pthread_sigmask(SIG_BLOCK, &mask, NULL)) - return -1; - return signalfd(-1, &mask, 0); - } - - ServiceDescriptionVector GetServiceDescription() - { - return ServiceDescriptionVector(); - } - - void Start() {} - void Stop() {} - - void Event(const AcceptEvent &) {} // not supported - void Event(const WriteEvent &) {} // not supported - void Event(const CloseEvent &) {} // not supported - void Event(const SecurityEvent &) {} // not supported - - void Event(const 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"); - static_cast<SocketManager*>(m_serviceManager)->MainLoopStop(); - return; - } - - LogInfo("This should not happend. Got signal: " << siginfo->ssi_signo); - } + int GetDescriptor() + { + LogInfo("set up"); + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + + if (-1 == pthread_sigmask(SIG_BLOCK, &mask, NULL)) + return -1; + + return signalfd(-1, &mask, 0); + } + + ServiceDescriptionVector GetServiceDescription() + { + return ServiceDescriptionVector(); + } + + void Start() {} + void Stop() {} + + void Event(const AcceptEvent &) {} // not supported + void Event(const WriteEvent &) {} // not supported + void Event(const CloseEvent &) {} // not supported + void Event(const SecurityEvent &) {} // not supported + + void Event(const 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; + } + + auto siginfo = reinterpret_cast<const signalfd_siginfo *> + (event.rawBuffer.data()); + + if (siginfo->ssi_signo == SIGTERM) { + LogInfo("Got signal: SIGTERM"); + dynamic_cast<SocketManager *>(m_serviceManager)->MainLoopStop(); + return; + } + + LogInfo("This should not happend. Got signal: " << siginfo->ssi_signo); + } }; -SocketManager::SocketDescription& +SocketManager::SocketDescription & SocketManager::CreateDefaultReadSocketDescription(int sock, bool timeout) { - if ((int)m_socketDescriptionVector.size() <= sock) - m_socketDescriptionVector.resize(sock+20); - - auto &desc = m_socketDescriptionVector[sock]; - desc.setListen(false); - desc.setOpen(true); - desc.setCynara(false); - desc.interfaceID = 0; - desc.service = NULL; - desc.counter = ++m_counter; - - if (timeout) { - desc.timeout = time(NULL) + SOCKET_TIMEOUT; - Timeout tm; - tm.time = desc.timeout; - tm.sock = sock; - m_timeoutQueue.push(tm); - } - - desc.setTimeout(timeout); - - FD_SET(sock, &m_readSet); - m_maxDesc = sock > m_maxDesc ? sock : m_maxDesc; - return desc; + if ((int)m_socketDescriptionVector.size() <= sock) + m_socketDescriptionVector.resize(sock + 20); + + auto &desc = m_socketDescriptionVector[sock]; + desc.setListen(false); + desc.setOpen(true); + desc.setCynara(false); + desc.interfaceID = 0; + desc.service = NULL; + desc.counter = ++m_counter; + + if (timeout) { + desc.timeout = time(NULL) + SOCKET_TIMEOUT; + Timeout tm; + tm.time = desc.timeout; + tm.sock = sock; + m_timeoutQueue.push(tm); + } + + desc.setTimeout(timeout); + + FD_SET(sock, &m_readSet); + m_maxDesc = sock > m_maxDesc ? sock : m_maxDesc; + return desc; } SocketManager::SocketManager() : - m_maxDesc(0), - m_working(true), - m_counter(0) + m_maxDesc(0), + m_working(true), + m_counter(0) { - FD_ZERO(&m_readSet); - FD_ZERO(&m_writeSet); - - if (-1 == pipe(m_notifyMe)) { - int err = errno; - ThrowMsg(Exception::InitFailed, "Error in pipe: " << GetErrnoString(err)); - } - - LogInfo("Pipe: Read desc: " << m_notifyMe[0] << " Write desc: " << m_notifyMe[1]); - - auto &desc = CreateDefaultReadSocketDescription(m_notifyMe[0], false); - desc.service = new DummyService; - m_serviceVector.push_back(desc.service); - - // std::thread bases on pthread so this should work fine - sigset_t set; - sigemptyset(&set); - sigaddset(&set, SIGPIPE); - pthread_sigmask(SIG_BLOCK, &set, NULL); - - // 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"); - } - - if (signalService) - m_serviceVector.push_back(signalService); - - // We cannot create Cynara earlier because descriptors are not initialized! - m_cynara.reset(new Cynara(this)); + FD_ZERO(&m_readSet); + FD_ZERO(&m_writeSet); + + if (-1 == pipe(m_notifyMe)) { + int err = errno; + ThrowMsg(Exception::InitFailed, "Error in pipe: " << GetErrnoString(err)); + } + + LogInfo("Pipe: Read desc: " << m_notifyMe[0] << " Write desc: " << + m_notifyMe[1]); + + auto &desc = CreateDefaultReadSocketDescription(m_notifyMe[0], false); + desc.service = new DummyService; + m_serviceVector.push_back(desc.service); + + // std::thread bases on pthread so this should work fine + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGPIPE); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + // 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"); + } + + if (signalService) + m_serviceVector.push_back(signalService); + + // We cannot create Cynara earlier because descriptors are not initialized! + m_cynara.reset(new Cynara(this)); } SocketManager::~SocketManager() { - m_cynara.reset(nullptr); - - // Time to destroy all services. - for (auto service : m_serviceVector) { - LogDebug("delete " << (void*)(service)); - if (service) - service->Stop(); - delete service; - } - - for (size_t i = 0; i < m_socketDescriptionVector.size(); ++i) - if (m_socketDescriptionVector[i].isOpen()) - close(i); - - // All socket except one were closed. Now pipe input must be closed. - close(m_notifyMe[1]); + m_cynara.reset(nullptr); + + // Time to destroy all services. + for (auto service : m_serviceVector) { + LogDebug("delete " << (void *)(service)); + + if (service) + service->Stop(); + + delete service; + } + + for (size_t i = 0; i < m_socketDescriptionVector.size(); ++i) + if (m_socketDescriptionVector[i].isOpen()) + close(i); + + // All socket except one were closed. Now pipe input must be closed. + close(m_notifyMe[1]); } void SocketManager::ReadyForAccept(int sock) { - struct sockaddr_un clientAddr; - unsigned int clientLen = sizeof(clientAddr); - int client = accept4(sock, (struct sockaddr*) &clientAddr, &clientLen, SOCK_NONBLOCK); - - if (-1 == client) { - int err = errno; - LogDebug("Error in accept: " << GetErrnoString(err)); - return; - } - - std::string smack; - std::string user; - Credentials peerCred; - - if (0 > getCredentialsFromSocket(client, peerCred) - || !Cynara::GetUserFromSocket(client, user) - || !Cynara::GetClientFromSocket(client, smack)) { - LogDebug("Error in getting credentials from socket."); - TEMP_FAILURE_RETRY(close(client)); - return; - } - - auto &desc = CreateDefaultReadSocketDescription(client, true); - desc.interfaceID = m_socketDescriptionVector[sock].interfaceID; - desc.service = m_socketDescriptionVector[sock].service; - desc.cynaraPrivilege = m_socketDescriptionVector[sock].cynaraPrivilege; - desc.cynaraUser = std::move(user); - desc.cynaraClient = std::move(smack); - - GenericSocketService::AcceptEvent event; - event.connectionID.sock = client; - event.connectionID.counter = desc.counter; - event.interfaceID = desc.interfaceID; - event.credentials = peerCred; - desc.service->Event(event); + struct sockaddr_un clientAddr; + unsigned int clientLen = sizeof(clientAddr); + int client = accept4(sock, (struct sockaddr *) &clientAddr, &clientLen, + SOCK_NONBLOCK); + + if (-1 == client) { + int err = errno; + LogDebug("Error in accept: " << GetErrnoString(err)); + return; + } + + std::string smack; + std::string user; + Credentials peerCred; + + if (0 > getCredentialsFromSocket(client, peerCred) + || !Cynara::GetUserFromSocket(client, user) + || !Cynara::GetClientFromSocket(client, smack)) { + LogDebug("Error in getting credentials from socket."); + TEMP_FAILURE_RETRY(close(client)); + return; + } + + auto &desc = CreateDefaultReadSocketDescription(client, true); + desc.interfaceID = m_socketDescriptionVector[sock].interfaceID; + desc.service = m_socketDescriptionVector[sock].service; + desc.cynaraPrivilege = m_socketDescriptionVector[sock].cynaraPrivilege; + desc.cynaraUser = std::move(user); + desc.cynaraClient = std::move(smack); + + GenericSocketService::AcceptEvent event; + event.connectionID.sock = client; + event.connectionID.counter = desc.counter; + event.interfaceID = desc.interfaceID; + event.credentials = peerCred; + desc.service->Event(event); } void SocketManager::SecurityStatus(int sock, int counter, bool allowed) { - auto &desc = m_socketDescriptionVector[sock]; - if (!desc.isOpen()) { - LogDebug("Client from socket " << sock << - " closed connection before cynara answer was received."); - return; - } - - if (desc.counter != counter) { - LogDebug("Client from socket " << sock << - " closed connection before cynara answer was received."); - return; - } - - GenericSocketService::SecurityEvent event; - event.connectionID.sock = sock; - event.connectionID.counter = counter; - event.allowed = allowed; - desc.service->Event(event); + auto &desc = m_socketDescriptionVector[sock]; + + if (!desc.isOpen()) { + LogDebug("Client from socket " << sock << + " closed connection before cynara answer was received."); + return; + } + + if (desc.counter != counter) { + LogDebug("Client from socket " << sock << + " closed connection before cynara answer was received."); + return; + } + + GenericSocketService::SecurityEvent event; + event.connectionID.sock = sock; + event.connectionID.counter = counter; + event.allowed = allowed; + desc.service->Event(event); } void SocketManager::ReadyForRead(int sock) { - if (m_socketDescriptionVector[sock].isListen()) { - ReadyForAccept(sock); - return; - } - - if (m_socketDescriptionVector[sock].isCynara()) { - m_cynara->ProcessSocket(); - return; - } - - GenericSocketService::ReadEvent event; - event.connectionID.sock = sock; - event.connectionID.counter = m_socketDescriptionVector[sock].counter; - event.rawBuffer.resize(4096); - - auto &desc = m_socketDescriptionVector[sock]; - desc.timeout = time(NULL) + SOCKET_TIMEOUT; - - ssize_t size = read(sock, &event.rawBuffer[0], 4096); - - if (size == 0) { - CloseSocket(sock); - } else if (size >= 0) { - event.rawBuffer.resize(size); - desc.service->Event(event); - } else if (size == -1) { - int err = errno; - switch (err) { - case EAGAIN: - case EINTR: - break; - default: - LogDebug("Reading sock error: " << GetErrnoString(err)); - CloseSocket(sock); - } - } + if (m_socketDescriptionVector[sock].isListen()) { + ReadyForAccept(sock); + return; + } + + if (m_socketDescriptionVector[sock].isCynara()) { + m_cynara->ProcessSocket(); + return; + } + + GenericSocketService::ReadEvent event; + event.connectionID.sock = sock; + event.connectionID.counter = m_socketDescriptionVector[sock].counter; + event.rawBuffer.resize(4096); + + auto &desc = m_socketDescriptionVector[sock]; + desc.timeout = time(NULL) + SOCKET_TIMEOUT; + + ssize_t size = read(sock, &event.rawBuffer[0], 4096); + + if (size == 0) { + CloseSocket(sock); + } else if (size >= 0) { + event.rawBuffer.resize(size); + desc.service->Event(event); + } else if (size == -1) { + int err = errno; + + switch (err) { + case EAGAIN: + case EINTR: + break; + + default: + LogDebug("Reading sock error: " << GetErrnoString(err)); + CloseSocket(sock); + } + } } void SocketManager::ReadyForWrite(int sock) { - if (m_socketDescriptionVector[sock].isCynara()) { - m_cynara->ProcessSocket(); - return; - } - - auto &desc = m_socketDescriptionVector[sock]; - size_t size = desc.rawBuffer.size(); - ssize_t result = write(sock, &desc.rawBuffer[0], size); - - if (result == -1) { - int err = errno; - switch (err) { - case EAGAIN: - case EINTR: - // select will trigger write once again, nothing to do - break; - case EPIPE: - default: - LogDebug("Error during write: " << GetErrnoString(err)); - CloseSocket(sock); - break; - } - return; // We do not want to propagate error to next layer - } - - desc.rawBuffer.erase(desc.rawBuffer.begin(), desc.rawBuffer.begin()+result); - - desc.timeout = time(NULL) + SOCKET_TIMEOUT; - - if (desc.rawBuffer.empty()) - FD_CLR(sock, &m_writeSet); - - GenericSocketService::WriteEvent event; - event.connectionID.sock = sock; - event.connectionID.counter = desc.counter; - event.size = result; - event.left = desc.rawBuffer.size(); - - desc.service->Event(event); + if (m_socketDescriptionVector[sock].isCynara()) { + m_cynara->ProcessSocket(); + return; + } + + auto &desc = m_socketDescriptionVector[sock]; + size_t size = desc.rawBuffer.size(); + ssize_t result = write(sock, &desc.rawBuffer[0], size); + + if (result == -1) { + int err = errno; + + switch (err) { + case EAGAIN: + case EINTR: + // select will trigger write once again, nothing to do + break; + + case EPIPE: + default: + LogDebug("Error during write: " << GetErrnoString(err)); + CloseSocket(sock); + break; + } + + return; // We do not want to propagate error to next layer + } + + desc.rawBuffer.erase(desc.rawBuffer.begin(), desc.rawBuffer.begin() + result); + + desc.timeout = time(NULL) + SOCKET_TIMEOUT; + + if (desc.rawBuffer.empty()) + FD_CLR(sock, &m_writeSet); + + GenericSocketService::WriteEvent event; + event.connectionID.sock = sock; + event.connectionID.counter = desc.counter; + event.size = result; + event.left = desc.rawBuffer.size(); + + desc.service->Event(event); } void SocketManager::MainLoop() { - // remove evironment values passed by systemd - sd_listen_fds(1); - - // Daemon is ready to work. - sd_notify(0, "READY=1"); - - m_working = true; - while (m_working) { - fd_set readSet = m_readSet; - fd_set writeSet = m_writeSet; - - timeval localTempTimeout; - timeval *ptrTimeout = &localTempTimeout; - - // I need to extract timeout from priority_queue. - // Timeout in priority_queue may be deprecated. - // I need to find some actual one. - while (!m_timeoutQueue.empty()) { - auto &top = m_timeoutQueue.top(); - auto &desc = m_socketDescriptionVector[top.sock]; - - if (top.time == desc.timeout) { - // This timeout matches timeout from socket. - // It can be used. - break; - } else { - // This socket was used after timeout in priority queue was set up. - // We need to update timeout and find some useable one. - Timeout tm = { desc.timeout , top.sock}; - m_timeoutQueue.pop(); - m_timeoutQueue.push(tm); - } - } - - if (m_timeoutQueue.empty()) { - LogDebug("No usaable timeout found."); - ptrTimeout = NULL; // select will wait without timeout - } else { - time_t currentTime = time(NULL); - auto &pqTimeout = m_timeoutQueue.top(); - - // 0 means that select won't block and socket will be closed ;-) - ptrTimeout->tv_sec = - currentTime < pqTimeout.time ? pqTimeout.time - currentTime : 0; - ptrTimeout->tv_usec = 0; - } - - int ret = select(m_maxDesc+1, &readSet, &writeSet, NULL, ptrTimeout); - - if (0 == ret) { // timeout - Assert(!m_timeoutQueue.empty()); - - Timeout pqTimeout = m_timeoutQueue.top(); - m_timeoutQueue.pop(); - - auto &desc = m_socketDescriptionVector[pqTimeout.sock]; - - if (!desc.isTimeout() || !desc.isOpen()) { - // Connection was closed. Timeout is useless... - desc.setTimeout(false); - continue; - } - - if (pqTimeout.time < desc.timeout) { - // Is it possible? - // This socket was used after timeout. We need to update timeout. - pqTimeout.time = desc.timeout; - m_timeoutQueue.push(pqTimeout); - continue; - } - - // timeout from m_timeoutQueue matches with socket.timeout - // and connection is open. Time to close it! - // Putting new timeout in queue here is pointless. - desc.setTimeout(false); - CloseSocket(pqTimeout.sock); - - // All done. Now we should process next select ;-) - continue; - } - - if (-1 == ret) { - switch (errno) { - case EINTR: - LogDebug("EINTR in select"); - break; - default: - int err = errno; - LogError("Error in select: " << GetErrnoString(err)); - return; - } - continue; - } - for (int i = 0; i < m_maxDesc+1 && ret; ++i) { - if (FD_ISSET(i, &readSet)) { - ReadyForRead(i); - --ret; - } - if (FD_ISSET(i, &writeSet)) { - ReadyForWrite(i); - --ret; - } - } - ProcessQueue(); - } + // remove evironment values passed by systemd + sd_listen_fds(1); + + // Daemon is ready to work. + sd_notify(0, "READY=1"); + + m_working = true; + + while (m_working) { + fd_set readSet = m_readSet; + fd_set writeSet = m_writeSet; + + timeval localTempTimeout; + timeval *ptrTimeout = &localTempTimeout; + + // I need to extract timeout from priority_queue. + // Timeout in priority_queue may be deprecated. + // I need to find some actual one. + while (!m_timeoutQueue.empty()) { + auto &top = m_timeoutQueue.top(); + auto &desc = m_socketDescriptionVector[top.sock]; + + if (top.time == desc.timeout) { + // This timeout matches timeout from socket. + // It can be used. + break; + } else { + // This socket was used after timeout in priority queue was set up. + // We need to update timeout and find some useable one. + Timeout tm = { desc.timeout , top.sock}; + m_timeoutQueue.pop(); + m_timeoutQueue.push(tm); + } + } + + if (m_timeoutQueue.empty()) { + LogDebug("No usaable timeout found."); + ptrTimeout = NULL; // select will wait without timeout + } else { + time_t currentTime = time(NULL); + auto &pqTimeout = m_timeoutQueue.top(); + + // 0 means that select won't block and socket will be closed ;-) + ptrTimeout->tv_sec = + currentTime < pqTimeout.time ? pqTimeout.time - currentTime : 0; + ptrTimeout->tv_usec = 0; + } + + int ret = select(m_maxDesc + 1, &readSet, &writeSet, NULL, ptrTimeout); + + if (0 == ret) { // timeout + Assert(!m_timeoutQueue.empty()); + + Timeout pqTimeout = m_timeoutQueue.top(); + m_timeoutQueue.pop(); + + auto &desc = m_socketDescriptionVector[pqTimeout.sock]; + + if (!desc.isTimeout() || !desc.isOpen()) { + // Connection was closed. Timeout is useless... + desc.setTimeout(false); + continue; + } + + if (pqTimeout.time < desc.timeout) { + // Is it possible? + // This socket was used after timeout. We need to update timeout. + pqTimeout.time = desc.timeout; + m_timeoutQueue.push(pqTimeout); + continue; + } + + // timeout from m_timeoutQueue matches with socket.timeout + // and connection is open. Time to close it! + // Putting new timeout in queue here is pointless. + desc.setTimeout(false); + CloseSocket(pqTimeout.sock); + + // All done. Now we should process next select ;-) + continue; + } + + if (-1 == ret) { + switch (errno) { + case EINTR: + LogDebug("EINTR in select"); + break; + + default: + int err = errno; + LogError("Error in select: " << GetErrnoString(err)); + return; + } + + continue; + } + + for (int i = 0; i < m_maxDesc + 1 && ret; ++i) { + if (FD_ISSET(i, &readSet)) { + ReadyForRead(i); + --ret; + } + + if (FD_ISSET(i, &writeSet)) { + ReadyForWrite(i); + --ret; + } + } + + ProcessQueue(); + } } void SocketManager::MainLoopStop() { - m_working = false; - NotifyMe(); + m_working = false; + NotifyMe(); } int SocketManager::GetSocketFromSystemD( - const GenericSocketService::ServiceDescription &desc) + const GenericSocketService::ServiceDescription &desc) { - int fd; - - // TODO optimalization - do it once in object constructor - // and remember all information path->sockfd - int n = sd_listen_fds(0); - - LogInfo("sd_listen_fds returns: " << n); - - if (n < 0) { - LogError("Error in sd_listend_fds"); - ThrowMsg(Exception::InitFailed, "Error in sd_listend_fds"); - } - - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START+n; ++fd) { - if (0 < sd_is_socket_unix(fd, SOCK_STREAM, 1, - desc.serviceHandlerPath.c_str(), 0)) { - LogInfo("Useable socket " << desc.serviceHandlerPath << - " was passed by SystemD under descriptor " << fd); - return fd; - } - } - LogError("No useable sockets were passed by systemd."); - return -1; + int fd; + + // TODO optimalization - do it once in object constructor + // and remember all information path->sockfd + int n = sd_listen_fds(0); + + LogInfo("sd_listen_fds returns: " << n); + + if (n < 0) { + LogError("Error in sd_listend_fds"); + ThrowMsg(Exception::InitFailed, "Error in sd_listend_fds"); + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) { + if (0 < sd_is_socket_unix(fd, SOCK_STREAM, 1, + desc.serviceHandlerPath.c_str(), 0)) { + LogInfo("Useable socket " << desc.serviceHandlerPath << + " was passed by SystemD under descriptor " << fd); + return fd; + } + } + + LogError("No useable sockets were passed by systemd."); + return -1; } int SocketManager::CreateDomainSocketHelp( - const GenericSocketService::ServiceDescription &desc) + const GenericSocketService::ServiceDescription &desc) { - int sockfd; - - if (desc.serviceHandlerPath.size()*sizeof(decltype(desc.serviceHandlerPath)::value_type) >= - sizeof(static_cast<sockaddr_un*>(0)->sun_path)) { - LogError("Service handler path too long: " << desc.serviceHandlerPath.size()); - ThrowMsg(Exception::InitFailed, - "Service handler path too long: " << desc.serviceHandlerPath.size()); - } - - if (-1 == (sockfd = socket(AF_UNIX, SOCK_STREAM, 0))) { - int err = errno; - LogError("Error in socket: " << GetErrnoString(err)); - ThrowMsg(Exception::InitFailed, "Error in socket: " << GetErrnoString(err)); - } - - if (smack_check()) { - LogInfo("Set up smack label: " << desc.privilege); - -// if (0 != smack_fsetlabel(sockfd, desc.smackLabel.c_str(), SMACK_LABEL_IPIN)) { -// LogError("Error in smack_fsetlabel"); -// ThrowMsg(Exception::InitFailed, "Error in smack_fsetlabel"); -// } - } else { - LogInfo("No smack on platform. Socket won't be securied with smack label!"); - } - - int flags; - if (-1 == (flags = fcntl(sockfd, F_GETFL, 0))) - flags = 0; - - if (-1 == fcntl(sockfd, F_SETFL, flags | O_NONBLOCK)) { - int err = errno; - close(sockfd); - LogError("Error in fcntl: " << GetErrnoString(err)); - ThrowMsg(Exception::InitFailed, "Error in fcntl: " << GetErrnoString(err)); - } - - sockaddr_un serverAddress; - memset(&serverAddress, 0, sizeof(serverAddress)); - serverAddress.sun_family = AF_UNIX; - strncpy(serverAddress.sun_path, desc.serviceHandlerPath.c_str(), sizeof(serverAddress.sun_path) - 1); - unlink(serverAddress.sun_path); - - mode_t originalUmask; - originalUmask = umask(0); - - if (-1 == bind(sockfd, (struct sockaddr*)&serverAddress, sizeof(serverAddress))) { - int err = errno; - close(sockfd); - LogError("Error in bind: " << GetErrnoString(err)); - ThrowMsg(Exception::InitFailed, "Error in bind: " << GetErrnoString(err)); - } - - umask(originalUmask); - - if (-1 == listen(sockfd, 5)) { - int err = errno; - close(sockfd); - LogError("Error in listen: " << GetErrnoString(err)); - ThrowMsg(Exception::InitFailed, "Error in listen: " << GetErrnoString(err)); - } - - return sockfd; + int sockfd; + + if (desc.serviceHandlerPath.size()*sizeof(decltype(desc.serviceHandlerPath) + ::value_type) >= + sizeof(static_cast<sockaddr_un *>(0)->sun_path)) { + LogError("Service handler path too long: " << desc.serviceHandlerPath.size()); + ThrowMsg(Exception::InitFailed, + "Service handler path too long: " << desc.serviceHandlerPath.size()); + } + + if (-1 == (sockfd = socket(AF_UNIX, SOCK_STREAM, 0))) { + int err = errno; + LogError("Error in socket: " << GetErrnoString(err)); + ThrowMsg(Exception::InitFailed, "Error in socket: " << GetErrnoString(err)); + } + + if (smack_check()) { + LogInfo("Set up smack label: " << desc.privilege); + + // if (0 != smack_fsetlabel(sockfd, desc.smackLabel.c_str(), SMACK_LABEL_IPIN)) { + // LogError("Error in smack_fsetlabel"); + // ThrowMsg(Exception::InitFailed, "Error in smack_fsetlabel"); + // } + } else { + LogInfo("No smack on platform. Socket won't be securied with smack label!"); + } + + int flags; + + if (-1 == (flags = fcntl(sockfd, F_GETFL, 0))) + flags = 0; + + if (-1 == fcntl(sockfd, F_SETFL, flags | O_NONBLOCK)) { + int err = errno; + close(sockfd); + LogError("Error in fcntl: " << GetErrnoString(err)); + ThrowMsg(Exception::InitFailed, "Error in fcntl: " << GetErrnoString(err)); + } + + sockaddr_un serverAddress; + memset(&serverAddress, 0, sizeof(serverAddress)); + serverAddress.sun_family = AF_UNIX; + strncpy(serverAddress.sun_path, desc.serviceHandlerPath.c_str(), + sizeof(serverAddress.sun_path) - 1); + unlink(serverAddress.sun_path); + + mode_t originalUmask; + originalUmask = umask(0); + + if (-1 == bind(sockfd, (struct sockaddr *)&serverAddress, + sizeof(serverAddress))) { + int err = errno; + close(sockfd); + LogError("Error in bind: " << GetErrnoString(err)); + ThrowMsg(Exception::InitFailed, "Error in bind: " << GetErrnoString(err)); + } + + umask(originalUmask); + + if (-1 == listen(sockfd, 5)) { + int err = errno; + close(sockfd); + LogError("Error in listen: " << GetErrnoString(err)); + ThrowMsg(Exception::InitFailed, "Error in listen: " << GetErrnoString(err)); + } + + return sockfd; } void SocketManager::CreateDomainSocket( - GenericSocketService *service, - const GenericSocketService::ServiceDescription &desc) + GenericSocketService *service, + const GenericSocketService::ServiceDescription &desc) { - int sockfd = GetSocketFromSystemD(desc); - if (-1 == sockfd) - sockfd = CreateDomainSocketHelp(desc); + int sockfd = GetSocketFromSystemD(desc); + + if (-1 == sockfd) + sockfd = CreateDomainSocketHelp(desc); - auto &description = CreateDefaultReadSocketDescription(sockfd, false); + auto &description = CreateDefaultReadSocketDescription(sockfd, false); - description.setListen(true); - description.interfaceID = desc.interfaceID; - description.service = service; - description.cynaraPrivilege = desc.privilege; + description.setListen(true); + description.interfaceID = desc.interfaceID; + description.service = service; + description.cynaraPrivilege = desc.privilege; - LogDebug("Listen on socket: " << sockfd << - " Handler: " << desc.serviceHandlerPath.c_str()); + LogDebug("Listen on socket: " << sockfd << + " Handler: " << desc.serviceHandlerPath.c_str()); } void SocketManager::RegisterSocketService(GenericSocketService *service) { - service->SetSocketManager(this); - service->SetCommManager(&m_commMgr); - auto serviceVector = service->GetServiceDescription(); - m_serviceVector.push_back(service); - Try { - for (auto iter = serviceVector.begin(); iter != serviceVector.end(); ++iter) - CreateDomainSocket(service, *iter); - } Catch(Exception::Base) { - for (int i =0; i < (int)m_socketDescriptionVector.size(); ++i) { - auto &desc = m_socketDescriptionVector[i]; - if (desc.service == service && desc.isOpen()) { - close(i); - desc.setOpen(false); - } - } - ReThrow(Exception::Base); - } + service->SetSocketManager(this); + service->SetCommManager(&m_commMgr); + auto serviceVector = service->GetServiceDescription(); + m_serviceVector.push_back(service); + + try { + for (auto iter = serviceVector.begin(); iter != serviceVector.end(); ++iter) + CreateDomainSocket(service, *iter); + } catch (const Exception::Base &) { + for (int i = 0; i < (int)m_socketDescriptionVector.size(); ++i) { + auto &desc = m_socketDescriptionVector[i]; + + if (desc.service == service && desc.isOpen()) { + close(i); + desc.setOpen(false); + } + } + + throw; + } } void SocketManager::Close(ConnectionID connectionID) { - CloseEvent event; - event.sock = connectionID.sock; - event.counter = connectionID.counter; - AddEvent(event); + CloseEvent event; + event.sock = connectionID.sock; + event.counter = connectionID.counter; + AddEvent(event); } void SocketManager::Write(ConnectionID connectionID, const RawBuffer &rawBuffer) { - WriteEvent event{connectionID, rawBuffer}; - AddEvent(event); + WriteEvent event{connectionID, rawBuffer}; + AddEvent(event); } void SocketManager::SecurityCheck(ConnectionID connectionID) { - SecurityEvent event; - event.sock = connectionID.sock; - event.counter = connectionID.counter; - AddEvent(event); + SecurityEvent event; + event.sock = connectionID.sock; + event.counter = connectionID.counter; + AddEvent(event); } void SocketManager::CreateEvent(EventFunction fun) { - { - std::lock_guard<std::mutex> ulock(m_eventQueueMutex); - m_eventQueue.push(std::move(fun)); - } - NotifyMe(); + { + std::lock_guard<std::mutex> l(this->m_eventQueueMutex); + m_eventQueue.push(std::move(fun)); + } + + NotifyMe(); } void SocketManager::NotifyMe() { - TEMP_FAILURE_RETRY(write(m_notifyMe[1], "You have message ;-)", 1)); + TEMP_FAILURE_RETRY(write(m_notifyMe[1], "You have message ;-)", 1)); } void SocketManager::ProcessQueue() { - while (1) { - EventFunction fun; - { - std::lock_guard<std::mutex> ulock(m_eventQueueMutex); - if (m_eventQueue.empty()) - return; - fun = std::move(m_eventQueue.front()); - m_eventQueue.pop(); - } - fun(); - } + while (1) { + EventFunction fun; + + { + std::lock_guard<std::mutex> l(this->m_eventQueueMutex); + + if (m_eventQueue.empty()) + return; + + fun = std::move(m_eventQueue.front()); + m_eventQueue.pop(); + } + + fun(); + } } void SocketManager::Handle(const WriteEvent &event) { - auto &desc = m_socketDescriptionVector[event.connectionID.sock]; + auto &desc = m_socketDescriptionVector[event.connectionID.sock]; - if (!desc.isOpen()) { - LogDebug("Received packet for write but connection is closed. Packet ignored!"); - return; - } + if (!desc.isOpen()) { + LogDebug("Received packet for write but connection is closed. Packet ignored!"); + return; + } - if (desc.counter != event.connectionID.counter) { - LogDebug("Received packet for write but counter is broken. Packet ignored!"); - return; - } + if (desc.counter != event.connectionID.counter) { + LogDebug("Received packet for write but counter is broken. Packet ignored!"); + return; + } - std::copy( - event.rawBuffer.begin(), - event.rawBuffer.end(), - std::back_inserter(desc.rawBuffer)); + std::copy( + event.rawBuffer.begin(), + event.rawBuffer.end(), + std::back_inserter(desc.rawBuffer)); - FD_SET(event.connectionID.sock, &m_writeSet); + FD_SET(event.connectionID.sock, &m_writeSet); } void SocketManager::Handle(const CloseEvent &event) { - if (!m_socketDescriptionVector[event.sock].isOpen()) - return; + if (!m_socketDescriptionVector[event.sock].isOpen()) + return; - if (event.counter != m_socketDescriptionVector[event.sock].counter) - return; + if (event.counter != m_socketDescriptionVector[event.sock].counter) + return; - CloseSocket(event.sock); + CloseSocket(event.sock); } void SocketManager::Handle(const SecurityEvent &event) { - auto& desc = m_socketDescriptionVector[event.sock]; - if (!desc.isOpen()) - return; - - if (event.counter != desc.counter) - return; - - std::string session = std::to_string(desc.counter); - - m_cynara->Request(desc.cynaraUser, - desc.cynaraClient, - session, - desc.cynaraPrivilege, - [this, event](bool allowed) { - this->SecurityStatus(event.sock, event.counter, allowed); - }); + auto &desc = m_socketDescriptionVector[event.sock]; + + if (!desc.isOpen()) + return; + + if (event.counter != desc.counter) + return; + + std::string session = std::to_string(desc.counter); + + m_cynara->Request(desc.cynaraUser, + desc.cynaraClient, + session, + desc.cynaraPrivilege, + [this, event](bool allowed) { + this->SecurityStatus(event.sock, event.counter, allowed); + }); } void SocketManager::CloseSocket(int sock) { - auto &desc = m_socketDescriptionVector[sock]; - - if (!(desc.isOpen())) { - // This may happend when some information was waiting for write to the - // socket and in the same time socket was closed by the client. - LogError("Socket " << sock << " is not open. Nothing to do!"); - return; - } - - GenericSocketService::CloseEvent event; - event.connectionID.sock = sock; - event.connectionID.counter = desc.counter; - auto service = desc.service; - - desc.setOpen(false); - desc.service = NULL; - desc.interfaceID = -1; - desc.rawBuffer.clear(); - - if (service) - service->Event(event); - else - LogError("Critical! Service is NULL! This should never happend!"); - - TEMP_FAILURE_RETRY(close(sock)); - FD_CLR(sock, &m_readSet); - FD_CLR(sock, &m_writeSet); + auto &desc = m_socketDescriptionVector[sock]; + + if (!(desc.isOpen())) { + // This may happend when some information was waiting for write to the + // socket and in the same time socket was closed by the client. + LogError("Socket " << sock << " is not open. Nothing to do!"); + return; + } + + GenericSocketService::CloseEvent event; + event.connectionID.sock = sock; + event.connectionID.counter = desc.counter; + auto service = desc.service; + + desc.setOpen(false); + desc.service = NULL; + desc.interfaceID = -1; + desc.rawBuffer.clear(); + + if (service) + service->Event(event); + else + LogError("Critical! Service is NULL! This should never happend!"); + + TEMP_FAILURE_RETRY(close(sock)); + FD_CLR(sock, &m_readSet); + FD_CLR(sock, &m_writeSet); } void SocketManager::CynaraSocket(int oldFd, int newFd, bool isRW) { - if (newFd != oldFd) { - if (newFd >= 0) { - auto &desc = CreateDefaultReadSocketDescription(newFd, false); - desc.service = nullptr; - desc.setCynara(true); - } - - if (oldFd >= 0) { - auto &old = m_socketDescriptionVector[oldFd]; - old.setOpen(false); - old.setCynara(false); - FD_CLR(oldFd, &m_writeSet); - FD_CLR(oldFd, &m_readSet); - } - } - - if (newFd >= 0) { - FD_SET(newFd, &m_readSet); - - if (isRW) - FD_SET(newFd, &m_writeSet); - else - FD_CLR(newFd, &m_writeSet); - } + if (newFd != oldFd) { + if (newFd >= 0) { + auto &desc = CreateDefaultReadSocketDescription(newFd, false); + desc.service = nullptr; + desc.setCynara(true); + } + + if (oldFd >= 0) { + auto &old = m_socketDescriptionVector[oldFd]; + old.setOpen(false); + old.setCynara(false); + FD_CLR(oldFd, &m_writeSet); + FD_CLR(oldFd, &m_readSet); + } + } + + if (newFd >= 0) { + FD_SET(newFd, &m_readSet); + + if (isRW) + FD_SET(newFd, &m_writeSet); + else + FD_CLR(newFd, &m_writeSet); + } } } // namespace CKM |