示例#1
0
文件: dlg_state.c 项目: asyn/openvims
/**
 * Find out if a message is within a saved dialog.
 * @param msg - the SIP message
 * @param str1 - the direction of the dialog ("orig"/"term")
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if in, #CSCF_RETURN_FALSE else or #CSCF_RETURN_BREAK on error
 */
int P_is_in_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	str host;
	int port,transport;
	enum p_dialog_direction dir;

	dir = get_dialog_direction(str1);
	
	if (!find_dialog_contact(msg,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_is_in_dialog(%s): Error retrieving %s contact\n",str1,str1);
		return CSCF_RETURN_BREAK;
	}		

	//print_p_dialog(L_ERR);
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;
			
	if (is_p_dialog(call_id,host,port,transport,0)) {
		return CSCF_RETURN_TRUE;
	}
	else 
		return CSCF_RETURN_FALSE;
}
示例#2
0
/**
 * Check if the message is from the AS.
 * Inserts route headers and set the dst_uri
 * @param msg - the message to check
 * @param str1 - the direction of the request orig/term
 * @param str2 - not used
 * @returns #ISC_RETURN_TRUE if from AS, #ISC_RETURN_FALSE if not, #ISC_RETURN_BREAK on error
 */
int ISC_from_AS(struct sip_msg *msg,char *str1,char *str2)
{
	int ret = ISC_RETURN_FALSE;
	isc_mark old_mark;
	
	enum dialog_direction dir = get_dialog_direction(str1);
		
	if (dir==DLG_MOBILE_UNKNOWN) 
		return ISC_RETURN_BREAK;
	
	if (!isc_is_initial_request(msg)) return ISC_RETURN_FALSE;
		
	/* starting or resuming? */
	if (isc_mark_get_from_msg(msg,&old_mark)){		
		LOG(L_INFO,"INFO:"M_NAME":ISC_from_AS(%s): Message returned s=%d;h=%d;d=%d\n",
			str1,old_mark.skip,old_mark.handling,old_mark.direction);
		if (old_mark.direction==IFC_ORIGINATING_SESSION && dir!=DLG_MOBILE_ORIGINATING)
			ret = ISC_RETURN_FALSE;
		else
		if ((old_mark.direction==IFC_TERMINATING_SESSION||old_mark.direction==IFC_TERMINATING_UNREGISTERED)
			 && dir!=DLG_MOBILE_TERMINATING)
			ret = ISC_RETURN_FALSE;
		else
			ret = ISC_RETURN_TRUE;
	} else {
		ret = ISC_RETURN_FALSE;
	}
	return ret;
}
示例#3
0
/**
 * Check if we already did record-route
 * @param msg - the SIP message to add to
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error
 */
int S_is_record_routed(struct sip_msg *msg,char *str1,char *str2)
{
	str rr;
	str u = {0,0},scheme={0,0},scscf={0,0};
	struct hdr_field *hdr=0;
	rr_t *rr_s;
	
	enum s_dialog_direction dir = get_dialog_direction(str1);
	
	switch (dir){
		case DLG_MOBILE_ORIGINATING:
			STR_PKG_DUP(rr,scscf_record_route_mo,"pkg");
			break;
		case DLG_MOBILE_TERMINATING:
			STR_PKG_DUP(rr,scscf_record_route_mt,"pkg");
			break;
		default:
			u.s = str1;
			u.len = strlen(str1);
			if (scscf_name_str.len>4 &&
				strncasecmp(scscf_name_str.s,"sip:",4)==0){
				scheme.s = scscf_name_str.s;
				scheme.len = 4;
			}else if (scscf_name_str.len>5 &&
				strncasecmp(scscf_name_str.s,"sips:",5)==0){
				scheme.s = scscf_name_str.s;
				scheme.len = 4;
			}
			scscf.s = scheme.s+scheme.len;
			scscf.len = scscf_name_str.len - scheme.len;
			
			rr.len = scheme.len+u.len+1+scscf.len;
			rr.s = pkg_malloc(rr.len);
			if (!rr.s){
				LOG(L_ERR,"ERR:"M_NAME":S_record_route: error allocating %d bytes!\n",rr.len);	
				return CSCF_RETURN_BREAK;
			}
			rr.len = 0;
			STR_APPEND(rr,scheme);
			STR_APPEND(rr,u);
			rr.s[rr.len++]='@';
			STR_APPEND(rr,scscf);
	}

	for(hdr = cscf_get_next_record_route(msg,(struct hdr_field*) 0); hdr ; hdr = cscf_get_next_record_route(msg,hdr)){
		for (rr_s = (rr_t *)hdr->parsed;rr_s; rr_s = rr_s->next)
			if (rr_s->nameaddr.uri.len == rr.len &&
				strncasecmp(rr_s->nameaddr.uri.s,rr.s,rr.len)==0){
					pkg_free(rr.s);
					return CSCF_RETURN_TRUE;
				}
	}

	pkg_free(rr.s);
	return CSCF_RETURN_FALSE;
out_of_memory:
	return CSCF_RETURN_ERROR;
}
示例#4
0
文件: mod.c 项目: gbour/kamailio
/**
 * Check if the message is from the AS.
 * Inserts route headers and set the dst_uri
 * @param msg - the message to check
 * @param str1 - the direction of the request orig/term
 * @param str2 - not used
 * @returns #ISC_RETURN_TRUE if from AS, #ISC_RETURN_FALSE if not, #ISC_RETURN_BREAK on error
 */
int isc_from_as(struct sip_msg *msg, char *str1, char *str2) {
    int ret = ISC_RETURN_FALSE;
    isc_mark old_mark;
    str s = {0, 0};
    //sometimes s is populated by an ims_getter method cscf_get_terminating_user that alloc memory that must be free-ed at the end
    int free_s = 0;
    
    
    enum dialog_direction dir = get_dialog_direction(str1);

    if (dir == DLG_MOBILE_UNKNOWN)
        return ISC_RETURN_BREAK;

    if (!cscf_is_initial_request(msg))
        return ISC_RETURN_FALSE;

    /* starting or resuming? */
    if (isc_mark_get_from_msg(msg, &old_mark)) {
        LM_DBG("Message returned s=%d;h=%d;d=%d\n", old_mark.skip, old_mark.handling, old_mark.direction);

        /*according to spec 24.229, 5.4.3.3 if the URI is different then the RURI is retargeted and we can do one of 2 things,
         * a) mark as originating session and forward according to normal RURI procedures,
         * b) run IFC criteria on new retrageturi  and route accordingly.
         *
         * We will therefore leave it in the hands of the config writer to decide. We will make them aware here that retargeting has happened
         * by retirning a special error code ISC_RETURN_RETARGET(-2).
         */
        if (dir == DLG_MOBILE_TERMINATING) {
            cscf_get_terminating_user(msg, &s);
            //sometimes s is populated by an ims_getter method cscf_get_terminating_user that alloc memory that must be free-ed at the end
            free_s = 1;
            if (memcmp(old_mark.aor.s, s.s, s.len) != 0) {
                LM_DBG("This is a new call....... RURI has been retargeted\n");
                return ISC_RETURN_RETARGET;
            }
        }
        if (old_mark.direction == IFC_ORIGINATING_SESSION
                && dir != DLG_MOBILE_ORIGINATING)
            ret = ISC_RETURN_FALSE;
        else if ((old_mark.direction == IFC_TERMINATING_SESSION
                || old_mark.direction == IFC_TERMINATING_UNREGISTERED)
                && dir != DLG_MOBILE_TERMINATING)
            ret = ISC_RETURN_FALSE;
        else
            ret = ISC_RETURN_TRUE;
    } else {
        ret = ISC_RETURN_FALSE;
    }
    if (old_mark.aor.s)
        pkg_free(old_mark.aor.s);
    
    if (s.s && free_s == 1)
        shm_free(s.s); // shm_malloc in cscf_get_terminating_user  
    
    return ret;
}
示例#5
0
/**
 * Record routes, with given user as parameter.
 * @param msg - the SIP message to add to
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error
 */ 
