예제 #1
0
/*! \brief
 * Lookup contact in the database and rewrite Request-URI
 * \return:  1 : contacts found and returned
 *          -1 : not found
 *          -2 : error
 */
int lookup_transport(struct sip_msg* _m, udomain_t* _d, str* _uri) {
    str uri;
    pcontact_t* pcontact;
    char tmp[MAX_URI_SIZE];
    char srcip[20];
    str received_host;
    str tmp_s;
    int ret = 1;

    if (_m->new_uri.s) uri = _m->new_uri;
    else uri = _m->first_line.u.request.uri;

    received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
    received_host.s = srcip;
    
    //now lookup in usrloc
    ul.lock_udomain(_d, &uri, &received_host, _m->rcv.src_port);
    if (ul.get_pcontact(_d, &uri, &received_host, _m->rcv.src_port, &pcontact) != 0) { //need to insert new contact
	LM_WARN("received request for contact that we don't know about\n");
	ret = -1;
	goto done;
    }
    
    if (pcontact->received_proto != _m->rcv.proto) {
	reset_dst_uri(_m);
	memset(tmp, 0, MAX_URI_SIZE);	
	switch (pcontact->received_proto) {
	    case PROTO_TCP:
		snprintf(tmp, MAX_URI_SIZE, "%.*s;transport=tcp", pcontact->aor.len, pcontact->aor.s);
		break;
	    case PROTO_UDP:
		snprintf(tmp, MAX_URI_SIZE, "%.*s;transport=udp", pcontact->aor.len, pcontact->aor.s);
		break;
	    default:
		LM_WARN("unsupported transport [%d]\n", pcontact->received_proto);
		ret = -2;
		goto done;
	}

	tmp_s.s = tmp;
	tmp_s.len = strlen(tmp);
	if (set_dst_uri(_m, &tmp_s) < 0) {
	    LM_ERR("failed to set dst_uri for terminating UE\n");
	    ret = -2;
	    goto done;
	}	
	LM_DBG("Changed dst URI transport for UE to [%.*s]\n", tmp_s.len, tmp_s.s);
    }
	
done:
    ul.unlock_udomain(_d, &uri, &received_host, _m->rcv.src_port);
    return ret;
}
예제 #2
0
int pcscf_unregister(udomain_t* _d, str * uri, str * received_host, int received_port) {
	int result = -1;
	struct pcontact * pcontact;
	struct pcontact_info ci;
    	memset(&ci, 0, sizeof (struct pcontact_info));

	pcontact_info_t search_ci;
	memset(&ci, 0, sizeof(struct pcontact_info));
	
	sip_uri_t contact_uri;
        if (parse_uri(uri->s, uri->len, &contact_uri) != 0) {
            LM_WARN("Failed to parse aor [%.*s]\n", uri->len, uri->s);
            return -1;
        }

        search_ci.received_host.s = received_host->s;
        search_ci.received_host.len = received_host->len;
        search_ci.received_port = received_port;
        search_ci.received_proto = contact_uri.proto? contact_uri.proto : PROTO_UDP;
        search_ci.searchflag = SEARCH_RECEIVED;
        search_ci.via_host.s = received_host->s;
        search_ci.via_host.len = received_host->len;
        search_ci.via_port = received_port;
        search_ci.via_prot = search_ci.received_proto;
        search_ci.aor.s = uri->s;
        search_ci.aor.len = uri->len;
		search_ci.reg_state = PCONTACT_ANY;

	if (ul.get_pcontact(_d, &search_ci, &pcontact) == 0) {
		/* Lock this record while working with the data: */
		ul.lock_udomain(_d, &pcontact->via_host, pcontact->via_port, pcontact->via_proto);

		LM_DBG("Updating contact [%.*s]: setting state to PCONTACT_DEREG_PENDING_PUBLISH\n", pcontact->aor.len, pcontact->aor.s);

		ci.reg_state = PCONTACT_DEREG_PENDING_PUBLISH;
		ci.num_service_routes = 0;
		if (ul.update_pcontact(_d, &ci, pcontact) == 0) result = 1;

		/* Unlock domain */
		ul.unlock_udomain(_d, &pcontact->via_host, pcontact->via_port, pcontact->via_proto);
	}
	return result;
}
예제 #3
0
int unregister(udomain_t* _d, str * uri, str * received_host, int received_port) {
	int result = -1;
	struct pcontact * pcontact;
	struct pcontact_info ci;
    	memset(&ci, 0, sizeof (struct pcontact_info));

	if (ul.get_pcontact(_d, uri, received_host, received_port, &pcontact) == 0) {
		/* Lock this record while working with the data: */
		ul.lock_udomain(_d, &pcontact->aor, received_host, received_port);

		LM_DBG("Updating contact [%.*s]: setting state to PCONTACT_DEREG_PENDING_PUBLISH\n", pcontact->aor.len, pcontact->aor.s);

		ci.reg_state = PCONTACT_DEREG_PENDING_PUBLISH;
		ci.num_service_routes = 0;
		if (ul.update_pcontact(_d, &ci, pcontact) == 0) result = 1;

		// if (ul.delete_pcontact(_d, &pc->aor, received_host, received_port, pcontact) == 0) result = 1;

		/* Unlock domain */
		ul.unlock_udomain(_d, &pcontact->aor, received_host, received_port);
	}
	return result;
}
예제 #4
0
void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
    struct cell *t = 0;
    pcontact_t* pcontact;
    unsigned int cdp_result;
    struct pcontact_info ci;
    udomain_t* domain_t;
    int finalReply = 0;
    AAASession *auth = 0;
    rx_authsessiondata_t* p_session_data = 0;
    int result = CSCF_RETURN_ERROR;
    pcontact_info_t contact_info;

    LM_DBG("Received AAR callback\n");
    saved_transaction_local_t* local_data = (saved_transaction_local_t*) param;
    saved_transaction_t* data = local_data->global_data;
    domain_t = data->domain;

    int is_rereg = local_data->is_rereg;

    //before we do anything else, lets decrement the reference counter on replies
    lock_get(data->lock);
    data->answers_not_received--;
    if (data->answers_not_received <= 0) {
        finalReply = 1;
    }
    if (data->ignore_replies) { //there was obv. a subsequent error AFTER we had sent one/more AAR's - so we can ignore these replies and just free memory
        free_saved_transaction_data(local_data);
        if (finalReply) {
            free_saved_transaction_global_data(data);
        }
        return;
    }
    lock_release(data->lock);

    LM_DBG("received answer and we are waiting for [%d] answers so far failures flag is [%d]\n", data->answers_not_received, data->failed);

    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
        LM_ERR("t_continue: transaction not found\n");
        goto error;
    }
    //we have T, lets restore our state (esp. for AVPs)
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);

    if (is_timeout != 0) {
        LM_ERR("Error timeout when sending AAR message via CDP\n");
        counter_inc(ims_qos_cnts_h.registration_aar_timeouts);
        goto error;
    }
    if (!aaa) {
        LM_ERR("Error sending message via CDP\n");
        goto error;
    }

    counter_inc(ims_qos_cnts_h.registration_aars);
    counter_add(ims_qos_cnts_h.registration_aar_response_time, elapsed_msecs);
    counter_inc(ims_qos_cnts_h.registration_aar_replies_received);

    /* Process the response to AAR, retrieving result code and associated Rx session ID */
    if (rx_process_aaa(aaa, &cdp_result) < 0) {
        LM_ERR("Failed to process AAA from PCRF\n"); //puri.host.len, puri.host.s);
        goto error;
    }

    if (cdp_result >= 2000 && cdp_result < 3000) {
        counter_inc(ims_qos_cnts_h.successful_registration_aars);
	if (is_rereg) {
            LM_DBG("this is a re-registration, therefore we don't need to do anything except know that the the subscription was successful\n");
            result = CSCF_RETURN_TRUE;
            create_return_code(result);
            goto done;
        }
	//need to set Rx auth data to say this session has been successfully opened
	//This is used elsewhere to prevent acting on termination events when the session has not been opened
	//getting auth session
	auth = cdpb.AAAGetAuthSession(aaa->sessionId->data);
	if (!auth) {
	    LM_DBG("Could not get Auth Session for session id: [%.*s]\n", aaa->sessionId->data.len, aaa->sessionId->data.s);
	    goto error;
	}
	//getting session data
	p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
	if (!p_session_data) {
	    LM_DBG("Could not get session data on Auth Session for session id: [%.*s]\n", aaa->sessionId->data.len, aaa->sessionId->data.s);
	    if (auth) cdpb.AAASessionsUnlock(auth->hash);
	    goto error;
	}
	p_session_data->session_has_been_opened = 1;
	counter_inc(ims_qos_cnts_h.active_registration_rx_sessions);
	
	if (auth) cdpb.AAASessionsUnlock(auth->hash);
	
	
        LM_DBG("Success, received code: [%i] from PCRF for AAR request (contact: [%.*s]), (auth session id: %.*s)\n",
                cdp_result, local_data->contact.len, local_data->contact.s,
                local_data->auth_session_id.len, local_data->auth_session_id.s);
        LM_DBG("Registering for Usrloc callbacks on DELETE\n");

        ul.lock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
        
        contact_info.received_host = local_data->recv_host;
        contact_info.received_port = local_data->recv_port;
        contact_info.received_proto = local_data->recv_proto;
        contact_info.searchflag = (1 << SEARCH_RECEIVED);
        
        
        contact_info.aor = local_data->contact;
        contact_info.via_host = local_data->via_host;
        contact_info.via_port = local_data->via_port;
        contact_info.via_prot = local_data->via_proto;
        
        if (ul.get_pcontact(domain_t, &contact_info, &pcontact) != 0) {
            LM_ERR("Shouldn't get here, can't find contact....\n");
            ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
            goto error;
        }

        //at this point we have the contact
        /*set the contact state to say we have succesfully done ARR for register and that we dont need to do it again
         * for the duration of the registration.
         * */
        if (ul.update_rx_regsession(domain_t, &local_data->auth_session_id, pcontact) != 0) {
            LM_ERR("unable to update pcontact......\n");
            ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
            goto error;
        }
        memset(&ci, 0, sizeof (struct pcontact_info));
        ci.reg_state = PCONTACT_REG_PENDING_AAR;
        ci.num_service_routes = 0;
        ci.num_public_ids = 0;
        LM_DBG("impu: [%.*s] updating status to PCONTACT_REG_PENDING\n", pcontact->aor.len, pcontact->aor.s);
        ul.update_pcontact(domain_t, &ci, pcontact);
        //register for callbacks on contact
        ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE,
                callback_pcscf_contact_cb, NULL);
        ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
        result = CSCF_RETURN_TRUE;
    } else {
        LM_DBG("Received negative reply from PCRF for AAR Request\n");
	counter_inc(ims_qos_cnts_h.failed_registration_aars);
        result = CSCF_RETURN_FALSE;
        goto error;
    }

    //set success response code AVP
    create_return_code(result);
    goto done;

