summaryrefslogtreecommitdiffstats
path: root/src/transaction.h
blob: bc3156fc8398a7d0fabb905377f4d983f8451994 (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
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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
/*
    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 _TRANSACTION_H
#define _TRANSACTION_H

#include <string>
#include "protocol.h"
#include "parser/request.h"
#include "parser/response.h"
#include "sockets/socket.h"
#include "threads/mutex.h"

using namespace std;

typedef unsigned short	t_tid;

/////////////////////////////////////////////////////////////
// Transaction state (see RFC 3261 17)
/////////////////////////////////////////////////////////////
enum t_trans_state {
	TS_NULL,	// non-state used for initialization
	TS_CALLING,
	TS_TRYING,
	TS_PROCEEDING,
	TS_COMPLETED,
	TS_CONFIRMED,
	TS_TERMINATED,
};

string trans_state2str(t_trans_state s);

/////////////////////////////////////////////////////////////
// General transaction
/////////////////////////////////////////////////////////////
//
// Concurrent creation of transactions is not allowed. If this
// is needed then updates to static members need to be
// synchronized with a mutex.
// All transactions are created by the transaction manager. This
// should not be changed as transactions start timers and all timers
// must be started from a single thread.

class t_transaction {
private:
	static t_mutex		mtx_class; // protect static members
	static t_tid		next_id; // next id to be issued

protected:
	t_tid			id; 	// transaction id
	unsigned short		tuid;	// TU id
	t_trans_state		state;
	string			to_tag;	// tag for to-header

public:
	// Request that created the transaction
	t_request		*request;

	t_tid get_id(void) const;

	// Provisional responses in order of arrival/sending
	list<t_response *>	provisional;

	// Final response for the transaction
	t_response		*final;

	// The transaction will keep a copy of the request
	t_transaction(t_request *r, unsigned short _tuid);

	// All request and response pointers contained by the
	// request will be deleted.
	virtual ~t_transaction();

	// Process a provisional repsonse
	// Transaction will keep a copy of the response
	virtual void process_provisional(t_response *r);

	// Process a final response
	// Transaction will keep a copy of the response
	virtual void process_final(t_response *r);

	// Process a response
	virtual void process_response(t_response *r);

	// Process timer expiry
	virtual void timeout(t_sip_timer t) = 0;

	// Get state of the transaction
	t_trans_state get_state(void) const;

	// Set TU ID
	void set_tuid(unsigned short _tuid);

	// Get type of request
	t_method get_method(void) const;

	// Get tag for to-header
	string get_to_tag(void);

	// Create response according to general rules
	t_response *create_response(int code, string reason = "");
};

/////////////////////////////////////////////////////////////
// Client transaction
/////////////////////////////////////////////////////////////
class t_trans_client : public t_transaction {
protected:
	/** Destination for request. */
	t_ip_port	dst_ip_port;

public:
	/**
	 * Create transaction and send request to destination.
	 * @param r [in] Request creating the transaction.
	 * @param ip_port [in] Destination of the request.
	 * @param _tuid [in] Transaction user id assigned to this transaction.
	 */
	t_trans_client(t_request *r, const t_ip_port &ip_port,
		unsigned short _tuid);

	/**
	 * Match a response with a transaction.
	 * @param r [in] The response to match.
	 * @return true if the response matches the transaction.
	 */
	bool match(t_response *r) const;
	
	/**
	 * @param icmp [in] ICMP message to match.
	 * @return true if the ICMP error matches the transaction
	 */
	bool match(const t_icmp_msg &icmp) const;
	
	/**
	 * Match transaction with a branch and CSeq method value.
	 * @param branch [in] Branch to match.
	 * @param cseq_method [in] CSeq method to match.
	 * @return true if transaction matches, otherwise false.
	 */
	bool match(const string &branch, const t_method &cseq_method) const;
	
	virtual void process_provisional(t_response *r);
	
	/** 
	 * Process ICMP errors.
	 * @param icmp [in] ICMP message.
	 */
	virtual void process_icmp(const t_icmp_msg &icmp) = 0;
	
	/**
	 * Process failures.
	 * @param failure [in] Type of failure.
	 */
	virtual void process_failure(t_failure failure) = 0;

	/**
	 * Abort a transaction.
	 * This will send a 408 response internally to finish the transaction.
	 */
	virtual void abort(void) = 0;
};

/////////////////////////////////////////////////////////////
// Client INVITE transaction
/////////////////////////////////////////////////////////////
class t_tc_invite : public t_trans_client {
private:
	// Timers
	unsigned short	timer_A;
	unsigned short	timer_B;
	unsigned short	timer_D;

	// Duration of next timer A in msec
	long	duration_A;

