By moving the call to Load() up in SearchProvider::Start(), we are giving a chance...
[chromium-blink-merge.git] / net / tools / flip_server / flip_in_mem_edsm_server.cc
blob8ba150579eec7cc8de33d0f8763702750e6b0411
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 <sys/file.h>
8 #include <sys/stat.h>
10 #include <iostream>
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 "base/timer.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"
26 #include "net/tools/flip_server/split.h"
28 using std::cout;
29 using std::cerr;
31 // If true, then disables the nagle algorithm);
32 bool FLAGS_disable_nagle = true;
34 // The number of times that accept() will be called when the
35 // alarm goes off when the accept_using_alarm flag is set to true.
36 // If set to 0, accept() will be performed until the accept queue
37 // is completely drained and the accept() call returns an error);
38 int32 FLAGS_accepts_per_wake = 0;
40 // The size of the TCP accept backlog);
41 int32 FLAGS_accept_backlog_size = 1024;
43 // If set to false a single socket will be used. If set to true
44 // then a new socket will be created for each accept thread.
45 // Note that this only works with kernels that support
46 // SO_REUSEPORT);
47 bool FLAGS_reuseport = false;
49 // Flag to force spdy, even if NPN is not negotiated.
50 bool FLAGS_force_spdy = false;
52 // The amount of time the server delays before sending back the
53 // reply);
54 double FLAGS_server_think_time_in_s = 0;
56 net::FlipConfig g_proxy_config;
58 ////////////////////////////////////////////////////////////////////////////////
60 std::vector<std::string> &split(const std::string &s,
61 char delim,
62 std::vector<std::string> &elems) {
63 std::stringstream ss(s);
64 std::string item;
65 while(std::getline(ss, item, delim)) {
66 elems.push_back(item);
68 return elems;
71 std::vector<std::string> split(const std::string &s, char delim) {
72 std::vector<std::string> elems;
73 return split(s, delim, elems);
76 bool GotQuitFromStdin() {
77 // Make stdin nonblocking. Yes this is done each time. Oh well.
78 fcntl(0, F_SETFL, O_NONBLOCK);
79 char c;
80 std::string maybequit;
81 while (read(0, &c, 1) > 0) {
82 maybequit += c;
84 if (maybequit.size()) {
85 VLOG(1) << "scanning string: \"" << maybequit << "\"";
87 return (maybequit.size() > 1 &&
88 (maybequit.c_str()[0] == 'q' ||
89 maybequit.c_str()[0] == 'Q'));
92 const char* BoolToStr(bool b) {
93 if (b)
94 return "true";
95 return "false";
98 ////////////////////////////////////////////////////////////////////////////////
100 static bool wantExit = false;
101 static bool wantLogClose = false;
102 void SignalHandler(int signum)
104 switch(signum) {
105 case SIGTERM:
106 case SIGINT:
107 wantExit = true;
108 break;
109 case SIGHUP:
110 wantLogClose = true;
111 break;
115 static int OpenPidFile(const char *pidfile)
117 int fd;
118 struct stat pid_stat;
119 int ret;
121 fd = open(pidfile, O_RDWR | O_CREAT, 0600);
122 if (fd == -1) {
123 cerr << "Could not open pid file '" << pidfile << "' for reading.\n";
124 exit(1);
127 ret = flock(fd, LOCK_EX | LOCK_NB);
128 if (ret == -1) {
129 if (errno == EWOULDBLOCK) {
130 cerr << "Flip server is already running.\n";
131 } else {
132 cerr << "Error getting lock on pid file: " << strerror(errno) << "\n";
134 exit(1);
137 if (fstat(fd, &pid_stat) == -1) {
138 cerr << "Could not stat pid file '" << pidfile << "': " << strerror(errno)
139 << "\n";
141 if (pid_stat.st_size != 0) {
142 if (ftruncate(fd, pid_stat.st_size) == -1) {
143 cerr << "Could not truncate pid file '" << pidfile << "': "
144 << strerror(errno) << "\n";
148 char pid_str[8];
149 snprintf(pid_str, sizeof(pid_str), "%d", getpid());
150 int bytes = static_cast<int>(strlen(pid_str));
151 if (write(fd, pid_str, strlen(pid_str)) != bytes) {
152 cerr << "Could not write pid file: " << strerror(errno) << "\n";
153 close(fd);
154 exit(1);
157 return fd;
160 int main (int argc, char**argv)
162 unsigned int i = 0;
163 bool wait_for_iface = false;
164 int pidfile_fd;
166 signal(SIGPIPE, SIG_IGN);
167 signal(SIGTERM, SignalHandler);
168 signal(SIGINT, SignalHandler);
169 signal(SIGHUP, SignalHandler);
171 CommandLine::Init(argc, argv);
172 CommandLine cl(argc, argv);
174 if (cl.HasSwitch("help") || argc < 2) {
175 cout << argv[0] << " <options>\n";
176 cout << " Proxy options:\n";
177 cout << "\t--proxy<1..n>=\"<listen ip>,<listen port>,"
178 << "<ssl cert filename>,\n"
179 << "\t <ssl key filename>,<http server ip>,"
180 << "<http server port>,\n"
181 << "\t [https server ip],[https server port],"
182 << "<spdy only 0|1>\"\n";
183 cout << "\t * The https server ip and port may be left empty if they are"
184 << " the same as\n"
185 << "\t the http server fields.\n";
186 cout << "\t * spdy only prevents non-spdy https connections from being"
187 << " passed\n"
188 << "\t through the proxy listen ip:port.\n";
189 cout << "\t--forward-ip-header=<header name>\n";
190 cout << "\n Server options:\n";
191 cout << "\t--spdy-server=\"<listen ip>,<listen port>,[ssl cert filename],"
192 << "\n\t [ssl key filename]\"\n";
193 cout << "\t--http-server=\"<listen ip>,<listen port>,[ssl cert filename],"
194 << "\n\t [ssl key filename]\"\n";
195 cout << "\t * Leaving the ssl cert and key fields empty will disable ssl"
196 << " for the\n"
197 << "\t http and spdy flip servers\n";
198 cout << "\n Global options:\n";
199 cout << "\t--logdest=<file|system|both>\n";
200 cout << "\t--logfile=<logfile>\n";
201 cout << "\t--wait-for-iface\n";
202 cout << "\t * The flip server will block until the listen ip has been"
203 << " raised.\n";
204 cout << "\t--ssl-session-expiry=<seconds> (default is 300)\n";
205 cout << "\t--ssl-disable-compression\n";
206 cout << "\t--idle-timeout=<seconds> (default is 300)\n";
207 cout << "\t--pidfile=<filepath> (default /var/run/flip-server.pid)\n";
208 cout << "\t--help\n";
209 exit(0);
212 if (cl.HasSwitch("pidfile")) {
213 pidfile_fd = OpenPidFile(cl.GetSwitchValueASCII("pidfile").c_str());
214 } else {
215 pidfile_fd = OpenPidFile(PIDFILE);
218 net::OutputOrdering::set_server_think_time_in_s(FLAGS_server_think_time_in_s);
220 if (cl.HasSwitch("forward-ip-header")) {
221 net::SpdySM::set_forward_ip_header(
222 cl.GetSwitchValueASCII("forward-ip-header"));
223 net::StreamerSM::set_forward_ip_header(
224 cl.GetSwitchValueASCII("forward-ip-header"));
227 if (cl.HasSwitch("logdest")) {
228 std::string log_dest_value = cl.GetSwitchValueASCII("logdest");
229 if (log_dest_value.compare("file") == 0) {
230 g_proxy_config.log_destination_ = logging::LOG_ONLY_TO_FILE;
231 } else if (log_dest_value.compare("system") == 0) {
232 g_proxy_config.log_destination_ = logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG;
233 } else if (log_dest_value.compare("both") == 0) {
234 g_proxy_config.log_destination_ =
235 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG;
236 } else {
237 LOG(FATAL) << "Invalid logging destination value: " << log_dest_value;
239 } else {
240 g_proxy_config.log_destination_ = logging::LOG_NONE;
243 if (cl.HasSwitch("logfile")) {
244 g_proxy_config.log_filename_ = cl.GetSwitchValueASCII("logfile");
245 if (g_proxy_config.log_destination_ == logging::LOG_NONE) {
246 g_proxy_config.log_destination_ = logging::LOG_ONLY_TO_FILE;
248 } else if (g_proxy_config.log_destination_ == logging::LOG_ONLY_TO_FILE ||
249 g_proxy_config.log_destination_ ==
250 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
251 LOG(FATAL) << "Logging destination requires a log file to be specified.";
254 if (cl.HasSwitch("wait-for-iface")) {
255 wait_for_iface = true;
258 if (cl.HasSwitch("ssl-session-expiry")) {
259 std::string session_expiry = cl.GetSwitchValueASCII("ssl-session-expiry");
260 g_proxy_config.ssl_session_expiry_ = atoi(session_expiry.c_str());
263 if (cl.HasSwitch("ssl-disable-compression")) {
264 g_proxy_config.ssl_disable_compression_ = true;
267 if (cl.HasSwitch("idle-timeout")) {
268 g_proxy_config.idle_socket_timeout_s_ =
269 atoi(cl.GetSwitchValueASCII("idle-timeout").c_str());
272 if (cl.HasSwitch("force_spdy"))
273 net::SMConnection::set_force_spdy(true);
275 InitLogging(g_proxy_config.log_filename_.c_str(),
276 g_proxy_config.log_destination_,
277 logging::DONT_LOCK_LOG_FILE,
278 logging::APPEND_TO_OLD_LOG_FILE,
279 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
281 LOG(INFO) << "Flip SPDY proxy started with configuration:";
282 LOG(INFO) << "Logging destination : " << g_proxy_config.log_destination_;
283 LOG(INFO) << "Log file : " << g_proxy_config.log_filename_;
284 LOG(INFO) << "Forward IP Header : "
285 << (net::SpdySM::forward_ip_header().length() ?
286 net::SpdySM::forward_ip_header() : "<disabled>");
287 LOG(INFO) << "Wait for interfaces : " << (wait_for_iface?"true":"false");
288 LOG(INFO) << "Accept backlog size : " << FLAGS_accept_backlog_size;
289 LOG(INFO) << "Accepts per wake : " << FLAGS_accepts_per_wake;
290 LOG(INFO) << "Disable nagle : "
291 << (FLAGS_disable_nagle?"true":"false");
292 LOG(INFO) << "Reuseport : "
293 << (FLAGS_reuseport?"true":"false");
294 LOG(INFO) << "Force SPDY : "
295 << (FLAGS_force_spdy?"true":"false");
296 LOG(INFO) << "SSL session expiry : "
297 << g_proxy_config.ssl_session_expiry_;
298 LOG(INFO) << "SSL disable compression : "
299 << g_proxy_config.ssl_disable_compression_;
300 LOG(INFO) << "Connection idle timeout : "
301 << g_proxy_config.idle_socket_timeout_s_;
303 // Proxy Acceptors
304 while (true) {
305 i += 1;
306 std::stringstream name;
307 name << "proxy" << i;
308 if (!cl.HasSwitch(name.str())) {
309 break;
311 std::string value = cl.GetSwitchValueASCII(name.str());
312 std::vector<std::string> valueArgs = split(value, ',');
313 CHECK_EQ((unsigned int)9, valueArgs.size());
314 int spdy_only = atoi(valueArgs[8].c_str());
315 // If wait_for_iface is enabled, then this call will block
316 // indefinitely until the interface is raised.
317 g_proxy_config.AddAcceptor(net::FLIP_HANDLER_PROXY,
318 valueArgs[0], valueArgs[1],
319 valueArgs[2], valueArgs[3],
320 valueArgs[4], valueArgs[5],
321 valueArgs[6], valueArgs[7],
322 spdy_only,
323 FLAGS_accept_backlog_size,
324 FLAGS_disable_nagle,
325 FLAGS_accepts_per_wake,
326 FLAGS_reuseport,
327 wait_for_iface,
328 NULL);
331 // Spdy Server Acceptor
332 net::MemoryCache spdy_memory_cache;
333 if (cl.HasSwitch("spdy-server")) {
334 spdy_memory_cache.AddFiles();
335 std::string value = cl.GetSwitchValueASCII("spdy-server");
336 std::vector<std::string> valueArgs = split(value, ',');
337 while (valueArgs.size() < 4)
338 valueArgs.push_back("");
339 g_proxy_config.AddAcceptor(net::FLIP_HANDLER_SPDY_SERVER,
340 valueArgs[0], valueArgs[1],
341 valueArgs[2], valueArgs[3],
342 "", "", "", "",
344 FLAGS_accept_backlog_size,
345 FLAGS_disable_nagle,
346 FLAGS_accepts_per_wake,
347 FLAGS_reuseport,
348 wait_for_iface,
349 &spdy_memory_cache);
352 // Spdy Server Acceptor
353 net::MemoryCache http_memory_cache;
354 if (cl.HasSwitch("http-server")) {
355 http_memory_cache.AddFiles();
356 std::string value = cl.GetSwitchValueASCII("http-server");
357 std::vector<std::string> valueArgs = split(value, ',');
358 while (valueArgs.size() < 4)
359 valueArgs.push_back("");
360 g_proxy_config.AddAcceptor(net::FLIP_HANDLER_HTTP_SERVER,
361 valueArgs[0], valueArgs[1],
362 valueArgs[2], valueArgs[3],
363 "", "", "", "",
365 FLAGS_accept_backlog_size,
366 FLAGS_disable_nagle,
367 FLAGS_accepts_per_wake,
368 FLAGS_reuseport,
369 wait_for_iface,
370 &http_memory_cache);
373 std::vector<net::SMAcceptorThread*> sm_worker_threads_;
375 for (i = 0; i < g_proxy_config.acceptors_.size(); i++) {
376 net::FlipAcceptor *acceptor = g_proxy_config.acceptors_[i];
378 sm_worker_threads_.push_back(
379 new net::SMAcceptorThread(acceptor,
380 (net::MemoryCache *)acceptor->memory_cache_));
381 // Note that spdy_memory_cache is not threadsafe, it is merely
382 // thread compatible. Thus, if ever we are to spawn multiple threads,
383 // we either must make the MemoryCache threadsafe, or use
384 // a separate MemoryCache for each thread.
386 // The latter is what is currently being done as we spawn
387 // a separate thread for each http and spdy server acceptor.
389 sm_worker_threads_.back()->InitWorker();
390 sm_worker_threads_.back()->Start();
393 while (!wantExit) {
394 // Close logfile when HUP signal is received. Logging system will
395 // automatically reopen on next log message.
396 if ( wantLogClose ) {
397 wantLogClose = false;
398 VLOG(1) << "HUP received, reopening log file.";
399 logging::CloseLogFile();
401 if (GotQuitFromStdin()) {
402 for (unsigned int i = 0; i < sm_worker_threads_.size(); ++i) {
403 sm_worker_threads_[i]->Quit();
405 for (unsigned int i = 0; i < sm_worker_threads_.size(); ++i) {
406 sm_worker_threads_[i]->Join();
408 break;
410 usleep(1000*10); // 10 ms
413 unlink(PIDFILE);
414 close(pidfile_fd);
415 return 0;