Browse Source

sca: support Record-Route

- Save Record-Route values from SUBSCRIBEs to ensure NOTIFYs traverse
  correct path to subscriber.
- Update SCA DB schema & creation scripts: add record_route column,
  increment sca_subscriptsion table version.
Andrew Mortensen 12 years ago
parent
commit
8632a265c3

+ 7 - 0
lib/srdb1/schema/sca.xml

@@ -90,6 +90,13 @@
         <description>To-tag for subscription dialog</description>
     </column>
 
+    <column id="record_route">
+        <name>record_route</name>
+        <type>text</type>
+	<null />
+        <description>Subscription Record-Route values</description>
+    </column>
+
     <column id="notify_cseq">
         <name>notify_cseq</name>
         <type>int</type>

+ 4 - 0
modules/sca/sca_db.c

@@ -38,6 +38,7 @@ const str  SCA_DB_APP_IDX_COL_NAME = STR_STATIC_INIT( "app_idx" );
 const str  SCA_DB_CALL_ID_COL_NAME = STR_STATIC_INIT( "call_id" );
 const str  SCA_DB_FROM_TAG_COL_NAME = STR_STATIC_INIT( "from_tag" );
 const str  SCA_DB_TO_TAG_COL_NAME = STR_STATIC_INIT( "to_tag" );
+const str  SCA_DB_RECORD_ROUTE_COL_NAME = STR_STATIC_INIT( "record_route" );
 const str  SCA_DB_NOTIFY_CSEQ_COL_NAME = STR_STATIC_INIT( "notify_cseq" );
 const str  SCA_DB_SUBSCRIBE_CSEQ_COL_NAME = STR_STATIC_INIT( "subscribe_cseq" );
 
