... | ... |
@@ -18,7 +18,7 @@ auto_gen=lex.yy.c cfg.tab.c #lexx, yacc etc |
18 | 18 |
#include source related defs |
19 | 19 |
include Makefile.sources |
20 | 20 |
|
21 |
-override exclude_modules:=CVS cpl cpl-c ext radius_acc radius_auth snmp \ |
|
21 |
+override exclude_modules:=CVS cpl cpl-c ext radius_acc radius_auth snmp jabber sms pa extcmd msilo auth \ |
|
22 | 22 |
$(exclude_modules) |
23 | 23 |
static_modules= |
24 | 24 |
static_modules_path=$(addprefix modules/, $(static_modules)) |
... | ... |
@@ -175,8 +175,6 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \ |
175 | 175 |
-DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=1024 \ |
176 | 176 |
-DDNS_IP_HACK \ |
177 | 177 |
-DUSE_IPV6 \ |
178 |
- -DVOICE_MAIL \ |
|
179 |
- -D_TOTAG \ |
|
180 | 178 |
-DUSE_TCP \ |
181 | 179 |
-DDISABLE_NAGLE \ |
182 | 180 |
-DDIGEST_DOMAIN \ |
... | ... |
@@ -197,7 +195,7 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \ |
197 | 195 |
#-DNO_LOG |
198 | 196 |
|
199 | 197 |
#PROFILE= -pg #set this if you want profiling |
200 |
-#mode = debug |
|
198 |
+mode = debug |
|
201 | 199 |
ifeq ($(mode),) |
202 | 200 |
mode = release |
203 | 201 |
endif |
... | ... |
@@ -43,12 +43,26 @@ |
43 | 43 |
#include "t_cancel.h" |
44 | 44 |
#include "t_stats.h" |
45 | 45 |
|
46 |
+static enum kill_reason kr; |
|
47 |
+ |
|
46 | 48 |
/* pointer to the big table where all the transaction data |
47 | 49 |
lives |
48 | 50 |
*/ |
49 | 51 |
|
50 | 52 |
static struct s_table* tm_table; |
51 | 53 |
|
54 |
+void set_kr( enum kill_reason _kr ) |
|
55 |
+{ |
|
56 |
+ if (kr!=0 && _kr!=0) { |
|
57 |
+ DBG("DEBUG: set_kr: kill reason reset: " |
|
58 |
+ "old=%d update=%d\n", kr, _kr ); |
|
59 |
+ } |
|
60 |
+ kr|=_kr; |
|
61 |
+} |
|
62 |
+enum kill_reason get_kr() { |
|
63 |
+ return kr; |
|
64 |
+} |
|
65 |
+ |
|
52 | 66 |
void lock_hash(int i) |
53 | 67 |
{ |
54 | 68 |
lock(&tm_table->entrys[i].mutex); |
... | ... |
@@ -84,6 +98,7 @@ void free_cell( struct cell* dead_cell ) |
84 | 98 |
char *b; |
85 | 99 |
int i; |
86 | 100 |
struct sip_msg *rpl; |
101 |
+ struct totag_elem *tt, *foo; |
|
87 | 102 |
|
88 | 103 |
release_cell_lock( dead_cell ); |
89 | 104 |
shm_lock(); |
... | ... |
@@ -116,6 +131,15 @@ void free_cell( struct cell* dead_cell ) |
116 | 131 |
} |
117 | 132 |
} |
118 | 133 |
|
134 |
+ /* collected to tags */ |
|
135 |
+ tt=dead_cell->fwded_totags; |
|
136 |
+ while(tt) { |
|
137 |
+ foo=tt->next; |
|
138 |
+ shm_free_unsafe(tt->tag.s); |
|
139 |
+ shm_free_unsafe(tt); |
|
140 |
+ tt=foo; |
|
141 |
+ } |
|
142 |
+ |
|
119 | 143 |
/* the cell's body */ |
120 | 144 |
shm_free_unsafe( dead_cell ); |
121 | 145 |
|
... | ... |
@@ -158,6 +182,9 @@ struct cell* build_cell( struct sip_msg* p_msg ) |
158 | 182 |
/*fprintf(stderr,"before clone VIA |%.*s|\n",via_len(p_msg->via1), |
159 | 183 |
via_s(p_msg->via1,p_msg));*/ |
160 | 184 |
|
185 |
+ callback_event(TMCB_REQUEST_IN, new_cell, p_msg, |
|
186 |
+ p_msg ? p_msg->REQ_METHOD : METHOD_UNDEF ); |
|
187 |
+ |
|
161 | 188 |
if (p_msg) { |
162 | 189 |
new_cell->uas.request = sip_msg_cloner(p_msg); |
163 | 190 |
if (!new_cell->uas.request) |
... | ... |
@@ -120,10 +120,16 @@ typedef struct ua_server |
120 | 120 |
struct sip_msg *request; |
121 | 121 |
struct retr_buf response; |
122 | 122 |
unsigned int status; |
123 |
+ /* keep to-tags for local 200 replies for INVITE -- |
|
124 |
+ * we need them for dialog-wise matching of ACKs; |
|
125 |
+ * the pointer shows to shmem-ed reply */ |
|
126 |
+ str local_totag; |
|
123 | 127 |
#ifdef _TOTAG |
124 | 128 |
str to_tag; |
125 | 129 |
#endif |
130 |
+#ifdef _OBSO |
|
126 | 131 |
unsigned int isACKed; |
132 |
+#endif |
|
127 | 133 |
}ua_server_type; |
128 | 134 |
|
129 | 135 |
|
... | ... |
@@ -151,6 +157,11 @@ typedef struct ua_client |
151 | 157 |
}ua_client_type; |
152 | 158 |
|
153 | 159 |
|
160 |
+struct totag_elem { |
|
161 |
+ str tag; |
|
162 |
+ short acked; |
|
163 |
+ struct totag_elem *next; |
|
164 |
+}; |
|
154 | 165 |
|
155 | 166 |
/* transaction context */ |
156 | 167 |
|
... | ... |
@@ -205,7 +216,8 @@ typedef struct cell |
205 | 216 |
|
206 | 217 |
/* number of forks */ |
207 | 218 |
int nr_of_outgoings; |
208 |
- /* nr of replied branch */ |
|
219 |
+ /* nr of replied branch; 0..MAX_BRANCHES=branch value, |
|
220 |
+ * -1 no reply, -2 local reply */ |
|
209 | 221 |
int relaied_reply_branch; |
210 | 222 |
/* UA Server */ |
211 | 223 |
struct ua_server uas; |
... | ... |
@@ -221,16 +233,9 @@ typedef struct cell |
221 | 233 |
dropping when C timer hits |
222 | 234 |
*/ |
223 | 235 |
int noisy_ctimer; |
224 |
- /* is it a local transaction ? */ |
|
236 |
+ /* is it a local UAC transaction ? */ |
|
225 | 237 |
int local; |
226 | 238 |
|
227 |
-#ifdef _XWAIT |
|
228 |
- /* protection against reentering WAIT state */ |
|
229 |
- ser_lock_t wait_mutex; |
|
230 |
- /* has the transaction been put on wait status ? */ |
|
231 |
- int on_wait; |
|
232 |
-#endif |
|
233 |
- |
|
234 | 239 |
/* MD5checksum (meaningful only if syn_branch=0 */ |
235 | 240 |
char md5[MD5_LEN]; |
236 | 241 |
|
... | ... |
@@ -239,7 +244,12 @@ typedef struct cell |
239 | 244 |
short damocles; |
240 | 245 |
#endif |
241 | 246 |
/* has the transaction been scheduled to die? */ |
242 |
- enum kill_reason kr; |
|
247 |
+/* enum kill_reason kr; */ |
|
248 |
+ |
|
249 |
+ /* to-tags of 200/INVITEs which were received from downstream and |
|
250 |
+ * forwarded or passed to UAC; note that there can be arbitrarily |
|
251 |
+ * many due to downstream forking; */ |
|
252 |
+ struct totag_elem *fwded_totags; |
|
243 | 253 |
}cell_type; |
244 | 254 |
|
245 | 255 |
|
... | ... |
@@ -266,14 +276,9 @@ struct s_table |
266 | 276 |
struct entry entrys[ TABLE_ENTRIES ]; |
267 | 277 |
}; |
268 | 278 |
|
269 |
-inline static void set_kr( struct cell *t, enum kill_reason kr ) |
|
270 |
-{ |
|
271 |
- if (t->kr!=0) { |
|
272 |
- LOG(L_ERR, "ERROR: set_kr: kill_reason reset: from=%d to=%d\n", |
|
273 |
- t->kr, kr); |
|
274 |
- } |
|
275 |
- t->kr|=kr; |
|
276 |
-} |
|
279 |
+ |
|
280 |
+void set_kr( enum kill_reason kr ); |
|
281 |
+enum kill_reason get_kr(); |
|
277 | 282 |
|
278 | 283 |
struct s_table* get_tm_table(); |
279 | 284 |
struct s_table* init_hash_table(); |
... | ... |
@@ -92,10 +92,12 @@ int send_pr_buffer( struct retr_buf *rb, |
92 | 92 |
UNREF_UNSAFE(_T_cell); \ |
93 | 93 |
UNLOCK_HASH( (_T_cell)->hash_index ); }) |
94 | 94 |
#define REF_UNSAFE(_T_cell) ({ (_T_cell)->ref_count++; }) |
95 |
+#ifdef _OBSO |
|
95 | 96 |
#define REF(_T_cell) ({ \ |
96 | 97 |
LOCK_HASH( (_T_cell)->hash_index ); \ |
97 | 98 |
REF_UNSAFE(_T_cell); \ |
98 | 99 |
UNLOCK_HASH( (_T_cell)->hash_index ); }) |
100 |
+#endif |
|
99 | 101 |
#define INIT_REF_UNSAFE(_T_cell) (_T_cell)->ref_count=1 |
100 | 102 |
#define IS_REFFED_UNSAFE(_T_cell) ((_T_cell)->ref_count!=0) |
101 | 103 |
|
... | ... |
@@ -111,19 +113,14 @@ void tm_shutdown(); |
111 | 113 |
int t_add_transaction( struct sip_msg* p_msg ); |
112 | 114 |
|
113 | 115 |
|
114 |
-/* returns 1 if everything was OK or -1 for error |
|
115 |
- */ |
|
116 |
+/* returns 1 if everything was OK or -1 for error */ |
|
116 | 117 |
int t_release_transaction( struct cell *trans ); |
117 | 118 |
|
118 | 119 |
|
119 |
-/* int forward_serial_branch(struct cell* Trans,int branch); */ |
|
120 |
-int t_put_on_wait( struct cell *Trans ); |
|
121 | 120 |
int get_ip_and_port_from_uri( str* uri , unsigned int *param_ip, |
122 | 121 |
unsigned int *param_port); |
123 | 122 |
|
124 | 123 |
|
125 |
-int t_newtran( struct sip_msg* p_msg ); |
|
126 |
- |
|
127 | 124 |
void put_on_wait( struct cell *Trans ); |
128 | 125 |
|
129 | 126 |
void start_retr( struct retr_buf *rb ); |
... | ... |
@@ -75,7 +75,7 @@ char *print_uac_request( struct cell *t, struct sip_msg *i_req, |
75 | 75 |
i_req->new_uri=*uri; |
76 | 76 |
|
77 | 77 |
/* ... give apps a chance to change things ... */ |
78 |
- callback_event( TMCB_REQUEST_OUT, t, i_req, -i_req->REQ_METHOD); |
|
78 |
+ callback_event( TMCB_REQUEST_FWDED, t, i_req, -i_req->REQ_METHOD); |
|
79 | 79 |
|
80 | 80 |
/* ... and build it now */ |
81 | 81 |
buf=build_req_buf_from_sip_req( i_req, len, send_sock, i_req->rcv.proto ); |
... | ... |
@@ -110,6 +110,45 @@ error01: |
110 | 110 |
return shbuf; |
111 | 111 |
} |
112 | 112 |
|
113 |
+/* introduce a new uac, which is blind -- it only creates the |
|
114 |
+ data structures and starts FR timer, but that's it; it does |
|
115 |
+ not print messages and send anything anywhere; that is good |
|
116 |
+ for FIFO apps -- the transaction must look operationally |
|
117 |
+ and FR must be ticking, whereas the request is "forwarded" |
|
118 |
+ using a non-SIP way and will be replied the same way |
|
119 |
+*/ |
|
120 |
+int add_blind_uac( /*struct cell *t*/ ) |
|
121 |
+{ |
|
122 |
+ unsigned short branch; |
|
123 |
+ struct cell *t; |
|
124 |
+ |
|
125 |
+ t=get_t(); |
|
126 |
+ if (t==T_UNDEFINED || !t ) { |
|
127 |
+ LOG(L_ERR, "ERROR: add_blind_uac: no transaction context\n"); |
|
128 |
+ return -1; |
|
129 |
+ } |
|
130 |
+ |
|
131 |
+ branch=t->nr_of_outgoings; |
|
132 |
+ if (branch==MAX_BRANCHES) { |
|
133 |
+ LOG(L_ERR, "ERROR: add_blind_uac: " |
|
134 |
+ "maximum number of branches exceeded\n"); |
|
135 |
+ return -1; |
|
136 |
+ } |
|
137 |
+ /* make sure it will be replied */ |
|
138 |
+ t->noisy_ctimer=1; |
|
139 |
+ t->nr_of_outgoings++; |
|
140 |
+ /* start FR timer -- protocol set by default to PROTO_NONE, |
|
141 |
+ which means retransmission timer will not be started |
|
142 |
+ */ |
|
143 |
+ start_retr(&t->uac[branch].request); |
|
144 |
+ /* we are on a timer -- don't need to put on wait on script |
|
145 |
+ clean-up |
|
146 |
+ */ |
|
147 |
+ set_kr(REQ_FWDED); |
|
148 |
+ |
|
149 |
+ return 1; /* success */ |
|
150 |
+} |
|
151 |
+ |
|
113 | 152 |
/* introduce a new uac to transaction; returns its branch id (>=0) |
114 | 153 |
or error (<0); it doesn't send a message yet -- a reply to it |
115 | 154 |
might interfere with the processes of adding multiple branches |
... | ... |
@@ -343,7 +382,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , |
343 | 382 |
/* make -Wall happy */ |
344 | 383 |
current_uri.s=0; |
345 | 384 |
|
346 |
- set_kr(t, REQ_FWDED); |
|
385 |
+ set_kr(REQ_FWDED); |
|
347 | 386 |
|
348 | 387 |
if (p_msg->REQ_METHOD==METHOD_CANCEL) { |
349 | 388 |
t_invite=t_lookupOriginalT( p_msg ); |
... | ... |
@@ -40,6 +40,7 @@ |
40 | 40 |
#include "../../proxy.h" |
41 | 41 |
|
42 | 42 |
typedef int (*tfwd_f)(struct sip_msg* p_msg , struct proxy_l * proxy ); |
43 |
+typedef int (*taddblind_f)( /*struct cell *t */ ); |
|
43 | 44 |
|
44 | 45 |
int t_replicate(struct sip_msg *p_msg, struct proxy_l * proxy, int proto); |
45 | 46 |
char *print_uac_request( struct cell *t, struct sip_msg *i_req, |
... | ... |
@@ -48,6 +49,7 @@ void e2e_cancel( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell |
48 | 49 |
int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite, int branch ); |
49 | 50 |
int add_uac( struct cell *t, struct sip_msg *request, str *uri, |
50 | 51 |
struct proxy_l *proxy, int proto ); |
52 |
+int add_blind_uac( /* struct cell *t */ ); |
|
51 | 53 |
int t_forward_nonack( struct cell *t, struct sip_msg* p_msg, |
52 | 54 |
struct proxy_l * p, int proto); |
53 | 55 |
int t_forward_ack( struct sip_msg* p_msg ); |
... | ... |
@@ -35,83 +35,95 @@ |
35 | 35 |
struct sip_msg; |
36 | 36 |
struct cell; |
37 | 37 |
|
38 |
-typedef enum { TMCB_REPLY, TMCB_E2EACK, TMCB_REPLY_IN, |
|
39 |
- TMCB_REQUEST_OUT, TMCB_LOCAL_COMPLETED, TMCB_ON_NEGATIVE, |
|
40 |
- TMCB_END } tmcb_type; |
|
38 |
+typedef enum { |
|
39 |
+ /* input events */ |
|
40 |
+ TMCB_RESPONSE_IN=1, TMCB_REQUEST_IN, TMCB_E2EACK_IN, |
|
41 |
+ /* routing decisions in progress */ |
|
42 |
+ TMCB_REQUEST_FWDED, TMCB_RESPONSE_FWDED, TMCB_ON_FAILURE, |
|
43 |
+ /* completion events */ |
|
44 |
+ TMCB_RESPONSE_OUT, TMCB_LOCAL_COMPLETED, |
|
45 |
+ TMCB_END } tmcb_type; |
|
41 | 46 |
|
42 | 47 |
/* |
43 |
- TMCB_REPLY - a reply has been sent out |
|
44 |
- no chance to change anything in the message; |
|
45 |
- still good enough for many uses, such as accounting |
|
46 |
- of completed transactions; note well that the message |
|
47 |
- passed to the callback may also have value FAKED_REPLY, |
|
48 |
- i.e., refering to it will segfault |
|
49 |
- TMCB_REPLY_IN - a reply was received and is about to be forwarded; |
|
50 |
- compared to TMCB_REPLY, it is a very internal callback and |
|
51 |
- you should use it with lot of caution |
|
52 |
- - it allows you to change the message (called before printing |
|
53 |
- the relayed message) |
|
54 |
- - it is called from a reply lock -- it is mroe dangerous and |
|
55 |
- anything you do makes the processes spend more time in |
|
56 |
- the lock, decreasing overall performance |
|
57 |
- - is is called only for replies >100, <300 (final replies |
|
58 |
- might be cached on forking, stored in shmem -- then, there |
|
59 |
- is no more easy way to change messages) |
|
60 |
- - as it is called before printing and forwarding, there is |
|
61 |
- no guarantee the message will be sent out -- either can |
|
62 |
- fail |
|
63 |
- |
|
64 |
- Note: none of the reply callbacks will be evoked if |
|
65 |
- "silent C timer" hits. Silent C timer is a feature which |
|
66 |
- prevents cancellation of a call in progress by a server |
|
67 |
- in the middle, when C timer expires. On one side, |
|
68 |
- INVITE transactional state cannot be kept for ever, |
|
69 |
- on the other side you want to allow long ringing |
|
70 |
- uninterrupted by a proxy server. The silent_c feature |
|
71 |
- -- if circumstances allow -- simply discards transaction |
|
72 |
- state when C timer hits, the transaction can then complete |
|
73 |
- statelessly. Then, however, the stateful callback will |
|
74 |
- NOT be called. If you do not wish this behaviour (e.g., |
|
75 |
- for sake of transaction accounting, in which you do |
|
76 |
- not desire users to wait until silent C hits and |
|
77 |
- eventually complete an unaccounted transaction), turn |
|
78 |
- silent C off either globaly (TM option "noisy_ctimer" |
|
79 |
- set to 1) or for a specific transaction (you can for |
|
80 |
- example set the transaction member "noisy_timer" |
|
81 |
- from request callback.) |
|
82 |
- |
|
83 |
- TMCB_E2EACK - presumably, an end2end ACK was received and |
|
84 |
- is about to be processed statelessly; you better don't |
|
85 |
- use this callback as there is no reliable way to match |
|
86 |
- an e2e ACK to an INVITE transaction, we just try it for |
|
87 |
- those, who believe they can't live without knowing about |
|
88 |
- the ACK; There are more reasons why the e2e ACK callback |
|
89 |
- is never triggered: 1) the e2eACK does not pass the server |
|
90 |
- at all 2) the e2e ACK does not match an INVITE transaction |
|
91 |
- because its r-uri or via is different |
|
92 |
- TMCB_REQUEST_OUT - a request was received and is about to be fwd-ed; |
|
93 |
- it is not called on retransmissions; it is called prior to |
|
94 |
- printing the relayed message, i.e., changes to it can |
|
95 |
- be done |
|
96 |
- TMCB_LOCAL_COMPLETED - a local transaction completed; note that |
|
97 |
- the callback parameter may be FAKED_REPLY |
|
98 |
- TMCB_MISSED -- transaction was replied with a negative value; |
|
99 |
- called from within a REPLY_LOCK, message may be FAKED_REPLY |
|
100 |
- TMCB_ON_NEGATIVE -- called whenever a transaction is about to complete |
|
101 |
- with a negative result; it's a great time to introduce a new |
|
102 |
- uac (serial forking) or change the reply code; be cautions |
|
103 |
- though -- it is called from within REPLY_LOCK and careless |
|
104 |
- usage of the callback can easily result in a deadlock; msg |
|
105 |
- is always 0 (callback refers to whole transaction and not |
|
106 |
- to individual message), code is the currently lowest status |
|
107 |
- code |
|
108 |
- TMCB_END - just a bumper |
|
48 |
+ * Caution: most of the callbacks work with shmem-ized messages |
|
49 |
+ * which you can no more change (e.g., lumps are fixed). Most |
|
50 |
+ * reply-processing callbacks are also called from a mutex, |
|
51 |
+ * which may cause deadlock if you are not careful. Also, reply |
|
52 |
+ * callbacks may pass the value of FAKED_REPLY messages, which |
|
53 |
+ * is a non-dereferencable pointer indicating that no message |
|
54 |
+ * was received and a timer hit instead. |
|
55 |
+ * |
|
56 |
+ * Callback description: |
|
57 |
+ * --------------------- |
|
58 |
+ * |
|
59 |
+ * TMCB_REQUEST_IN -- a brand-new request was received and is |
|
60 |
+ * about to establish transaction; it is not yet cloned and |
|
61 |
+ * lives in pkg mem -- your last chance to mangle it before |
|
62 |
+ * it gets shmem-ized (then, it's read-only); it's called from |
|
63 |
+ * HASH_LOCK, so be careful. It is guaranteed not to be |
|
64 |
+ * a retransmission. |
|
65 |
+ * |
|
66 |
+ * TMCB_RESPONSE_IN -- a brand-new reply was received which matches |
|
67 |
+ * an existing transaction. It may or may not be a retranmisssion. |
|
68 |
+ * |
|
69 |
+ * TMCB_RESPONSE_OUT -- a final reply was sent out (eiter local |
|
70 |
+ * or proxied) -- there is nothing more you can change from |
|
71 |
+ * the callback, it is good for accounting-like uses. |
|
72 |
+ * |
|
73 |
+ * Note: the message passed to callback may also have |
|
74 |
+ * value FAKED_REPLY (like other reply callbacks) which |
|
75 |
+ * indicates a psedo_reply caused by a timer. Check for |
|
76 |
+ * this value before derefing -- you will cause a segfault |
|
77 |
+ * otherwise. |
|
78 |
+ * |
|
79 |
+ * TMCB_ON_FAILURE -- called on receipt of a reply or timer; |
|
80 |
+ * it means all branches completed with a failure; that's |
|
81 |
+ * a chance for example to add new transaction branches |
|
82 |
+ * |
|
83 |
+ * TMCB_RESPONSE_FWDED -- called when a reply is about to be |
|
84 |
+ * forwarded; it is called after a message is received but before |
|
85 |
+ * a message is sent out: it is called when the decision is |
|
86 |
+ * made to forward a reply; it is parametrized by pkg message |
|
87 |
+ * which caused the transaction to complete (which is not |
|
88 |
+ * necessarily the same which will be forwarded). As forwarding |
|
89 |
+ * has not been executed and may fail, there is no guarentee |
|
90 |
+ * a reply will be successfuly sent out at this point of time. |
|
91 |
+ * |
|
92 |
+ * Note: TMCB_REPLY_ON_FAILURE and TMCB_REPLY_FWDED are |
|
93 |
+ * called from reply mutex which is used to deterministically |
|
94 |
+ * process multiple replies received in parallel. A failure |
|
95 |
+ * to set the mutex again or stay too long in the callback |
|
96 |
+ * may result in deadlock. |
|
97 |
+ * |
|
98 |
+ * Note: the reply callbacks will not be evoked if "silent |
|
99 |
+ * C-timer hits". That's a feature to clean transactional |
|
100 |
+ * state from a proxy quickly -- transactions will then |
|
101 |
+ * complete statelessly. If you wish to disable this |
|
102 |
+ * feature, either set the global option "noisy_ctimer" |
|
103 |
+ * to 1, or set t->noisy_ctimer for selected transaction. |
|
104 |
+ * |
|
105 |
+ * TMCB_E2EACK_IN -- called when an ACK belonging to a proxied |
|
106 |
+ * INVITE transaction completed with 200 arrived. Note that |
|
107 |
+ * because it can be only dialog-wise matched, only the first |
|
108 |
+ * transaction occurence will be matched with spirals. If |
|
109 |
+ * record-routing is not enabled, you will never receive the |
|
110 |
+ * ACK and the callback will be never triggered. |
|
111 |
+ * |
|
112 |
+ * |
|
113 |
+ * TMCB_REQUEST_FWDED -- request is being forwarded out. It is |
|
114 |
+ * called before a message is forwarded and it is your last |
|
115 |
+ * chance to change its shape. |
|
116 |
+ * |
|
117 |
+ * TMCB_LOCAL COMPLETED -- final reply for localy initiated |
|
118 |
+ * transaction arrived. Message may be FAKED_REPLY. |
|
119 |
+ * |
|
120 |
+ * TMCB_END - just a bumper |
|
109 | 121 |
|
110 | 122 |
see the 'acc' module for an example of callback usage |
111 | 123 |
|
112 | 124 |
note that callbacks MUST be installed before forking |
113 | 125 |
(callback lists do not live in shmem and have no access |
114 |
- protection) |
|
126 |
+ protection), i.e., at best from mod_init functions. |
|
115 | 127 |
*/ |
116 | 128 |
|
117 | 129 |
typedef void (transaction_cb) ( struct cell* t, struct sip_msg* msg, |
... | ... |
@@ -71,6 +71,7 @@ |
71 | 71 |
#include "../../dprint.h" |
72 | 72 |
#include "../../config.h" |
73 | 73 |
#include "../../parser/parser_f.h" |
74 |
+#include "../../parser/parse_from.h" |
|
74 | 75 |
#include "../../ut.h" |
75 | 76 |
#include "../../timer.h" |
76 | 77 |
#include "../../hash_func.h" |
... | ... |
@@ -141,54 +142,178 @@ struct cell *get_t() { return T; } |
141 | 142 |
void set_t(struct cell *t) { T=t; } |
142 | 143 |
void init_t() {global_msg_id=0; set_t(T_UNDEFINED);} |
143 | 144 |
|
145 |
+static inline int parse_dlg( struct sip_msg *msg ) |
|
146 |
+{ |
|
147 |
+ if (parse_headers(msg, HDR_FROM | HDR_CSEQ | HDR_TO, 0)==-1) { |
|
148 |
+ LOG(L_ERR, "ERROR: tid_matching: From or Cseq or To invalid\n"); |
|
149 |
+ return 0; |
|
150 |
+ } |
|
151 |
+ if (parse_from_header(msg)==-1) { |
|
152 |
+ LOG(L_ERR, "ERROR: tid_matching: From broken\n"); |
|
153 |
+ return 0; |
|
154 |
+ } |
|
155 |
+ /* To is automatically parsed through HDR_TO in parse bitmap, |
|
156 |
+ * we don't need to worry about it now |
|
157 |
+ if (parse_to_header(msg)==-1) { |
|
158 |
+ LOG(L_ERR, "ERROR: tid_matching: To broken\n"); |
|
159 |
+ return 0; |
|
160 |
+ } |
|
161 |
+ */ |
|
162 |
+ return 1; |
|
163 |
+} |
|
164 |
+ |
|
165 |
+/* is the ACK (p_msg) in p_msg dialog-wise equal to the INVITE (t_msg) |
|
166 |
+ * except to-tags? */ |
|
167 |
+static inline int partial_dlg_matching(struct sip_msg *t_msg, struct sip_msg *p_msg) |
|
168 |
+{ |
|
169 |
+ struct to_body *inv_from; |
|
170 |
+ |
|
171 |
+ if (!EQ_LEN(callid)) return 0; |
|
172 |
+ if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len) |
|
173 |
+ return 0; |
|
174 |
+ inv_from=get_from(t_msg); |
|
175 |
+ if (!inv_from) { |
|
176 |
+ LOG(L_ERR, "ERROR: partial_dlg_matching: INV/From not parsed\n"); |
|
177 |
+ return 0; |
|
178 |
+ } |
|
179 |
+ if (inv_from->tag_value.len!=get_from(p_msg)->tag_value.len) |
|
180 |
+ return 0; |
|
181 |
+ if (!EQ_STR(callid)) |
|
182 |
+ return 0; |
|
183 |
+ if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s, |
|
184 |
+ get_cseq(p_msg)->number.len)!=0) |
|
185 |
+ return 0; |
|
186 |
+ if (memcmp(inv_from->tag_value.s, get_from(p_msg)->tag_value.s, |
|
187 |
+ get_from(p_msg)->tag_value.len)!=0) |
|
188 |
+ return 0; |
|
189 |
+ return 1; |
|
190 |
+} |
|
191 |
+ |
|
192 |
+/* are to-tags in ACK/200 same as those we sent out? */ |
|
193 |
+static inline int dlg_matching(struct cell *p_cell, struct sip_msg *ack ) |
|
194 |
+{ |
|
195 |
+ if (get_to(ack)->tag_value.len!=p_cell->uas.local_totag.len) |
|
196 |
+ return 0; |
|
197 |
+ if (memcmp(get_to(ack)->tag_value.s,p_cell->uas.local_totag.s, |
|
198 |
+ p_cell->uas.local_totag.len)!=0) |
|
199 |
+ return 0; |
|
200 |
+ return 1; |
|
201 |
+} |
|
202 |
+ |
|
203 |
+static inline int ack_matching(struct cell *p_cell, struct sip_msg *p_msg) |
|
204 |
+{ |
|
205 |
+ /* partial dialog matching -- no to-tag, only from-tag, |
|
206 |
+ * callid, cseq number ; */ |
|
207 |
+ if (!partial_dlg_matching(p_cell->uas.request, p_msg)) |
|
208 |
+ return 0; |
|
209 |
+ |
|
210 |
+ /* if this transaction is proxied (as opposed to UAS) we're |
|
211 |
+ * done now -- we ignore to-tags; the ACK simply belongs to |
|
212 |
+ * this UAS part of dialog, whatever to-tag it gained |
|
213 |
+ */ |
|
214 |
+ if (p_cell->relaied_reply_branch!=-2) { |
|
215 |
+ return 2; /* e2e proxied ACK */ |
|
216 |
+ } |
|
217 |
+ /* it's a local dialog -- we wish to verify to-tags too */ |
|
218 |
+ if (dlg_matching(p_cell, p_msg)) { |
|
219 |
+ return 1; |
|
220 |
+ } |
|
221 |
+ return 0; |
|
222 |
+} |
|
223 |
+ |
|
224 |
+/* branch-based transaction matching */ |
|
225 |
+static inline int via_matching( struct via_body *inv_via, |
|
226 |
+ struct via_body *ack_via ) |
|
227 |
+{ |
|
228 |
+ if (inv_via->tid.len!=ack_via->tid.len) |
|
229 |
+ return 0; |
|
230 |
+ if (memcmp(inv_via->tid.s, ack_via->tid.s, |
|
231 |
+ ack_via->tid.len)!=0) |
|
232 |
+ return 0; |
|
233 |
+ /* ok, tid matches -- now make sure that the |
|
234 |
+ * originater matches too to avoid confusion with |
|
235 |
+ * different senders generating the same tid |
|
236 |
+ */ |
|
237 |
+ if (inv_via->host.len!=ack_via->host.len) |
|
238 |
+ return 0;; |
|
239 |
+ if (memcmp(inv_via->host.s, ack_via->host.s, |
|
240 |
+ ack_via->host.len)!=0) |
|
241 |
+ return 0; |
|
242 |
+ if (inv_via->port!=ack_via->port) |
|
243 |
+ return 0; |
|
244 |
+ if (inv_via->transport.len!=ack_via->transport.len) |
|
245 |
+ return 0; |
|
246 |
+ if (memcmp(inv_via->transport.s, ack_via->transport.s, |
|
247 |
+ ack_via->transport.len)!=0) |
|
248 |
+ return 0; |
|
249 |
+ /* everything matched -- we found it */ |
|
250 |
+ return 1; |
|
251 |
+} |
|
252 |
+ |
|
144 | 253 |
|
145 | 254 |
/* transaction matching a-la RFC-3261 using transaction ID in branch |
146 |
- * (the function assumes there is magic cookie in branch) */ |
|
255 |
+ (the function assumes there is magic cookie in branch) |
|
256 |
+ It returns: |
|
257 |
+ 2 if e2e ACK for a proxied transaction found |
|
258 |
+ 1 if found (covers ACK for local UAS) |
|
259 |
+ 0 if not found (trans undefined) |
|
260 |
+*/ |
|
147 | 261 |
|
148 |
-static struct cell *tid_matching( int hash_index, |
|
149 |
- struct via_body *via1, |
|
150 |
- enum request_method skip_method) |
|
262 |
+static int matching_3261( struct sip_msg *p_msg, struct cell **trans, |
|
263 |
+ enum request_method skip_method) |
|
151 | 264 |
{ |
152 | 265 |
struct cell *p_cell; |
153 | 266 |
struct sip_msg *t_msg; |
267 |
+ struct via_body *via1; |
|
268 |
+ int is_ack; |
|
269 |
+ int dlg_parsed; |
|
270 |
+ int ret; |
|
154 | 271 |
|
155 |
- |
|
272 |
+ via1=p_msg->via1; |
|
273 |
+ is_ack=p_msg->REQ_METHOD==METHOD_ACK; |
|
274 |
+ dlg_parsed=0; |
|
156 | 275 |
/* update parsed tid */ |
157 | 276 |
via1->tid.s=via1->branch->value.s+MCOOKIE_LEN; |
158 | 277 |
via1->tid.len=via1->branch->value.len-MCOOKIE_LEN; |
159 | 278 |
|
160 |
- for ( p_cell = get_tm_table()->entrys[hash_index].first_cell; |
|
279 |
+ for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell; |
|
161 | 280 |
p_cell; p_cell = p_cell->next_cell ) |
162 | 281 |
{ |
163 | 282 |
t_msg=p_cell->uas.request; |
164 | 283 |
if (skip_method & t_msg->REQ_METHOD) |
165 | 284 |
continue; |
166 |
- if (t_msg->via1->tid.len!=via1->tid.len) |
|
167 |
- continue; |
|
168 |
- if (memcmp(t_msg->via1->tid.s, via1->tid.s, |
|
169 |
- via1->tid.len)!=0) |
|
170 |
- continue; |
|
171 |
- /* ok, tid matches -- now make sure that the |
|
172 |
- * originater matches too to avoid confusion with |
|
173 |
- * different senders generating the same tid |
|
174 |
- */ |
|
175 |
- if (via1->host.len!=t_msg->via1->host.len) |
|
176 |
- continue; |
|
177 |
- if (memcmp(via1->host.s, t_msg->via1->host.s, |
|
178 |
- via1->host.len)!=0) |
|
179 |
- continue; |
|
180 |
- if (via1->port!=t_msg->via1->port) |
|
181 |
- continue; |
|
182 |
- if (via1->transport.len!=t_msg->via1->transport.len) |
|
285 |
+ |
|
286 |
+ /* dialog matching needs to be applied for ACK/200s */ |
|
287 |
+ if (is_ack && p_cell->uas.status<300) { |
|
288 |
+ /* make sure we have parsed all things we need for dialog |
|
289 |
+ * matching */ |
|
290 |
+ if (!dlg_parsed) { |
|
291 |
+ dlg_parsed=1; |
|
292 |
+ if (!parse_dlg(p_msg)) { |
|
293 |
+ LOG(L_ERR, "ERROR: tid_matching: dlg parsing failed\n"); |
|
294 |
+ return 0; |
|
295 |
+ } |
|
296 |
+ } |
|
297 |
+ ret=ack_matching(p_cell /* t w/invite */, p_msg /* ack */); |
|
298 |
+ if (ret>0) { |
|
299 |
+ *trans=p_cell; |
|
300 |
+ return ret; /* 2: e2e proxied ACK, 1 e2e UAS ACK */ |
|
301 |
+ } |
|
302 |
+ /* this ACK is neither local "negative" one, nor a proxied |
|
303 |
+ * end-2-end one, nor an end-2-end one for a UAS transaction |
|
304 |
+ * -- we failed to match */ |
|
183 | 305 |
continue; |
184 |
- if (memcmp(via1->transport.s, t_msg->via1->transport.s, |
|
185 |
- via1->transport.len)!=0) |
|
306 |
+ } |
|
307 |
+ /* now real tid matching occurs for negative ACKs and any |
|
308 |
+ * other requests */ |
|
309 |
+ if (!via_matching(t_msg->via1 /* inv via */, via1 /* ack */ )) |
|
186 | 310 |
continue; |
187 | 311 |
/* all matched -- we found the transaction ! */ |
188 | 312 |
DBG("DEBUG: RFC3261 transaction matched, tid=%.*s\n", |
189 | 313 |
via1->tid.len, via1->tid.s); |
190 | 314 |
|
191 |
- return p_cell; |
|
315 |
+ *trans=p_cell; |
|
316 |
+ return 1; |
|
192 | 317 |
} |
193 | 318 |
/* :-( ... we didn't find any */ |
194 | 319 |
DBG("DEBUG: RFC3261 transaction matching failed\n"); |
... | ... |
@@ -209,6 +334,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) |
209 | 334 |
struct sip_msg *t_msg; |
210 | 335 |
int ret; |
211 | 336 |
struct via_param *branch; |
337 |
+ int match_status; |
|
212 | 338 |
|
213 | 339 |
/* parse all*/ |
214 | 340 |
if (check_transaction_quadruple(p_msg)==0) |
... | ... |
@@ -221,8 +347,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) |
221 | 347 |
|
222 | 348 |
/* start searching into the table */ |
223 | 349 |
if (!p_msg->hash_index) |
224 |
- p_msg->hash_index=hash( p_msg->callid->body , |
|
225 |
- get_cseq(p_msg)->number ) ; |
|
350 |
+ p_msg->hash_index=hash( p_msg->callid->body , get_cseq(p_msg)->number ) ; |
|
226 | 351 |
isACK = p_msg->REQ_METHOD==METHOD_ACK; |
227 | 352 |
DBG("t_lookup_request: start searching: hash=%d, isACK=%d\n", |
228 | 353 |
p_msg->hash_index,isACK); |
... | ... |
@@ -245,29 +370,20 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) |
245 | 370 |
&& memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) { |
246 | 371 |
/* huhuhu! the cookie is there -- let's proceed fast */ |
247 | 372 |
LOCK_HASH(p_msg->hash_index); |
248 |
- p_cell=tid_matching(p_msg->hash_index, p_msg->via1, |
|
249 |
- /* skip transactions with different |
|
250 |
- * method; otherwise CANCEL would |
|
251 |
- * match the previous INVITE trans. |
|
252 |
- */ |
|
373 |
+ match_status=matching_3261(p_msg,&p_cell, |
|
374 |
+ /* skip transactions with different method; otherwise CANCEL would |
|
375 |
+ * match the previous INVITE trans. */ |
|
253 | 376 |
isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD); |
254 |
- if (p_cell) { |
|
255 |
- /* ACK/200 */ |
|
256 |
- if (isACK && p_cell->uas.status>=200 && p_cell->uas.status<300) { |
|
257 |
- /* perhaps there are some spirals on the synonym list, but |
|
258 |
- it makes no sense to iterate the list until bitter end */ |
|
259 |
- t_ack=p_cell; |
|
260 |
- ret=-2; |
|
261 |
- goto notfound; |
|
262 |
- } |
|
263 |
- /* all but 200/ACK */ |
|
264 |
- goto found; |
|
265 |
- } |
|
266 |
- /* new */ |
|
267 |
- goto notfound; |
|
377 |
+ switch(match_status) { |
|
378 |
+ case 0: goto notfound; /* no match */ |
|
379 |
+ case 1: goto found; /* match */ |
|
380 |
+ case 2: goto e2e_ack; /* e2e proxy ACK */ |
|
381 |
+ } |
|
268 | 382 |
} |
269 | 383 |
|
270 |
- /* ok -- it's ugly old-fashioned transaction matching */ |
|
384 |
+ /* ok -- it's ugly old-fashioned transaction matching -- it is |
|
385 |
+ * a bit simplified to be fast -- we don't do all the comparisons |
|
386 |
+ * of parsed uri, which was simply too bloated */ |
|
271 | 387 |
DBG("DEBUG: proceeding to pre-RFC3261 transaction matching\n"); |
272 | 388 |
|
273 | 389 |
/* lock the whole entry*/ |
... | ... |
@@ -303,63 +419,39 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) |
303 | 419 |
/* ACK's relate only to INVITEs */ |
304 | 420 |
if (t_msg->REQ_METHOD!=METHOD_INVITE) continue; |
305 | 421 |
|
422 |
+ /* From|To URI , CallID, CSeq # must be always there */ |
|
306 | 423 |
/* compare lengths now */ |
307 | 424 |
if (!EQ_LEN(callid)) continue; |
308 | 425 |
/* CSeq only the number without method ! */ |
309 | 426 |
if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len) |
310 | 427 |
continue; |
311 | 428 |
if (! EQ_LEN(from)) continue; |
312 |
- /* To only the uri and ... */ |
|
429 |
+ /* To only the uri -- to many UACs screw up tags */ |
|
313 | 430 |
if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len) |
314 | 431 |
continue; |
315 |
- /* don't care about to-tags -- many UAC screw them |
|
316 |
- * up anyway, and it doesn't hurt if we ignore |
|
317 |
- * them */ |
|
318 |
-#ifdef ACKTAG |
|
319 |
- /* ... its to-tag compared to reply's tag */ |
|
320 |
- if (p_cell->uas.to_tag.len!=get_to(p_msg)->tag_value.len) |
|
321 |
- continue; |
|
322 |
-#endif |
|
323 |
- |
|
324 |
- /* we first skip r-uri and Via and proceed with |
|
325 |
- content of other header-fields */ |
|
326 |
- |
|
327 |
- if ( memcmp(t_msg->callid->body.s, p_msg->callid->body.s, |
|
328 |
- p_msg->callid->body.len)!=0) continue; |
|
329 |
- if ( memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s, |
|
432 |
+ if (!EQ_STR(callid)) continue; |
|
433 |
+ if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s, |
|
330 | 434 |
get_cseq(p_msg)->number.len)!=0) continue; |
331 | 435 |
if (!EQ_STR(from)) continue; |
332 | 436 |
if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s, |
333 | 437 |
get_to(t_msg)->uri.len)!=0) continue; |
334 |
-#ifdef ACKTAG |
|
335 |
- if ( |
|
336 |
-#ifdef _BUG |
|
337 |
- p_cell->uas.to_tag.len!=0 /* to-tags empty */ || |
|
338 |
-#endif |
|
339 |
- memcmp(p_cell->uas.to_tag.s, get_to(p_msg)->tag_value.s, |
|
340 |
- p_cell->uas.to_tag.len)!=0) continue; |
|
341 |
-#endif |
|
342 |
- |
|
343 |
- /* ok, now only r-uri or via can mismatch; they must match |
|
344 |
- for non-2xx; if it is a 2xx, we don't try to match |
|
345 |
- (we might have checked that earlier to speed-up, but |
|
346 |
- we still want to see a diagnosti message telling |
|
347 |
- "this ACK presumably belongs to this 2xx transaction"; |
|
348 |
- might change in future); the reason is 2xx ACKs are |
|
349 |
- a separate transaction which may carry different |
|
350 |
- r-uri/via1 and is thus also impossible to match it |
|
351 |
- uniquely to a spiraled transaction; |
|
352 |
- */ |
|
353 |
- if (p_cell->uas.status>=200 && p_cell->uas.status<300) { |
|
354 |
- DBG("DEBUG: an ACK hit a 2xx transaction (T=%p); " |
|
355 |
- "considered mismatch\n", p_cell ); |
|
356 |
- /* perhaps there are some spirals on the synonym list, but |
|
357 |
- it makes no sense to iterate the list until bitter end */ |
|
358 |
- t_ack=p_cell; |
|
359 |
- ret=-2; |
|
360 |
- break; |
|
438 |
+ |
|
439 |
+ /* it is e2e ACK/200 */ |
|
440 |
+ if (p_cell->uas.status<300) { |
|
441 |
+ /* all criteria for proxied ACK are ok */ |
|
442 |
+ if (p_cell->relaied_reply_branch!=-2) |
|
443 |
+ goto e2e_ack; |
|
444 |
+ /* it's a local UAS transaction */ |
|
445 |
+ if (dlg_matching(p_cell, p_msg)) |
|
446 |
+ goto found; |
|
447 |
+ continue; |
|
361 | 448 |
} |
362 |
- /* its for a >= 300 ... everything must match ! */ |
|
449 |
+ |
|
450 |
+ /* it is not an e2e ACK/200 -- perhaps it is |
|
451 |
+ * local negative case; in which case we will want |
|
452 |
+ * more elements to match: r-uri and via; allow |
|
453 |
+ * mismatching r-uri as an config option for broken |
|
454 |
+ * UACs */ |
|
363 | 455 |
if (ruri_matching && ! EQ_REQ_URI_LEN ) continue; |
364 | 456 |
if (! EQ_VIA_LEN(via1)) continue; |
365 | 457 |
if (ruri_matching && !EQ_REQ_URI_STR) continue; |
... | ... |
@@ -378,12 +470,21 @@ notfound: |
378 | 470 |
UNLOCK_HASH(p_msg->hash_index); |
379 | 471 |
} |
380 | 472 |
DBG("DEBUG: t_lookup_request: no transaction found\n"); |
381 |
- return ret; |
|
473 |
+ return -1; |
|
474 |
+ |
|
475 |
+e2e_ack: |
|
476 |
+ t_ack=p_cell; /* e2e proxied ACK */ |
|
477 |
+ set_t(0); |
|
478 |
+ if (!leave_new_locked) { |
|
479 |
+ UNLOCK_HASH(p_msg->hash_index); |
|
480 |
+ } |
|
481 |
+ DBG("DEBUG: t_lookup_request: e2e proxy ACK found\n"); |
|
482 |
+ return -2; |
|
382 | 483 |
|
383 | 484 |
found: |
384 | 485 |
set_t(p_cell); |
385 | 486 |
REF_UNSAFE( T ); |
386 |
- set_kr(T, REQ_EXIST); |
|
487 |
+ set_kr(REQ_EXIST); |
|
387 | 488 |
UNLOCK_HASH( p_msg->hash_index ); |
388 | 489 |
DBG("DEBUG: t_lookup_request: transaction found (T=%p)\n",T); |
389 | 490 |
return 1; |
... | ... |
@@ -402,6 +503,7 @@ struct cell* t_lookupOriginalT( struct sip_msg* p_msg ) |
402 | 503 |
unsigned int hash_index; |
403 | 504 |
struct sip_msg *t_msg; |
404 | 505 |
struct via_param *branch; |
506 |
+ int ret; |
|
405 | 507 |
|
406 | 508 |
|
407 | 509 |
/* start searching in the table */ |
... | ... |
@@ -423,12 +525,12 @@ struct cell* t_lookupOriginalT( struct sip_msg* p_msg ) |
423 | 525 |
&& memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) { |
424 | 526 |
/* huhuhu! the cookie is there -- let's proceed fast */ |
425 | 527 |
LOCK_HASH(hash_index); |
426 |
- p_cell=tid_matching(hash_index, p_msg->via1, |
|
528 |
+ ret=matching_3261(p_msg, &p_cell, |
|
427 | 529 |
/* we are seeking the original transaction -- |
428 | 530 |
* skip CANCEL transactions during search |
429 | 531 |
*/ |
430 | 532 |
METHOD_CANCEL); |
431 |
- if (p_cell) goto found; else goto notfound; |
|
533 |
+ if (ret==1) goto found; else goto notfound; |
|
432 | 534 |
} |
433 | 535 |
|
434 | 536 |
/* no cookies --proceed to old-fashioned pre-3261 t-matching */ |
... | ... |
@@ -658,6 +760,23 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) |
658 | 760 |
REF_UNSAFE( T ); |
659 | 761 |
UNLOCK_HASH(hash_index); |
660 | 762 |
DBG("DEBUG: t_reply_matching: reply matched (T=%p)!\n",T); |
763 |
+ /* if this is a 200 for INVITE, we will wish to store to-tags to be |
|
764 |
+ * able to distuingish retransmissions later and not to call |
|
765 |
+ * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are |
|
766 |
+ * enabled -- except callback customers, nobody cares about |
|
767 |
+ * retransmissions of multiple 200/INV or ACK/200s |
|
768 |
+ */ |
|
769 |
+ if (p_cell->is_invite && p_msg->REPLY_STATUS>=200 |
|
770 |
+ && p_msg->REPLY_STATUS<300 |
|
771 |
+ && ( (!p_cell->local && |
|
772 |
+ (callback_array[TMCB_RESPONSE_OUT]|| |
|
773 |
+ callback_array[TMCB_E2EACK_IN])) |
|
774 |
+ || (p_cell->local && callback_array[TMCB_LOCAL_COMPLETED]) )) { |
|
775 |
+ if (parse_headers(p_msg, HDR_TO, 0)==-1) { |
|
776 |
+ LOG(L_ERR, "ERROR: t_reply_matching: to parsing failed\n"); |
|
777 |
+ } |
|
778 |
+ } |
|
779 |
+ callback_event(TMCB_RESPONSE_IN, T, p_msg, p_msg->REPLY_STATUS); |
|
661 | 780 |
return 1; |
662 | 781 |
} /* for cycle */ |
663 | 782 |
|
... | ... |
@@ -675,10 +794,12 @@ nomatch2: |
675 | 794 |
|
676 | 795 |
|
677 | 796 |
|
678 |
-/* Functions update T (T gets either a valid pointer in it or it equals zero) if no transaction |
|
679 |
- * for current message exists; |
|
680 |
- * it returns 1 if found, 0 if not found, -1 on error |
|
681 |
- */ |
|
797 |
+/* Determine current transaction |
|
798 |
+ * |
|
799 |
+ * Found Not Found Error (e.g. parsing) |
|
800 |
+ * Return Value 1 0 -1 |
|
801 |
+ * T ptr 0 T_UNDEFINED |
|
802 |
+ */ |
|
682 | 803 |
int t_check( struct sip_msg* p_msg , int *param_branch ) |
683 | 804 |
{ |
684 | 805 |
int local_branch; |
... | ... |
@@ -693,8 +814,20 @@ int t_check( struct sip_msg* p_msg , int *param_branch ) |
693 | 814 |
/* transaction lookup */ |
694 | 815 |
if ( p_msg->first_line.type==SIP_REQUEST ) { |
695 | 816 |
/* force parsing all the needed headers*/ |
696 |
- if (parse_headers(p_msg, HDR_EOH, 0 )==-1) |
|
817 |
+ if (parse_headers(p_msg, HDR_EOH, 0 )==-1) { |
|
818 |
+ LOG(L_ERR, "ERROR: t_check: parsing error\n"); |
|
697 | 819 |
return -1; |
820 |
+ } |
|
821 |
+ /* in case, we act as UAS for INVITE and reply with 200, |
|
822 |
+ * we will need to run dialog-matching for subsequent |
|
823 |
+ * ACK, for which we need From-tag; We also need from-tag |
|
824 |
+ * in case people want to have proxied e2e ACKs accounted |
|
825 |
+ */ |
|
826 |
+ if (p_msg->REQ_METHOD==METHOD_INVITE |
|
827 |
+ && parse_from_header(p_msg)==-1) { |
|
828 |
+ LOG(L_ERR, "ERROR: t_check: from parsing failed\n"); |
|
829 |
+ return -1; |
|
830 |
+ } |
|
698 | 831 |
t_lookup_request( p_msg , 0 /* unlock before returning */ ); |
699 | 832 |
} else { |
700 | 833 |
/* we need Via for branch and Cseq method to distinguish |
... | ... |
@@ -738,7 +871,7 @@ int t_check( struct sip_msg* p_msg , int *param_branch ) |
738 | 871 |
DBG("DEBUG: t_check: T previously sought and not found\n"); |
739 | 872 |
} |
740 | 873 |
|
741 |
- return ((T)?1:0) ; |
|
874 |
+ return T ? (T==T_UNDEFINED ? -1 : 1 ) : 0; |
|
742 | 875 |
} |
743 | 876 |
|
744 | 877 |
int init_rb( struct retr_buf *rb, struct sip_msg *msg) |
... | ... |
@@ -840,6 +973,21 @@ int t_newtran( struct sip_msg* p_msg ) |
840 | 973 |
if (lret<0) { |
841 | 974 |
new_cell=0; |
842 | 975 |
if ( p_msg->REQ_METHOD!=METHOD_ACK ) { |
976 |
+ /* REVIEW */ |
|
977 |
+ /* for ACK-dlw-wise matching, we want From-tags */ |
|
978 |
+ if (p_msg->REQ_METHOD==METHOD_INVITE) { |
|
979 |
+ if (parse_from_header(p_msg)<0) { |
|
980 |
+ LOG(L_ERR, "ERROR: t_newtran: no valid From\n"); |
|
981 |
+ return E_BAD_REQ; |
|
982 |
+ } |
|
983 |
+ } |
|
984 |
+ /* REVIEW */ |
|
985 |
+ /* make sure uri will be parsed before cloning */ |
|
986 |
+ if (parse_sip_msg_uri(p_msg)<0) { |
|
987 |
+ LOG(L_ERR, "ERROR: t_new_tran: uri invalid\n"); |
|
988 |
+ return E_BAD_REQ; |
|
989 |
+ } |
|
990 |
+ |
|
843 | 991 |
/* add new transaction */ |
844 | 992 |
new_cell = build_cell( p_msg ) ; |
845 | 993 |
if ( !new_cell ){ |
... | ... |
@@ -867,6 +1015,7 @@ int t_newtran( struct sip_msg* p_msg ) |
867 | 1015 |
|
868 | 1016 |
new_cell->method=new_cell->uas.request->first_line.u.request.method; |
869 | 1017 |
new_cell->is_invite=p_msg->REQ_METHOD==METHOD_INVITE; |
1018 |
+ |
|
870 | 1019 |
} |
871 | 1020 |
|
872 | 1021 |
} |
... | ... |
@@ -875,7 +1024,9 @@ int t_newtran( struct sip_msg* p_msg ) |
875 | 1024 |
if (lret==-2) { |
876 | 1025 |
REF_UNSAFE(t_ack); |
877 | 1026 |
UNLOCK_HASH(p_msg->hash_index); |
878 |
- callback_event( TMCB_E2EACK, t_ack, p_msg, p_msg->REQ_METHOD ); |
|
1027 |
+ if (unmatched_totag(t_ack, p_msg)) { |
|
1028 |
+ callback_event( TMCB_E2EACK_IN, t_ack, p_msg, p_msg->REQ_METHOD ); |
|
1029 |
+ } |
|
879 | 1030 |
UNREF(t_ack); |
880 | 1031 |
} else { /* not e2e ACK */ |
881 | 1032 |
UNLOCK_HASH(p_msg->hash_index); |
... | ... |
@@ -915,10 +1066,13 @@ int t_newtran( struct sip_msg* p_msg ) |
915 | 1066 |
|
916 | 1067 |
int t_unref( struct sip_msg* p_msg ) |
917 | 1068 |
{ |
1069 |
+ enum kill_reason kr; |
|
1070 |
+ |
|
918 | 1071 |
if (T==T_UNDEFINED || T==T_NULL_CELL) |
919 | 1072 |
return -1; |
920 |
- if (T->kr==0 |
|
921 |
- ||(p_msg->REQ_METHOD==METHOD_ACK && !(T->kr & REQ_RLSD))) { |
|
1073 |
+ kr=get_kr(); |
|
1074 |
+ if (kr==0 |
|
1075 |
+ ||(p_msg->REQ_METHOD==METHOD_ACK && !(kr & REQ_RLSD))) { |
|
922 | 1076 |
LOG(L_WARN, "WARNING: script writer didn't release transaction\n"); |
923 | 1077 |
t_release_transaction(T); |
924 | 1078 |
} |
... | ... |
@@ -927,7 +1081,6 @@ int t_unref( struct sip_msg* p_msg ) |
927 | 1081 |
return 1; |
928 | 1082 |
} |
929 | 1083 |
|
930 |
-#ifdef VOICE_MAIL |
|
931 | 1084 |
int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label) |
932 | 1085 |
{ |
933 | 1086 |
struct cell* t; |
... | ... |
@@ -947,14 +1100,13 @@ int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned |
947 | 1100 |
return 1; |
948 | 1101 |
} |
949 | 1102 |
|
950 |
-int t_lookup_ident(struct sip_msg** p_msg, unsigned int hash_index, unsigned int label) |
|
1103 |
+int t_lookup_ident(struct cell ** trans, unsigned int hash_index, unsigned int label) |
|
951 | 1104 |
{ |
952 |
- int ret = 0; |
|
953 | 1105 |
struct cell* p_cell; |
954 | 1106 |
|
955 | 1107 |
if(hash_index >= TABLE_ENTRIES){ |
956 |
- LOG(L_ERR,"ERROR: t_lookup_ident: invalid hash_index=%u\n",hash_index); |
|
957 |
- return -1; |
|
1108 |
+ LOG(L_ERR,"ERROR: t_lookup_ident: invalid hash_index=%u\n",hash_index); |
|
1109 |
+ return -1; |
|
958 | 1110 |
} |
959 | 1111 |
|
960 | 1112 |
LOCK_HASH(hash_index); |
... | ... |
@@ -963,21 +1115,23 @@ int t_lookup_ident(struct sip_msg** p_msg, unsigned int hash_index, unsigned int |
963 | 1115 |
for ( p_cell = get_tm_table()->entrys[hash_index].first_cell; |
964 | 1116 |
p_cell; p_cell = p_cell->next_cell ) |
965 | 1117 |
{ |
966 |
- if(p_cell->label == label){ |
|
967 |
- ret = 1; |
|
968 |
- break; |
|
969 |
- } |
|
1118 |
+ if(p_cell->label == label){ |
|
1119 |
+ REF_UNSAFE(p_cell); |
|
1120 |
+ UNLOCK_HASH(hash_index); |
|
1121 |
+ set_t(p_cell); |
|
1122 |
+ *trans=p_cell; |
|
1123 |
+ DBG("DEBUG: t_lookup_ident: transaction found\n"); |
|
1124 |
+ return 1; |
|
1125 |
+ } |
|
970 | 1126 |
} |
1127 |
+ |
|
1128 |
+ UNLOCK_HASH(hash_index); |
|
1129 |
+ set_t(0); |
|
1130 |
+ *trans=p_cell; |
|
971 | 1131 |
|
972 |
- if(ret==1){ |
|
973 |
- DBG("DEBUG: t_lookup_ident: transaction found\n"); |
|
974 |
- *p_msg = p_cell->uas.request; |
|
975 |
- } |
|
976 |
- else |
|
977 | 1132 |
DBG("DEBUG: t_lookup_ident: transaction not found\n"); |
978 | 1133 |
|
979 |
- UNLOCK_HASH(hash_index); |
|
980 |
- return ret; |
|
1134 |
+ return -1; |
|
981 | 1135 |
} |
982 | 1136 |
|
983 | 1137 |
int t_is_local(struct sip_msg* p_msg) |
... | ... |
@@ -995,8 +1149,3 @@ int t_is_local(struct sip_msg* p_msg) |
995 | 1149 |
|
996 | 1150 |
return t->local; |
997 | 1151 |
} |
998 |
- |
|
999 |
-#endif |
|
1000 |
- |
|
1001 |
- |
|
1002 |
- |
... | ... |
@@ -75,7 +75,6 @@ struct cell *get_t(); |
75 | 75 |
* primarily set by lookup functions */ |
76 | 76 |
void set_t(struct cell *t); |
77 | 77 |
|
78 |
-#ifdef VOICE_MAIL |
|
79 | 78 |
|
80 | 79 |
#define T_GET_TI "t_get_trans_ident" |
81 | 80 |
#define T_LOOKUP_IDENT "t_lookup_ident" |
... | ... |
@@ -83,12 +82,11 @@ void set_t(struct cell *t); |
83 | 82 |
|
84 | 83 |
typedef int (*tislocal_f)(struct sip_msg*); |
85 | 84 |
typedef int (*tget_ti_f)(struct sip_msg*, unsigned int*, unsigned int*); |
86 |
-typedef int (*tlookup_ident_f)(struct sip_msg**, unsigned int, unsigned int); |
|
85 |
+typedef int (*tlookup_ident_f)(struct cell**, unsigned int, unsigned int); |
|
87 | 86 |
|
88 | 87 |
int t_is_local(struct sip_msg*); |
89 | 88 |
int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label); |
90 |
-int t_lookup_ident(struct sip_msg** p_msg, unsigned int hash_index, unsigned int label); |
|
91 |
-#endif |
|
89 |
+int t_lookup_ident(struct cell** trans, unsigned int hash_index, unsigned int label); |
|
92 | 90 |
|
93 | 91 |
#endif |
94 | 92 |
|
... | ... |
@@ -36,12 +36,15 @@ |
36 | 36 |
* 2003-01-19 faked lump list created in on_reply handlers |
37 | 37 |
*/ |
38 | 38 |
|
39 |
+ |
|
40 |
+#include <assert.h> |
|
39 | 41 |
#include "defs.h" |
40 | 42 |
|
41 | 43 |
#include "../../comp_defs.h" |
42 | 44 |
|
43 | 45 |
#include "../../hash_func.h" |
44 | 46 |
#include "t_funcs.h" |
47 |
+#include "h_table.h" |
|
45 | 48 |
#include "../../dprint.h" |
46 | 49 |
#include "../../config.h" |
47 | 50 |
#include "../../parser/parser_f.h" |
... | ... |
@@ -73,6 +76,7 @@ static char *tm_tag_suffix; |
73 | 76 |
/* where to go if there is no positive reply */ |
74 | 77 |
static int goto_on_negative=0; |
75 | 78 |
|
79 |
+ |
|
76 | 80 |
/* we store the reply_route # in private memory which is |
77 | 81 |
then processed during t_relay; we cannot set this value |
78 | 82 |
before t_relay creates transaction context or after |
... | ... |
@@ -101,6 +105,88 @@ void tm_init_tags() |
101 | 105 |
"SER-TM/tags", TM_TAG_SEPARATOR ); |
102 | 106 |
} |
103 | 107 |
|
108 |
+/* returns 0 if the message was previously acknowledged |
|
109 |
+ * (i.e., no E2EACK callback is needed) and one if the |
|
110 |
+ * callback shall be executed */ |
|
111 |
+int unmatched_totag(struct cell *t, struct sip_msg *ack) |
|
112 |
+{ |
|
113 |
+ struct totag_elem *i; |
|
114 |
+ str *tag; |
|
115 |
+ |
|
116 |
+ if (parse_headers(ack, HDR_TO,0)==-1 || |
|
117 |
+ !ack->to ) { |
|
118 |
+ LOG(L_ERR, "ERROR: ack_totag_set: To invalid\n"); |
|
119 |
+ return 1; |
|
120 |
+ } |
|
121 |
+ tag=&get_to(ack)->tag_value; |
|
122 |
+ for (i=t->fwded_totags; i; i=i->next) { |
|
123 |
+ if (i->tag.len==tag->len |
|
124 |
+ && memcmp(i->tag.s, tag->s, tag->len)==0) { |
|
125 |
+ DBG("DEBUG: totag for e2e ACK found: %d\n", i->acked); |
|
126 |
+ /* to-tag recorded, and an ACK has been received for it */ |
|
127 |
+ if (i->acked) return 0; |
|
128 |
+ /* to-tag recorded, but this ACK came for the first time */ |
|
129 |
+ i->acked=1; |
|
130 |
+ return 1; |
|
131 |
+ } |
|
132 |
+ } |
|
133 |
+ /* surprising: to-tag never sighted before */ |
|
134 |
+ return 1; |
|
135 |
+} |
|
136 |
+ |
|
137 |
+ |
|
138 |
+/* append a newly received tag from a 200/INVITE to |
|
139 |
+ * transaction's set; (only safe if called from within |
|
140 |
+ * a REPLY_LOCK); it returns 1 if such a to tag already |
|
141 |
+ * exists |
|
142 |
+ */ |
|
143 |
+inline static int update_totag_set(struct cell *t, struct sip_msg *ok) |
|
144 |
+{ |
|
145 |
+ struct totag_elem *i, *n; |
|
146 |
+ str *tag; |
|
147 |
+ char *s; |
|
148 |
+ |
|
149 |
+ if (!ok->to || !ok->to->parsed) { |
|
150 |
+ LOG(L_ERR, "ERROR: update_totag_set: to not parsed\n"); |
|
151 |
+ return 0; |
|
152 |
+ } |
|
153 |
+ tag=&get_to(ok)->tag_value; |
|
154 |
+ if (!tag->s) { |
|
155 |
+ LOG(L_ERR, "ERROR: update_totag_set: no tag in to\n"); |
|
156 |
+ return 0; |
|
157 |
+ } |
|
158 |
+ |
|
159 |
+ for (i=t->fwded_totags; i; i=i->next) { |
|
160 |
+ if (i->tag.len==tag->len |
|
161 |
+ && memcmp(i->tag.s, tag->s, tag->len) ==0 ) |
|
162 |
+ /* to tag already recorded */ |
|
163 |
+#ifdef XL_DEBUG |
|
164 |
+ LOG(L_CRIT, "DEBUG: update_totag_set: totag retranmission\n"); |
|
165 |
+#else |
|
166 |
+ DBG("DEBUG: update_totag_set: totag retranmission\n"); |
|
167 |
+#endif |
|
168 |
+ return 1; |
|
169 |
+ } |
|
170 |
+ /* that's a new to-tag -- record it */ |
|
171 |
+ shm_lock(); |
|
172 |
+ n=(struct totag_elem*) shm_malloc_unsafe(sizeof(struct totag_elem)); |
|
173 |
+ s=(char *)shm_malloc_unsafe(tag->len); |
|
174 |
+ shm_unlock(); |
|
175 |
+ if (!s || !n) { |
|
176 |
+ LOG(L_ERR, "ERROR: update_totag_set: no memory \n"); |
|
177 |
+ if (n) shm_free(n); |
|
178 |
+ if (s) shm_free(s); |
|
179 |
+ return 0; |
|
180 |
+ } |
|
181 |
+ memset(n, 0, sizeof(struct totag_elem)); |
|
182 |
+ memcpy(s, tag->s, tag->len ); |
|
183 |
+ n->tag.s=s;n->tag.len=tag->len; |
|
184 |
+ n->next=t->fwded_totags; |
|
185 |
+ t->fwded_totags=n; |
|
186 |
+ DBG("DEBUG: update_totag_set: new totag \n"); |
|
187 |
+ return 0; |
|
188 |
+} |
|
189 |
+ |
|
104 | 190 |
|
105 | 191 |
static char *build_ack(struct sip_msg* rpl,struct cell *trans,int branch, |
106 | 192 |
unsigned int *ret_len) |
... | ... |
@@ -315,7 +401,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code, |
315 | 401 |
/* no more pending branches -- try if that changes after |
316 | 402 |
a callback |
317 | 403 |
*/ |
318 |
- callback_event( TMCB_ON_NEGATIVE, Trans, |
|
404 |
+ callback_event( TMCB_ON_FAILURE, Trans, |
|
319 | 405 |
lowest_b==branch?reply:Trans->uac[lowest_b].reply, |
320 | 406 |
lowest_s ); |
321 | 407 |
|
... | ... |
@@ -458,18 +544,7 @@ error: |
458 | 544 |
} |
459 | 545 |
|
460 | 546 |
|
461 |
-#ifdef VOICE_MAIL |
|
462 |
-static int _reply_light( struct cell *trans, char* buf, unsigned int len, |
|
463 |
- unsigned int code, char * text, |
|
464 |
- char *to_tag, unsigned int to_tag_len, int lock ); |
|
465 | 547 |
|
466 |
-int t_reply_light( struct cell *t, char* buf, unsigned int len, |
|
467 |
- unsigned int code, char * text, |
|
468 |
- char *to_tag, unsigned int to_tag_len ) |
|
469 |
-{ |
|
470 |
- return _reply_light( t, buf, len, code, text, to_tag, to_tag_len, 1 /* lock replies */ ); |
|
471 |
-} |
|
472 |
-#endif |
|
473 | 548 |
|
474 | 549 |
int t_reply( struct cell *t, struct sip_msg* p_msg, unsigned int code, |
475 | 550 |
char * text ) |
... | ... |
@@ -484,69 +559,26 @@ int t_reply_unsafe( struct cell *t, struct sip_msg* p_msg, unsigned int code, |
484 | 559 |
} |
485 | 560 |
|
486 | 561 |
|
487 |
- |
|
488 |
-/* send a UAS reply |
|
489 |
- * returns 1 if everything was OK or -1 for error |
|
490 |
- */ |
|
491 |
-static int _reply( struct cell *trans, struct sip_msg* p_msg, |
|
492 |
- unsigned int code, char * text, int lock ) |
|
562 |
+static inline void update_local_tags(struct cell *trans, |
|
563 |
+ struct bookmark *bm, char *dst_buffer, |
|
564 |
+ char *src_buffer /* to which bm refers */) |
|
493 | 565 |
{ |
494 |
-#ifndef VOICE_MAIL |
|
495 |
- unsigned int len, buf_len=0; |
|
496 |
- char * buf; |
|
497 |
- struct retr_buf *rb; |
|
498 |
- |
|
499 |
- branch_bm_t cancel_bitmap; |
|
500 |
-#else |
|
501 |
- unsigned int len; |
|
502 |
- char * buf; |
|
503 |
-#endif |
|
504 |
- |
|
505 |
- if (code>=200) set_kr(trans,REQ_RPLD); |
|
506 |
- /* |
|
507 |
- buf = build_res_buf_from_sip_req(code,text,trans->uas.tag->s, |
|
508 |
- trans->uas.tag->len, trans->uas.request,&len); |
|
509 |
- */ |
|
510 |
-#ifndef VOICE_MAIL |
|
511 |
- cancel_bitmap=0; |
|
512 |
-#endif |
|
513 |
- /* compute the buffer in private memory prior to entering lock; |
|
514 |
- * create to-tag if needed */ |
|
515 |
- if (code>=180 && p_msg->to |
|
516 |
- && (get_to(p_msg)->tag_value.s==0 |
|
517 |
- || get_to(p_msg)->tag_value.len==0)) { |
|
518 |
- calc_crc_suffix( p_msg, tm_tag_suffix ); |
|
519 |
- buf = build_res_buf_from_sip_req(code,text, |
|
520 |
- tm_tags, TOTAG_VALUE_LEN, |
|
521 |
- p_msg,&len); |
|
522 |
-#ifdef VOICE_MAIL |
|
523 |
- |
|
524 |
- return _reply_light(trans,buf,len,code,text, |
|
525 |
- tm_tags, TOTAG_VALUE_LEN, |
|
526 |
- lock); |
|
527 |
-#endif |
|
528 |
- } else { |
|
529 |
- buf = build_res_buf_from_sip_req(code,text, 0,0, /* no to-tag */ |
|
530 |
- p_msg,&len); |
|
531 |
-#ifdef VOICE_MAIL |
|
532 |
- |
|
533 |
- return _reply_light(trans,buf,len,code,text, |
|
534 |
- 0,0, /* no to-tag */ |
|
535 |
- lock); |
|
536 |
-#endif |
|
566 |
+ if (bm->to_tag_val.s) { |
|
567 |
+ trans->uas.local_totag.s=bm->to_tag_val.s-src_buffer+dst_buffer; |
|
568 |
+ trans->uas.local_totag.len=bm->to_tag_val.len; |
|
537 | 569 |
} |
538 |
- DBG("DEBUG: t_reply: buffer computed\n"); |
|
539 |
-#ifdef VOICE_MAIL |
|
540 | 570 |
} |
541 | 571 |
|
572 |
+ |
|
542 | 573 |
static int _reply_light( struct cell *trans, char* buf, unsigned int len, |
543 | 574 |
unsigned int code, char * text, |
544 |
- char *to_tag, unsigned int to_tag_len, int lock ) |
|
575 |
+ char *to_tag, unsigned int to_tag_len, int lock, |
|
576 |
+ struct bookmark *bm ) |
|
545 | 577 |
{ |
546 | 578 |
struct retr_buf *rb; |
547 |
- unsigned int buf_len=0; |
|
548 |
- branch_bm_t cancel_bitmap=0; |
|
549 |
-#endif |
|
579 |
+ unsigned int buf_len; |
|
580 |
+ branch_bm_t cancel_bitmap; |
|
581 |
+ |
|
550 | 582 |
if (!buf) |
551 | 583 |
{ |
552 | 584 |
DBG("DEBUG: t_reply: response building failed\n"); |
... | ... |
@@ -560,6 +592,7 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len, |
560 | 592 |
goto error; |
561 | 593 |
} |
562 | 594 |
|
595 |
+ cancel_bitmap=0; |
|
563 | 596 |
if (lock) LOCK_REPLIES( trans ); |
564 | 597 |
if (trans->is_invite) which_cancel(trans, &cancel_bitmap ); |
565 | 598 |
if (trans->uas.status>=200) { |
... | ... |
@@ -567,6 +600,19 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len, |
567 | 600 |
" when a final %d was sent out\n", code, trans->uas.status); |
568 | 601 |
goto error2; |
569 | 602 |
} |
603 |
+ |
|
604 |
+#ifdef _TOTAG |
|
605 |
+ if(to_tag){ |
|
606 |
+ trans->uas.to_tag.s = (char*)shm_resize( trans->uas.to_tag.s, to_tag_len ); |
|
607 |
+ if(! trans->uas.to_tag.s ){ |
|
608 |
+ LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n"); |
|
609 |
+ goto error2; |
|
610 |
+ } |
|
611 |
+ trans->uas.to_tag.len = to_tag_len; |
|
612 |
+ memcpy( trans->uas.to_tag.s, to_tag, to_tag_len ); |
|
613 |
+ } |
|
614 |
+#endif |
|
615 |
+ |
|
570 | 616 |
rb = & trans->uas.response; |
571 | 617 |
rb->activ_type=code; |
572 | 618 |
|
... | ... |
@@ -576,27 +622,17 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len, |
576 | 622 |
/* puts the reply's buffer to uas.response */ |
577 | 623 |
if (! rb->buffer ) { |
578 | 624 |
LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n"); |
579 |
- goto error2; |
|
625 |
+ goto error3; |
|
580 | 626 |
} |
627 |
+ update_local_tags(trans, bm, rb->buffer, buf); |
|
628 |
+ |
|
581 | 629 |
rb->buffer_len = len ; |
582 | 630 |
memcpy( rb->buffer , buf , len ); |
583 |
-#ifdef VOICE_MAIL |
|
584 |
- if(to_tag){ |
|
585 |
- trans->uas.to_tag.s = (char*)shm_resize( trans->uas.to_tag.s, to_tag_len ); |
|
586 |
- if(! trans->uas.to_tag.s ){ |
|
587 |
- LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n"); |
|
588 |
- // Is it ok? or should i free rb->buffer also, |
|
589 |
- // or will it be freed in free_cell() ? |
|
590 |
- goto error2; |
|
591 |
- } |
|
592 |
- trans->uas.to_tag.len = to_tag_len; |
|
593 |
- memcpy( trans->uas.to_tag.s, to_tag, to_tag_len ); |
|
594 |
- } |
|
595 |
-#endif |
|
596 | 631 |
/* needs to be protected too because what timers are set depends |
597 | 632 |
on current transactions status */ |
598 | 633 |
/* t_update_timers_after_sending_reply( rb ); */ |
599 | 634 |
update_reply_stats( code ); |
635 |
+ trans->relaied_reply_branch=-2; |
|
600 | 636 |
tm_stats->replied_localy++; |
601 | 637 |
if (lock) UNLOCK_REPLIES( trans ); |
602 | 638 |
|
... | ... |
@@ -609,7 +645,7 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len, |
609 | 645 |
if (trans->completion_cb) |
610 | 646 |
trans->completion_cb( trans, FAKED_REPLY, code, 0 /* empty param */); |
611 | 647 |
} else { |
612 |
- callback_event( TMCB_REPLY, trans, FAKED_REPLY, code ); |
|
648 |
+ callback_event( TMCB_RESPONSE_OUT, trans, FAKED_REPLY, code ); |
|
613 | 649 |
} |
614 | 650 |
|
615 | 651 |
cleanup_uac_timers( trans ); |
... | ... |
@@ -632,6 +668,13 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len, |
632 | 668 |
DBG("DEBUG: t_reply: finished\n"); |
633 | 669 |
return 1; |
634 | 670 |
|
671 |
+error3: |
|
672 |
+#ifdef _TOTAG |
|
673 |
+ if (totag) { |
|
674 |
+ shm_free(trans->uas.to_tag.s); |
|
675 |
+ trans->uas.to_tag.s=0; |
|
676 |
+ } |
|
677 |
+#endif |
|
635 | 678 |
error2: |
636 | 679 |
if (lock) UNLOCK_REPLIES( trans ); |
637 | 680 |
pkg_free ( buf ); |
... | ... |
@@ -644,11 +687,47 @@ error: |
644 | 687 |
return -1; |
645 | 688 |
} |
646 | 689 |
|
690 |
+/* send a UAS reply |
|
691 |
+ * returns 1 if everything was OK or -1 for error |
|
692 |
+ */ |
|
693 |
+static int _reply( struct cell *trans, struct sip_msg* p_msg, |
|
694 |
+ unsigned int code, char * text, int lock ) |
|
695 |
+{ |
|
696 |
+ unsigned int len; |
|
697 |
+ char * buf; |
|
698 |
+ struct bookmark bm; |
|
699 |
+ |
|
700 |
+ if (code>=200) set_kr(REQ_RPLD); |
|
701 |