static void __dialog_cbtest(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { str tag; LM_DBG("dialog callback received, from=%.*s, to=%.*s\n", dlg->from_uri.len, dlg->from_uri.s, dlg->to_uri.len, dlg->to_uri.s); if (dlg->tag[0].len && dlg->tag[0].s ) { LM_DBG("dialog callback: tag[0] = %.*s\n", dlg->tag[0].len, dlg->tag[0].s); } if (dlg->tag[0].len && dlg->tag[1].s ) { LM_DBG("dialog callback: tag[1] = %.*s\n", dlg->tag[1].len, dlg->tag[1].s); } if (_params->msg && _params->msg!=FAKED_REPLY && type != DLGCB_DESTROY) { /* get to tag*/ if ( !_params->msg->to) { /* to header not defined, parse to header */ LM_DBG("to header not defined, parse to header\n"); if (parse_headers(_params->msg, HDR_TO_F,0)<0) { /* parser error */ LM_ERR("parsing of to-header failed\n"); tag.s = 0; tag.len = 0; } else if (!_params->msg->to) { /* to header still not defined */ LM_ERR("no to although to-header is parsed: bad reply " "or missing TO hdr :-/\n"); tag.s = 0; tag.len = 0; } else tag = get_to(_params->msg)->tag_value; } else { tag = get_to(_params->msg)->tag_value; if (tag.s==0 || tag.len==0) { LM_DBG("missing TAG param in TO hdr :-/\n"); tag.s = 0; tag.len = 0; } } if (tag.s) { LM_DBG("dialog callback: _params->msg->to->parsed->tag_value " "= %.*s\n", tag.len, tag.s); } } switch (type) { case DLGCB_FAILED: LM_DBG("dialog callback type 'DLGCB_FAILED' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_CONFIRMED: LM_DBG("dialog callback type 'DLGCB_CONFIRMED' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_REQ_WITHIN: LM_DBG("dialog callback type 'DLGCB_REQ_WITHIN' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_TERMINATED: LM_DBG("dialog callback type 'DLGCB_TERMINATED' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_EXPIRED: LM_DBG("dialog callback type 'DLGCB_EXPIRED' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_EARLY: LM_DBG("dialog callback type 'DLGCB_EARLY' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_RESPONSE_FWDED: LM_DBG("dialog callback type 'DLGCB_RESPONSE_FWDED' received, " "from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_RESPONSE_WITHIN: LM_DBG("dialog callback type 'DLGCB_RESPONSE_WITHIN' received, " "from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_MI_CONTEXT: LM_DBG("dialog callback type 'DLGCB_MI_CONTEXT' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; case DLGCB_DESTROY: LM_DBG("dialog callback type 'DLGCB_DESTROY' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); break; default: LM_DBG("dialog callback type 'unknown' received, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); } }
int is_other_contact_f(struct sip_msg* msg, char* _d, char *_s) { pv_spec_p spec = (pv_spec_p)_s; struct usr_avp *avp = NULL; urecord_t *r = NULL; str ip, contact; str uri, aor; ucontact_t *c; contact_t* ct; int exp, found; udomain_t* ud = (udomain_t*)_d; if (parse_message(msg) < 0) { LM_ERR("unable to parse message\n"); return -2; } if (!ud) { LM_ERR("no location specified\n"); return -2; } /* msg doesn't have contacts */ if (!msg->contact || !(ct = (((contact_body_t*)msg->contact->parsed)->contacts))) return -1; while (ct) { /* if expires is 0 */ calc_contact_expires(msg, ct->expires, &exp); if (exp) break; ct = ct->next; } if (!ct) { LM_DBG("contact has expire 0\n"); return -1; } uri = get_to(msg)->uri; if (extract_aor(&uri, &aor) < 0) { LM_ERR("failed to extract AOR record\n"); return -2; } ul.lock_udomain(ud, &aor); ul.get_urecord(ud, &aor, &r); if (!r) { /* dont't test anything */ LM_DBG("no contact found for aor=<%.*s>\n", aor.len, aor.s); found = -1; goto end; } else { c = r->contacts; } while (c) { if (!c->received.len || !c->received.s || c->received.len < 4 /* sip:*/) { c = c->next; continue; } contact.s = c->received.s + 4; /* check for "sips:" */ if (*contact.s == ':') { contact.len = c->received.len - 5; contact.s++; } else { /* skip "sip:" */ contact.len = c->received.len - 4; } avp = NULL; found = 0; /* the ip should always be a string */ while ((avp = search_first_avp(spec->pvp.pvn.u.isname.type, spec->pvp.pvn.u.isname.name.n, (int_str *)&ip, avp))!=0) { if (!(avp->flags & AVP_VAL_STR)) { LM_NOTICE("avp value should be string\n"); continue; } if ((contact.len == ip.len || (contact.len>ip.len && contact.s[ip.len]==':')) && !memcmp(contact.s, ip.s, ip.len)) { found = 1; break; } } if (!found) { LM_DBG("no contact <%.*s> registered earlier\n", contact.len, contact.s); found = 1; goto end; } c = c->next; } found = -1; end: ul.unlock_udomain(ud, &aor); return found; }
/*Create cell to control Subscriber Dialog States This cell save this information: - Dialog Id: .Callid .rem_tag .local_tag - expires - Local_uri - Remote_uri - Notifier_uri - INVITE's Callid - Event body - State */ int create_subscriber_cell(struct sip_msg* reply, struct parms_cb* params_cb){ str* callid = NULL; int expires= 0; struct to_body *pto= NULL, *pfrom = NULL; int size_subs_cell; int vsp_addr_len; char *vsp_addr = "@vsp.com"; time_t rawtime; int time_now; struct sm_subscriber *subs_cell = NULL; char *p; unsigned int hash_code; callid= (str*) pkg_malloc (sizeof (str)); if (callid == NULL) { LM_ERR("--------------------------------------------------no more pkg memory\n"); return 0; } /*Verify repĺy is OK and get callid and expires from response*/ if ( !extract_reply_headers(reply, callid, expires)){ LM_ERR("fail in extract headers\n"); pkg_free(callid); return 0; } /*get From header fields */ pfrom = get_from(reply); LM_DBG("PFROM: %.*s \n ", pfrom->uri.len, pfrom->uri.s ); if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0){ LM_ERR("reply without tag value \n"); pkg_free(callid); return 0; } /*get To header fields */ pto = get_to(reply); LM_DBG("PTO: %.*s \n ", pto->uri.len, pto->uri.s ); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("failed to parse TO header\n"); pkg_free(callid); return 0; } // get source ip address that send INVITE vsp_addr = ip_addr2a(&reply->rcv.src_ip); vsp_addr_len = strlen(vsp_addr); time(&rawtime); time_now = (int)rawtime; LM_DBG("TIME : %d \n", (int)rawtime ); /* build subscriber cell */ size_subs_cell = sizeof (struct sm_subscriber) + (2 * sizeof(struct dialog_id)) + callid->len + pfrom->tag_value.len + pto->tag_value.len + pfrom->uri.len + pto->uri.len + params_cb->callid_ori.len + params_cb->event.len + params_cb->from_tag.len + vsp_addr_len + 9 ; subs_cell = pkg_malloc(size_subs_cell + 1); if (!subs_cell) { LM_ERR("no more shm\n"); return 0; } memset(subs_cell, 0, size_subs_cell + 1); subs_cell->expires = expires; subs_cell->timeout = TIMER_N + time_now; LM_DBG("SUBS_TIMEOUT: %d \n ", subs_cell->timeout ); subs_cell->version = -1; subs_cell->dlg_id = (struct dialog_id*)(subs_cell + 1); subs_cell->dlg_id->callid.len = callid->len; subs_cell->dlg_id->callid.s = (char *) (subs_cell->dlg_id + 1); memcpy(subs_cell->dlg_id->callid.s, callid->s, callid->len); LM_DBG("SUBS_CALLID: %.*s \n ", subs_cell->dlg_id->callid.len, subs_cell->dlg_id->callid.s ); subs_cell->dlg_id->local_tag.len = pfrom->tag_value.len; subs_cell->dlg_id->local_tag.s = (char *) (subs_cell->dlg_id + 1) + callid->len; memcpy(subs_cell->dlg_id->local_tag.s, pfrom->tag_value.s, pfrom->tag_value.len); LM_DBG("SUBS_FROM_TAG: %.*s \n ", subs_cell->dlg_id->local_tag.len, subs_cell->dlg_id->local_tag.s ); subs_cell->dlg_id->rem_tag.len = pto->tag_value.len; subs_cell->dlg_id->rem_tag.s = (char *) (subs_cell->dlg_id + 1) + callid->len + pfrom->tag_value.len; memcpy(subs_cell->dlg_id->rem_tag.s, pto->tag_value.s, pto->tag_value.len); LM_DBG("SUBS_TO_TAG: %.*s \n ", subs_cell->dlg_id->rem_tag.len, subs_cell->dlg_id->rem_tag.s ); p = (char *)(subs_cell->dlg_id + 1) + callid->len + pfrom->tag_value.len + pto->tag_value.len; subs_cell->call_dlg_id = (struct dialog_id*)p; subs_cell->call_dlg_id->callid.len= params_cb->callid_ori.len; subs_cell->call_dlg_id->callid.s = (char *) (subs_cell->call_dlg_id + 1); memcpy(subs_cell->call_dlg_id->callid.s, params_cb->callid_ori.s, params_cb->callid_ori.len); LM_DBG("SUBS_CALLID_ORI: %.*s \n ", subs_cell->call_dlg_id->callid.len, subs_cell->call_dlg_id->callid.s ); subs_cell->call_dlg_id->local_tag.len= params_cb->from_tag.len; subs_cell->call_dlg_id->local_tag.s = (char *) (subs_cell->call_dlg_id + 1) + params_cb->callid_ori.len; memcpy(subs_cell->call_dlg_id->local_tag.s, params_cb->from_tag.s, params_cb->from_tag.len); LM_DBG("SUBS_FROMTAG_event: %.*s \n ", subs_cell->call_dlg_id->local_tag.len, subs_cell->call_dlg_id->local_tag.s ); subs_cell->loc_uri.len = pfrom->uri.len; subs_cell->loc_uri.s = (char *) (subs_cell->call_dlg_id + 1) + params_cb->callid_ori.len + params_cb->from_tag.len; memcpy(subs_cell->loc_uri.s,pfrom->uri.s,pfrom->uri.len); LM_DBG("SUBS_LOC_URI: %.*s \n ", subs_cell->loc_uri.len, subs_cell->loc_uri.s ); subs_cell->rem_uri.len= pto->uri.len; subs_cell->rem_uri.s = (char *) (subs_cell->call_dlg_id + 1) + params_cb->callid_ori.len + params_cb->from_tag.len + pfrom->uri.len; memcpy(subs_cell->rem_uri.s, pto->uri.s, pto->uri.len); LM_DBG("SUBS_REM_URI: %.*s \n ", subs_cell->rem_uri.len, subs_cell->rem_uri.s ); subs_cell->event.len= params_cb->event.len; subs_cell->event.s = (char *) (subs_cell->call_dlg_id + 1) + params_cb->callid_ori.len + params_cb->from_tag.len + pfrom->uri.len + pto->uri.len; memcpy(subs_cell->event.s, params_cb->event.s, params_cb->event.len); LM_DBG("SUBS_EVENT: %.*s \n ", subs_cell->event.len, subs_cell->event.s ); subs_cell->contact.len = vsp_addr_len + 9; subs_cell->contact.s = (char *) (subs_cell->call_dlg_id + 1) + params_cb->callid_ori.len + params_cb->from_tag.len + pfrom->uri.len + pto->uri.len + params_cb->event.len; memcpy(subs_cell->contact.s, "sip:test@", 9); memcpy(subs_cell->contact.s + 9, vsp_addr, vsp_addr_len); LM_DBG("SUBS_CONTACT: %.*s \n ", subs_cell->contact.len, subs_cell->contact.s ); subs_cell->dlg_id->status = NOTIFY_WAIT; hash_code= core_hash(&subs_cell->dlg_id->callid, 0, subst_size); LM_DBG("********************************************HASH_CODE%d\n", hash_code); if(insert_shtable(subs_htable, hash_code,subs_cell) == NULL){ LM_ERR("inserting new record in subs_htable\n"); } pkg_free(subs_cell); pkg_free(callid); return 1; }
/*! * \brief Function that is registered as TM callback and called on replies * * Function that is registered as TM callback and called on replies. It * parses the reply and set the appropriate event. This is then used to * update the dialog state, run eventual dialog callbacks and save or * update the necessary informations about the dialog. * \see next_state_dlg * \param t transaction, unused * \param type type of the entered callback * \param param saved dialog structure in the callback */ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) { struct dlg_cell *dlg; struct dlg_cell_out *dlg_out = 0; int new_state, old_state, unref, event; str to_tag, to_uri; struct sip_msg *req = param->req; struct sip_msg *rpl = param->rpl; struct dlg_entry_out* dlg_entry_out = 0; if (t && t->fwded_totags) LM_DBG("ONREPLY CALL_BACK from TM received and type is [%i] and TO is [%.*s]\n", type, t->fwded_totags->tag.len, t->fwded_totags->tag.s); else LM_DBG("ONREPLY CALL_BACK from TM received and type is [%i]\n", type); dlg = (struct dlg_cell *) (*param->param); if (shutdown_done || dlg == 0) return; if (t) { dlg->transaction = t; } LM_DBG("DLG dialogid is entry:id [%i:%i]\n", dlg->h_entry, dlg->h_id); if (type == TMCB_RESPONSE_FWDED) { // The state does not change, but the msg is mutable in this callback LM_DBG("TMCB_RESPONSE_FWDED from TM received"); run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); return; } if (type == TMCB_RESPONSE_OUT) { LM_DBG("TMCB_RESPONSE_OUT\n"); return; } if (type == TMCB_RESPONSE_READY) { if (rpl == FAKED_REPLY) { LM_DBG("Faked reply\n"); return; } // get to tag LM_DBG("Extracting to-tag from reply"); if (!rpl->to && ((parse_headers(rpl, HDR_TO_F, 0) < 0) || !rpl->to)) { LM_ERR("bad reply or missing TO hdr :-/\n"); to_tag.s = 0; to_tag.len = 0; } else { //populate to uri for this branch. to_uri = get_to(rpl)->uri; to_tag = get_to(rpl)->tag_value; if (to_tag.s == 0 || to_tag.len == 0) { LM_ERR("missing TAG param in TO hdr :-/\n"); to_tag.s = 0; to_tag.len = 0; //Here we assume that the transaction module timer will remove any early dialogs return; } } LM_DBG("Got to-tag from response: %.*s \n", to_tag.len, to_tag.s); } if (type == TMCB_DESTROY) event = DLG_EVENT_TDEL; else if (param->code < 200) event = DLG_EVENT_RPL1xx; else if (param->code < 300) event = DLG_EVENT_RPL2xx; else event = DLG_EVENT_RPL3xx; LM_DBG("Calling next_state_dlg and event is %i\n", event); next_state_dlg(dlg, event, &old_state, &new_state, &unref, &to_tag); if (type == TMCB_RESPONSE_READY) { LM_DBG("Checking if there is an existing dialog_out entry with same to-tag"); dlg_entry_out = &dlg->dlg_entry_out; lock_get(dlg->dlg_out_entries_lock); dlg_out = dlg_entry_out->first; LM_DBG("Scanning dlg_entry_out list for dlg_out"); while (dlg_out) { //Check if there is an already dialog_out entry with same To-tag if (dlg_out->to_tag.len == to_tag.len && memcmp(dlg_out->to_tag.s, to_tag.s, dlg_out->to_tag.len) == 0) { //Found a dialog_out entry with same to_tag! LM_DBG("Found dlg_out for to-tag: %.*s\n", dlg_out->to_tag.len, dlg_out->to_tag.s); break; } dlg_out = dlg_out->next; } lock_release(dlg->dlg_out_entries_lock); if (!dlg_out) { LM_DBG("No dlg_out entry found - creating a new dialog_out entry on dialog [%p]\n", dlg); dlg_out = build_new_dlg_out(dlg, &to_uri, &to_tag); link_dlg_out(dlg, dlg_out, 0); /* save callee's cseq, caller cseq, callee contact and callee record route*/ if (populate_leg_info(dlg, rpl, t, DLG_CALLEE_LEG, &to_tag) != 0) { LM_ERR("could not add further info to the dlg out\n"); } if (!dlg_out) { LM_ERR("failed to create new dialog out structure\n"); //TODO do something on this error! } } else { //This dlg_out already exists, update cseq and contact if present LM_DBG("dlg_out entry found - updating cseq's for dialog out [%p] for to-tag [%.*s] \n", dlg_out, dlg_out->to_tag.len, dlg_out->to_tag.s); if ((!rpl->cseq && parse_headers(rpl, HDR_CSEQ_F, 0) < 0) || !rpl->cseq || !rpl->cseq->parsed) { LM_ERR("bad sip message or missing CSeq hdr :-/\n"); } dlg_update_cseq(dlg, DLG_CALLEE_LEG, &((get_cseq(rpl))->number), &(dlg_out->to_tag)); /* extract the contact address to update if present*/ if (!rpl->contact && (parse_headers(rpl, HDR_CONTACT_F, 0) < 0 || !rpl->contact)) { LM_ERR("Can not update callee contact: bad sip message or missing Contact hdr\n"); } else if (parse_contact(rpl->contact) < 0 || ((contact_body_t *) rpl->contact->parsed)->contacts == NULL || ((contact_body_t *) rpl->contact->parsed)->contacts->next != NULL) { LM_ERR("Can not update callee contact: bad Contact HDR\n"); } else { str contact; contact = ((contact_body_t *) rpl->contact->parsed)->contacts->uri; dlg_update_contact(dlg, DLG_CALLEE_LEG, &contact, &(dlg_out->to_tag)); } } } if (new_state == DLG_STATE_EARLY) { if ((dlg->dflags & DLG_FLAG_INSERTED) == 0) { dlg->dflags |= DLG_FLAG_NEW; } else { dlg->dflags |= DLG_FLAG_CHANGED; } if (dlg_db_mode == DB_MODE_REALTIME) update_dialog_dbinfo(dlg); run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); return; } LM_DBG("new state is %i and old state is %i\n", new_state, old_state); if ((new_state == DLG_STATE_CONFIRMED) && (event == DLG_EVENT_RPL2xx)) { LM_DBG("dialog %p confirmed \n", dlg); //Remove all the other entries in dialog_out for the same dialog after TM expires the transaction //(not before in order to absorb late in-early-dialog requests). //remove all other dlg_out objects if (dlg_out) { if (d_tmb.register_tmcb(req, NULL, TMCB_DESTROY, unlink_dlgouts_from_cb, (void*) dlg, NULL) < 0) { LM_ERR("failed to register deletion delay function\n"); LM_DBG("Removing all other DLGs"); dlg_remove_dlg_out(dlg_out, dlg, 0); } else { //mark the outs for deletion dlg_remove_dlg_out(dlg_out, dlg, 1); } } else { LM_ERR("There is no dlg_out structure - this is bad\n"); //TODO: add error handling here } /* set start time */ dlg->start_ts = (unsigned int) (time(0)); /* save the settings to the database, * if realtime saving mode configured- save dialog now * else: the next time the timer will fire the update*/ if ((dlg->dflags & DLG_FLAG_INSERTED) == 0) { dlg->dflags |= DLG_FLAG_NEW; } else { dlg->dflags |= DLG_FLAG_CHANGED; } if (dlg_db_mode == DB_MODE_REALTIME) update_dialog_dbinfo(dlg); if (0 != insert_dlg_timer(&dlg->tl, dlg->lifetime)) { LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] " "with clid '%.*s' and tags '%.*s' \n", dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state, dlg->callid.len, dlg->callid.s, dlg->from_tag.len, dlg->from_tag.s); } else { ref_dlg(dlg, 1); } run_dlg_callbacks(DLGCB_CONFIRMED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if (unref) unref_dlg(dlg, unref); return; } if (new_state == DLG_STATE_CONCURRENTLY_CONFIRMED && (old_state == DLG_STATE_CONFIRMED || old_state == DLG_STATE_CONCURRENTLY_CONFIRMED)) { //This is a concurrently confirmed call LM_DBG("This is a concurrently confirmed call."); //Create a new Dialog ID token “X” //Not sure how to do this so just going to use existing Did and add an X character to it str new_did; create_concurrent_did(dlg, &new_did); //assign new did to the created or updated dialog_out entry. update_dlg_out_did(dlg_out, &new_did); //Then, duplicate the dialog_in entry and set its Dialog ID value to new_did //for now rather just create new dlg structure with the correct params - this should be fixed if future use requires struct dlg_cell *new_dlg = 0; new_dlg = build_new_dlg(&(dlg->callid) /*callid*/, &(dlg->from_uri) /*from uri*/, &(dlg->from_tag)/*from_tag*/, &(dlg->req_uri) /*r-uri*/); //assign new did to dlg_in update_dlg_did(new_dlg, &new_did); if (new_dlg == 0) { LM_ERR("failed to create new dialog\n"); return; } //link the new_dlg with dlg_out object link_dlg_out(new_dlg, dlg_out, 0); } if (old_state != DLG_STATE_DELETED && new_state == DLG_STATE_DELETED) { LM_DBG("dialog %p failed (negative reply)\n", dlg); /* dialog setup not completed (3456XX) */ run_dlg_callbacks(DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); /* do unref */ if (unref) unref_dlg(dlg, unref); return; } if (unref) unref_dlg(dlg, unref); return; }
/* builds digest string of msg Return value: 1: success 0: else digestString must point to an array with at least MAX_DIGEST bytes */ static int makeDigestString(char * digestString, char * dateHF, struct sip_msg * msg) { struct to_body * from = NULL; struct to_body * to = NULL; struct cseq_body * cseq = NULL; struct hdr_field * date = NULL; contact_t * contact = NULL; unsigned int l; str tmp; if(!digestString || !msg) { LM_ERR("not all parameters set\n"); return 0; } l = 0; /* ###from### */ if(parse_from_header(msg) != 0) { LM_ERR("error parsing from header\n"); return 0; } from = get_from(msg); if(!from) { LM_ERR("error getting from header\n"); return 0; } if (l+from->uri.len+1>MAX_DIGEST) { LM_ERR("buffer to short 1\n"); return 0; } memcpy( digestString+l, from->uri.s, from->uri.len); l += from->uri.len; *(digestString+(l++)) = '|'; /* ###To### */ to = get_to(msg); if(!to) { LM_ERR("error getting to header\n"); return 0; } if (l+to->uri.len+1>MAX_DIGEST) { LM_ERR("buffer to short 2\n"); return 0; } memcpy( digestString+l, to->uri.s, to->uri.len); l += to->uri.len; *(digestString+(l++)) = '|'; /* ###callid### */ if(!msg->callid) { LM_ERR("error getting callid header\n"); return 0; } if (l+msg->callid->body.len+1>MAX_DIGEST) { LM_ERR("buffer to short 3\n"); return 0; } memcpy( digestString+l, msg->callid->body.s, msg->callid->body.len); l += msg->callid->body.len; *(digestString+(l++)) = '|'; /* ###CSeq### */ cseq = (struct cseq_body *)msg->cseq->parsed; if (!cseq) { LM_ERR("error getting cseq header\n"); return 0; } tmp.s = cseq->number.s; tmp.len = cseq->number.len; /* strip leading zeros */ while((*(tmp.s) == '0') && (tmp.len > 1)) { (tmp.s)++; (tmp.len)--; } if (l+tmp.len+cseq->method.len+2>MAX_DIGEST) { LM_ERR("buffer to short 4\n"); return 0; } memcpy( digestString+l, tmp.s, tmp.len); l += tmp.len; *(digestString+(l++)) = ' '; memcpy( digestString+l, cseq->method.s, cseq->method.len); l += cseq->method.len; *(digestString+(l++)) = '|'; /* ###Date### */ if(!dateHF) { /* Date header field is taken from msg: verifier */ date = get_header_by_static_name(msg,"Date"); if (!date) { LM_ERR("error getting date header\n"); return 0; } tmp = date->body; } else { /* Date header field is taken from dateHF: authentication service */ tmp.s = dateHF; tmp.len = strlen(tmp.s); } if (l+tmp.len+1>MAX_DIGEST) { LM_ERR("buffer to short 5\n"); return 0; } memcpy( digestString+l, tmp.s, tmp.len); l += tmp.len; *(digestString+(l++)) = '|'; /* ###Contact### */ if(msg->contact) { if(parse_contact(msg->contact) != 0) { LM_ERR("error parsing contact header\n"); return 0; } /* first contact in list */ contact = ((contact_body_t *)(msg->contact->parsed))->contacts; tmp = contact->uri; } else { tmp.len = 0; tmp.s = 0; } if (l+tmp.len+1>MAX_DIGEST) { LM_ERR("buffer to short 6\n"); return 0; } if (tmp.len) { memcpy( digestString+l, tmp.s, tmp.len); l += tmp.len; } *(digestString+(l++)) = '|'; /* ###body### */ if ( get_body(msg,&tmp)!=0 ) { LM_ERR("failed to inspect body\n"); return 0; } if (tmp.len != 0) { if (l+tmp.len+1>MAX_DIGEST) { LM_ERR("buffer to short 7\n"); return 0; } memcpy( digestString+l, tmp.s, tmp.len); l += tmp.len; *(digestString+(l++)) = 0; } LM_DBG("Digest-String=>%s<\n", digestString); return 1; }
void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) { struct sip_msg* msg= NULL; int lexpire= 0; unsigned int cseq; ua_pres_t* presentity= NULL, *hentity= NULL; struct to_body *pto= NULL, *pfrom = NULL; int size= 0; int flag ; str record_route= {0, 0}; int rt; str contact; int initial_request = 0; if(ps==NULL || ps->param== NULL || *ps->param== NULL ) { LM_ERR("null callback parameter\n"); return; } LM_DBG("completed with status %d\n",ps->code) ; hentity= (ua_pres_t*)(*ps->param); flag= hentity->flag; if(hentity->flag & XMPP_INITIAL_SUBS) hentity->flag= XMPP_SUBSCRIBE; /* get dialog information from reply message: callid, to_tag, from_tag */ msg= ps->rpl; if(msg == NULL) { LM_ERR("no reply message found\n "); goto error; } if(msg== FAKED_REPLY) { /* delete record from hash_table and call registered functions */ if(hentity->call_id.s== NULL) /* if a new requets failed-> do nothing*/ { LM_DBG("initial Subscribe request failed\n"); goto done; } lock_get(&HashT->p_records[hentity->hash_index].lock); presentity = get_htable_safe(hentity->hash_index, hentity->local_index); if(presentity) { delete_htable_safe(presentity, hentity->hash_index); lock_release(&HashT->p_records[hentity->hash_index].lock); } lock_release(&HashT->p_records[hentity->hash_index].lock); goto done; } if ( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("when parsing headers\n"); goto done; } /*if initial request */ if(hentity->call_id.s== NULL) { initial_request = 1; if(ps->code>= 300) { LM_DBG("initial Subscribe request failed\n"); goto done; } if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); goto done; } if (!msg->from || !msg->from->body.s) { LM_ERR("cannot find 'from' header!\n"); goto done; } if (msg->from->parsed == NULL) { if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); goto done; } } pfrom = (struct to_body*)msg->from->parsed; if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); goto done; } if( msg->to==NULL || msg->to->body.s==NULL) { LM_ERR("cannot parse TO header\n"); goto done; } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("failed to parse TO header\n"); goto done; } if( pto->tag_value.s ==NULL || pto->tag_value.len == 0) { LM_ERR("no to tag value present\n"); goto done; } hentity->call_id= msg->callid->body; hentity->to_tag= pto->tag_value; hentity->from_tag= pfrom->tag_value; } /* extract the other necesary information for inserting a new record */ if(ps->rpl->expires && msg->expires->body.len > 0) { if (!msg->expires->parsed && (parse_expires(msg->expires) < 0)) { LM_ERR("cannot parse Expires header\n"); goto done; } lexpire = ((exp_body_t*)msg->expires->parsed)->val; LM_DBG("lexpire= %d\n", lexpire); } if(ps->code >= 300 ) { /* if an error code and a stored dialog delete it and try to send a subscription with type= INSERT_TYPE, else return*/ if(!initial_request) { subs_info_t subs; lock_get(&HashT->p_records[hentity->hash_index].lock); presentity = get_htable_safe(hentity->hash_index, hentity->local_index); if(presentity) { hentity->event= presentity->event; delete_htable_safe(presentity, hentity->hash_index); lock_release(&HashT->p_records[hentity->hash_index].lock); } lock_release(&HashT->p_records[hentity->hash_index].lock); memset(&subs, 0, sizeof(subs_info_t)); subs.pres_uri= hentity->pres_uri; subs.to_uri = hentity->to_uri; subs.watcher_uri= hentity->watcher_uri; subs.contact= &hentity->contact; if(hentity->remote_contact.s) subs.remote_target= &hentity->remote_contact; if(hentity->desired_expires== 0) subs.expires= -1; else if(hentity->desired_expires< (int)time(NULL)) subs.expires= 0; else subs.expires= hentity->desired_expires- (int)time(NULL)+ 3; subs.flag= INSERT_TYPE; subs.source_flag= flag; subs.event= hentity->event; subs.id= hentity->id; subs.outbound_proxy= hentity->outbound_proxy; subs.extra_headers= &hentity->extra_headers; subs.cb_param= hentity->cb_param; if(send_subscribe(&subs)< 0) { LM_ERR("when trying to send SUBSCRIBE\n"); goto done; } } goto done; } /*if a 2XX reply handle the two cases- an existing dialog and a new one*/ /* extract the contact */ if(msg->contact== NULL || msg->contact->body.s== NULL) { LM_ERR("no contact header found"); goto error; } if( parse_contact(msg->contact) <0 ) { LM_ERR(" cannot parse contact header\n"); goto error; } if(msg->contact->parsed == NULL) { LM_ERR("cannot parse contact header\n"); goto error; } contact = ((contact_body_t* )msg->contact->parsed)->contacts->uri; if(!initial_request) { /* do not delete the dialog - allow Notifies to be recognized as * inside a known dialog */ if (lexpire == 0) lexpire = 5; LM_DBG("*** Update expires\n"); update_htable(hentity->hash_index, hentity->local_index, lexpire, NULL, &contact); goto done; } /* if a new dialog -> insert */ if(lexpire== 0) { LM_DBG("expires= 0: no not insert\n"); goto done; } if( msg->cseq==NULL || msg->cseq->body.s==NULL) { LM_ERR("cannot parse cseq header\n"); goto done; } if( str2int( &(get_cseq(msg)->number), &cseq)< 0) { LM_ERR("while converting str to int\n"); goto done; } /*process record route and add it to a string*/ if (msg->record_route!=NULL) { rt = print_rr_body(msg->record_route, &record_route, 1, 0); if(rt != 0) { LM_ERR("parsing record route [%d]\n", rt); record_route.s=NULL; record_route.len=0; } } size= sizeof(ua_pres_t)+ 2*sizeof(str)+(hentity->pres_uri->len+ pto->uri.len+ pfrom->uri.len+ pto->tag_value.len+ pfrom->tag_value.len +msg->callid->body.len+ record_route.len+ hentity->contact.len+ hentity->id.len )*sizeof(char); presentity= (ua_pres_t*)shm_malloc(size); if(presentity== NULL) { LM_ERR("no more share memory\n"); if(record_route.s) pkg_free(record_route.s); goto done; } memset(presentity, 0, size); size= sizeof(ua_pres_t); presentity->pres_uri= (str*)( (char*)presentity+ size); size+= sizeof(str); presentity->pres_uri->s= (char*)presentity+ size; memcpy(presentity->pres_uri->s, hentity->pres_uri->s, hentity->pres_uri->len); presentity->pres_uri->len= hentity->pres_uri->len; size+= hentity->pres_uri->len; presentity->to_uri.s= (char*)presentity+ size; memcpy(presentity->to_uri.s, pto->uri.s, pto->uri.len); presentity->to_uri.len= pto->uri.len; size+= pto->uri.len; presentity->watcher_uri= (str*)( (char*)presentity+ size); size+= sizeof(str); presentity->watcher_uri->s= (char*)presentity+ size; memcpy(presentity->watcher_uri->s, pfrom->uri.s, pfrom->uri.len); presentity->watcher_uri->len= pfrom->uri.len; size+= pfrom->uri.len; presentity->call_id.s= (char*)presentity + size; memcpy(presentity->call_id.s,msg->callid->body.s, msg->callid->body.len); presentity->call_id.len= msg->callid->body.len; size+= presentity->call_id.len; presentity->to_tag.s= (char*)presentity + size; memcpy(presentity->to_tag.s,pto->tag_value.s, pto->tag_value.len); presentity->to_tag.len= pto->tag_value.len; size+= pto->tag_value.len; presentity->from_tag.s= (char*)presentity + size; memcpy(presentity->from_tag.s,pfrom->tag_value.s, pfrom->tag_value.len); presentity->from_tag.len= pfrom->tag_value.len; size+= pfrom->tag_value.len; if(record_route.len && record_route.s) { presentity->record_route.s= (char*)presentity + size; memcpy(presentity->record_route.s, record_route.s, record_route.len); presentity->record_route.len= record_route.len; size+= record_route.len; pkg_free(record_route.s); } presentity->contact.s= (char*)presentity + size; memcpy(presentity->contact.s, hentity->contact.s, hentity->contact.len); presentity->contact.len= hentity->contact.len; size+= hentity->contact.len; if(hentity->id.s) { presentity->id.s=(char*)presentity+ size; memcpy(presentity->id.s, hentity->id.s, hentity->id.len); presentity->id.len= hentity->id.len; size+= presentity->id.len; } if(hentity->extra_headers.s && hentity->extra_headers.len) { presentity->extra_headers.s= (char*)shm_malloc(hentity->extra_headers.len* sizeof(char)); if(presentity->extra_headers.s== NULL) { ERR_MEM(SHARE_MEM); } memcpy(presentity->extra_headers.s, hentity->extra_headers.s, hentity->extra_headers.len); presentity->extra_headers.len= hentity->extra_headers.len; } /* write the remote contact filed */ presentity->remote_contact.s= (char*)shm_malloc(contact.len* sizeof(char)); if(presentity->remote_contact.s== NULL) { ERR_MEM(SHARE_MEM); } memcpy(presentity->remote_contact.s, contact.s, contact.len); presentity->remote_contact.len= contact.len; presentity->event|= hentity->event; presentity->flag= hentity->flag; presentity->etag.s= NULL; presentity->cseq= cseq; presentity->desired_expires= hentity->desired_expires; presentity->expires= lexpire+ (int)time(NULL); if(BLA_SUBSCRIBE & presentity->flag) { LM_DBG("BLA_SUBSCRIBE FLAG inserted\n"); } LM_DBG("record for subscribe from %.*s to %.*s inserted in datatbase\n", presentity->watcher_uri->len, presentity->watcher_uri->s, presentity->pres_uri->len, presentity->pres_uri->s); insert_htable(presentity); done: if(hentity->ua_flag == REQ_OTHER) { hentity->flag= flag; run_pua_callbacks( hentity, msg); } error: if(hentity) { if(presentity) { if(presentity->extra_headers.s) shm_free(presentity->extra_headers.s); if(presentity->remote_contact.s) shm_free(presentity->remote_contact.s); } shm_free(hentity); hentity= NULL; } return; }
int run_helper_logic(struct sip_msg *msg, void *param) { str totag; str status_404 = str_init("Not Here"); str status_500 = str_init("Server Internal Error"); int rc, seq_request = 0; LM_DBG("running helper logic\n"); if (parse_headers(msg, HDR_TO_F|HDR_CALLID_F, 0) == -1) { LM_ERR("failed to parse To header\n"); return SCB_DROP_MSG; } totag = get_to(msg)->tag_value; /* sequential request */ if (totag.s && totag.len > 0) { seq_request = 1; if (msg->REQ_METHOD == METHOD_INVITE) rr_api.record_route(msg, NULL); /* if not RR_DRIVEN */ if (rr_api.loose_route(msg) < 0) { /* attempt a full dialog search (not the usual quick did lookup) */ if (use_dialog && dlg_api.match_dialog(msg) < 0) LM_ERR("failed to match dialog, ci '%.*s'\n", msg->callid->body.len, msg->callid->body.s); if (msg->REQ_METHOD == METHOD_ACK) { rc = tm_api.t_check_trans(msg, NULL, NULL, NULL, NULL, NULL, NULL); if (rc > 0) tm_api.t_relay(msg, NULL, NULL, NULL, NULL, NULL, NULL); return SCB_RUN_POST_CBS; } sl_api.reply(msg, 404, &status_404); return SCB_RUN_POST_CBS; } } if (msg->REQ_METHOD == METHOD_CANCEL) { seq_request = 1; rc = tm_api.t_check_trans(msg, NULL, NULL, NULL, NULL, NULL, NULL); if (rc > 0) tm_api.t_relay(msg, NULL, NULL, NULL, NULL, NULL, NULL); return SCB_RUN_POST_CBS; } if (tm_api.t_check_trans(msg, NULL, NULL, NULL, NULL, NULL, NULL) == 0) return SCB_RUN_POST_CBS; /** * for sequential requests: * - optionally run a given route * - relay them and do not trigger the request route at all */ if (seq_request) { if (seq_route_id > 0) { LM_DBG("running seq route '%s'\n", seq_route); if (run_top_route(rlist[seq_route_id].a, msg) & ACT_FL_DROP) { LM_DBG("script exited in the seq route\n"); return SCB_RUN_POST_CBS; } } if (tm_api.t_relay(msg, NULL, NULL, NULL, NULL, NULL, NULL) < 0) sl_api.reply(msg, 500, &status_500); return SCB_RUN_POST_CBS; } /* record-routing for initial requests */ if (!(msg->REQ_METHOD & (METHOD_REGISTER|METHOD_MESSAGE))) rr_api.record_route(msg, NULL); if (use_dialog && msg->REQ_METHOD & METHOD_INVITE) dlg_api.create_dlg(msg, create_dialog_flags); return SCB_RUN_ALL; }
/* get data from Subscriber and save in list link with notify information: . dialog id of emergency call . dialog id of subscribe . local uri . remote uri . contact . expires . time to expire subscriber - status . cell next . cell previus */ struct sm_subscriber* build_notify_cell(struct sip_msg *msg, int expires){ char *subs_callid, *subs_fromtag; str callid_event; str fromtag_event; str callid; struct to_body *pto= NULL, *pfrom = NULL; int size_notify_cell; int vsp_addr_len; char *vsp_addr = "@vsp.com"; int vsp_port = 5060; int size_vsp_port = 4; char* str_vsp_port; struct sm_subscriber *notify_cell = NULL; time_t rawtime; int time_now; char *p; unsigned int hash_code; static str msg489={"Bad Event",sizeof("Bad Event")-1}; // get data from SUBSCRIBE request // get callid from Subscribe if( msg->callid==NULL || msg->callid->body.s==NULL){ LM_ERR("subscribe without callid header\n"); return NULL; } callid = msg->callid->body; LM_DBG("CALLID: %.*s \n ", callid.len, callid.s ); //get From header from Subscribe if (msg->from->parsed == NULL){ if ( parse_from_header( msg )<0 ){ LM_ERR("subscribe without From header\n"); return NULL; } } pfrom = get_from(msg); LM_DBG("PFROM: %.*s \n ", pfrom->uri.len, pfrom->uri.s ); LM_DBG("PFROM_TAG: %.*s \n ", pfrom->tag_value.len, pfrom->tag_value.s ); if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0){ LM_ERR("subscribe without from_tag value \n"); return NULL; } if( msg->to==NULL || msg->to->body.s==NULL){ LM_ERR("error in parse TO header\n"); return NULL; } // get To header from Subscribe pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("failed to parse TO header\n"); return NULL; } LM_DBG("PTO: %.*s \n ", pto->uri.len, pto->uri.s ); LM_DBG("PTO_TAG: %.*s \n ", pto->tag_value.len, pto->tag_value.s ); /* get in event header: callid and from_tag */ if(get_event_header(msg, &subs_callid, &subs_fromtag) != 1){ LM_ERR("failed to parse Event header\n"); return NULL; } LM_DBG("SUBS_CALLID: %s\n ", subs_callid); LM_DBG("SUBS_FROMTAG: %s\n ", subs_fromtag); callid_event.s = subs_callid; callid_event.len = strlen(subs_callid); fromtag_event.s = subs_fromtag; fromtag_event.len = strlen(subs_fromtag); hash_code= core_hash(&callid_event, 0, emet_size); LM_DBG("********************************************HASH_CODE%d\n", hash_code); // search call hash with hash_code, callidHeader and from/to_tag params if (search_ehtable(call_htable, subs_callid, subs_fromtag, hash_code, 0) == NULL) { LM_ERR(" ---CALLID NOT FOUND IN SHTABLE\n"); if(!eme_tm.t_reply(msg,489,&msg489)){ LM_DBG("t_reply (489)\n"); } pkg_free(callid_event.s); pkg_free(fromtag_event.s); return 0; } LM_DBG("CALLID OK in subs_hash\n"); time(&rawtime); time_now = (int)rawtime; LM_DBG("TIME : %d \n", (int)rawtime ); // get source ip address that send INVITE vsp_addr = ip_addr2a(&msg->rcv.src_ip); vsp_addr_len = strlen(vsp_addr); vsp_port = msg->rcv.src_port; str_vsp_port= int2str(vsp_port, &size_vsp_port); LM_DBG("SRC_PORT : %s \n", str_vsp_port); /* build notifier cell */ size_notify_cell = sizeof(struct sm_subscriber) + (2 * sizeof(struct dialog_id)) + callid.len + pfrom->tag_value.len + pto->tag_value.len + pfrom->uri.len + pto->uri.len + callid_event.len + fromtag_event.len + vsp_addr_len + size_vsp_port + 11 ; notify_cell = pkg_malloc(size_notify_cell + 1); if (!notify_cell) { LM_ERR("no more shm\n"); return NULL; } memset(notify_cell, 0, size_notify_cell + 1); notify_cell->expires = expires; LM_DBG("EXPIRES: %d \n ", notify_cell->expires ); notify_cell->timeout = TIMER_N + time_now; LM_DBG("SUBS_TIMEOUT: %d \n ", notify_cell->timeout ); notify_cell->version = 0; LM_DBG("SUBS_VERSION: %d \n ", notify_cell->version ); notify_cell->dlg_id = (struct dialog_id*)(notify_cell + 1); notify_cell->dlg_id->callid.len = callid.len; notify_cell->dlg_id->callid.s = (char *) (notify_cell->dlg_id + 1); memcpy(notify_cell->dlg_id->callid.s, callid.s, callid.len); LM_DBG("SUBS_CALLID: %.*s \n ", notify_cell->dlg_id->callid.len, notify_cell->dlg_id->callid.s ); notify_cell->dlg_id->rem_tag.len = pfrom->tag_value.len; notify_cell->dlg_id->rem_tag.s = (char *) (notify_cell->dlg_id + 1) + callid.len; memcpy(notify_cell->dlg_id->rem_tag.s, pfrom->tag_value.s, pfrom->tag_value.len); LM_DBG("SUBS_FROM_TAG: %.*s \n ", notify_cell->dlg_id->rem_tag.len, notify_cell->dlg_id->rem_tag.s ); p = (char *)(notify_cell->dlg_id + 1) + callid.len + pfrom->tag_value.len; notify_cell->call_dlg_id = (struct dialog_id*)p; notify_cell->call_dlg_id->callid.len= callid_event.len; notify_cell->call_dlg_id->callid.s = (char *) (notify_cell->call_dlg_id + 1); memcpy(notify_cell->call_dlg_id->callid.s, callid_event.s, callid_event.len); LM_DBG("SUBS_CALLID_event: %.*s \n ", notify_cell->call_dlg_id->callid.len, notify_cell->call_dlg_id->callid.s ); notify_cell->call_dlg_id->rem_tag.len= fromtag_event.len; notify_cell->call_dlg_id->rem_tag.s = (char *) (notify_cell->call_dlg_id + 1) + callid_event.len; memcpy(notify_cell->call_dlg_id->rem_tag.s, fromtag_event.s, fromtag_event.len); LM_DBG("SUBS_FROMTAG_event: %.*s \n ", notify_cell->call_dlg_id->rem_tag.len, notify_cell->call_dlg_id->rem_tag.s ); notify_cell->loc_uri.len = pto->uri.len; notify_cell->loc_uri.s = (char *) (notify_cell->call_dlg_id + 1) + callid_event.len + fromtag_event.len; memcpy(notify_cell->loc_uri.s,pto->uri.s,pto->uri.len); LM_DBG("SUBS_LOC_URI: %.*s \n ", notify_cell->loc_uri.len, notify_cell->loc_uri.s ); notify_cell->rem_uri.len= pfrom->uri.len; notify_cell->rem_uri.s = (char *) (notify_cell->call_dlg_id + 1) + callid_event.len + fromtag_event.len + pto->uri.len; memcpy(notify_cell->rem_uri.s, pfrom->uri.s, pfrom->uri.len); LM_DBG("SUBS_REM_URI: %.*s \n ", notify_cell->rem_uri.len, notify_cell->rem_uri.s ); notify_cell->contact.len = vsp_addr_len + size_vsp_port +11; notify_cell->contact.s = (char *) (notify_cell->call_dlg_id + 1) + pfrom->uri.len + pto->uri.len + callid_event.len + fromtag_event.len; memcpy(notify_cell->contact.s, "sip:teste@", 10); memcpy(notify_cell->contact.s + 10, vsp_addr, vsp_addr_len); memcpy(notify_cell->contact.s + 10 + vsp_addr_len, ":", 1); memcpy(notify_cell->contact.s + 11 + vsp_addr_len, str_vsp_port, size_vsp_port); LM_DBG("SUBS_CONTACT: %.*s \n ", notify_cell->contact.len, notify_cell->contact.s ); notify_cell->dlg_id->status = RESP_WAIT; pkg_free(callid_event.s); pkg_free(fromtag_event.s); return notify_cell; }
int push_on_network(struct sip_msg *msg, int net) { str body; struct sip_uri uri; struct sms_msg *sms_messg; struct to_body *from; char *p; int len; int mime; /* get the message's body * anyhow we have to call this function, so let's do it at the beginning * to force the parsing of all the headers - like this we avoid separate * calls of parse_headers function for FROM, CONTENT_LENGTH, TO hdrs */ body.s = get_body( msg ); if (body.s==0) { LM_ERR("failed to extract body from msg!\n"); goto error; } /* content-length (if present) must be already parsed */ if (!msg->content_length) { LM_ERR("no Content-Length header found!\n"); goto error; } body.len = get_content_length( msg ); /* parse the content-type header */ if ( (mime=parse_content_type_hdr(msg))<1 ) { LM_ERR("failed to parse Content-Type header\n"); goto error; } /* check the content-type value */ if ( mime!=(TYPE_TEXT<<16)+SUBTYPE_PLAIN && mime!=(TYPE_MESSAGE<<16)+SUBTYPE_CPIM ) { LM_ERR("invalid content-type for a message request! type found=%d\n", mime); goto error; } /* we try to get the user name (phone number) first from the RURI (in our case means from new_uri or from first_line.u.request.uri); if it's missing there (like in requests generated by MSN MESSENGER), we go for "to" header */ LM_DBG("string to get user from new_uri\n"); if ( !msg->new_uri.s||parse_uri( msg->new_uri.s,msg->new_uri.len,&uri) || !uri.user.len ) { LM_DBG("string to get user from R_uri\n"); if ( parse_uri( msg->first_line.u.request.uri.s, msg->first_line.u.request.uri.len ,&uri)||!uri.user.len ) { LM_DBG("string to get user from To\n"); if ( (!msg->to&&((parse_headers(msg,HDR_TO_F,0)==-1) || !msg->to)) || parse_uri( get_to(msg)->uri.s, get_to(msg)->uri.len, &uri)==-1 || !uri.user.len) { LM_ERR("unable to extract user name from RURI and To header!\n"); goto error; } } } /* check the uri.user format = '+(inter code)(number)' */ if (uri.user.len<2 || uri.user.s[0]!='+' || uri.user.s[1]<'1' || uri.user.s[1]>'9') { LM_ERR("user tel number [%.*s] does not respect international format\n" ,uri.user.len,uri.user.s); goto error; } /* parsing from header */ if ( parse_from_header( msg )==-1 ) { LM_ERR("failed to get FROM header\n"); goto error; } from = (struct to_body*)msg->from->parsed; #if 0 /* adds contact header into reply */ if (add_contact(msg,&(uri.user))==-1) { LM_ERR("can't build contact for reply\n"); goto error; } #endif /*-------------BUILD AND FILL THE SMS_MSG STRUCTURE --------------------*/ /* computes the amount of memory needed */ len = SMS_HDR_BF_ADDR_LEN + from->uri.len + SMS_HDR_AF_ADDR_LEN + body.len + SMS_FOOTER_LEN /*text to send*/ + from->uri.len /* from */ + uri.user.len-1 /* to user (without '+') */ + sizeof(struct sms_msg) ; /* the sms_msg structure */ /* allocs a new sms_msg structure in shared memory */ sms_messg = (struct sms_msg*)shm_malloc(len); if (!sms_messg) { LM_ERR("failed to get shm memory!\n"); goto error; } p = (char*)sms_messg + sizeof(struct sms_msg); /* copy "from" into sms struct */ sms_messg->from.len = from->uri.len; sms_messg->from.s = p; append_str(p,from->uri.s,from->uri.len); /* copy "to.user" - we have to strip out the '+' */ sms_messg->to.len = uri.user.len-1; sms_messg->to.s = p; append_str(p,uri.user.s+1,sms_messg->to.len); /* copy (and composing) sms body */ sms_messg->text.len = SMS_HDR_BF_ADDR_LEN + sms_messg->from.len + SMS_HDR_AF_ADDR_LEN + body.len+SMS_FOOTER_LEN; sms_messg->text.s = p; append_str(p, SMS_HDR_BF_ADDR, SMS_HDR_BF_ADDR_LEN); append_str(p, sms_messg->from.s, sms_messg->from.len); append_str(p, SMS_HDR_AF_ADDR, SMS_HDR_AF_ADDR_LEN); append_str(p, body.s, body.len); append_str(p, SMS_FOOTER, SMS_FOOTER_LEN); if (*queued_msgs>MAX_QUEUED_MESSAGES) goto error; (*queued_msgs)++; if (write(net_pipes_in[net], &sms_messg, sizeof(sms_messg))!= sizeof(sms_messg) ) { LM_ERR("error when writing for net %d to pipe [%d] : %s\n", net,net_pipes_in[net],strerror(errno) ); shm_free(sms_messg); (*queued_msgs)--; goto error; } return 1; error: return -1; }
/* returns: 0/1 (false/true) or -1 on error, -127 EXPR_DROP */ static int eval_elem(struct expr* e, struct sip_msg* msg) { struct sip_uri uri; int ret; ret=E_BUG; if (e->type!=ELEM_T){ LOG(L_CRIT," BUG: eval_elem: invalid type\n"); goto error; } switch(e->l.operand){ case METHOD_O: ret=comp_strstr(&msg->first_line.u.request.method, e->r.param, e->op, e->subtype); break; case URI_O: if(msg->new_uri.s){ if (e->subtype==MYSELF_ST){ if (parse_sip_msg_uri(msg)<0) ret=-1; else ret=check_self_op(e->op, &msg->parsed_uri.host, msg->parsed_uri.port_no? msg->parsed_uri.port_no:SIP_PORT); }else{ ret=comp_strstr(&msg->new_uri, e->r.param, e->op, e->subtype); } }else{ if (e->subtype==MYSELF_ST){ if (parse_sip_msg_uri(msg)<0) ret=-1; else ret=check_self_op(e->op, &msg->parsed_uri.host, msg->parsed_uri.port_no? msg->parsed_uri.port_no:SIP_PORT); }else{ ret=comp_strstr(&msg->first_line.u.request.uri, e->r.param, e->op, e->subtype); } } break; case FROM_URI_O: if (parse_from_header(msg)!=0){ LOG(L_ERR, "ERROR: eval_elem: bad or missing" " From: header\n"); goto error; } if (e->subtype==MYSELF_ST){ if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len, &uri) < 0){ LOG(L_ERR, "ERROR: eval_elem: bad uri in From:\n"); goto error; } ret=check_self_op(e->op, &uri.host, uri.port_no?uri.port_no:SIP_PORT); }else{ ret=comp_strstr(&get_from(msg)->uri, e->r.param, e->op, e->subtype); } break; case TO_URI_O: if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) || (msg->to==0))){ LOG(L_ERR, "ERROR: eval_elem: bad or missing" " To: header\n"); goto error; } /* to content is parsed automatically */ if (e->subtype==MYSELF_ST){ if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len, &uri) < 0){ LOG(L_ERR, "ERROR: eval_elem: bad uri in To:\n"); goto error; } ret=check_self_op(e->op, &uri.host, uri.port_no?uri.port_no:SIP_PORT); }else{ ret=comp_strstr(&get_to(msg)->uri, e->r.param, e->op, e->subtype); } break; case SRCIP_O: ret=comp_ip(&msg->rcv.src_ip, e->r.param, e->op, e->subtype); break; case DSTIP_O: ret=comp_ip(&msg->rcv.dst_ip, e->r.param, e->op, e->subtype); break; case NUMBER_O: ret=!(!e->r.intval); /* !! to transform it in {0,1} */ break; case ACTION_O: ret=run_action_list( (struct action*)e->r.param, msg); if (ret<=0) ret=(ret==0)?EXPR_DROP:0; else ret=1; break; case SRCPORT_O: ret=comp_no(msg->rcv.src_port, e->r.param, /* e.g., 5060 */ e->op, /* e.g. == */ e->subtype /* 5060 is number */); break; case DSTPORT_O: ret=comp_no(msg->rcv.dst_port, e->r.param, e->op, e->subtype); break; case PROTO_O: ret=comp_no(msg->rcv.proto, e->r.param, e->op, e->subtype); break; case AF_O: ret=comp_no(msg->rcv.src_ip.af, e->r.param, e->op, e->subtype); break; case RETCODE_O: ret=comp_no(return_code, e->r.param, e->op, e->subtype); break; case MSGLEN_O: ret=comp_no(msg->len, e->r.param, e->op, e->subtype); break; default: LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n", e->l.operand); } return ret; error: return -1; }
int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri) { contact_t* c; int st, mode; str aor; int ret; sip_uri_t *u; rr_t *route; struct sip_uri puri; param_hooks_t hooks; param_t *params; contact_t *contact; int use_ob = 1, use_regid = 1; u = parse_to_uri(_m); if(u==NULL) goto error; rerrno = R_FINE; ret = 1; if (parse_message(_m) < 0) { goto error; } if (check_contacts(_m, &st) > 0) { goto error; } if (parse_supported(_m) == 0) { if (!(get_supported(_m) & F_OPTION_TAG_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_REQUIRE) { LM_WARN("Outbound required by server and not supported by UAC\n"); rerrno = R_OB_UNSUP; goto error; } } if (parse_require(_m) == 0) { if ((get_require(_m) & F_OPTION_TAG_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_NONE) { LM_WARN("Outbound required by UAC and not supported by server\n"); rerrno = R_OB_REQD; goto error; } } if (reg_outbound_mode != REG_OUTBOUND_NONE && _m->contact && _m->contact->parsed && !(parse_headers(_m, HDR_VIA2_F, 0) == -1 || _m->via2 == 0 || _m->via2->error != PARSE_OK)) { /* Outbound supported on server, and more than one Via: - not the first hop */ if (!(parse_headers(_m, HDR_PATH_F, 0) == -1 || _m->path == 0)) { route = (rr_t *)0; if (parse_rr_body(_m->path->body.s, _m->path->body.len, &route) < 0) { LM_ERR("Failed to parse Path: header body\n"); goto error; } if (parse_uri(route->nameaddr.uri.s, route->nameaddr.uri.len, &puri) < 0) { LM_ERR("Failed to parse Path: URI\n"); goto error; } if (parse_params(&puri.params, CLASS_URI, &hooks, ¶ms) != 0) { LM_ERR("Failed to parse Path: URI parameters\n"); goto error; } if (!hooks.uri.ob) { /* No ;ob parameter to top Path: URI - no outbound */ use_ob = 0; } } else { /* No Path: header - no outbound */ use_ob = 0; } contact = ((contact_body_t *) _m->contact->parsed)->contacts; if (!contact) { LM_ERR("empty Contact:\n"); goto error; } if ((use_ob == 0) && (reg_regid_mode == REG_REGID_OUTBOUND)) { if ((get_supported(_m) & F_OPTION_TAG_OUTBOUND) && contact->reg_id) { LM_WARN("Outbound used by UAC but not supported by edge proxy\n"); rerrno = R_OB_UNSUP_EDGE; goto error; } else { /* ignore ;reg-id parameter */ use_regid = 0; } } } get_act_time(); c = get_first_contact(_m); if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor, NULL) < 0) { LM_ERR("failed to extract Address Of Record\n"); goto error; } mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE; if (c == 0) { if (st) { if (star(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error; else ret=3; } else { if (no_contacts(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error; else ret=4; } } else { mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0; if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode, use_regid)) < 0) goto error; ret = (ret==0)?1:ret; } update_stat(accepted_registrations, 1); /* Only send reply upon request, not upon reply */ if ((is_route_type(REQUEST_ROUTE) || is_route_type(FAILURE_ROUTE)) && !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0)) return -1; return ret; error: update_stat(rejected_registrations, 1); if (is_route_type(REQUEST_ROUTE) && !is_cflag_set(REG_SAVE_NORPL_FL) ) reg_send_reply(_m); return 0; }
/** * sngtc_offer - will remove the SDP body of an early negotiation INVITE and * store it in the newly created dialog as a dlg_val. * * @return: 1 on success, negative on failure */ static int sngtc_offer(struct sip_msg *msg) { struct hdr_field *hf; struct lump *lump; struct dlg_cell *dlg; struct sngtc_info *info = NULL; str body, totag, st; if (dlg_binds.create_dlg(msg, 0) < 0) { LM_ERR("failed to create dialog\n"); return SNGTC_ERR; } dlg = dlg_binds.get_dlg(); if (!dlg) { LM_ERR("failed to fetch current dialog\n"); return SNGTC_ERR; } if (get_body(msg, &body) != 0 || body.len <= 0) { LM_ERR("can only do transcoding for early negotiation INVITES\n"); return SNGTC_SDP_ERR; } totag = get_to(msg)->tag_value; /* INVITE retransmissions will skip this part */ if (dlg_binds.fetch_dlg_value(dlg, &dlg_key_sngtc_info, &st, 0) != 0) { if (store_sngtc_info(dlg, &body) != 0) { LM_ERR("failed to create sngtc info struct\n"); return SNGTC_ERR; } /* register a callback to free the above */ if (dlg_binds.register_dlgcb(dlg, DLGCB_EXPIRED|DLGCB_FAILED|DLGCB_TERMINATED, sngtc_dlg_terminated, NULL, NULL) != 0) { LM_ERR("failed to register dialog callback\n"); return SNGTC_ERR; } /* for re-INVITES, just recreate the struct sngtc_info */ } else if (totag.s && totag.len != 0) { info = *(struct sngtc_info **)(st.s); free_transcoding_sessions(info->sessions); if (info->caller_sdp.s) shm_free(info->caller_sdp.s); if (info->modified_caller_sdp.s) shm_free(info->modified_caller_sdp.s); if (store_sngtc_info(dlg, &body) != 0) { LM_ERR("failed to create sngtc info struct\n"); return SNGTC_ERR; } shm_free(info); } LM_DBG("SDP body:\n"); LM_DBG("%.*s\n", body.len, body.s); hf = msg->content_type; /* delete the Content-Type header, we're setting up late negotiation */ lump = del_lump(msg, hf->name.s - msg->buf, hf->len, HDR_OTHER_T); if (!lump) { LM_ERR("no more pkg mem\n"); return SNGTC_ERR; } /* trim the entire SDP body */ lump = del_lump(msg, body.s - msg->buf, body.len, HDR_OTHER_T); if (!lump) { LM_ERR("no more pkg mem\n"); return SNGTC_ERR; } return 1; }
int dialoginfo_set(struct sip_msg* msg, char* flag_pv, char* str2) { struct dlg_cell * dlg; str peer_uri= {0, 0}; /* constructed from TO display name and RURI */ struct to_body* from, peer_to_body, FROM, *to; str* ruri; int len =0,ret=-1; char flag= DLG_PUB_AB; static char buf[256]; int buf_len= 255; str flag_str; char caller_buf[256], callee_buf[256]; pv_value_t tok; peer_to_body.param_lst = FROM.param_lst = NULL; if (msg->REQ_METHOD != METHOD_INVITE) return 1; if(dlg_api.create_dlg(msg,0)< 0) { LM_ERR("Failed to create dialog\n"); return -1; } dlg = dlg_api.get_dlg(); LM_DBG("new INVITE dialog created: from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); from = get_from(msg); /* if defined overwrite */ if(caller_spec_param.s) /* if parameter defined */ { memset(&tok, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, &caller_spec, &tok) < 0) /* if value set */ { LM_ERR("Failed to get caller value\n"); return -1; } if(tok.flags&PV_VAL_STR) { str caller_str; if(tok.rs.len + CRLF_LEN > buf_len) { LM_ERR("Buffer overflow"); return -1; } trim(&tok.rs); memcpy(caller_buf, tok.rs.s, tok.rs.len); len = tok.rs.len; if(strncmp(tok.rs.s+len-CRLF_LEN, CRLF, CRLF_LEN)) { memcpy(caller_buf + len, CRLF, CRLF_LEN); len+= CRLF_LEN; } parse_to(caller_buf, caller_buf+len , &FROM); if(FROM.error != PARSE_OK) { LM_ERR("Failed to parse caller specification - not a valid uri\n"); goto end; } from = &FROM; caller_str.s = caller_buf; caller_str.len = len; LM_DBG("caller: %*s- len= %d\n", len, caller_buf, len); /* store caller in a dlg variable */ if(dlg_api.store_dlg_value(dlg, &entity_dlg_var, &caller_str)< 0) { LM_ERR("Failed to store dialog ruri\n"); goto end; } } } peer_uri.s = callee_buf; if(callee_spec_param.s) { memset(&tok, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, &callee_spec, &tok) < 0) { LM_ERR("Failed to get callee value\n"); goto end; } if(tok.flags&PV_VAL_STR) { if(tok.rs.len + CRLF_LEN > buf_len) { LM_ERR("Buffer overflow"); goto end; } trim(&tok.rs); memcpy(peer_uri.s, tok.rs.s, tok.rs.len); len = tok.rs.len; if(strncmp(tok.rs.s+len-CRLF_LEN, CRLF, CRLF_LEN)) { memcpy(peer_uri.s + len, CRLF, CRLF_LEN); len+= CRLF_LEN; } peer_uri.len = len; } else goto default_callee; } else { default_callee: ruri = GET_RURI(msg); to = get_to(msg); len= to->display.len + 2 + ruri->len + CRLF_LEN; if(len > buf_len) { LM_ERR("Buffer overflow\n"); goto end; } len = 0; if(to->display.len && to->display.s) { memcpy(peer_uri.s, to->display.s, to->display.len); peer_uri.s[to->display.len]='<'; len = to->display.len + 1; } memcpy(peer_uri.s + len, ruri->s, ruri->len); len+= ruri->len; if(to->display.len) { peer_uri.s[len++]='>'; } memcpy(peer_uri.s + len, CRLF, CRLF_LEN); len+= CRLF_LEN; peer_uri.len = len; } LM_DBG("Peer uri = %.*s\n", peer_uri.len, peer_uri.s); parse_to(peer_uri.s, peer_uri.s+peer_uri.len, &peer_to_body); if(peer_to_body.error != PARSE_OK) { LM_ERR("Failed to peer uri [%.*s]\n", peer_uri.len, peer_uri.s); goto end; } /* store peer uri in dialog structure */ if(dlg_api.store_dlg_value(dlg, &peer_dlg_var, &peer_uri)< 0) { LM_ERR("Failed to store dialog ruri\n"); goto end; } /* store flag, if defined */ if(flag_pv) { if(pv_printf(msg, (pv_elem_t*)flag_pv, buf, &buf_len)<0) { LM_ERR("cannot print the format\n"); goto end; } if(!check_flag(buf, buf_len)) { LM_ERR("Wrong value for flag\n"); goto end; } flag = buf[0]; flag_str.s = buf; flag_str.len = buf_len; if(dlg_api.store_dlg_value(dlg, &flag_dlg_var, &flag_str)< 0) { LM_ERR("Failed to store dialog ruri\n"); goto end; } } /* register dialog callbacks which triggers sending PUBLISH */ if (dlg_api.register_dlgcb(dlg, DLGCB_FAILED| DLGCB_CONFIRMED | DLGCB_TERMINATED | DLGCB_EXPIRED | DLGCB_RESPONSE_WITHIN | DLGCB_EARLY, __dialog_sendpublish, 0, 0) != 0) { LM_ERR("cannot register callback for interesting dialog types\n"); goto end; } #ifdef PUA_DIALOGINFO_DEBUG /* dialog callback testing (registered last to be executed first) */ if (dlg_api.register_dlgcb(dlg, DLGCB_FAILED| DLGCB_CONFIRMED | DLGCB_REQ_WITHIN | DLGCB_TERMINATED | DLGCB_EXPIRED | DLGCB_EARLY | DLGCB_RESPONSE_FWDED | DLGCB_RESPONSE_WITHIN | DLGCB_MI_CONTEXT | DLGCB_DESTROY, __dialog_cbtest, NULL, NULL) != 0) { LM_ERR("cannot register callback for all dialog types\n"); goto end; } #endif if(publish_on_trying) { if(flag == DLG_PUB_A || flag == DLG_PUB_AB) dialog_publish("trying", from, &peer_to_body, &(dlg->callid), 1, DEFAULT_CREATED_LIFETIME, 0, 0); if(flag == DLG_PUB_B || flag == DLG_PUB_AB) dialog_publish("trying", &peer_to_body, from, &(dlg->callid), 0, DEFAULT_CREATED_LIFETIME, 0, 0); } ret=1; end: if (peer_to_body.param_lst) free_to_params(&peer_to_body); if (FROM.param_lst) free_to_params(&FROM); return ret; }
static void __dialog_sendpublish(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { str tag = {0,0}; struct to_body from; str peer_uri= {0, 0}; char flag = DLG_PUB_AB; str flag_str; struct to_body peer_to_body; str entity_uri= {0, 0}; int buf_len = 255; struct sip_msg* msg = _params->msg; flag_str.s = &flag; flag_str.len = 1; memset(&from, 0, sizeof(struct to_body)); memset(&peer_to_body, 0, sizeof(struct to_body)); from.uri = dlg->from_uri; peer_uri.len = buf_len; peer_uri.s = (char*)pkg_malloc(buf_len); if(peer_uri.s == NULL) { LM_ERR("No more memory\n"); goto error; } /* extract the peer_uri */ if(dlg_api.fetch_dlg_value(dlg, &peer_dlg_var, &peer_uri, 1) < 0 || peer_uri.len==0) { LM_ERR("Failed to fetch peer uri dialog variable\n"); goto error; } LM_DBG("peer_uri = %.*s\n", peer_uri.len, peer_uri.s); parse_to(peer_uri.s, peer_uri.s+peer_uri.len, &peer_to_body); if(peer_to_body.error != PARSE_OK) { LM_ERR("Failed to peer uri [%.*s]\n", peer_uri.len, peer_uri.s); goto error; } /* try to extract the flag */ dlg_api.fetch_dlg_value(dlg, &flag_dlg_var, &flag_str, 1); LM_DBG("flag = %c\n", flag); entity_uri.len = buf_len; entity_uri.s = (char*)pkg_malloc(buf_len); if(entity_uri.s == NULL) { LM_ERR("No more memory\n"); goto error; } /* check if entity is also custom */ if(dlg_api.fetch_dlg_value(dlg, &entity_dlg_var, &entity_uri, 1) == 0) { /* overwrite from with this value */ parse_to(entity_uri.s, entity_uri.s + entity_uri.len, &from); if(from.error != PARSE_OK) { LM_ERR("Wrong format for entity body\n"); goto error; } LM_DBG("entity_uri = %.*s\n", entity_uri.len, entity_uri.s); LM_DBG("from uri = %.*s\n", from.uri.len, from.uri.s); } switch (type) { case DLGCB_FAILED: case DLGCB_TERMINATED: case DLGCB_EXPIRED: LM_DBG("dialog over, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); if(flag == DLG_PUB_AB || flag == DLG_PUB_A) dialog_publish("terminated", &from, &peer_to_body, &(dlg->callid), 1, 0, 0, 0); if(flag == DLG_PUB_AB || flag == DLG_PUB_B) dialog_publish("terminated", &peer_to_body, &from, &(dlg->callid), 0, 0, 0, 0); break; case DLGCB_RESPONSE_WITHIN: if (get_cseq(msg)->method_id==METHOD_INVITE) { if (msg->flags & nopublish_flag) { LM_DBG("nopublish flag was set for this INVITE\n"); break; } LM_DBG("nopublish flag not set for this INVITE, will publish\n"); } else { /* no publish for non-INVITEs */ break; } case DLGCB_CONFIRMED: LM_DBG("dialog confirmed, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); if(flag == DLG_PUB_AB || flag == DLG_PUB_A) dialog_publish("confirmed", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, 0, 0); if(flag == DLG_PUB_AB || flag == DLG_PUB_B) dialog_publish("confirmed", &peer_to_body, &from, &(dlg->callid), 0, dlg->lifetime, 0, 0); break; case DLGCB_EARLY: LM_DBG("dialog is early, from=%.*s\n", from.uri.len, from.uri.s); if (include_tags) { /* get to tag*/ if ( !_params->msg->to && ((parse_headers(_params->msg, HDR_TO_F,0)<0) || !_params->msg->to) ) { LM_ERR("bad reply or missing TO hdr :-/\n"); tag.s = 0; tag.len = 0; } else { tag = get_to(_params->msg)->tag_value; if (tag.s==0 || tag.len==0) { LM_ERR("missing TAG param in TO hdr :-/\n"); tag.s = 0; tag.len = 0; } } if(flag == DLG_PUB_AB || flag == DLG_PUB_A) { if (caller_confirmed) { dialog_publish("confirmed", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, &(dlg->legs[DLG_CALLER_LEG].tag), &tag); } else { dialog_publish("early", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, &(dlg->legs[DLG_CALLER_LEG].tag), &tag); } } if(flag == DLG_PUB_AB || flag == DLG_PUB_B) { dialog_publish("early", &peer_to_body, &from, &(dlg->callid), 0, dlg->lifetime, &tag, &(dlg->legs[DLG_CALLER_LEG].tag)); } } else { if(flag == DLG_PUB_AB || flag == DLG_PUB_A) { if (caller_confirmed) { dialog_publish("confirmed", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, 0, 0); } else { dialog_publish("early", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, 0, 0); } } if(flag == DLG_PUB_AB || flag == DLG_PUB_B) { dialog_publish("early", &peer_to_body, &from, &(dlg->callid), 0, dlg->lifetime, 0, 0); } } break; default: LM_ERR("unhandled dialog callback type %d received, from=%.*s\n", type, dlg->from_uri.len, dlg->from_uri.s); if(flag == DLG_PUB_AB || flag == DLG_PUB_A) dialog_publish("terminated", &from, &peer_to_body, &(dlg->callid), 1, 0, 0, 0); if(flag == DLG_PUB_AB || flag == DLG_PUB_B) dialog_publish("terminated", &peer_to_body, &from, &(dlg->callid), 0, 0, 0, 0); } error: if(peer_uri.s) pkg_free(peer_uri.s); if(entity_uri.s) pkg_free(entity_uri.s); if (peer_to_body.param_lst) free_to_params(&peer_to_body); if (from.param_lst) free_to_params(&from); }
/*Create cell to control Subscriber Dialog States This cell save this information: - Dialog Id: .Callid .to_tag .from_tag - expires - Local_uri - Remote_uri - Notifier_uri - INVITE's Callid - Event body - State */ int create_subscriber_cell(struct sip_msg* reply, struct parms_cb* params_cb){ str* callid = NULL; int expires= 0; struct to_body *pto= NULL, *pfrom = NULL; int size_subs_cell; struct sm_subscriber *new_cell = NULL; int vsp_addr_len; char *vsp_addr = "@vsp.com"; time_t rawtime; int time_now; struct sm_subscriber *subs_cell = NULL; callid= (str*) pkg_malloc (sizeof (str)); if (callid == NULL) { LM_ERR("--------------------------------------------------no more pkg memory\n"); return 0; } /*Verify repĺy is OK and get callid and expires from response*/ if ( !extract_reply_headers(reply, callid, expires)){ LM_ERR("fail in extract headers\n"); return 0; } /*get From header fields */ pfrom = get_from(reply); LM_INFO("PFROM: %.*s \n ", pfrom->uri.len, pfrom->uri.s ); if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0){ LM_ERR("reply without tag value \n"); return 0; } /*get To header fields */ pto = get_to(reply); LM_INFO("PTO: %.*s \n ", pto->uri.len, pto->uri.s ); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("failed to parse TO header\n"); return 0; } // get source ip address that send INVITE vsp_addr = ip_addr2a(&reply->rcv.src_ip); vsp_addr_len = strlen(vsp_addr); time(&rawtime); time_now = (int)rawtime; LM_INFO("TIME : %d \n", (int)rawtime ); /* build subscriber cell */ size_subs_cell = sizeof (struct sm_subscriber) + callid->len + pfrom->tag_value.len + pto->tag_value.len + pfrom->uri.len + pto->uri.len + params_cb->callid_ori.len + params_cb->event.len + vsp_addr_len + 10 ; subs_cell = shm_malloc(size_subs_cell + 1); if (!subs_cell) { LM_ERR("no more shm\n"); return 0; } memset(subs_cell, 0, size_subs_cell + 1); subs_cell->expires = expires; subs_cell->timeout = TIMER_B + time_now; LM_INFO("SUBS_TIMEOUT: %d \n ", subs_cell->timeout ); subs_cell->dlg_id.callid.len = callid->len; subs_cell->dlg_id.callid.s = (char *) (subs_cell + 1); memcpy(subs_cell->dlg_id.callid.s, callid->s, callid->len); LM_INFO("SUBS_CALLID: %.*s \n ", subs_cell->dlg_id.callid.len, subs_cell->dlg_id.callid.s ); subs_cell->dlg_id.from_tag.len = pfrom->tag_value.len; subs_cell->dlg_id.from_tag.s = (char *) (subs_cell + 1) + callid->len; memcpy(subs_cell->dlg_id.from_tag.s, pfrom->tag_value.s, pfrom->tag_value.len); LM_INFO("SUBS_FROM_TAG: %.*s \n ", subs_cell->dlg_id.from_tag.len, subs_cell->dlg_id.from_tag.s ); subs_cell->dlg_id.to_tag.len = pto->tag_value.len; subs_cell->dlg_id.to_tag.s = (char *) (subs_cell + 1) + callid->len + pfrom->tag_value.len; memcpy(subs_cell->dlg_id.to_tag.s, pto->tag_value.s, pto->tag_value.len); LM_INFO("SUBS_TO_TAG: %.*s \n ", subs_cell->dlg_id.to_tag.len, subs_cell->dlg_id.to_tag.s ); subs_cell->loc_uri.len = pfrom->uri.len; subs_cell->loc_uri.s = (char *) (subs_cell + 1) + callid->len + pfrom->tag_value.len + pto->tag_value.len; memcpy(subs_cell->loc_uri.s,pfrom->uri.s,pfrom->uri.len); LM_INFO("SUBS_LOC_URI: %.*s \n ", subs_cell->loc_uri.len, subs_cell->loc_uri.s ); subs_cell->rem_uri.len= pto->uri.len; subs_cell->rem_uri.s = (char *) (subs_cell + 1) + callid->len + pfrom->tag_value.len + pfrom->uri.len + pto->tag_value.len; memcpy(subs_cell->rem_uri.s, pto->uri.s, pto->uri.len); LM_INFO("SUBS_REM_URI: %.*s \n ", subs_cell->rem_uri.len, subs_cell->rem_uri.s ); subs_cell->callid_ori.len= params_cb->callid_ori.len; subs_cell->callid_ori.s = (char *) (subs_cell + 1) + callid->len + pfrom->tag_value.len + pfrom->uri.len + pto->tag_value.len + pto->uri.len; memcpy(subs_cell->callid_ori.s, params_cb->callid_ori.s, params_cb->callid_ori.len); LM_INFO("SUBS_CALLID_ORI: %.*s \n ", subs_cell->callid_ori.len, subs_cell->callid_ori.s ); subs_cell->event.len= params_cb->event.len; subs_cell->event.s = (char *) (subs_cell + 1) + callid->len + pfrom->tag_value.len + pfrom->uri.len + pto->tag_value.len + pto->uri.len + params_cb->callid_ori.len; memcpy(subs_cell->event.s, params_cb->event.s, params_cb->event.len); LM_INFO("SUBS_EVENT: %.*s \n ", subs_cell->event.len, subs_cell->event.s ); subs_cell->contact.len = vsp_addr_len + 10; subs_cell->contact.s = (char *) (subs_cell + 1) + callid->len + pfrom->tag_value.len + pfrom->uri.len + pto->tag_value.len + pto->uri.len + params_cb->callid_ori.len + params_cb->event.len; memcpy(subs_cell->contact.s, "sip:teste@", 10); memcpy(subs_cell->contact.s + 10, vsp_addr, vsp_addr_len); LM_INFO("SUBS_CONTACT: %.*s \n ", subs_cell->contact.len, subs_cell->contact.s ); subs_cell -> status = NOTIFY_WAIT; /* push cell in Subscriber list linked */ if (new_cell != NULL) { new_cell->next = subs_cell; new_cell = subs_cell; } else { new_cell = subs_cell; *subs_pt = new_cell; } pkg_free(callid); return 1; }
/*! * \brief Function that is registered as RR callback for dialog tracking * * Function that is registered as RR callback for dialog tracking. It * sets the appropriate events after the SIP method and run the state * machine to update the dialog state. It updates then the saved * dialogs and also the statistics. * \param req SIP request * \param route_params record-route parameter * \param param unused */ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) { dlg_cell_t *dlg; dlg_iuid_t *iuid; str val, callid, ftag, ttag; int h_entry, h_id, new_state, old_state, unref, event, timeout, reset; unsigned int dir; int ret = 0; dlg = dlg_get_ctx_dialog(); if (dlg!=NULL) { dlg_release(dlg); return; } /* skip initial requests - they may end up here because of the * preloaded route */ if ( (!req->to && parse_headers(req, HDR_TO_F,0)<0) || !req->to ) { LM_ERR("bad request or missing TO hdr :-/\n"); return; } if ( get_to(req)->tag_value.len==0 ) return; dlg = 0; dir = DLG_DIR_NONE; if ( seq_match_mode!=SEQ_MATCH_NO_ID ) { if( d_rrb.get_route_param( req, &rr_param, &val)!=0) { LM_DBG("Route param '%.*s' not found\n", rr_param.len,rr_param.s); if (seq_match_mode==SEQ_MATCH_STRICT_ID ) return; } else { LM_DBG("route param is '%.*s' (len=%d)\n",val.len,val.s,val.len); if ( parse_dlg_rr_param( val.s, val.s+val.len, &h_entry, &h_id)<0 ) return; dlg = dlg_lookup(h_entry, h_id); if (dlg==0) { LM_WARN("unable to find dialog for %.*s " "with route param '%.*s' [%u:%u]\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s, val.len,val.s, h_entry, h_id); if (seq_match_mode==SEQ_MATCH_STRICT_ID ) return; } else { if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0) { // lookup_dlg has incremented the ref count by 1 dlg_release(dlg); return; } if (match_dialog( dlg, &callid, &ftag, &ttag, &dir )==0) { LM_WARN("tight matching failed for %.*s with callid='%.*s'/%d, " "ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s, callid.len, callid.s, callid.len, ftag.len, ftag.s, ftag.len, ttag.len, ttag.s, ttag.len, dir); LM_WARN("dialog identification elements are callid='%.*s'/%d, " "caller tag='%.*s'/%d, callee tag='%.*s'/%d\n", dlg->callid.len, dlg->callid.s, dlg->callid.len, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s, dlg->tag[DLG_CALLEE_LEG].len); // lookup_dlg has incremented the ref count by 1 dlg_release(dlg); // Reset variables in order to do a lookup based on SIP-Elements. dlg = 0; dir = DLG_DIR_NONE; if (seq_match_mode==SEQ_MATCH_STRICT_ID ) return; } } } } if (dlg==0) { if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0) return; /* TODO - try to use the RR dir detection to speed up here the * search -bogdan */ dlg = get_dlg(&callid, &ftag, &ttag, &dir); if (dlg==0){ LM_DBG("Callid '%.*s' not found\n", req->callid->body.len, req->callid->body.s); return; } } /* set current dialog - re-use ref increment from dlg_get() above */ set_current_dialog( req, dlg); _dlg_ctx.iuid.h_entry = dlg->h_entry; _dlg_ctx.iuid.h_id = dlg->h_id; if (req->first_line.u.request.method_value != METHOD_ACK) { iuid = dlg_get_iuid_shm_clone(dlg); if(iuid!=NULL) { /* register callback for the replies of this request */ if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_IN|TMCB_ON_FAILURE, dlg_onreply, (void*)iuid, dlg_iuid_sfree)<0 ) { LM_ERR("failed to register TMCB (3)\n"); shm_free(iuid); } iuid = NULL; } } /* run state machine */ switch ( req->first_line.u.request.method_value ) { case METHOD_PRACK: event = DLG_EVENT_REQPRACK; break; case METHOD_ACK: event = DLG_EVENT_REQACK; break; case METHOD_BYE: event = DLG_EVENT_REQBYE; break; default: event = DLG_EVENT_REQ; } next_state_dlg( dlg, event, &old_state, &new_state, &unref); CURR_DLG_ID = req->id; CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts; CURR_DLG_STATUS = new_state; dlg_run_event_route(dlg, req, old_state, new_state); /* delay deletion of dialog until transaction has died off in order * to absorb in-air messages */ if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) { iuid = dlg_get_iuid_shm_clone(dlg); if(iuid!=NULL) { if ( d_tmb.register_tmcb(req, NULL, TMCB_DESTROY, unref_dlg_from_cb, (void*)iuid, dlg_iuid_sfree)<0 ) { LM_ERR("failed to register deletion delay function\n"); shm_free(iuid); } else { dlg_ref(dlg, 1); } } } if (new_state==DLG_STATE_CONFIRMED && old_state!=DLG_STATE_CONFIRMED) dlg_ka_add(dlg); /* run actions for the transition */ if (event==DLG_EVENT_REQBYE && new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) { LM_DBG("BYE successfully processed\n"); /* remove from timer */ ret = remove_dialog_timer(&dlg->tl); if (ret < 0) { LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] " "with clid '%.*s' and tags '%.*s' '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, dlg->callid.len, dlg->callid.s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s); } else if (ret > 0) { LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] " "with clid '%.*s' and tags '%.*s' '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, dlg->callid.len, dlg->callid.s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s); } else { /* one extra unref due to removal from timer list */ unref++; } /* dialog terminated (BYE) */ dlg_terminated( req, dlg, dir); dlg_unref(dlg, unref); _dlg_ctx.cpid = my_pid(); _dlg_ctx.expect_t = 1; dlg_set_ctx_iuid(dlg); if_update_stat( dlg_enable_stats, active_dlgs, -1); goto done; } if ( (event==DLG_EVENT_REQ || event==DLG_EVENT_REQACK) && (new_state==DLG_STATE_CONFIRMED || new_state==DLG_STATE_EARLY)) { timeout = get_dlg_timeout(req); if (timeout!=default_timeout) { dlg->lifetime = timeout; } reset = !((dlg->iflags & DLG_IFLAG_TIMER_NORESET) || dlg_timeout_noreset); if ((new_state!=DLG_STATE_EARLY) && (old_state!=DLG_STATE_CONFIRMED || reset)) { if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1) { LM_ERR("failed to update dialog lifetime\n"); } else { dlg->dflags |= DLG_FLAG_CHANGED; } } if(event != DLG_EVENT_REQACK) { if(update_cseqs(dlg, req, dir)!=0) { LM_ERR("cseqs update failed\n"); } else { dlg->dflags |= DLG_FLAG_CHANGED; } } if(dlg_db_mode==DB_MODE_REALTIME && (dlg->dflags&DLG_FLAG_CHANGED)) { update_dialog_dbinfo(dlg); } if (old_state==DLG_STATE_CONFIRMED_NA) { LM_DBG("confirming ACK successfully processed\n"); /* confirming ACK request */ run_dlg_callbacks( DLGCB_CONFIRMED, dlg, req, NULL, dir, 0); } else { LM_DBG("sequential request successfully processed\n"); /* within dialog request */ run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, NULL, dir, 0); if ( (event!=DLG_EVENT_REQACK) && (dlg->cbs.types)&DLGCB_RESPONSE_WITHIN ) { iuid = dlg_get_iuid_shm_clone(dlg); if(iuid!=NULL) { /* register callback for the replies of this request */ if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED, (dir==DLG_DIR_UPSTREAM)?dlg_seq_down_onreply: dlg_seq_up_onreply, (void*)iuid, dlg_iuid_sfree)<0 ) { LM_ERR("failed to register TMCB (2)\n"); shm_free(iuid); } } } } } if(new_state==DLG_STATE_CONFIRMED && old_state==DLG_STATE_CONFIRMED_NA){ dlg->dflags |= DLG_FLAG_CHANGED; if(dlg_db_mode == DB_MODE_REALTIME) update_dialog_dbinfo(dlg); } done: dlg_release(dlg); return; }
/* * function that simply prints the parameters passed */ static int siprec_start_rec(struct sip_msg *msg, str *srs, str *group, str *_cA, str *_cB, str *rtp, str *m_ip) { int ret; str *aor, *display, *xml_val; struct src_sess *ss; struct dlg_cell *dlg; /* create the dialog, if does not exist yet */ dlg = srec_dlg.get_dlg(); if (!dlg) { if (srec_dlg.create_dlg(msg, 0) < 0) { LM_ERR("cannot create dialog!\n"); return -2; } dlg = srec_dlg.get_dlg(); } /* XXX: if there is a forced send socket in the message, use it * this is the only way to provide a different socket for SRS, but * we might need to take a different approach */ /* check if the current dialog has a siprec session ongoing */ if (!(ss = src_new_session(srs, rtp, m_ip, group, msg->force_send_socket))) { LM_ERR("cannot create siprec session!\n"); return -2; } /* we ref the dialog to make sure it does not dissapear until we receive * the reply from the SRS */ srec_dlg.ref_dlg(dlg, 1); ss->dlg = dlg; ret = -2; /* caller info */ if (_cA) { xml_val = _cA; display = aor = NULL; } else { if (parse_from_header(msg) < 0) { LM_ERR("cannot parse from header!\n"); goto session_cleanup; } aor = &get_from(msg)->uri; display = (get_from(msg)->display.s ? &get_from(msg)->display : NULL); xml_val = NULL; } if (src_add_participant(ss, aor, display, xml_val, NULL) < 0) { LM_ERR("cannot add caller participant!\n"); goto session_cleanup; } if (srs_fill_sdp_stream(msg, ss, &ss->participants[0], 0) < 0) { LM_ERR("cannot add SDP for caller!\n"); goto session_cleanup; } /* caller info */ if (_cB) { xml_val = _cB; } else { if ((!msg->to && parse_headers(msg, HDR_TO_F, 0) < 0) || !msg->to) { LM_ERR("inexisting or invalid to header!\n"); goto session_cleanup; } aor = &get_to(msg)->uri; display = (get_to(msg)->display.s ? &get_to(msg)->display : NULL); xml_val = NULL; } if (src_add_participant(ss, aor, display, xml_val, NULL) < 0) { LM_ERR("cannot add callee pariticipant!\n"); goto session_cleanup; } SIPREC_REF_UNSAFE(ss); if (srec_tm.register_tmcb(msg, 0, TMCB_RESPONSE_OUT, tm_start_recording, ss, src_unref_session) <= 0) { LM_ERR("cannot register tm callbacks\n"); SIPREC_UNREF_UNSAFE(ss); goto session_cleanup; } return 1; session_cleanup: src_free_session(ss); return ret; }
/*! * \brief Function that is registered as TM callback and called on replies * * Function that is registered as TM callback and called on replies. It * parses the reply and set the appropriate event. This is then used to * update the dialog state, run eventual dialog callbacks and save or * update the necessary informations about the dialog. * \see next_state_dlg * \param t transaction, unused * \param type type of the entered callback * \param param saved dialog structure in the callback */ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) { dlg_cell_t *dlg = NULL; dlg_iuid_t *iuid = NULL; int new_state, old_state, unref, event; str tag; sip_msg_t *req = param->req; sip_msg_t *rpl = param->rpl; if (shutdown_done) return; iuid = (dlg_iuid_t*)(*param->param); dlg = dlg_get_by_iuid(iuid); if(dlg==0) return; unref = 0; if (type & (TMCB_RESPONSE_IN|TMCB_ON_FAILURE)) { /* Set the dialog context so it is available in onreply_route and failure_route*/ set_current_dialog(req, dlg); dlg_set_ctx_iuid(dlg); goto done; } if (type==TMCB_RESPONSE_FWDED) { /* The state does not change, but the msg is mutable in this callback*/ run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); goto done; } if (type==TMCB_DESTROY) event = DLG_EVENT_TDEL; else if (param->code<200) event = DLG_EVENT_RPL1xx; else if (param->code<300) event = DLG_EVENT_RPL2xx; else event = DLG_EVENT_RPL3xx; next_state_dlg( dlg, event, &old_state, &new_state, &unref); dlg_run_event_route(dlg, (rpl==FAKED_REPLY)?NULL:rpl, old_state, new_state); if (new_state==DLG_STATE_EARLY) { run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if (old_state!=DLG_STATE_EARLY) if_update_stat(dlg_enable_stats, early_dlgs, 1); goto done; } if (new_state==DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED ) { LM_DBG("dialog %p confirmed (ACK pending)\n",dlg); if (rpl != FAKED_REPLY) { /* get to tag*/ if ( !rpl->to && ((parse_headers(rpl, HDR_TO_F,0)<0) || !rpl->to) ) { LM_ERR("bad reply or missing TO hdr :-/\n"); tag.s = 0; tag.len = 0; } else { tag = get_to(rpl)->tag_value; if (tag.s==0 || tag.len==0) { LM_ERR("missing TAG param in TO hdr :-/\n"); tag.s = 0; tag.len = 0; } } /* save callee's tag, cseq, contact and record route*/ if (populate_leg_info( dlg, rpl, t, DLG_CALLEE_LEG, &tag) !=0) { LM_ERR("could not add further info to the dialog\n"); } } else { LM_ERR("Faked reply!\n"); } /* set start time */ dlg->start_ts = (unsigned int)(time(0)); /* save the settings to the database, * if realtime saving mode configured- save dialog now * else: the next time the timer will fire the update*/ dlg->dflags |= DLG_FLAG_NEW; if ( dlg_db_mode==DB_MODE_REALTIME ) update_dialog_dbinfo(dlg); if (0 != insert_dlg_timer( &dlg->tl, dlg->lifetime )) { LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] " "with clid '%.*s' and tags '%.*s' '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state, dlg->callid.len, dlg->callid.s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s); } else { /* dialog pointer inserted in timer list */ dlg_ref(dlg, 1); } /* dialog confirmed (ACK pending) */ run_dlg_callbacks( DLGCB_CONFIRMED_NA, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if (old_state==DLG_STATE_EARLY) if_update_stat(dlg_enable_stats, early_dlgs, -1); if (unref) dlg_unref(dlg, unref); if_update_stat(dlg_enable_stats, active_dlgs, 1); goto done; } if ( new_state==DLG_STATE_DELETED && (old_state==DLG_STATE_UNCONFIRMED || old_state==DLG_STATE_EARLY) ) { LM_DBG("dialog %p failed (negative reply)\n", dlg); /* dialog setup not completed (3456XX) */ run_dlg_callbacks( DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if(dlg_wait_ack==1) dlg_set_tm_waitack(t, dlg); /* do unref */ if (unref) dlg_unref(dlg, unref); if (old_state==DLG_STATE_EARLY) if_update_stat(dlg_enable_stats, early_dlgs, -1); if_update_stat(dlg_enable_stats, failed_dlgs, 1); goto done; } if (unref) dlg_unref(dlg, unref); done: /* unref due to dlg_get_by_iuid() */ dlg_release(dlg); return; }
int update_contact(struct sip_msg* msg, char* str1, char* str2) { ua_pres_t* p, hentity; str contact; struct to_body *pto= NULL, *pfrom = NULL; unsigned int hash_code; if ( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("when parsing headers\n"); return -1; } /* find the record */ if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); return -1; } if (!msg->from || !msg->from->body.s) { LM_ERR("cannot find 'from' header!\n"); return -1; } if (msg->from->parsed == NULL) { if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); return -1; } } pfrom = (struct to_body*)msg->from->parsed; if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); return -1; } if( msg->to==NULL || msg->to->body.s==NULL) { LM_ERR("cannot parse TO header\n"); return -1; } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("failed to parse TO header\n"); return -1; } if( pto->tag_value.s ==NULL || pto->tag_value.len == 0) { LM_ERR("no to tag value present\n"); return -1; } memset( &hentity, 0, sizeof(ua_pres_t)); /* as we have a NOTIFY, we are looking for any SUBSCRIBER-like entity in the hash (we do not know the exact type) - bogdan */ hentity.flag = BLA_SUBSCRIBE | XMPP_SUBSCRIBE | XMPP_INITIAL_SUBS | MI_SUBSCRIBE | RLS_SUBSCRIBE; hentity.watcher_uri= &pto->uri; hentity.to_uri= pfrom->uri; hentity.call_id= msg->callid->body; hentity.to_tag= pto->tag_value; hentity.from_tag= pfrom->tag_value; hash_code= core_hash(&hentity.to_uri,hentity.watcher_uri, HASH_SIZE); /* extract the contact */ if(msg->contact== NULL || msg->contact->body.s== NULL) { LM_ERR("no contact header found in 200 OK reply"); return -1; } contact= msg->contact->body; lock_get(&HashT->p_records[hash_code].lock); p= get_dialog(&hentity, hash_code); if(p== NULL) { lock_release(&HashT->p_records[hash_code].lock); LM_ERR("no record for the dialog found in hash table\n"); return -1; } shm_free(p->remote_contact.s); if(!(p->remote_contact.len== contact.len && strncmp(p->remote_contact.s, contact.s, contact.len)==0)) { /* update remote contact */ shm_free(p->remote_contact.s); p->remote_contact.s= (char*)shm_malloc(contact.len); if(p->remote_contact.s== NULL) { LM_ERR("no more shared memory\n"); lock_release(&HashT->p_records[hash_code].lock); return -1; } memcpy(p->remote_contact.s, contact.s, contact.len); p->remote_contact.len= contact.len; } lock_release(&HashT->p_records[hash_code].lock); return 1; }
/*! * \brief Create a new dialog from a sip message * * Create a new dialog from a SIP message, register a callback * to keep track of the dialog with help of the tm module. * This function is either called from the request callback, or * from the dlg_manage function in the configuration script. * \see dlg_onreq * \see w_dlg_manage * \param req SIP message * \param t transaction * \param run_initial_cbs if set zero, initial callbacks are not executed * \return 0 on success, -1 on failure */ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs) { dlg_cell_t *dlg; str s; str callid; str ftag; str ttag; str req_uri; unsigned int dir; int mlock; dlg = dlg_get_ctx_dialog(); if(dlg != NULL) { dlg_release(dlg); return -1; } if(req->first_line.u.request.method_value != METHOD_INVITE) return -1; if(pre_match_parse( req, &callid, &ftag, &ttag, 0)<0) { LM_WARN("pre-matching failed\n"); return -1; } if(ttag.s!=0 && ttag.len!=0) return -1; if(pv_printf_s(req, ruri_param_model, &req_uri)<0) { LM_ERR("error - cannot print the r-uri format\n"); return -1; } trim(&req_uri); dir = DLG_DIR_NONE; mlock = 1; /* search dialog by SIP attributes * - if not found, hash table slot is left locked, to avoid races * to add 'same' dialog on parallel forking or not-handled-yet * retransmissions. Release slot after linking new dialog */ dlg = search_dlg(&callid, &ftag, &ttag, &dir); if(dlg) { mlock = 0; if (detect_spirals) { if (spiral_detected == 1) return 0; if ( dlg->state != DLG_STATE_DELETED ) { LM_DBG("Callid '%.*s' found, must be a spiraled request\n", callid.len, callid.s); spiral_detected = 1; if (run_initial_cbs) run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, NULL, DLG_DIR_DOWNSTREAM, 0); /* set ctx dlg id shortcuts */ _dlg_ctx.iuid.h_entry = dlg->h_entry; _dlg_ctx.iuid.h_id = dlg->h_id; /* search_dlg() has incremented the ref count by 1 */ dlg_release(dlg); return 0; } dlg_release(dlg); } /* lock the slot - dlg found, but in dlg_state_deleted, do a new one */ dlg_hash_lock(&callid); } spiral_detected = 0; dlg = build_new_dlg (&callid /*callid*/, &(get_from(req)->uri) /*from uri*/, &(get_to(req)->uri) /*to uri*/, &ftag/*from_tag*/, &req_uri /*r-uri*/ ); if (dlg==0) { if(likely(mlock==1)) dlg_hash_release(&callid); LM_ERR("failed to create new dialog\n"); return -1; } /* save caller's tag, cseq, contact and record route*/ if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG, &(get_from(req)->tag_value)) !=0) { if(likely(mlock==1)) dlg_hash_release(&callid); LM_ERR("could not add further info to the dialog\n"); shm_free(dlg); return -1; } /* Populate initial varlist: */ dlg->vars = get_local_varlist_pointer(req, 1); /* if search_dlg() returned NULL, slot was kept locked */ link_dlg(dlg, 0, mlock); if(likely(mlock==1)) dlg_hash_release(&callid); dlg->lifetime = get_dlg_timeout(req); s.s = _dlg_ctx.to_route_name; s.len = strlen(s.s); dlg_set_toroute(dlg, &s); dlg->sflags |= _dlg_ctx.flags; dlg->iflags |= _dlg_ctx.iflags; if (dlg_send_bye!=0 || _dlg_ctx.to_bye!=0) dlg->iflags |= DLG_IFLAG_TIMEOUTBYE; if (run_initial_cbs) run_create_callbacks( dlg, req); /* first INVITE seen (dialog created, unconfirmed) */ if ( seq_match_mode!=SEQ_MATCH_NO_ID && add_dlg_rr_param( req, dlg->h_entry, dlg->h_id)<0 ) { LM_ERR("failed to add RR param\n"); goto error; } if_update_stat( dlg_enable_stats, processed_dlgs, 1); _dlg_ctx.cpid = my_pid(); _dlg_ctx.iuid.h_entry = dlg->h_entry; _dlg_ctx.iuid.h_id = dlg->h_id; set_current_dialog(req, dlg); return 0; error: if (!spiral_detected) dlg_unref(dlg, 1); // undo ref regarding linking return -1; }
/*! * \brief Function that is registered as RR callback for dialog tracking * * Function that is registered as RR callback for dialog tracking. It * sets the appropriate events after the SIP method and run the state * machine to update the dialog state. It updates then the saved * dialogs and also the statistics. * \param req SIP request * \param route_params record-route parameter * \param param unused */ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) { struct dlg_cell *dlg; str val, callid, ftag, ttag; int h_entry, h_id, new_state, old_state, unref, event, timeout; unsigned int dir; int ret = 0; if (current_dlg_pointer != NULL) return; /* skip initial requests - they may end up here because of the * preloaded route */ if ((!req->to && parse_headers(req, HDR_TO_F, 0) < 0) || !req->to) { LM_ERR("bad request or missing TO hdr :-/\n"); return; } if (get_to(req)->tag_value.len == 0) return; dlg = 0; dir = DLG_DIR_NONE; if (seq_match_mode != SEQ_MATCH_NO_ID) { if (d_rrb.get_route_param(req, &rr_param, &val) != 0) { LM_DBG("Route param '%.*s' not found\n", rr_param.len, rr_param.s); if (seq_match_mode == SEQ_MATCH_STRICT_ID) return; } else { LM_DBG("route param is '%.*s' (len=%d)\n", val.len, val.s, val.len); if (parse_dlg_rr_param(val.s, val.s + val.len, &h_entry, &h_id) < 0) return; dlg = lookup_dlg(h_entry, h_id); if (dlg == 0) { LM_WARN("unable to find dialog for %.*s " "with route param '%.*s' [%u:%u]\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s, val.len, val.s, h_entry, h_id); if (seq_match_mode == SEQ_MATCH_STRICT_ID) return; } else { if (pre_match_parse(req, &callid, &ftag, &ttag, 1) < 0) { // lookup_dlg has incremented the ref count by 1 unref_dlg(dlg, 1); return; } if (match_dialog(dlg, &callid, &ftag, &ttag, &dir) == 0) { LM_WARN("tight matching failed for %.*s with callid='%.*s'/%d, " "ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s, callid.len, callid.s, callid.len, ftag.len, ftag.s, ftag.len, ttag.len, ttag.s, ttag.len, dir); LM_WARN("dialog identification elements are callid='%.*s'/%d, " "caller tag='%.*s'/%d\n", dlg->callid.len, dlg->callid.s, dlg->callid.len, dlg->from_tag.len, dlg->from_tag.s, dlg->from_tag.len); // lookup_dlg has incremented the ref count by 1 unref_dlg(dlg, 1); // Reset variables in order to do a lookup based on SIP-Elements. dlg = 0; dir = DLG_DIR_NONE; if (seq_match_mode == SEQ_MATCH_STRICT_ID) return; } } } } if (dlg == 0) { if (pre_match_parse(req, &callid, &ftag, &ttag, 1) < 0) return; /* TODO - try to use the RR dir detection to speed up here the * search -bogdan */ dlg = get_dlg(&callid, &ftag, &ttag, &dir); if (!dlg) { LM_DBG("Callid '%.*s' not found\n", req->callid->body.len, req->callid->body.s); return; } } /* set current dialog - re-use ref increment from dlg_get() above */ set_current_dialog(req, dlg); _dlg_ctx.dlg = dlg; if (d_tmb.register_tmcb(req, NULL, TMCB_REQUEST_FWDED, store_dlg_in_tm_cb, (void*) dlg, NULL) < 0) { LM_ERR("failed to store dialog in transaction during dialog creation for later reference\n"); } /* run state machine */ switch (req->first_line.u.request.method_value) { case METHOD_PRACK: event = DLG_EVENT_REQPRACK; break; case METHOD_ACK: event = DLG_EVENT_REQACK; break; case METHOD_BYE: event = DLG_EVENT_REQBYE; break; default: event = DLG_EVENT_REQ; } next_state_dlg(dlg, event, &old_state, &new_state, &unref, 0); LM_DBG("unref after next state is %i\n", unref); CURR_DLG_ID = req->id; CURR_DLG_LIFETIME = (unsigned int) (time(0)) - dlg->start_ts; CURR_DLG_STATUS = new_state; /* run actions for the transition */ if (event == DLG_EVENT_REQBYE && new_state == DLG_STATE_DELETED && old_state != DLG_STATE_DELETED) { LM_DBG("BYE successfully processed\n"); /* remove from timer */ ret = remove_dialog_timer(&dlg->tl); if (ret < 0) { LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] " "with clid '%.*s' and tags '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, dlg->callid.len, dlg->callid.s, dlg->from_tag.len, dlg->from_tag.s); } else if (ret > 0) { LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] " "with clid '%.*s' and tags '%.*s' \n", dlg, dlg->h_entry, dlg->h_id, dlg->callid.len, dlg->callid.s, dlg->from_tag.len, dlg->from_tag.s); } else { unref++; } /* dialog terminated (BYE) */ dlg_terminated(req, dlg, dir); unref_dlg(dlg, unref); return; } if ((event == DLG_EVENT_REQ || event == DLG_EVENT_REQACK) && new_state == DLG_STATE_CONFIRMED) { timeout = get_dlg_timeout(req); if (timeout != default_timeout) { dlg->lifetime = timeout; } if (update_dlg_timer(&dlg->tl, dlg->lifetime) == -1) { LM_ERR("failed to update dialog lifetime\n"); } if (update_cseqs(dlg, req, dir, &ttag) != 0) { LM_ERR("cseqs update failed\n"); } else { dlg->dflags |= DLG_FLAG_CHANGED; } if(dlg_db_mode==DB_MODE_REALTIME && (dlg->dflags&DLG_FLAG_CHANGED)) { update_dialog_dbinfo(dlg); } if (old_state != DLG_STATE_CONFIRMED) { LM_DBG("confirming ACK successfully processed\n"); /* confirming ACK request */ run_dlg_callbacks(DLGCB_CONFIRMED, dlg, req, NULL, dir, 0); } else { LM_DBG("sequential request successfully processed\n"); /* within dialog request */ run_dlg_callbacks(DLGCB_REQ_WITHIN, dlg, req, NULL, dir, 0); if ((event != DLG_EVENT_REQACK) && (dlg->cbs.types) & DLGCB_RESPONSE_WITHIN) { /* ref the dialog as registered into the transaction callback. * unref will be done when the callback will be destroyed */ ref_dlg(dlg, 1); /* register callback for the replies of this request */ if (d_tmb.register_tmcb(req, 0, TMCB_RESPONSE_FWDED, (dir == DLG_DIR_UPSTREAM) ? dlg_seq_down_onreply : dlg_seq_up_onreply, (void*) dlg, unreference_dialog) < 0) { LM_ERR("failed to register TMCB (2)\n"); unref_dlg(dlg, 1); } } } } if (new_state == DLG_STATE_CONFIRMED && old_state != DLG_STATE_CONFIRMED) { dlg->dflags |= DLG_FLAG_CHANGED; if(dlg_db_mode == DB_MODE_REALTIME) update_dialog_dbinfo(dlg); } return; }
/* this is the code which decides what and when shall be relayed upstream; note well -- it assumes it is entered locked with REPLY_LOCK and it returns unlocked! */ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, unsigned int msg_status, branch_bm_t *cancel_bitmap ) { int relay; int save_clone; char *buf; /* length of outbound reply */ unsigned int res_len; int relayed_code; struct sip_msg *relayed_msg; struct bookmark bm; int totag_retr; enum rps reply_status; /* retransmission structure of outbound reply and request */ struct retr_buf *uas_rb; str cb_s; str text; /* keep compiler warnings about use of uninit vars silent */ res_len=0; buf=0; relayed_msg=0; relayed_code=0; totag_retr=0; /* remember, what was sent upstream to know whether we are * forwarding a first final reply or not */ /* *** store and relay message as needed *** */ reply_status = t_should_relay_response(t, msg_status, branch, &save_clone, &relay, cancel_bitmap, p_msg ); LM_DBG("branch=%d, save=%d, relay=%d\n", branch, save_clone, relay ); /* store the message if needed */ if (save_clone) /* save for later use, typically branch picking */ { if (!store_reply( t, branch, p_msg )) goto error01; } uas_rb = & t->uas.response; if (relay >= 0 ) { /* initialize sockets for outbound reply */ uas_rb->activ_type=msg_status; t->relaied_reply_branch = relay; /* try building the outbound reply from either the current * or a stored message */ relayed_msg = branch==relay ? p_msg : t->uac[relay].reply; if (relayed_msg==FAKED_REPLY) { relayed_code = branch==relay ? msg_status : t->uac[relay].last_received; text.s = error_text(relayed_code); text.len = strlen(text.s); /* FIXME - bogdan*/ if (relayed_code>=180 && t->uas.request->to && (get_to(t->uas.request)->tag_value.s==0 || get_to(t->uas.request)->tag_value.len==0)) { calc_crc_suffix( t->uas.request, tm_tag_suffix ); buf = build_res_buf_from_sip_req( relayed_code, &text, &tm_tag, t->uas.request, &res_len, &bm ); } else { buf = build_res_buf_from_sip_req( relayed_code, &text, 0/* no to-tag */, t->uas.request, &res_len, &bm ); } } else { /* run callbacks for all types of responses - * even if they are shmem-ed or not */ if (has_tran_tmcbs(t,TMCB_RESPONSE_FWDED) ) { run_trans_callbacks( TMCB_RESPONSE_FWDED, t, t->uas.request, relayed_msg, msg_status ); } relayed_code=relayed_msg->REPLY_STATUS; buf = build_res_buf_from_sip_res( relayed_msg, &res_len, uas_rb->dst.send_sock,0); /* remove all lumps which are not in shm * added either by build_res_buf_from_sip_res, or by * the callbacks that have been called with shmem-ed messages - vlad */ if (branch!=relay) { del_notflaged_lumps( &(relayed_msg->add_rm), LUMPFLAG_SHMEM); del_notflaged_lumps( &(relayed_msg->body_lumps), LUMPFLAG_SHMEM); } } if (!buf) { LM_ERR("no mem for outbound reply buffer\n"); goto error02; } /* attempt to copy the message to UAS's shmem: - copy to-tag for ACK matching as well - allocate little a bit more for provisional as larger messages are likely to follow and we will be able to reuse the memory frag */ uas_rb->buffer.s = (char*)shm_resize( uas_rb->buffer.s, res_len + (msg_status<200 ? REPLY_OVERBUFFER_LEN : 0)); if (!uas_rb->buffer.s) { LM_ERR("no more share memory\n"); goto error03; } uas_rb->buffer.len = res_len; memcpy( uas_rb->buffer.s, buf, res_len ); if (relayed_msg==FAKED_REPLY) { /* to-tags for local replies */ update_local_tags(t, &bm, uas_rb->buffer.s, buf); } stats_trans_rpl( relayed_code, (relayed_msg==FAKED_REPLY)?1:0 ); /* update the status ... */ t->uas.status = relayed_code; if (is_invite(t) && relayed_msg!=FAKED_REPLY && relayed_code>=200 && relayed_code < 300 && has_tran_tmcbs( t, TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT)) { totag_retr=update_totag_set(t, relayed_msg); } }; /* if relay ... */ UNLOCK_REPLIES( t ); /* Setup retransmission timer _before_ the reply is sent * to avoid race conditions */ if (reply_status == RPS_COMPLETED) { /* for auth related replies, we do not do retransmission (via set_final_timer()), but only wait for a final reply (put_on_wait() ) - see RFC 3261 (26.3.2.4 DoS Protection) */ if ((relayed_code != 401) && (relayed_code != 407)) set_final_timer(t); else put_on_wait(t); } /* send it now (from the private buffer) */ if (relay >= 0) { /* run the PRE sending out callback */ if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_PRE_OUT) ) { cb_s.s = buf; cb_s.len = res_len; set_extra_tmcb_params( &cb_s, &uas_rb->dst); run_trans_callbacks_locked(TMCB_RESPONSE_PRE_OUT,t,t->uas.request, relayed_msg, relayed_code); } SEND_PR_BUFFER( uas_rb, buf, res_len ); LM_DBG("sent buf=%p: %.9s..., shmem=%p: %.9s\n", buf, buf, uas_rb->buffer.s, uas_rb->buffer.s ); /* run the POST sending out callback */ if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT) ) { cb_s.s = buf; cb_s.len = res_len; set_extra_tmcb_params( &cb_s, &uas_rb->dst); run_trans_callbacks_locked( TMCB_RESPONSE_OUT, t, t->uas.request, relayed_msg, relayed_code); } pkg_free( buf ); } /* success */ return reply_status; error03: pkg_free( buf ); error02: if (save_clone) { if (t->uac[branch].reply!=FAKED_REPLY) free_cloned_msg( t->uac[branch].reply ); t->uac[branch].reply = NULL; } error01: text.s = "Reply processing error"; text.len = sizeof("Reply processing error")-1; t_reply_unsafe( t, t->uas.request, 500, &text ); UNLOCK_REPLIES(t); if (is_invite(t)) cancel_uacs( t, *cancel_bitmap ); /* a serious error occurred -- attempt to send an error reply; it will take care of clean-ups */ /* failure */ return RPS_ERROR; }
static int append_fixed_vars(struct sip_msg *msg, struct hf_wrapper **list) { static char tid[MD5_LEN]; str *uri; struct sip_uri parsed_uri, oparsed_uri; char *val; int val_len; /* source ip */ if (!append_var(EV_SRCIP, ip_addr2a(&msg->rcv.src_ip), 0, list)) { LOG(L_ERR, "ERROR: append_var SRCIP failed \n"); return 0; } /* request URI */ uri=msg->new_uri.s && msg->new_uri.len ? &msg->new_uri : &msg->first_line.u.request.uri; if (!append_var(EV_RURI, uri->s, uri->len, list )) { LOG(L_ERR, "ERROR: append_var URI failed\n"); return 0; } /* userpart of request URI */ if (parse_uri(uri->s, uri->len, &parsed_uri)<0) { LOG(L_WARN, "WARNING: append_var: URI not parsed\n"); } else { if (!append_var(EV_USER, parsed_uri.user.s, parsed_uri.user.len, list)) { LOG(L_ERR, "ERROR: append_var USER failed\n"); goto error; } } /* original URI */ if (!append_var(EV_ORURI, msg->first_line.u.request.uri.s, msg->first_line.u.request.uri.len, list)) { LOG(L_ERR, "ERROR: append_var O-URI failed\n"); goto error; } /* userpart of request URI */ if (parse_uri(msg->first_line.u.request.uri.s, msg->first_line.u.request.uri.len, &oparsed_uri)<0) { LOG(L_WARN, "WARNING: append_var: orig URI not parsed\n"); } else { if (!append_var(EV_OUSER, oparsed_uri.user.s, oparsed_uri.user.len, list)) { LOG(L_ERR, "ERROR: append_var OUSER failed\n"); goto error; } } /* tid, transaction id == via/branch */ if (!char_msg_val(msg, tid)) { LOG(L_WARN, "WARNING: no tid can be determined\n"); val=0; val_len=0; } else { val=tid;val_len=MD5_LEN; } if (!append_var(EV_TID, val,val_len, list)) { LOG(L_ERR, "ERROR: append_var TID failed\n"); goto error; } /* did, dialogue id == To-tag */ if (!(msg->to && get_to(msg) )) { LOG(L_ERR, "ERROR: append_var: no to-tag\n"); val=0; val_len=0; } else { val=get_to(msg)->tag_value.s; val_len=get_to(msg)->tag_value.len; } if (!append_var(EV_DID, val, val_len, list)) { LOG(L_ERR, "ERROR: append_var DID failed\n"); goto error; } return 1; error: return 0; }
int t_reply_with_body( struct cell *trans, unsigned int code, str *text, str *body, str *new_header, str *to_tag ) { struct lump_rpl *hdr_lump; struct lump_rpl *body_lump; str rpl; int ret; struct bookmark bm; struct sip_msg* p_msg = trans->uas.request; str to_tag_rpl= {0, 0}; /* add the lumps for new_header and for body (by bogdan) */ if (new_header && new_header->len) { hdr_lump = add_lump_rpl( p_msg, new_header->s, new_header->len, LUMP_RPL_HDR ); if ( !hdr_lump ) { LM_ERR("failed to add hdr lump\n"); goto error; } } else { hdr_lump = 0; } /* body lump */ if(body && body->len) { body_lump = add_lump_rpl( p_msg, body->s, body->len, LUMP_RPL_BODY ); if (body_lump==0) { LM_ERR("failed add body lump\n"); goto error_1; } } else { body_lump = 0; } if(to_tag && to_tag->len) { rpl.s = build_res_buf_from_sip_req(code, text, to_tag, p_msg, (unsigned int*)&rpl.len, &bm); to_tag_rpl = *to_tag; } else if (code>=180 && p_msg->to && (get_to(p_msg)->tag_value.s==0 || get_to(p_msg)->tag_value.len==0)) { calc_crc_suffix( p_msg, tm_tag_suffix ); rpl.s = build_res_buf_from_sip_req(code,text, &tm_tag, p_msg, (unsigned int*)&rpl.len, &bm); to_tag_rpl.s = tm_tag.s; to_tag_rpl.len = TOTAG_VALUE_LEN; } else { rpl.s = build_res_buf_from_sip_req(code,text, 0 /*no to-tag*/, p_msg, (unsigned int*)&rpl.len, &bm); } /* since the msg (trans->uas.request) is a clone into shm memory, to avoid * memory leak or crashing (lumps are create in private memory) I will * remove the lumps by myself here (bogdan) */ if ( hdr_lump ) { unlink_lump_rpl( p_msg, hdr_lump); free_lump_rpl( hdr_lump ); } if( body_lump ) { unlink_lump_rpl( p_msg, body_lump); free_lump_rpl( body_lump ); } if (rpl.s==0) { LM_ERR("failed in doing build_res_buf_from_sip_req()\n"); goto error; } ret=_reply_light( trans, rpl.s, rpl.len, code, to_tag_rpl.s, to_tag_rpl.len, 1 /* lock replies */, &bm ); /* mark the transaction as replied */ if (code>=200) set_kr(REQ_RPLD); return ret; error_1: if ( hdr_lump ) { unlink_lump_rpl( p_msg, hdr_lump); free_lump_rpl( hdr_lump ); } error: return -1; }
int save_aux(struct sip_msg* _m, str* forced_binding, char* _d, char* _f, char* _s) { struct save_ctx sctx; contact_t* c; contact_t* forced_c; int st; str uri; str flags_s; pv_value_t val; rerrno = R_FINE; memset( &sctx, 0 , sizeof(sctx)); sctx.max_contacts = -1; sctx.flags = 0; if (_f && _f[0]!=0) { if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) { LM_ERR("invalid flags parameter"); return -1; } for( st=0 ; st< flags_s.len ; st++ ) { switch (flags_s.s[st]) { case 'm': sctx.flags |= REG_SAVE_MEMORY_FLAG; break; case 'r': sctx.flags |= REG_SAVE_NOREPLY_FLAG; break; case 's': sctx.flags |= REG_SAVE_SOCKET_FLAG; break; case 'v': sctx.flags |= REG_SAVE_PATH_RECEIVED_FLAG; break; case 'f': sctx.flags |= REG_SAVE_FORCE_REG_FLAG; break; case 'c': sctx.max_contacts = 0; while (st<flags_s.len-1 && isdigit(flags_s.s[st+1])) { sctx.max_contacts = sctx.max_contacts*10 + flags_s.s[st+1] - '0'; st++; } break; case 'p': if (st<flags_s.len-1) { st++; if (flags_s.s[st]=='2') { sctx.flags |= REG_SAVE_PATH_STRICT_FLAG; break; } if (flags_s.s[st]=='1') { sctx.flags |= REG_SAVE_PATH_LAZY_FLAG; break; } if (flags_s.s[st]=='0') { sctx.flags |= REG_SAVE_PATH_OFF_FLAG; break; } } default: LM_WARN("unsuported flag %c \n",flags_s.s[st]); } } } if(route_type == ONREPLY_ROUTE) sctx.flags |= REG_SAVE_NOREPLY_FLAG; /* if no max_contact per AOR is defined, use the global one */ if (sctx.max_contacts == -1) sctx.max_contacts = max_contacts; if (parse_message(_m) < 0) { goto error; } if (forced_binding) { if (parse_contacts(forced_binding, &forced_c) < 0) { LM_ERR("Unable to parse forced binding [%.*s]\n", forced_binding->len, forced_binding->s); goto error; } /* prevent processing all the headers from the message */ reset_first_contact(); st = 0; c = forced_c; } else { if (check_contacts(_m, &st) > 0) { goto error; } c = get_first_contact(_m); } get_act_time(); if (_s) { if (pv_get_spec_value( _m, (pv_spec_p)_s, &val)!=0) { LM_ERR("failed to get PV value\n"); return -1; } if ( (val.flags&PV_VAL_STR)==0 ) { LM_ERR("PV vals is not string\n"); return -1; } uri = val.rs; } else { uri = get_to(_m)->uri; } if (extract_aor( &uri, &sctx.aor) < 0) { LM_ERR("failed to extract Address Of Record\n"); goto error; } if (c == 0) { if (st) { if (star((udomain_t*)_d, &sctx) < 0) goto error; } else { if (no_contacts((udomain_t*)_d, &sctx.aor) < 0) goto error; } } else { if (add_contacts(_m, c, (udomain_t*)_d, &sctx) < 0) goto error; } update_stat(accepted_registrations, 1); if (!is_cflag_set(REG_SAVE_NOREPLY_FLAG) && (send_reply(_m,sctx.flags)<0)) return -1; return 1; error: update_stat(rejected_registrations, 1); if ( !is_cflag_set(REG_SAVE_NOREPLY_FLAG) ) send_reply(_m,sctx.flags); return 0; }
/*! \brief * \return 0/1 (false/true) or -1 on error, -127 EXPR_DROP */ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) { struct sip_uri uri; int ret; int retl; int retr; int ival; pv_value_t lval; pv_value_t rval; char *p; int i,n; ret=E_BUG; if (e->type!=ELEM_T){ LM_CRIT("invalid type\n"); goto error; } if(val) memset(val, 0, sizeof(pv_value_t)); switch(e->left.type){ case METHOD_O: ret=comp_strval(msg, e->op, &msg->first_line.u.request.method, &e->right); break; case URI_O: if(msg->new_uri.s){ if (e->right.type==MYSELF_ST){ if (parse_sip_msg_uri(msg)<0) ret=-1; else ret=check_self_op(e->op, &msg->parsed_uri.host, msg->parsed_uri.port_no? msg->parsed_uri.port_no:SIP_PORT); }else{ ret=comp_strval(msg, e->op, &msg->new_uri, &e->right); } }else{ if (e->right.type==MYSELF_ST){ if (parse_sip_msg_uri(msg)<0) ret=-1; else ret=check_self_op(e->op, &msg->parsed_uri.host, msg->parsed_uri.port_no? msg->parsed_uri.port_no:SIP_PORT); }else{ ret=comp_strval(msg, e->op, &msg->first_line.u.request.uri, &e->right); } } break; case FROM_URI_O: if (parse_from_header(msg)<0){ LM_ERR("bad or missing From: header\n"); goto error; } if (e->right.type==MYSELF_ST){ if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len, &uri) < 0){ LM_ERR("bad uri in From:\n"); goto error; } ret=check_self_op(e->op, &uri.host, uri.port_no?uri.port_no:SIP_PORT); }else{ ret=comp_strval(msg, e->op, &get_from(msg)->uri, &e->right); } break; case TO_URI_O: if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) || (msg->to==0))){ LM_ERR("bad or missing To: header\n"); goto error; } /* to content is parsed automatically */ if (e->right.type==MYSELF_ST){ if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len, &uri) < 0){ LM_ERR("bad uri in To:\n"); goto error; } ret=check_self_op(e->op, &uri.host, uri.port_no?uri.port_no:SIP_PORT); }else{ ret=comp_strval(msg, e->op, &get_to(msg)->uri, &e->right); } break; case SRCIP_O: ret=comp_ip(msg, e->op, &msg->rcv.src_ip, &e->right); break; case DSTIP_O: ret=comp_ip(msg, e->op, &msg->rcv.dst_ip, &e->right); break; case NUMBER_O: ret=!(!e->right.v.n); /* !! to transform it in {0,1} */ break; case ACTION_O: ret=run_action_list( (struct action*)e->right.v.data, msg); if(val) { val->flags = PV_TYPE_INT|PV_VAL_INT; val->ri = ret; } if (ret<=0) ret=(ret==0)?EXPR_DROP:0; else ret=1; return ret; case EXPR_O: retl = retr = 0; memset(&lval, 0, sizeof(pv_value_t)); memset(&rval, 0, sizeof(pv_value_t)); if(e->left.v.data) retl=eval_expr((struct expr*)e->left.v.data,msg,&lval); if(lval.flags == PV_VAL_NONE) { pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } if(e->op == BNOT_OP) { if(lval.flags&PV_VAL_INT) { if(val!=NULL) { val->flags = PV_TYPE_INT|PV_VAL_INT; val->ri = ~lval.ri; } pv_value_destroy(&lval); pv_value_destroy(&rval); return (val->ri)?1:0; } LM_ERR("binary NOT on non-numeric value\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } if(e->right.v.data) retr=eval_expr((struct expr*)e->right.v.data,msg,&rval); if(lval.flags&PV_TYPE_INT) { if( (rval.flags&PV_VAL_NULL) ) { rval.ri = 0; } else if(!(rval.flags&PV_VAL_INT)) { LM_ERR("invalid numeric operands\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } if(val!=NULL) val->flags = PV_TYPE_INT|PV_VAL_INT; ival = 0; switch(e->op) { case PLUS_OP: ival = lval.ri + rval.ri; break; case MINUS_OP: ival = lval.ri - rval.ri; break; case DIV_OP: if(rval.ri==0) { LM_ERR("divide by 0\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } else ival = lval.ri / rval.ri; break; case MULT_OP: ival = lval.ri * rval.ri; break; case MODULO_OP: if(rval.ri==0) { LM_ERR("divide by 0\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } else ival = lval.ri % rval.ri; break; case BAND_OP: ival = lval.ri & rval.ri; break; case BOR_OP: ival = lval.ri | rval.ri; break; case BXOR_OP: ival = lval.ri ^ rval.ri; break; case BLSHIFT_OP: ival = lval.ri << rval.ri; break; case BRSHIFT_OP: ival = lval.ri >> rval.ri; break; default: LM_ERR("invalid int op %d\n", e->op); val->ri = 0; pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } pv_value_destroy(&lval); pv_value_destroy(&rval); if(val!=NULL) val->ri = ival; return (ival)?1:0; } else if (e->op == PLUS_OP) { if( (rval.flags&PV_VAL_NULL) || (val==NULL)) { if (val) val->flags|=PV_VAL_STR; ret = (lval.rs.len>0 || rval.rs.len>0); pv_value_destroy(&lval); pv_value_destroy(&rval); return ret; } if(!(rval.flags&PV_VAL_STR)) { LM_ERR("invalid string operands\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } val->rs.s=(char*)pkg_malloc((lval.rs.len+rval.rs.len+1) *sizeof(char)); if(val->rs.s==0) { LM_ERR("no more memory\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } val->flags = PV_VAL_PKG|PV_VAL_STR; memcpy(val->rs.s, lval.rs.s, lval.rs.len); memcpy(val->rs.s+lval.rs.len, rval.rs.s, rval.rs.len); val->rs.len = lval.rs.len + rval.rs.len; val->rs.s[val->rs.len] = '\0'; pv_value_destroy(&lval); pv_value_destroy(&rval); return 1; } else if ((lval.flags & PV_VAL_STR) && (rval.flags & PV_VAL_STR)) { if (lval.rs.len != rval.rs.len) { LM_ERR("Different length string operands\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } n = lval.rs.len; val->rs.s = pkg_malloc(n+1); if (!val->rs.s) { LM_ERR("no more memory\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } switch(e->op) { case BAND_OP: for (i=0;i<n;i++) val->rs.s[i] = lval.rs.s[i] & rval.rs.s[i]; break; case BOR_OP: for (i=0;i<n;i++) val->rs.s[i] = lval.rs.s[i] | rval.rs.s[i]; break; case BXOR_OP: for (i=0;i<n;i++) val->rs.s[i] = lval.rs.s[i] ^ rval.rs.s[i]; break; default: LM_ERR("Only bitwise operations can be applied on strings\n"); val->ri = 0; pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } val->flags = PV_VAL_PKG|PV_VAL_STR; val->rs.len = n; val->rs.s[n] = '\0'; pv_value_destroy(&lval); pv_value_destroy(&rval); return 1; } else { LM_ERR("Invalid operator : %d \n",e->op); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } break; case SRCPORT_O: ret=comp_no(msg->rcv.src_port, e->right.v.data, /* e.g., 5060 */ e->op, /* e.g. == */ e->right.type /* 5060 is number */); break; case DSTPORT_O: ret=comp_no(msg->rcv.dst_port, e->right.v.data, e->op, e->right.type); break; case PROTO_O: ret=comp_no(msg->rcv.proto, e->right.v.data, e->op, e->right.type); break; case AF_O: ret=comp_no(msg->rcv.src_ip.af, e->right.v.data, e->op, e->right.type); break; case RETCODE_O: ret=comp_no(return_code, e->right.v.data, e->op, e->right.type); break; case MSGLEN_O: ret=comp_no(msg->len, e->right.v.data, e->op, e->right.type); break; case STRINGV_O: if(val) { val->flags = PV_VAL_STR; val->rs = e->left.v.s; } /* optimization for no dup ?!?! */ return (e->left.v.s.len>0)?1:0; case NUMBERV_O: if(val) { val->flags = PV_TYPE_INT|PV_VAL_INT; val->ri = e->left.v.n; } ret=!(!e->left.v.n); /* !! to transform it in {0,1} */ return ret; case SCRIPTVAR_O: if(e->op==NO_OP) { memset(&rval, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, e->right.v.spec, &rval)==0) { if(rval.flags==PV_VAL_NONE || (rval.flags&PV_VAL_NULL) || (rval.flags&PV_VAL_EMPTY) || ((rval.flags&PV_TYPE_INT)&&rval.ri==0)) { pv_value_destroy(&rval); return 0; } if(rval.flags&PV_TYPE_INT) { pv_value_destroy(&rval); return 1; } if(rval.rs.len!=0) { pv_value_destroy(&rval); return 1; } pv_value_destroy(&rval); } return 0; } if(e->op==VALUE_OP) { if(pv_get_spec_value(msg, e->left.v.spec, &lval)==0) { if(val!=NULL) memcpy(val, &lval, sizeof(pv_value_t)); if(lval.flags&PV_VAL_STR) { if(!((lval.flags&PV_VAL_PKG) || (lval.flags&PV_VAL_SHM))) { if(val!=NULL) { /* do pkg duplicate */ p = (char*)pkg_malloc((val->rs.len+1) *sizeof(char)); if(p==0) { LM_ERR("no more pkg memory\n"); memset(val, 0, sizeof(pv_value_t)); return 0; } memcpy(p, val->rs.s, val->rs.len); p[val->rs.len] = 0; val->rs.s = p; val->flags|= PV_VAL_PKG; } } return 1; } if(lval.flags==PV_VAL_NONE || (lval.flags & PV_VAL_NULL) || (lval.flags & PV_VAL_EMPTY)) return 0; if(lval.flags&PV_TYPE_INT) return (lval.ri!=0); else return (lval.rs.len>0); } return 0; } ret=comp_scriptvar(msg, e->op, &e->left, &e->right); break; default: LM_CRIT("invalid operand %d\n", e->left.type); }
int tps_request_sent(sip_msg_t *msg, int dialog, int direction, int local) { tps_data_t mtsd; tps_data_t stsd; tps_data_t *ptsd; str lkey; memset(&mtsd, 0, sizeof(tps_data_t)); memset(&stsd, 0, sizeof(tps_data_t)); ptsd = &mtsd; if(tps_pack_request(msg, &mtsd)<0) { LM_ERR("failed to extract and pack the headers\n"); return -1; } if(direction==TPS_DIR_DOWNSTREAM) { lkey = get_from(msg)->tag_value; } else { lkey = get_to(msg)->tag_value; } tps_storage_lock_get(&lkey); if(dialog==0) { if(tps_storage_record(msg, ptsd)<0) { goto error; } } /* local generated requests */ if(local) { /* ACK and CANCEL go downstream */ if(get_cseq(msg)->method_id==METHOD_ACK || get_cseq(msg)->method_id==METHOD_CANCEL || local==2) { // th_mask_callid(&msg); goto done; } else { /* should be for upstream */ goto done; } } tps_remove_headers(msg, HDR_RECORDROUTE_T); tps_remove_headers(msg, HDR_CONTACT_T); tps_remove_headers(msg, HDR_VIA_T); tps_reinsert_via(msg, ptsd, &ptsd->x_via1); if(direction==TPS_DIR_UPSTREAM) { tps_reinsert_contact(msg, ptsd, &ptsd->as_contact); } else { tps_reinsert_contact(msg, ptsd, &ptsd->bs_contact); } done: tps_storage_lock_release(&lkey); return 0; error: tps_storage_lock_release(&lkey); return -1; }
void dlg_bridge_tm_callback(struct cell *t, int type, struct tmcb_params *ps) { struct sip_msg *msg = NULL; dlg_transfer_ctx_t *dtc = NULL; struct dlg_cell *dlg = NULL; str s; str cseq; str empty = {"", 0}; if(ps->param==NULL || *ps->param==0) { LM_DBG("message id not received\n"); return; } dtc = *((dlg_transfer_ctx_t**)ps->param); if(dtc==NULL) return; LM_DBG("completed with status %d\n", ps->code); if(ps->code>=300) goto error; /* 2xx - build dialog/send refer */ msg = ps->rpl; if((msg->cseq==NULL || parse_headers(msg,HDR_CSEQ_F,0)<0) || msg->cseq==NULL || msg->cseq->parsed==NULL) { LM_ERR("bad sip message or missing CSeq hdr :-/\n"); goto error; } cseq = (get_cseq(msg))->number; if((msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL) { LM_ERR("bad request or missing TO hdr\n"); goto error; } if(parse_from_header(msg)) { LM_ERR("bad request or missing FROM hdr\n"); goto error; } if((msg->callid==NULL && parse_headers(msg,HDR_CALLID_F,0)<0) || msg->callid==NULL){ LM_ERR("bad request or missing CALLID hdr\n"); goto error; } s = msg->callid->body; trim(&s); /* some sanity checks */ if (s.len==0 || get_from(msg)->tag_value.len==0) { LM_ERR("invalid request -> callid (%d) or from TAG (%d) empty\n", s.len, get_from(msg)->tag_value.len); goto error; } dlg = build_new_dlg(&s /*callid*/, &(get_from(msg)->uri) /*from uri*/, &(get_to(msg)->uri) /*to uri*/, &(get_from(msg)->tag_value)/*from_tag*/, &(get_to(msg)->uri) /*use to as r-uri*/ ); if (dlg==0) { LM_ERR("failed to create new dialog\n"); goto error; } dtc->dlg = dlg; if (dlg_set_leg_info(dlg, &(get_from(msg)->tag_value), &empty, &dlg_bridge_controller, &cseq, DLG_CALLER_LEG)!=0) { LM_ERR("dlg_set_leg_info failed\n"); goto error; } if (populate_leg_info(dlg, msg, t, DLG_CALLEE_LEG, &(get_to(msg)->tag_value)) !=0) { LM_ERR("could not add further info to the dialog\n"); shm_free(dlg); goto error; } if(dlg_refer_callee(dtc)!=0) goto error; return; error: dlg_transfer_ctx_free(dtc); return; }
/* look for subscriber cell using callid and to_tag of Notify*/ struct sm_subscriber* get_subs_cell(struct sip_msg *msg, str callid_event) { str callid; str method; struct to_body *pto= NULL, *pfrom = NULL; struct sm_subscriber* s; unsigned int hash_code; method.s = msg->first_line.u.request.method.s; method.len = msg->first_line.u.request.method.len; if ( parse_headers(msg,HDR_EOH_F, 0) == -1 ){ LM_ERR("error in parsing headers\n"); return NULL; } // get callid from Notify if( msg->callid==NULL || msg->callid->body.s==NULL){ LM_ERR("reply without callid header\n"); return NULL; } callid = msg->callid->body; LM_DBG("CALLID: %.*s \n ", callid.len, callid.s ); if (msg->from->parsed == NULL){ if ( parse_from_header( msg )<0 ){ LM_ERR("reply without From header\n"); return NULL; } } //get From header from Notify pfrom = get_from(msg); LM_DBG("PFROM: %.*s \n ", pfrom->uri.len, pfrom->uri.s ); if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0){ LM_ERR("reply without tag value \n"); return NULL; } if( msg->to==NULL || msg->to->body.s==NULL){ LM_ERR("error in parse TO header\n"); return NULL; } // get To header from Notify pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("failed to parse TO header\n"); return NULL; } if( pto->tag_value.s ==NULL || pto->tag_value.len == 0){ LM_ERR("reply without tag value \n"); } LM_DBG("PTO: %.*s \n ", pto->uri.len, pto->uri.s ); LM_DBG("PTO_TAG: %.*s \n ", pto->tag_value.len, pto->tag_value.s ); LM_DBG("********************************************CALLID_STR%.*s\n", callid_event.len, callid_event.s); hash_code= core_hash(&callid_event, 0, subst_size); LM_DBG("********************************************HASH_CODE%d\n", hash_code); s= search_shtable(subs_htable, &callid, &pfrom->tag_value, hash_code, &method); if (s == NULL) { LM_ERR(" ---FAILURE SUB_CELL NOT FOUND IN SHTABLE\n"); } return s; }
int sl_send_reply_helper(struct sip_msg *msg ,int code, str *text) { str buf; union sockaddr_union to; char *dset; int dset_len; struct bookmark dummy_bm; int backup_mhomed; int ret; if ( msg->REQ_METHOD==METHOD_ACK) return 0; update_sock_struct_from_ip( &to, msg ); /* if that is a redirection message, dump current message set to it */ if (code>=300 && code<400) { dset=print_dset(msg, &dset_len); if (dset) { add_lump_rpl(msg, dset, dset_len, LUMP_RPL_HDR); } } /* add a to-tag if there is a To header field without it */ if ( code>=180 && (msg->to || (parse_headers(msg,HDR_TO_F, 0)!=-1 && msg->to)) && (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) ) { calc_crc_suffix( msg, tag_suffix ); buf.s = build_res_buf_from_sip_req( code, text, &sl_tag, msg, (unsigned int*)&buf.len, &dummy_bm); } else { buf.s = build_res_buf_from_sip_req( code, text, 0, msg, (unsigned int*)&buf.len, &dummy_bm); } if (!buf.s) { LM_ERR("response building failed\n"); goto error; } run_sl_callbacks( SLCB_REPLY_OUT, msg, &buf, code, text, &to ); /* supress multhoming support when sending a reply back -- that makes sure that replies will come from where requests came in; good for NATs (there is no known use for mhomed for locally generated replies; note: forwarded cross-interface replies do benefit of mhomed! */ backup_mhomed=mhomed; mhomed=0; /* use for sending the received interface -bogdan*/ ret = msg_send( msg->rcv.bind_address, msg->rcv.proto, &to, msg->rcv.proto_reserved1, buf.s, buf.len); mhomed=backup_mhomed; pkg_free(buf.s); if (ret<0) goto error; *(sl_timeout) = get_ticks() + SL_RPL_WAIT_TIME; update_sl_reply_stat(code); return 1; error: return -1; }