1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
|
/*
Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* @file
* Subscription (RFC 3265)
*/
#ifndef _SUBSCRIPTION_H
#define _SUBSCRIPTION_H
#include <queue>
#include <string>
#include "abstract_dialog.h"
/** Subscription role */
enum t_subscription_role {
SR_SUBSCRIBER, /**< Subscriber */
SR_NOTIFIER /**< Notifier */
};
/** Subscription state */
enum t_subscription_state {
SS_NULL, /**< Initial state */
SS_ESTABLISHED, /**< Subscription is in place */
SS_UNSUBSCRIBING, /**< A request to unsubscribe has been sent */
SS_UNSUBSCRIBED, /**< An outoging unsubscribe was successful. Waiting for the final NOTIFY. */
SS_TERMINATED, /**< Subscription ended */
};
/**
* Convert a subscription state to string.
* @param state [in] Subscription state.
* @return String representation of state.
*/
string t_subscription_state2str(t_subscription_state state);
/**
* RFC 3265
* Generic subscription state for subscribers and notifiers
* For each event type this class should be subclassed.
*/
class t_subscription {
protected:
t_subscription_role role;
t_subscription_state state;
/**
* When a subscriber subscription is terminated, this reason indicates
* the reason conveyed in the NOTIFY, if any.
*/
string reason_termination;
/**
* If the NOTIFY indicated that the subscriber may retry subscription at
* a later time, then resubscribe_after indicates the number of seconds to wait.
*/
unsigned long resubscribe_after;
/** Indicates if a re-subscribe may be done after a failure. */
bool may_resubscribe;
t_abstract_dialog *dialog; /**< Dialog owning the subscription */
string event_type;
string event_id;
/**
* User profile of user using the line
* This is a pointer to the user_config owned by a phone user.
* So this pointer should never be deleted.
*/
t_user *user_config;
bool pending; /**< Indicates if not active yet. */
/** @name Timers */
//@{
/**
* For a subscriber the subscription_timeout timer indicates when
* the subscription must be refreshed.
* For a notifier it indicates when the subscription expires.
*/
unsigned short id_subscription_timeout;
/**
* Indicates if a subscriber automatically refreshes the subscritption
* when the subscription timer expires. If not, then the subscription
* terminates at expiry.
*/
bool auto_refresh;
/** Subcription expiry for a SUBSCRIBE request */
unsigned long subscription_expiry;
/** Default duration for a subscription */
unsigned long default_duration;
//@}
/** Protect constructor from being used */
t_subscription() {};
/** Write event type and id to log file */
void log_event() const;
/**
* Remove a pending request. Pass one of the client request pointers.
* @param cr [in] Client request to remove.
*/
void remove_client_request(t_client_request **cr);
/** @name Create requests based on the event type */
//@{
/**
* Create a SUBSCRIBE request.
* Creating a SUBSCRIBE is for subscription refreshment/unsubscribe.
* @param expires [in] Expiry time in seconds.
*/
virtual t_request *create_subscribe(unsigned long expires) const;
/**
* Create a NOTIFY request.
* @param sub_state [in] Subscription state to be put in the Subscription-State header.
* @param reason [in] The reason parameter of the Subscription-State header.
*/
virtual t_request *create_notify(const string &sub_state,
const string &reason = "") const;
//@}
/**
* Send request.
* @param user_config [in] User profile of user sending the request.
* @param r [in] Request to send.
* @param tuid [in] Transaction user id.
*/
void send_request(t_user *user_config, t_request *r, t_tuid tuid) const;
/**
* Send response.
* @param user_config [in] User profile of user sending the response.
* @param r [in] Response to send.
* @param tuid [in] Transaction user id.
* @param tid [in] Transaction id.
*/
void send_response(t_user *user_config, t_response *r, t_tuid tuid, t_tid tid) const;
/**
* Start a subscription timer.
* @param timer [in] Type of subscription timer.
* @param duration [in] Duration of timer in ms
*/
void start_timer(t_subscribe_timer timer, long duration);
/**
* Stop a subscription timer.
* @param timer [in] Type of subscription timer.
*/
void stop_timer(t_subscribe_timer timer);
public:
/** Pending request */
t_client_request *req_out;
/**
* Queue of pending outgoing NOTIFY requests. A next NOTIFY
* will only be sent after the previous NOTIFY has been
* answered.
*/
queue<t_request *> queue_notify;
/**
* Constructor
* @param _dialog [in] Dialog owning this subscription. SUBSCRIBE and NOTIFY
* requests are sent within this dialog.
* @param _role [in] Role
* @param _event_type [in] Event type of the subscription.
*/
t_subscription(t_abstract_dialog *_dialog, t_subscription_role _role,
const string &_event_type);
/**
* Constructor
* @param _dialog [in] Dialog owning this subscription. SUBSCRIBE and NOTIFY
* requests are sent within this dialog.
* @param _role [in] Role
* @param _event_type [in] Event type of the subscription.
* @param _event_id [in] Event id.
*/
t_subscription(t_abstract_dialog *_dialog, t_subscription_role _role,
const string &_event_type, const string &_event_id);
/** Destructor */
virtual ~t_subscription();
/** @name Getters */
//@{
t_subscription_role get_role(void) const;
t_subscription_state get_state(void) const;
string get_reason_termination(void) const;
unsigned long get_resubscribe_after(void) const;
bool get_may_resubscribe(void) const;
string get_event_type(void) const;
string get_event_id(void) const;
unsigned long get_expiry(void) const;
//@}
/** @name Receive requests */
//@{
/**
* Reveive SUBSCRIBE request
* @param r [in] Received request.
* @param tuid [in] Transaction user id.
* @param tid [in] Transaction id.
* @return The return value indicates if processing is finished.
* This way a subclass can first call the parent class method.
* If the parent indicates that process is finished, then the child
* does not need to further process.
* Note that recv_subscribe returns false if the SUBSCRIBE is valid. The
* subscription timer will be started, but no response is sent. The subclass
* MUST further handle the SUBSCRIBE, i.e. send a response and a NOTIFY.
*/
virtual bool recv_subscribe(t_request *r, t_tuid tuid, t_tid tid);
/**
* Receive NOTIFY request.
* @param r [in] Received request.
* @param tuid [in] Transaction user id.
* @param tid [in] Transaction id.
* @return When the NOTIFY is valid, false is returned. The subclass MUST further
* handle the NOTIFY, i.e. send a response.
*/
virtual bool recv_notify(t_request *r, t_tuid tuid, t_tid tid);
//@}
/** @name Receive responses */
//@{
/**
* Receive NOTIFY/SUBSCRIBE response.
* @param r [in] Received response.
* @param tuid [in] Transaction user id.
* @param tid [in] Transaction id.
* @return The return value indicates if processing is finished.
*/
virtual bool recv_response(t_response *r, t_tuid tuid, t_tid tid);
/**
* Receive NOTIFY response.
* @param r [in] Received response.
* @param tuid [in] Transaction user id.
* @param tid [in] Transaction id.
* @return The return value indicates if processing is finished.
*/
virtual bool recv_notify_response(t_response *r, t_tuid tuid, t_tid tid);
/**
* Receive SUBSCRIBE response.
* @param r [in] Received response.
* @param tuid [in] Transaction user id.
* @param tid [in] Transaction id.
* @return The return value indicates if processing is finished.
*/
virtual bool recv_subscribe_response(t_response *r, t_tuid tuid, t_tid tid);
//@}
/**
* Process timeouts
* @param timer [in] Type of subscription timer.
* @return The return value indicates if processing is finished.
*/
virtual bool timeout(t_subscribe_timer timer);
/**
* Match timer id with a running timer.
* @param timer [in] Type of subscription timer.
* @return True, if id matches, otherwise false.
*/
virtual bool match_timer(t_subscribe_timer timer, t_object_id id_timer) const;
/**
* Does incoming request match with event type and id?
* @param r [in] Request to match.
* @return True if request matches, otherwise false.
*/
virtual bool match(t_request *r) const;
/**
* Check if subscription is pending.
* @return True if subscription is pending, otherwise false.
*/
bool is_pending(void) const;
/**
* Subscribe to an event.
* @param expires [in] Expiry in seconds. If expires == 0, then the default duration is used.
*/
virtual void subscribe(unsigned long expires);
/** Unsubscribe from an event. */
virtual void unsubscribe(void);
/** Refresh subscription. */
virtual void refresh_subscribe(void);
};
#endif
|