error:
    //set failure response code
    create_return_code(result);

done:
    if (t) tmb.unref_cell(t);
    //free memory
    if (aaa)
        cdpb.AAAFreeMessage(&aaa);

    if (finalReply) {
        tmb.t_continue(data->tindex, data->tlabel, data->act);
        free_saved_transaction_global_data(data);
    }
    free_saved_transaction_data(local_data);
}
예제 #5
0
pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d, enum pcontact_reg_states reg_state, char service_routes[][MAXROUTESIZE], int num_service_routes) {
	ppublic_t * p;
	contact_body_t *b = 0;
	contact_t *ct;
	pcontact_info_t search_ci;
	str received_host = {0, 0};
	char srcip[50];
	struct via_body *vb;
	unsigned short port, proto;
	str host;
	sip_uri_t contact_uri;
	int mustRetryViaSearch = 0;
	int mustRetryReceivedSearch = 0;

	LM_DBG("number of service routes to look for is %d\n", num_service_routes);
    b = cscf_parse_contacts(_m);

    if (_m->first_line.type == SIP_REPLY && _m->contact && _m->contact->parsed && b->contacts) {
		mustRetryViaSearch = 1;
		mustRetryReceivedSearch = 1;
        LM_DBG("This is a reply - to look for contact we favour the contact header above the via (b2bua)... if no contact we will use last via\n");
        ct = b->contacts;
        host = ct->uri;
        if (parse_uri(ct->uri.s, ct->uri.len, &contact_uri) != 0) {
            LM_WARN("Failed to parse contact [%.*s]\n", ct->uri.len, ct->uri.s);
            return NULL;
        }
        host = contact_uri.host;
        port = contact_uri.port_no ? contact_uri.port_no : 5060;
        proto = contact_uri.proto;
        if (proto == 0) {
            LM_DBG("Contact protocol not specified - using received\n");
            proto = _m->rcv.proto;
        }
    } else {
        if (_m->first_line.type == SIP_REPLY)
            LM_DBG("This is a reply but we are forced to use the via header\n");
        else
            LM_DBG("This is a request - using first via to find contact\n");

        vb = cscf_get_ue_via(_m);
        host = vb->host;
        port = vb->port ? vb->port : 5060;
        proto = vb->proto;
    }

    LM_DBG("searching for contact with host:port:proto contact [%d://%.*s:%d]\n", proto, host.len, host.s, port);

    received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof (srcip));
    received_host.s = srcip;

//    if (_m->id != current_msg_id) {
        current_msg_id = _m->id;
        c = NULL;
	//search_ci.reg_state = PCONTACT_REGISTERED;          //we can do this because this function is always called expecting a REGISTERED contact
	memset(&search_ci, 0, sizeof(struct pcontact_info));
    search_ci.reg_state = reg_state;
	search_ci.received_host.s = received_host.s;
	search_ci.received_host.len = received_host.len;
	search_ci.received_port = _m->rcv.src_port;
	search_ci.received_proto = _m->rcv.proto;
	search_ci.searchflag = SEARCH_RECEIVED;
	search_ci.num_service_routes = 0;
	if (is_registered_fallback2ip == 1) {
		search_ci.searchflag = SEARCH_NORMAL;
	} 
	search_ci.via_host = host;
	search_ci.via_port = port;
	search_ci.via_prot = proto;
	search_ci.aor.s = 0;
	search_ci.aor.len = 0;
	
	int size = num_service_routes==0?1:num_service_routes;
	str s_service_routes[size];
	int i;
	for (i=0;i<num_service_routes;i++) {
		s_service_routes[i].s = service_routes[i];
		s_service_routes[i].len = strlen(service_routes[i]);
		LM_DBG("Setting service routes str for pos %d to %.*s", i, s_service_routes[i].len, s_service_routes[i].s);
	}
	if (num_service_routes > 0) {
		LM_DBG("asked to search for specific service routes...\n");
		search_ci.service_routes = s_service_routes;
		search_ci.num_service_routes = num_service_routes;
		search_ci.extra_search_criteria = SEARCH_SERVICE_ROUTES;
	}

//	b = cscf_parse_contacts(_m);
tryagain:
	if (b && b->contacts) {
		for (ct = b->contacts; ct; ct = ct->next) {
			search_ci.aor = ct->uri;
			if (ul.get_pcontact(_d, &search_ci, &c) == 0) {
				if (checkcontact(_m, c) != 0) {
					c = NULL;
				} else {
					break;
				}
			}
		}
	} else {
		LM_WARN("No contact-header found...\n");
	}

	if ((c == NULL) && (is_registered_fallback2ip == 1)) {
		LM_INFO("Contact not found based on Contact-header, trying IP/Port/Proto\n");
		//			received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
		//			received_host.s = srcip;
		search_ci.searchflag = SEARCH_RECEIVED;
		if (ul.get_pcontact(_d, &search_ci, &c) == 1) {
			LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto);
		} else {
			if (checkcontact(_m, c) != 0) {
				c = NULL;
			}
		}
	}

	if ((c == NULL) && (is_registered_fallback2ip == 2)) {
		LM_INFO("Contact not found based on IP/Port/Proto, trying Contact-header\n");
		search_ci.searchflag = SEARCH_NORMAL;
		if (ul.get_pcontact(_d, &search_ci, &c) == 1) {
		} else {
			if (checkcontact(_m, c) != 0) {
				c = NULL;
			}
		}
	}

	asserted_identity = NULL;
	registration_contact = NULL;
	if (c) {
                LM_DBG("Trying to set asserted identity field");
		registration_contact = &c->contact_user;
		p = c->head;
		while (p) {
                        LM_DBG("Checking through contact users");
			if (p->is_default == 1) {
                            LM_DBG("Found default contact user so setting asserted identity");
                            asserted_identity = &p->public_identity;
                        }
			p = p->next;
		}
	}
        if (asserted_identity != NULL && asserted_identity->len > 0) {
            LM_DBG("Have set the asserted_identity param to [%.*s]\n", asserted_identity->len, asserted_identity->s);
        } else {
            LM_DBG("Asserted identity not set");
        }
            
    