int S_record_route(struct sip_msg *msg,char *str1,char *str2)
{
	str rr={0,0};
	str u = {0,0},scheme={0,0},scscf={0,0};
	
	enum s_dialog_direction dir = get_dialog_direction(str1);
	
	switch (dir){
		case DLG_MOBILE_ORIGINATING:
			STR_PKG_DUP(rr,scscf_record_route_mo,"pkg");
			break;
		case DLG_MOBILE_TERMINATING:
			STR_PKG_DUP(rr,scscf_record_route_mt,"pkg");
			break;
		default:
			u.s = str1;
			u.len = strlen(str1);
			if (scscf_name_str.len>4 &&
				strncasecmp(scscf_name_str.s,"sip:",4)==0){
				scheme.s = scscf_name_str.s;
				scheme.len = 4;
			}else if (scscf_name_str.len>5 &&
				strncasecmp(scscf_name_str.s,"sips:",5)==0){
				scheme.s = scscf_name_str.s;
				scheme.len = 4;
			}
			scscf.s = scheme.s+scheme.len;
			scscf.len = scscf_name_str.len - scheme.len;
			
			rr.len = s_record_route_s.len+scheme.len+u.len+1+scscf.len+s_record_route_e.len;
			rr.s = pkg_malloc(rr.len);
			if (!rr.s){
				LOG(L_ERR,"ERR:"M_NAME":S_record_route: error allocating %d bytes!\n",rr.len);	
				return CSCF_RETURN_BREAK;
			}
			rr.len = 0;
			STR_APPEND(rr,s_record_route_s);
			STR_APPEND(rr,scheme);
			STR_APPEND(rr,u);
			rr.s[rr.len++]='@';
			STR_APPEND(rr,scscf);
			STR_APPEND(rr,s_record_route_e);					
	}
	
	if (cscf_add_header_first(msg,&rr,HDR_RECORDROUTE_T)) return CSCF_RETURN_TRUE;
	else{
		if (rr.s) pkg_free(rr.s);
		return CSCF_RETURN_BREAK;
	}
	
out_of_memory:
	return CSCF_RETURN_BREAK;	
}
示例#6
0
文件: dlg_state.c 项目: asyn/openvims
/**
 * Saves a dialog.
 * @param msg - the initial request
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_save_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	str aor;
	str uri,tag;
	str ruri;	
	enum s_dialog_direction dir = get_dialog_direction(str1);
	
	if (!find_dialog_aor(msg,dir,&aor)){
		LOG(L_ERR,"ERR:"M_NAME":S_save_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_INFO,"DBG:"M_NAME":S_save_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	if (is_s_dialog(call_id,aor)){
		LOG(L_ERR,"ERR:"M_NAME":S_save_dialog: dialog already exists!\n");	
		return CSCF_RETURN_FALSE;
	}
	
	d = add_s_dialog(call_id,aor,dir);
	if (!d) return CSCF_RETURN_FALSE;

	d->method = get_dialog_method(msg->first_line.u.request.method);
	STR_SHM_DUP(d->method_str,msg->first_line.u.request.method,"shm");
	d->first_cseq = cscf_get_cseq(msg,0);
	d->last_cseq = d->first_cseq;
	d->state = DLG_STATE_INITIAL;
	d->expires = d_act_time()+60;
	
	cscf_get_from_tag(msg,&tag);
	cscf_get_from_uri(msg,&uri);
	ruri=cscf_get_identity_from_ruri(msg);
	 
	tmb.new_dlg_uac(&call_id,
						&tag,
						d->first_cseq,&uri,
						&ruri,
						&d->dialog_c);
	
	tmb.new_dlg_uas(msg,99,&d->dialog_s);

	d_unlock(d->hash);
	
//	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
示例#7
0
/**
 * Drops and deletes a dialog.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_drop_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	int hash;
//	struct sip_msg *req;
	enum s_dialog_direction dir = get_dialog_direction(str1);
	
	
//	if (!find_dialog_aor(msg,str1,&aor)){
//		LOG(L_ERR,"ERR:"M_NAME":S_is_in_dialog(): Error retrieving %s contact\n",str1);
//		return CSCF_RETURN_BREAK;
//	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":S_drop_dialog(%s): Call-ID <%.*s> DIR[%d]\n",
		str1,call_id.len,call_id.s,
		dir);

	d = get_s_dialog_dir(call_id,dir);
//	if (!d && msg->first_line.type==SIP_REPLY){
//		/* Try to get the dialog from the request */
//		req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}		
//		d = get_s_dialog(call_id,aor);		
//	}
	if (!d){
		LOG(L_ERR,"ERR:"M_NAME":S_drop_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	hash = d->hash;
	
	del_s_dialog(d);
		
	d_unlock(hash);
	
	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
示例#8
0
文件: dlg_state.c 项目: asyn/openvims
/**
 * Drops and deletes a dialog.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_drop_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	p_dialog *d;
	int hash;
	str host;
	int port,transport;
	struct sip_msg *req;
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
	
	if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
	else req = msg;
	if (!find_dialog_contact(req,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_is_in_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":P_drop_dialog(%s): Call-ID <%.*s> %d://%.*s:%d\n",
		str1,call_id.len,call_id.s,
		transport,host.len,host.s,port);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":P_drop_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	hash = d->hash;
	
	del_p_dialog(d);
		
	d_unlock(hash);
	
	print_p_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
/**
 * Drops and deletes a dialog.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int LRF_drop_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	lrf_dialog *d;
	int hash;
	struct sip_msg *req;
	enum lrf_dialog_direction dir;
	str target_uri = {0,0};
	dir = get_dialog_direction(str1);
	
	if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
	else req = msg;
	if (!find_dialog_contact(req,dir,&target_uri)){
		LOG(L_ERR,"ERR:"M_NAME":LRF_is_in_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":LRF_drop_dialog(%s): Call-ID <%.*s>: target <%.*s>\n",
		str1,call_id.len,call_id.s,
		target_uri.len, target_uri.s);
	d = get_lrf_dialog(call_id, &dir);
	if (!d)
		d = get_lrf_dialog(call_id, NULL);
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":LRF_drop_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	hash = d->hash;
	
	del_lrf_dialog(d);
		
	d_unlock(hash);
	
	print_lrf_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
示例#10
0
/**
 * Find out if a message is within a saved dialog.
 * @param msg - the SIP message
 * @param str1 - the direction of the dialog ("orig"/"term")
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if in, #CSCF_RETURN_FALSE else or #CSCF_RETURN_BREAK on error
 */
int S_is_in_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	enum s_dialog_direction dir = get_dialog_direction(str1);
	enum s_dialog_direction dirmsg = find_dialog_route_dir(msg);
	

//	LOG(L_CRIT,"%d - %d\n",dir,dirmsg);
	if (dir!=dirmsg) return CSCF_RETURN_FALSE;				
			
//	print_s_dialogs(L_ERR);
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len){
		
		return CSCF_RETURN_FALSE;
	}
	
	if (is_s_dialog_dir(call_id,dir))
		return CSCF_RETURN_TRUE;
	else 
		return CSCF_RETURN_FALSE;
}
/**
 * Find out if a message is within a saved dialog.
 * @param msg - the SIP message
 * @param str1 - the direction of the dialog ("orig"/"term")
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if in, #CSCF_RETURN_FALSE else or #CSCF_RETURN_BREAK on error
 */
int LRF_is_in_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	enum lrf_dialog_direction dir;
	dir = get_dialog_direction(str1);
	str target_uri={0,0};
	
	if (!find_dialog_contact(msg,dir,&target_uri)){
		LOG(L_ERR,"ERR:"M_NAME":LRF_is_in_dialog(%s): Error retrieving %s contact\n",str1,str1);
		return CSCF_RETURN_BREAK;
	}		

	//print_lrf_dialog(L_ERR);
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;
			
	if (is_lrf_dialog(call_id, 0)) {
		return CSCF_RETURN_TRUE;
	}
	else 
		return CSCF_RETURN_FALSE;
}
示例#12
0
/* Wrapper to send AAR from config file - this only allows for AAR for calls - not register, which uses r_rx_aar_register
 * return: 1 - success, <=0 failure. 2 - message not a AAR generating message (ie proceed without PCC if you wish)
 */
