Pārlūkot izejas kodu

Added parameter to dlg_request_uas and dlg_response_uac.

This parameter specifies if it is target refresh request/response. This is
needed because TM module is not able to determine target refresh methods for
all dialog types.  Only INVITE method was used as target refresh, but this is
error for non-INVITE dialogs (SUBSCRIBE/NOTIFY, ...).

If you want to behave like previous versions use TARGET_REFRESH_UNKNOWN as
value but be aware of possible problems.
Vaclav Kubart 19 gadi atpakaļ
vecāks
revīzija
665ec3ae9c
2 mainītis faili ar 75 papildinājumiem un 34 dzēšanām
  1. 66 30
      modules/tm/dlg.c
  2. 9 4
      modules/tm/dlg.h

+ 66 - 30
modules/tm/dlg.c

@@ -366,6 +366,54 @@ static inline int get_route_set(struct sip_msg* _m, rr_t** _rs, unsigned char _o
 	return -1;
 	return -1;
 }
 }
 
 
+/*
+ * Extract method from CSeq header field
+ */
+static inline int get_cseq_method(struct sip_msg* _m, str* _method)
+{
+	if (!_m->cseq && ((parse_headers(_m, HDR_CSEQ_F, 0) == -1) || !_m->cseq)) {
+		LOG(L_ERR, "get_cseq_method(): Error while parsing CSeq\n");
+		return -1;
+	}
+
+	_method->s = get_cseq(_m)->method.s;
+	_method->len = get_cseq(_m)->method.len;
+	return 0;
+}
+
+
+static inline int refresh_dialog_resp(struct sip_msg* _m, 
+		target_refresh_t is_target_refresh)
+{
+	str method;
+	
+	switch (is_target_refresh) {
+		case IS_NOT_TARGET_REFRESH: 
+			return 0;
+		case IS_TARGET_REFRESH: 
+			return 1;
+		case TARGET_REFRESH_UNKNOWN: 
+			if (get_cseq_method(_m, &method) < 0) return 0; /* error */
+			if ((method.len == 6) && !memcmp("INVITE", method.s, 6)) 
+				return 1;
+			else return 0;
+	}
+	return 0;
+}
+		
+static inline int refresh_dialog_req(struct sip_msg* _m, target_refresh_t is_target_refresh)
+{
+	switch (is_target_refresh) {
+		case IS_NOT_TARGET_REFRESH: 
+			return 0;
+		case IS_TARGET_REFRESH: 
+			return 1;
+		case TARGET_REFRESH_UNKNOWN: 
+			return (_m->first_line.u.request.method_value == METHOD_INVITE);
+			break;
+	}
+	return 0;
+}
 
 
 /*
 /*
  * Extract all necessary information from a response and put it
  * Extract all necessary information from a response and put it
@@ -469,6 +517,10 @@ static inline int dlg_early_resp_uac(dlg_t* _d, struct sip_msg* _m)
 		     /* We are in early state already, do nothing
 		     /* We are in early state already, do nothing
 		      */
 		      */
 	} else if ((code >= 200) && (code <= 299)) {
 	} else if ((code >= 200) && (code <= 299)) {
+		/* Warning - we can handle here response for non-initial request (for
+		 * example UPDATE within early INVITE/BYE dialog) and move into
+		 * confirmed state may be error! But this depends on dialog type... */
+		
 		     /* Same as in dlg_new_resp_uac */
 		     /* Same as in dlg_new_resp_uac */
 		     /* A final response, update the structures and transit
 		     /* A final response, update the structures and transit
 		      * into DLG_CONFIRMED
 		      * into DLG_CONFIRMED
@@ -491,30 +543,15 @@ static inline int dlg_early_resp_uac(dlg_t* _d, struct sip_msg* _m)
 }
 }
 
 
 
 
-/*
- * Extract method from CSeq header field
- */
-static inline int get_cseq_method(struct sip_msg* _m, str* _method)
-{
-	if (!_m->cseq && ((parse_headers(_m, HDR_CSEQ_F, 0) == -1) || !_m->cseq)) {
-		LOG(L_ERR, "get_cseq_method(): Error while parsing CSeq\n");
-		return -1;
-	}
-
-	_method->s = get_cseq(_m)->method.s;
-	_method->len = get_cseq(_m)->method.len;
-	return 0;
-}
-
-
 /*
 /*
  * Handle dialog in DLG_CONFIRMED state, we will be processing
  * Handle dialog in DLG_CONFIRMED state, we will be processing
  * a response to a request sent within a dialog
  * a response to a request sent within a dialog
  */
  */
-static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m)
+static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m, 
+		target_refresh_t is_target_refresh)
 {
 {
 	int code;
 	int code;
-	str method, contact;
+	str contact;
 
 
 	code = _m->first_line.u.reply.statuscode;	
 	code = _m->first_line.u.reply.statuscode;	
 
 
@@ -524,10 +561,6 @@ static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m)
 	      * a target refresher. 
 	      * a target refresher. 
 	      */
 	      */
 
 
-	     /* FIXME: Currently we support only INVITEs as target refreshers,
-	      * this should be generalized
-	      */
-
 	     /* IF we receive a 481 response, terminate the dialog because
 	     /* IF we receive a 481 response, terminate the dialog because
 	      * the remote peer indicated that it didn't have the dialog
 	      * the remote peer indicated that it didn't have the dialog
 	      * state anymore, signal this termination with a positive return
 	      * state anymore, signal this termination with a positive return
@@ -541,8 +574,7 @@ static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m)
 	     /* Do nothing if not 2xx */
 	     /* Do nothing if not 2xx */
 	if ((code < 200) || (code >= 300)) return 0;
 	if ((code < 200) || (code >= 300)) return 0;
 	
 	
-	if (get_cseq_method(_m, &method) < 0) return -1;
-	if ((method.len == 6) && !memcmp("INVITE", method.s, 6)) {
+	if (refresh_dialog_resp(_m, is_target_refresh)) {
 		     /* Get contact if any and update remote target */
 		     /* Get contact if any and update remote target */
 		if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
 		if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
 			LOG(L_ERR, "dlg_confirmed_resp_uac(): Error while parsing headers\n");
 			LOG(L_ERR, "dlg_confirmed_resp_uac(): Error while parsing headers\n");
@@ -558,6 +590,8 @@ static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m)
 			     /* Duplicate new remote target */
 			     /* Duplicate new remote target */
 			if (str_duplicate(&_d->rem_target, &contact) < 0) return -4;
 			if (str_duplicate(&_d->rem_target, &contact) < 0) return -4;
 		}
 		}