//    LM_DBG("pcontact flag is [%d]\n", c->flags);
//    if (c && (c->flags & (1<<FLAG_READFROMDB)) != 0) {
//        LM_DBG("we have a contact that was read fresh from the DB....\n");
//    }
	if (!c && mustRetryViaSearch) {
		LM_DBG("This is a reply so we will search using the last via once more...\n");
		vb = cscf_get_ue_via(_m);
		search_ci.via_host = vb->host;
		search_ci.via_port = vb->port ? vb->port : 5060;
		search_ci.via_prot = vb->proto;
		mustRetryViaSearch = 0;
		goto tryagain;
	}
	
	if (!c && mustRetryReceivedSearch) {
		LM_DBG("This is a reply and we still don't have a match - will try src ip/port of message\n");
		search_ci.via_host = received_host;
		search_ci.via_port = _m->rcv.src_port;
		search_ci.via_prot = _m->rcv.proto;
		mustRetryReceivedSearch = 0;
		goto tryagain;
	}

    return c;
}
예제 #6
0
/**
 * get PContact-Structure for message
 * (search only once per Request)
 */
pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d) {
	ppublic_t * p;
	contact_body_t *b = 0;
	str received_host = {0, 0};
	contact_t *ct;
	char srcip[50];	
	int security_server_port = -1;

	if (_m->id != current_msg_id) {
		current_msg_id = _m->id;
		c = NULL;

		b = cscf_parse_contacts(_m);

		if (b && b->contacts) {
			for (ct = b->contacts; ct; ct = ct->next) {
				if (ul.get_pcontact(_d, &ct->uri, &c) == 0) {
					if (c->security) {
						switch (c->security->type) {
						case SECURITY_IPSEC:
							security_server_port = c->security->data.ipsec->port_uc;
							break;
						case SECURITY_TLS:
						case SECURITY_NONE:
							break;
						}
					} else if (c->security_temp) {
						switch (c->security->type) {
						case SECURITY_IPSEC:
							security_server_port = c->security->data.ipsec->port_uc;
							break;
						case SECURITY_TLS:
						case SECURITY_NONE:
							break;
						}
					}

					if ((c->reg_state == PCONTACT_REGISTERED) && ((c->received_port == _m->rcv.src_port) || (security_server_port == _m->rcv.src_port)) && (c->received_proto == _m->rcv.proto)) {
						received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
						received_host.s = srcip;
						LM_DBG("Received host len %d (search %d)\n", c->received_host.len, received_host.len);
						// Then check the length:
						if (c->received_host.len == received_host.len) {
							LM_DBG("Received host %.*s (search %.*s)\n",
								c->received_host.len, c->received_host.s,
								received_host.len, received_host.s);

							// Finally really compare the "received_host"
							if (!memcmp(c->received_host.s, received_host.s, received_host.len))
								break;
							c = NULL;
						}
					} else {
						c = NULL;
					}
				}
			}
		} else {
			LM_WARN("No contact-header found\n");
		}

		if ((c == NULL) && (is_registered_fallback2ip > 0)) {
			LM_WARN("Contact not found based on Contact-header, trying IP/Port/Proto\n");
			received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
			received_host.s = srcip;
			if (ul.get_pcontact_by_src(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &c) == 1)
				LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto);
		}
	}
	asserted_identity = NULL;
	if (c) {
		p = c->head;
		while (p) {
			if (p->is_default == 1)
				asserted_identity = &p->public_identity;
			p = p->next;
		}
	}

	return c;
}
예제 #7
0
파일: cmd.c 프로젝트: btriller/kamailio
int ipsec_forward(struct sip_msg* m, udomain_t* d)
{
    struct pcontact_info ci;
    pcontact_t* pcontact = NULL;
    int ret = IPSEC_CMD_FAIL; // FAIL by default

    //
    // Find the contact
    //
    if(fill_contact(&ci, m) != 0) {
        LM_ERR("Error filling in contact data\n");
        return ret;
    }

    ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);

    if (ul.get_pcontact(d, &ci, &pcontact) != 0) {
        LM_ERR("Contact doesn't exist\n");
        goto cleanup;
    }


    if(pcontact->security_temp == NULL) {
        LM_ERR("No security parameters found in contact\n");
        goto cleanup;
    }

    //get security parameters
    if(pcontact->security_temp->type != SECURITY_IPSEC ) {
        LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type);
        goto cleanup;
    }

    ipsec_t* s = pcontact->security_temp->data.ipsec;


    // Update the destination
    //
    //       from sec-agree
    //            v
    // sip:host:port
    //       ^
    //    from URI
    //int uri_len = 4 /* strlen("sip:") */ + ci.via_host.len + 5 /* max len of port number */ ;

    if(m->dst_uri.s) {
        pkg_free(m->dst_uri.s);
        m->dst_uri.s = NULL;
        m->dst_uri.len = 0;
    }

    char buf[1024];
    int buf_len = snprintf(buf, sizeof(buf) - 1, "sip:%.*s:%d", ci.via_host.len, ci.via_host.s, s->port_us);

    if((m->dst_uri.s = pkg_malloc(buf_len)) == NULL) {
        LM_ERR("Error allocating memory for dst_uri\n");
        goto cleanup;
    }

    memcpy(m->dst_uri.s, buf, buf_len);
    m->dst_uri.len = buf_len;

    // Set send socket
    struct socket_info * client_sock = grep_sock_info(&ipsec_listen_addr, ipsec_client_port, PROTO_UDP);
    if(!client_sock) {
        LM_ERR("Error calling grep_sock_info() for ipsec client port in ipsec_forward\n");
        return -1;
    }
    m->force_send_socket = client_sock;

   // Set destination info
    struct dest_info dst_info;
    dst_info.send_sock = client_sock;
#ifdef USE_DNS_FAILOVER
    if (!uri2dst(NULL, &dst_info, m, &m->dst_uri, PROTO_UDP)) {
#else
    if (!uri2dst(&dst_info, m, &m->dst_uri, PROTO_UDP)) {
#endif
        LM_ERR("Error converting dst_uri (%.*s) to struct dst_info\n", m->dst_uri.len, m->dst_uri.s);
        goto cleanup;
    }

    // Update dst_info in message
    if(m->first_line.type == SIP_REPLY) {
        struct cell *t = tmb.t_gett();
        if (!t) {
            LM_ERR("Error getting transaction\n");
            goto cleanup;
        }
        t->uas.response.dst = dst_info;
    }

    LM_DBG("Destination changed to %.*s\n", m->dst_uri.len, m->dst_uri.s);

    ret = IPSEC_CMD_SUCCESS; // all good, return SUCCESS

    if(add_supported_secagree_header(m) != 0) {
        goto cleanup;
    }

    if(add_security_server_header(m, s) != 0) {
        goto cleanup;
    }

    ret = IPSEC_CMD_SUCCESS;    // all good, set ret to SUCCESS, and exit

cleanup:
    ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);
    pkg_free(ci.received_host.s);
    return ret;
}


int ipsec_destroy(struct sip_msg* m, udomain_t* d)
{
    struct pcontact_info ci;
    pcontact_t* pcontact = NULL;
    int ret = IPSEC_CMD_FAIL; // FAIL by default

    //
    // Find the contact
    //
    if(fill_contact(&ci, m) != 0) {
        LM_ERR("Error filling in contact data\n");
        return ret;
    }

    ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);

    if (ul.get_pcontact(d, &ci, &pcontact) != 0) {
        LM_ERR("Contact doesn't exist\n");
        goto cleanup;
    }


    if(pcontact->security_temp == NULL) {
        LM_ERR("No security parameters found in contact\n");
        goto cleanup;
    }

    //get security parameters
    if(pcontact->security_temp->type != SECURITY_IPSEC ) {
        LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type);
        goto cleanup;
    }

    destroy_ipsec_tunnel(ci.received_host, pcontact->security_temp->data.ipsec);

    ret = IPSEC_CMD_SUCCESS;    // all good, set ret to SUCCESS, and exit

cleanup:
    ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);
    pkg_free(ci.received_host.s);
    return ret;
}

