1 /*
2  * Copyright (C) 2012 Frafos GmbH
3  *
4  * This file is part of SEMS, a free SIP media server.
5  *
6  * SEMS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version. This program is released under
10  * the GPL with the additional exemption that compiling, linking,
11  * and/or using OpenSSL is allowed.
12  *
13  * For a license to use the SEMS software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * SEMS is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 #ifndef _AmSipSubscription_h_
28 #define _AmSipSubscription_h_
29 
30 #include "AmSipMsg.h"
31 #include "AmBasicSipDialog.h"
32 #include "AmEvent.h"
33 #include "AmEventQueue.h"
34 #include "AmAppTimer.h"
35 
36 #include <map>
37 #include <list>
38 #include <memory>
39 using std::map;
40 using std::list;
41 
42 class AmBasicSipDialog;
43 class AmEventQueue;
44 class AmSipSubscription;
45 class SingleSubscription;
46 
47 struct SingleSubTimeoutEvent
48   : public AmEvent
49 {
50   string ltag;
51   int timer_id;
52   SingleSubscription* sub;
53 
SingleSubTimeoutEventSingleSubTimeoutEvent54   SingleSubTimeoutEvent(const string& ltag, int timer_id, SingleSubscription* sub)
55     : AmEvent(E_SIP_SUBSCRIPTION), ltag(ltag), timer_id(timer_id), sub(sub)
56   {}
57 };
58 
59 /**
60  * \brief Single SIP Subscription
61  *
62  * This class contain only one SIP suscription,
63  * identified by its event package name, id and role.
64  */
65 class SingleSubscription
66 {
67 public:
68   enum Role {
69     Subscriber=0,
70     Notifier
71   };
72 
73 private:
74   class SubscriptionTimer
75     : public DirectAppTimer
76   {
77     SingleSubscription* sub;
78     int timer_id;
79 
80   public:
SubscriptionTimer(SingleSubscription * sub,int timer_id)81     SubscriptionTimer(SingleSubscription* sub, int timer_id)
82       : sub(sub), timer_id(timer_id)
83     {}
84 
fire()85     void fire(){
86       sub->onTimer(timer_id);
87     }
88   };
89 
90   enum SubscriptionTimerId {
91     RFC6665_TIMER_N=0,
92     SUBSCRIPTION_EXPIRE
93   };
94 
95   // state
96   unsigned int sub_state;
97   int  pending_subscribe;
98   unsigned long  expires;
99 
100   // timers
101   SubscriptionTimer timer_n;
102   SubscriptionTimer timer_expires;
103 
104   AmSipSubscription* subs;
105 
106   void onTimer(int timer_id);
107 
108   AmBasicSipDialog* dlg();
109 
110   void requestFSM(const AmSipRequest& req);
111 
112   friend class SubscriptionTimer;
113 
114 public:
115   enum SubscriptionState {
116     SubState_init=0,
117     SubState_notify_wait,
118     SubState_pending,
119     SubState_active,
120     SubState_terminated
121   };
122 
123   // identifiers
124   string event;
125   string    id;
126   Role    role;
127 
128   SingleSubscription(AmSipSubscription* subs, Role role,
129 		     const string& event, const string& id);
130 
131   virtual ~SingleSubscription();
132 
133   bool onRequestIn(const AmSipRequest& req);
134   void onRequestSent(const AmSipRequest& req);
135   virtual void replyFSM(const AmSipRequest& req, const AmSipReply& reply);
136 
getState()137   unsigned int getState() { return sub_state; }
138   virtual void setState(unsigned int st);
139 
getExpires()140   unsigned long getExpires() { return expires; }
141   void setExpires(unsigned long exp);
142 
143   void terminate();
144   bool terminated();
145 
146   string to_str();
147 };
148 
149 /**
150  * \brief SIP Subscription collection
151  *
152  * This class contains all the suscriptions sharing
153  * the same dialog.
154  */
155 class AmSipSubscription
156 {
157 protected:
158   typedef list<SingleSubscription*> Subscriptions;
159   typedef map<unsigned int,Subscriptions::iterator> CSeqMap;
160 
161   AmBasicSipDialog* dlg;
162   AmEventQueue*    ev_q;
163   Subscriptions    subs;
164   CSeqMap  uas_cseq_map;
165   CSeqMap  uac_cseq_map;
166 
167   bool allow_subless_notify;
168 
169   SingleSubscription* makeSubscription(const AmSipRequest& req, bool uac);
170   Subscriptions::iterator createSubscription(const AmSipRequest& req, bool uac);
171   Subscriptions::iterator matchSubscription(const AmSipRequest& req, bool uac);
172   Subscriptions::iterator findSubscription(SingleSubscription::Role role,
173 					   const string& event, const string& id);
174   void removeSubFromUACCSeqMap(Subscriptions::iterator sub);
175   void removeSubFromUASCSeqMap(Subscriptions::iterator sub);
176 
177   virtual void removeSubscription(Subscriptions::iterator sub);
178 
179   virtual SingleSubscription* newSingleSubscription(SingleSubscription::Role role,
180 						    const string& event,
181 						    const string& id);
182 
183   friend class SingleSubscription;
184 
185 public:
186   AmSipSubscription(AmBasicSipDialog* dlg, AmEventQueue* ev_q);
187   virtual ~AmSipSubscription();
188 
allowUnsolicitedNotify(bool allow)189   virtual void allowUnsolicitedNotify(bool allow) {
190     allow_subless_notify = allow;
191   }
192 
193   /**
194    * Is there at least one active subscription?
195    */
196   bool isActive();
197 
198   /**
199    * Terminate all subscriptions
200    */
201   void terminate();
202 
203   /**
204    * Check if a subscription exists
205    */
206   bool subscriptionExists(SingleSubscription::Role role,
207 			  const string& event, const string& id);
208 
209   bool onRequestIn(const AmSipRequest& req);
210   void onRequestSent(const AmSipRequest& req);
211   bool onReplyIn(const AmSipRequest& req, const AmSipReply& reply);
212   void onReplySent(const AmSipRequest& req, const AmSipReply& reply);
213 
onNotify(const AmSipRequest & req,SingleSubscription * sub)214   virtual void onNotify(const AmSipRequest& req, SingleSubscription* sub) {}
onFailureReply(const AmSipReply & reply,SingleSubscription * sub)215   virtual void onFailureReply(const AmSipReply& reply, SingleSubscription* sub) {}
216   virtual void onTimeout(int timer_id, SingleSubscription* sub);
217 
218   virtual void debug();
219 };
220 
221 struct SIPSubscriptionEvent
222   : public AmEvent
223 {
224 
225   enum SubscriptionStatus {
226     SubscribeActive=0,
227     SubscribeFailed,
228     SubscribeTerminated,
229     SubscribePending,
230     SubscriptionTimeout
231   };
232 
233   string handle;
234   unsigned int code;
235   string reason;
236   SubscriptionStatus status;
237   unsigned int expires;
238   std::unique_ptr<AmMimeBody> notify_body;
239 
240   SIPSubscriptionEvent(SubscriptionStatus status, const string& handle,
241 		       unsigned int expires = 0,
242 		       unsigned int code=0, const string& reason="");
243 
244   const char* getStatusText();
245 };
246 
247 struct AmSipSubscriptionInfo
248 {
249   string domain;
250   string user;
251   string from_user;
252   string pwd;
253   string proxy;
254   string event;
255   string accept;
256   string id;
257 
AmSipSubscriptionInfoAmSipSubscriptionInfo258   AmSipSubscriptionInfo(const string& domain,
259 			const string& user,
260 			const string& from_user,
261 			const string& pwd,
262 			const string& proxy,
263 			const string& event)
264   : domain(domain),user(user),
265     from_user(from_user),pwd(pwd),proxy(proxy),
266     event(event)
267   { }
268 };
269 
270 class AmSipSubscriptionDialog
271   : public AmBasicSipDialog,
272     public AmBasicSipEventHandler,
273     public AmSipSubscription
274 {
275   string event;
276   string event_id;
277   string accept;
278   string sess_link;
279 
280 public:
281   AmSipSubscriptionDialog(const AmSipSubscriptionInfo& info,
282 			  const string& sess_link,
283 			  AmEventQueue* ev_q = NULL);
284 
285   int subscribe(int expires);
286 
287   string getDescription();
288 
289   /** AmSipSubscription interface */
290   void onNotify(const AmSipRequest& req, SingleSubscription* sub);
291   void onFailureReply(const AmSipReply& reply, SingleSubscription* sub);
292   void onTimeout(int timer_id, SingleSubscription* sub);
293 
294   /** AmBasicDialogEventHandler interface */
onSipRequest(const AmSipRequest & req)295   void onSipRequest(const AmSipRequest& req)
296   { AmSipSubscription::onRequestIn(req); }
297 
onRequestSent(const AmSipRequest & req)298   void onRequestSent(const AmSipRequest& req)
299   { AmSipSubscription::onRequestSent(req); }
300 
onSipReply(const AmSipRequest & req,const AmSipReply & reply,AmBasicSipDialog::Status old_status)301   void onSipReply(const AmSipRequest& req, const AmSipReply& reply,
302 		  AmBasicSipDialog::Status old_status)
303   { AmSipSubscription::onReplyIn(req,reply); }
304 
onReplySent(const AmSipRequest & req,const AmSipReply & reply)305   void onReplySent(const AmSipRequest& req, const AmSipReply& reply)
306   { AmSipSubscription::onReplySent(req,reply); }
307 };
308 
309 #endif
310