1 /*
2  * Copyright (C) 2012 FRAFOS GmbH
3  *
4  * Development sponsored by Sipwise GmbH.
5  *
6  * This file is part of SEMS, a free SIP media server.
7  *
8  * SEMS is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version. This program is released under
12  * the GPL with the additional exemption that compiling, linking,
13  * and/or using OpenSSL is allowed.
14  *
15  * For a license to use the SEMS software under conditions
16  * other than those described here, or to purchase support for this
17  * software, please contact iptel.org by e-mail at the following addresses:
18  *    info@iptel.org
19  *
20  * SEMS is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29 
30 #include "AmSipSubscriptionContainer.h"
31 #include "AmSession.h"
32 #include "AmEventDispatcher.h"
33 
34 #define SUBSCRIPTION_CONTAINER_EVQ_ID "_subscription_container_"
35 
_AmSipSubscriptionContainer()36 _AmSipSubscriptionContainer::_AmSipSubscriptionContainer()
37  : initialized(false)
38 {
39 }
40 
~_AmSipSubscriptionContainer()41 _AmSipSubscriptionContainer::~_AmSipSubscriptionContainer() {
42 }
43 
initialize()44 void _AmSipSubscriptionContainer::initialize() {
45   if (!initialized) {
46     // AmEventDispatcher::instance()->addEventQueue(SUBSCRIPTION_CONTAINER_EVQ_ID, this);
47     initialized = true;
48     DBG("Starting SIP Subscription client thread ([%p])\n", this);
49     start();
50   }
51 }
52 
53 string _AmSipSubscriptionContainer::
createSubscription(const AmSipSubscriptionInfo & info,const string & sess_link,unsigned int wanted_expires)54 createSubscription(const AmSipSubscriptionInfo& info,
55 		   const string& sess_link,
56 		   unsigned int wanted_expires)
57 {
58   initialize();
59   AmSipSubscriptionDialog* new_sub = new AmSipSubscriptionDialog(info,sess_link,
60 								 this);
61 
62   string handle = new_sub->getLocalTag();
63 
64   subscriptions_mut.lock();
65   subscriptions[handle] = new_sub;
66   AmEventDispatcher::instance()->addEventQueue(handle, this);
67   if (new_sub->subscribe(wanted_expires) < 0) {
68     DBG("subscribe failed - removing subscription\b");
69     AmEventDispatcher::instance()->delEventQueue(handle);
70     subscriptions.erase(handle);
71     subscriptions_mut.unlock();
72     delete new_sub;
73     return "";
74   }
75   subscriptions_mut.unlock();
76 
77   return handle;
78 }
79 
refreshSubscription(const string & sub_handle,unsigned int wanted_expires)80 bool _AmSipSubscriptionContainer::refreshSubscription(const string& sub_handle,
81 						      unsigned int wanted_expires) {
82   bool res = true;
83   subscriptions_mut.lock();
84   AmSipSubscriptionMapIter it = subscriptions.find(sub_handle);
85   if (it != subscriptions.end()) {
86     DBG("refreshing subscription '%s'\n", sub_handle.c_str());
87     res = it->second->subscribe(wanted_expires);
88   } else {
89     DBG("subscription '%s' already removed\n", sub_handle.c_str());
90     res = false;
91   }
92   subscriptions_mut.unlock();
93   return res;
94 }
95 
removeSubscription(const string & sub_handle)96 void _AmSipSubscriptionContainer::removeSubscription(const string& sub_handle) {
97   subscriptions_mut.lock();
98   AmSipSubscriptionMapIter it = subscriptions.find(sub_handle);
99   if (it != subscriptions.end()) {
100     DBG("unsubscribing subscription '%s'\n", sub_handle.c_str());
101     it->second->subscribe(0);
102   } else {
103     DBG("subscription '%s' already removed - ignoring\n", sub_handle.c_str());
104   }
105   subscriptions_mut.unlock();
106 }
107 
108 // AmEventProcessingThread
onEvent(AmEvent * event)109 void _AmSipSubscriptionContainer::onEvent(AmEvent* event)
110 {
111   AmSipRequestEvent* sip_req_ev = dynamic_cast<AmSipRequestEvent*>(event);
112   if (sip_req_ev) {
113     // DBG("got SIP request: '%s'\n", sip_req_ev->req.print().c_str());
114     DBG("got SIP request: %s %s\n",
115 	sip_req_ev->req.method.c_str(), sip_req_ev->req.r_uri.c_str());
116     string ltag = sip_req_ev->req.to_tag;
117 
118     subscriptions_mut.lock();
119     AmSipSubscriptionMapIter it = subscriptions.find(ltag);
120     if (it == subscriptions.end()) {
121       subscriptions_mut.unlock();
122       WARN("got SIP request '%s' for unknown subscription '%s'\n",
123 	   sip_req_ev->req.print().c_str(), ltag.c_str());
124       AmSipDialog::reply_error(sip_req_ev->req, 481, SIP_REPLY_NOT_EXIST);
125       return;
126     }
127     it->second->onRxRequest(sip_req_ev->req);
128     if (!(it->second->getUsages() > 0)) {
129       DBG("subscription '%s' terminated - removing\n", it->second->getDescription().c_str());
130       delete it->second;
131       subscriptions.erase(it);
132       AmEventDispatcher::instance()->delEventQueue(ltag);
133     }
134     subscriptions_mut.unlock();
135     return;
136   }
137 
138   AmSipReplyEvent* sip_reply_ev = dynamic_cast<AmSipReplyEvent*>(event);
139   if (sip_reply_ev) {
140     DBG("got SIP reply: '%s'\n", sip_reply_ev->reply.print().c_str());
141     string ltag = sip_reply_ev->reply.from_tag;
142 
143     subscriptions_mut.lock();
144     AmSipSubscriptionMapIter it = subscriptions.find(ltag);
145     if (it == subscriptions.end()) {
146       subscriptions_mut.unlock();
147       WARN("got SIP reply '%s' for unknown subscription '%s'\n",
148 	   sip_reply_ev->reply.print().c_str(), ltag.c_str());
149 
150       return;
151     }
152     it->second->onRxReply(sip_reply_ev->reply);
153     if (!(it->second->getUsages() > 0)) {
154       DBG("subscription '%s' terminated - removing\n", it->second->getDescription().c_str());
155       delete it->second;
156       subscriptions.erase(it);
157       AmEventDispatcher::instance()->delEventQueue(ltag);
158     }
159     subscriptions_mut.unlock();
160     return;
161   }
162 
163   SingleSubTimeoutEvent* to_ev = dynamic_cast<SingleSubTimeoutEvent*>(event);
164   if(to_ev) {
165     DBG("got timeout event: %s/%i/%p\n",
166 	to_ev->ltag.c_str(), to_ev->timer_id, to_ev->sub);
167 
168     string ltag = to_ev->ltag;
169 
170     subscriptions_mut.lock();
171     AmSipSubscriptionMapIter it = subscriptions.find(ltag);
172     if (it == subscriptions.end()) {
173       subscriptions_mut.unlock();
174       WARN("got timeout event '%i/%p' for unknown subscription '%s'\n",
175 	   to_ev->timer_id, to_ev->sub, ltag.c_str());
176 
177       return;
178     }
179     it->second->onTimeout(to_ev->timer_id, to_ev->sub);
180     if (!(it->second->getUsages() > 0)) {
181       DBG("subscription '%s' terminated - removing\n", it->second->getDescription().c_str());
182       delete it->second;
183       subscriptions.erase(it);
184       AmEventDispatcher::instance()->delEventQueue(ltag);
185     }
186     subscriptions_mut.unlock();
187     return;
188   }
189 }
190 
191 
192