	void start_timer_A(void);
	void start_timer_B(void);
	void start_timer_D(void);
	void stop_timer_A(void);
	void stop_timer_B(void);
	void stop_timer_D(void);


public:
	t_request		*ack;	// ACK request

	// Create transaction and send request to destination
	// Start timer A and timer B
	t_tc_invite(t_request *r, const t_ip_port &ip_port,
		unsigned short _tuid);

	virtual ~t_tc_invite();

	// Process a provisional repsonse
	// Stop timer A
	void process_provisional(t_response *r);

	// Process a final response
	// Stop timer B.
	// Start timer D (for non-2xx final).
	void process_final(t_response *r);
	
	void process_icmp(const t_icmp_msg &icmp);
	
	void process_failure(t_failure failure);

	void timeout(t_sip_timer t);

	void abort(void);
};

/////////////////////////////////////////////////////////////
// Client non-INVITE transaction
/////////////////////////////////////////////////////////////
class t_tc_non_invite : public t_trans_client {
private:
	// Timers
	unsigned short	timer_E;
	unsigned short	timer_F;
	unsigned short	timer_K;

	// Duration of next timer E in msec
	long	duration_E;

	void start_timer_E(void);
	void start_timer_F(void);
	void start_timer_K(void);
	void stop_timer_E(void);
	void stop_timer_F(void);
	void stop_timer_K(void);

public:
	// Create transaction and send request to destination
	// Stop timer E and timer F
	t_tc_non_invite(t_request *r, const t_ip_port &ip_port,
		unsigned short _tuid);

	virtual ~t_tc_non_invite();

	// Process a provisional repsonse
	void process_provisional(t_response *r);

	// Process final response
	// Stop timer E and F. Start timer K.
	void process_final(t_response *r);
	
	void process_icmp(const t_icmp_msg &icmp);
	
	void process_failure(t_failure failure);

	void timeout(t_sip_timer t);

	void abort(void);
};

/////////////////////////////////////////////////////////////
// Server transaction
/////////////////////////////////////////////////////////////
class t_trans_server : public t_transaction {
private:
	// Match a the transaction to a request. Argument
	// If cancel==true then the target for a CANCEL
	// is matched.
	// If cancel==false then the request itself is matched,
	// eg. retransmission or ACK to INVITE matching
	bool match(t_request *r, bool cancel) const;
	
	// Indicates if a 100 Trying has already been sent.
	// A 100 Trying should only be sent once.
	// The reason for sending a 100 Trying is to indicate that
	// the request has been received but that processing will
	// take some time.
	// Based on the tasks to perform several parts of the transaction
	// user can decide independently to send a 100 Trying. This
	// flag assures that only one 100 Trying will be sent out
	// though.
	bool resp_100_trying_sent;

public:
	t_trans_server(t_request *r, unsigned short _tuid);

	// Process a provisional repsonse
	// Send provisional response
	void process_provisional(t_response *r);

	// Process a final response
	// Send the final response
	void process_final(t_response *r);

	// Process a received retransmission of the request
	virtual void process_retransmission(void);

	// Returns true if request matches transaction
	bool match(t_request *r) const;

	// Returns true if the transaction is the target of CANCEL
	bool match_cancel(t_request *r) const;
};

/////////////////////////////////////////////////////////////
// Server INIVITE transaction
/////////////////////////////////////////////////////////////
class t_ts_invite : public t_trans_server {
private:
	// Timers
	unsigned short	timer_G;
	unsigned short	timer_H;
	unsigned short	timer_I;

	// Duration of next timer G in msec
	long	duration_G;

	void start_timer_G(void);
	void start_timer_H(void);
	void start_timer_I(void);
	void stop_timer_G(void);
	void stop_timer_H(void);
	void stop_timer_I(void);

public:
	t_request		*ack;	// ACK request

	t_ts_invite(t_request *r, unsigned short _tuid);
	virtual ~t_ts_invite();

	void process_provisional(t_response *r);
	void process_final(t_response *r);
	void process_retransmission(void);
	void timeout(t_sip_timer t);

	// Transaction will keep a copy of the ACK.
	void acknowledge(t_request *ack_request);
};

/////////////////////////////////////////////////////////////
// Server non-INVITE transaction
/////////////////////////////////////////////////////////////
class t_ts_non_invite : public t_trans_server {
private:
	// Timers
	unsigned short	timer_J;

	void start_timer_J(void);
	void stop_timer_J(void);

public:
	t_ts_non_invite(t_request *r, unsigned short _tuid);
	virtual ~t_ts_non_invite();

	void process_provisional(t_response *r);
	void process_final(t_response *r);
	void process_retransmission(void);
	void timeout(t_sip_timer t);
};

#endif