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