int ipsec_cleanall()
{
    struct mnl_socket* nlsock = init_mnl_socket();
    if(!nlsock) {
        return -1;
    }

    if(clean_sa(nlsock) != 0) {
        LM_WARN("Error cleaning IPSec Security associations during startup.\n");
    }

    if(clean_policy(nlsock) != 0) {
        LM_WARN("Error cleaning IPSec Policies during startup.\n");
    }

    close_mnl_socket(nlsock);

    return 0;
}
예제 #8
0
파일: cmd.c 프로젝트: btriller/kamailio
int ipsec_create(struct sip_msg* m, udomain_t* d)
{
    pcontact_t* pcontact = NULL;
    struct pcontact_info ci;
    int ret = IPSEC_CMD_FAIL;   // FAIL by default

    // Find the contact
    if(fill_contact(&ci, m) != 0) {
        LM_ERR("Error filling in contact data\n");
        return ret;
    }

    ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);

    if (ul.get_pcontact(d, &ci, &pcontact) != 0) {
        LM_ERR("Contact doesn't exist\n");
        goto cleanup;
    }

    // Get security parameters
    if(pcontact->security_temp == NULL) {
        LM_ERR("No security parameters found in contact\n");
        goto cleanup;
    }

    if(pcontact->security_temp->type != SECURITY_IPSEC ) {
        LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type);
        goto cleanup;
    }

    ipsec_t* s = pcontact->security_temp->data.ipsec;

    if(update_contact_ipsec_params(s, m) != 0) {
        goto cleanup;
    }

    if(create_ipsec_tunnel(ci.received_host, s) != 0) {
        goto cleanup;
    }

    // TODO: Save security_tmp to security!!!!!

    if (ul.update_pcontact(d, &ci, pcontact) != 0) {
        LM_ERR("Error updating contact\n");
        goto cleanup;
    }

    // Destroy the tunnel, if the contact expires
    if(ul.register_ulcb(pcontact, PCSCF_CONTACT_EXPIRE|PCSCF_CONTACT_DELETE, on_expire, NULL) != 1) {
        LM_ERR("Error subscribing for contact\n");
        goto cleanup;
    }


    if(add_supported_secagree_header(m) != 0) {
        goto cleanup;
    }

    if(add_security_server_header(m, s) != 0) {
        goto cleanup;
    }

    ret = IPSEC_CMD_SUCCESS;    // all good, set ret to SUCCESS, and exit

cleanup:
    // Do not free str* sec_header! It will be freed in data_lump.c -> free_lump()
    ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);
    pkg_free(ci.received_host.s);
    return ret;
}
예제 #9
0
파일: notify.c 프로젝트: krys1976/kamailio
int process_contact(udomain_t * _d, int expires, str contact_uri, int contact_state) {
    char bufport[5], *rest, *sep, *val, *port, *trans;
    pcontact_t* pcontact;
    struct pcontact_info ci;
    struct sip_uri puri, uri;
    unsigned int received_proto, received_port_len;
    int local_time_now, rest_len, val_len, has_alias;
    int ret = RESULT_CONTACTS_FOUND;

    pcscf_act_time();
    local_time_now = time_now;

    has_alias = 0;

    //get contact
    //if does not exist then add it
    //if it does exist check if state it terminated - if so delete it, if not update it

    memset(&ci, 0, sizeof (struct pcontact_info));
    ci.num_public_ids = 0;
    ci.num_service_routes = 0;

    LM_DBG("Processing contact using contact from NOTIFY [%.*s]\n", contact_uri.len, contact_uri.s);
    if (parse_uri(contact_uri.s, contact_uri.len, &puri) < 0) {
        LM_DBG("Error parsing Contact URI <%.*s>\n", contact_uri.len, contact_uri.s);
        return RESULT_ERROR;
    }

    expires = local_time_now + expires; //turn expires into correct time since epoch format
    LM_DBG("Changed expires to format time since the epoch: %d", expires);
    ci.expires = expires;
    ci.reg_state = PCONTACT_REGISTERED;


    ul.lock_udomain(_d, &puri.host, puri.port_no, puri.proto);
    ci.aor = contact_uri;
    ci.via_host = puri.host;
    ci.via_prot = puri.proto;
    ci.via_port = puri.port_no;

    /* parse the uri in the NOTIFY */
    if (parse_uri(contact_uri.s, contact_uri.len, &uri) != 0) {
        LM_ERR("Unable to parse contact in SIP notify [%.*s]\n", contact_uri.len, contact_uri.s);
        return RESULT_ERROR;
    }
    /*check for alias - NAT */
    rest = uri.sip_params.s;
    rest_len = uri.sip_params.len;

    while (rest_len >= ALIAS_LEN) {
        if (strncmp(rest, ALIAS, ALIAS_LEN) == 0) {
            has_alias = 1;
            break;
        }
        sep = memchr(rest, 59 /* ; */, rest_len);
        if (sep == NULL) {
            LM_DBG("no alias param\n");
            break;
        } else {
            rest_len = rest_len - (sep - rest + 1);
            rest = sep + 1;
        }
    }

    if (has_alias) {
        val = rest + ALIAS_LEN;
        val_len = rest_len - ALIAS_LEN;
        port = memchr(val, 126 /* ~ */, val_len);
        if (port == NULL) {
            LM_ERR("no '~' in alias param value\n");
            return RESULT_ERROR;
        }
        port++;
        //            received_port = atoi(port);
        trans = memchr(port, 126 /* ~ */, val_len - (port - val));
        if (trans == NULL) {
            LM_ERR("no second '~' in alias param value\n");
            return RESULT_ERROR;
        }

        received_port_len = trans - port;

        trans = trans + 1;
        received_proto = *trans - 48 /* char 0 */;

        memcpy(bufport, port, received_port_len);
        bufport[received_port_len]=0;
        
        ci.received_host.s = val;
        ci.received_host.len = port - val - 1;
        LM_DBG("Setting received host in search to [%.*s]\n", ci.received_host.len, ci.received_host.s);
        ci.received_port = atoi(bufport);
        LM_DBG("Setting received port in search to %d\n", ci.received_port);
        ci.received_proto = received_proto;
        LM_DBG("Setting received proto in search to %d\n", ci.received_proto);
        ci.searchflag = SEARCH_RECEIVED;
    } else {
        LM_DBG("Contact in NOTIFY does not have an alias....\n");
    }

    if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //contact does not exist
        if (contact_state == STATE_TERMINATED) {
            LM_DBG("This contact: <%.*s> is in state terminated and is not in usrloc, ignore\n", contact_uri.len, contact_uri.s);
            ret = RESULT_CONTACTS_FOUND;
            goto done;
        }
        LM_WARN("This contact: <%.*s> is in state active and is not in usrloc - must be another contact on a different P so going to ignore\n", contact_uri.len, contact_uri.s);
        //		LM_DBG("This contact: <%.*s> is in state active and is not in usrloc so adding it to usrloc, expires: %d which is in %d seconds\n", contact_uri.len, contact_uri.s, expires, expires-local_time_now);
        //		if (ul.insert_pcontact(_d, &contact_uri, &ci, &pcontact) != 0) {
        //			LM_ERR("Failed inserting new pcontact\n");
        //			ret = RESULT_ERROR;
        //			goto done;
        //		} else {
        //			//register for callbacks on this contact so we can send PUBLISH to SCSCF should status change
        //			LM_DBG("registering for UL callback\n");
        //			ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL);
        //		}
    } else {//contact exists
        if (contact_state == STATE_TERMINATED) {
            //delete contact
            LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
            if (ul.delete_pcontact(_d, pcontact) != 0) {
                LM_DBG("failed to delete pcscf contact <%.*s> - not a problem this may have been removed by de registration", contact_uri.len, contact_uri.s);
            }
            /*TODO_LATEST - put this back */
        } else {//state is active
            //update this contact
            LM_DBG("This contact: <%.*s> is in state active and is in usrloc so just updating - old expires: %li, new expires: %i which is in %i seconds\n", contact_uri.len, contact_uri.s,
                    pcontact->expires,
                    expires,
                    expires - local_time_now);
            if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
                LM_ERR("failed to update pcscf contact\n");
                ret = RESULT_ERROR;
                goto done;
            }
            pcontact->expires = expires;
        }
    }

done:
    ul.unlock_udomain(_d, &puri.host, puri.port_no, puri.proto);
    return ret;
}
예제 #10
0
/**
 * Save contact based on REGISTER request. this will be a pending save, until we receive response
 * from SCSCF. If no response after pending_timeout seconds, the contacts is removed. Can only be used from REQUEST ROUTE
 */