static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {

    int ret = CSCF_RETURN_ERROR;
    struct cell *t;

    AAASession* auth_session;
    rx_authsessiondata_t* rx_authdata_p = 0;
    str *rx_session_id;
    str callid = {0, 0};
    str ftag = {0, 0};
    str ttag = {0, 0};
    
    str route_name;

    cfg_action_t* cfg_action = 0;
    saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call
    char* direction = str1;
    if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
        LM_ERR("no async route block for assign_server_unreg\n");
        return -1;
    }
    
    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
    int ri = route_get(&main_rt, route_name.s);
    if (ri < 0) {
        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
        return -1;
    }
    cfg_action = main_rt.rlist[ri];
    if (cfg_action == NULL) {
        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
        return -1;
    }

    LM_DBG("Rx AAR called\n");
    //create the default return code AVP
    create_return_code(ret);

    //We don't ever do AAR on request for calling scenario...
    if (msg->first_line.type != SIP_REPLY) {
        LM_DBG("Can't do AAR for call session in request\n");
        return CSCF_RETURN_ERROR;
    }

    //is it appropriate to send AAR at this stage?
    t = tmb.t_gett();
    if (t == NULL || t == T_UNDEFINED) {
        LM_WARN("Cannot get transaction for AAR based on SIP Request\n");
        //goto aarna;
        return CSCF_RETURN_ERROR;
    }

    //we dont apply QoS if its not a reply to an INVITE! or UPDATE or PRACK!
    if ((t->method.len == 5 && memcmp(t->method.s, "PRACK", 5) == 0)
            || (t->method.len == 6 && (memcmp(t->method.s, "INVITE", 6) == 0
            || memcmp(t->method.s, "UPDATE", 6) == 0))) {
        if (cscf_get_content_length(msg) == 0
                || cscf_get_content_length(t->uas.request) == 0) {
            LM_DBG("No SDP offer answer -> therefore we can not do Rx AAR");
            //goto aarna; //AAR na if we dont have offer/answer pair
            return CSCF_RETURN_ERROR;
        }
    } else {
        LM_DBG("Message is not response to INVITE, PRACK or UPDATE -> therefore we do not Rx AAR");
        return CSCF_RETURN_ERROR;
    }

    /* get callid, from and to tags to be able to identify dialog */
    callid = cscf_get_call_id(msg, 0);
    if (callid.len <= 0 || !callid.s) {
        LM_ERR("unable to get callid\n");
        return CSCF_RETURN_ERROR;
    }
    if (!cscf_get_from_tag(msg, &ftag)) {
        LM_ERR("Unable to get ftag\n");
        return CSCF_RETURN_ERROR;
    }
    if (!cscf_get_to_tag(msg, &ttag)) {
        LM_ERR("Unable to get ttag\n");
        return CSCF_RETURN_ERROR;
    }

    //check to see that this is not a result of a retransmission in reply route only
    if (msg->cseq == NULL
            && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || (msg->cseq == NULL))) {
        LM_ERR("No Cseq header found - aborting\n");
        return CSCF_RETURN_ERROR;
    }

    saved_t_data = (saved_transaction_t*) shm_malloc(sizeof (saved_transaction_t));
    if (!saved_t_data) {
        LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n");
        return CSCF_RETURN_ERROR;
    }
    memset(saved_t_data, 0, sizeof (saved_transaction_t));
    saved_t_data->act = cfg_action;
    //OTHER parms need after async response set here
    //store call id
    saved_t_data->callid.s = (char*) shm_malloc(callid.len + 1);
    if (!saved_t_data->callid.s) {
        LM_ERR("no more memory trying to save transaction state : callid\n");
        shm_free(saved_t_data);
        return CSCF_RETURN_ERROR;
    }
    memset(saved_t_data->callid.s, 0, callid.len + 1);
    memcpy(saved_t_data->callid.s, callid.s, callid.len);
    saved_t_data->callid.len = callid.len;

    //store ttag
    saved_t_data->ttag.s = (char*) shm_malloc(ttag.len + 1);
    if (!saved_t_data->ttag.s) {
        LM_ERR("no more memory trying to save transaction state : ttag\n");
        shm_free(saved_t_data);
        return CSCF_RETURN_ERROR;
    }
    memset(saved_t_data->ttag.s, 0, ttag.len + 1);
    memcpy(saved_t_data->ttag.s, ttag.s, ttag.len);
    saved_t_data->ttag.len = ttag.len;

    //store ftag
    saved_t_data->ftag.s = (char*) shm_malloc(ftag.len + 1);
    if (!saved_t_data->ftag.s) {
        LM_ERR("no more memory trying to save transaction state : ftag\n");
        shm_free(saved_t_data);
        return CSCF_RETURN_ERROR;
    }
    memset(saved_t_data->ftag.s, 0, ftag.len + 1);
    memcpy(saved_t_data->ftag.s, ftag.s, ftag.len);
    saved_t_data->ftag.len = ftag.len;

    //store branch
    int branch;
    if (tmb.t_check( msg  , &branch )==-1){
        LOG(L_ERR, "ERROR: t_suspend: failed find UAC branch\n");
        return CSCF_RETURN_ERROR;
    }
    
    //Check that we dont already have an auth session for this specific dialog
    //if not we create a new one and attach it to the dialog (via session ID).
    enum dialog_direction dlg_direction = get_dialog_direction(direction);
    if (dlg_direction == DLG_MOBILE_ORIGINATING) {
        rx_session_id = dlgb.get_dlg_var(&callid, &ftag, &ttag,
                &orig_session_key);
    } else {
        rx_session_id = dlgb.get_dlg_var(&callid, &ftag, &ttag,
                &term_session_key);
    }

    if (!rx_session_id || rx_session_id->len <= 0 || !rx_session_id->s) {
        LM_DBG("New AAR session for this dialog in mode %s\n", direction);
        //create new diameter auth session
        int ret = create_new_callsessiondata(&callid, &ftag, &ttag, &rx_authdata_p);
        if (!ret) {
            LM_DBG("Unable to create new media session data parcel\n");
            goto error;
        }
        auth_session = cdpb.AAACreateClientAuthSession(1, callback_for_cdp_session, rx_authdata_p); //returns with a lock
        if (!auth_session) {
            LM_ERR("Rx: unable to create new Rx Media Session\n");
            if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash);
            if (rx_authdata_p) {
                shm_free(rx_authdata_p);
                rx_authdata_p = 0;
            }
            goto error;
        }

        //attach new cdp auth session to dlg for this direction
        if (dlg_direction == DLG_MOBILE_ORIGINATING) {
            dlgb.set_dlg_var(&callid, &ftag, &ttag,
                    &orig_session_key, &auth_session->id);
        } else {
            dlgb.set_dlg_var(&callid, &ftag, &ttag,
                    &term_session_key, &auth_session->id);
        }
        LM_DBG("Attached CDP auth session [%.*s] for Rx to dialog in %s mode\n", auth_session->id.len, auth_session->id.s, direction);
    } else {
        LM_DBG("Update AAR session for this dialog in mode %s\n", direction);
        if (saved_t_data)
                free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
        create_return_code(CSCF_RETURN_TRUE);
        return CSCF_RETURN_TRUE;
    }

    LM_DBG("Suspending SIP TM transaction\n");
    if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
        LM_ERR("failed to suspend the TM processing\n");
        free_saved_transaction_global_data(saved_t_data);
        return CSCF_RETURN_ERROR;
    }

    LM_DBG("Sending Rx AAR");
    ret = rx_send_aar(t->uas.request, msg, auth_session, direction, saved_t_data);

    if (!ret) {
        LM_ERR("Failed to send AAR\n");
        tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
        goto error;


    } else {
        LM_DBG("Successful async send of AAR\n");
        return CSCF_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process
    }

error:
    LM_ERR("Error trying to send AAR (calling)\n");
    if (saved_t_data)
        free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
    //otherwise the callback will segfault

     return CSCF_RETURN_ERROR;
}
示例#13
0
文件: dlg_state.c 项目: asyn/openvims
/**
 * Updates a dialog.
 * If the initial request was:
 * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog 
 * if found
 * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration 
 * and if terminated destroys the dialog
 * - When adding more dialogs, add the refreshal methods here or they will expire and will
 * be destroyed. Also add the termination to reduce the memory consumption and improve the
 * performance.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_update_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	p_dialog *d;
	int response;
	int cseq;
	struct hdr_field *h=0;
	struct sip_msg *req=0;
	str host;
	int port,transport;
	int expires;
	str totag;
	time_t t_time=0;
	str ses_exp = {0,0};
	str refresher = {0,0};
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
	
	if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
	else req = msg;
	if (!find_dialog_contact(req,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		if (msg->first_line.type==SIP_REQUEST &&
			msg->first_line.u.request.method.len == 3 && 
			strncasecmp(msg->first_line.u.request.method.s,"ACK",3)){
			/* to skip the ACK after a 4xx when the dialog was dropped already*/
			return CSCF_RETURN_TRUE;
		}else{
			LOG(L_CRIT,"ERR:"M_NAME":P_update_dialog: dialog does not exists!\n");
			return CSCF_RETURN_FALSE;
		}	
	}


	if (msg->first_line.type==SIP_REQUEST){
		/* Request */
		LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Method <%.*s> \n",str1,
			msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq>d->last_cseq) d->last_cseq = cseq;
		if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE)
		{
			d->uac_supp_timer = supports_extension(msg, &str_ext_timer);
	
			ses_exp = cscf_get_session_expires_body(msg, &h);
			t_time = cscf_get_session_expires(ses_exp, &refresher);
			if (!t_time){
				d->expires = d_act_time()+pcscf_dialogs_expiration_time;
				d->lr_session_expires = 0;
			} else {
				d->expires = d_act_time() + t_time;
				d->lr_session_expires = t_time;
				if (refresher.len)
					STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
			}
		}
		else if (d->method == DLG_METHOD_SUBSCRIBE && 
			msg->first_line.u.request.method.len == 6 && 
			strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0)
		{
			// Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2
			expires = cscf_get_subscription_state(msg);
			if (expires >= 0)
			{
				d->expires = d_act_time()+expires;
			}
			else
			{
				d->expires = d_act_time()+pcscf_dialogs_expiration_time;
			}
		}
		else
		{
			expires = cscf_get_expires_hdr(msg);
			if (expires >= 0) 
			{
				LOG(L_INFO,"DBG:"M_NAME":P_update_dialog(%.*s): Update expiration time to %d via Expire header 2\n",call_id.len,call_id.s,expires);
				d->expires = d_act_time()+expires;
			}
			else
			{
				LOG(L_INFO,"INF:"M_NAME": update_dialog(%.*s): d->expires+=pcscf_dialogs_expiration_time 4\n",call_id.len,call_id.s);
				d->expires = d_act_time()+pcscf_dialogs_expiration_time;
			}
			d->lr_session_expires = 0;		
		}
	}else{
		/* Reply */
		response = msg->first_line.u.reply.statuscode;
		LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): <%d> \n",str1,response);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq==0 || h==0) return CSCF_RETURN_FALSE;
		if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len &&
			strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 &&
			d->state < DLG_STATE_CONFIRMED){
			/* reply to initial request */
			if (response<200 && response>100){
				save_dialog_routes(msg,str1,d);
				d->state = DLG_STATE_EARLY;
				d->expires = d_act_time()+300;
				cscf_get_to_tag(msg,&totag);
				tmb.update_dlg_uas(d->dialog_s,response,&totag);
				tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);
			}else
			if (response>=200 && response<300){
				save_dialog_routes(msg,str1,d);
				d->state = DLG_STATE_CONFIRMED;
				
				update_dialog_on_reply(msg, d);
				
				cscf_get_to_tag(msg,&totag);
				tmb.update_dlg_uas(d->dialog_s,response,&totag);
				tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);
				
			}else
				if (response>300){
					d->state = DLG_STATE_TERMINATED;
					d_unlock(d->hash);				
					return P_drop_dialog(msg,str1,str2);
				}				
		}else{
			/* reply to subsequent request */			
			if (!req) req = cscf_get_request_from_reply(msg);
			
			/* destroy dialogs on specific methods */
			switch (d->method){
				case DLG_METHOD_OTHER:							
					expires = cscf_get_expires_hdr(msg);
					if (expires >= 0)
					{
						d->expires = d_act_time()+expires;
					}
					else
					{
						d->expires = d_act_time()+pcscf_dialogs_expiration_time;
					}
					d->lr_session_expires = 0;
					break;
				case DLG_METHOD_INVITE:
					if (req && req->first_line.u.request.method.len==3 &&
						strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){
						d->state = DLG_STATE_TERMINATED;
						d_unlock(d->hash);				
						return P_drop_dialog(msg,str1,str2);
					}
					update_dialog_on_reply(msg, d);
					break;
				case DLG_METHOD_SUBSCRIBE:
//					if (req && req->first_line.u.request.method.len==9 &&
//						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 &&
//						cscf_get_expires_hdr(msg)==0){						
//						d->state = DLG_STATE_TERMINATED;
//						d_unlock(d->hash);				
//						return P_drop_dialog(msg,str1,str2);
//					}
					if (req && req->first_line.u.request.method.len==6 &&
						strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){
						expires = cscf_get_subscription_state(req);
						if (expires==0){						
							d->state = DLG_STATE_TERMINATED;
							d_unlock(d->hash);				
							return P_drop_dialog(msg,str1,str2);
						}else if (expires>0){
							d->expires = d_act_time() + expires;
						}
					}
					break;
			}
			if (cseq>d->last_cseq) d->last_cseq = cseq;
		}
	}
	
	d_unlock(d->hash);
	
	print_p_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
