All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Service.cpp
Go to the documentation of this file.
1 /*
2  * Service.cpp
3  *
4  * This file is part of the HausmiSEP project
5  *
6  * Copyright (C) 2012, 2013 Marco Alvarado (malvcr@gmail.com)
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <HSEP/Service.h>
23 #include <HSEP/LoggerTool.h>
24 
25 #include <sys/types.h> // umask
26 #include <sys/stat.h> // umask
27 #include <unistd.h> // fork
28 #include <signal.h>
29 
30 namespace HSEP {
31 
33 
34  bool vResult = false;
35  string vLogFileStr("/var/log/"+aName+".log");
36 
37  aServiceLogPtr = new fstream(vLogFileStr.c_str(),fstream::out);
38 
39  string vMessage = "Service "+aName+"(";
40 
41  if (aServiceLogPtr->bad()) {
42  vMessage.append("can't open particular log file - ");
43  vMessage.append(to_string(aServiceLogPtr->flags()));
44  vMessage.append(")");
46  delete aServiceLogPtr;
47  aServiceLogPtr = nullptr;
48  }
49  else {
50  vResult = true;
51  }
52  return vResult;
53 
54  } // ServiceThread::prepare
55 
56 
58 
59  if (aServiceLogPtr) {
60  aServiceLogPtr->close();
61  delete aServiceLogPtr;
62  }
63 
64  string vMessage = "Service "+aName+"(finishing)";
66 
67  } // ServiceThread::dispose
68 
69  void ServiceThread::log(string pData) {
70 
71  ExclusiveScope vScope(&aMutex);
72  (*aServiceLogPtr) << pData << endl;
73 
74  } // ServiceThread::log
75 
77  string pName
78  ) : Thread("ServiceThread") {
79  aName = pName;
80  aServiceLogPtr = nullptr;
81  } // ServiceThread constructor
82 
84  } // ServiceThread destructor
85 
86  ServiceThread* Service::aThreadInstance = nullptr;
87 
89  string pName,
90  ServiceThreadFactory& pServiceThreadFactoryRef
91  ) {
92 
93  aName = pName;
94 
95  string vMessage = "Service "+pName+"(";
96  aPid = fork();
97 
98  if (0 > aPid) {
99  vMessage.append("main fork failed -");
100  vMessage.append(to_string(errno));
101  vMessage.append(")");
103  exit(EXIT_FAILURE);
104  }
105  else if (0 < aPid) {
106  // The forked process is already running, we can die
107  vMessage.append("child dispatched)");
109  exit(EXIT_SUCCESS);
110  }
111 
112  aSid = setsid();
113 
114  if (0 > aSid) {
115  vMessage.append("new session failed - ");
116  vMessage.append(to_string(errno));
117  vMessage.append(")");
119  exit(EXIT_FAILURE);
120  }
121 
122  if (0 > chdir("/")) {
123  vMessage.append("can't change to root directory - ");
124  vMessage.append(to_string(errno));
125  vMessage.append(")");
127  exit(EXIT_FAILURE);
128  }
129  umask(0);
130 
131  close(STDIN_FILENO);
132  close(STDOUT_FILENO);
133  close(STDERR_FILENO);
134 
135  aTerminate = false;
136 
137  // Take note. This thread is create within the forked instance.
138  // If the thread is created before the constructor, it will belong
139  // to the original process and will die with it, so the service won't
140  // have any functionality.
141  //
142  aThreadInstance = pServiceThreadFactoryRef.createPtr();;
143  aThreadInstance->dispatch();
144 
145  LoggerTool::send(LT_SYSTEMINFO,"main thread dispatched");
146 
147  } // Service constructor
148 
150 
151  string vMessage("Service "+aName+"(finished)");
153 
154  } // Service destructor
155 
156  void TerminateHandler(int pSignal) {
157 
158  if (SIGTERM == pSignal) {
159 
160  LoggerTool::send(LT_SYSTEMINFO,"Signal SIGTERM Received");
161 
162  //Service::aThreadInstance->log("SIGTERM Received");
163  Service::aThreadInstance->finish();
164  Service::aThreadInstance->join();
165 
166  delete Service::aThreadInstance;
167 
168  LoggerTool::send(LT_SYSTEMINFO,"Process thread Finished - Closing service");
169 
170  sleep(1);
171 
172  exit(EXIT_SUCCESS);
173  }
174 
175  } // TerminateHandler
176 
178  ExclusiveScope(&this->aTermMutex); // G++ can't locate the aTermMutex instance without the "this->"
179  return !aTerminate;
180  } // Service::_continue
181 
183 
184  int vResult = 0;
185 
186  struct sigaction vAction; // this is because there are two different sigactions,
187  // the struct and the function
188  struct sigaction vOldAction;
189  sigset_t vSignalSet;
190 
191  sigemptyset(&vSignalSet);
192  sigaddset(&vSignalSet,SIGTERM);
193 
194  vAction.sa_handler = TerminateHandler;
195  vAction.sa_mask = vSignalSet;
196 
197  if (sigaction(SIGTERM,&vAction,&vOldAction) < 0) {
198  string vMessage = "Service "+aName+"(terminate handler failed -";
199  vMessage.append(to_string(errno));
200  vMessage.append(")");
202  exit(EXIT_FAILURE);
203  }
204 
205  while (_continue()) {
206  sleep(1);
207  }
208 
209  sigaction(SIGTERM,&vOldAction,nullptr);
210 
211  return vResult;
212  }
213 
215  ExclusiveScope(&this->aTermMutex); // G++ can't locate the aTermMutex instance without the "this->"
216  aTerminate = true;
217  } // Service::finish
218 
219 } // HSEP namespace