Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(429)

Side by Side Diff: remoting/protocol/pepper_session.cc

Issue 7778022: Chromoting protocol implementation based on P2P Transport API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: - Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "remoting/protocol/pepper_session.h"
6
7 #include "base/bind.h"
8 #include "base/rand_util.h"
9 #include "base/stl_util.h"
10 #include "base/string_number_conversions.h"
11 #include "remoting/base/constants.h"
12 #include "remoting/jingle_glue/iq_request.h"
13 #include "remoting/protocol/content_description.h"
14 #include "remoting/protocol/jingle_messages.h"
15 #include "remoting/protocol/pepper_session_manager.h"
16 #include "remoting/protocol/pepper_stream_channel.h"
17 #include "third_party/libjingle/source/talk/p2p/base/candidate.h"
18 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
19
20 using buzz::XmlElement;
21
22 namespace remoting {
23 namespace protocol {
24
25 namespace {
26 const int kTransportInfoSendDelayMs = 2;
Wez 2011/09/09 23:39:12 Why 2ms? If the issue is that there may be severa
Sergey Ulanov 2011/09/12 19:50:50 Yes, this is so that we send fewer transport-info
27 } // namespace
28
29 PepperSession::PepperSession(PepperSessionManager* session_manager)
30 : session_manager_(session_manager),
31 state_(INITIALIZING),
32 error_(ERROR_NO_ERROR) {
33 }
34
35 PepperSession::~PepperSession() {
36 control_channel_socket_.reset();
37 event_channel_socket_.reset();
38 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
39 session_manager_->SessionDestroyed(this);
40 }
41
42 PepperSession::Error PepperSession::error() {
43 return error_;
44 }
45
46 void PepperSession::SetStateChangeCallback(StateChangeCallback* callback) {
47 state_change_callback_.reset(callback);
48 }
49
50 void PepperSession::StartConnection(
51 const std::string& host_jid,
52 const std::string& host_public_key,
53 const std::string& client_token,
54 CandidateSessionConfig* config,
55 Session::StateChangeCallback* state_change_callback) {
56 host_jid_ = host_jid;
57 host_public_key_ = host_public_key;
58 initiator_token_ = client_token;
59 candidate_config_.reset(config);
60 state_change_callback_.reset(state_change_callback);
61
62 session_id_ = base::Int64ToString(base::RandGenerator(kint64max));
Wez 2011/09/09 23:39:12 Add a comment to explain why it's OK for our Id to
Sergey Ulanov 2011/09/12 19:50:50 Done.
63
64 JingleMessage message(host_jid_, JingleMessage::SESSION_INITIATE,
65 session_id_);
66 message.from = session_manager_->local_jid_;
67 message.description.reset(
68 new ContentDescription(candidate_config_->Clone(), initiator_token_, ""));
69 initiate_request_.reset(session_manager_->CreateIqRequest());
70 initiate_request_->set_callback(base::Bind(
71 &PepperSession::OnSessionInitiateResponse, base::Unretained(this)));
72 initiate_request_->SendIq(message.ToXml());
Wez 2011/09/09 23:39:12 Add a comment e.g. "Send the session-initiate stan
Sergey Ulanov 2011/09/12 19:50:50 Done.
73
74 SetState(CONNECTING);
75 }
76
77 void PepperSession::OnSessionInitiateResponse(
78 const buzz::XmlElement* response) {
79 const std::string& type = response->Attr(buzz::QName("", "type"));
80 if (type != "result") {
81 LOG(ERROR) << "Received error in response to session-initiate message: \""
82 << response->Str()
83 << "\" Terminating the session.";
84
85 // TODO(sergeyu): There may be different reasons for error
86 // here. Parse the response stanza to find failure reason.
87 OnError(ERROR_HOST_IS_OFFLINE);
88 }
89 }
90
91 void PepperSession::OnError(Error error) {
92 error_ = error;
93 CloseInternal(true);
94 }
95
96 void PepperSession::CreateStreamChannel(
97 const std::string& name,
98 const StreamChannelCallback& callback) {
99 DCHECK(!channels_[name]);
100
101 PepperStreamChannel* channel = new PepperStreamChannel(this, name, callback);
102 channels_[name] = channel;
103 channel->Connect(session_manager_->pp_instance_,
104 session_manager_->transport_config_, remote_cert_);
105 }
106
107 void PepperSession::CreateDatagramChannel(
108 const std::string& name,
109 const DatagramChannelCallback& callback) {
110 // TODO(sergeyu): Implement datagram channel support.
111 NOTREACHED();
112 }
113
114 net::Socket* PepperSession::control_channel() {
115 DCHECK(CalledOnValidThread());
116 return control_channel_socket_.get();
117 }
118
119 net::Socket* PepperSession::event_channel() {
120 DCHECK(CalledOnValidThread());
121 return event_channel_socket_.get();
122 }
123
124 const std::string& PepperSession::jid() {
125 DCHECK(CalledOnValidThread());
126 return host_jid_;
127 }
128
129 const CandidateSessionConfig* PepperSession::candidate_config() {
130 DCHECK(CalledOnValidThread());
131 return candidate_config_.get();
132 }
133
134 const SessionConfig* PepperSession::config() {
Wez 2011/09/09 23:39:12 Check CalledOnValidThread()?
Sergey Ulanov 2011/09/12 19:50:50 Done.
135 return config_.get();
136 }
137
138 void PepperSession::set_config(const SessionConfig* config) {
Wez 2011/09/09 23:39:12 Here too?
Sergey Ulanov 2011/09/12 19:50:50 Done.
139 // set_config() should never be called on the client.
140 NOTREACHED();
141 }
142
143 const std::string& PepperSession::initiator_token() {
144 DCHECK(CalledOnValidThread());
145 return initiator_token_;
146 }
147
148 void PepperSession::set_initiator_token(const std::string& initiator_token) {
149 DCHECK(CalledOnValidThread());
150 initiator_token_ = initiator_token;
151 }
152
153 const std::string& PepperSession::receiver_token() {
154 DCHECK(CalledOnValidThread());
155 return receiver_token_;
156 }
157
158 void PepperSession::set_receiver_token(const std::string& receiver_token) {
Wez 2011/09/09 23:39:12 And again?
Sergey Ulanov 2011/09/12 19:50:50 Done.
159 // set_receiver_token() should not be called on the client side.
160 NOTREACHED();
161 }
162
163 void PepperSession::set_shared_secret(const std::string& secret) {
164 DCHECK(CalledOnValidThread());
165 shared_secret_ = secret;
166 }
167
168 const std::string& PepperSession::shared_secret() {
169 DCHECK(CalledOnValidThread());
170 return shared_secret_;
171 }
172
173 void PepperSession::Close() {
174 DCHECK(CalledOnValidThread());
175
176 if (state_ == CONNECTING || state_ == CONNECTED ||
177 state_ == CONNECTED_CHANNELS) {
178 // Send session-terminate message.
179 JingleMessage message(host_jid_, JingleMessage::SESSION_TERMINATE,
180 session_id_);
181 scoped_ptr<IqRequest> terminate_request(
182 session_manager_->CreateIqRequest());
183 terminate_request->SendIq(message.ToXml());
184 }
185
186 CloseInternal(false);
187 }
188
189 void PepperSession::OnIncomingMessage(const JingleMessage& message,
190 JingleMessageReply* reply) {
191 DCHECK(CalledOnValidThread());
192
193 if (message.from != host_jid_) {
194 // Ignore messages received from a different Jid.
195 *reply = JingleMessageReply(JingleMessageReply::INVALID_SID);
Wez 2011/09/09 23:39:12 Can that ever happen?
Sergey Ulanov 2011/09/12 19:50:50 Yes if somebody guesses SID and tries to spoof ses
196 return;
197 }
198
199 switch (message.action) {
200 case JingleMessage::SESSION_ACCEPT:
201 OnAccept(message, reply);
202 break;
203
204 case JingleMessage::TRANSPORT_INFO:
205 ProcessTransportInfo(message);
206 break;
207
208 case JingleMessage::SESSION_REJECT:
209 OnReject(message, reply);
210 break;
211
212 case JingleMessage::SESSION_TERMINATE:
213 OnTerminate(message, reply);
214 break;
215
216 default:
217 *reply = JingleMessageReply(JingleMessageReply::UNEXPECTED_REQUEST);
218 }
219 }
220
221 void PepperSession::OnAccept(const JingleMessage& message,
222 JingleMessageReply* reply) {
223 if (state_ != CONNECTING) {
224 *reply = JingleMessageReply(JingleMessageReply::UNEXPECTED_REQUEST);
225 return;
226 }
227
228 if (!InitializeConfigFromDescription(message.description.get())) {
229 OnError(ERROR_INCOMPATIBLE_PROTOCOL);
230 return;
231 }
232
233 CreateChannels();
234 SetState(CONNECTED);
235
236 // In case there is transport information in the accept message.
237 ProcessTransportInfo(message);
238 }
239
240 void PepperSession::ProcessTransportInfo(const JingleMessage& message) {
241 for (std::list<cricket::Candidate>::const_iterator it =
242 message.candidates.begin();
243 it != message.candidates.end(); ++it) {
244 ChannelsMap::iterator channel = channels_.find(it->name());
245 if (channel == channels_.end()) {
246 LOG(WARNING) << "Received candidate for unknown channel " << it->name();
247 continue;
248 }
249 channel->second->AddRemoveCandidate(*it);
250 }
251 }
252
253 void PepperSession::OnReject(const JingleMessage& message,
254 JingleMessageReply* reply) {
255 if (state_ != CONNECTING) {
256 *reply = JingleMessageReply(JingleMessageReply::UNEXPECTED_REQUEST);
257 return;
258 }
259
260 // TODO(sergeyu): Pass exact rejection reason from reply and pass it
Wez 2011/09/09 23:39:12 nit: You mean "parse exact..."?
Sergey Ulanov 2011/09/12 19:50:50 Done.
261 // to OnError().
262 OnError(ERROR_SESSION_REJECTED);
263 }
264
265 void PepperSession::OnTerminate(const JingleMessage& message,
266 JingleMessageReply* reply) {
267 if (state_ == CONNECTING) {
268 // If we are not connected yet, then interpret terminate message
269 // as rejection.
270 OnError(ERROR_SESSION_REJECTED);
271 return;
272 }
273
274 CloseInternal(false);
275 }
276
277 bool PepperSession::InitializeConfigFromDescription(
278 const ContentDescription* description) {
279 DCHECK(description);
280
281 remote_cert_ = description->certificate();
282 if (remote_cert_.empty()) {
283 LOG(ERROR) << "session-accept does not specify certificate";
284 return false;
285 }
286
287 config_.reset(description->config()->GetFinalConfig());
288 if (!config_.get()) {
289 LOG(ERROR) << "session-accept does not specify configuration";
290 return false;
291 }
292 if (!candidate_config()->IsSupported(config_.get())) {
293 LOG(ERROR) << "session-accept specifies an invalid configuration";
294 return false;
295 }
296
297 return true;
298 }
299
300 void PepperSession::AddLocalCandidate(const cricket::Candidate& candidate) {
301 pending_candidates_.push_back(candidate);
302
303 if (!transport_infos_timer_.IsRunning()) {
304 // Delay sending the new candidates in case we get more candidates
305 // that we can send in one message.
306 transport_infos_timer_.Start(
307 FROM_HERE, base::TimeDelta::FromMilliseconds(kTransportInfoSendDelayMs),
308 this, &PepperSession::SendTransportInfo);
309 }
310 }
311
312 void PepperSession::OnDeleteChannel(PepperChannel* channel) {
313 ChannelsMap::iterator it = channels_.find(channel->name());
314 DCHECK_EQ(it->second, channel);
315 channels_.erase(it);
316 }
317
318 void PepperSession::SendTransportInfo() {
319 JingleMessage message(host_jid_, JingleMessage::TRANSPORT_INFO, session_id_);
320 message.candidates.swap(pending_candidates_);
321 scoped_ptr<IqRequest> request(session_manager_->CreateIqRequest());
322 request->SendIq(message.ToXml());
323 }
324
325 void PepperSession::CreateChannels() {
326 CreateStreamChannel(
327 kControlChannelName,
328 base::Bind(&PepperSession::OnChannelConnected,
329 base::Unretained(this), &control_channel_socket_));
330 CreateStreamChannel(
331 kEventChannelName,
332 base::Bind(&PepperSession::OnChannelConnected,
333 base::Unretained(this), &event_channel_socket_));
334 }
335
336 void PepperSession::OnChannelConnected(
337 scoped_ptr<net::Socket>* socket_container,
338 net::StreamSocket* socket) {
339 if (!socket) {
340 LOG(ERROR) << "Failed to connect control or events channel. "
341 << "Terminating connection";
342 OnError(ERROR_CHANNEL_CONNECTION_FAILURE);
343 return;
344 }
345
346 socket_container->reset(socket);
347
348 if (control_channel_socket_.get() && event_channel_socket_.get())
349 SetState(CONNECTED_CHANNELS);
350 }
351
352 void PepperSession::CloseInternal(bool failed) {
353 DCHECK(CalledOnValidThread());
354
355 if (state_ != FAILED && state_ != CLOSED) {
356 control_channel_socket_.reset();
357 event_channel_socket_.reset();
358
359 // Inform the StateChangeCallback, so calling code knows not to
360 // touch any channels. Needs to be done in the end because the
Wez 2011/09/09 23:39:12 nit: "... in the end ..."?
Sergey Ulanov 2011/09/12 19:50:50 Removed the comment.
361 // session may be deleted in response to this event.
362 if (failed)
363 SetState(FAILED);
364 else
365 SetState(CLOSED);
366 }
367 }
368
369 void PepperSession::SetState(State new_state) {
370 DCHECK(CalledOnValidThread());
371
372 if (new_state != state_) {
373 DCHECK_NE(state_, CLOSED);
374 DCHECK_NE(state_, FAILED);
375
376 state_ = new_state;
377 if (state_change_callback_.get())
378 state_change_callback_->Run(new_state);
379 }
380 }
381
382 } // namespace protocol
383 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698