out_of_memory:
	d_unlock(d->hash);
	return CSCF_RETURN_ERROR;	
}
示例#14
0
文件: dlg_state.c 项目: asyn/openvims
/**
 * Checks if the message follows the saved dialog routes.
 * @param msg - the SIP request
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_follows_dialog_routes(struct sip_msg *msg,char *str1,char *str2)
{
	int i;
	struct hdr_field *hdr=0;
	rr_t *r;
	p_dialog *d;
	str call_id,host;
	int port,transport;
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
	
	if (!find_dialog_contact(msg,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_follows_dialog_routes(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes(%s): Call-ID <%.*s> %d://%.*s:%d\n",
		str1,call_id.len,call_id.s,
		transport,host.len,host.s,port);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		LOG(L_ERR,"ERR:"M_NAME":P_follows_dialog_routes: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}
	/* todo - fix this to match exactly the first request */
	if (d->first_cseq == cscf_get_cseq(msg,0) &&
		d->method == get_dialog_method(msg->first_line.u.request.method)){
		LOG(L_INFO,"INF:"M_NAME":P_follows_dialog_routes: this looks like the initial request (retransmission?)!\n");
		goto ok;		
	}

	hdr = cscf_get_next_route(msg,0);
	r = 0;
	if (!hdr){
		if (d->routes_cnt==0) goto ok;
		else goto nok;
	}
	r = (rr_t*) hdr->parsed;	
	for(i=0;i<d->routes_cnt;i++){
		LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes:  must <%.*s>\n",
			d->routes[i].len,d->routes[i].s);		
		if (!r) {
			hdr = cscf_get_next_route(msg,hdr);
			if (!hdr) goto nok;
			r = (rr_t*) hdr->parsed;	
		}
		LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: src %.*s\n",
			r->nameaddr.uri.len,r->nameaddr.uri.s);		
		if (r->nameaddr.uri.len==d->routes[i].len &&
				strncasecmp(r->nameaddr.uri.s,
					d->routes[i].s,d->routes[i].len)==0)
		{
			LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: src match\n");		
		} else {
			LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: found <%.*s>\n",
				r->nameaddr.uri.len,r->nameaddr.uri.s);					
			goto nok;
		}
		r = r->next;
	}
	if (r) {
		LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: still has some extra Routes\n");		
		goto nok;
	}
	else 
		if (cscf_get_next_route(msg,hdr)) goto nok;
	
ok:
	if (d) d_unlock(d->hash);
	return CSCF_RETURN_TRUE;	
nok:
	if (d) d_unlock(d->hash);
	return CSCF_RETURN_FALSE;		
}
示例#15
0
/**
 * Updates a dialog.
 * If the initial request was:
 * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog 
 * if found
 * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration 
 * and if terminated destroys the dialog
 * - When adding more dialogs, add the refreshal methods here or they will expire and will
 * be destroyed. Also add the termination to reduce the memory consumption and improve the
 * performance.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_update_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	int response;
	int cseq;

	struct hdr_field *h=0;
	struct sip_msg *req=0;
	int expires=0;
	str totag;
	time_t t_time;
	str ses_exp = {0,0};
	str refresher = {0,0};

	enum s_dialog_direction dir = get_dialog_direction(str1);
		
//	if (!find_dialog_aor(msg,str1,&aor)){
//		req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}
//	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	d = get_s_dialog_dir(call_id,dir);
//	if (!d && msg->first_line.type==SIP_REPLY){
//		/* Try to get the dialog from the request */
//		if (!req) req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}		
//		d = get_s_dialog_dir(call_id,aor);		
//	}
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}


	if (msg->first_line.type==SIP_REQUEST){
		/* Request */
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1,
			msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq>d->last_cseq) d->last_cseq = cseq;
		if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE)
		{
			d->uac_supp_timer = supports_extension(msg, &str_ext_timer);
	
			ses_exp = cscf_get_session_expires_body(msg, &h);
			t_time = cscf_get_session_expires(ses_exp, &refresher);
			if (!t_time)
			{
				d->expires = d_act_time()+scscf_dialogs_expiration_time;
				d->lr_session_expires = 0;
			}
			else
			{
				d->expires = d_act_time() + t_time;
				d->lr_session_expires = t_time;
				if (refresher.len)
					STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
			}
		}
		else if (d->method == DLG_METHOD_SUBSCRIBE &&
			msg->first_line.u.request.method.len == 6 &&
			strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0)
		{
			// Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2
			expires = cscf_get_subscription_state(msg);
			if (expires >= 0)
				d->expires = d_act_time()+expires;
			else
				d->expires = d_act_time()+scscf_dialogs_expiration_time;
		}
		else
		{
			expires = cscf_get_expires_hdr(msg,0);
			if (expires >= 0)
			        d->expires = d_act_time()+expires;
			else
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
	
			d->lr_session_expires = 0;		
		}
	}else{
		/* Reply */
		response = msg->first_line.u.reply.statuscode;
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq==0 || h==0) return CSCF_RETURN_FALSE;
		if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len &&
			strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 &&
			d->state < DLG_STATE_CONFIRMED){
			/* reply to initial request */
			if (response<200){
				d->state = DLG_STATE_EARLY;
				d->expires = d_act_time()+300;
			}else
			if (response>=200 && response<300){
				d->state = DLG_STATE_CONFIRMED;
				update_dialog_on_reply(msg, d);
				
				/*I save the dialogs only here because
				 * i only want to release confirmed dialogs*/
				cscf_get_to_tag(msg,&totag);
				if (d->dialog_s){
					tmb.update_dlg_uas(d->dialog_s,response,&totag);
					tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);
				}else{
					LOG(L_ERR,"ERR:S_update_dialog(): dialog_s for dialog was NULL!\n");
				}
			}else
				if (response>300){
					d->state = DLG_STATE_TERMINATED;
					d_unlock(d->hash);				
					struct cell * t = tmb.t_gett();
					if(t->nr_of_outgoings < 2)
						return S_drop_dialog(msg,str1,str2);
				}				
		}else{
			/* reply to subsequent request */			
			if (!req) req = cscf_get_request_from_reply(msg);
			
			/* destroy dialogs on specific methods */
			switch (d->method){
				case DLG_METHOD_OTHER:							
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
					d->lr_session_expires = 0;
					break;
				
				case DLG_METHOD_INVITE:
					if (req && req->first_line.u.request.method.len==3 &&
						strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){
						d->state = DLG_STATE_TERMINATED;
						d_unlock(d->hash);				
						return S_drop_dialog(msg,str1,str2);
					}
					update_dialog_on_reply(msg, d);
					break;
				case DLG_METHOD_SUBSCRIBE:
//					if (req && req->first_line.u.request.method.len==9 &&
//						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 &&
//						cscf_get_expires_hdr(msg)==0){						
//						d->state = DLG_STATE_TERMINATED;
//						d_unlock(d->hash);				
//						return P_dros_dialog(msg,str1,str2);
//					}
					if (req && req->first_line.u.request.method.len==6 &&
						strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){
						expires = cscf_get_subscription_state(req);
						if (expires==0){						
							d->state = DLG_STATE_TERMINATED;
							d_unlock(d->hash);				
							return S_drop_dialog(msg,str1,str2);
						}else if (expires>0){
							d->expires = d_act_time() + expires;
						}
					}
					else if (req && req->first_line.u.request.method.len==9 &&
						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0){
						expires = cscf_get_expires_hdr(msg,0);
						if (expires >= 0)
							d->expires = d_act_time()+expires;
						else
							d->expires = d_act_time()+scscf_dialogs_expiration_time;
					}					
					break;
			}
			if (cseq>d->last_cseq) d->last_cseq = cseq;						
		}
	}
	
	d_unlock(d->hash);
	
	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
