Browse code

tm: Reason header copy for received CANCELs

When canceling branches due to a received CANCEL, use the Reason
headers in the received CANCEL (all the Reason headers from the
received CANCEL will be copied in the generated CANCELs, see
RFC3326 for more details).

Andrei Pelinescu-Onciul authored on 02/03/2010 16:28:16
Showing 3 changed files
... ...
@@ -951,13 +951,15 @@ error:
951 951
 
952 952
 
953 953
 
954
-void e2e_cancel( struct sip_msg *cancel_msg, 
954
+void e2e_cancel( struct sip_msg *cancel_msg,
955 955
 	struct cell *t_cancel, struct cell *t_invite )
956 956
 {
957 957
 	branch_bm_t cancel_bm;
958 958
 #ifndef E2E_CANCEL_HOP_BY_HOP
959 959
 	branch_bm_t tmp_bm;
960
-#endif
960
+#else /* def E2E_CANCEL_HOP_BY_HOP */
961
+	struct cancel_reason reason;
962
+#endif /* E2E_CANCEL_HOP_BY_HOP */
961 963
 	int i;
962 964
 	int lowest_error;
963 965
 	int ret;
... ...
@@ -1002,6 +1004,9 @@ void e2e_cancel( struct sip_msg *cancel_msg,
1002 1002
 	 * have 0 branches and we check for the branch number in 
1003 1003
 	 * t_reply_matching() ).
1004 1004
 	 */
1005
+	init_cancel_reason(&reason);
1006
+	reason.cause=CANCEL_REAS_RCVD_CANCEL;
1007
+	reason.u.e2e_cancel=cancel_msg;
1005 1008
 	for (i=0; i<t_invite->nr_of_outgoings; i++)
1006 1009
 		if (cancel_bm & (1<<i)) {
1007 1010
 			/* it's safe to get the reply lock since e2e_cancel is
... ...
@@ -1011,7 +1016,7 @@ void e2e_cancel( struct sip_msg *cancel_msg,
1011 1011
 			ret=cancel_branch(
1012 1012
 				t_invite,
1013 1013
 				i,
1014
-				0,
1014
+				&reason,
1015 1015
 				cfg_get(tm,tm_cfg, cancel_b_flags)
1016 1016
 					| ((t_invite->uac[i].request.buffer==NULL)?
1017 1017
 						F_CANCEL_B_FAKE_REPLY:0) /* blind UAC? */
... ...
@@ -104,6 +104,7 @@ char *build_local(struct cell *Trans,unsigned int branch,
104 104
 	str via_id;
105 105
 	struct hostport hp;
106 106
 	int reason_len, code_len;
107
+	struct hdr_field *reas1, *reas_last;
107 108
 
108 109
 	/* init */
109 110
 	via_id.s=0;
... ...
@@ -169,6 +170,7 @@ char *build_local(struct cell *Trans,unsigned int branch,
169 169
 	/* Content Length, EoM */
170 170
 	*len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
171 171
 	reason_len = 0;
172
+	reas1 = 0;
172 173
 	/* compute reason size */
173 174
 	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
174 175
 		if (likely(reason->cause > 0)){
... ...
@@ -179,7 +181,14 @@ char *build_local(struct cell *Trans,unsigned int branch,
179 179
 				CRLF_LEN;
180 180
 		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
181 181
 					reason->u.e2e_cancel) {
182
-			/* FIXME: TODO */
182
+			/* parse the entire cancel, to get all the Reason headers */
183
+			parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0);
184
+			for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr;
185
+					hdr; hdr=next_sibling_hdr(hdr)) {
186
+				/* hdr->len includes CRLF */
187
+				reason_len += hdr->len;
188
+				reas_last=hdr;
189
+			}
183 190
 		} else if (unlikely(reason->cause != -1))
184 191
 			BUG("unhandled reason cause %d\n", reason->cause);
185 192
 	}
... ...
@@ -243,7 +252,12 @@ char *build_local(struct cell *Trans,unsigned int branch,
243 243
 			}
244 244
 			append_str(p, CRLF, CRLF_LEN);
245 245
 		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
246
-			/* FIXME: handle cancel */
246
+			for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) {
247
+				/* hdr->len includes CRLF */
248
+				append_str(p, hdr->name.s, hdr->len);
249
+				if (likely(hdr==reas_last))
250
+					break;
251
+			}
247 252
 		}
248 253
 	}
249 254
 	append_str(p, CRLF, CRLF_LEN); /* msg. end */
... ...
@@ -274,6 +288,7 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
274 274
 	enum _hdr_types_t	hf_type;
275 275
 	int	first_via, to_len;
276 276
 	int cancel_buf_len, reason_len, code_len;
277
+	struct hdr_field *reas1, *reas_last, *hdr;
277 278
 
278 279
 	invite_buf = Trans->uac[branch].request.buffer;
279 280
 	invite_len = Trans->uac[branch].request.buffer_len;
... ...
@@ -289,6 +304,7 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
289 289
 	}
290 290
 	
291 291
 	reason_len = 0;
292
+	reas1 = 0;
292 293
 	/* compute reason size */
293 294
 	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
294 295
 		if (likely(reason->cause > 0)){
... ...
@@ -299,7 +315,14 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
299 299
 				CRLF_LEN;
300 300
 		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
301 301
 					reason->u.e2e_cancel) {
302
-			/* FIXME: TODO */
302
+			/* parse the entire cancel, to get all the Reason headers */
303
+			parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0);
304
+			for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr;
305
+					hdr; hdr=next_sibling_hdr(hdr)) {
306
+				/* hdr->len includes CRLF */
307
+				reason_len += hdr->len;
308
+				reas_last=hdr;
309
+			}
303 310
 		} else if (unlikely(reason->cause != -1))
304 311
 			BUG("unhandled reason cause %d\n", reason->cause);
305 312
 	}
... ...
@@ -424,9 +447,15 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
424 424
 						}
425 425
 						append_str(d, CRLF, CRLF_LEN);
426 426
 					} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
427
-						/* FIXME: handle cancel */
427
+						for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) {
428
+							/* hdr->len includes CRLF */
429
+							append_str(d, hdr->name.s, hdr->len);
430
+							if (likely(hdr==reas_last))
431
+								break;
432
+						}
428 433
 					}
429 434
 				}
435
+				/* final (end-of-headers) CRLF */
430 436
 				append_str(d, CRLF, CRLF_LEN);
431 437
 				*len = d - cancel_buf;
432 438
 				/* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */
... ...
@@ -2035,12 +2035,15 @@ int reply_received( struct sip_msg  *p_msg )
2035 2035
 				SEND_BUFFER( &uac->local_cancel );
2036 2036
 #endif
2037 2037
 				/* retrs. should be already started so do nothing */
2038
-			}else if (atomic_cmpxchg_long((void*)&uac->local_cancel.buffer, 0, 
2038
+			}else if (atomic_cmpxchg_long((void*)&uac->local_cancel.buffer, 0,
2039 2039
 										(long)BUSY_BUFFER)==0){
2040 2040
 				/* try to rebuild it if empty (not set or marked as BUSY).
2041 2041
 				 * if BUSY or set just exit, a cancel will be (or was) sent 
2042 2042
 				 * shortly on this branch */
2043 2043
 				DBG("tm: reply_received: branch CANCEL created\n");
2044
+				/* note that in this case we do not know the reason
2045
+				   (it could be a final reply or a received cancel)
2046
+				   and we don't want to wait for it => no reason */
2044 2047
 				cancel_branch(t, branch, 0, F_CANCEL_B_FORCE_C);
2045 2048
 			}
2046 2049
 			goto done; /* nothing to do */