# HG changeset patch # User Sebastien Decugis # Date 1360860777 -3600 # Node ID 877592751fee97896606a70ce5277bda84eee86f # Parent 6a4d08e239bdfec8f27a7a1948c8a5bc5dcb7287 Fix (tentative) for invalid handling of sessions fast creation/destruction as pointed by Yusuke Okura -- http://lists.freediameter.net/pipermail/help/2013-February/000584.html and http://lists.freediameter.net/pipermail/help/2013-February/000589.html -- Thank you very much diff -r 6a4d08e239bd -r 877592751fee extensions/app_radgw/rgwx_auth.c --- a/extensions/app_radgw/rgwx_auth.c Thu Feb 14 15:58:55 2013 +0100 +++ b/extensions/app_radgw/rgwx_auth.c Thu Feb 14 17:52:57 2013 +0100 @@ -457,7 +457,7 @@ if (si_len) { /* We already have the Session-Id, just use it */ - CHECK_FCT( fd_sess_fromsid ( si, si_len, session, NULL) ); + CHECK_FCT( fd_sess_fromsid_msg ( si, si_len, session, NULL) ); } else { /* Create a new Session-Id string */ @@ -495,6 +495,7 @@ value.os.len = sess_strlen; CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) ); + CHECK_FCT( fd_msg_sess_set( *diam_fw, *session) ); } diff -r 6a4d08e239bd -r 877592751fee extensions/app_radgw/rgwx_sip.c --- a/extensions/app_radgw/rgwx_sip.c Thu Feb 14 15:58:55 2013 +0100 +++ b/extensions/app_radgw/rgwx_sip.c Thu Feb 14 17:52:57 2013 +0100 @@ -479,6 +479,7 @@ value.os.len = sidlen; CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) ); + CHECK_FCT( fd_msg_sess_set( *diam_fw, *session) ); /* If the RADIUS Access-Request message does not diff -r 6a4d08e239bd -r 877592751fee extensions/app_sip/registrationtermination.c --- a/extensions/app_sip/registrationtermination.c Thu Feb 14 15:58:55 2013 +0100 +++ b/extensions/app_sip/registrationtermination.c Thu Feb 14 17:52:57 2013 +0100 @@ -147,15 +147,7 @@ // Create a new session { #define APP_SIP_SID_OPT "app_sip" - CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)APP_SIP_SID_OPT, CONSTSTRLEN(APP_SIP_SID_OPT) )); - os0_t sid; - size_t sidlen; - CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); - CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); - value.os.data = sid; - value.os.len = sidlen; - CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); - CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); + CHECK_FCT( fd_msg_new_session( message, (os0_t)APP_SIP_SID_OPT, CONSTSTRLEN(APP_SIP_SID_OPT) ) ); } //Add the Auth-Application-Id diff -r 6a4d08e239bd -r 877592751fee extensions/test_app/ta_bench.c --- a/extensions/test_app/ta_bench.c Thu Feb 14 15:58:55 2013 +0100 +++ b/extensions/test_app/ta_bench.c Thu Feb 14 17:52:57 2013 +0100 @@ -121,7 +121,6 @@ struct avp * avp; union avp_value val; struct ta_mess_info * mi = NULL; - struct session *sess = NULL; TRACE_DEBUG(FULL, "Creating a new message for sending."); @@ -130,7 +129,7 @@ /* Create a new session */ #define TEST_APP_SID_OPT "app_testb" - CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out ); + CHECK_FCT_DO( fd_msg_new_session( req, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out ); /* Create the random value to store with the session */ mi = malloc(sizeof(struct ta_mess_info)); @@ -143,19 +142,6 @@ /* Now set all AVPs values */ - /* Session-Id */ - { - os0_t sid; - size_t sidlen; - CHECK_FCT_DO( fd_sess_getsid ( sess, &sid, &sidlen ), goto out ); - CHECK_FCT_DO( fd_msg_avp_new ( ta_sess_id, 0, &avp ), goto out ); - val.os.data = sid; - val.os.len = sidlen; - CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); - CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ), goto out ); - - } - /* Set the Destination-Realm AVP */ { CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_realm, 0, &avp ), goto out ); diff -r 6a4d08e239bd -r 877592751fee extensions/test_app/ta_cli.c --- a/extensions/test_app/ta_cli.c Thu Feb 14 15:58:55 2013 +0100 +++ b/extensions/test_app/ta_cli.c Thu Feb 14 17:52:57 2013 +0100 @@ -150,7 +150,8 @@ /* Create a new session */ #define TEST_APP_SID_OPT "app_test" - CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out ); + CHECK_FCT_DO( fd_msg_new_session( req, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out ); + CHECK_FCT_DO( fd_msg_sess_get(fd_g_config->cnf_dict, req, &sess, NULL), goto out ); /* Create the random value to store with the session */ mi = malloc(sizeof(struct ta_mess_info)); @@ -163,19 +164,6 @@ /* Now set all AVPs values */ - /* Session-Id */ - { - os0_t sid; - size_t sidlen; - CHECK_FCT_DO( fd_sess_getsid ( sess, &sid, &sidlen ), goto out ); - CHECK_FCT_DO( fd_msg_avp_new ( ta_sess_id, 0, &avp ), goto out ); - val.os.data = sid; - val.os.len = sidlen; - CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); - CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ), goto out ); - - } - /* Set the Destination-Realm AVP */ { CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_realm, 0, &avp ), goto out ); diff -r 6a4d08e239bd -r 877592751fee extensions/test_sip/locationinfo.c --- a/extensions/test_sip/locationinfo.c Thu Feb 14 15:58:55 2013 +0100 +++ b/extensions/test_sip/locationinfo.c Thu Feb 14 17:52:57 2013 +0100 @@ -41,7 +41,6 @@ struct dict_object * lir_model=NULL; struct msg * message=NULL; struct avp *avp=NULL; - struct session *sess=NULL; union avp_value value; //Fake values START @@ -61,15 +60,7 @@ // Create a new session { - CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 )); - os0_t sid; - size_t sidlen; - CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); - CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); - value.os.data = sid; - value.os.len = sidlen; - CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); - CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); + CHECK_FCT( fd_msg_new_session( message, (os0_t)"appsip", CONSTSTRLEN("appsip") ) ); } //Add the Auth-Application-Id diff -r 6a4d08e239bd -r 877592751fee extensions/test_sip/locationinfosl.c --- a/extensions/test_sip/locationinfosl.c Thu Feb 14 15:58:55 2013 +0100 +++ b/extensions/test_sip/locationinfosl.c Thu Feb 14 17:52:57 2013 +0100 @@ -41,7 +41,6 @@ struct dict_object * lir_model=NULL; struct msg * message=NULL; struct avp *avp=NULL; - struct session *sess=NULL; union avp_value value; //Fake values START @@ -61,15 +60,7 @@ // Create a new session { - CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 )); - os0_t sid; - size_t sidlen; - CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); - CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); - value.os.data = sid; - value.os.len = sidlen; - CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); - CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); + CHECK_FCT( fd_msg_new_session( message, (os0_t)"appsip", CONSTSTRLEN("appsip") ) ); } //Add the Auth-Application-Id diff -r 6a4d08e239bd -r 877592751fee extensions/test_sip/serverassignment.c --- a/extensions/test_sip/serverassignment.c Thu Feb 14 15:58:55 2013 +0100 +++ b/extensions/test_sip/serverassignment.c Thu Feb 14 17:52:57 2013 +0100 @@ -41,7 +41,6 @@ struct dict_object * sar_model=NULL; struct msg * message=NULL; struct avp *avp=NULL; - struct session *sess=NULL; union avp_value value; //Fake values START @@ -70,15 +69,7 @@ // Create a new session { - CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 )); - os0_t sid; - size_t sidlen; - CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); - CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); - value.os.data = sid; - value.os.len = sidlen; - CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); - CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); + CHECK_FCT( fd_msg_new_session( message, (os0_t)"appsip", CONSTSTRLEN("appsip") ) ); } //Add the Auth-Application-Id diff -r 6a4d08e239bd -r 877592751fee extensions/test_sip/userauthorization.c --- a/extensions/test_sip/userauthorization.c Thu Feb 14 15:58:55 2013 +0100 +++ b/extensions/test_sip/userauthorization.c Thu Feb 14 17:52:57 2013 +0100 @@ -41,7 +41,6 @@ struct dict_object * uar_model=NULL; struct msg * message=NULL; struct avp *avp=NULL; - struct session *sess=NULL; union avp_value value; //Fake values START @@ -66,15 +65,7 @@ // Create a new session { - CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 )); - os0_t sid; - size_t sidlen; - CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); - CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); - value.os.data = sid; - value.os.len = sidlen; - CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); - CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); + CHECK_FCT( fd_msg_new_session( message, (os0_t)"appsip", CONSTSTRLEN("appsip") ) ); } //Add the Auth-Application-Id diff -r 6a4d08e239bd -r 877592751fee include/freeDiameter/libfdproto.h --- a/include/freeDiameter/libfdproto.h Thu Feb 14 15:58:55 2013 +0100 +++ b/include/freeDiameter/libfdproto.h Thu Feb 14 17:52:57 2013 +0100 @@ -1815,9 +1815,9 @@ * If diamId is NULL, the string is exactly the content of opt. * * RETURN VALUE: - * 0 : The session is created. + * 0 : The session is created, the initial msg refcount is 1. * EINVAL : A parameter is invalid. - * EALREADY : A session with the same name already exists (returned in *session) + * EALREADY : A session with the same name already exists (returned in *session), the msg refcount is increased. * ENOMEM : Not enough memory to complete the operation */ int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen ); @@ -2504,6 +2504,10 @@ */ int fd_msg_sess_get(struct dictionary * dict, struct msg * msg, struct session ** session, int * isnew); +/* This one is used by the libfdcore, you should use fd_msg_new_session rather than fd_sess_new, when possible */ +int fd_msg_sess_set(struct msg * msg, struct session * session); + + /***************************************/ /* Manage AVP values */ /***************************************/ diff -r 6a4d08e239bd -r 877592751fee libfdcore/messages.c --- a/libfdcore/messages.c Thu Feb 14 15:58:55 2013 +0100 +++ b/libfdcore/messages.c Thu Feb 14 17:52:57 2013 +0100 @@ -158,6 +158,9 @@ /* Add it to the message */ CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) ); + /* Save the session associated with the message */ + CHECK_FCT( fd_msg_sess_set( msg, sess) ); + /* Done! */ return 0; } diff -r 6a4d08e239bd -r 877592751fee libfdproto/fdproto-internal.h --- a/libfdproto/fdproto-internal.h Thu Feb 14 15:58:55 2013 +0100 +++ b/libfdproto/fdproto-internal.h Thu Feb 14 17:52:57 2013 +0100 @@ -69,6 +69,7 @@ int fd_sess_ref_msg ( struct session * session ); int fd_sess_reclaim_msg ( struct session ** session ); + /* For dump routines into string buffers */ #include static __inline__ int dump_init_str(char **outstr, size_t *offset, size_t *outlen) diff -r 6a4d08e239bd -r 877592751fee libfdproto/messages.c --- a/libfdproto/messages.c Thu Feb 14 15:58:55 2013 +0100 +++ b/libfdproto/messages.c Thu Feb 14 17:52:57 2013 +0100 @@ -1215,6 +1215,20 @@ return 0; } +/* Associate a session with a message, use only when the session was just created */ +int fd_msg_sess_set(struct msg * msg, struct session * session) +{ + TRACE_ENTRY("%p %p", msg, session); + + /* Check we received valid parameters */ + CHECK_PARAMS( CHECK_MSG(msg) ); + CHECK_PARAMS( session ); + CHECK_PARAMS( msg->msg_sess == NULL ); + + msg->msg_sess = session; + return 0; +} + /* Retrieve the session of the message */ int fd_msg_sess_get(struct dictionary * dict, struct msg * msg, struct session ** session, int * new) diff -r 6a4d08e239bd -r 877592751fee libfdproto/sessions.c --- a/libfdproto/sessions.c Thu Feb 14 15:58:55 2013 +0100 +++ b/libfdproto/sessions.c Thu Feb 14 17:52:57 2013 +0100 @@ -359,7 +359,7 @@ -/* Create a new session object with the default timeout value, and link it */ +/* Create a new session object with the default timeout value, and link it. The refcount is increased by 1, whether the session existed or not */ int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen ) { os0_t sid = NULL; @@ -460,16 +460,22 @@ } ); fd_list_insert_before(li, &sess->chain_h); /* hash table */ + sess->msg_cnt++; } else { free(sid); + + CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) ); + (*session)->msg_cnt++; + CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) ); + /* it was found: was it previously destroyed? */ if ((*session)->is_destroyed == 0) { ret = EALREADY; goto out; } else { /* the session was marked destroyed, let's re-activate it. */ - TODO("Re-creating a deleted session. Should investigate if this can lead to an issue... (need more feedback)"); sess = *session; + sess->is_destroyed = 0; /* update the expiry time */ CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &sess->timeout), { ASSERT(0); } ); @@ -500,7 +506,7 @@ CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); } ); /* if it fails, we might not pop the cleanup handler, but this should not happen -- and we'd have a serious problem otherwise */ out: - ; + ; pthread_cleanup_pop(0); CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) ); @@ -511,8 +517,8 @@ return 0; } -/* Find or create a session */ -int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * new) +/* Find or create a session -- the msg refcount is increased */ +int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new) { int ret; @@ -801,17 +807,19 @@ } /* For the messages module */ -int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new) +int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * new) { TRACE_ENTRY("%p %zd %p %p", sid, len, session, new); CHECK_PARAMS( sid && len && session ); /* Get the session object */ - CHECK_FCT( fd_sess_fromsid ( sid, len, session, new) ); + CHECK_FCT( fd_sess_fromsid_msg ( sid, len, session, new) ); - /* Increase count */ - CHECK_FCT( fd_sess_ref_msg ( *session ) ); - + /* Decrease the refcount */ + CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) ); + (*session)->msg_cnt--; /* was increased in fd_sess_new */ + CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) ); + /* Done */ return 0; } @@ -832,16 +840,27 @@ int fd_sess_reclaim_msg ( struct session ** session ) { int reclaim; + uint32_t hash; TRACE_ENTRY("%p", session); CHECK_PARAMS( session && VALIDATE_SI(*session) ); + /* Lock the hash line to avoid possibility that session is freed while we are reclaiming */ + hash = (*session)->hash; + CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash)) ); + pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) ); + /* Update the msg refcount */ CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) ); reclaim = (*session)->msg_cnt; (*session)->msg_cnt = reclaim - 1; CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) ); + /* Ok, now unlock the hash line */ + pthread_cleanup_pop( 0 ); + CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) ); + + /* and reclaim if no message references the session anymore */ if (reclaim == 1) { CHECK_FCT(fd_sess_reclaim ( session )); } else {