@@ -55,6 +56,7 @@ sca_db_subscriptions_get_value_for_column( int column, db_val_t *row_values,
     case SCA_DB_SUBS_CALL_ID_COL:
     case SCA_DB_SUBS_FROM_TAG_COL:
     case SCA_DB_SUBS_TO_TAG_COL:
+    case SCA_DB_SUBS_RECORD_ROUTE_COL:
 	((str *)column_value)->s = (char *)row_values[ column ].val.string_val;
 	((str *)column_value)->len = strlen(((str *)column_value)->s );
 	break;
@@ -89,6 +91,7 @@ sca_db_subscriptions_set_value_for_column( int column, db_val_t *row_values,
     case SCA_DB_SUBS_CALL_ID_COL:
     case SCA_DB_SUBS_FROM_TAG_COL:
     case SCA_DB_SUBS_TO_TAG_COL:
+    case SCA_DB_SUBS_RECORD_ROUTE_COL:
 	row_values[ column ].val.str_val = *((str *)column_value);
 	row_values[ column ].type = DB1_STR;
 	row_values[ column ].nul = 0;
@@ -136,6 +139,7 @@ sca_db_subscriptions_columns( void )
 			    (str *)&SCA_DB_CALL_ID_COL_NAME,
 			    (str *)&SCA_DB_FROM_TAG_COL_NAME,
 			    (str *)&SCA_DB_TO_TAG_COL_NAME,
+			    (str *)&SCA_DB_RECORD_ROUTE_COL_NAME,
 			    (str *)&SCA_DB_NOTIFY_CSEQ_COL_NAME,
 			    (str *)&SCA_DB_SUBSCRIBE_CSEQ_COL_NAME,
 			    NULL

+ 4 - 2
modules/sca/sca_db.h

@@ -27,9 +27,9 @@
 #include "../../lib/srdb1/db.h"
 
 
-#define SCA_DB_SUBSCRIPTIONS_TABLE_VERSION	0
+#define SCA_DB_SUBSCRIPTIONS_TABLE_VERSION	1
 
-#define SCA_DB_SUBSCRIPTIONS_NUM_COLUMNS	11
+#define SCA_DB_SUBSCRIPTIONS_NUM_COLUMNS	12
 
 enum {
     SCA_DB_SUBS_SUBSCRIBER_COL = 0,
@@ -41,6 +41,7 @@ enum {
     SCA_DB_SUBS_CALL_ID_COL,
     SCA_DB_SUBS_FROM_TAG_COL,
     SCA_DB_SUBS_TO_TAG_COL,
+    SCA_DB_SUBS_RECORD_ROUTE_COL,
     SCA_DB_SUBS_NOTIFY_CSEQ_COL,
     SCA_DB_SUBS_SUBSCRIBE_CSEQ_COL,
 
@@ -77,6 +78,7 @@ extern const str	SCA_DB_APP_IDX_COL_NAME;
 extern const str	SCA_DB_CALL_ID_COL_NAME;
 extern const str	SCA_DB_FROM_TAG_COL_NAME;
 extern const str	SCA_DB_TO_TAG_COL_NAME;
+extern const str	SCA_DB_RECORD_ROUTE_COL_NAME;
 extern const str	SCA_DB_NOTIFY_CSEQ_COL_NAME;
 extern const str	SCA_DB_SUBSCRIBE_CSEQ_COL_NAME;
 

+ 23 - 2
modules/sca/sca_notify.c

@@ -98,13 +98,13 @@ sca_notify_reply_cb( struct cell *t, int cb_type, struct tmcb_params *cbp )
     static dlg_t *
 sca_notify_dlg_for_subscription( sca_subscription *sub )
 {
-    dlg_t		*dlg;
+    dlg_t		*dlg = NULL;
 
     dlg = (dlg_t *)pkg_malloc( sizeof( dlg_t ));
     if ( dlg == NULL ) {
 	LM_ERR( "pkg_malloc dlg_t for %.*s failed: out of memory",
 		STR_FMT( &sub->subscriber ));
-	return( NULL );
+	goto error;
     }
     memset( dlg, 0, sizeof( dlg_t ));
 
@@ -122,6 +122,16 @@ sca_notify_dlg_for_subscription( sca_subscription *sub )
     dlg->loc_uri = sub->target_aor;
     dlg->rem_uri = sub->target_aor;
 
+    /* restore route */
+    if ( !SCA_STR_EMPTY( &sub->rr )) {
+	if ( parse_rr_body( sub->rr.s, sub->rr.len, &dlg->route_set ) < 0 ) {
+	    LM_ERR( "sca_notify_dlg_for_subscription: failed to parse "
+		    "%.*s subscription's Record-Route info",
+		    STR_FMT( &sub->subscriber ));
+	    goto error;
+	}
+    }
+
     /*
      * the dialog state in an SCA NOTIFY should always be confirmed,
      * since we generated the dialog to-tag in our response to the
@@ -130,6 +140,13 @@ sca_notify_dlg_for_subscription( sca_subscription *sub )
     dlg->state = DLG_CONFIRMED;
 
     return( dlg );
+
+error:
+    if ( dlg != NULL ) {
+	pkg_free( dlg );
+    }
+
+    return( NULL );
 }
 
     static int
@@ -281,6 +298,10 @@ sca_notify_subscriber_internal( sca_mod *scam, sca_subscription *sub,
 
 done:
     if ( dlg != NULL ) {
+	if ( dlg->route_set != NULL ) {
+	    free_rr( &dlg->route_set );
+	}
+
 	pkg_free( dlg );
     }
 

+ 52 - 3
modules/sca/sca_subscribe.c

@@ -186,6 +186,8 @@ sca_subscription_from_db_row_values( db_val_t *values, sca_subscription *sub )
 						&sub->dialog.from_tag );
     sca_db_subscriptions_get_value_for_column( SCA_DB_SUBS_TO_TAG_COL, values,
 						&sub->dialog.to_tag );
+    sca_db_subscriptions_get_value_for_column( SCA_DB_SUBS_RECORD_ROUTE_COL,
+						values, &sub->rr );
     sca_db_subscriptions_get_value_for_column( SCA_DB_SUBS_NOTIFY_CSEQ_COL,
 					    values, &sub->dialog.notify_cseq );
     sca_db_subscriptions_get_value_for_column( SCA_DB_SUBS_SUBSCRIBE_CSEQ_COL,
@@ -220,6 +222,8 @@ sca_subscription_to_db_row_values( sca_subscription *sub, db_val_t *values )
 						&sub->dialog.from_tag );
     sca_db_subscriptions_set_value_for_column( SCA_DB_SUBS_TO_TAG_COL, values,
 						&sub->dialog.to_tag );
+    sca_db_subscriptions_set_value_for_column( SCA_DB_SUBS_RECORD_ROUTE_COL,
+						values, &sub->rr );
 
     notify_cseq = sub->dialog.notify_cseq + 1;
     subscribe_cseq = sub->dialog.subscribe_cseq + 1;
@@ -542,13 +546,16 @@ sca_subscription_db_update_timer( unsigned int ticks, void *param )
     sca_subscription *
 sca_subscription_create( str *aor, int event, str *subscriber,
 	unsigned int notify_cseq, unsigned int subscribe_cseq, int expire_delta,
-	str *call_id, str *from_tag, str *to_tag, int opts )
+	str *call_id, str *from_tag, str *to_tag, str *rr, int opts )
 {
     sca_subscription		*sub = NULL;
     int				len = 0;
 
     len += sizeof( sca_subscription );
     len += sizeof( char ) * ( aor->len + subscriber->len );
+    if ( !SCA_STR_EMPTY( rr )) {
+	len += sizeof( char ) * rr->len;
+    }
 
     sub = (sca_subscription *)shm_malloc( len );
     if ( sub == NULL ) {
@@ -580,6 +587,12 @@ sca_subscription_create( str *aor, int event, str *subscriber,
     SCA_STR_COPY( &sub->target_aor, aor );
     len += aor->len;
 
+    if ( !SCA_STR_EMPTY( rr )) {
+	sub->rr.s = (char *)sub + len;
+	SCA_STR_COPY( &sub->rr, rr );
+	len += rr->len;
+    }
+
     /*
      * dialog.id holds call-id + from-tag + to-tag; dialog.call_id,
      * dialog.from_tag, and dialog.to_tag point to offsets within
@@ -664,7 +677,8 @@ sca_subscription_print( void *value )
     sca_subscription		*sub = (sca_subscription *)value;
 
     LM_INFO( "%.*s %s (%d) %.*s, expires: %ld, index: %d, "
-	     "dialog %.*s;%.*s;%.*s, notify_cseq: %d, subscribe_cseq: %d",
+	     "dialog %.*s;%.*s;%.*s, record_route: %.*s, "
+	     "notify_cseq: %d, subscribe_cseq: %d",
 		STR_FMT( &sub->target_aor ),
 		sca_event_name_from_type( sub->event ),
 		sub->event,
@@ -673,6 +687,8 @@ sca_subscription_print( void *value )
 		STR_FMT( &sub->dialog.call_id ),
 		STR_FMT( &sub->dialog.from_tag ),
 		STR_FMT( &sub->dialog.to_tag ),
+		SCA_STR_EMPTY( &sub->rr ) ? 4 : sub->rr.len,
+		SCA_STR_EMPTY( &sub->rr ) ? "null" : sub->rr.s,
 		sub->dialog.notify_cseq,
 		sub->dialog.subscribe_cseq );
 }
@@ -694,7 +710,8 @@ sca_subscription_save_unsafe( sca_mod *scam, sca_subscription *sub,
 				       sub->expires,
 				       &sub->dialog.call_id,
 				       &sub->dialog.from_tag,
-				       &sub->dialog.to_tag, opts );
+				       &sub->dialog.to_tag,
+				       &sub->rr, opts );
     if ( new_sub == NULL ) {
 	return( -1 );
     }
@@ -819,6 +836,18 @@ sca_subscription_update_unsafe( sca_mod *scam, sca_subscription *saved_sub,
     /* set notify_cseq in update_sub, since we use it to send the NOTIFY */
     update_sub->dialog.notify_cseq = saved_sub->dialog.notify_cseq;
 
+    /* ensure we send the NOTIFY back through the same path as the SUBSCRIBE */
+    if ( SCA_STR_EMPTY( &update_sub->rr ) && !SCA_STR_EMPTY( &saved_sub->rr )) {
+	update_sub->rr.s = (char *)pkg_malloc( saved_sub->rr.len );
+	if ( update_sub->rr.s == NULL ) {
+	    LM_ERR( "sca_subscription_update_unsafe: pkg_malloc record-route "
+		    "value %.*s failed", STR_FMT( &saved_sub->rr ));
+	    goto done;
+	}
+
+	SCA_STR_COPY( &update_sub->rr, &saved_sub->rr );
+    }
+
     rc = 1;
 
 done:
@@ -997,6 +1026,18 @@ sca_subscription_from_request( sca_mod *scam, sip_msg_t *msg, int event_type,
 			STR_FMT( &REQ_LINE( msg ).uri ));
 	    goto error;
 	}
+
+	if ( !SCA_HEADER_EMPTY( msg->record_route )) {
+	    if ( print_rr_body( msg->record_route, &req_sub->rr,
+				0, NULL ) < 0 ) {
+		LM_ERR( "Failed to parse Record-Route header %.*s in "
+			"SUBSCRIBE %.*s from %.*s",
+			STR_FMT( &msg->record_route->body ),
+			STR_FMT( &REQ_LINE( msg ).uri ),
+			STR_FMT( &contact_uri ));
+		goto error;
+	    }
+	}
     }
 
     req_sub->subscriber = contact_uri;
@@ -1035,6 +1076,11 @@ sca_subscription_from_request( sca_mod *scam, sip_msg_t *msg, int event_type,
 error:
     free_to_params( &tmp_to );
 
+    if ( !SCA_STR_EMPTY( &req_sub->rr )) {
+	pkg_free( req_sub->rr.s );
+	req_sub->rr.s = NULL;
+    }
+
     return( -1 );
 }
 
@@ -1224,6 +1270,9 @@ done:
     if ( req_sub.dialog.to_tag.s != NULL ) {
 	pkg_free( req_sub.dialog.to_tag.s );
     }
+    if ( req_sub.rr.s != NULL ) {
+	pkg_free( req_sub.rr.s );
+    }
 
     return( rc );
 }

+ 2 - 0
modules/sca/sca_subscribe.h

@@ -49,6 +49,8 @@ struct _sca_subscription {
 
     sca_dialog	dialog;		/* call-id, to- and from-tags, cseq */
 
+    str		rr;		/* Record-Route header values */
+
     int		db_cmd_flag;	/* track whether to INSERT or UPDATE */
 };
 typedef struct _sca_subscription	sca_subscription;

+ 2 - 2
utils/kamctl/db_berkeley/kamailio/sca_subscriptions

@@ -1,5 +1,5 @@
 METADATA_COLUMNS
-id(int) subscriber(str) aor(str) event(int) expires(int) state(int) app_idx(int) call_id(str) from_tag(str) to_tag(str) notify_cseq(int) subscribe_cseq(int)
+id(int) subscriber(str) aor(str) event(int) expires(int) state(int) app_idx(int) call_id(str) from_tag(str) to_tag(str) record_route(str) notify_cseq(int) subscribe_cseq(int)
 METADATA_KEY
 
 METADATA_READONLY
@@ -7,4 +7,4 @@ METADATA_READONLY
 METADATA_LOGFLAGS
 0
 METADATA_DEFAULTS
-NIL|NIL|NIL|0|0|0|0|NIL|NIL|NIL|NIL|NIL
+NIL|NIL|NIL|0|0|0|0|NIL|NIL|NIL|NIL|NIL|NIL

+ 2 - 1
utils/kamctl/db_sqlite/sca-create.sql

@@ -1,4 +1,4 @@
-INSERT INTO version (table_name, table_version) values ('sca_subscriptions','0');
+INSERT INTO version (table_name, table_version) values ('sca_subscriptions','1');
 CREATE TABLE sca_subscriptions (
     id INTEGER PRIMARY KEY NOT NULL,
     subscriber VARCHAR(255) NOT NULL,
@@ -10,6 +10,7 @@ CREATE TABLE sca_subscriptions (
     call_id VARCHAR(255) NOT NULL,
     from_tag VARCHAR(64) NOT NULL,
     to_tag VARCHAR(64) NOT NULL,
+    record_route TEXT DEFAULT NULL,
     notify_cseq INTEGER NOT NULL,
     subscribe_cseq INTEGER NOT NULL,
     CONSTRAINT sca_subscriptions_sca_subscriptions_idx UNIQUE (subscriber, call_id, from_tag, to_tag)

+ 1 - 1
utils/kamctl/dbtext/kamailio/sca_subscriptions

@@ -1 +1 @@
-id(int,auto) subscriber(string) aor(string) event(int) expires(int) state(int) app_idx(int) call_id(string) from_tag(string) to_tag(string) notify_cseq(int) subscribe_cseq(int) 
+id(int,auto) subscriber(string) aor(string) event(int) expires(int) state(int) app_idx(int) call_id(string) from_tag(string) to_tag(string) record_route(string,null) notify_cseq(int) subscribe_cseq(int) 

+ 2 - 1
utils/kamctl/mysql/sca-create.sql

@@ -1,4 +1,4 @@
-INSERT INTO version (table_name, table_version) values ('sca_subscriptions','0');
+INSERT INTO version (table_name, table_version) values ('sca_subscriptions','1');
 CREATE TABLE sca_subscriptions (
     id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
     subscriber VARCHAR(255) NOT NULL,
@@ -10,6 +10,7 @@ CREATE TABLE sca_subscriptions (
     call_id VARCHAR(255) NOT NULL,
     from_tag VARCHAR(64) NOT NULL,
     to_tag VARCHAR(64) NOT NULL,
+    record_route TEXT DEFAULT NULL,
     notify_cseq INT(11) NOT NULL,
     subscribe_cseq INT(11) NOT NULL,
     CONSTRAINT sca_subscriptions_idx UNIQUE (subscriber, call_id, from_tag, to_tag)

+ 2 - 1
utils/kamctl/oracle/sca-create.sql

@@ -1,4 +1,4 @@
-INSERT INTO version (table_name, table_version) values ('sca_subscriptions','0');
+INSERT INTO version (table_name, table_version) values ('sca_subscriptions','1');
 CREATE TABLE sca_subscriptions (
     id NUMBER(10) PRIMARY KEY,
     subscriber VARCHAR2(255),
@@ -10,6 +10,7 @@ CREATE TABLE sca_subscriptions (
     call_id VARCHAR2(255),
     from_tag VARCHAR2(64),
     to_tag VARCHAR2(64),
+    record_route CLOB,
     notify_cseq NUMBER(10),
     subscribe_cseq NUMBER(10),
     CONSTRAINT ORA_sca_subscriptions_idx  UNIQUE (subscriber, call_id, from_tag, to_tag)

+ 2 - 1
utils/kamctl/postgres/sca-create.sql

@@ -1,4 +1,4 @@
-INSERT INTO version (table_name, table_version) values ('sca_subscriptions','0');
+INSERT INTO version (table_name, table_version) values ('sca_subscriptions','1');
 CREATE TABLE sca_subscriptions (
     id SERIAL PRIMARY KEY NOT NULL,
     subscriber VARCHAR(255) NOT NULL,
@@ -10,6 +10,7 @@ CREATE TABLE sca_subscriptions (
     call_id VARCHAR(255) NOT NULL,
     from_tag VARCHAR(64) NOT NULL,
     to_tag VARCHAR(64) NOT NULL,
+    record_route TEXT DEFAULT NULL,
     notify_cseq INTEGER NOT NULL,
     subscribe_cseq INTEGER NOT NULL,
     CONSTRAINT sca_subscriptions_sca_subscriptions_idx UNIQUE (subscriber, call_id, from_tag, to_tag)