1 /*
2 * Copyright (C) 2011 Stefan Sayer
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
28 #include "AmSessionContainer.h"
29
30 #include "AmAppTimer.h"
31 #include "log.h"
32
33 using std::map;
34
35 class app_timer : public timer
36 {
37 string q_id;
38 int timer_id;
39
40 public:
app_timer(const string & q_id,int timer_id,unsigned int expires)41 app_timer(const string& q_id, int timer_id, unsigned int expires)
42 : timer(expires), q_id(q_id), timer_id(timer_id) {}
43
~app_timer()44 ~app_timer() {}
45
get_id()46 int get_id() { return timer_id; }
get_q_id()47 string get_q_id() { return q_id; }
48
49 // timer interface
fire()50 void fire() {
51 AmAppTimer::instance()->app_timer_cb(this);
52 }
53 };
54
55 class direct_app_timer
56 : public timer
57 {
58 public:
59 DirectAppTimer* dt;
60
direct_app_timer(DirectAppTimer * dt,unsigned int expires)61 direct_app_timer(DirectAppTimer* dt, unsigned int expires)
62 : timer(expires), dt(dt) {}
63
~direct_app_timer()64 ~direct_app_timer() {}
65
fire()66 void fire() {
67 AmAppTimer::instance()->direct_app_timer_cb(this);
68 }
69 };
70
_AmAppTimer()71 _AmAppTimer::_AmAppTimer()
72 : direct_timers_mut(true)
73 {
74 }
75
~_AmAppTimer()76 _AmAppTimer::~_AmAppTimer() {
77 }
78
app_timer_cb(app_timer * at)79 void _AmAppTimer::app_timer_cb(app_timer* at)
80 {
81 user_timers_mut.lock();
82 app_timer* at_local = erase_timer(at->get_q_id(), at->get_id());
83
84 if (NULL != at_local) {
85
86 if (at_local != at) {
87 DBG("timer was reset while expiring - not firing timer\n");
88 // we'd better re-insert at_local into user_timers
89 // what happens else, when at_local get fired ???
90 user_timers[at->get_q_id()][at->get_id()] = at_local;
91 } else {
92 DBG("timer fired: %d for '%s'\n", at->get_id(), at->get_q_id().c_str());
93 AmSessionContainer::instance()->postEvent(at->get_q_id(),
94 new AmTimeoutEvent(at->get_id()));
95 delete at;
96 }
97
98 } else {
99 DBG("timer %d for '%s' already removed\n",
100 at->get_id(), at->get_q_id().c_str());
101 // will be deleted by wheeltimer
102 }
103
104 user_timers_mut.unlock();
105 }
106
direct_app_timer_cb(direct_app_timer * t)107 void _AmAppTimer::direct_app_timer_cb(direct_app_timer* t)
108 {
109 DirectAppTimer* dt = t->dt;
110
111 direct_timers_mut.lock();
112 DirectTimers::iterator dt_it = direct_timers.find(dt);
113 if(dt_it != direct_timers.end()){
114 if(dt_it->second != t) {
115 // timer has been re-initialized
116 // with the same pointer... do not trigger!
117 // it will be deleted later by the wheeltimer
118 }
119 else {
120 // everything ok:
121
122 // remove stuff
123 direct_timers.erase(dt_it);
124 delete t;
125
126 // finally fire this timer!
127 dt->fire();
128 }
129 }
130 direct_timers_mut.unlock();
131 }
132
erase_timer(const string & q_id,int id)133 app_timer* _AmAppTimer::erase_timer(const string& q_id, int id)
134 {
135 app_timer* res = NULL;
136
137 map<string, map<int, app_timer*> >::iterator it=user_timers.find(q_id);
138 if (it != user_timers.end()) {
139 map<int, app_timer*>::iterator t_it = it->second.find(id);
140 if (t_it != it->second.end()) {
141 res = t_it->second;
142 it->second.erase(t_it);
143 if (it->second.empty())
144 user_timers.erase(it);
145 }
146 }
147
148 return res;
149 }
150
create_timer(const string & q_id,int id,unsigned int expires)151 app_timer* _AmAppTimer::create_timer(const string& q_id, int id,
152 unsigned int expires)
153 {
154 app_timer* timer = new app_timer(q_id, id, expires);
155 if (!timer)
156 return NULL;
157
158 user_timers[q_id][id] = timer;
159
160 return timer;
161 }
162
163 #define MAX_TIMER_SECONDS 365*24*3600 // one year, well below 1<<31
164
setTimer(const string & eventqueue_name,int timer_id,double timeout)165 void _AmAppTimer::setTimer(const string& eventqueue_name, int timer_id, double timeout) {
166
167 // microseconds
168 unsigned int expires;
169 if (timeout < 0) { // in the past
170 expires = 0;
171 } else if (timeout > MAX_TIMER_SECONDS) { // more than one year
172 ERROR("Application requesting timer %d for '%s' with timeout %f, "
173 "clipped to maximum of one year\n", timer_id, eventqueue_name.c_str(), timeout);
174 expires = (double)MAX_TIMER_SECONDS*1000.0*1000.0 / (double)TIMER_RESOLUTION;
175 } else {
176 expires = timeout*1000.0*1000.0 / (double)TIMER_RESOLUTION;
177 }
178
179 expires += wall_clock;
180
181 user_timers_mut.lock();
182 app_timer* t = erase_timer(eventqueue_name, timer_id);
183 if (NULL != t) {
184 remove_timer(t);
185 }
186 t = create_timer(eventqueue_name, timer_id, expires);
187 if (NULL != t) {
188 insert_timer(t);
189 }
190 user_timers_mut.unlock();
191 }
192
removeTimer(const string & eventqueue_name,int timer_id)193 void _AmAppTimer::removeTimer(const string& eventqueue_name, int timer_id)
194 {
195 user_timers_mut.lock();
196 app_timer* t = erase_timer(eventqueue_name, timer_id);
197 if (NULL != t) {
198 remove_timer(t);
199 }
200 user_timers_mut.unlock();
201 }
202
removeTimers(const string & eventqueue_name)203 void _AmAppTimer::removeTimers(const string& eventqueue_name)
204 {
205 user_timers_mut.lock();
206 TimerQueues::iterator it=user_timers.find(eventqueue_name);
207 if (it != user_timers.end()) {
208 for (AppTimers::iterator t_it =
209 it->second.begin(); t_it != it->second.end(); t_it++) {
210 if (NULL != t_it->second)
211 remove_timer(t_it->second);
212 }
213 user_timers.erase(it);
214 }
215 user_timers_mut.unlock();
216 }
217
setTimer_unsafe(DirectAppTimer * t,double timeout)218 void _AmAppTimer::setTimer_unsafe(DirectAppTimer* t, double timeout)
219 {
220 unsigned int expires = timeout*1000.0*1000.0 / (double)TIMER_RESOLUTION;
221 expires += wall_clock;
222
223 direct_app_timer* dt = new direct_app_timer(t,expires);
224 if(!dt) return;
225
226 DirectTimers::iterator dt_it = direct_timers.find(t);
227 if(dt_it != direct_timers.end()){
228 remove_timer(dt_it->second);
229 dt_it->second = dt;
230 }
231 else {
232 direct_timers[t] = dt;
233 }
234 insert_timer(dt);
235 }
236
setTimer(DirectAppTimer * t,double timeout)237 void _AmAppTimer::setTimer(DirectAppTimer* t, double timeout)
238 {
239 direct_timers_mut.lock();
240 setTimer_unsafe(t,timeout);
241 direct_timers_mut.unlock();
242 }
243
removeTimer_unsafe(DirectAppTimer * t)244 void _AmAppTimer::removeTimer_unsafe(DirectAppTimer* t)
245 {
246 DirectTimers::iterator dt_it = direct_timers.find(t);
247 if(dt_it != direct_timers.end()){
248 remove_timer(dt_it->second);
249 direct_timers.erase(dt_it);
250 }
251 }
252
removeTimer(DirectAppTimer * t)253 void _AmAppTimer::removeTimer(DirectAppTimer* t)
254 {
255 direct_timers_mut.lock();
256 removeTimer_unsafe(t);
257 direct_timers_mut.unlock();
258 }
259