1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,640 @@ |
1 |
+#include "t_funcs.h" |
|
2 |
+ |
|
3 |
+struct cell *T; |
|
4 |
+unsigned int global_msg_id; |
|
5 |
+struct s_table* hash_table; |
|
6 |
+ |
|
7 |
+struct cell* t_lookupOriginalT( struct s_table* hash_table , struct sip_msg* p_msg ); |
|
8 |
+ |
|
9 |
+int t_reply_matching( struct s_table* , struct sip_msg* , struct cell** , unsigned int* ); |
|
10 |
+int t_store_incoming_reply( struct cell* , unsigned int , struct sip_msg* ); |
|
11 |
+int t_relay_reply( struct cell* , unsigned int , struct sip_msg* ); |
|
12 |
+int t_check( struct s_table* , struct sip_msg* ); |
|
13 |
+int t_all_final( struct cell * ); |
|
14 |
+int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg ); |
|
15 |
+int push_reply_from_uac_to_uas( struct sip_msg * , unsigned int ); |
|
16 |
+ |
|
17 |
+void del_Transaction( struct s_table *hash_table , struct cell * p_cell ); |
|
18 |
+void start_FR_timer( struct s_table* hash_table, struct cell* p_cell ); |
|
19 |
+void start_WT_timer( struct s_table* hash_table, struct cell* p_cell ); |
|
20 |
+ |
|
21 |
+ |
|
22 |
+ |
|
23 |
+ |
|
24 |
+/* function returns: |
|
25 |
+ * 0 - a new transaction was created |
|
26 |
+ * -1 - retransmission |
|
27 |
+ * -2 - error |
|
28 |
+ */ |
|
29 |
+int t_add_transaction( struct s_table* hash_table , struct sip_msg* p_msg ) |
|
30 |
+{ |
|
31 |
+ struct cell* new_cell; |
|
32 |
+ |
|
33 |
+ /* it's about the same transaction or not?*/ |
|
34 |
+ if ( global_msg_id != p_msg->id ) |
|
35 |
+ { |
|
36 |
+ T = (struct cell*)-1; |
|
37 |
+ global_msg_id = p_msg->id; |
|
38 |
+ } |
|
39 |
+ |
|
40 |
+ /* if the transaction is not found yet we are tring to look for it*/ |
|
41 |
+ if ( (int)T==-1 ) |
|
42 |
+ /* if the lookup's result is not 0 means that it's a retransmission */ |
|
43 |
+ if ( t_lookup_request( hash_table , p_msg ) ) |
|
44 |
+ return -1; |
|
45 |
+ |
|
46 |
+ /* creates a new transaction */ |
|
47 |
+ new_cell = build_cell( hash_table , p_msg ) ; |
|
48 |
+ if ( !new_cell ) |
|
49 |
+ return -2; |
|
50 |
+ insert_into_hash_table( hash_table , new_cell ); |
|
51 |
+ |
|
52 |
+ T = new_cell; |
|
53 |
+ return 0; |
|
54 |
+} |
|
55 |
+ |
|
56 |
+ |
|
57 |
+/* function returns: |
|
58 |
+ * 0 - transaction wasn't found |
|
59 |
+ * 1 - transaction found |
|
60 |
+ */ |
|
61 |
+int t_lookup_request( struct s_table* hash_table , struct sip_msg* p_msg ) |
|
62 |
+{ |
|
63 |
+ struct cell *p_cell; |
|
64 |
+ struct cell *tmp_cell; |
|
65 |
+ unsigned int hash_index=0; |
|
66 |
+ unsigned int isACK = 0; |
|
67 |
+ |
|
68 |
+ /* it's about the same transaction or not?*/ |
|
69 |
+ if ( global_msg_id != p_msg->id ) |
|
70 |
+ { |
|
71 |
+ T = (struct cell*)-1; |
|
72 |
+ global_msg_id = p_msg->id; |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ /* if T is previous found -> return found */ |
|
76 |
+ if ( (int)T !=-1 && T ) |
|
77 |
+ return 1; |
|
78 |
+ |
|
79 |
+ /* if T was previous searched and not found -> return not found*/ |
|
80 |
+ if ( !T ) |
|
81 |
+ return 0; |
|
82 |
+ |
|
83 |
+ /* start searching into the table */ |
|
84 |
+ hash_index = hash( p_msg->callid , get_cseq(p_msg)->number ) ; |
|
85 |
+ if ( p_msg->first_line.u.request.method_value==METHOD_ACK ) |
|
86 |
+ isACK = 1; |
|
87 |
+ |
|
88 |
+ /* all the transactions from the entry are compared */ |
|
89 |
+ p_cell = hash_table->entrys[hash_index].first_cell; |
|
90 |
+ tmp_cell = 0; |
|
91 |
+ while( p_cell ) |
|
92 |
+ { |
|
93 |
+ /* the transaction is referenceted for reading */ |
|
94 |
+ ref_transaction( p_cell ); |
|
95 |
+ |
|
96 |
+ /* is it the wanted transaction ? */ |
|
97 |
+ if ( !isACK ) |
|
98 |
+ { /* is not an ACK request */ |
|
99 |
+ /* first only the length are checked */ |
|
100 |
+ if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len ) |
|
101 |
+ if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len ) |
|
102 |
+ //if ( /*tag length*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && p_cell->inbound_request->tag->body.len == p_msg->tag->body.len) ) |
|
103 |
+ if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len ) |
|
104 |
+ if ( /*cseq length*/ p_cell->inbound_request->cseq->body.len == p_msg->cseq->body.len ) |
|
105 |
+ /* so far the lengths are the same -> let's check the contents */ |
|
106 |
+ if ( /*from*/ !memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len ) ) |
|
107 |
+ if ( /*to*/ !memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len) ) |
|
108 |
+ //if ( /*tag*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && !memcmp( p_cell->inbound_request->tag->body.s , p_msg->tag->body.s , p_msg->tag->body.len )) ) |
|
109 |
+ if ( /*callid*/ !memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len ) ) |
|
110 |
+ if ( /*cseq*/ !memcmp( p_cell->inbound_request->cseq->body.s , p_msg->cseq->body.s , p_msg->cseq->body.len ) ) |
|
111 |
+ { /* WE FOUND THE GOLDEN EGG !!!! */ |
|
112 |
+ T = p_cell; |
|
113 |
+ unref_transaction ( p_cell ); |
|
114 |
+ return 1; |
|
115 |
+ } |
|
116 |
+ } |
|
117 |
+ else |
|
118 |
+ { /* it's a ACK request*/ |
|
119 |
+ /* first only the length are checked */ |
|
120 |
+ if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len ) |
|
121 |
+ if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len ) |
|
122 |
+ if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len ) |
|
123 |
+ if ( /*cseq_nr length*/ get_cseq(p_cell->inbound_request)->number.len == get_cseq(p_msg)->number.len ) |
|
124 |
+ if ( /*cseq_method length*/ get_cseq(p_cell->inbound_request)->method.len == 6 /*INVITE*/ ) |
|
125 |
+ //if ( /*tag length*/ p_cell->tag && p_cell->tag->len==p_msg->tag->body.len ) |
|
126 |
+ /* so far the lengths are the same -> let's check the contents */ |
|
127 |
+ if ( /*from*/ !memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len ) ) |
|
128 |
+ if ( /*to*/ !memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len) ) |
|
129 |
+ //if ( /*tag*/ !memcmp( p_cell->tag->s , p_msg->tag->body.s , p_msg->tag->body.len ) ) |
|
130 |
+ if ( /*callid*/ !memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len ) ) |
|
131 |
+ if ( /*cseq_nr*/ !memcmp( get_cseq(p_cell->inbound_request)->number.s , get_cseq(p_msg)->number.s , get_cseq(p_msg)->number.len ) ) |
|
132 |
+ if ( /*cseq_method*/ !memcmp( get_cseq(p_cell->inbound_request)->method.s , "INVITE" , 6 ) ) |
|
133 |
+ { /* WE FOUND THE GOLDEN EGG !!!! */ |
|
134 |
+ T = p_cell; |
|
135 |
+ unref_transaction ( p_cell ); |
|
136 |
+ return 1; |
|
137 |
+ } |
|
138 |
+ } /* end if is ACK or not*/ |
|
139 |
+ /* next transaction */ |
|
140 |
+ tmp_cell = p_cell; |
|
141 |
+ p_cell = p_cell->next_cell; |
|
142 |
+ |
|
143 |
+ /* the transaction is dereferenceted */ |
|
144 |
+ unref_transaction ( tmp_cell ); |
|
145 |
+ } |
|
146 |
+ |
|
147 |
+ /* no transaction found */ |
|
148 |
+ T = 0; |
|
149 |
+ return 0; |
|
150 |
+} |
|
151 |
+ |
|
152 |
+ |
|
153 |
+ |
|
154 |
+/* function returns: |
|
155 |
+ * 0 - transaction wasn't found |
|
156 |
+ * T - transaction found |
|
157 |
+ */ |
|
158 |
+struct cell* t_lookupOriginalT( struct s_table* hash_table , struct sip_msg* p_msg ) |
|
159 |
+{ |
|
160 |
+ struct cell *p_cell; |
|
161 |
+ struct cell *tmp_cell; |
|
162 |
+ unsigned int hash_index=0; |
|
163 |
+ |
|
164 |
+ /* it's a CANCEL request for sure */ |
|
165 |
+ |
|
166 |
+ /* start searching into the table */ |
|
167 |
+ hash_index = hash( p_msg->callid , get_cseq(p_msg)->number ) ; |
|
168 |
+ |
|
169 |
+ /* all the transactions from the entry are compared */ |
|
170 |
+ p_cell = hash_table->entrys[hash_index].first_cell; |
|
171 |
+ tmp_cell = 0; |
|
172 |
+ while( p_cell ) |
|
173 |
+ { |
|
174 |
+ /* the transaction is referenceted for reading */ |
|
175 |
+ ref_transaction( p_cell ); |
|
176 |
+ |
|
177 |
+ /* is it the wanted transaction ? */ |
|
178 |
+ /* first only the length are checked */ |
|
179 |
+ if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len ) |
|
180 |
+ if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len ) |
|
181 |
+ //if ( /*tag length*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && p_cell->inbound_request->tag->body.len == p_msg->tag->body.len) ) |
|
182 |
+ if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len ) |
|
183 |
+ if ( /*cseq_nr length*/ get_cseq(p_cell->inbound_request)->number.len == get_cseq(p_msg)->number.len ) |
|
184 |
+ //if ( /*cseq_method length*/ p_cell->inbound_request->cseq_method->body.len != 6 /*CANCEL*/ ) |
|
185 |
+ if ( /*req_uri length*/ p_cell->inbound_request->first_line.u.request.uri.len == p_msg->first_line.u.request.uri.len ) |
|
186 |
+ /* so far the lengths are the same -> let's check the contents */ |
|
187 |
+ if ( /*from*/ !memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len ) ) |
|
188 |
+ if ( /*to*/ !memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len) ) |
|
189 |
+ //if ( /*tag*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && !memcmp( p_cell->inbound_request->tag->body.s , p_msg->tag->body.s , p_msg->tag->body.len )) ) |
|
190 |
+ if ( /*callid*/ !memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len ) ) |
|
191 |
+ if ( /*cseq_nr*/ !memcmp( get_cseq(p_cell->inbound_request)->number.s , get_cseq(p_msg)->number.s , get_cseq(p_msg)->number.len ) ) |
|
192 |
+ if ( /*cseq_method*/ strcmp( get_cseq(p_cell->inbound_request)->method.s , "CANCEL" ) ) |
|
193 |
+ if ( /*req_uri*/ memcmp( p_cell->inbound_request->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.len ) ) |
|
194 |
+ { /* WE FOUND THE GOLDEN EGG !!!! */ |
|
195 |
+ unref_transaction ( p_cell ); |
|
196 |
+ return p_cell; |
|
197 |
+ } |
|
198 |
+ /* next transaction */ |
|
199 |
+ tmp_cell = p_cell; |
|
200 |
+ p_cell = p_cell->next_cell; |
|
201 |
+ |
|
202 |
+ /* the transaction is dereferenceted */ |
|
203 |
+ unref_transaction ( tmp_cell ); |
|
204 |
+ } |
|
205 |
+ |
|
206 |
+ /* no transaction found */ |
|
207 |
+ T = 0; |
|
208 |
+ return 0; |
|
209 |
+ |
|
210 |
+ |
|
211 |
+ return 0; |
|
212 |
+} |
|
213 |
+ |
|
214 |
+ |
|
215 |
+/* function returns: |
|
216 |
+ * 0 - forward successfull |
|
217 |
+ * -1 - error during forward |
|
218 |
+ */ |
|
219 |
+int t_forward( struct s_table* hash_table , struct sip_msg* p_msg , unsigned int dest_ip_param , unsigned int dest_port_param ) |
|
220 |
+{ |
|
221 |
+ /* it's about the same transaction or not? */ |
|
222 |
+ if ( global_msg_id != p_msg->id ) |
|
223 |
+ { |
|
224 |
+ T = (struct cell*)-1; |
|
225 |
+ global_msg_id = p_msg->id; |
|
226 |
+ } |
|
227 |
+ |
|
228 |
+ /* if T hasn't been previous searched -> search for it */ |
|
229 |
+ if ( (int)T !=-1 ) |
|
230 |
+ t_lookup_request( hash_table , p_msg ); |
|
231 |
+ |
|
232 |
+ /*if T hasn't been found after all -> return not found (error) */ |
|
233 |
+ if ( !T ) |
|
234 |
+ return -1; |
|
235 |
+ |
|
236 |
+ /*if it's an ACK and the status is not final or is final, but error the ACK is not forwarded*/ |
|
237 |
+ if ( !memcmp(p_msg->first_line.u.request.method.s,"ACK",3) && (T->status/100)!=2 ) |
|
238 |
+ return 0; |
|
239 |
+ |
|
240 |
+ /* if it's forwarded for the first time ; else the request is retransmited from the transaction buffer */ |
|
241 |
+ if ( T->outbound_request[0]==NULL ) |
|
242 |
+ { |
|
243 |
+ unsigned int dest_ip = dest_ip_param; |
|
244 |
+ unsigned int dest_port = dest_port_param; |
|
245 |
+ unsigned int len; |
|
246 |
+ char *buf; |
|
247 |
+ |
|
248 |
+ /* allocates a new retrans_buff for the outbound request */ |
|
249 |
+ T->outbound_request[0] = (struct retrans_buff*)sh_malloc( sizeof(struct retrans_buff) ); |
|
250 |
+ T->nr_of_outgoings = 1; |
|
251 |
+ |
|
252 |
+ /* special case : CANCEL */ |
|
253 |
+ if ( p_msg->first_line.u.request.method_value==METHOD_CANCEL ) |
|
254 |
+ { |
|
255 |
+ struct cell *T2; |
|
256 |
+ /* find original cancelled transaction; if found, use its next-hops; otherwise use those passed by script */ |
|
257 |
+ T2 = t_lookupOriginalT( hash_table , p_msg ); |
|
258 |
+ /* if found */ |
|
259 |
+ if (T2) |
|
260 |
+ { /* if in 1xx status, send to the same destination */ |
|
261 |
+ if ( (T2->status/100)==1 ) |
|
262 |
+ { |
|
263 |
+ dest_ip = T2->outbound_request[0]->dest_ip; |
|
264 |
+ dest_port = T2->outbound_request[0]->dest_port; |
|
265 |
+ } |
|
266 |
+ else |
|
267 |
+ /* transaction exists, but nothing to cancel */ |
|
268 |
+ return 0; |
|
269 |
+ } |
|
270 |
+ }/* end special case CANCEL*/ |
|
271 |
+ |
|
272 |
+ /* store */ |
|
273 |
+ T->outbound_request[0]->dest_ip = dest_ip; |
|
274 |
+ T->outbound_request[0]->dest_port = dest_port; |
|
275 |
+ // buf = build_message( p_mesg , &len ); |
|
276 |
+ // T->outbound_request[0]->bufflen = len ; |
|
277 |
+ // memcpy( T->outbound_request[0]->buffer , buf , len ); |
|
278 |
+ }/* end for the first time */ |
|
279 |
+ |
|
280 |
+ /* send the request */ |
|
281 |
+ // send ( T->outbound_request.buffer , T->outbound_request.dest_ip , T->outbound_request.dest_ip ); |
|
282 |
+ |
|
283 |
+} |
|
284 |
+ |
|
285 |
+ |
|
286 |
+ |
|
287 |
+ |
|
288 |
+ |
|
289 |
+/* This function is called whenever a reply for our module is received; we need to register |
|
290 |
+ * this function on module initialization; |
|
291 |
+ * Returns : 1 - core router stops |
|
292 |
+ * 0 - core router relay statelessly |
|
293 |
+ */ |
|
294 |
+int t_on_reply_received( struct s_table *hash_table , struct sip_msg *p_msg ) |
|
295 |
+{ |
|
296 |
+ unsigned int branch; |
|
297 |
+ |
|
298 |
+ global_msg_id = p_msg->id; |
|
299 |
+ |
|
300 |
+ /* we use label-matching to lookup for T */ |
|
301 |
+ t_reply_matching( hash_table , p_msg , &T , &branch ); |
|
302 |
+ |
|
303 |
+ /* if no T found ->tell the core router to forward statelessly */ |
|
304 |
+ if ( !T ) |
|
305 |
+ return 0; |
|
306 |
+ |
|
307 |
+ /* on a non-200 reply to INVITE, generate local ACK and stop retransmission of the INVITE */ |
|
308 |
+ if ( T->inbound_request->first_line.u.request.method_value==METHOD_INVITE && p_msg->first_line.u.reply.statusclass>2 ) |
|
309 |
+ { |
|
310 |
+ // sendACK TO DO !!!!!!!!!! |
|
311 |
+ // remove_from_retransmission_list( T->outbound_request[branch] ); TO DO !!!!! |
|
312 |
+ t_store_incoming_reply( T , branch , p_msg ); |
|
313 |
+ } |
|
314 |
+ |
|
315 |
+ #ifdef FORKING |
|
316 |
+ /* skipped for the moment*/ |
|
317 |
+ #endif |
|
318 |
+ |
|
319 |
+ /*let's check the current inbound response status (is final or not) */ |
|
320 |
+ if ( T->inbound_response && (T->status/100)>1 ) |
|
321 |
+ { /*a final reply was already sent upstream */ |
|
322 |
+ /* alway relay 2xx immediately ; drop anything else */ |
|
323 |
+ if ( p_msg->first_line.u.reply.statusclass==2 ) |
|
324 |
+ t_relay_reply( T , branch , p_msg ); |
|
325 |
+ /* nothing to do for the ser core */ |
|
326 |
+ return 1; |
|
327 |
+ } |
|
328 |
+ else |
|
329 |
+ { /* no reply sent yet or sent but not final*/ |
|
330 |
+ |
|
331 |
+ /* stops the request's retransmission*/ |
|
332 |
+ // remove_from_retransmission_list( T->outbound_request[branch] ); TO DO !!!!! |
|
333 |
+ /* restart retransmission if provisional response came for a non_INVITE -> retrasmit at RT_T2*/ |
|
334 |
+ if ( p_msg->first_line.u.reply.statusclass==1 && T->inbound_request->first_line.u.request.method_value!=METHOD_INVITE ) |
|
335 |
+ /*put_in_retransmission_list( T->trasaction.outbound_request[branch] , RT_T2 ) TO DO !!!!!!!*/ ; |
|
336 |
+ |
|
337 |
+ |
|
338 |
+ /* relay ringing and OK immediately */ |
|
339 |
+ if ( p_msg->first_line.u.reply.statusclass ==1 || p_msg->first_line.u.reply.statusclass ==2 ) |
|
340 |
+ { |
|
341 |
+ if ( p_msg->first_line.u.reply.statuscode > T->status ) |
|
342 |
+ t_relay_reply( T , branch , p_msg ); |
|
343 |
+ return 1; |
|
344 |
+ } |
|
345 |
+ |
|
346 |
+ /* error final responses are only stored */ |
|
347 |
+ if ( p_msg->first_line.u.reply.statusclass>=3 && p_msg->first_line.u.reply.statusclass<=5 ) |
|
348 |
+ { |
|
349 |
+ t_store_incoming_reply( T , branch , p_msg ); |
|
350 |
+ if ( t_all_final(T) ) |
|
351 |
+ relay_lowest_reply_upstream( T , p_msg ); |
|
352 |
+ /* nothing to do for the ser core */ |
|
353 |
+ return 1; |
|
354 |
+ } |
|
355 |
+ |
|
356 |
+ /* global failure responses relay immediately */ |
|
357 |
+ if ( p_msg->first_line.u.reply.statusclass==6 ) |
|
358 |
+ { |
|
359 |
+ t_relay_reply( T , branch , p_msg ); |
|
360 |
+ /* nothing to do for the ser core */ |
|
361 |
+ return 1; |
|
362 |
+ } |
|
363 |
+ } |
|
364 |
+} |
|
365 |
+ |
|
366 |
+ |
|
367 |
+ |
|
368 |
+ |
|
369 |
+/* Retransmits the last sent inbound reply. |
|
370 |
+ * Returns -1 -error |
|
371 |
+ * 0 - OK |
|
372 |
+ */ |
|
373 |
+int t_retransmit_reply( struct s_table *hash_table , struct sip_msg* p_msg ) |
|
374 |
+{ |
|
375 |
+ t_check( hash_table, p_msg ); |
|
376 |
+ |
|
377 |
+ /* if no transaction exists or no reply to be resend -> out */ |
|
378 |
+ if ( T && T->inbound_response ) |
|
379 |
+ { |
|
380 |
+ //sendto( ); TO DO !!!!!! |
|
381 |
+ return 0; |
|
382 |
+ } |
|
383 |
+ |
|
384 |
+ return -1; |
|
385 |
+} |
|
386 |
+ |
|
387 |
+ |
|
388 |
+ |
|
389 |
+ |
|
390 |
+/* ----------------------------HELPER FUNCTIONS-------------------------------- */ |
|
391 |
+ |
|
392 |
+ |
|
393 |
+/* Returns 0 - nothing found |
|
394 |
+ * 1 - T found |
|
395 |
+ */ |
|
396 |
+int t_reply_matching( struct s_table *hash_table , struct sip_msg *p_msg , struct cell **p_Trans , unsigned int *p_branch ) |
|
397 |
+{ |
|
398 |
+ struct cell* p_cell; |
|
399 |
+ struct cell* tmp_cell; |
|
400 |
+ unsigned int hash_index = 0; |
|
401 |
+ unsigned int entry_label = 0; |
|
402 |
+ unsigned int branch_id = 0; |
|
403 |
+ |
|
404 |
+ /* getting the hash_index from the brach param , via header*/ |
|
405 |
+ // hash_index = get_hash_index( p_msg ); TO DO !!!! |
|
406 |
+ |
|
407 |
+ /*if the hash index is corect */ |
|
408 |
+ if ( hash_index>=0 && hash_index<TABLE_ENTRIES-1 ) |
|
409 |
+ { |
|
410 |
+ /* getting the entry label value */ |
|
411 |
+ // entry_label = get_entry_label( p_msg ); TO DO !!!! |
|
412 |
+ /* if the entry label also is corect */ |
|
413 |
+ if ( entry_label>=0 ) |
|
414 |
+ { |
|
415 |
+ /* getting the branch_id value */ |
|
416 |
+ // entry_label = get_branch_id( p_msg ); TO DO !!!! |
|
417 |
+ /* if the entry label also is corect */ |
|
418 |
+ if ( branch_id>=0 ) |
|
419 |
+ { |
|
420 |
+ /*all the cells from the entry are scan to detect an entry_label matching */ |
|
421 |
+ p_cell = hash_table->entrys[hash_index].first_cell; |
|
422 |
+ tmp_cell = 0; |
|
423 |
+ while( p_cell ) |
|
424 |
+ { |
|
425 |
+ /* the transaction is referenceted for reading */ |
|
426 |
+ ref_transaction( p_cell ); |
|
427 |
+ /* is it the cell with the wanted entry_label? */ |
|
428 |
+ if ( p_cell->label = entry_label ) |
|
429 |
+ /* has the transaction the wanted branch? */ |
|
430 |
+ if ( p_cell->nr_of_outgoings>branch_id && p_cell->outbound_request[branch_id] ) |
|
431 |
+ {/* WE FOUND THE GOLDEN EGG !!!! */ |
|
432 |
+ p_Trans = &p_cell; |
|
433 |
+ *p_branch = branch_id; |
|
434 |
+ unref_transaction( p_cell ); |
|
435 |
+ return 1; |
|
436 |
+ } |
|
437 |
+ |
|
438 |
+ /* next cell */ |
|
439 |
+ tmp_cell = p_cell; |
|
440 |
+ p_cell = p_cell->next_cell; |
|
441 |
+ |
|
442 |
+ /* the transaction is dereferenceted */ |
|
443 |
+ unref_transaction( tmp_cell ); |
|
444 |
+ } |
|
445 |
+ } |
|
446 |
+ } |
|
447 |
+ } |
|
448 |
+ |
|
449 |
+ /* nothing found */ |
|
450 |
+ *p_branch = -1; |
|
451 |
+ return 0; |
|
452 |
+} |
|
453 |
+ |
|
454 |
+ |
|
455 |
+ |
|
456 |
+ |
|
457 |
+/* We like this incoming reply, so, let's store it, we'll decide |
|
458 |
+ * later what to d with that |
|
459 |
+ */ |
|
460 |
+int t_store_incoming_reply( struct cell* Trans, unsigned int branch, struct sip_msg* p_msg ) |
|
461 |
+{ |
|
462 |
+ /* if there is a previous reply, replace it */ |
|
463 |
+ if ( Trans->outbound_response[branch] ) |
|
464 |
+ /*free_sip_msg( Trans->outbound_response[branch] ) TO DO*/ ; |
|
465 |
+ Trans->outbound_response[branch] = sip_msg_cloner( p_msg ); |
|
466 |
+} |
|
467 |
+ |
|
468 |
+ |
|
469 |
+ |
|
470 |
+ |
|
471 |
+/* We like this incoming reply and we want ot store it and |
|
472 |
+ * to relay it upstream |
|
473 |
+ */ |
|
474 |
+int t_relay_reply( struct cell* Trans, unsigned int branch, struct sip_msg* p_msg ) |
|
475 |
+{ |
|
476 |
+ t_store_incoming_reply( Trans , branch, p_msg ); |
|
477 |
+ push_reply_from_uac_to_uas( p_msg , branch ); |
|
478 |
+} |
|
479 |
+ |
|
480 |
+ |
|
481 |
+ |
|
482 |
+ |
|
483 |
+/* Functions update T (T gets either a valid pointer in it or it equals zero) if no transaction |
|
484 |
+ * for current message exists; |
|
485 |
+ * Returns 1 if T was modified or 0 if not. |
|
486 |
+ */ |
|
487 |
+int t_check( struct s_table *hash_table , struct sip_msg* p_msg ) |
|
488 |
+{ |
|
489 |
+ unsigned int branch; |
|
490 |
+ |
|
491 |
+ /* is T still up-to-date ? */ |
|
492 |
+ if ( p_msg->id != global_msg_id || (int)T==-1 ) |
|
493 |
+ { |
|
494 |
+ global_msg_id = p_msg->id; |
|
495 |
+ /* transaction lookup */ |
|
496 |
+ if ( p_msg->first_line.type=SIP_REQUEST ) |
|
497 |
+ t_lookup_request( hash_table , p_msg ); |
|
498 |
+ else |
|
499 |
+ t_reply_matching( hash_table , p_msg , &T , &branch ); |
|
500 |
+ |
|
501 |
+ return 1; |
|
502 |
+ } |
|
503 |
+ |
|
504 |
+ return 0; |
|
505 |
+} |
|
506 |
+ |
|
507 |
+ |
|
508 |
+ |
|
509 |
+ |
|
510 |
+/* Checks if all the transaction's outbound request has a final response. |
|
511 |
+ * Return 1 - all are final |
|
512 |
+ * 0 - some waitting |
|
513 |
+ */ |
|
514 |
+int t_all_final( struct cell *Trans ) |
|
515 |
+{ |
|
516 |
+ unsigned int i; |
|
517 |
+ |
|
518 |
+ for( i=0 ; i<Trans->nr_of_outgoings ; i++ ) |
|
519 |
+ if ( !Trans->outbound_response[i] || (Trans->outbound_response[i]) && Trans->outbound_response[i]->first_line.u.reply.statuscode<200 ) |
|
520 |
+ return 0; |
|
521 |
+ |
|
522 |
+ return 1; |
|
523 |
+} |
|
524 |
+ |
|
525 |
+ |
|
526 |
+ |
|
527 |
+ |
|
528 |
+/* Picks the lowest code reply and send it upstream. |
|
529 |
+ * Returns -1 if no lowest find reply found (all provisional) |
|
530 |
+ */ |
|
531 |
+int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg ) |
|
532 |
+{ |
|
533 |
+ unsigned int i =0 ; |
|
534 |
+ unsigned int lowest_i = -1; |
|
535 |
+ int lowest_v = 999; |
|
536 |
+ |
|
537 |
+ for( ; i<T->nr_of_outgoings ; i++ ) |
|
538 |
+ if ( T->outbound_response[i] && T->outbound_response[i]->first_line.u.reply.statuscode>=200 && T->outbound_response[i]->first_line.u.reply.statuscode<lowest_v ) |
|
539 |
+ { |
|
540 |
+ lowest_i =i; |
|
541 |
+ lowest_v = T->outbound_response[i]->first_line.u.reply.statuscode; |
|
542 |
+ } |
|
543 |
+ |
|
544 |
+ if ( lowest_i != -1 ) |
|
545 |
+ push_reply_from_uac_to_uas( p_msg ,lowest_i ); |
|
546 |
+ |
|
547 |
+ return lowest_i; |
|
548 |
+} |
|
549 |
+ |
|
550 |
+ |
|
551 |
+ |
|
552 |
+ |
|
553 |
+/* Push a previously stored reply from UA Client to UA Server |
|
554 |
+ * and send it out |
|
555 |
+ */ |
|
556 |
+int push_reply_from_uac_to_uas( struct sip_msg *p_msg , unsigned int branch ) |
|
557 |
+{ |
|
558 |
+ /* if there is a reply, release the buffer (everything else stays same) */ |
|
559 |
+ if ( T->inbound_response ) |
|
560 |
+ { |
|
561 |
+ sh_free( T->inbound_response->buffer ); |
|
562 |
+ //release_retransmision.... ???? |
|
563 |
+ } |
|
564 |
+ |
|
565 |
+ |
|
566 |
+} |
|
567 |
+ |
|
568 |
+ |
|
569 |
+ |
|
570 |
+ |
|
571 |
+ |
|
572 |
+ |
|
573 |
+ |
|
574 |
+ |
|
575 |
+ |
|
576 |
+ |
|
577 |
+ |
|
578 |
+ |
|
579 |
+/* |
|
580 |
+* The cell is inserted at the end of the FINAL RESPONSE timer list. |
|
581 |
+* The expire time is given by the current time plus the FINAL |
|
582 |
+ RESPONSE timeout - FR_TIME_OUT |
|
583 |
+*/ |
|
584 |
+void start_FR_timer( struct s_table* hash_table, struct cell* p_cell ) |
|
585 |
+{ |
|
586 |
+ |
|
587 |
+ /* adds the cell int FINAL RESPONSE timer list*/ |
|
588 |
+ add_to_tail_of_timer_list( hash_table, &(p_cell->tl[FR_TIMER_LIST]), FR_TIMER_LIST, FR_TIME_OUT); |
|
589 |
+ |
|
590 |
+} |
|
591 |
+ |
|
592 |
+ |
|
593 |
+/* |
|
594 |
+* The cell is inserted at the end of the WAIT timer list. Before adding to the WT list, it's verify if the cell is |
|
595 |
+* or not in the FR list (normally it should be there). If it is, it's first removed from FR list and after that |
|
596 |
+* added to the WT list. |
|
597 |
+* The expire time is given by the current time plus the WAIT timeout - WT_TIME_OUT |
|
598 |
+*/ |
|
599 |
+ |
|
600 |
+void start_WT_timer( struct s_table* hash_table, struct cell* p_cell ) |
|
601 |
+{ |
|
602 |
+ struct timer* timers= hash_table->timers; |
|
603 |
+ |
|
604 |
+ //if is in FR list -> first it must be removed from there |
|
605 |
+ remove_from_timer_list( hash_table, &(p_cell->tl[FR_TIMER_LIST]), FR_TIMER_LIST ); |
|
606 |
+ |
|
607 |
+ /* adds the cell int WAIT timer list*/ |
|
608 |
+ add_to_tail_of_timer_list( hash_table, &(p_cell->tl[WT_TIMER_LIST]), WT_TIMER_LIST, WT_TIME_OUT ); |
|
609 |
+} |
|
610 |
+ |
|
611 |
+ |
|
612 |
+ |
|
613 |
+ |
|
614 |
+/* |
|
615 |
+* prepare for del a transaction ; the transaction is first removed from the hash entry list (oniy the links from |
|
616 |
+* cell to list are deleted in order to make the cell unaccessible from the list and in the same time to keep the |
|
617 |
+* list accessible from the cell for process that are currently reading the cell). If no process is reading the cell |
|
618 |
+* (ref conter is 0) the cell is immediatly deleted. Otherwise it is put in a waitting list (del_hooker list) for |
|
619 |
+* future del. This list is veify by the the timer every sec and the cell that finaly have ref_counter 0 are del. |
|
620 |
+*/ |
|
621 |
+void del_Transaction( struct s_table *hash_table , struct cell * p_cell ) |
|
622 |
+{ |
|
623 |
+ int ref_counter = 0; |
|
624 |
+ |
|
625 |
+ /* the cell is removed from the list */ |
|
626 |
+ remove_from_hash_table( hash_table, p_cell ); |
|
627 |
+ |
|
628 |
+ /* gets the cell's ref counter*/ |
|
629 |
+ lock( p_cell->mutex ); |
|
630 |
+ ref_counter = p_cell->ref_counter; |
|
631 |
+ unlock( p_cell->mutex ); |
|
632 |
+ |
|
633 |
+ /* if is not refenceted -> is deleted*/ |
|
634 |
+ if ( ref_counter==0 ) |
|
635 |
+ free_cell( p_cell ); |
|
636 |
+ /* else it's added to del hooker list for future del */ |
|
637 |
+ else add_to_tail_of_timer_list( hash_table, &(p_cell->tl[DELETE_LIST]), DELETE_LIST, 0 ); |
|
638 |
+} |
|
639 |
+ |
|
640 |
+ |