Add more checks to investigate SupervisedUserPrefStore crash at startup.
[chromium-blink-merge.git] / net / tools / flip_server / flip_in_mem_edsm_server.cc
blob80c5e6c17284e7ab08a7a3558045809f93d1cc21
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <errno.h>
6 #include <signal.h>
7 #include <stdio.h>
8 #include <sys/file.h>
9 #include <sys/stat.h>
11 #include <string>
12 #include <vector>
14 #include "base/command_line.h"
15 #include "base/logging.h"
16 #include "base/synchronization/lock.h"
17 #include "net/tools/balsa/split.h"
18 #include "net/tools/flip_server/acceptor_thread.h"
19 #include "net/tools/flip_server/constants.h"
20 #include "net/tools/flip_server/flip_config.h"
21 #include "net/tools/flip_server/output_ordering.h"
22 #include "net/tools/flip_server/sm_connection.h"
23 #include "net/tools/flip_server/sm_interface.h"
24 #include "net/tools/flip_server/spdy_interface.h"
25 #include "net/tools/flip_server/streamer_interface.h"
27 // If true, then disables the nagle algorithm);
28 bool FLAGS_disable_nagle = true;
30 // The number of times that accept() will be called when the
31 // alarm goes off when the accept_using_alarm flag is set to true.
32 // If set to 0, accept() will be performed until the accept queue
33 // is completely drained and the accept() call returns an error);
34 int32 FLAGS_accepts_per_wake = 0;
36 // The size of the TCP accept backlog);
37 int32 FLAGS_accept_backlog_size = 1024;
39 // If set to false a single socket will be used. If set to true
40 // then a new socket will be created for each accept thread.
41 // Note that this only works with kernels that support
42 // SO_REUSEPORT);
43 bool FLAGS_reuseport = false;
45 // Flag to force spdy, even if NPN is not negotiated.
46 bool FLAGS_force_spdy = false;
48 // The amount of time the server delays before sending back the
49 // reply);
50 double FLAGS_server_think_time_in_s = 0;
52 net::FlipConfig g_proxy_config;
54 std::vector<std::string>& split(const std::string& s,
55 char delim,
56 std::vector<std::string>& elems) {
57 std::stringstream ss(s);
58 std::string item;
59 while (std::getline(ss, item, delim)) {
60 elems.push_back(item);
62 return elems;
65 std::vector<std::string> split(const std::string& s, char delim) {
66 std::vector<std::string> elems;
67 return split(s, delim, elems);
70 bool GotQuitFromStdin() {
71 // Make stdin nonblocking. Yes this is done each time. Oh well.
72 fcntl(0, F_SETFL, O_NONBLOCK);
73 char c;
74 std::string maybequit;
75 while (read(0, &c, 1) > 0) {
76 maybequit += c;
78 if (maybequit.size()) {
79 VLOG(1) << "scanning string: \"" << maybequit << "\"";
81 return (maybequit.size() > 1 &&
82 (maybequit.c_str()[0] == 'q' || maybequit.c_str()[0] == 'Q'));
85 const char* BoolToStr(bool b) {
86 if (b)
87 return "true";
88 return "false";
91 static bool wantExit = false;
92 static bool wantLogClose = false;
93 void SignalHandler(int signum) {
94 switch (signum) {
95 case SIGTERM:
96 case SIGINT:
97 wantExit = true;
98 break;
99 case SIGHUP:
100 wantLogClose = true;
101 break;
105 static int OpenPidFile(const char* pidfile) {
106 int fd;
107 struct stat pid_stat;
108 int ret;
110 fd = open(pidfile, O_RDWR | O_CREAT, 0600);
111 if (fd == -1) {
112 fprintf(stderr, "Could not open pid file '%s' for reading.\n", pidfile);
113 exit(1);
116 ret = flock(fd, LOCK_EX | LOCK_NB);
117 if (ret == -1) {
118 if (errno == EWOULDBLOCK) {
119 fprintf(stderr, "Flip server is already running.\n");
120 } else {
121 perror("Error getting lock on pid file");
123 exit(1);
126 if (fstat(fd, &pid_stat) == -1) {
127 fprintf(
128 stderr, "Could not stat pid file '%s': %s\n", pidfile, strerror(errno));
129 exit(1);
131 if (pid_stat.st_size != 0) {
132 if (ftruncate(fd, pid_stat.st_size) == -1) {
133 fprintf(stderr,
134 "Could not truncate pid file '%s': %s\n",
135 pidfile,
136 strerror(errno));
137 exit(1);
141 char pid_str[8];
142 snprintf(pid_str, sizeof(pid_str), "%d", getpid());
143 int bytes = static_cast<int>(strlen(pid_str));
144 if (write(fd, pid_str, strlen(pid_str)) != bytes) {
145 perror("Could not write pid file");
146 close(fd);
147 exit(1);
150 return fd;
153 int main(int argc, char** argv) {
154 unsigned int i = 0;
155 bool wait_for_iface = false;
156 int pidfile_fd;
158 signal(SIGPIPE, SIG_IGN);
159 signal(SIGTERM, SignalHandler);
160 signal(SIGINT, SignalHandler);
161 signal(SIGHUP, SignalHandler);
163 base::CommandLine::Init(argc, argv);
164 base::CommandLine cl(argc, argv);
166 if (cl.HasSwitch("help") || argc < 2) {
167 printf("%s <options>\n", argv[0]);
168 printf(" Proxy options:\n");
169 printf(
170 "\t--proxy<1..n>=\"<listen ip>,<listen port>,"
171 "<ssl cert filename>,\n"
172 "\t <ssl key filename>,<http server ip>,"
173 "<http server port>,\n"
174 "\t [https server ip],[https server port],"
175 "<spdy only 0|1>\"\n"
176 "\t * The https server ip and port may be left empty if they are"
177 " the same as\n"
178 "\t the http server fields.\n"
179 "\t * spdy only prevents non-spdy https connections from being"
180 " passed\n"
181 "\t through the proxy listen ip:port.\n"
182 "\t--forward-ip-header=<header name>\n"
183 "\n Server options:\n"
184 "\t--spdy-server=\"<listen ip>,<listen port>,[ssl cert filename],"
185 "\n\t [ssl key filename]\"\n"
186 "\t--http-server=\"<listen ip>,<listen port>,[ssl cert filename],"
187 "\n\t [ssl key filename]\"\n"
188 "\t * Leaving the ssl cert and key fields empty will disable ssl"
189 " for the\n"
190 "\t http and spdy flip servers\n"
191 "\n Global options:\n"
192 "\t--logdest=<file|system|both>\n"
193 "\t--logfile=<logfile>\n"
194 "\t--wait-for-iface\n"
195 "\t * The flip server will block until the listen ip has been"
196 " raised.\n"
197 "\t--ssl-session-expiry=<seconds> (default is 300)\n"
198 "\t--ssl-disable-compression\n"
199 "\t--idle-timeout=<seconds> (default is 300)\n"
200 "\t--pidfile=<filepath> (default /var/run/flip-server.pid)\n"
201 "\t--help\n");
202 exit(0);
205 if (cl.HasSwitch("pidfile")) {
206 pidfile_fd = OpenPidFile(cl.GetSwitchValueASCII("pidfile").c_str());
207 } else {
208 pidfile_fd = OpenPidFile(PIDFILE);
211 net::OutputOrdering::set_server_think_time_in_s(FLAGS_server_think_time_in_s);
213 if (cl.HasSwitch("forward-ip-header")) {
214 net::SpdySM::set_forward_ip_header(
215 cl.GetSwitchValueASCII("forward-ip-header"));
216 net::StreamerSM::set_forward_ip_header(
217 cl.GetSwitchValueASCII("forward-ip-header"));
220 if (cl.HasSwitch("logdest")) {
221 std::string log_dest_value = cl.GetSwitchValueASCII("logdest");
222 if (log_dest_value.compare("file") == 0) {
223 g_proxy_config.log_destination_ = logging::LOG_TO_FILE;
224 } else if (log_dest_value.compare("system") == 0) {
225 g_proxy_config.log_destination_ = logging::LOG_TO_SYSTEM_DEBUG_LOG;
226 } else if (log_dest_value.compare("both") == 0) {
227 g_proxy_config.log_destination_ = logging::LOG_TO_ALL;
228 } else {
229 LOG(FATAL) << "Invalid logging destination value: " << log_dest_value;
231 } else {
232 g_proxy_config.log_destination_ = logging::LOG_NONE;
235 if (cl.HasSwitch("logfile")) {
236 g_proxy_config.log_filename_ = cl.GetSwitchValueASCII("logfile");
237 if (g_proxy_config.log_destination_ == logging::LOG_NONE) {
238 g_proxy_config.log_destination_ = logging::LOG_TO_FILE;
240 } else if ((g_proxy_config.log_destination_ & logging::LOG_TO_FILE) != 0) {
241 LOG(FATAL) << "Logging destination requires a log file to be specified.";
244 if (cl.HasSwitch("wait-for-iface")) {
245 wait_for_iface = true;
248 if (cl.HasSwitch("ssl-session-expiry")) {
249 std::string session_expiry = cl.GetSwitchValueASCII("ssl-session-expiry");
250 g_proxy_config.ssl_session_expiry_ = atoi(session_expiry.c_str());
253 if (cl.HasSwitch("ssl-disable-compression")) {
254 g_proxy_config.ssl_disable_compression_ = true;
257 if (cl.HasSwitch("idle-timeout")) {
258 g_proxy_config.idle_socket_timeout_s_ =
259 atoi(cl.GetSwitchValueASCII("idle-timeout").c_str());
262 if (cl.HasSwitch("force_spdy"))
263 net::SMConnection::set_force_spdy(true);
265 logging::LoggingSettings settings;
266 settings.logging_dest = g_proxy_config.log_destination_;
267 settings.log_file = g_proxy_config.log_filename_.c_str();
268 settings.lock_log = logging::DONT_LOCK_LOG_FILE;
269 logging::InitLogging(settings);
271 LOG(INFO) << "Flip SPDY proxy started with configuration:";
272 LOG(INFO) << "Logging destination : " << g_proxy_config.log_destination_;
273 LOG(INFO) << "Log file : " << g_proxy_config.log_filename_;
274 LOG(INFO) << "Forward IP Header : "
275 << (net::SpdySM::forward_ip_header().length()
276 ? net::SpdySM::forward_ip_header()
277 : "<disabled>");
278 LOG(INFO) << "Wait for interfaces : " << (wait_for_iface ? "true"
279 : "false");
280 LOG(INFO) << "Accept backlog size : " << FLAGS_accept_backlog_size;
281 LOG(INFO) << "Accepts per wake : " << FLAGS_accepts_per_wake;
282 LOG(INFO) << "Disable nagle : " << (FLAGS_disable_nagle ? "true"
283 : "false");
284 LOG(INFO) << "Reuseport : " << (FLAGS_reuseport ? "true"
285 : "false");
286 LOG(INFO) << "Force SPDY : " << (FLAGS_force_spdy ? "true"
287 : "false");
288 LOG(INFO) << "SSL session expiry : "
289 << g_proxy_config.ssl_session_expiry_;
290 LOG(INFO) << "SSL disable compression : "
291 << g_proxy_config.ssl_disable_compression_;
292 LOG(INFO) << "Connection idle timeout : "
293 << g_proxy_config.idle_socket_timeout_s_;
295 // Proxy Acceptors
296 while (true) {
297 i += 1;
298 std::stringstream name;
299 name << "proxy" << i;
300 if (!cl.HasSwitch(name.str())) {
301 break;
303 std::string value = cl.GetSwitchValueASCII(name.str());
304 std::vector<std::string> valueArgs = split(value, ',');
305 CHECK_EQ((unsigned int)9, valueArgs.size());
306 int spdy_only = atoi(valueArgs[8].c_str());
307 // If wait_for_iface is enabled, then this call will block
308 // indefinitely until the interface is raised.
309 g_proxy_config.AddAcceptor(net::FLIP_HANDLER_PROXY,
310 valueArgs[0],
311 valueArgs[1],
312 valueArgs[2],
313 valueArgs[3],
314 valueArgs[4],
315 valueArgs[5],
316 valueArgs[6],
317 valueArgs[7],
318 spdy_only,
319 FLAGS_accept_backlog_size,
320 FLAGS_disable_nagle,
321 FLAGS_accepts_per_wake,
322 FLAGS_reuseport,
323 wait_for_iface,
324 NULL);
327 // Spdy Server Acceptor
328 net::MemoryCache spdy_memory_cache;
329 if (cl.HasSwitch("spdy-server")) {
330 spdy_memory_cache.AddFiles();
331 std::string value = cl.GetSwitchValueASCII("spdy-server");
332 std::vector<std::string> valueArgs = split(value, ',');
333 while (valueArgs.size() < 4)
334 valueArgs.push_back(std::string());
335 g_proxy_config.AddAcceptor(net::FLIP_HANDLER_SPDY_SERVER,
336 valueArgs[0],
337 valueArgs[1],
338 valueArgs[2],
339 valueArgs[3],
340 std::string(),
341 std::string(),
342 std::string(),
343 std::string(),
345 FLAGS_accept_backlog_size,
346 FLAGS_disable_nagle,
347 FLAGS_accepts_per_wake,
348 FLAGS_reuseport,
349 wait_for_iface,
350 &spdy_memory_cache);
353 // Spdy Server Acceptor
354 net::MemoryCache http_memory_cache;
355 if (cl.HasSwitch("http-server")) {
356 http_memory_cache.AddFiles();
357 std::string value = cl.GetSwitchValueASCII("http-server");
358 std::vector<std::string> valueArgs = split(value, ',');
359 while (valueArgs.size() < 4)
360 valueArgs.push_back(std::string());
361 g_proxy_config.AddAcceptor(net::FLIP_HANDLER_HTTP_SERVER,
362 valueArgs[0],
363 valueArgs[1],
364 valueArgs[2],
365 valueArgs[3],
366 std::string(),
367 std::string(),
368 std::string(),
369 std::string(),
371 FLAGS_accept_backlog_size,
372 FLAGS_disable_nagle,
373 FLAGS_accepts_per_wake,
374 FLAGS_reuseport,
375 wait_for_iface,
376 &http_memory_cache);
379 std::vector<net::SMAcceptorThread*> sm_worker_threads_;
381 for (i = 0; i < g_proxy_config.acceptors_.size(); i++) {
382 net::FlipAcceptor* acceptor = g_proxy_config.acceptors_[i];
384 sm_worker_threads_.push_back(new net::SMAcceptorThread(
385 acceptor, (net::MemoryCache*)acceptor->memory_cache_));
386 // Note that spdy_memory_cache is not threadsafe, it is merely
387 // thread compatible. Thus, if ever we are to spawn multiple threads,
388 // we either must make the MemoryCache threadsafe, or use
389 // a separate MemoryCache for each thread.
391 // The latter is what is currently being done as we spawn
392 // a separate thread for each http and spdy server acceptor.
394 sm_worker_threads_.back()->InitWorker();
395 sm_worker_threads_.back()->Start();
398 while (!wantExit) {
399 // Close logfile when HUP signal is received. Logging system will
400 // automatically reopen on next log message.
401 if (wantLogClose) {
402 wantLogClose = false;
403 VLOG(1) << "HUP received, reopening log file.";
404 logging::CloseLogFile();
406 if (GotQuitFromStdin()) {
407 for (unsigned int i = 0; i < sm_worker_threads_.size(); ++i) {
408 sm_worker_threads_[i]->Quit();
410 for (unsigned int i = 0; i < sm_worker_threads_.size(); ++i) {
411 sm_worker_threads_[i]->Join();
413 break;
415 usleep(1000 * 10); // 10 ms
418 unlink(PIDFILE);
419 close(pidfile_fd);
420 return 0;