out_of_memory:
	if (d) d_unlock(d->hash);
	return CSCF_RETURN_ERROR;	
}
示例#16
0
文件: dlg_state.c 项目: asyn/openvims
/**
 * Inserts the Route header containing the dialog routes to be enforced
 * @param msg - the SIP message to add to
 * @param str1 - the value to insert - !!! quoted if needed
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_enforce_dialog_routes(struct sip_msg *msg,char *str1,char*str2)
{
	int i;
	str newuri={0,0};
	p_dialog *d;
	str call_id,host;
	int port,transport;
	str x;
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
		
	if (!find_dialog_contact(msg,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_enforce_dialog_routes(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_INFO,"DBG:"M_NAME":P_enforce_dialog_routes(%s): Call-ID <%.*s> %d://%.*s:%d\n",
		str1,call_id.len,call_id.s,
		transport,host.len,host.s,port);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		LOG(L_ERR,"ERR:"M_NAME":P_enforce_dialog_routes: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	if (!d->routes_cnt){
		d_unlock(d->hash);
		return CSCF_RETURN_TRUE;
	}

	x.len = route_s.len + route_e.len + (d->routes_cnt-1)*route_1.len;
	for(i=0;i<d->routes_cnt;i++)
		x.len+=d->routes[i].len;
			
	x.s = pkg_malloc(x.len);
	if (!x.s){
		LOG(L_ERR, "ERR:"M_NAME":P_enforce_dialog_routes: Error allocating %d bytes\n",
			x.len);
		x.len=0;
		d_unlock(d->hash);
		return CSCF_RETURN_ERROR;
	}
	x.len=0;
	STR_APPEND(x,route_s);
	for(i=0;i<d->routes_cnt;i++){
		if (i) STR_APPEND(x,route_1);
		STR_APPEND(x,d->routes[i]);
	}	
	STR_APPEND(x,route_e);
	
	newuri.s = pkg_malloc(d->routes[0].len);
	if (!newuri.s){
		LOG(L_ERR, "ERR:"M_NAME":P_enforce_dialog_routes: Error allocating %d bytes\n",
			d->routes[0].len);
		d_unlock(d->hash);
		return CSCF_RETURN_ERROR;
	}
	newuri.len = d->routes[0].len;
	memcpy(newuri.s,d->routes[0].s,newuri.len);
	if (msg->dst_uri.s) pkg_free(msg->dst_uri.s);
	msg->dst_uri = newuri;
	
	//LOG(L_ERR,"%.*s",x.len,x.s);
	d_unlock(d->hash);
	if (cscf_add_header_first(msg,&x,HDR_ROUTE_T)) {
		if (cscf_del_all_headers(msg,HDR_ROUTE_T))
			return CSCF_RETURN_TRUE;
		else {
			LOG(L_ERR,"ERR:"M_NAME":P_enforce_dialog_routes: new Route headers added, but failed to drop old ones.\n");
			return CSCF_RETURN_ERROR;
		}
	}
	else {
		if (x.s) pkg_free(x.s);
		return CSCF_RETURN_ERROR;
	}
}
示例#17
0
/**
 * Saves a dialog.
 * @param msg - the initial request
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_save_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	str aor;
	char buf1[256],buf2[256];
	str uri,tag,ruri,x;	
	time_t t_time;
	str ses_exp = {0,0};
	str refresher = {0,0};
	str event = {0,0};
	struct hdr_field *h;
	unsigned int hash;
	
	enum s_dialog_direction dir = get_dialog_direction(str1);
	
	if (!find_dialog_aor(msg,dir,&aor)){
		LOG(L_ERR,"ERR:"M_NAME":S_save_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_INFO,"DBG:"M_NAME":S_save_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	if (is_s_dialog(call_id,aor,dir)){
		LOG(L_ERR,"ERR:"M_NAME":S_save_dialog: dialog already exists!\n");	
		return CSCF_RETURN_TRUE;
	}
	
	d = add_s_dialog(call_id,aor,dir);
	if (!d) return CSCF_RETURN_FALSE;

	d->method = get_dialog_method(msg->first_line.u.request.method);
	STR_SHM_DUP(d->method_str,msg->first_line.u.request.method,"shm");
	d->first_cseq = cscf_get_cseq(msg,0);
	d->last_cseq = d->first_cseq;
	d->state = DLG_STATE_INITIAL;

	d->uac_supp_timer = supports_extension(msg, &str_ext_timer);

	ses_exp = cscf_get_session_expires_body(msg, &h);
	t_time = cscf_get_session_expires(ses_exp, &refresher);
	if (!t_time) {
		d->expires = d_act_time() + 60;
		d->lr_session_expires = 0;
	} else {
		d->expires = d_act_time() + t_time;
		d->lr_session_expires = t_time;
		if (refresher.len)
			STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
	}
	
	cscf_get_from_tag(msg,&tag);
	cscf_get_from_uri(msg,&x);
	uri.len = snprintf(buf1,256,"<%.*s>",x.len,x.s);
	uri.s = buf1;	
	cscf_get_to_uri(msg,&x);
	ruri.len = snprintf(buf2,256,"<%.*s>",x.len,x.s);
	ruri.s = buf2;
	 
	tmb.new_dlg_uac(&call_id,
						&tag,
						d->first_cseq,&uri,
						&ruri,
						&d->dialog_c);
	
	tmb.new_dlg_uas(msg,99,&d->dialog_s);
	
	event = cscf_get_event(msg);
	if (event.len){
		STR_SHM_DUP(d->event,event,"shm");
	}
	else
		d->event = event;

	d_unlock(d->hash);
	
	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
out_of_memory:
	if (d){
		hash = d->hash;
		del_s_dialog(d);
		d_unlock(hash);
	}
	return CSCF_RETURN_ERROR;	
}
示例#18
0
文件: mod.c 项目: gbour/kamailio
/**
 * Checks if there is a match.
 * Inserts route headers and set the dst_uri
 * @param msg - the message to check
 * @param str1 - the direction of the request orig/term
 * @param str2 - not used
 * @returns #ISC_RETURN_TRUE if found, #ISC_RETURN_FALSE if not, #ISC_RETURN_BREAK on error
 */
