예제 #1
0
파일: notify.c 프로젝트: vingarzan/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;
}
예제 #2
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;
}
예제 #3
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;
}
예제 #4
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;
}