1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 // Session Server
31 
32 #include "session/session_server.h"
33 
34 #include <memory>
35 #include <string>
36 
37 #include "base/logging.h"
38 #include "base/port.h"
39 #include "base/scheduler.h"
40 #include "engine/engine_factory.h"
41 #include "ipc/ipc.h"
42 #include "ipc/named_event.h"
43 #include "protocol/commands.pb.h"
44 #include "session/session_handler.h"
45 #include "session/session_usage_observer.h"
46 #include "usage_stats/usage_stats_uploader.h"
47 
48 namespace {
49 
50 #ifdef OS_WIN
51 // On Windows, multiple processes can create named pipe objects whose names are
52 // the same. To reduce the potential risk of DOS, we limit the maximum number
53 // of pipe instances to 1 here.
54 const int kNumConnections   = 1;
55 #else
56 const int kNumConnections   = 10;
57 #endif  // OS_WIN
58 
59 const int kTimeOut = 5000;  // 5000msec
60 const char kSessionName[] = "session";
61 const char kEventName[] = "session";
62 
63 }  // namespace
64 
65 namespace mozc {
66 
SessionServer()67 SessionServer::SessionServer()
68     : IPCServer(kSessionName, kNumConnections, kTimeOut),
69       usage_observer_(new session::SessionUsageObserver()),
70       session_handler_(new SessionHandler(
71       std::unique_ptr<Engine>(EngineFactory::Create()))) {
72   using usage_stats::UsageStatsUploader;
73   // start session watch dog timer
74   session_handler_->StartWatchDog();
75   session_handler_->AddObserver(usage_observer_.get());
76 
77   // start usage stats timer
78   // send usage stats within 6 min later
79   Scheduler::AddJob(Scheduler::JobSetting(
80       "UsageStatsTimer",
81       UsageStatsUploader::kDefaultScheduleInterval,
82       UsageStatsUploader::kDefaultScheduleMaxInterval,
83       UsageStatsUploader::kDefaultSchedulerDelay,
84       UsageStatsUploader::kDefaultSchedulerRandomDelay,
85       &UsageStatsUploader::Send,
86       nullptr));
87 
88   // Send a notification event to the UI.
89   NamedEventNotifier notifier(kEventName);
90   if (!notifier.Notify()) {
91     LOG(WARNING) << "NamedEvent " << kEventName << " is not found";
92   }
93 }
94 
95 SessionServer::~SessionServer() = default;
96 
Connected() const97 bool SessionServer::Connected() const {
98   return (session_handler_ &&
99           session_handler_->IsAvailable() &&
100           IPCServer::Connected());
101 }
102 
Process(const char * request,size_t request_size,char * response,size_t * response_size)103 bool SessionServer::Process(const char *request,
104                             size_t request_size,
105                             char *response,
106                             size_t *response_size) {
107   if (!session_handler_) {
108     LOG(WARNING) << "handler is not available";
109     return false;   // shutdown the server if handler doesn't exist
110   }
111 
112   commands::Command command;   // can define as a private member?
113   if (!command.mutable_input()->ParseFromArray(request, request_size)) {
114     LOG(WARNING) << "Invalid request";
115     *response_size = 0;
116     return true;
117   }
118 
119   if (!session_handler_->EvalCommand(&command)) {
120     LOG(WARNING) << "EvalCommand() returned false. Exiting the loop.";
121     *response_size = 0;
122     return false;
123   }
124 
125   string output;
126   if (!command.output().SerializeToString(&output)) {
127     LOG(WARNING) << "SerializeToString() failed";
128     *response_size = 0;
129     return true;
130   }
131 
132   // TODO(taku) automatically increase the buffer.
133   // Needs to fix IPCServer as well
134   if (*response_size < output.size()) {
135     LOG(WARNING) << "response size < output.size";
136     *response_size = 0;
137     return true;
138   }
139 
140   ::memcpy(response, output.data(), output.size());
141   *response_size = output.size();
142 
143   // debug message
144   VLOG(2) << command.DebugString();
145 
146   return true;
147 }
148 }  // namespace mozc
149