Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / tools / android / forwarder2 / daemon.cc
1 // Copyright (c) 2012 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.
4
5 #include "tools/android/forwarder2/daemon.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <signal.h>
10 #include <sys/file.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <sys/wait.h>
14 #include <unistd.h>
15
16 #include <cstdlib>
17 #include <cstring>
18 #include <string>
19
20 #include "base/basictypes.h"
21 #include "base/files/file_path.h"
22 #include "base/files/file_util.h"
23 #include "base/logging.h"
24 #include "base/memory/scoped_ptr.h"
25 #include "base/posix/eintr_wrapper.h"
26 #include "base/safe_strerror_posix.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/stringprintf.h"
29 #include "tools/android/forwarder2/common.h"
30 #include "tools/android/forwarder2/socket.h"
31
32 namespace forwarder2 {
33 namespace {
34
35 const int kBufferSize = 256;
36
37 // Timeout constant used for polling when connecting to the daemon's Unix Domain
38 // Socket and also when waiting for its death when it is killed.
39 const int kNumTries = 100;
40 const int kIdleTimeMSec = 20;
41
42 void InitLoggingForDaemon(const std::string& log_file) {
43   logging::LoggingSettings settings;
44   settings.logging_dest =
45       log_file.empty() ?
46       logging::LOG_TO_SYSTEM_DEBUG_LOG : logging::LOG_TO_FILE;
47   settings.log_file = log_file.c_str();
48   settings.lock_log = logging::DONT_LOCK_LOG_FILE;
49   CHECK(logging::InitLogging(settings));
50 }
51
52 bool RunServerAcceptLoop(const std::string& welcome_message,
53                          Socket* server_socket,
54                          Daemon::ServerDelegate* server_delegate) {
55   bool failed = false;
56   for (;;) {
57     scoped_ptr<Socket> client_socket(new Socket());
58     if (!server_socket->Accept(client_socket.get())) {
59       if (server_socket->DidReceiveEvent())
60         break;
61       PError("Accept()");
62       failed = true;
63       break;
64     }
65     if (!client_socket->Write(welcome_message.c_str(),
66                               welcome_message.length() + 1)) {
67       PError("Write()");
68       failed = true;
69       continue;
70     }
71     server_delegate->OnClientConnected(client_socket.Pass());
72   }
73   return !failed;
74 }
75
76 void SigChildHandler(int signal_number) {
77   DCHECK_EQ(signal_number, SIGCHLD);
78   int status;
79   pid_t child_pid = waitpid(-1 /* any child */, &status, WNOHANG);
80   if (child_pid < 0) {
81     PError("waitpid");
82     return;
83   }
84   if (child_pid == 0)
85     return;
86   if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
87     return;
88   // Avoid using StringAppendF() since it's unsafe in a signal handler due to
89   // its use of LOG().
90   FixedSizeStringBuilder<256> string_builder;
91   string_builder.Append("Daemon (pid=%d) died unexpectedly with ", child_pid);
92   if (WIFEXITED(status))
93     string_builder.Append("status %d.", WEXITSTATUS(status));
94   else if (WIFSIGNALED(status))
95     string_builder.Append("signal %d.", WTERMSIG(status));
96   else
97     string_builder.Append("unknown reason.");
98   SIGNAL_SAFE_LOG(ERROR, string_builder.buffer());
99 }
100
101 scoped_ptr<Socket> ConnectToUnixDomainSocket(
102     const std::string& socket_name,
103     int tries_count,
104     int idle_time_msec,
105     const std::string& expected_welcome_message) {
106   for (int i = 0; i < tries_count; ++i) {
107     scoped_ptr<Socket> socket(new Socket());
108     if (!socket->ConnectUnix(socket_name)) {
109       if (idle_time_msec)
110         usleep(idle_time_msec * 1000);
111       continue;
112     }
113     char buf[kBufferSize];
114     DCHECK(expected_welcome_message.length() + 1 <= sizeof(buf));
115     memset(buf, 0, sizeof(buf));
116     if (socket->Read(buf, expected_welcome_message.length() + 1) < 0) {
117       perror("read");
118       continue;
119     }
120     if (expected_welcome_message != buf) {
121       LOG(ERROR) << "Unexpected message read from daemon: " << buf;
122       break;
123     }
124     return socket.Pass();
125   }
126   return scoped_ptr<Socket>();
127 }
128
129 }  // namespace
130
131 Daemon::Daemon(const std::string& log_file_path,
132                const std::string& identifier,
133                ClientDelegate* client_delegate,
134                ServerDelegate* server_delegate,
135                GetExitNotifierFDCallback get_exit_fd_callback)
136   : log_file_path_(log_file_path),
137     identifier_(identifier),
138     client_delegate_(client_delegate),
139     server_delegate_(server_delegate),
140     get_exit_fd_callback_(get_exit_fd_callback) {
141   DCHECK(client_delegate_);
142   DCHECK(server_delegate_);
143   DCHECK(get_exit_fd_callback_);
144 }
145
146 Daemon::~Daemon() {}
147
148 bool Daemon::SpawnIfNeeded() {
149   const int kSingleTry = 1;
150   const int kNoIdleTime = 0;
151   scoped_ptr<Socket> client_socket = ConnectToUnixDomainSocket(
152       identifier_, kSingleTry, kNoIdleTime, identifier_);
153   if (!client_socket) {
154     switch (fork()) {
155       case -1:
156         PError("fork()");
157         return false;
158       // Child.
159       case 0: {
160         if (setsid() < 0) {  // Detach the child process from its parent.
161           PError("setsid()");
162           exit(1);
163         }
164         InitLoggingForDaemon(log_file_path_);
165         CloseFD(STDIN_FILENO);
166         CloseFD(STDOUT_FILENO);
167         CloseFD(STDERR_FILENO);
168         const int null_fd = open("/dev/null", O_RDWR);
169         CHECK_EQ(null_fd, STDIN_FILENO);
170         CHECK_EQ(dup(null_fd), STDOUT_FILENO);
171         CHECK_EQ(dup(null_fd), STDERR_FILENO);
172         Socket command_socket;
173         if (!command_socket.BindUnix(identifier_)) {
174           scoped_ptr<Socket> client_socket = ConnectToUnixDomainSocket(
175               identifier_, kSingleTry, kNoIdleTime, identifier_);
176           if (client_socket.get()) {
177             // The daemon was spawned by a concurrent process.
178             exit(0);
179           }
180           PError("bind()");
181           exit(1);
182         }
183         server_delegate_->Init();
184         command_socket.AddEventFd(get_exit_fd_callback_());
185         return RunServerAcceptLoop(
186             identifier_, &command_socket, server_delegate_);
187       }
188       default:
189         break;
190     }
191   }
192   // Parent.
193   // Install the custom SIGCHLD handler.
194   sigset_t blocked_signals_set;
195   if (sigprocmask(0 /* first arg ignored */, NULL, &blocked_signals_set) < 0) {
196     PError("sigprocmask()");
197     return false;
198   }
199   struct sigaction old_action;
200   struct sigaction new_action;
201   memset(&new_action, 0, sizeof(new_action));
202   new_action.sa_handler = SigChildHandler;
203   new_action.sa_flags = SA_NOCLDSTOP;
204   sigemptyset(&new_action.sa_mask);
205   if (sigaction(SIGCHLD, &new_action, &old_action) < 0) {
206     PError("sigaction()");
207     return false;
208   }
209   // Connect to the daemon's Unix Domain Socket.
210   bool failed = false;
211   if (!client_socket) {
212     client_socket = ConnectToUnixDomainSocket(
213         identifier_, kNumTries, kIdleTimeMSec, identifier_);
214     if (!client_socket) {
215       LOG(ERROR) << "Could not connect to daemon's Unix Daemon socket";
216       failed = true;
217     }
218   }
219   if (!failed)
220     client_delegate_->OnDaemonReady(client_socket.get());
221   // Restore the previous signal action for SIGCHLD.
222   if (sigaction(SIGCHLD, &old_action, NULL) < 0) {
223     PError("sigaction");
224     failed = true;
225   }
226   return !failed;
227 }
228
229 bool Daemon::Kill() {
230   pid_t daemon_pid = Socket::GetUnixDomainSocketProcessOwner(identifier_);
231   if (daemon_pid < 0) {
232     LOG(ERROR) << "No forwarder daemon seems to be running";
233     return true;
234   }
235   if (kill(daemon_pid, SIGTERM) < 0) {
236     if (errno == ESRCH /* invalid PID */) {
237       // The daemon exited for some reason (e.g. kill by a process other than
238       // us) right before the call to kill() above.
239       LOG(ERROR) << "Could not kill daemon with PID " << daemon_pid;
240       return true;
241     }
242     PError("kill");
243     return false;
244   }
245   for (int i = 0; i < kNumTries; ++i) {
246     const pid_t previous_pid = daemon_pid;
247     daemon_pid = Socket::GetUnixDomainSocketProcessOwner(identifier_);
248     if (daemon_pid < 0)
249       return true;
250     // Since we are polling we might not see the 'daemon exited' event if
251     // another daemon was spawned during our idle period.
252     if (daemon_pid != previous_pid) {
253       LOG(WARNING) << "Daemon (pid=" << previous_pid
254                    << ") was successfully killed but a new daemon (pid="
255                    << daemon_pid << ") seems to be running now.";
256       return true;
257     }
258     usleep(kIdleTimeMSec * 1000);
259   }
260   LOG(ERROR) << "Timed out while killing daemon. "
261                 "It might still be tearing down.";
262   return false;
263 }
264
265 }  // namespace forwarder2