1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2010 - 2015, Göteborg Bit Factory.
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included
13 // in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 //
23 // http://www.opensource.org/licenses/mit-license.php
24 //
25 ////////////////////////////////////////////////////////////////////////////////
26
27 #include <cmake.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <syslog.h>
40 #include <string.h>
41 #include <assert.h>
42 #include <Server.h>
43 #include <TLSServer.h>
44 #include <Timer.h>
45 #include <text.h>
46
47 // Indicates that certain signals were caught.
48 bool _sighup = false;
49 bool _sigusr1 = false;
50 bool _sigusr2 = false;
51
52 ////////////////////////////////////////////////////////////////////////////////
signal_handler(int s)53 static void signal_handler (int s)
54 {
55 switch (s)
56 {
57 case SIGHUP: _sighup = true; break; // Graceful stop
58 case SIGUSR1: _sigusr1 = true; break; // Config reload
59 case SIGUSR2: _sigusr2 = true; break;
60 }
61 }
62
63 ////////////////////////////////////////////////////////////////////////////////
Server()64 Server::Server ()
65 : _log (NULL)
66 , _log_clients (false)
67 , _client_address ("")
68 , _client_port (0)
69 , _host ("::")
70 , _port ("12345")
71 , _pool_size (4)
72 , _queue_size (10)
73 , _daemon (false)
74 , _pid_file ("")
75 , _request_count (0)
76 , _limit (0) // Unlimited
77 , _ca_file ("")
78 , _cert_file ("")
79 , _key_file ("")
80 , _crl_file ("")
81 {
82 }
83
84 ////////////////////////////////////////////////////////////////////////////////
~Server()85 Server::~Server ()
86 {
87 }
88
89 ////////////////////////////////////////////////////////////////////////////////
setPort(const std::string & port)90 void Server::setPort (const std::string& port)
91 {
92 if (_log) _log->format ("Using port %s", port.c_str ());
93 _port = port;
94 }
95
96 ////////////////////////////////////////////////////////////////////////////////
setHost(const std::string & host)97 void Server::setHost (const std::string& host)
98 {
99 if (_log) _log->format ("Using address %s", host.c_str ());
100 _host = host;
101 }
102
103 ////////////////////////////////////////////////////////////////////////////////
setFamily(const std::string & family)104 void Server::setFamily (const std::string& family)
105 {
106 if (_log) _log->format ("Using family %s", family.c_str ());
107 _family = family;
108 }
109
110 ////////////////////////////////////////////////////////////////////////////////
setQueueSize(int size)111 void Server::setQueueSize (int size)
112 {
113 if (_log) _log->format ("Queue size %d requests", size);
114 _queue_size = size;
115 }
116
117 ////////////////////////////////////////////////////////////////////////////////
setPoolSize(int size)118 void Server::setPoolSize (int size)
119 {
120 if (_log) _log->format ("Thread Pool size %d", size);
121 _pool_size = size;
122 }
123
124 ////////////////////////////////////////////////////////////////////////////////
setDaemon()125 void Server::setDaemon ()
126 {
127 if (_log) _log->write ("Will run as daemon");
128 _daemon = true;
129 }
130
131 ////////////////////////////////////////////////////////////////////////////////
setPidFile(const std::string & file)132 void Server::setPidFile (const std::string& file)
133 {
134 if (_log) _log->write ("PID file " + file);
135 assert (file.length () > 0);
136 _pid_file = file;
137 }
138
139 ////////////////////////////////////////////////////////////////////////////////
setLimit(int max)140 void Server::setLimit (int max)
141 {
142 if (_log) _log->format ("Request size limit %d bytes", max);
143 assert (max >= 0);
144 _limit = max;
145 }
146
147 ////////////////////////////////////////////////////////////////////////////////
setCAFile(const std::string & file)148 void Server::setCAFile (const std::string& file)
149 {
150 if (_log) _log->format ("CA %s", file.c_str ());
151 _ca_file = file;
152 File cert (file);
153 if (! cert.readable ())
154 throw format ("CA Certificate not readable: '{1}'", file);
155 }
156
157 ////////////////////////////////////////////////////////////////////////////////
setCertFile(const std::string & file)158 void Server::setCertFile (const std::string& file)
159 {
160 if (_log) _log->format ("Certificate %s", file.c_str ());
161 _cert_file = file;
162 File cert (file);
163 if (! cert.readable ())
164 throw format ("Server Certificate not readable: '{1}'", file);
165 }
166
167 ////////////////////////////////////////////////////////////////////////////////
setKeyFile(const std::string & file)168 void Server::setKeyFile (const std::string& file)
169 {
170 if (_log) _log->format ("Private Key %s", file.c_str ());
171 _key_file = file;
172 File key (file);
173 if (! key.readable ())
174 throw format ("Server key not readable: '{1}'", file);
175 }
176
177 ////////////////////////////////////////////////////////////////////////////////
setCRLFile(const std::string & file)178 void Server::setCRLFile (const std::string& file)
179 {
180 if (_log) _log->format ("CRL %s", file.c_str ());
181 _crl_file = file;
182 File crl (file);
183 if (! crl.readable ())
184 throw format ("CRL Certificate not readable: '{1}'", file);
185 }
186
187 ////////////////////////////////////////////////////////////////////////////////
setLogClients(bool value)188 void Server::setLogClients (bool value)
189 {
190 if (_log) _log->format ("IP logging %s", (value ? "on" : "off"));
191 _log_clients = value;
192 }
193
194 ////////////////////////////////////////////////////////////////////////////////
setLog(Log * l)195 void Server::setLog (Log* l)
196 {
197 _log = l;
198 }
199
200 ////////////////////////////////////////////////////////////////////////////////
setConfig(Config * c)201 void Server::setConfig (Config* c)
202 {
203 _config = c;
204 }
205
206 ////////////////////////////////////////////////////////////////////////////////
beginServer()207 void Server::beginServer ()
208 {
209 if (_log) _log->write ("Server starting");
210
211 if (_daemon)
212 {
213 daemonize (); // Only the child returns.
214 writePidFile ();
215 }
216
217 signal (SIGHUP, signal_handler); // Graceful stop
218 signal (SIGUSR1, signal_handler); // Config reload
219 signal (SIGUSR2, signal_handler);
220
221 TLSServer server;
222 if (_config)
223 {
224 server.debug (_config->getInteger ("debug.tls"));
225
226 std::string ciphers = _config->get ("ciphers");
227 if (ciphers != "")
228 {
229 server.ciphers (ciphers);
230 if (_log) _log->format ("Using ciphers: %s", ciphers.c_str ());
231 }
232
233 std::string trust = _config->get ("trust");
234 if (trust == "allow all")
235 server.trust (TLSServer::allow_all);
236 else if (trust == "strict")
237 server.trust (TLSServer::strict);
238 else if (_log)
239 _log->format ("Invalid 'trust' setting value of '%s'", trust.c_str ());
240 }
241
242 server.init (_ca_file, // CA
243 _crl_file, // CRL
244 _cert_file, // Cert
245 _key_file); // Key
246 server.queue (_queue_size);
247 server.bind (_host, _port, _family);
248 server.listen ();
249
250 if (_log) _log->write ("Server ready");
251
252 _request_count = 0;
253 while (1)
254 {
255 try
256 {
257 TLSTransaction tx;
258 tx.trust (server.trust ());
259 server.accept (tx);
260
261 if (_sighup)
262 throw "SIGHUP shutdown.";
263
264 // Get client address and port, for logging.
265 if (_log_clients)
266 tx.getClient (_client_address, _client_port);
267
268 // Metrics.
269 HighResTimer timer;
270 timer.start ();
271
272 std::string input;
273 tx.recv (input);
274
275 // Handle the request.
276 ++_request_count;
277
278 // Call the derived class handler.
279 std::string output;
280 handler (input, output);
281 if (output.length ())
282 tx.send (output);
283
284 if (_log)
285 {
286 timer.stop ();
287 _log->format ("[%d] Serviced in %.6fs", _request_count, timer.total ());
288 }
289 }
290
291 catch (std::string& e) { if (_log) _log->write (std::string ("Error: ") + e); }
292 catch (char* e) { if (_log) _log->write (std::string ("Error: ") + e); }
293 catch (...) { if (_log) _log->write ("Error: Unknown exception"); }
294 }
295 }
296
297 ////////////////////////////////////////////////////////////////////////////////
298 // TODO To provide these data, a request count, a start time, and a cumulative
299 // utilization time must be tracked.
stats(int & requests,time_t & uptime,double & utilization)300 void Server::stats (int& requests, time_t& uptime, double& utilization)
301 {
302 requests = _request_count;
303 uptime = 0;
304 utilization = 0.0;
305 }
306
307 ////////////////////////////////////////////////////////////////////////////////
daemonize()308 void Server::daemonize ()
309 {
310 if (_log) _log->write ("Daemonizing");
311
312 /* TODO Load RUN_AS_USER from config.
313
314 // If run as root, switch to preferred user.
315 if (getuid () == 0 || geteuid () == 0 )
316 {
317 struct passwd *pw = getpwnam (RUN_AS_USER);
318 if (pw)
319 {
320 if (_log) _log->write ("setting user to " RUN_AS_USER);
321 setuid (pw->pw_uid);
322 }
323 }
324 */
325
326 // Fork off the parent process
327 pid_t pid = fork ();
328 if (pid < 0)
329 {
330 exit (EXIT_FAILURE);
331 }
332
333 // If we got a good PID, then we can exit the parent process.
334 if (pid > 0)
335 {
336 exit (EXIT_SUCCESS);
337 }
338
339 // Change the file mode mask
340 umask (0);
341
342 // Create a new SID for the child process
343 pid_t sid = setsid ();
344 if (sid < 0)
345 {
346 if (_log) _log->write ("setsid failed");
347 exit (EXIT_FAILURE);
348 }
349
350 // Change the current working directory
351 // Why is this important? To ensure that program is independent of $CWD?
352 if ((chdir ("/")) < 0)
353 {
354 if (_log) _log->write ("chdir failed");
355 exit (EXIT_FAILURE);
356 }
357
358 // Redirect standard files to /dev/null.
359 freopen ("/dev/null", "r", stdin);
360 freopen ("/dev/null", "w", stdout);
361 freopen ("/dev/null", "w", stderr);
362
363 if (_log) _log->write ("Daemonized");
364 }
365
366 ////////////////////////////////////////////////////////////////////////////////
writePidFile()367 void Server::writePidFile ()
368 {
369 pid_t pid = getpid ();
370
371 FILE* output = fopen (_pid_file.c_str (), "w");
372 if (output)
373 {
374 fprintf (output, "%d", pid);
375 fclose (output);
376 }
377 else
378 if (_log) _log->write ("Error: could not write PID to '" + _pid_file + "'.");
379 }
380
381 ////////////////////////////////////////////////////////////////////////////////
removePidFile()382 void Server::removePidFile ()
383 {
384 assert (_pid_file.length () > 0);
385 unlink (_pid_file.c_str ());
386 }
387
388 ////////////////////////////////////////////////////////////////////////////////
389