summaryrefslogtreecommitdiffstats
path: root/src/timekeeper.h
blob: cac6b381f41e28fe6bfa340c56ea705f6aca4edf (plain)
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
/*
    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, see <https://www.gnu.org/licenses/>.
*/

#ifndef _TIMEKEEPER_H
#define _TIMEKEEPER_H

#include <list>
#include "id_object.h"
#include "protocol.h"
#include "transaction.h"
#include "threads/mutex.h"
#include "threads/sema.h"

using namespace std;

// Forward declarations
class t_phone;
class t_line;
class t_subscription;

/** Timer type */
enum t_timer_type {
	TMR_TRANSACTION,	/**< Transaction timer */
	TMR_PHONE,		/**< Timer associated with the phone */
	TMR_LINE,		/**< Timer associated with a line */
	TMR_SUBSCRIBE,		/**< Subscription timer */
	TMR_PUBLISH,		/**< Publication timer */
	TMR_STUN_TRANSACTION	/**< STUN timer */
};
////////////////////////////////////////////////////////////////
// General timer.
////////////////////////////////////////////////////////////////
// Instances should be created from subclasses.
class t_timer : public t_id_object {
private:
	long			duration; // milliseconds
	long			relative_duration; // milliseconds

public:
	t_timer(long dur);
	virtual ~t_timer() {}

	// This method is invoked on expiry
	// Subclasses should implent the action to be taken.
	virtual void expired(void) = 0;

	long get_duration(void) const;
	long get_relative_duration(void) const;
	void set_relative_duration(long d);
	virtual t_timer *copy(void) const = 0;
	virtual t_timer_type get_type(void) const = 0;

	// Get the name of the timer (for debugging purposes)
	virtual string get_name(void) const = 0;
};

////////////////////////////////////////////////////////////////
// Transaction timer
////////////////////////////////////////////////////////////////
class t_tmr_transaction : public t_timer {
private:
	unsigned short	transaction_id;
	t_sip_timer	sip_timer;

public:
	t_tmr_transaction(long dur, t_sip_timer tmr, unsigned short tid);

	void expired(void);
	t_timer *copy(void) const;
	t_timer_type get_type(void) const;
	unsigned short get_tid(void) const;
	t_sip_timer get_sip_timer(void) const;
	string get_name(void) const;
};

////////////////////////////////////////////////////////////////
// Phone timer
////////////////////////////////////////////////////////////////
class t_tmr_phone : public t_timer {
private:
	t_phone		*the_phone;
	t_phone_timer	phone_timer;

public:
	t_tmr_phone(long dur, t_phone_timer ptmr, t_phone *p);

	void expired(void);
	t_timer *copy(void) const;
	t_timer_type get_type(void) const;
	t_phone_timer get_phone_timer(void) const;
	t_phone *get_phone(void) const;
	string get_name(void) const;
};

////////////////////////////////////////////////////////////////
// Line timer
////////////////////////////////////////////////////////////////
class t_tmr_line : public t_timer {
private:
	t_object_id	line_id;
	t_line_timer	line_timer;
	t_object_id	dialog_id;

public:
	t_tmr_line(long dur, t_line_timer ltmr, t_object_id lid,
			t_object_id d);

	void expired(void);
	t_timer *copy(void) const;
	t_timer_type get_type(void) const;
	t_line_timer get_line_timer(void) const;
	t_object_id get_line_id(void) const;
	t_object_id get_dialog_id(void) const;
	string get_name(void) const;
};

////////////////////////////////////////////////////////////////
// Subscribe timer
////////////////////////////////////////////////////////////////
class t_tmr_subscribe : public t_timer {
private:
	t_subscribe_timer	subscribe_timer;
	t_object_id		line_id;
	t_object_id		dialog_id;
	string			sub_event_type;
	string			sub_event_id;


public:
	t_tmr_subscribe(long dur, t_subscribe_timer stmr, t_object_id lid, t_object_id d,
		const string &event_type, const string &event_id);

	void expired(void);
	t_timer *copy(void) const;
	t_timer_type get_type(void) const;
	t_subscribe_timer get_subscribe_timer(void) const;
	t_object_id get_line_id(void) const;
	t_object_id get_dialog_id(void) const;
	string get_sub_event_type(void) const;
	string get_sub_event_id(void) const;
	string get_name(void) const;
};

/** Publication timer */
class t_tmr_publish : public t_timer {
private:
	t_publish_timer		publish_timer;	/**< Type of timer */
	string			event_type;	/**< Event type of publication */


public:
	t_tmr_publish(long dur, t_publish_timer ptmr, const string &_event_type);

	void expired(void);
	t_timer *copy(void) const;
	t_timer_type get_type(void) const;
	t_publish_timer get_publish_timer(void) const;
	string get_name(void) const;
};

////////////////////////////////////////////////////////////////
// STUN transaction timer
////////////////////////////////////////////////////////////////
class t_tmr_stun_trans : public t_timer {
private:
	unsigned short	transaction_id;
	t_stun_timer	stun_timer;

public:
	t_tmr_stun_trans(long dur, t_stun_timer tmr, unsigned short tid);

	void expired(void);
	t_timer *copy(void) const;
	t_timer_type get_type(void) const;
	unsigned short get_tid(void) const;
	t_stun_timer get_stun_timer(void) const;
	string get_name(void) const;
};


////////////////////////////////////////////////////////////////
// Timekeeper
////////////////////////////////////////////////////////////////
// A timekeeper keeps track of multiple timers per thread.
// Only one single thread should call the methods of a single
// timekeeper. Multiple threads using the same timekeeper will
// cause havoc.

class t_timekeeper {
private:
	// List of running timers in order of timeout. As there
	// is only 1 real timer running on the OS. Each timer gets
	// a duration relative to its predecessor in the list.
	list<t_timer *>		timer_list;

	// Mutex to synchronize timekeeper actions.
	t_mutex			mutex;

	// Indicate if current timer was stopped, but not removed
	// to prevent race conditions. Expiry of a stopped timer
	// will not trigger any actions.
	bool			stopped;

	// Indicate if the current timer expired while the
	// mutex was locked.
	bool			timer_expired;

	// Every method should start with locking the timekeeper
	// and end with unlocking. The unlocking method will check
	// if a timer expired during the locked state. If so, then
	// the expiry will be processed.
	void lock(void);
	void unlock(void);

	// Start the timekeeper from the thread that will handle
	// the SIGALRM signal. Start must be called before the
	// timekeeper can be used.
	void start(void (*timeout_handler)(int));

	// Start a timer. The timer id is returned. This id is
	// needed to stop a timer. Pointer t should not be used
	// or deleted after starting. When the timer expires or
	// is stopped it will be deleted.
	void start_timer(t_timer *t);

	void stop_timer(t_object_id id);

public:
	// The timeout_handler must be a signal handler for SIGALRM
	t_timekeeper();
	~t_timekeeper();

	// Report that the current timer has expired.
	void report_expiry(void);

	// Get remaining time of a running timer.
	// Returns 0 if the timer is not running anymore.
	unsigned long get_remaining_time(t_object_id timer_id);

	// Main loop to be run in a separate thread
	void run(void);
};

// Entry function for timekeeper thread
void *timekeeper_main(void *arg);

// Entry function of the thread waiting for SIGALRM
// A dedicated thread is started to catch the SIGALRM signal and take
// the appropriate action. All threads must block the SIGALRM signal.
void *timekeeper_sigwait(void *arg);

#endif