int save_pending(struct sip_msg* _m, udomain_t* _d) {
	contact_body_t* cb = 0;
	int cexpires = 0;
	pcontact_t* pcontact;
	contact_t* c;
	struct pcontact_info ci;
        struct via_body* vb;
        unsigned short port, proto;
	int_str val;
	struct sip_uri parsed_received;
	char srcip[50];

	memset(&ci, 0, sizeof(struct pcontact_info));
        
        vb = cscf_get_ue_via(_m);
        port = vb->port?vb->port:5060;
        proto = vb->proto;

	cb = cscf_parse_contacts(_m);
	if (!cb || (!cb->contacts)) {
		LM_ERR("No contact headers\n");
		goto error;
	}
        
        c = cb->contacts;
	//TODO: need support for multiple contacts - currently assume one contact
	//make sure this is not a de-registration
	int expires_hdr = cscf_get_expires_hdr(_m, 0);
	if (expires_hdr < 0) {
		//no global header we have to check the contact expiry
		if (c && c->expires && c->expires->body.len) {
				str2int(&(c->expires->body), (unsigned int*) &cexpires);
		}
		if (!cexpires){ //assume de-registration
			LM_DBG("not doing pending reg on de-registration\n");
			return 1;
		}
	}
        
	pcscf_act_time();
	int local_time_now = time_now;
	int expires = calc_contact_expires(c, expires_hdr, local_time_now);
	if (expires <= 0) {
		LM_DBG("not doing pending reg on de-registration\n");
		return 1;
	}
        LM_DBG("Save Pending");
	LM_DBG("contact requesting to expire in %d seconds\n", expires-local_time_now);

	/*populate CI with bare minimum*/
        ci.via_host = vb->host;
        ci.via_port = port;
        ci.via_prot = proto;
        ci.aor = c->uri;
	ci.num_public_ids=0;
	ci.num_service_routes=0;
	ci.expires=local_time_now + pending_reg_expires;
	ci.reg_state=PCONTACT_ANY;
        ci.searchflag=SEARCH_RECEIVED;  //we want to make sure we are very specific with this search to make sure we get the correct contact to put into reg_pending.

	// Received Info: First try AVP, otherwise simply take the source of the request:
	memset(&val, 0, sizeof(int_str));
	if (rcv_avp_name.n != 0
			&& search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0)
			&& val.s.len > 0) {
		if (val.s.len > RECEIVED_MAX_SIZE) {
			LM_ERR("received too long\n");
			goto error;
		}
		if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) {
			LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s);
			goto error;
		}
		ci.received_host = parsed_received.host;
		ci.received_port = parsed_received.port_no;
		ci.received_proto = parsed_received.proto;
	} else {
		ci.received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip,
				sizeof(srcip));
		ci.received_host.s = srcip;
		ci.received_port = _m->rcv.src_port;
		ci.received_proto = _m->rcv.proto;
                
	}
	// Set to default, if not set:
	if (ci.received_port == 0)
		ci.received_port = 5060;

	ul.lock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);
	if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
		LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s);
		ci.reg_state=PCONTACT_REG_PENDING;
		if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {
			LM_ERR("Failed inserting new pcontact\n");
		} else {
			LM_DBG("registering for UL callback\n");
			ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE | PCSCF_CONTACT_UPDATE, callback_pcscf_contact_cb, NULL);
		}
	} else { //contact already exists - update
		LM_DBG("Contact already exists - not doing anything for now\n");
	}
	ul.unlock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);

	return 1;

error:
	LM_DBG("Error saving pending contact\n");
	return -1;
}
예제 #11
0
/**
 * get PContact-Structure for message
 * (search only once per Request)
 */
pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d) {
	ppublic_t * p;
	contact_body_t *b = 0;
	contact_t *ct;
	str received_host = {0, 0};
	char srcip[50];	

	received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
			received_host.s = srcip;
			
	if (_m->id != current_msg_id) {
		current_msg_id = _m->id;
		c = NULL;

		if (is_registered_fallback2ip == 2) {
			LM_DBG("Searching in usrloc for %.*s:%i (Proto %i)\n",
				received_host.len, received_host.s,
				_m->rcv.src_port, _m->rcv.proto);

			if (ul.get_pcontact_by_src(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &c) == 1) {
				LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto);
			} else {
				if (checkcontact(_m, c) != 0) {
					c = NULL;
				}
			}
		}

		if (c == NULL) {
			b = cscf_parse_contacts(_m);

			if (b && b->contacts) {
				for (ct = b->contacts; ct; ct = ct->next) {
					if (ul.get_pcontact(_d, &ct->uri, &received_host, _m->rcv.src_port, &c) == 0) {
						if (checkcontact(_m, c) != 0) {
							c = NULL;
						} else {
							break;
						}
					}
				}
			} else {
				LM_WARN("No contact-header found?!?\n");
			}
		}

		if ((c == NULL) && (is_registered_fallback2ip == 1)) {
			LM_INFO("Contact not found based on Contact-header, trying IP/Port/Proto\n");
			received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
			received_host.s = srcip;
			if (ul.get_pcontact_by_src(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &c) == 1) {
				LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto);
			} else {
				if (checkcontact(_m, c) != 0) {
					c = NULL;
				}
			}
		}
	}
	asserted_identity = NULL;
	registration_contact = NULL;
	if (c) {
		registration_contact = &c->contact_user;
		p = c->head;
		while (p) {
			if (p->is_default == 1)
				asserted_identity = &p->public_identity;
			p = p->next;
		}
	}

	return c;
}
예제 #12
0
/**
 * Updates the registrar with the new values
 * @param req - the REGISTER request - to extract NAT info
 * @param rpl - the REGISTER reply - to extract contact info
 * @param is_star - whether this was a STAR contact header
 * @param expires_hdr - value of the Expires header
 * @param public_id - array of public identities attached to this contact
 * @param public_id_cnt - size of the public_id array
 * @param service_route - array of Service-Routes
 * @param service_route_cnt - size of the service_route array
 * @param requires_nat - if to create pinholes
 * @returns the maximum expiration time, -1 on error
 */
static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udomain_t* _d, unsigned char is_star,int expires_hdr,
        str *public_id,int public_id_cnt,str *service_route,int service_route_cnt, int requires_nat)
{
	int local_time_now, expires=0;
	struct hdr_field* h;
	contact_t* c;
	struct sip_uri puri;
	struct pcontact_info ci;
	pcontact_t* pcontact;
	unsigned short port, proto;
	char *alias_start, *p, *port_s, *proto_s;
	char portbuf[5];
	str alias_s;

	pcscf_act_time();
	local_time_now = time_now;
	if (is_star) {
		/* first of all, we shouldn't get here...
		 * then, we will update on NOTIFY */
		return 0;
	}

	// Set the structure to "0", to make sure it's properly initialized
	memset(&ci, 0, sizeof(struct pcontact_info));

	for (h = rpl->contact; h; h = h->next) {
		if (h->type == HDR_CONTACT_T && h->parsed) {
			for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) {
				expires = calc_contact_expires(c, expires_hdr, local_time_now);
				if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) {
					LM_DBG("Error parsing Contact URI <%.*s>\n", c->uri.len, c->uri.s);
					continue;
				}
				//build contact info
				ci.aor = c->uri;
				ci.expires = expires;
				ci.public_ids = public_id;
				ci.num_public_ids = public_id_cnt;
				ci.service_routes = service_route;
				ci.num_service_routes = service_route_cnt;
				ci.reg_state = PCONTACT_REGISTERED|PCONTACT_REG_PENDING|PCONTACT_REG_PENDING_AAR;   //we don't want to add contacts that did not come through us (pcscf)
				
				ci.received_host.len = 0;
				ci.received_host.s = 0;
				ci.received_port = 0;
				ci.received_proto = 0;
				port = puri.port_no ? puri.port_no : 5060;
				ci.via_host = puri.host;
				ci.via_port = port;
				ci.via_prot = puri.proto;
				ci.searchflag = SEARCH_NORMAL; /* this must be reset for each contact iteration */

				if (puri.params.len > 6 && (alias_start = _strnistr(puri.params.s, "alias=", puri.params.len)) != NULL) {
					LM_DBG("contact has an alias [%.*s] - we can use that as the received\n", puri.params.len, puri.params.s);
					alias_s.len = puri.params.len - (alias_start - puri.params.s) - 6;
					alias_s.s = alias_start + 6;
					LM_DBG("alias [%.*s]\n", alias_s.len, alias_s.s);
					p = _strnistr(alias_s.s, "~", alias_s.len);
					if (p!=NULL) {
						ci.received_host.s = alias_s.s;
						ci.received_host.len = p - alias_s.s;
						LM_DBG("alias(host) [%.*s]\n", ci.received_host.len, ci.received_host.s);
						port_s = p+1;
						p = _strnistr(port_s, "~", alias_s.len - ci.received_host.len);
						if (p!=NULL) {
							LM_DBG("alias(port) [%.*s]\n", (int)(p - port_s) , port_s);
							memset(portbuf, 0, 5);
							memcpy(portbuf, port_s, (p-port_s));
							port = atoi(portbuf);
							LM_DBG("alias(port) [%d]\n", port);
							
							proto_s = p + 1;
							memset(portbuf, 0, 5);
							memcpy(portbuf, proto_s, 1);
							proto = atoi(portbuf);
							LM_DBG("alias(proto) [%d]\n", proto);
							ci.received_port = port;
							ci.received_proto = proto;
							ci.searchflag = SEARCH_RECEIVED;
						}
					}
				} 
				
				ul.lock_udomain(_d, &puri.host, port, puri.proto);
				if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
					if ((expires-local_time_now)<=0) { //remove contact - de-register
						LM_DBG("This is a de-registration for contact <%.*s> but contact is not in usrloc - ignore\n", c->uri.len, c->uri.s);
						goto next_contact;
					} 
				    
                                        LM_DBG("We don't add contact from the 200OK that did not go through us (ie, not present in explicit REGISTER that went through us\n");
//					LM_DBG("Adding pcontact: <%.*s>, expires: %d which is in %d seconds\n", c->uri.len, c->uri.s, expires, expires-local_time_now);
//					ci.reg_state = PCONTACT_REGISTERED;
//					if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {
//						LM_ERR("Failed inserting new pcontact\n");
//					} else {
//						//register for callbacks on this contact so we can send PUBLISH to SCSCF should status change
//						LM_DBG("registering for UL callback\n");
//						ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL);
//						//we also need to subscribe to reg event of this contact at SCSCF
//					}
				} else { //contact already exists - update
					LM_DBG("contact already exists and is in state (%d) : [%s]\n",pcontact->reg_state, reg_state_to_string(pcontact->reg_state));
					if ((expires-local_time_now)<=0) { //remove contact - de-register
						LM_DBG("This is a de-registration for contact <%.*s>\n", c->uri.len, c->uri.s);
						if (ul.delete_pcontact(_d, pcontact) != 0) {
							LM_ERR("failed to delete pcscf contact <%.*s>\n", c->uri.len, c->uri.s);
						}
                                                //TODO_LATEST replace above
					} else { //update contact
						LM_DBG("Updating contact: <%.*s>, old expires: %li, new expires: %i which is in %i seconds\n", c->uri.len, c->uri.s,
								pcontact->expires-local_time_now,
								expires,
								expires-local_time_now);
						ci.reg_state = PCONTACT_REGISTERED;
						if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
							LM_ERR("failed to update pcscf contact\n");
						}
						pcontact->expires = expires;
					}
				}
