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

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;
27 } // namespace
28
29 PepperSession::PepperSession(PepperSessionManager* session_manager)
30 : session_manager_(session_manager),
31 state_(INITIALIZING),
32 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 pp::Instance* PepperSession::pp_instance() {
43 return session_manager_->pp_instance();
44 }
45
46 PepperSession::Error PepperSession::error() {
47 return error_;
48 }
49
50 void PepperSession::SetStateChangeCallback(StateChangeCallback* callback) {
51 state_change_callback_.reset(callback);
52 }
53
54 void PepperSession::StartConnection(
55 const std::string& host_jid,
56 const std::string& host_public_key,
57 const std::string& client_token,
58 CandidateSessionConfig* config,
59 Session::StateChangeCallback* state_change_callback) {
60 host_jid_ = host_jid;
61 host_public_key_ = host_public_key;
62 initiator_token_ = client_token;
63 candidate_config_.reset(config);
64 state_change_callback_.reset(state_change_callback);
65
66 sid_ = base::Int64ToString(base::RandGenerator(kint64max));
67
68 JingleMessage message(host_jid_, JingleMessage::SESSION_INITIATE, sid_);
69 message.from = session_manager_->local_jid_;
70 message.description.reset(
71 new ContentDescription(candidate_config_->Clone(), initiator_token_, ""));
72 initiate_request_.reset(session_manager_->CreateIqRequest());
73 initiate_request_->set_callback(base::Bind(
74 &PepperSession::OnSessionInitiateResponse, base::Unretained(this)));
75 initiate_request_->SendIq(message.ToXml());
76
77 SetState(CONNECTING);
78 }
79
80 void PepperSession::OnSessionInitiateResponse(
81 const buzz::XmlElement* response) {
82 const std::string& type = response->Attr(buzz::QName("", "type"));
83 if (type != "result") {
84 LOG(ERROR) << "Received error in response to session-initate message: \""
Wez 2011/09/01 01:08:29 nit: initiate
Sergey Ulanov 2011/09/08 00:48:36 Done.
85 << response->Str()
Wez 2011/09/01 01:08:29 Are we happy there can be nothing in the response
Sergey Ulanov 2011/09/08 00:48:36 The error message may contain the original session
86 << "\" Terminating the session.";
87
88 // TODO(sergeyu): There may be different reasons for error
89 // here. Parse the response stanza to find falure reason.
Wez 2011/09/01 01:08:29 nit: failure
Sergey Ulanov 2011/09/08 00:48:36 Done.
90 OnError(HOST_IS_OFFLINE);
91 }
92 }
93
94 void PepperSession::OnError(Error error) {
95 error_ = error;
96 CloseInternal(true);
97 }
98
99 void PepperSession::CreateStreamChannel(
100 const std::string& name,
101 const StreamChannelCallback& callback) {
102 DCHECK(!channels_[name]);
103
104 PepperStreamChannel* channel = new PepperStreamChannel(this, name, callback);
105 channels_[name] = channel;
106 channel->Connect(session_manager_->transport_config_, remote_cert_);
107 }
108
109 void PepperSession::CreateDatagramChannel(
110 const std::string& name,
111 const DatagramChannelCallback& callback) {
112 // TODO(sergeyu): Implement datagram channel support.
113 NOTREACHED();
114 }
115
116 net::Socket* PepperSession::control_channel() {
117 DCHECK(CalledOnValidThread());
118 return control_channel_socket_.get();
119 }
120
121 net::Socket* PepperSession::event_channel() {
122 DCHECK(CalledOnValidThread());
123 return event_channel_socket_.get();
124 }
125
126 const std::string& PepperSession::jid() {
127 DCHECK(CalledOnValidThread());
128 return host_jid_;
129 }
130
131 const CandidateSessionConfig* PepperSession::candidate_config() {
132 DCHECK(CalledOnValidThread());
133 return candidate_config_.get();
134 }
135
136 const SessionConfig* PepperSession::config() {
137 return config_.get();
138 }
139
140 void PepperSession::set_config(const SessionConfig* config) {
141 // set_config() should never be called on the client.
142 NOTREACHED();
143 }
144
145 const std::string& PepperSession::initiator_token() {
146 DCHECK(CalledOnValidThread());
147 return initiator_token_;
148 }
149
150 void PepperSession::set_initiator_token(const std::string& initiator_token) {
151 DCHECK(CalledOnValidThread());
152 initiator_token_ = initiator_token;
153 }
154
155 const std::string& PepperSession::receiver_token() {
156 DCHECK(CalledOnValidThread());
157 return receiver_token_;
158 }
159
160 void PepperSession::set_receiver_token(const std::string& receiver_token) {
161 // set_receiver_token() should not be called on the client side.
162 NOTREACHED();
163 }
164
165 void PepperSession::set_shared_secret(const std::string& secret) {
166 DCHECK(CalledOnValidThread());
167 shared_secret_ = secret;
168 }
169
170 const std::string& PepperSession::shared_secret() {
171 DCHECK(CalledOnValidThread());
172 return shared_secret_;
173 }
174
175 void PepperSession::Close() {
176 DCHECK(CalledOnValidThread());
177
178 if (state_ == CONNECTING || state_ == CONNECTED ||
179 state_ == CONNECTED_CHANNELS) {
180 // Send session-terminate message.
181 JingleMessage message(host_jid_, JingleMessage::SESSION_TERMINATE, sid_);
182 scoped_ptr<IqRequest> terminate_request(
183 session_manager_->CreateIqRequest());
184 terminate_request->SendIq(message.ToXml());
185 }
186
187 CloseInternal(false);
188 }
189
190 void PepperSession::OnIncomingMessage(const JingleMessage& message,
191 JingleMessageReply* reply) {
192 DCHECK(CalledOnValidThread());
193
194 if (message.from != host_jid_) {
195 // Ignore messages received from a different Jid.
196 *reply = JingleMessageReply(JingleMessageReply::INVALID_SID);
197 return;
198 }
199
200 switch (message.action) {
201 case JingleMessage::SESSION_ACCEPT:
202 OnAccept(message, reply);
203 break;
204
205 case JingleMessage::TRANSPORT_INFO:
206 ProcessTransportInfo(message);
207 break;
208
209 case JingleMessage::SESSION_REJECT:
210 OnReject(message, reply);
211 break;
212
213 case JingleMessage::SESSION_TERMINATE:
214 OnTerminate(message, reply);
215 break;
216
217 default:
218 *reply = JingleMessageReply(JingleMessageReply::UNEXPECTED_REQUEST);
219 }
220 }
221
222 void PepperSession::OnAccept(const JingleMessage& message,
223 JingleMessageReply* reply) {
224 if (state_ != CONNECTING) {
225 *reply = JingleMessageReply(JingleMessageReply::UNEXPECTED_REQUEST);
226 return;
227 }
228
229 if (!InitializeConfigFromDescription(message.description.get())) {
230 OnError(INCOMPATIBLE_PROTOCOL);
231 return;
232 }
233
234 CreateChannels();
235 SetState(CONNECTED);
236
237 // In case there is transport information in the accept message.
238 ProcessTransportInfo(message);
239 }
240
241 void PepperSession::ProcessTransportInfo(const JingleMessage& message) {
242 for (std::list<cricket::Candidate>::const_iterator it =
243 message.candidates.begin();
244 it != message.candidates.end(); ++it) {
245 ChannelsMap::iterator channel = channels_.find(it->name());
246 if (channel == channels_.end()) {
247 LOG(WARNING) << "Received candidate for unknown channel " << it->name();
248 continue;
249 }
250 channel->second->AddRemoveCandidate(*it);
251 }
252 }
253
254 void PepperSession::OnReject(const JingleMessage& message,
255 JingleMessageReply* reply) {
256 if (state_ != CONNECTING) {
257 *reply = JingleMessageReply(JingleMessageReply::UNEXPECTED_REQUEST);
258 return;
259 }
260
261 // TODO(sergeyu): Pass exact rejection reason from reply and pass it
262 // to OnError().
263 OnError(SESSION_REJECTED);
264 }
265
266 void PepperSession::OnTerminate(const JingleMessage& message,
267 JingleMessageReply* reply) {
268 if (state_ == CONNECTING) {
269 // If we are not connected yet, then interpret terminate message
270 // as rejection.
271 OnError(SESSION_REJECTED);
272 return;
273 }
274
275 CloseInternal(false);
276 }
277
278 bool PepperSession::InitializeConfigFromDescription(
279 const ContentDescription* description) {
280 DCHECK(description);
281
282 remote_cert_ = description->certificate();
283 if (remote_cert_.empty()) {
284 LOG(ERROR) << "session-accept does not specify certificate";
285 return false;
286 }
287
288 config_.reset(description->config()->GetFinalConfig());
289 if (!config_.get()) {
290 LOG(ERROR) << "session-accept does not specify configuration";
291 return false;
292 }
293 if (!candidate_config()->IsSupported(config_.get())) {
294 LOG(ERROR) << "session-accept specifies an invalid configuration";
295 return false;
296 }
297
298 return true;
299 }
300
301 void PepperSession::AddLocalCandidate(const cricket::Candidate& candidate) {
302 pending_candidates_.push_back(candidate);
303
304 if (!transport_infos_timer_.IsRunning()) {
305 // Delay sending the new candidates in case we get more candidates
306 // that we can send in one message.
307 transport_infos_timer_.Start(
308 base::TimeDelta::FromMilliseconds(kTransportInfoSendDelayMs),
309 this, &PepperSession::SendTransportInfos);
310 }
311 }
312
313 void PepperSession::SendTransportInfos() {
314 JingleMessage message(host_jid_, JingleMessage::TRANSPORT_INFO, sid_);
315 message.candidates.swap(pending_candidates_);
316 scoped_ptr<IqRequest> request(session_manager_->CreateIqRequest());
317 request->SendIq(message.ToXml());
318 }
319
320 void PepperSession::OnDeleteChannel(PepperChannel* channel) {
321 ChannelsMap::iterator it = channels_.find(channel->name());
322 DCHECK_EQ(it->second, channel);
323 channels_.erase(it);
324 }
325
326 void PepperSession::CreateChannels() {
327 CreateStreamChannel(
328 kControlChannelName,
329 base::Bind(&PepperSession::OnChannelConnected,
330 base::Unretained(this), &control_channel_socket_));
331 CreateStreamChannel(
332 kEventChannelName,
333 base::Bind(&PepperSession::OnChannelConnected,
334 base::Unretained(this), &event_channel_socket_));
335 }
336
337 void PepperSession::OnChannelConnected(
338 scoped_ptr<net::Socket>* socket_container,
339 net::StreamSocket* socket) {
340 if (!socket) {
341 LOG(ERROR) << "Failed to connect control or events channel. "
342 << "Terminating connection";
343 OnError(CHANNEL_CONNECTION_FAILURE);
344 return;
345 }
346
347 socket_container->reset(socket);
348
349 if (control_channel_socket_.get() && event_channel_socket_.get())
350 SetState(CONNECTED_CHANNELS);
351 }
352
353 void PepperSession::CloseInternal(bool failed) {
354 DCHECK(CalledOnValidThread());
355
356 if (state_ != FAILED && state_ != CLOSED) {
357 control_channel_socket_.reset();
358 event_channel_socket_.reset();
359
360 // Inform the StateChangeCallback, so calling code knows not to
361 // touch any channels. Needs to be done in the end because the
362 // session may be deleted in response to this event.
363 if (failed)
364 SetState(FAILED);
365 else
366 SetState(CLOSED);
367 }
368 }
369
370 void PepperSession::SetState(State new_state) {
371 DCHECK(CalledOnValidThread());
372
373 if (new_state != state_) {
374 DCHECK_NE(state_, CLOSED);
375 DCHECK_NE(state_, FAILED);
376
377 state_ = new_state;
378 if (state_change_callback_.get())
379 state_change_callback_->Run(new_state);
380 }
381 }
382
383 } // namespace protocol
384 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698