Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / protocol / jingle_session_manager.cc
1 // Copyright (c) 2012 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/jingle_session_manager.h"
6
7 #include "base/bind.h"
8 #include "remoting/protocol/authenticator.h"
9 #include "remoting/protocol/content_description.h"
10 #include "remoting/protocol/jingle_messages.h"
11 #include "remoting/protocol/jingle_session.h"
12 #include "remoting/protocol/transport.h"
13 #include "remoting/signaling/iq_sender.h"
14 #include "remoting/signaling/signal_strategy.h"
15 #include "third_party/webrtc/base/socketaddress.h"
16 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
17
18 using buzz::QName;
19
20 namespace remoting {
21 namespace protocol {
22
23 JingleSessionManager::JingleSessionManager(
24     scoped_ptr<TransportFactory> transport_factory)
25     : transport_factory_(transport_factory.Pass()),
26       signal_strategy_(NULL),
27       listener_(NULL),
28       ready_(false) {
29 }
30
31 JingleSessionManager::~JingleSessionManager() {
32   Close();
33 }
34
35 void JingleSessionManager::Init(
36     SignalStrategy* signal_strategy,
37     SessionManager::Listener* listener) {
38   listener_ = listener;
39   signal_strategy_ = signal_strategy;
40   iq_sender_.reset(new IqSender(signal_strategy_));
41
42   signal_strategy_->AddListener(this);
43
44   OnSignalStrategyStateChange(signal_strategy_->GetState());
45 }
46
47 scoped_ptr<Session> JingleSessionManager::Connect(
48     const std::string& host_jid,
49     scoped_ptr<Authenticator> authenticator,
50     scoped_ptr<CandidateSessionConfig> config) {
51   // Notify |transport_factory_| that it may be used soon.
52   transport_factory_->PrepareTokens();
53
54   scoped_ptr<JingleSession> session(new JingleSession(this));
55   session->StartConnection(host_jid, authenticator.Pass(), config.Pass());
56   sessions_[session->session_id_] = session.get();
57   return session.Pass();
58 }
59
60 void JingleSessionManager::Close() {
61   DCHECK(CalledOnValidThread());
62
63   // Close() can be called only after all sessions are destroyed.
64   DCHECK(sessions_.empty());
65
66   listener_ = NULL;
67
68   if (signal_strategy_) {
69     signal_strategy_->RemoveListener(this);
70     signal_strategy_ = NULL;
71   }
72 }
73
74 void JingleSessionManager::set_authenticator_factory(
75     scoped_ptr<AuthenticatorFactory> authenticator_factory) {
76   DCHECK(CalledOnValidThread());
77   authenticator_factory_ = authenticator_factory.Pass();
78 }
79
80 void JingleSessionManager::OnSignalStrategyStateChange(
81     SignalStrategy::State state) {
82   if (state == SignalStrategy::CONNECTED && !ready_) {
83     ready_ = true;
84     listener_->OnSessionManagerReady();
85   }
86 }
87
88 bool JingleSessionManager::OnSignalStrategyIncomingStanza(
89     const buzz::XmlElement* stanza) {
90   if (!JingleMessage::IsJingleMessage(stanza))
91     return false;
92
93   JingleMessage message;
94   std::string error;
95   if (!message.ParseXml(stanza, &error)) {
96     SendReply(stanza, JingleMessageReply::BAD_REQUEST);
97     return true;
98   }
99
100   if (message.action == JingleMessage::SESSION_INITIATE) {
101     // Description must be present in session-initiate messages.
102     DCHECK(message.description.get());
103
104     SendReply(stanza, JingleMessageReply::NONE);
105
106     // Notify |transport_factory_| that it may be used soon.
107     transport_factory_->PrepareTokens();
108
109     scoped_ptr<Authenticator> authenticator =
110         authenticator_factory_->CreateAuthenticator(
111             signal_strategy_->GetLocalJid(), message.from,
112             message.description->authenticator_message());
113
114     JingleSession* session = new JingleSession(this);
115     session->InitializeIncomingConnection(message, authenticator.Pass());
116     sessions_[session->session_id_] = session;
117
118     IncomingSessionResponse response = SessionManager::DECLINE;
119     listener_->OnIncomingSession(session, &response);
120
121     if (response == SessionManager::ACCEPT) {
122       session->AcceptIncomingConnection(message);
123     } else {
124       ErrorCode error;
125       switch (response) {
126         case INCOMPATIBLE:
127           error = INCOMPATIBLE_PROTOCOL;
128           break;
129
130         case OVERLOAD:
131           error = HOST_OVERLOAD;
132           break;
133
134         case DECLINE:
135           error = SESSION_REJECTED;
136           break;
137
138         default:
139           NOTREACHED();
140           error = SESSION_REJECTED;
141       }
142
143       session->CloseInternal(error);
144       delete session;
145       DCHECK(sessions_.find(message.sid) == sessions_.end());
146     }
147
148     return true;
149   }
150
151   SessionsMap::iterator it = sessions_.find(message.sid);
152   if (it == sessions_.end()) {
153     SendReply(stanza, JingleMessageReply::INVALID_SID);
154     return true;
155   }
156
157   it->second->OnIncomingMessage(message, base::Bind(
158       &JingleSessionManager::SendReply, base::Unretained(this), stanza));
159   return true;
160 }
161
162 void JingleSessionManager::SendReply(const buzz::XmlElement* original_stanza,
163                                      JingleMessageReply::ErrorType error) {
164   signal_strategy_->SendStanza(
165       JingleMessageReply(error).ToXml(original_stanza));
166 }
167
168 void JingleSessionManager::SessionDestroyed(JingleSession* session) {
169   sessions_.erase(session->session_id_);
170 }
171
172 }  // namespace protocol
173 }  // namespace remoting