next_contact:
				ul.unlock_udomain(_d, &puri.host, port, puri.proto);
			}
		}
	}
	return 1;
}
예제 #13
0
파일: mod.c 프로젝트: Jared-Prime/kamailio
/* Wrapper to send AAR from config file - only used for registration */
static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char* bar) {

    int ret = CSCF_RETURN_ERROR;
    struct pcontact_info ci;
    struct cell *t;
    contact_t* c;
    struct hdr_field* h;
    pcontact_t* pcontact;
    contact_body_t* cb = 0;
    AAASession* auth;
    rx_authsessiondata_t* rx_regsession_data_p;
    cfg_action_t* cfg_action = 0;
    str route_name;
    char* p;
    int aar_sent = 0;
    saved_transaction_local_t* local_data = 0; //data to be shared across all async calls
    saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call
    
    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;
    }
    
    udomain_t* domain_t = (udomain_t*) str1;
    
    int is_rereg = 0; //is this a reg/re-reg

    LM_DBG("Rx AAR Register called\n");

    //create the default return code AVP
    create_return_code(ret);

    memset(&ci, 0, sizeof (struct pcontact_info));

    /** If this is a response then let's check the status before we try and do an AAR.
     * We will only do AAR for register on success response and of course if message is register
     */
    if (msg->first_line.type == SIP_REPLY) {
        //check this is a response to a register
        /* Get the SIP request from this transaction */
        t = tmb.t_gett();
        if (!t) {
            LM_ERR("Cannot get transaction for AAR based on SIP Request\n");
            goto error;
        }
        if ((strncmp(t->method.s, "REGISTER", 8) != 0)) {
            LM_ERR("Method is not a response to a REGISTER\n");
            goto error;
        }
        if (msg->first_line.u.reply.statuscode < 200
                || msg->first_line.u.reply.statuscode >= 300) {
            LM_DBG("Message is not a 2xx OK response to a REGISTER\n");
            goto error;
        }
        tmb.t_release(msg);
    } else { //SIP Request
        /* in case of request make sure it is a REGISTER */
        if (msg->first_line.u.request.method_value != METHOD_REGISTER) {
            LM_DBG("This is not a register request\n");
            goto error;
        }

        if ((cscf_get_max_expires(msg, 0) == 0)) {
            //if ((cscf_get_expires(msg) == 0)) {
            LM_DBG("This is a de registration\n");
            LM_DBG("We ignore it as these are dealt with by usrloc callbacks \n");
            create_return_code(CSCF_RETURN_TRUE);
            return CSCF_RETURN_TRUE;
        }
    }

    //before we continue, make sure we have a transaction to work with (viz. cdp async)
    t = tmb.t_gett();
    if (t == NULL || t == T_UNDEFINED) {
        if (tmb.t_newtran(msg) < 0) {
            LM_ERR("cannot create the transaction for UAR async\n");
            return CSCF_RETURN_ERROR;
        }
        t = tmb.t_gett();
        if (t == NULL || t == T_UNDEFINED) {
            LM_ERR("cannot lookup the transaction\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;
    saved_t_data->domain = domain_t;
    saved_t_data->lock = lock_alloc();
    if (saved_t_data->lock == NULL) {
        LM_ERR("unable to allocate init lock for saved_t_transaction reply counter\n");
        return CSCF_RETURN_ERROR;
    }
    if (lock_init(saved_t_data->lock) == NULL) {
        LM_ERR("unable to init lock for saved_t_transaction reply counter\n");
        return CSCF_RETURN_ERROR;
    }

    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("Successfully suspended transaction\n");

    //now get the contacts in the REGISTER and do AAR for each one.
    cb = cscf_parse_contacts(msg);
    if (!cb || (!cb->contacts && !cb->star)) {
        LM_DBG("No contact headers in Register message\n");
        goto error;
    }

    lock_get(saved_t_data->lock); //we lock here to make sure we send all requests before processing replies asynchronously
    for (h = msg->contact; h; h = h->next) {
        if (h->type == HDR_CONTACT_T && h->parsed) {
            for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) {
                ul.lock_udomain(domain_t, &c->uri);
                if (ul.get_pcontact(domain_t, &c->uri, &pcontact) != 0) {
                    LM_DBG("This contact does not exist in PCSCF usrloc - error in cfg file\n");
                    ul.unlock_udomain(domain_t, &c->uri);
                    lock_release(saved_t_data->lock);
                    goto error;
                } else if (pcontact->reg_state == PCONTACT_REG_PENDING
                        || pcontact->reg_state == PCONTACT_REGISTERED) { //NEW reg request
                    LM_DBG("Contact [%.*s] exists and is in state PCONTACT_REG_PENDING or PCONTACT_REGISTERED\n"
                            , pcontact->aor.len, pcontact->aor.s);

                    //get IP address from contact
                    struct sip_uri puri;
                    if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) {
                        LM_ERR("failed to parse Contact\n");
                        ul.unlock_udomain(domain_t, &c->uri);
                        lock_release(saved_t_data->lock);
                        goto error;

                    }
                    LM_DBG("Parsed URI of from host is [%.*s]\n", puri.host.len, puri.host.s);
                    uint16_t ip_version = AF_INET; //TODO IPv6!!!?

                    //check for existing Rx session
                    if (pcontact->rx_session_id.len > 0
                            && pcontact->rx_session_id.s
                            && (auth = cdpb.AAAGetAuthSession(pcontact->rx_session_id))) {
                        LM_DBG("Rx session already exists for this user\n");
                        if (memcmp(pcontact->rx_session_id.s, auth->id.s, auth->id.len) != 0) {
                            LM_ERR("Rx session mismatch when URI is [%.*s].......Aborting\n", puri.host.len, puri.host.s);
                            if (auth) cdpb.AAASessionsUnlock(auth->hash);
                            lock_release(saved_t_data->lock);
                            goto error;
                        }
                        //re-registration - update auth lifetime
                        auth->u.auth.lifetime = time(NULL) + rx_auth_expiry;
                        is_rereg = 1;
                    } else {
                        LM_DBG("Creating new Rx session for contact <%.*s>\n", pcontact->aor.len, pcontact->aor.s);
                        int ret = create_new_regsessiondata(domain_t->name, &pcontact->aor, &rx_regsession_data_p);
                        if (!ret) {
                            LM_ERR("Unable to create regsession data parcel when URI is [%.*s]...Aborting\n", puri.host.len, puri.host.s);
                            ul.unlock_udomain(domain_t, &c->uri);
                            if (rx_regsession_data_p) {
                                shm_free(rx_regsession_data_p);
                                rx_regsession_data_p = 0;
                            }
                            lock_release(saved_t_data->lock);
                            goto error;
                        }
                        auth = cdpb.AAACreateClientAuthSession(1, callback_for_cdp_session, rx_regsession_data_p); //returns with a lock
                        if (!auth) {
                            LM_ERR("Rx: unable to create new Rx Reg Session when URI is [%.*s]\n", puri.host.len, puri.host.s);
                            if (rx_regsession_data_p) {
                                shm_free(rx_regsession_data_p);
                                rx_regsession_data_p = 0;
                            }
                            ul.unlock_udomain(domain_t, &c->uri);
                            if (auth) cdpb.AAASessionsUnlock(auth->hash);
                            if (rx_regsession_data_p) {
                                shm_free(rx_regsession_data_p);
                                rx_regsession_data_p = 0;
                            }
                            lock_release(saved_t_data->lock);
                            goto error;
                        }
                    }

                    //we are ready to send the AAR async. lets save the local data data
                    int local_data_len = sizeof (saved_transaction_local_t) + c->uri.len + auth->id.len;
                    local_data = shm_malloc(local_data_len);
                    if (!local_data) {
                        LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n");
                        lock_release(saved_t_data->lock);
                        goto error;
                    }
                    memset(local_data, 0, local_data_len);

                    local_data->is_rereg = is_rereg;
                    local_data->global_data = saved_t_data;
                    p = (char*) (local_data + 1);

                    local_data->contact.s = p;
                    local_data->contact.len = c->uri.len;
                    memcpy(p, c->uri.s, c->uri.len);
                    p += c->uri.len;

                    local_data->auth_session_id.s = p;
                    local_data->auth_session_id.len = auth->id.len;
                    memcpy(p, auth->id.s, auth->id.len);
                    p += auth->id.len;

                    if (p != (((char*) local_data) + local_data_len)) {
                        LM_CRIT("buffer overflow\n");
                        free_saved_transaction_data(local_data);
                        goto error;
                    }

                    LM_DBG("Calling send aar register");

                    //TODOD remove - no longer user AOR parm
                    //ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object
                    ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, local_data); //returns a locked rx auth object

                    ul.unlock_udomain(domain_t, &c->uri);

                    if (!ret) {
                        LM_ERR("Failed to send AAR\n");
                        lock_release(saved_t_data->lock);
                        free_saved_transaction_data(local_data); //free the local data becuase the CDP async request was not successful (we must free here)
                        goto error;
                    } else {
                        aar_sent = 1;
                        //before we send - bump up the reply counter
                        saved_t_data->answers_not_received++; //we dont need to lock as we already hold the lock above
                    }
                } else {
                    //contact exists - this is a re-registration, for now we just ignore this
                    LM_DBG("This contact exists and is not in state REGISTER PENDING - we assume re (or de) registration and ignore\n");
                    ul.unlock_udomain(domain_t, &c->uri);
                    //now we loop for any other contacts.
                }
            }
        } else {
            if (h->type == HDR_CONTACT_T) { //means we couldnt parse the contact - this is an error
                LM_ERR("Failed to parse contact header\n");
                lock_release(saved_t_data->lock);
                goto error;
            }
        }
    }
    //all requests sent at this point - we can unlock the reply lock
    lock_release(saved_t_data->lock);

    /*if we get here, we have either:
     * 1. Successfully sent AAR's for ALL contacts, or
     * 2. haven't needed to send ANY AAR's for ANY contacts
     */
    if (aar_sent) {
        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
    } else {
        create_return_code(CSCF_RETURN_TRUE);
        tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
        if (saved_t_data) {
            free_saved_transaction_global_data(saved_t_data); //no aar sent so we must free the global data
        }
        //return CSCF_RETURN_ERROR;
        return CSCF_RETURN_TRUE;
    }