+
+		calculate_hooks(_d);
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -567,7 +601,8 @@ static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m)
 /*
 /*
  * A response arrived, update dialog
  * A response arrived, update dialog
  */
  */
-int dlg_response_uac(dlg_t* _d, struct sip_msg* _m)
+int dlg_response_uac(dlg_t* _d, struct sip_msg* _m, 
+		target_refresh_t is_target_refresh)
 {
 {
 	if (!_d || !_m) {
 	if (!_d || !_m) {
 		LOG(L_ERR, "dlg_response_uac(): Invalid parameter value\n");
 		LOG(L_ERR, "dlg_response_uac(): Invalid parameter value\n");
@@ -583,7 +618,7 @@ int dlg_response_uac(dlg_t* _d, struct sip_msg* _m)
 		return dlg_early_resp_uac(_d, _m);
 		return dlg_early_resp_uac(_d, _m);
 
 
 	case DLG_CONFIRMED: 
 	case DLG_CONFIRMED: 
-		return dlg_confirmed_resp_uac(_d, _m);
+		return dlg_confirmed_resp_uac(_d, _m, is_target_refresh);
 
 
 	case DLG_DESTROYED:
 	case DLG_DESTROYED:
 		LOG(L_ERR, "dlg_response_uac(): Cannot handle destroyed dialog\n");
 		LOG(L_ERR, "dlg_response_uac(): Cannot handle destroyed dialog\n");
@@ -791,11 +826,10 @@ int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d)
 	return 0;
 	return 0;
 }
 }
 
 
-
 /*
 /*
  * UAS side - update a dialog from a request
  * UAS side - update a dialog from a request
  */
  */
-int dlg_request_uas(dlg_t* _d, struct sip_msg* _m)
+int dlg_request_uas(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_refresh)
 {
 {
 	str contact;
 	str contact;
 	int cseq;
 	int cseq;
@@ -822,8 +856,7 @@ int dlg_request_uas(dlg_t* _d, struct sip_msg* _m)
 	     /* We will als update remote target URI if the message 
 	     /* We will als update remote target URI if the message 
 	      * is target refresher
 	      * is target refresher
 	      */
 	      */
-	if (_m->first_line.u.request.method_value == METHOD_INVITE) {
-		     /* target refresher */
+	if (refresh_dialog_req(_m, is_target_refresh)) { /* target refresher */
 		if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
 		if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
 			LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n");
 			LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n");
 			return -4;
 			return -4;
@@ -834,6 +867,9 @@ int dlg_request_uas(dlg_t* _d, struct sip_msg* _m)
 			if (_d->rem_target.s) shm_free(_d->rem_target.s);
 			if (_d->rem_target.s) shm_free(_d->rem_target.s);
 			if (str_duplicate(&_d->rem_target, &contact) < 0) return -6;
 			if (str_duplicate(&_d->rem_target, &contact) < 0) return -6;
 		}
 		}
+
+		calculate_hooks(_d);
+		
 	}
 	}
 
 
 	return 0;
 	return 0;

+ 9 - 4
modules/tm/dlg.h

@@ -105,6 +105,11 @@ typedef struct dlg {
 				 */
 				 */
 } dlg_t;
 } dlg_t;
 
 
+typedef enum {
+	IS_TARGET_REFRESH,
+	IS_NOT_TARGET_REFRESH,
+	TARGET_REFRESH_UNKNOWN
+} target_refresh_t;
 
 
 /*
 /*
  * Create a new dialog
  * Create a new dialog
@@ -116,8 +121,8 @@ typedef int (*new_dlg_uac_f)(str* _cid, str* _ltag, unsigned int _lseq, str* _lu
 /*
 /*
  * A response arrived, update dialog
  * A response arrived, update dialog
  */
  */
-int dlg_response_uac(dlg_t* _d, struct sip_msg* _m);
-typedef int (*dlg_response_uac_f)(dlg_t* _d, struct sip_msg* _m);
+int dlg_response_uac(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_refresh);
+typedef int (*dlg_response_uac_f)(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_refresh);
 
 
 /*
 /*
  * Establishing a new dialog, UAS side
  * Establishing a new dialog, UAS side
@@ -129,8 +134,8 @@ typedef int (*new_dlg_uas_f)(struct sip_msg* _req, int _code, dlg_t** _d);
 /*
 /*
  * UAS side - update a dialog from a request
  * UAS side - update a dialog from a request
  */
  */
-int dlg_request_uas(dlg_t* _d, struct sip_msg* _m);
-typedef int (*dlg_request_uas_f)(dlg_t* _d, struct sip_msg* _m);
+int dlg_request_uas(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_request);
+typedef int (*dlg_request_uas_f)(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_request);
 
 
 
 
 /*
 /*