int isc_match_filter(struct sip_msg *msg, char *str1, udomain_t* d) {
    int k = 0;
    isc_match *m = NULL;
    str s = {0, 0};

    //sometimes s is populated by an ims_getter method cscf_get_terminating_user that alloc memory that must be free-ed at the end
    int free_s = 0;


    int ret = ISC_RETURN_FALSE;
    isc_mark new_mark, old_mark;

    enum dialog_direction dir = get_dialog_direction(str1);

    LM_INFO("Checking triggers\n");

    if (dir == DLG_MOBILE_UNKNOWN)
        return ISC_RETURN_BREAK;

    if (!cscf_is_initial_request(msg))
        return ISC_RETURN_FALSE;

    /* starting or resuming? */
    memset(&old_mark, 0, sizeof (isc_mark));
    memset(&new_mark, 0, sizeof (isc_mark));
    if (isc_mark_get_from_msg(msg, &old_mark)) {
        LM_DBG("Message returned s=%d;h=%d;d=%d;a=%.*s\n", old_mark.skip, old_mark.handling, old_mark.direction, old_mark.aor.len, old_mark.aor.s);
    } else {
        LM_DBG("Starting triggering\n");
    }

    if (is_route_type(FAILURE_ROUTE)) {
        /* need to find the handling for the failed trigger */
        if (dir == DLG_MOBILE_ORIGINATING) {
            k = cscf_get_originating_user(msg, &s);
            if (k) {
                k = isc_is_registered(&s, d);
                if (k == IMPU_NOT_REGISTERED) {
                    ret = ISC_RETURN_FALSE;
                    goto done;
                }
                new_mark.direction = IFC_ORIGINATING_SESSION;
                LM_DBG("Orig User <%.*s> [%d]\n", s.len, s.s, k);
            } else
                goto done;
        }
        if (dir == DLG_MOBILE_TERMINATING) {
            k = cscf_get_terminating_user(msg, &s);
            //sometimes s is populated by an ims_getter method cscf_get_terminating_user that alloc memory that must be free-ed at the end
            free_s = 1;

            if (k) {
                k = isc_is_registered(&s, d);
                //LOG(L_DBG,"after isc_is_registered in ISC_match_filter\n");
                if (k == IMPU_REGISTERED) {
                    new_mark.direction = IFC_TERMINATING_SESSION;
                } else {
                    new_mark.direction = IFC_TERMINATING_UNREGISTERED;
                }
                LM_DBG("Term User <%.*s> [%d]\n", s.len, s.s, k);
            } else {
                goto done;
            }
        }
        struct cell * t = isc_tmb.t_gett();
        LM_CRIT("SKIP: %d\n", old_mark.skip);
        int index = old_mark.skip;
        for (k = 0; k < t->nr_of_outgoings; k++) {
            m = isc_checker_find(s, new_mark.direction, index, msg,
                    isc_is_registered(&s, d), d);
            if (m) {
                index = m->index;
                if (k < t->nr_of_outgoings - 1)
                    isc_free_match(m);
            } else {
                LM_ERR("On failure, previously matched trigger no longer matches?!\n");
                ret = ISC_RETURN_BREAK;
                goto done;
            }
        }
        if (m->default_handling == IFC_SESSION_TERMINATED) {
            /* Terminate the session */
            LM_DBG("Terminating session.\n");
            isc_tmb.t_reply(msg, IFC_AS_UNAVAILABLE_STATUS_CODE, "AS Contacting Failed - iFC terminated dialog");
            LM_DBG("Responding with %d to URI: %.*s\n",
                    IFC_AS_UNAVAILABLE_STATUS_CODE, msg->first_line.u.request.uri.len, msg->first_line.u.request.uri.s);
            isc_free_match(m);
            ret = ISC_RETURN_BREAK;
            goto done;
        }
        /* skip the failed triggers (IFC_SESSION_CONTINUED) */
        old_mark.skip = index + 1;

        isc_free_match(m);
        isc_mark_drop_route(msg);
    }

    LM_DBG("Checking if ISC is for originating user\n");
    /* originating leg */
    if (dir == DLG_MOBILE_ORIGINATING) {
        k = cscf_get_originating_user(msg, &s);
        LM_DBG("ISC is for Orig user\n");
        if (k) {
            LM_DBG("Orig user is [%.*s]\n", s.len, s.s);
            k = isc_is_registered(&s, d);
            if (k == IMPU_NOT_REGISTERED) {
                LM_DBG("User is not registered\n");
                return ISC_RETURN_FALSE;
            }

            LM_DBG("Orig User <%.*s> [%d]\n", s.len, s.s, k);
            //CHECK if this is a new call (According to spec if the new uri and old mark URI are different then this is a new call and should
            //be triggered accordingly
            LM_DBG("Checking if RURI has changed...comparing: <%.*s> and <%.*s>\n",
                    old_mark.aor.len, old_mark.aor.s,
                    s.len, s.s);
            if ((old_mark.aor.len == s.len) && memcmp(old_mark.aor.s, s.s, s.len) != 0) {
                LM_DBG("This is a new call....... trigger accordingly\n");
                m = isc_checker_find(s, old_mark.direction, 0, msg,
                        isc_is_registered(&s, d), d);
            } else {
                m = isc_checker_find(s, old_mark.direction, old_mark.skip, msg,
                        isc_is_registered(&s, d), d);
            }
            if (m) {
                new_mark.direction = IFC_ORIGINATING_SESSION;
                new_mark.skip = m->index + 1;
                new_mark.handling = m->default_handling;
                new_mark.aor = s;
                ret = isc_forward(msg, m, &new_mark);
                isc_free_match(m);
                goto done;
            }
        }
        goto done;
    }
    LM_DBG("Checking if ISC is for terminating user\n");
    /* terminating leg */
    if (dir == DLG_MOBILE_TERMINATING) {
        k = cscf_get_terminating_user(msg, &s);
        //sometimes s is populated by an ims_getter method cscf_get_terminating_user that alloc memory that must be free-ed at the end
        free_s = 1;
        LM_DBG("ISC is for Term user\n");
        if (k) {
            k = isc_is_registered(&s, d);
            if (k == IMPU_REGISTERED) {
                new_mark.direction = IFC_TERMINATING_SESSION;
            } else {
                new_mark.direction = IFC_TERMINATING_UNREGISTERED;
            }
            LM_DBG("Term User <%.*s> [%d]\n", s.len, s.s, k);
            //CHECK if this is a new call (According to spec if the new uri and old mark URI are different then this is a new call and should
            //be triggered accordingly
            LM_DBG("Checking if RURI has changed...comparing: <%.*s> and <%.*s>\n",
                    old_mark.aor.len, old_mark.aor.s,
                    s.len, s.s);
            if ((old_mark.aor.len == s.len) && memcmp(old_mark.aor.s, s.s, s.len) != 0) {
                LM_DBG("This is a new call....... trigger accordingly\n");
                m = isc_checker_find(s, new_mark.direction, 0, msg, isc_is_registered(&s, d), d);
            } else {
                LM_DBG("Resuming triggering\n");
                m = isc_checker_find(s, new_mark.direction, old_mark.skip, msg, isc_is_registered(&s, d), d);
            }
            if (m) {
                new_mark.skip = m->index + 1;
                new_mark.handling = m->default_handling;
                new_mark.aor = s;
                ret = isc_forward(msg, m, &new_mark);
                isc_free_match(m);
                goto done;
            }
        }
        goto done;
    }

done:

    if (s.s && free_s == 1)
        shm_free(s.s); // shm_malloc in cscf_get_terminating_user  

    if (old_mark.aor.s)
        pkg_free(old_mark.aor.s);
    return ret;
}
示例#19
0
文件: mod.c 项目: asyn/openvims
/**
 * Checks if there is a match.
 * Inserts route headers and set the dst_uri
 * @param msg - the message to check
 * @param str1 - the direction of the request orig/term
 * @param str2 - not used
 * @returns #ISC_RETURN_TRUE if found, #ISC_RETURN_FALSE if not, #ISC_RETURN_BREAK on error
 */
int ISC_match_filter(struct sip_msg *msg,char *str1,char *str2)
{
	int k;
	isc_match *m;
	str s={0,0};
	int ret = ISC_RETURN_FALSE;
	isc_mark new_mark,old_mark;
	
	enum dialog_direction dir = get_dialog_direction(str1);
	
	LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Checking triggers\n",str1);
	
	if (dir==DLG_MOBILE_UNKNOWN) 
		return ISC_RETURN_BREAK;
	
	if (!isc_is_initial_request(msg)) return ISC_RETURN_FALSE;
		
	/* starting or resuming? */
	memset(&old_mark,0,sizeof(isc_mark));
	if (isc_mark_get_from_msg(msg,&old_mark)){		
		LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Message returned s=%d;h=%d;d=%d\n",
			str1,old_mark.skip,old_mark.handling,old_mark.direction);
	}
	else {
		LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Starting triggering\n",str1);				
	}

	/* originating leg */
	if (dir==DLG_MOBILE_ORIGINATING){
		k = isc_get_originating_user(msg,&s);
		if (k){
			k = isc_is_registered(&s);
			if (k==NOT_REGISTERED) return ISC_MSG_NOT_FORWARDED;
			
			LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Orig User <%.*s> [%d]\n",str1,
				s.len,s.s,k);
			m = isc_checker_find(s,old_mark.direction,old_mark.skip,msg);
			if (m){
				new_mark.direction = IFC_ORIGINATING_SESSION;
				new_mark.skip = m->index+1;
				new_mark.handling = m->default_handling;
				ret = isc_forward(msg,m,&new_mark);
				isc_free_match(m);
				return ret;
			}
		}
		return ret;
	}

	/* terminating leg */
	if (dir==DLG_MOBILE_TERMINATING){
		k = isc_get_terminating_user(msg,&s);
		if (k){
			k = isc_is_registered(&s);
			if (k==REGISTERED) {
				new_mark.direction = IFC_TERMINATING_SESSION;
			} else {
				new_mark.direction = IFC_TERMINATING_UNREGISTERED;
			}
			LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Orig User <%.*s> [%d]\n",str1,
				s.len,s.s,k);
			m = isc_checker_find(s,new_mark.direction,old_mark.skip,msg);
			if (m){
				new_mark.skip = m->index+1;
				new_mark.handling = m->default_handling;
				ret = isc_forward(msg,m,&new_mark);
				isc_free_match(m);
				if (s.s) pkg_free(s.s);	
				return ret;
			}
		}
		if (s.s) pkg_free(s.s);	
		return ret;
	}					
		
	return ret;
}
示例#20
0
/**
 * Checks if there is a match.
 * Inserts route headers and set the dst_uri
 * @param msg - the message to check
 * @param str1 - the direction of the request orig/term
 * @param str2 - not used
 * @returns #ISC_RETURN_TRUE if found, #ISC_RETURN_FALSE if not, #ISC_RETURN_BREAK on error
 */