error:
    LM_ERR("Error trying to send AAR\n");
    if (!aar_sent) {
        tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
        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;
    //return CSCF_RETURN_FALSE;
}
예제 #14
0
/*main event process function*/
void cdp_cb_event_process() {
    cdp_cb_event_t *ev;
    udomain_t* domain;
    pcontact_t* pcontact;
    str release_reason = {"QoS released", 12}; /* TODO: This could be a module parameter */
    struct pcontact_info ci;
    memset(&ci, 0, sizeof (struct pcontact_info));

    for (;;) {
        ev = pop_cdp_cb_event();

        if (cdp_event_latency) { //track delays
            unsigned int diff = time(NULL) - ev->registered;
            if (diff > cdp_event_threshold) {
                switch (cdp_event_latency_loglevel) {
                    case 0:
                        LM_ERR("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
                        break;
                    case 1:
                        LM_WARN("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
                        break;
                    case 2:
                        LM_INFO("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
                        break;
                    case 3:
                        LM_DBG("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
                        break;
                    default:
                        LM_DBG("Unknown log level....printing as debug\n");
                        LM_DBG("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
                        break;
                }
            }
        }
        LM_DBG("processing event [%d]\n", ev->event);
        rx_authsessiondata_t *p_session_data = ev->session_data;
        str *rx_session_id = &ev->rx_session_id;

        switch (ev->event) {
            case AUTH_EV_SESSION_TIMEOUT:
            case AUTH_EV_SESSION_GRACE_TIMEOUT:
            case AUTH_EV_RECV_ASR:
                LM_DBG("Received notification of ASR from transport plane or CDP timeout for CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
                        " and domain [%.*s]\n",
                        rx_session_id->len, rx_session_id->s,
                        p_session_data->registration_aor.len, p_session_data->registration_aor.s,
                        p_session_data->domain.len, p_session_data->domain.s);


                if (p_session_data->subscribed_to_signaling_path_status) {
                    LM_DBG("This is a subscription to signalling bearer session");
                    //nothing to do here - just wait for AUTH_EV_SERVICE_TERMINATED event
                } else {
                    LM_DBG("This is a media bearer session session");
                    //this is a media bearer session that was terminated from the transport plane - we need to terminate the associated dialog
                    //so we set p_session_data->must_terminate_dialog to 1 and when we receive AUTH_EV_SERVICE_TERMINATED event we will terminate the dialog
                    p_session_data->must_terminate_dialog = 1;
                }
                break;

            case AUTH_EV_SERVICE_TERMINATED:
                LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
                        " and domain [%.*s]\n",
                        rx_session_id->len, rx_session_id->s,
                        p_session_data->registration_aor.len, p_session_data->registration_aor.s,
                        p_session_data->domain.len, p_session_data->domain.s);

                if (p_session_data->subscribed_to_signaling_path_status) {
                    LM_DBG("This is a subscription to signalling bearer session");
                    //instead of removing the contact from usrloc_pcscf we just change the state of the contact to TERMINATE_PENDING_NOTIFY
                    //pcscf_registrar sees this, sends a SIP PUBLISH and on SIP NOTIFY the contact is deleted

                    if (ul.register_udomain(p_session_data->domain.s, &domain)
                            < 0) {
                        LM_DBG("Unable to register usrloc domain....aborting\n");
                        return;
                    }
                    ul.lock_udomain(domain, &p_session_data->registration_aor);
                    if (ul.get_pcontact(domain, &p_session_data->registration_aor,
                            &pcontact) != 0) {
                        LM_DBG("no contact found for terminated Rx reg session..... ignoring\n");
                    } else {
                        LM_DBG("Updating contact [%.*s] after Rx reg session terminated, setting state to PCONTACT_DEREG_PENDING_PUBLISH\n", pcontact->aor.len, pcontact->aor.s);
                        ci.reg_state = PCONTACT_DEREG_PENDING_PUBLISH;
                        ci.num_service_routes = 0;
                        ul.update_pcontact(domain, &ci, pcontact);
                    }
                    ul.unlock_udomain(domain, &p_session_data->registration_aor);
                } else {
                    LM_DBG("This is a media bearer session session");
                    
                    //we only terminate the dialog if this was triggered from the transport plane or timeout - i.e. if must_terminate_dialog is set
                    //if this was triggered from the signalling plane (i.e. someone hanging up) then we don'y need to terminate the dialog
                    if (p_session_data->must_terminate_dialog) {
                        LM_DBG("Terminating dialog with callid, ftag, ttag: [%.*s], [%.*s], [%.*s]\n",
                                p_session_data->callid.len, p_session_data->callid.s,
                                p_session_data->ftag.len, p_session_data->ftag.s,
                                p_session_data->ttag.len, p_session_data->ttag.s);
                        dlgb.terminate_dlg(&p_session_data->callid,
                                &p_session_data->ftag, &p_session_data->ttag, NULL,
                                &release_reason);
                    }
                }

                //free callback data
                if (p_session_data) {
                    shm_free(p_session_data);
                    p_session_data = 0;
                }
                break;
            default:
                break;
        }

        free_cdp_cb_event(ev);
    }
}
예제 #15
0
파일: save.c 프로젝트: Jared-Prime/kamailio
/**
 * Updates the registrar with the new values
 * @param req - the REGISTER request - to extract NAT info
 * @param rpl - the REGISTER reply - to extract contact info
 * @param is_star - whether this was a STAR contact header
 * @param expires_hdr - value of the Expires header
 * @param public_id - array of public identities attached to this contact
 * @param public_id_cnt - size of the public_id array
 * @param service_route - array of Service-Routes
 * @param service_route_cnt - size of the service_route array
 * @param requires_nat - if to create pinholes
 * @returns the maximum expiration time, -1 on error
 */
static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udomain_t* _d, unsigned char is_star,int expires_hdr,
        str *public_id,int public_id_cnt,str *service_route,int service_route_cnt, int requires_nat)
{
	int local_time_now, expires=0;
	struct hdr_field* h;
	contact_t* c;
	struct sip_uri puri;
	struct sip_uri parsed_received;
	struct pcontact_info ci;
	pcontact_t* pcontact;
	char srcip[50];
	int_str val;

	pcscf_act_time();
	local_time_now = time_now;
	if (is_star) {
		/* first of all, we shouldn't get here...
		 * then, we will update on NOTIFY */
		return 0;
	}

	// Set the structure to "0", to make sure it's properly initialized
	memset(&ci, 0, sizeof(struct pcontact_info));

	for (h = rpl->contact; h; h = h->next) {
		if (h->type == HDR_CONTACT_T && h->parsed)
			for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) {
				expires = calc_contact_expires(c, expires_hdr, local_time_now);
				if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) {
					LM_DBG("Error parsing Contact URI <%.*s>\n", c->uri.len, c->uri.s);
					continue;
				}
				//build contact info
				ci.expires = expires;
				ci.public_ids = public_id;
				ci.num_public_ids = public_id_cnt;
				ci.service_routes = service_route;
				ci.num_service_routes = service_route_cnt;
				ci.reg_state = PCONTACT_REGISTERED;

				ci.received_host.len = 0;
				ci.received_host.s = 0;
				ci.received_port = 0;
				ci.received_proto = 0;

				// Received Info: First try AVP, otherwise simply take the source of the request:
				memset(&val, 0, sizeof(int_str));
				if (rcv_avp_name.n!=0 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0) && val.s.len > 0) {
					if (val.s.len>RECEIVED_MAX_SIZE) {
						LM_ERR("received too long\n");
						goto error;
					}
					if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) {
						LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s);
						continue;
					}
					ci.received_host = parsed_received.host;
					ci.received_port = parsed_received.port_no;
					ci.received_proto = parsed_received.proto;
				} else {
					ci.received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, sizeof(srcip));
					ci.received_host.s = srcip;
					ci.received_port = req->rcv.src_port;
					ci.received_proto = req->rcv.proto;
				}
				// Set to default, if not set:
				if (ci.received_port == 0) ci.received_port = 5060;

				ul.lock_udomain(_d, &c->uri);
				if (ul.get_pcontact(_d, &c->uri, &pcontact) != 0) { //need to insert new contact
					if ((expires-local_time_now)<=0) { //remove contact - de-register
						LM_DBG("This is a de-registration for contact <%.*s> but contact is not in usrloc - ignore\n", c->uri.len, c->uri.s);
						goto next_contact;
					} 
				    
					LM_DBG("Adding pcontact: <%.*s>, expires: %d which is in %d seconds\n", c->uri.len, c->uri.s, expires, expires-local_time_now);

					if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {
						LM_ERR("Failed inserting new pcontact\n");
					} else {
						//register for callbacks on this contact so we can send PUBLISH to SCSCF should status change
						LM_DBG("registering for UL callback\n");
						ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL);
						//we also need to subscribe to reg event of this contact at SCSCF
					}
				} else { //contact already exists - update
					LM_DBG("contact already exists and is in state (%d) : [%s]\n",pcontact->reg_state, reg_state_to_string(pcontact->reg_state));
					if ((expires-local_time_now)<=0) { //remove contact - de-register
						LM_DBG("This is a de-registration for contact <%.*s>\n", c->uri.len, c->uri.s);
						if (ul.delete_pcontact(_d, &c->uri, pcontact) != 0) {
							LM_ERR("failed to delete pcscf contact <%.*s>\n", c->uri.len, c->uri.s);
						}
					} else { //update contact
						LM_DBG("Updating contact: <%.*s>, old expires: %li, new expires: %i which is in %i seconds\n", c->uri.len, c->uri.s,
								pcontact->expires-local_time_now,
								expires,
								expires-local_time_now);
						if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
							LM_ERR("failed to update pcscf contact\n");
						}
						pcontact->expires = expires;
					}
				}
