Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / p2p / base / sessionmanager.cc
1 /*
2  * libjingle
3  * Copyright 2004--2005, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "talk/p2p/base/sessionmanager.h"
29
30 #include "talk/p2p/base/constants.h"
31 #include "talk/p2p/base/session.h"
32 #include "talk/p2p/base/sessionmessages.h"
33 #include "talk/xmpp/constants.h"
34 #include "talk/xmpp/jid.h"
35 #include "webrtc/base/common.h"
36 #include "webrtc/base/helpers.h"
37 #include "webrtc/base/logging.h"
38 #include "webrtc/base/scoped_ptr.h"
39 #include "webrtc/base/stringencode.h"
40
41 namespace cricket {
42
43 SessionManager::SessionManager(PortAllocator *allocator,
44                                rtc::Thread *worker) {
45   allocator_ = allocator;
46   signaling_thread_ = rtc::Thread::Current();
47   if (worker == NULL) {
48     worker_thread_ = rtc::Thread::Current();
49   } else {
50     worker_thread_ = worker;
51   }
52   timeout_ = 50;
53 }
54
55 SessionManager::~SessionManager() {
56   // Note: Session::Terminate occurs asynchronously, so it's too late to
57   // delete them now.  They better be all gone.
58   ASSERT(session_map_.empty());
59   // TerminateAll();
60   SignalDestroyed();
61 }
62
63 void SessionManager::AddClient(const std::string& content_type,
64                                SessionClient* client) {
65   ASSERT(client_map_.find(content_type) == client_map_.end());
66   client_map_[content_type] = client;
67 }
68
69 void SessionManager::RemoveClient(const std::string& content_type) {
70   ClientMap::iterator iter = client_map_.find(content_type);
71   ASSERT(iter != client_map_.end());
72   client_map_.erase(iter);
73 }
74
75 SessionClient* SessionManager::GetClient(const std::string& content_type) {
76   ClientMap::iterator iter = client_map_.find(content_type);
77   return (iter != client_map_.end()) ? iter->second : NULL;
78 }
79
80 Session* SessionManager::CreateSession(const std::string& local_name,
81                                        const std::string& content_type) {
82   std::string id;
83   return CreateSession(id, local_name, content_type);
84 }
85
86 Session* SessionManager::CreateSession(const std::string& id,
87                                        const std::string& local_name,
88                                        const std::string& content_type) {
89   std::string sid =
90       id.empty() ? rtc::ToString(rtc::CreateRandomId64()) : id;
91   return CreateSession(local_name, local_name, sid, content_type, false);
92 }
93
94 Session* SessionManager::CreateSession(
95     const std::string& local_name, const std::string& initiator_name,
96     const std::string& sid, const std::string& content_type,
97     bool received_initiate) {
98   SessionClient* client = GetClient(content_type);
99   ASSERT(client != NULL);
100
101   Session* session = new Session(this, local_name, initiator_name,
102                                  sid, content_type, client);
103   session->SetIdentity(transport_desc_factory_.identity());
104   session_map_[session->id()] = session;
105   session->SignalRequestSignaling.connect(
106       this, &SessionManager::OnRequestSignaling);
107   session->SignalOutgoingMessage.connect(
108       this, &SessionManager::OnOutgoingMessage);
109   session->SignalErrorMessage.connect(this, &SessionManager::OnErrorMessage);
110   SignalSessionCreate(session, received_initiate);
111   session->client()->OnSessionCreate(session, received_initiate);
112   return session;
113 }
114
115 void SessionManager::DestroySession(Session* session) {
116   if (session != NULL) {
117     SessionMap::iterator it = session_map_.find(session->id());
118     if (it != session_map_.end()) {
119       SignalSessionDestroy(session);
120       session->client()->OnSessionDestroy(session);
121       session_map_.erase(it);
122       delete session;
123     }
124   }
125 }
126
127 Session* SessionManager::GetSession(const std::string& sid) {
128   SessionMap::iterator it = session_map_.find(sid);
129   if (it != session_map_.end())
130     return it->second;
131   return NULL;
132 }
133
134 void SessionManager::TerminateAll() {
135   while (session_map_.begin() != session_map_.end()) {
136     Session* session = session_map_.begin()->second;
137     session->Terminate();
138   }
139 }
140
141 bool SessionManager::IsSessionMessage(const buzz::XmlElement* stanza) {
142   return cricket::IsSessionMessage(stanza);
143 }
144
145 Session* SessionManager::FindSession(const std::string& sid,
146                                      const std::string& remote_name) {
147   SessionMap::iterator iter = session_map_.find(sid);
148   if (iter == session_map_.end())
149     return NULL;
150
151   Session* session = iter->second;
152   if (buzz::Jid(remote_name) != buzz::Jid(session->remote_name()))
153     return NULL;
154
155   return session;
156 }
157
158 void SessionManager::OnIncomingMessage(const buzz::XmlElement* stanza) {
159   SessionMessage msg;
160   ParseError error;
161
162   if (!ParseSessionMessage(stanza, &msg, &error)) {
163     SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
164                      error.text, NULL);
165     return;
166   }
167
168   Session* session = FindSession(msg.sid, msg.from);
169   if (session) {
170     session->OnIncomingMessage(msg);
171     return;
172   }
173   if (msg.type != ACTION_SESSION_INITIATE) {
174     SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
175                      "unknown session", NULL);
176     return;
177   }
178
179   std::string content_type;
180   if (!ParseContentType(msg.protocol, msg.action_elem,
181                         &content_type, &error)) {
182     SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
183                      error.text, NULL);
184     return;
185   }
186
187   if (!GetClient(content_type)) {
188     SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
189                      "unknown content type: " + content_type, NULL);
190     return;
191   }
192
193   session = CreateSession(msg.to, msg.initiator, msg.sid,
194                           content_type, true);
195   session->OnIncomingMessage(msg);
196 }
197
198 void SessionManager::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
199     const buzz::XmlElement* response_stanza) {
200   if (orig_stanza == NULL || response_stanza == NULL) {
201     return;
202   }
203
204   SessionMessage msg;
205   ParseError error;
206   if (!ParseSessionMessage(orig_stanza, &msg, &error)) {
207     LOG(LS_WARNING) << "Error parsing incoming response: " << error.text
208                     << ":" << orig_stanza;
209     return;
210   }
211
212   Session* session = FindSession(msg.sid, msg.to);
213   if (!session) {
214     // Also try the QN_FROM in the response stanza, in case we sent the request
215     // to a bare JID but got the response from a full JID.
216     std::string ack_from = response_stanza->Attr(buzz::QN_FROM);
217     session = FindSession(msg.sid, ack_from);
218   }
219   if (session) {
220     session->OnIncomingResponse(orig_stanza, response_stanza, msg);
221   }
222 }
223
224 void SessionManager::OnFailedSend(const buzz::XmlElement* orig_stanza,
225                                   const buzz::XmlElement* error_stanza) {
226   SessionMessage msg;
227   ParseError error;
228   if (!ParseSessionMessage(orig_stanza, &msg, &error)) {
229     return;  // TODO: log somewhere?
230   }
231
232   Session* session = FindSession(msg.sid, msg.to);
233   if (session) {
234     rtc::scoped_ptr<buzz::XmlElement> synthetic_error;
235     if (!error_stanza) {
236       // A failed send is semantically equivalent to an error response, so we
237       // can just turn the former into the latter.
238       synthetic_error.reset(
239         CreateErrorMessage(orig_stanza, buzz::QN_STANZA_ITEM_NOT_FOUND,
240                            "cancel", "Recipient did not respond", NULL));
241       error_stanza = synthetic_error.get();
242     }
243
244     session->OnFailedSend(orig_stanza, error_stanza);
245   }
246 }
247
248 void SessionManager::SendErrorMessage(const buzz::XmlElement* stanza,
249                                       const buzz::QName& name,
250                                       const std::string& type,
251                                       const std::string& text,
252                                       const buzz::XmlElement* extra_info) {
253   rtc::scoped_ptr<buzz::XmlElement> msg(
254       CreateErrorMessage(stanza, name, type, text, extra_info));
255   SignalOutgoingMessage(this, msg.get());
256 }
257
258 buzz::XmlElement* SessionManager::CreateErrorMessage(
259     const buzz::XmlElement* stanza,
260     const buzz::QName& name,
261     const std::string& type,
262     const std::string& text,
263     const buzz::XmlElement* extra_info) {
264   buzz::XmlElement* iq = new buzz::XmlElement(buzz::QN_IQ);
265   iq->SetAttr(buzz::QN_TO, stanza->Attr(buzz::QN_FROM));
266   iq->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
267   iq->SetAttr(buzz::QN_TYPE, "error");
268
269   CopyXmlChildren(stanza, iq);
270
271   buzz::XmlElement* error = new buzz::XmlElement(buzz::QN_ERROR);
272   error->SetAttr(buzz::QN_TYPE, type);
273   iq->AddElement(error);
274
275   // If the error name is not in the standard namespace, we have to first add
276   // some error from that namespace.
277   if (name.Namespace() != buzz::NS_STANZA) {
278      error->AddElement(
279          new buzz::XmlElement(buzz::QN_STANZA_UNDEFINED_CONDITION));
280   }
281   error->AddElement(new buzz::XmlElement(name));
282
283   if (extra_info)
284     error->AddElement(new buzz::XmlElement(*extra_info));
285
286   if (text.size() > 0) {
287     // It's okay to always use English here.  This text is for debugging
288     // purposes only.
289     buzz::XmlElement* text_elem = new buzz::XmlElement(buzz::QN_STANZA_TEXT);
290     text_elem->SetAttr(buzz::QN_XML_LANG, "en");
291     text_elem->SetBodyText(text);
292     error->AddElement(text_elem);
293   }
294
295   // TODO: Should we include error codes as well for SIP compatibility?
296
297   return iq;
298 }
299
300 void SessionManager::OnOutgoingMessage(Session* session,
301                                        const buzz::XmlElement* stanza) {
302   SignalOutgoingMessage(this, stanza);
303 }
304
305 void SessionManager::OnErrorMessage(BaseSession* session,
306                                     const buzz::XmlElement* stanza,
307                                     const buzz::QName& name,
308                                     const std::string& type,
309                                     const std::string& text,
310                                     const buzz::XmlElement* extra_info) {
311   SendErrorMessage(stanza, name, type, text, extra_info);
312 }
313
314 void SessionManager::OnSignalingReady() {
315   for (SessionMap::iterator it = session_map_.begin();
316       it != session_map_.end();
317       ++it) {
318     it->second->OnSignalingReady();
319   }
320 }
321
322 void SessionManager::OnRequestSignaling(Session* session) {
323   SignalRequestSignaling();
324 }
325
326 }  // namespace cricket