/* * gcsd * * gcsd the generic command sequencer daemon can be used to serialize * commands sent over various paralell communication channels to a * single command output. It can be seen as a multiplexer for any * kind of communication between a single resource and various clients * which want to submit commands to it or query information from it. * gcsd is written in C and Lua. The goal is to provide an easy to * understand high level API based on Lua which can be used to * implement the business logic of the so formed multiplexer daemon. * * * Copyright (C) 2009-2010 Markus Grueneis * Christian Pointner * * This file is part of gcsd. * * gcsd is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * gcsd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with gcsd. If not, see . */ #include "datatypes.h" #include "log.h" #include "sig_handler.h" #include #include #ifndef WINVER #include #include #include static int sig_pipe_fds[2]; static void sig_handler(int sig) { sigset_t set; int ret = read(sig_pipe_fds[0], &set, sizeof(sigset_t)); if(ret != sizeof(sigset_t)) sigemptyset(&set); sigaddset(&set, sig); ret = write(sig_pipe_fds[1], &set, sizeof(sigset_t)); } int signal_init() { if(pipe(sig_pipe_fds)) { log_printf(ERROR, "signal handling init failed (pipe error: %s)", strerror(errno)); return -1; } int i; for(i=0; i<2; ++i) { int fd_flags = fcntl(sig_pipe_fds[i], F_GETFL); if(fd_flags == -1) { log_printf(ERROR, "signal handling init failed (pipe fd[%d] read flags error: %s)", i, strerror(errno)); return -1; } if(fcntl(sig_pipe_fds[i], F_SETFL, fd_flags | O_NONBLOCK) == -1){ log_printf(ERROR, "signal handling init failed (pipe fd[%d] write flags error: %s)", i, strerror(errno)); return -1; } } struct sigaction act, act_ign; act.sa_handler = sig_handler; sigfillset(&act.sa_mask); act.sa_flags = 0; act_ign.sa_handler = SIG_IGN; sigfillset(&act_ign.sa_mask); act_ign.sa_flags = 0; if((sigaction(SIGINT, &act, NULL) < 0) || (sigaction(SIGQUIT, &act, NULL) < 0) || (sigaction(SIGTERM, &act, NULL) < 0) || (sigaction(SIGHUP, &act, NULL) < 0) || (sigaction(SIGUSR1, &act, NULL) < 0) || (sigaction(SIGUSR2, &act, NULL) < 0) || (sigaction(SIGPIPE, &act_ign, NULL) < 0)) { log_printf(ERROR, "signal handling init failed (sigaction error: %s)", strerror(errno)); close(sig_pipe_fds[0]); close(sig_pipe_fds[1]); } return sig_pipe_fds[0]; } int signal_handle() { sigset_t set, oldset, tmpset; sigemptyset(&tmpset); sigaddset(&tmpset, SIGINT); sigaddset(&tmpset, SIGQUIT); sigaddset(&tmpset, SIGTERM); sigaddset(&tmpset, SIGHUP); sigaddset(&tmpset, SIGUSR1); sigaddset(&tmpset, SIGUSR2); sigprocmask(SIG_BLOCK, &tmpset, &oldset); int ret = read(sig_pipe_fds[0], &set, sizeof(sigset_t)); if(ret != sizeof(sigset_t)) sigemptyset(&set); int return_value = 0; int sig; for(sig=1; sig < NSIG; ++sig) { if(sigismember(&set, sig)) { switch(sig) { case SIGINT: log_printf(NOTICE, "SIG-Int caught, exitting"); return_value = 1; break; case SIGQUIT: log_printf(NOTICE, "SIG-Quit caught, exitting"); return_value = 1; break; case SIGTERM: log_printf(NOTICE, "SIG-Term caught, exitting"); return_value = 1; break; case SIGHUP: log_printf(NOTICE, "SIG-Hup caught"); break; case SIGUSR1: log_printf(NOTICE, "SIG-Usr1 caught"); break; case SIGUSR2: log_printf(NOTICE, "SIG-Usr2 caught"); break; default: log_printf(WARNING, "unknown signal %d caught, ignoring", sig); break; } sigdelset(&set, sig); } } sigprocmask(SIG_SETMASK, &oldset, NULL); return return_value; } void signal_stop() { struct sigaction act; act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGUSR1, &act, NULL); sigaction(SIGUSR2, &act, NULL); sigaction(SIGPIPE, &act, NULL); close(sig_pipe_fds[0]); close(sig_pipe_fds[1]); } #else #include #include static SOCKET sig_sock_fds[2]; static SOCKET server_sock; static DWORD WINAPI signal_connect_thread(void* p) { uint16_t port = *((uint16_t*)p); SOCKET client; client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(client == INVALID_SOCKET) { log_printf(ERROR, "Error at socket(): 0x%04X\n", WSAGetLastError()); return -1; } struct sockaddr_in server; server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr("127.0.0.1"); server.sin_port = port; int cnt = 0; int ret = SOCKET_ERROR; do { Sleep(100); ret = connect(client, (SOCKADDR*) &server, sizeof(server)); cnt++; } while(ret != 0 && cnt < 10); if(ret != 0) { log_printf(ERROR, "connect() failed: 0x%04X", WSAGetLastError()); closesocket(client); return -1; } log_printf(DEBUG, "sig_handler connected to port %d", port); sig_sock_fds[1] = client; return 0; } static BOOL WINAPI signal_ctrl_handler(DWORD ctrlType) { char c = (char)ctrlType; send(sig_sock_fds[1], &c, 1, 0); return 1; } int signal_init() { WSADATA wsaData; int ret = WSAStartup(MAKEWORD(2,2), &wsaData); if(ret != NO_ERROR) { log_printf(ERROR, "Error at WSAStartup(): 0x%04X", WSAGetLastError()); return -1; } server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(server_sock == INVALID_SOCKET) { log_printf(ERROR, "Error at socket(): 0x%04X\n", WSAGetLastError()); WSACleanup(); return -1; } struct sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr("127.0.0.1"); service.sin_port = 0; if(bind(server_sock, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) { log_printf(ERROR, "bind() failed: 0x%04X", WSAGetLastError()); closesocket(server_sock); WSACleanup(); return -1; } struct sockaddr_in hugo; int hugo_len = sizeof(hugo); if(getsockname(server_sock, (SOCKADDR*) &hugo, &hugo_len) == SOCKET_ERROR) { log_printf(ERROR, "getsockname() failed: 0x%04X", WSAGetLastError()); closesocket(server_sock); WSACleanup(); return -1; } if(listen(server_sock, 1) == SOCKET_ERROR) { log_printf(ERROR, "listen() failed: 0x%04X", WSAGetLastError()); closesocket(server_sock); WSACleanup(); return -1; } log_printf(DEBUG, "sig_handler listening on port %d", hugo.sin_port); HANDLE t = CreateThread(NULL, 0, signal_connect_thread, &(hugo.sin_port), 0, NULL); if(t == INVALID_HANDLE_VALUE) { log_printf(ERROR, "CreateThread() failed: 0x%04X", GetLastError()); closesocket(server_sock); WSACleanup(); return -1; } sig_sock_fds[0] = accept(server_sock, NULL, NULL); if(sig_sock_fds[0] == INVALID_SOCKET) { log_printf(ERROR, "accept() failed: 0x%04X", WSAGetLastError()); closesocket(server_sock); WSACleanup(); WaitForSingleObject(t, INFINITE); return -1; } WaitForSingleObject(t, INFINITE); if(!SetConsoleCtrlHandler(signal_ctrl_handler, 1)) { log_printf(ERROR, "adding console ctrl handler failed: 0x%04X" , GetLastError()); } return sig_sock_fds[0]; } int signal_handle() { char c; int ret = recv(sig_sock_fds[0], &c, 1, 0); if(ret == 1) { switch(c) { case CTRL_C_EVENT: log_printf(NOTICE, "CTRL-C Event received, exitting"); return 1; case CTRL_BREAK_EVENT: log_printf(NOTICE, "CTRL-Break Event received, ignoring"); return 1; case CTRL_CLOSE_EVENT: log_printf(NOTICE, "Close Event received, exitting"); return 1; case CTRL_LOGOFF_EVENT: log_printf(NOTICE, "LogOff Event received, exitting"); return 1; case CTRL_SHUTDOWN_EVENT: log_printf(NOTICE, "Shutdown Event received, exitting"); return 1; default: log_printf(NOTICE, "unknown event received 0x%02X, ignoring", c); return 0; } } if(ret == 0) { log_printf(ERROR, "signal socket closed normally, exitting"); return 1; } log_printf(ERROR, "signal socket closed with error 0x%04X, exitting", GetLastError()); return 1; } void signal_stop() { if(!SetConsoleCtrlHandler(signal_ctrl_handler, 0)) { log_printf(ERROR, "removeing console ctrl handler failed: 0x%04X" , GetLastError()); } closesocket(sig_sock_fds[0]); closesocket(sig_sock_fds[1]); closesocket(server_sock); WSACleanup(); return; } #endif