next_contact:
				ul.unlock_udomain(_d, &c->uri);
			}
	}
	return 1;
error:
	return 0;
}
예제 #16
0
파일: notify.c 프로젝트: carlosp/kamailio
int process_contact(udomain_t * _d, int expires, str contact_uri, int contact_state) {

    pcontact_t* pcontact;

    struct pcontact_info ci;

    int local_time_now;
    int ret = RESULT_CONTACTS_FOUND;

    pcscf_act_time();
    local_time_now = time_now;

    //get contact
    //if does not exist then add it
    //if it does exist check if state it terminated - if so delete it, if not update it

    memset(&ci, 0, sizeof(struct pcontact_info));
    ci.num_public_ids=0;
    ci.num_service_routes=0;

    expires = local_time_now + expires;  //turn expires into correct time since epoch format
    LM_DBG("Changed expires to format time since the epoch: %d", expires);
    ci.expires=expires;
    ci.reg_state = PCONTACT_REGISTERED;


    ul.lock_udomain(_d, &contact_uri);

    if (ul.get_pcontact(_d, &contact_uri, &pcontact) != 0) { //contact does not exist
        if (contact_state == STATE_TERMINATED) {
            LM_DBG("This contact: <%.*s> is in state terminated and is not in usrloc, ignore\n", contact_uri.len, contact_uri.s);
            ret = RESULT_CONTACTS_FOUND;
            goto done;
        }
        LM_DBG("This contact: <%.*s> is in state active and is not in usrloc so adding it to usrloc, expires: %d which is in %d seconds\n", contact_uri.len, contact_uri.s, expires, expires-local_time_now);
        if (ul.insert_pcontact(_d, &contact_uri, &ci, &pcontact) != 0) {
            LM_ERR("Failed inserting new pcontact\n");
            ret = RESULT_ERROR;
            goto done;
        } else {
            //register for callbacks on this contact so we can send PUBLISH to SCSCF should status change
            LM_DBG("registering for UL callback\n");
            ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL);
        }
    } else {//contact exists
        if (contact_state == STATE_TERMINATED) {
            //delete contact
            LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
            if (ul.delete_pcontact(_d, &contact_uri, pcontact) != 0) {
                LM_DBG("failed to delete pcscf contact <%.*s> - not a problem this may have been removed by de registration", contact_uri.len, contact_uri.s);
            }
        } else {//state is active
            //update this contact
            LM_DBG("This contact: <%.*s> is in state active and is in usrloc so just updating - old expires: %li, new expires: %i which is in %i seconds\n", contact_uri.len, contact_uri.s,
                   pcontact->expires,
                   expires,
                   expires-local_time_now);
            if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
                LM_ERR("failed to update pcscf contact\n");
                ret = RESULT_ERROR;
                goto done;
            }
            pcontact->expires = expires;
        }
    }

done:
    ul.unlock_udomain(_d, &contact_uri);
    return ret;
}