int ISC_match_filter(struct sip_msg *msg,char *str1,char *str2)
{
	int k = 0;
	isc_match *m = NULL;
	str s={0,0};
	int ret = ISC_RETURN_FALSE;
	isc_mark new_mark,old_mark;
	
	enum dialog_direction dir = get_dialog_direction(str1);
	
	LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Checking triggers\n",str1);
	
	if (dir==DLG_MOBILE_UNKNOWN) 
		return ISC_RETURN_BREAK;
	
	if (!isc_is_initial_request(msg)) return ISC_RETURN_FALSE;
		
	/* starting or resuming? */
	memset(&old_mark,0,sizeof(isc_mark));
	memset(&new_mark,0,sizeof(isc_mark));
	if (isc_mark_get_from_msg(msg,&old_mark)){		
		LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Message returned s=%d;h=%d;d=%d;a=%.*s\n",
			str1,old_mark.skip,old_mark.handling,old_mark.direction,old_mark.aor.len,old_mark.aor.s);
	}
	else {
		LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Starting triggering\n",str1);				
	}
	
	if (
#ifdef SER_MOD_INTERFACE
	is_route_type(FAILURE_ROUTE)
#else
	*isc_tmb.route_mode==MODE_ONFAILURE
#endif
		){
		LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): failure\n",str1);
		
		/* need to find the handling for the failed trigger */
		if (dir==DLG_MOBILE_ORIGINATING){
			k = isc_get_originating_user(msg,&old_mark,&s);
			if (k){
				k = isc_is_registered(&s);
				if (k==NOT_REGISTERED) {
					ret = ISC_MSG_NOT_FORWARDED;
					goto done;
				}
				new_mark.direction = IFC_ORIGINATING_SESSION;
				LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Orig User <%.*s> [%d]\n",str1,
					s.len,s.s,k);
			} else goto done;
		}
		if (dir==DLG_MOBILE_TERMINATING){
			k = isc_get_terminating_user(msg,&old_mark,&s);
			if (k){
				k = isc_is_registered(&s);
				//LOG(L_DBG,"after isc_is_registered in ISC_match_filter\n");
				if (k==REGISTERED) {
					new_mark.direction = IFC_TERMINATING_SESSION;
				} else {
					new_mark.direction = IFC_TERMINATING_UNREGISTERED;
				}
				LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Term User <%.*s> [%d]\n",str1,
					s.len,s.s,k);
			} else {
				goto done;
			}
		}
		struct cell * t = isc_tmb.t_gett();
		LOG(L_CRIT,"SKIP: %d\n",old_mark.skip);
		int index = old_mark.skip;
		for (k=0;k<t->nr_of_outgoings;k++) {
			m = isc_checker_find(s,new_mark.direction,index,msg,isc_is_registered(&s));
			if (m) {
				index = m->index;
				if (k < t->nr_of_outgoings - 1) isc_free_match(m);
			} else {
				LOG(L_ERR,"ERR:"M_NAME":ISC_match_filter(%s): On failure, previously matched trigger no longer matches?!\n", str1);
				ret = ISC_RETURN_BREAK;
				goto done;
			}
		}
		if (m->default_handling==IFC_SESSION_TERMINATED) {
			/* Terminate the session */
			DBG("DEBUG:"M_NAME":ISC_match_filter(%s): Terminating session.\n", str1);
			isc_tmb.t_reply(msg,IFC_AS_UNAVAILABLE_STATUS_CODE,
				"AS Contacting Failed - iFC terminated dialog");
			LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Responding with %d "
				"to URI: %.*s\n",str1, IFC_AS_UNAVAILABLE_STATUS_CODE,
				msg->first_line.u.request.uri.len,
				msg->first_line.u.request.uri.s);
			isc_free_match(m);
			ret = ISC_RETURN_BREAK;
			goto done;
		}
		
		/* skip the failed triggers (IFC_SESSION_CONTINUED) */
		old_mark.skip = index + 1;
		
		isc_free_match(m);
		isc_mark_drop_route(msg);
	}

	/* originating leg */
	if (dir==DLG_MOBILE_ORIGINATING){
		k = isc_get_originating_user(msg,&old_mark,&s);
		if (k){
			k = isc_is_registered(&s);
			if (k==NOT_REGISTERED) return ISC_MSG_NOT_FORWARDED;
			
			LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Orig User <%.*s> [%d]\n",str1,
				s.len,s.s,k);
			m = isc_checker_find(s,old_mark.direction,old_mark.skip,msg,isc_is_registered(&s));
			if (m){
				new_mark.direction = IFC_ORIGINATING_SESSION;
				new_mark.skip = m->index+1;
				new_mark.handling = m->default_handling;
				new_mark.aor = s;
				ret = isc_forward(msg,m,&new_mark);
				isc_free_match(m);
				goto done;
			}
		}
		goto done;
	}

	/* terminating leg */
	if (dir==DLG_MOBILE_TERMINATING){
		k = isc_get_terminating_user(msg,&old_mark,&s);
		if (k){
			k = isc_is_registered(&s);
			if (k==REGISTERED) {
				new_mark.direction = IFC_TERMINATING_SESSION;
			} else {
				new_mark.direction = IFC_TERMINATING_UNREGISTERED;
			}
			LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Term User <%.*s> [%d]\n",str1,
				s.len,s.s,k);
			
			m = isc_checker_find(s,new_mark.direction,old_mark.skip,msg,isc_is_registered(&s));
			if (m){
				new_mark.skip = m->index+1;
				new_mark.handling = m->default_handling;
				new_mark.aor = s;
				ret = isc_forward(msg,m,&new_mark);
				isc_free_match(m);
				goto done;
			}
		}
		goto done;
	}				
	
done:
	if (old_mark.aor.s) pkg_free(old_mark.aor.s);		
	return ret;
}
示例#21
0
文件: dlg_state.c 项目: asyn/openvims
/**
 * Updates a dialog.
 * If the initial request was:
 * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog 
 * if found
 * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration 
 * and if terminated destroys the dialog
 * - When adding more dialogs, add the refreshal methods here or they will expire and will
 * be destroyed. Also add the termination to reduce the memory consumption and improve the
 * performance.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_update_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	int response;
	int cseq;
	struct hdr_field *h=0;
	struct sip_msg *req=0;
	int expires=0;
	str totag;

	enum s_dialog_direction dir = get_dialog_direction(str1);
		
//	if (!find_dialog_aor(msg,str1,&aor)){
//		req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}
//	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_INFO,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	d = get_s_dialog_dir(call_id,dir);
//	if (!d && msg->first_line.type==SIP_REPLY){
//		/* Try to get the dialog from the request */
//		if (!req) req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}		
//		d = get_s_dialog_dir(call_id,aor);		
//	}
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}


	if (msg->first_line.type==SIP_REQUEST){
		/* Request */
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1,
			msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq>d->last_cseq) d->last_cseq = cseq;
		d->expires = d_act_time()+scscf_dialogs_expiration_time;
	}else{
		/* Reply */
		response = msg->first_line.u.reply.statuscode;
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq==0 || h==0) return CSCF_RETURN_FALSE;
		if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len &&
			strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 &&
			d->state < DLG_STATE_CONFIRMED){
			/* reply to initial request */
			if (response<200){
				d->state = DLG_STATE_EARLY;
				d->expires = d_act_time()+300;
			}else
			if (response>=200 && response<300){
				d->state = DLG_STATE_CONFIRMED;
				d->expires = d_act_time()+scscf_dialogs_expiration_time;
				/*I save the dialogs only here because
				 * i only want to release confirmed dialogs*/
				cscf_get_to_tag(msg,&totag);
				tmb.update_dlg_uas(d->dialog_s,response,&totag);
				tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);				
			}else
				if (response>300){
					d->state = DLG_STATE_TERMINATED;
					d_unlock(d->hash);				
					return S_drop_dialog(msg,str1,str2);
				}				
		}else{
			/* reply to subsequent request */			
			if (!req) req = cscf_get_request_from_reply(msg);
			
			/* destroy dialogs on specific methods */
			switch (d->method){
				case DLG_METHOD_OTHER:							
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
					break;
				case DLG_METHOD_INVITE:
					if (req && req->first_line.u.request.method.len==3 &&
						strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){
						d->state = DLG_STATE_TERMINATED;
						d_unlock(d->hash);				
						return S_drop_dialog(msg,str1,str2);
					}
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
					break;
				case DLG_METHOD_SUBSCRIBE:
//					if (req && req->first_line.u.request.method.len==9 &&
//						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 &&
//						cscf_get_expires_hdr(msg)==0){						
//						d->state = DLG_STATE_TERMINATED;
//						d_unlock(d->hash);				
//						return P_dros_dialog(msg,str1,str2);
//					}
					if (req && req->first_line.u.request.method.len==6 &&
						strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){
						expires = cscf_get_subscription_state(req);
						if (expires==0){						
							d->state = DLG_STATE_TERMINATED;
							d_unlock(d->hash);				
							return S_drop_dialog(msg,str1,str2);
						}else if (expires>0){
							d->expires = expires;
						}
					}
					break;
			}
			if (cseq>d->last_cseq) d->last_cseq = cseq;						
		}
	}
	
	d_unlock(d->hash);
	
