Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

service.cpp 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. // \file service.cpp
  2. //
  3. // Copyright (C) 2014 MicroNeil Research Corporation.
  4. //
  5. // This program is part of the MicroNeil Research Open Library Project. For
  6. // more information go to http://www.microneil.com/OpenLibrary/index.html
  7. //
  8. // This program is free software; you can redistribute it and/or modify it
  9. // under the terms of the GNU General Public License as published by the
  10. // Free Software Foundation; either version 2 of the License, or (at your
  11. // option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful, but WITHOUT
  14. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. // more details.
  17. //
  18. // You should have received a copy of the GNU General Public License along with
  19. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  20. // Place, Suite 330, Boston, MA 02111-1307 USA
  21. //==============================================================================
  22. #include <unistd.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <fcntl.h>
  26. #include <signal.h>
  27. #include <iostream>
  28. #include <cstdio>
  29. #include <cstdlib>
  30. #include <thread>
  31. #include <chrono>
  32. #include "service.hpp"
  33. // Main program for *nix daemon.
  34. int main(int argc, char *argv[]) {
  35. CodeDweller::Service &service = CodeDweller::Service::getInstance();
  36. return service.main(argc, argv);
  37. }
  38. namespace CodeDweller {
  39. Service::Service() :
  40. pauseReceived(false),
  41. resumeReceived(false),
  42. restartReceived(false),
  43. stopReceived(false) {
  44. }
  45. int Service::main(int argc, char *argv[]) {
  46. // Load the arguments.
  47. loadArguments(argc, argv);
  48. pid_t pid;
  49. // Fork the process.
  50. pid = fork();
  51. if (pid < 0) {
  52. perror("Error from first fork");
  53. return(EXIT_FAILURE);
  54. }
  55. // Terminate the parent.
  56. if (pid > 0) {
  57. return(EXIT_SUCCESS);
  58. }
  59. // This is the child. Become the session leader.
  60. if (setsid() < 0) {
  61. perror("Error from setsid");
  62. return(EXIT_FAILURE);
  63. }
  64. // Fork again.
  65. pid = fork();
  66. if (pid < 0) {
  67. perror("Error from second fork");
  68. return(EXIT_FAILURE);
  69. }
  70. // Terminate the parent.
  71. if (pid > 0) {
  72. return(EXIT_SUCCESS);
  73. }
  74. // Set default file permissions. This call always succeeds.
  75. umask(0);
  76. // Disassociate the process from the default directory of the
  77. // grandparent.
  78. if (chdir("/") != 0) {
  79. perror("Error from chdir");
  80. return(EXIT_FAILURE);
  81. }
  82. // Initialize the set of signals to wait for.
  83. if (sigemptyset(&signalSet) != 0) {
  84. perror("Error from sigemptyset");
  85. return(EXIT_FAILURE);
  86. }
  87. if ((sigaddset(&signalSet, SIGTSTP) != 0) ||
  88. (sigaddset(&signalSet, SIGCONT) != 0) ||
  89. (sigaddset(&signalSet, SIGHUP) != 0) ||
  90. (sigaddset(&signalSet, SIGTERM) != 0)) {
  91. perror("Error from sigaddset");
  92. return(EXIT_FAILURE);
  93. }
  94. // Block the signals.
  95. if (sigprocmask(SIG_BLOCK, &signalSet, NULL) != 0) {
  96. perror("Error from sigprocmask");
  97. return(EXIT_FAILURE);
  98. }
  99. // Close all open file descriptors.
  100. for (int fd = 2; fd >= 0; fd--) {
  101. if (close(fd) != 0) {
  102. // There is no controlling terminal to send any message to.
  103. return(EXIT_FAILURE);
  104. }
  105. }
  106. // Connect standard I/O to the null device.
  107. int fd;
  108. // stdin.
  109. fd = open("/dev/null", O_RDONLY);
  110. if (fd < 0) {
  111. return(EXIT_FAILURE);
  112. }
  113. // stdout.
  114. fd = open("/dev/null", O_WRONLY);
  115. if (fd < 0) {
  116. return(EXIT_FAILURE);
  117. }
  118. // stderr.
  119. fd = open("/dev/null", O_WRONLY);
  120. if (fd < 0) {
  121. return(EXIT_FAILURE);
  122. }
  123. // Start the thread to process messages.
  124. std::thread messageThread(&Service::processMessages, this);
  125. // Run the service.
  126. int status;
  127. status = run();
  128. // Send a Stop message so that messageThread exits.
  129. pthread_kill(messageThread.native_handle(), SIGTERM);
  130. messageThread.join();
  131. return(status);
  132. }
  133. void Service::loadArguments(int argc, char *argv[]) {
  134. for (int i = 0; i < argc; i++) {
  135. cmdLineArgs.push_back(argv[i]);
  136. }
  137. }
  138. const std::vector<std::string> &Service::arguments() {
  139. return cmdLineArgs;
  140. }
  141. void Service::onStopCall(Callback *stopFunctor) {
  142. stopCallbacks.push_back(stopFunctor);
  143. }
  144. bool Service::receivedPause() {
  145. return (pauseReceived);
  146. }
  147. bool Service::receivedResume() {
  148. return (resumeReceived);
  149. }
  150. bool Service::receivedRestart() {
  151. return (restartReceived);
  152. }
  153. bool Service::receivedStop() {
  154. return (stopReceived);
  155. }
  156. void Service::clearReceivedPause() {
  157. pauseReceived = false;
  158. }
  159. void Service::clearReceivedResume() {
  160. resumeReceived = false;
  161. }
  162. void Service::clearReceivedRestart() {
  163. restartReceived = false;
  164. }
  165. void Service::clearReceivedStop() {
  166. stopReceived = false;
  167. }
  168. void Service::processMessages() {
  169. int sigNum;
  170. int status;
  171. while (true) {
  172. // Wait for a signal.
  173. status = sigwait(&signalSet, &sigNum);
  174. if (0 != status) {
  175. perror("Error from sigwait");
  176. // TODO: Implement recovery.
  177. ;
  178. }
  179. // Process the message.
  180. switch (sigNum) {
  181. case SIGTSTP:
  182. pauseReceived = true;
  183. break;
  184. case SIGCONT:
  185. resumeReceived = true;
  186. break;
  187. case SIGHUP:
  188. restartReceived = true;
  189. break;
  190. case SIGTERM:
  191. stopReceived = true;
  192. for (auto callback : stopCallbacks) {
  193. (*callback)();
  194. }
  195. // Exit.
  196. return;
  197. break;
  198. default:
  199. ;
  200. } // switch.
  201. } // while.
  202. }
  203. }