1 : // Copyright 2014 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/kasko/service_bridge.h"
16 :
17 : #include "base/logging.h"
18 : #include "base/process/process_handle.h"
19 : #include "base/strings/utf_string_conversions.h"
20 : #include "syzygy/common/com_utils.h"
21 : #include "syzygy/common/rpc/helpers.h"
22 : #include "syzygy/kasko/service.h"
23 :
24 : namespace kasko {
25 : namespace {
26 : ServiceBridge* g_service_bridge = NULL;
27 : } // namespace
28 : } // namespace kasko
29 :
30 : // RPC calls all come through this single free function. We use the singleton
31 : // g_service_bridge to forward the call to the running Service.
32 : boolean KaskoService_SendDiagnosticReport(handle_t IDL_handle,
33 : unsigned long exception_info_address,
34 : unsigned long thread_id,
35 : DumpType minidump_type,
36 : unsigned long protobuf_length,
37 : const signed char* protobuf,
38 : unsigned long crash_keys_size,
39 E : const CrashKey* crash_keys) {
40 E : DCHECK(kasko::g_service_bridge);
41 :
42 : base::ProcessId client_process_id =
43 E : ::common::rpc::GetClientProcessID(IDL_handle);
44 E : if (!client_process_id)
45 i : return false;
46 :
47 E : std::map<base::string16, base::string16> crash_keys_map;
48 E : for (unsigned long i = 0; i < crash_keys_size; ++i) {
49 E : if (!crash_keys[i].name || !crash_keys[i].value)
50 i : continue;
51 : crash_keys_map[base::UTF8ToUTF16(
52 : reinterpret_cast<const char*>(crash_keys[i].name))] =
53 E : base::UTF8ToUTF16(reinterpret_cast<const char*>(crash_keys[i].value));
54 E : }
55 :
56 E : kasko::MinidumpType internal_minidump_type = kasko::SMALL_DUMP_TYPE;
57 E : switch (minidump_type) {
58 : case SMALL_DUMP:
59 E : internal_minidump_type = kasko::SMALL_DUMP_TYPE;
60 E : break;
61 : case LARGER_DUMP:
62 E : internal_minidump_type = kasko::LARGER_DUMP_TYPE;
63 E : break;
64 : case FULL_DUMP:
65 i : internal_minidump_type = kasko::FULL_DUMP_TYPE;
66 i : break;
67 : default:
68 i : NOTREACHED();
69 : break;
70 : }
71 :
72 : kasko::g_service_bridge->service_->SendDiagnosticReport(
73 : client_process_id, exception_info_address, thread_id,
74 : internal_minidump_type, reinterpret_cast<const char*>(protobuf),
75 E : protobuf_length, crash_keys_map);
76 :
77 E : return true;
78 E : }
79 :
80 : namespace kasko {
81 :
82 : ServiceBridge::ServiceBridge(const base::string16& protocol,
83 : const base::string16& endpoint,
84 : scoped_ptr<Service> service)
85 : : protocol_(protocol),
86 : endpoint_(endpoint),
87 : service_(service.Pass()),
88 E : running_(false) {
89 : // It's a bad idea to have two instances stepping on each other's toes.
90 E : CHECK(!g_service_bridge);
91 :
92 E : DCHECK(!protocol_.empty());
93 E : DCHECK(!endpoint_.empty());
94 E : DCHECK(service_);
95 E : g_service_bridge = this;
96 E : }
97 :
98 E : ServiceBridge::~ServiceBridge() {
99 : // It's a bad idea to shut down without stopping the service. It's also a bad
100 : // idea to block unexpectedly in our destructor.
101 E : CHECK(!running_);
102 :
103 E : DCHECK_EQ(this, g_service_bridge);
104 E : g_service_bridge = NULL;
105 E : }
106 :
107 E : bool ServiceBridge::Run() {
108 E : if (running_) return true;
109 :
110 : RPC_STATUS status = ::RpcServerUseProtseqEp(
111 : common::rpc::AsRpcWstr(&protocol_[0]), RPC_C_LISTEN_MAX_CALLS_DEFAULT,
112 E : common::rpc::AsRpcWstr(&endpoint_[0]), NULL /* Security descriptor. */);
113 :
114 : // RPC_S_DUPLICATE_ENDPOINT seems to be possible if a previous instance has
115 : // already registered this protocol and endpoint. The end result is still that
116 : // the endpoint is properly configured for this protocol.
117 E : if (status != RPC_S_OK && status != RPC_S_DUPLICATE_ENDPOINT) {
118 E : LOG(ERROR) << "Failed to init RPC protocol: " << ::common::LogWe(status)
119 : << ".";
120 E : } else {
121 : scoped_ptr<common::rpc::ScopedRpcInterfaceRegistration>
122 : interface_registration(new common::rpc::ScopedRpcInterfaceRegistration(
123 E : KaskoService_Kasko_v1_0_s_ifspec));
124 :
125 E : if (interface_registration->status() == RPC_S_OK) {
126 : status = ::RpcServerListen(1, // Minimum number of handler threads.
127 E : RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
128 :
129 E : if (status != RPC_S_OK) {
130 i : LOG(ERROR) << "Failed to run RPC server: " << ::common::LogWe(status)
131 : << ".";
132 i : } else {
133 E : running_ = true;
134 E : interface_registration_ = interface_registration.Pass();
135 : }
136 : }
137 E : }
138 :
139 E : return running_;
140 E : }
141 :
142 E : void ServiceBridge::Stop() {
143 E : if (!running_) return;
144 :
145 : // This call prevents new requests from being accepted.
146 E : RPC_STATUS status = ::RpcMgmtStopServerListening(NULL);
147 E : if (status != RPC_S_OK) {
148 : // If this fails, we could end up servicing calls in a bad state.
149 i : LOG(FATAL) << "Failed to stop the RPC server: " << ::common::LogWe(status)
150 : << ".";
151 : }
152 :
153 : // This call will block until all active requests are completed.
154 E : status = ::RpcMgmtWaitServerListen();
155 E : if (status != RPC_S_OK) {
156 : // If this fails, we could end up servicing calls in a bad state.
157 i : LOG(FATAL) << "Failed to wait for RPC server shutdown: "
158 : << ::common::LogWe(status) << ".";
159 : }
160 :
161 E : interface_registration_.reset();
162 E : running_ = false;
163 E : }
164 :
165 : } // namespace kasko
|