From 8cc43b39b5b6177119834c655c8db3d6b5fffe66 Mon Sep 17 00:00:00 2001 From: Benjamin Geer Date: Fri, 16 Dec 2016 11:48:50 +0100 Subject: [PATCH] fix: Make signal handler code asynchronous-safe. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add a SipiGlobal class to handle global initialisation and cleanup using RAII. - Replace exit() in main() with “return EXIT_SUCCESS” or “return EXIT_FAILURE”. --- README.md | 2 +- shttps/Server.h | 5 ++++- src/sipi.cpp | 43 ++++++++++++++++++++++++++++++------------- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 0783d586..503453a3 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ In the main directory, call: local/bin/sipi -config config/sipi.config.lua ``` -All operations are written to the log file `sipi.log.file`. +All operations are written to the log file `sipi.log`. ## Serving an Image diff --git a/shttps/Server.h b/shttps/Server.h index 9c4a5c9f..91e7f335 100644 --- a/shttps/Server.h +++ b/shttps/Server.h @@ -385,9 +385,12 @@ namespace shttps { /*! * Stop the server gracefully (all destructors are called etc.) and the - * cache file is updated. + * cache file is updated. This function is asynchronous-safe, so it may be called + * from within a signal handler. */ inline void stop(void) { + // POSIX declares write() to be asynchronous-safe. + // See https://www.securecoding.cert.org/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers write(stoppipe[1], "@", 1); } diff --git a/src/sipi.cpp b/src/sipi.cpp index 601a06b8..518eca54 100644 --- a/src/sipi.cpp +++ b/src/sipi.cpp @@ -31,6 +31,9 @@ #include #include +#include +#include + #include "shttps/Logger.h" #include "shttps/Global.h" #include "shttps/LuaServer.h" @@ -104,16 +107,13 @@ static std::string fileType_string(FileType f_type) { }; static void sighandler(int sig) { - std::cerr << std::endl << "Got SIGINT, stopping server gracefully...." << std::endl; - auto logger = Logger::getLogger(shttps::loggername); + // Any functions called in a signal handler must be asynchronous-safe. + // See https://www.securecoding.cert.org/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers + if (serverptr != NULL) { - *logger << Logger::LogLevel::INFORMATIONAL << "Got SIGINT, stopping server" << Logger::LogAction::FLUSH; + // Server::stop() is asynchronous-safe. serverptr->stop(); } - else { - *logger << Logger::LogLevel::INFORMATIONAL << "Got SIGINT, exiting server" << Logger::LogAction::FLUSH; - exit(0); - } } //========================================================================= @@ -245,8 +245,24 @@ static void sipiConfGlobals(lua_State *L, shttps::Connection &conn, void *user_d lua_setglobal(L, "config"); } +namespace Sipi { + /*! + * Handles global initialisation and cleanup. + */ + class SipiGlobal { + public: + SipiGlobal() { + curl_global_init(CURL_GLOBAL_ALL); + } + + ~SipiGlobal() { + curl_global_cleanup(); + } + }; +} int main (int argc, char *argv[]) { + Sipi::SipiGlobal sipiGlobal; // // register namespace sipi in xmp. Since this part of the XMP library is @@ -289,7 +305,7 @@ int main (int argc, char *argv[]) { } catch (Sipi::SipiError &err) { std::cerr << err; - exit (-1); + return EXIT_FAILURE; } // @@ -301,7 +317,7 @@ int main (int argc, char *argv[]) { } catch (Sipi::SipiError &err) { std::cerr << err; - exit (-1); + return EXIT_FAILURE; } Sipi::SipiImage img1, img2; img1.read(infname1); @@ -439,7 +455,7 @@ int main (int argc, char *argv[]) { } catch (Sipi::SipiError &err) { std::cerr << err; - exit (-1); + return EXIT_FAILURE; } // @@ -451,7 +467,7 @@ int main (int argc, char *argv[]) { } catch (Sipi::SipiError &err) { std::cerr << err; - exit (-1); + return EXIT_FAILURE; } // @@ -463,7 +479,7 @@ int main (int argc, char *argv[]) { } catch (Sipi::SipiError &err) { std::cerr << err; - exit (-1); + return EXIT_FAILURE; } @@ -590,5 +606,6 @@ int main (int argc, char *argv[]) { } } - return 0; + + return EXIT_SUCCESS; }