//	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
示例#22
0
int rx_send_aar(struct sip_msg *req, struct sip_msg *res,
        AAASession* auth, char* direction, saved_transaction_t* saved_t_data) {

    AAAMessage* aar = 0;
    
    str identifier;
    int identifier_type;


    AAA_AVP* avp = 0;
    char x[4];
    int ret = 0;

    str ip;
    uint16_t ip_version;

    //we get ip and identifier for the auth session data 
    rx_authsessiondata_t* p_session_data = 0;
    p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
    identifier = p_session_data->identifier;
    identifier_type = p_session_data->identifier_type;
    ip = p_session_data->ip;
    ip_version = p_session_data->ip_version;
    
    /* find direction for AAR (orig/term) */
    //need this to add the media component details
    enum dialog_direction dlg_direction = get_dialog_direction(direction);
    if (dlg_direction == DLG_MOBILE_UNKNOWN) {
        LM_DBG("Asked to send AAR for unknown direction.....Aborting...\n");
        goto error;
    }

    aar = cdpb.AAACreateRequest(IMS_Rx, IMS_AAR, Flag_Proxyable, auth);

    LM_DBG("Created aar request...\n");

    if (!aar)
        goto error;

    /*Adding AVPs*/

    LM_DBG("Adding auth app id AVP...\n");
    /* Add Auth-Application-Id AVP */
    if (!rx_add_auth_application_id_avp(aar, IMS_Rx))
        goto error;
    if (!rx_add_vendor_specific_application_id_group(aar, IMS_vendor_id_3GPP,
            IMS_Rx))
        goto error;

    LM_DBG("Adding dest realm if not there already...\n");
    /* Add Destination-Realm AVP, if not already there */
    avp = cdpb.AAAFindMatchingAVP(aar, aar->avpList.head, AVP_Destination_Realm,
            0, AAA_FORWARD_SEARCH);
    if (!avp) {
        str realm = rx_dest_realm;
        if (realm.len && !rx_add_destination_realm_avp(aar, realm))
            goto error;
    }

    LM_DBG("Adding AF App identifier...\n");
    /* Add AF-Application-Identifier AVP */
    str af_id = {0, 0};
    af_id = IMS_Serv_AVP_val;
    if (!rx_add_avp(aar, af_id.s, af_id.len, AVP_IMS_AF_Application_Identifier,
            AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
            __FUNCTION__))
        goto error;

    LM_DBG("Adding service info status...\n");
    /* Add Service-Info-Status AVP, if prelimiary
     * by default(when absent): final status is considered*/
    if (!res) {
        set_4bytes(x,
                AVP_EPC_Service_Info_Status_Preliminary_Service_Information);
        if (!rx_add_avp(aar, x, 4, AVP_IMS_Service_Info_Status,
                AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
                __FUNCTION__))
            goto error;
    }

    /* Add Auth lifetime AVP */LM_DBG("auth_lifetime %u\n", rx_auth_expiry); //TODO check why this is 0 all the time
    if (rx_auth_expiry) {
        set_4bytes(x, rx_auth_expiry);
        if (!rx_add_avp(aar, x, 4, AVP_Authorization_Lifetime,
                AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__))
            goto error;
    }

    LM_DBG("Adding subscription id...\n");

    rx_add_subscription_id_avp(aar, identifier, identifier_type);


    LM_DBG("Adding reservation priority...\n");
    /* Add Reservation Priority AVP*/
    set_4bytes(x, 0);
    if (!rx_add_avp(aar, x, 4, AVP_ETSI_Reservation_Priority,
            AAA_AVP_FLAG_VENDOR_SPECIFIC, IMS_vendor_id_ETSI,
            AVP_DUPLICATE_DATA, __FUNCTION__))
        goto error;

    LM_DBG("Adding media component...\n");
    //Note we add this AVP first as it gets the IP address which we need to create the auth session
    //Could and maybe should have a separate method that retrieves the IP from SDP - TODO

    /*---------- 2. Create and add Media-Component-Description AVP ----------*/

    /*
     *  See 3GPP TS29214
     *
     *  <Media-Component-Description> = {Media-Component-Number}
     * 								 	[Media-Sub-Component]
     * 								 	[AF-Application-Identifier]
     * 								 	[Media-Type]
     * 								 	[Max-Requested-Bandwidth-UL]
     * 									[Max-Requested-Bandwidth-DL]
     * 									[Flow-Status]
     * 									[Reservation-Priority] (Not used yet)
     * 								 	[RS-Bandwidth]
     * 									[RR-Bandwidth]
     * 									*[Codec-Data]
     */

    add_media_components(aar, req, res, dlg_direction, auth);

    LM_DBG("Adding framed ip address [%.*s]\n", ip.len, ip.s);
    /* Add Framed IP address AVP*/
    if (!rx_add_framed_ip_avp(&aar->avpList, ip, ip_version)) {
        LM_ERR("Unable to add framed IP AVP\n");
        goto error;
    }
    
    /* Add specific action AVP's */
    rx_add_specific_action_avp(aar, 1); // CHARGING_CORRELATION_EXCHANGE
    rx_add_specific_action_avp(aar, 2); // INDICATION_OF_LOSS_OF_BEARER
    rx_add_specific_action_avp(aar, 3); // INDICATION_RECOVERY_OF_BEARER
    rx_add_specific_action_avp(aar, 4); // INDICATION_RELEASE_OF_BEARER
    rx_add_specific_action_avp(aar, 5); // INDICATION_ESTABLISHMENT_OF_BEARER (now void)
    rx_add_specific_action_avp(aar, 6); // IP-CAN_CHANGE
    rx_add_specific_action_avp(aar, 12); // ACCESS_NETWORK_INFO_REPORT

    show_callsessiondata(p_session_data);
    
    LM_DBG("Unlocking AAA session...\n");

    if (auth)
        cdpb.AAASessionsUnlock(auth->hash);

    LM_DBG("sending AAR to PCRF\n");
    if (rx_forced_peer.len)
        ret = cdpb.AAASendMessageToPeer(aar, &rx_forced_peer,
            (void*) async_aar_callback, (void*) saved_t_data);
    else
        ret = cdpb.AAASendMessage(aar, (void*) async_aar_callback,
            (void*) saved_t_data);

    return ret;

error:
    LM_ERR("unexpected error\n");
    if (aar)
        cdpb.AAAFreeMessage(&aar);
    if (auth) {
        cdpb.AAASessionsUnlock(auth->hash);
        cdpb.AAADropAuthSession(auth);
        auth = 0;
    }
    return ret;
}
示例#23
0
文件: rx_aar.c 项目: halan/kamailio
AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res,
        AAASession* auth, str* callid, str* ftag, str* ttag, char* direction,
        rx_authsessiondata_t **rx_authdata) {
    AAAMessage* aar = 0;
    AAAMessage* aaa = 0;
    AAA_AVP* avp = 0;
    char x[4];

    str ip;
    uint16_t ip_version;

    /* find direction for AAR (orig/term) */
    //need this to add the media component details
    enum dialog_direction dlg_direction = get_dialog_direction(direction);
    if (dlg_direction == DLG_MOBILE_UNKNOWN) {
        LM_DBG("Asked to send AAR for unknown direction.....Aborting...\n");
        goto error;
    }

    aar = cdpb.AAACreateRequest(IMS_Rx, IMS_AAR, Flag_Proxyable, auth);

    LM_DBG("Created aar request...\n");

    if (!aar)
        goto error;

    /*Adding AVPs*/

    LM_DBG("Adding auth app id AVP...\n");
    /* Add Auth-Application-Id AVP */
    if (!rx_add_auth_application_id_avp(aar, IMS_Rx))
        goto error;
    if (!rx_add_vendor_specific_application_id_group(aar, IMS_vendor_id_3GPP,
            IMS_Rx))
        goto error;

    LM_DBG("Adding dest realm if not there already...\n");
    /* Add Destination-Realm AVP, if not already there */
    avp = cdpb.AAAFindMatchingAVP(aar, aar->avpList.head, AVP_Destination_Realm,
            0, AAA_FORWARD_SEARCH);
    if (!avp) {
        str realm = rx_dest_realm;
        if (realm.len && !rx_add_destination_realm_avp(aar, realm))
            goto error;
    }

    LM_DBG("Adding AF App identifier...\n");
    /* Add AF-Application-Identifier AVP */
    str af_id = {0, 0};
    af_id = IMS_Serv_AVP_val;
    if (!rx_add_avp(aar, af_id.s, af_id.len, AVP_IMS_AF_Application_Identifier,
            AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
            __FUNCTION__))
        goto error;

    LM_DBG("Adding service info status...\n");
    /* Add Service-Info-Status AVP, if prelimiary
     * by default(when absent): final status is considered*/
    if (!res) {
        set_4bytes(x,
                AVP_EPC_Service_Info_Status_Preliminary_Service_Information);
        if (!rx_add_avp(aar, x, 4, AVP_IMS_Service_Info_Status,
                AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
                __FUNCTION__))
            goto error;
    }

    /* Add Auth lifetime AVP */LM_DBG("auth_lifetime %u\n", rx_auth_expiry); //TODO check why this is 0 all the time
    if (rx_auth_expiry) {
        set_4bytes(x, rx_auth_expiry);
        if (!rx_add_avp(aar, x, 4, AVP_Authorization_Lifetime,
                AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__))
            goto error;
    }

    LM_DBG("Adding subscription id...\n");
    /* Add Subscription ID AVP*/
    int identifier_type = AVP_Subscription_Id_Type_SIP_URI; //we only do IMPU now
    //to get the SIP URI I use the dlg direction - if its mo I get the from uri from the req, if its mt I get the to uri from the req
    str identifier;
    if (dlg_direction == DLG_MOBILE_ORIGINATING) {
        cscf_get_from_uri(req, &identifier);
    } else {
        cscf_get_to_uri(req, &identifier);
    }
    rx_add_subscription_id_avp(aar, identifier, identifier_type);

    LM_DBG("Adding reservation priority...\n");
    /* Add Reservation Priority AVP*/
    set_4bytes(x, 0);
    if (!rx_add_avp(aar, x, 4, AVP_ETSI_Reservation_Priority,
            AAA_AVP_FLAG_VENDOR_SPECIFIC, IMS_vendor_id_ETSI,
            AVP_DUPLICATE_DATA, __FUNCTION__))
        goto error;

    LM_DBG("Adding media component...\n");
    //Note we add this AVP first as it gets the IP address which we need to create the auth session
    //Could and maybe should have a separate method that retrieves the IP from SDP - TODO

    /*---------- 2. Create and add Media-Component-Description AVP ----------*/

    /*
     *  See 3GPP TS29214
     *
     *  <Media-Component-Description> = {Media-Component-Number}
     * 								 	[Media-Sub-Component]
     * 								 	[AF-Application-Identifier]
     * 								 	[Media-Type]
     * 								 	[Max-Requested-Bandwidth-UL]
     * 									[Max-Requested-Bandwidth-DL]
     * 									[Flow-Status]
     * 									[Reservation-Priority] (Not used yet)
     * 								 	[RS-Bandwidth]
     * 									[RR-Bandwidth]
     * 									*[Codec-Data]
     */

    add_media_components(aar, req, res, dlg_direction, &ip, &ip_version);

    LM_DBG("Adding framed ip address [%.*s]\n", ip.len, ip.s);
    /* Add Framed IP address AVP*/
    if (!rx_add_framed_ip_avp(&aar->avpList, ip, ip_version)) {
        LM_ERR("Unable to add framed IP AVP\n");
        goto error;
    }
    LM_DBG("Unlocking AAA session...\n");

    if (auth)
        cdpb.AAASessionsUnlock(auth->hash);

    LM_DBG("sending AAR to PCRF\n");
    if (rx_forced_peer.len)
        aaa = cdpb.AAASendRecvMessageToPeer(aar, &rx_forced_peer);
    else
        aaa = cdpb.AAASendRecvMessage(aar);

    return aaa;

error:
    LM_ERR("unexpected error\n");
    if (aar)
        cdpb.AAAFreeMessage(&aar);
    if (auth) {
        cdpb.AAASessionsUnlock(auth->hash);
        cdpb.AAADropAuthSession(auth);
        auth = 0;
    }
    return NULL;
}