OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "mojo/public/cpp/bindings/lib/router.h" | |
6 | |
7 #include <string> | |
8 #include <utility> | |
9 | |
10 #include "mojo/public/cpp/bindings/message_validator.h" | |
11 #include "mojo/public/cpp/environment/logging.h" | |
12 | |
13 namespace mojo { | |
14 namespace internal { | |
15 | |
16 // ---------------------------------------------------------------------------- | |
17 | |
18 class ResponderThunk : public MessageReceiverWithStatus { | |
19 public: | |
20 explicit ResponderThunk(const SharedData<Router*>& router) | |
21 : router_(router), accept_was_invoked_(false) {} | |
22 ~ResponderThunk() override { | |
23 if (!accept_was_invoked_) { | |
24 // The Mojo application handled a message that was expecting a response | |
25 // but did not send a response. | |
26 Router* router = router_.value(); | |
27 if (router) { | |
28 // We close the pipe here as a way of signaling to the calling | |
29 // application that an error condition occurred. Without this the | |
30 // calling application would have no way of knowing it should stop | |
31 // waiting for a response. | |
32 router->CloseMessagePipe(); | |
33 } | |
34 } | |
35 } | |
36 | |
37 // MessageReceiver implementation: | |
38 bool Accept(Message* message) override { | |
39 accept_was_invoked_ = true; | |
40 MOJO_DCHECK(message->has_flag(kMessageIsResponse)); | |
41 | |
42 bool result = false; | |
43 | |
44 Router* router = router_.value(); | |
45 if (router) | |
46 result = router->Accept(message); | |
47 | |
48 return result; | |
49 } | |
50 | |
51 // MessageReceiverWithStatus implementation: | |
52 bool IsValid() override { | |
53 Router* router = router_.value(); | |
54 return router && !router->encountered_error() && router->is_valid(); | |
55 } | |
56 | |
57 private: | |
58 SharedData<Router*> router_; | |
59 bool accept_was_invoked_; | |
60 }; | |
61 | |
62 // ---------------------------------------------------------------------------- | |
63 | |
64 Router::HandleIncomingMessageThunk::HandleIncomingMessageThunk(Router* router) | |
65 : router_(router) {} | |
66 | |
67 Router::HandleIncomingMessageThunk::~HandleIncomingMessageThunk() {} | |
68 | |
69 bool Router::HandleIncomingMessageThunk::Accept(Message* message) { | |
70 return router_->HandleIncomingMessage(message); | |
71 } | |
72 | |
73 // ---------------------------------------------------------------------------- | |
74 | |
75 Router::Router(ScopedMessagePipeHandle message_pipe, | |
76 MessageValidatorList validators, | |
77 const MojoAsyncWaiter* waiter) | |
78 : thunk_(this), | |
79 validators_(std::move(validators)), | |
80 connector_(message_pipe.Pass(), waiter), | |
81 weak_self_(this), | |
82 incoming_receiver_(nullptr), | |
83 next_request_id_(0), | |
84 testing_mode_(false) { | |
85 // This receiver thunk redirects to Router::HandleIncomingMessage. | |
86 connector_.set_incoming_receiver(&thunk_); | |
87 } | |
88 | |
89 Router::~Router() { | |
90 weak_self_.set_value(nullptr); | |
91 | |
92 for (ResponderMap::const_iterator i = responders_.begin(); | |
93 i != responders_.end(); | |
94 ++i) { | |
95 delete i->second; | |
96 } | |
97 } | |
98 | |
99 bool Router::Accept(Message* message) { | |
100 MOJO_DCHECK(!message->has_flag(kMessageExpectsResponse)); | |
101 return connector_.Accept(message); | |
102 } | |
103 | |
104 bool Router::AcceptWithResponder(Message* message, MessageReceiver* responder) { | |
105 MOJO_DCHECK(message->has_flag(kMessageExpectsResponse)); | |
106 | |
107 // Reserve 0 in case we want it to convey special meaning in the future. | |
108 uint64_t request_id = next_request_id_++; | |
109 if (request_id == 0) | |
110 request_id = next_request_id_++; | |
111 | |
112 message->set_request_id(request_id); | |
113 if (!connector_.Accept(message)) | |
114 return false; | |
115 | |
116 // We assume ownership of |responder|. | |
117 responders_[request_id] = responder; | |
118 return true; | |
119 } | |
120 | |
121 void Router::EnableTestingMode() { | |
122 testing_mode_ = true; | |
123 connector_.set_enforce_errors_from_incoming_receiver(false); | |
124 } | |
125 | |
126 bool Router::HandleIncomingMessage(Message* message) { | |
127 std::string* err = nullptr; | |
128 #ifndef NDEBUG | |
129 std::string err2; | |
130 err = &err2; | |
131 #endif | |
132 | |
133 ValidationError result = RunValidatorsOnMessage(validators_, message, err); | |
134 if (result != ValidationError::NONE) | |
135 return false; | |
136 | |
137 if (message->has_flag(kMessageExpectsResponse)) { | |
138 if (incoming_receiver_) { | |
139 MessageReceiverWithStatus* responder = new ResponderThunk(weak_self_); | |
140 bool ok = incoming_receiver_->AcceptWithResponder(message, responder); | |
141 if (!ok) | |
142 delete responder; | |
143 return ok; | |
144 } | |
145 | |
146 // If we receive a request expecting a response when the client is not | |
147 // listening, then we have no choice but to tear down the pipe. | |
148 connector_.CloseMessagePipe(); | |
149 } else if (message->has_flag(kMessageIsResponse)) { | |
150 uint64_t request_id = message->request_id(); | |
151 ResponderMap::iterator it = responders_.find(request_id); | |
152 if (it == responders_.end()) { | |
153 MOJO_DCHECK(testing_mode_); | |
154 return false; | |
155 } | |
156 MessageReceiver* responder = it->second; | |
157 responders_.erase(it); | |
158 bool ok = responder->Accept(message); | |
159 delete responder; | |
160 return ok; | |
161 } else { | |
162 if (incoming_receiver_) | |
163 return incoming_receiver_->Accept(message); | |
164 // OK to drop message on the floor. | |
165 } | |
166 | |
167 return false; | |
168 } | |
169 | |
170 // ---------------------------------------------------------------------------- | |
171 | |
172 } // namespace internal | |
173 } // namespace mojo | |
OLD | NEW |