int send_leg_msg(struct dlg_cell *dlg,str *method,int src_leg,int dst_leg, str *hdrs,str *body,dlg_request_callback func,void *param,dlg_release_func release) { context_p old_ctx; dlg_t* dialog_info; int result; unsigned int method_type; if (parse_method(method->s,method->s+method->len,&method_type) == 0) { LM_ERR("Failed to parse method - [%.*s]\n",method->len,method->s); return -1; } if (method_type == METHOD_INVITE && (body == NULL || body->s == NULL || body->len == 0)) { LM_ERR("Cannot send INVITE without SDP body\n"); return -1; } if ((dialog_info = build_dialog_info(dlg, dst_leg, src_leg)) == 0) { LM_ERR("failed to create dlg_t\n"); return -1; } LM_DBG("sending [%.*s] to %s (%d)\n",method->len,method->s, (dst_leg==DLG_CALLER_LEG)?"caller":"callee", dst_leg); /* set new processing context */ if (push_new_processing_context( dlg, &old_ctx, NULL)!=0) return -1; dialog_info->T_flags=T_NO_AUTOACK_FLAG; result = d_tmb.t_request_within (method, /* method*/ hdrs, /* extra headers*/ body, /* body*/ dialog_info, /* dialog structure*/ func, /* callback function*/ param, /* callback parameter*/ release); /* release function*/ /* reset the processing contect */ current_processing_ctx = old_ctx; if(result < 0) { LM_ERR("failed to send the in-dialog request\n"); free_tm_dlg(dialog_info); return -1; } free_tm_dlg(dialog_info); return 0; }
/* send keep-alive * dlg - pointer to a struct dlg_cell * dir - direction: the request will be sent to: * DLG_CALLER_LEG (0): caller * DLG_CALLEE_LEG (1): callee */ int dlg_send_ka(dlg_cell_t *dlg, int dir, str *hdrs) { uac_req_t uac_r; dlg_t* di; str met = {"OPTIONS", 7}; int result; dlg_iuid_t *iuid = NULL; /* do not send KA request for non-confirmed dialogs (not supported) */ if (dlg->state != DLG_STATE_CONFIRMED) { LM_DBG("skipping non-confirmed dialogs\n"); return 0; } /* build tm dlg by direction */ if ((di = build_dlg_t(dlg, dir)) == 0){ LM_ERR("failed to create dlg_t\n"); goto err; } /* tm increases cseq value, decrease it no to make it invalid * - dialog is ended on timeout (408) or C/L does not exist (481) */ if(di->loc_seq.value>1) di->loc_seq.value -= 2; else di->loc_seq.value -= 1; LM_DBG("sending BYE to %s\n", (dir==DLG_CALLER_LEG)?"caller":"callee"); iuid = dlg_get_iuid_shm_clone(dlg); if(iuid==NULL) { LM_ERR("failed to create dialog unique id clone\n"); goto err; } memset(&uac_r,'\0', sizeof(uac_req_t)); set_uac_req(&uac_r, &met, hdrs, NULL, di, TMCB_LOCAL_COMPLETED, dlg_ka_cb, (void*)iuid); result = d_tmb.t_request_within(&uac_r); if(result < 0){ LM_ERR("failed to send the BYE request\n"); goto err; } free_tm_dlg(di); LM_DBG("keep-alive sent to %s\n", (dir==0)?"caller":"callee"); return 0; err: if(di) free_tm_dlg(di); return -1; }
static int dlg_refer_callee(dlg_transfer_ctx_t *dtc) { /*verify direction*/ dlg_t* dialog_info = NULL; str met = {"REFER", 5}; int result; str hdrs; struct dlg_cell *dlg; uac_req_t uac_r; dlg = dtc->dlg; if ((dialog_info = build_dlg_t(dlg, DLG_CALLEE_LEG)) == 0){ LM_ERR("failed to create dlg_t\n"); goto error; } hdrs.len = 23 + 2*CRLF_LEN + dlg_bridge_controller.len + dtc->to.len + dlg_bridge_ref_hdrs.len; LM_DBG("sending REFER [%d] <%.*s>\n", hdrs.len, dtc->to.len, dtc->to.s); hdrs.s = (char*)pkg_malloc(hdrs.len*sizeof(char)); if(hdrs.s == NULL) goto error; memcpy(hdrs.s, "Referred-By: ", 13); memcpy(hdrs.s+13, dlg_bridge_controller.s, dlg_bridge_controller.len); memcpy(hdrs.s+13+dlg_bridge_controller.len, CRLF, CRLF_LEN); memcpy(hdrs.s+13+dlg_bridge_controller.len+CRLF_LEN, "Refer-To: ", 10); memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN, dtc->to.s, dtc->to.len); memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN+dtc->to.len, CRLF, CRLF_LEN); memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN+dtc->to.len+CRLF_LEN, dlg_bridge_ref_hdrs.s, dlg_bridge_ref_hdrs.len); set_uac_req(&uac_r, &met, &hdrs, NULL, dialog_info, TMCB_LOCAL_COMPLETED, dlg_refer_tm_callback, (void*)dtc); result = d_tmb.t_request_within(&uac_r); pkg_free(hdrs.s); if(result < 0) { LM_ERR("failed to send the REFER request\n"); /* todo: clean-up dtc */ goto error; } free_tm_dlg(dialog_info); LM_DBG("REFER sent\n"); return 0; error: if(dialog_info) free_tm_dlg(dialog_info); return -1; }
void dlg_refer_tm_callback(struct cell *t, int type, struct tmcb_params *ps) { dlg_transfer_ctx_t *dtc = NULL; dlg_t* dialog_info = NULL; str met = {"BYE", 3}; int result; struct dlg_cell *dlg; uac_req_t uac_r; 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("REFER completed with status %d\n", ps->code); /* we send the BYE anyhow */ dlg = dtc->dlg; if ((dialog_info = build_dlg_t(dlg, DLG_CALLEE_LEG)) == 0){ LM_ERR("failed to create dlg_t\n"); goto error; } /* after REFER, the CSeq must be increased */ dialog_info->loc_seq.value++; set_uac_req(&uac_r, &met, NULL, NULL, dialog_info, 0, NULL, NULL); result = d_tmb.t_request_within(&uac_r); if(result < 0) { LM_ERR("failed to send the REFER request\n"); /* todo: clean-up dtc */ goto error; } free_tm_dlg(dialog_info); dlg_transfer_ctx_free(dtc); LM_DBG("BYE sent\n"); return; error: dlg_transfer_ctx_free(dtc); if(dialog_info) free_tm_dlg(dialog_info); return; }
/* cell- pointer to a struct dlg_cell * dir- direction: the request will be sent to: * DLG_CALLER_LEG (0): caller * DLG_CALLEE_LEG (1): callee */ static inline int send_bye(struct dlg_cell * cell, int dir, str *hdrs) { uac_req_t uac_r; dlg_t* dialog_info; str met = {"BYE", 3}; int result; dlg_iuid_t *iuid = NULL; /* do not send BYE request for non-confirmed dialogs (not supported) */ if (cell->state != DLG_STATE_CONFIRMED_NA && cell->state != DLG_STATE_CONFIRMED) { LM_ERR("terminating non-confirmed dialogs not supported\n"); return -1; } /*verify direction*/ if ((dialog_info = build_dlg_t(cell, dir)) == 0){ LM_ERR("failed to create dlg_t\n"); goto err; } LM_DBG("sending BYE to %s\n", (dir==DLG_CALLER_LEG)?"caller":"callee"); iuid = dlg_get_iuid_shm_clone(cell); if(iuid==NULL) { LM_ERR("failed to create dialog unique id clone\n"); goto err; } memset(&uac_r,'\0', sizeof(uac_req_t)); set_uac_req(&uac_r, &met, hdrs, NULL, dialog_info, TMCB_LOCAL_COMPLETED, bye_reply_cb, (void*)iuid); result = d_tmb.t_request_within(&uac_r); if(result < 0){ LM_ERR("failed to send the BYE request\n"); goto err; } free_tm_dlg(dialog_info); LM_DBG("BYE sent to %s\n", (dir==0)?"caller":"callee"); return 0; err: if(dialog_info) free_tm_dlg(dialog_info); return -1; }
dlg_t * build_dlg_t(struct dlg_cell * cell, int dir){ dlg_t* td = NULL; str cseq; unsigned int loc_seq; td = (dlg_t*)pkg_malloc(sizeof(dlg_t)); if(!td){ LM_ERR("out of pkg memory\n"); return NULL; } memset(td, 0, sizeof(dlg_t)); /*local sequence number*/ cseq = (dir == DLG_CALLER_LEG) ? cell->cseq[DLG_CALLEE_LEG]: cell->cseq[DLG_CALLER_LEG]; if(str2int(&cseq, &loc_seq) != 0){ LM_ERR("invalid cseq\n"); goto error; } /*we don not increase here the cseq as this will be done by TM*/ td->loc_seq.value = loc_seq; td->loc_seq.is_set = 1; /*route set*/ if( cell->route_set[dir].s && cell->route_set[dir].len){ if( parse_rr_body(cell->route_set[dir].s, cell->route_set[dir].len, &td->route_set) !=0){ LM_ERR("failed to parse route set\n"); goto error; } } /*remote target--- Request URI*/ if(cell->contact[dir].s==0 || cell->contact[dir].len==0){ LM_ERR("no contact available\n"); goto error; } td->rem_target = cell->contact[dir]; td->rem_uri = (dir == DLG_CALLER_LEG)? cell->from_uri: cell->to_uri; td->loc_uri = (dir == DLG_CALLER_LEG)? cell->to_uri: cell->from_uri; td->id.call_id = cell->callid; td->id.rem_tag = cell->tag[dir]; td->id.loc_tag = (dir == DLG_CALLER_LEG) ? cell->tag[DLG_CALLEE_LEG]: cell->tag[DLG_CALLER_LEG]; td->state= DLG_CONFIRMED; td->send_sock = cell->bind_addr[dir]; return td; error: free_tm_dlg(td); return NULL; }
/* cell- pointer to a struct dlg_cell * leg - a dialog leg to be BYE'ed : * = 0: caller leg * > 0: callee legs */ static inline int send_leg_bye(struct dlg_cell *cell, int dst_leg, int src_leg, str *extra_hdrs) { context_p old_ctx; context_p *new_ctx; dlg_t* dialog_info; str met = {"BYE", 3}; int result; if ((dialog_info = build_dlg_t(cell, dst_leg, src_leg)) == 0){ LM_ERR("failed to create dlg_t\n"); goto err; } LM_DBG("sending BYE to %s (%d)\n", (dst_leg==DLG_CALLER_LEG)?"caller":"callee", dst_leg); /* set new processing context */ if (push_new_processing_context( cell, &old_ctx, &new_ctx, NULL)!=0) goto err; ctx_lastdstleg_set(dst_leg); ref_dlg(cell, 1); result = d_tmb.t_request_within (&met, /* method*/ extra_hdrs, /* extra headers*/ NULL, /* body*/ dialog_info, /* dialog structure*/ bye_reply_cb, /* callback function*/ (void*)cell, /* callback parameter*/ NULL); /* release function*/ /* reset the processing contect */ if (current_processing_ctx == NULL) *new_ctx = NULL; else context_destroy(CONTEXT_GLOBAL, *new_ctx); current_processing_ctx = old_ctx; if(result < 0){ LM_ERR("failed to send the BYE request\n"); goto err1; } free_tm_dlg(dialog_info); LM_DBG("BYE sent to %s\n", (dst_leg==DLG_CALLER_LEG)?"caller":"callee"); return 0; err1: unref_dlg(cell, 1); err: return -1; }
/* cell- pointer to a struct dlg_cell * leg - a dialog leg to be BYE'ed : * = 0: caller leg * > 0: callee legs */ static inline int send_leg_bye(struct dlg_cell *cell, int dst_leg, int src_leg, str *extra_hdrs) { dlg_t* dialog_info; struct dlg_cell *old_cell; str met = {"BYE", 3}; int result; if ((dialog_info = build_dlg_t(cell, dst_leg, src_leg)) == 0){ LM_ERR("failed to create dlg_t\n"); goto err; } LM_DBG("sending BYE to %s (%d)\n", (dst_leg==DLG_CALLER_LEG)?"caller":"callee", dst_leg); ref_dlg(cell, 1); old_cell = current_dlg_pointer; current_dlg_pointer = cell; result = d_tmb.t_request_within (&met, /* method*/ extra_hdrs, /* extra headers*/ NULL, /* body*/ dialog_info, /* dialog structure*/ bye_reply_cb, /* callback function*/ (void*)cell, /* callback parameter*/ NULL); /* release function*/ current_dlg_pointer = old_cell; if(result < 0){ LM_ERR("failed to send the BYE request\n"); goto err1; } free_tm_dlg(dialog_info); LM_DBG("BYE sent to %s\n", (dst_leg==DLG_CALLER_LEG)?"caller":"callee"); return 0; err1: unref_dlg(cell, 1); err: return -1; }
dlg_t * build_dlg_t(struct dlg_cell * cell, int dir) { dlg_t* td = NULL; str cseq; unsigned int loc_seq; str route_set; str contact; struct dlg_cell_out *dlg_out = 0; struct dlg_entry_out* dlg_entry_out = 0; /* if trying to send by to callee we need to get the corresponding dlg_out cell */ lock_get(cell->dlg_out_entries_lock); dlg_entry_out = &cell->dlg_entry_out; dlg_out = dlg_entry_out->first; //must be concurrent call - lets choose - TODO - ie. check if there is more if (!dlg_out) { LM_ERR("Trying to send BYE for dialog with no callee leg\n"); lock_release(cell->dlg_out_entries_lock); return NULL; } td = (dlg_t*) pkg_malloc(sizeof (dlg_t)); if (!td) { LM_ERR("out of pkg memory\n"); lock_release(cell->dlg_out_entries_lock); return NULL; } memset(td, 0, sizeof (dlg_t)); if (dir == DLG_CALLER_LEG) { cseq = dlg_out->callee_cseq; route_set = cell->caller_route_set; contact = cell->caller_contact; td->rem_uri = cell->from_uri; td->loc_uri = dlg_out->to_uri; td->id.rem_tag = cell->from_tag; td->id.loc_tag = dlg_out->to_tag; td->send_sock = cell->caller_bind_addr; } else { cseq = dlg_out->caller_cseq; route_set = dlg_out->callee_route_set; contact = dlg_out->callee_contact; td->rem_uri = dlg_out->to_uri; td->loc_uri = cell->from_uri; td->id.rem_tag = dlg_out->to_tag; td->id.loc_tag = cell->from_tag; td->send_sock = dlg_out->callee_bind_addr; } if (str2int(&cseq, &loc_seq) != 0) { LM_ERR("invalid cseq\n"); goto error; } /*we don not increase here the cseq as this will be done by TM*/ td->loc_seq.value = loc_seq; td->loc_seq.is_set = 1; LM_DBG("CSeq is '%.*s' (%i)\n", cseq.len, cseq.s, loc_seq); /*route set*/ if (route_set.s && route_set.len) { if (parse_rr_body(route_set.s, route_set.len, &td->route_set) != 0) { LM_ERR("failed to parse route set\n"); goto error; } } if (contact.s == 0 || contact.len == 0) { LM_ERR("no contact available\n"); goto error; } td->id.call_id = cell->callid; td->rem_target = contact; td->state = DLG_CONFIRMED; lock_release(cell->dlg_out_entries_lock); return td; error: lock_release(cell->dlg_out_entries_lock); free_tm_dlg(td); return NULL; }
dlg_t * build_dlg_t(struct dlg_cell * cell, int dst_leg, int src_leg) { dlg_t* td = NULL; str cseq; unsigned int loc_seq; td = (dlg_t*)pkg_malloc(sizeof(dlg_t)); if(!td){ LM_ERR("out of pkg memory\n"); return NULL; } memset(td, 0, sizeof(dlg_t)); if ((dst_leg == DLG_CALLER_LEG && (cell->flags & DLG_FLAG_PING_CALLER)) || (dst_leg == callee_idx(cell) && (cell->flags & DLG_FLAG_PING_CALLEE))) { dlg_lock_dlg(cell); if (cell->legs[dst_leg].last_gen_cseq == 0) { /* no OPTIONS pings for this dlg yet */ dlg_unlock_dlg(cell); goto before_strcseq; } else { /* OPTIONS pings sent, use new cseq */ td->loc_seq.value = ++(cell->legs[dst_leg].last_gen_cseq); td->loc_seq.is_set=1; dlg_unlock_dlg(cell); goto after_strcseq; } } before_strcseq: /*local sequence number*/ cseq = cell->legs[dst_leg].r_cseq; if( !cseq.s || !cseq.len || str2int(&cseq, &loc_seq) != 0){ LM_ERR("invalid cseq\n"); goto error; } /*we don not increase here the cseq as this will be done by TM*/ td->loc_seq.value = loc_seq; td->loc_seq.is_set = 1; after_strcseq: /*route set*/ if( cell->legs[dst_leg].route_set.s && cell->legs[dst_leg].route_set.len){ if( parse_rr_body(cell->legs[dst_leg].route_set.s, cell->legs[dst_leg].route_set.len, &td->route_set) !=0){ LM_ERR("failed to parse route set\n"); goto error; } } /*remote target--- Request URI*/ if (cell->legs[dst_leg].contact.s==0 || cell->legs[dst_leg].contact.len==0){ LM_ERR("no contact available\n"); goto error; } td->rem_target = cell->legs[dst_leg].contact; td->rem_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_from_uri(cell,dst_leg): *dlg_leg_to_uri(cell,dst_leg); td->loc_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_to_uri(cell,dst_leg): *dlg_leg_from_uri(cell,dst_leg); td->id.call_id = cell->callid; td->id.rem_tag = cell->legs[dst_leg].tag; td->id.loc_tag = cell->legs[src_leg].tag; td->state= DLG_CONFIRMED; td->send_sock = cell->legs[dst_leg].bind_addr; return td; error: free_tm_dlg(td); return NULL; }
dlg_t * build_dialog_info(struct dlg_cell * cell, int dst_leg, int src_leg) { dlg_t* td = NULL; str cseq; unsigned int loc_seq; td = (dlg_t*)pkg_malloc(sizeof(dlg_t)); if(!td){ LM_ERR("out of pkg memory\n"); return NULL; } memset(td, 0, sizeof(dlg_t)); /*local sequence number*/ cseq = cell->legs[dst_leg].r_cseq; if( !cseq.s || !cseq.len || str2int(&cseq, &loc_seq) != 0){ LM_ERR("invalid cseq\n"); goto error; } if (cell->legs[dst_leg].last_gen_cseq == 0) cell->legs[dst_leg].last_gen_cseq = loc_seq+1; else cell->legs[dst_leg].last_gen_cseq++; cell->legs[dst_leg].reply_received = 0; td->loc_seq.value = cell->legs[dst_leg].last_gen_cseq -1; td->loc_seq.is_set = 1; /*route set*/ if( cell->legs[dst_leg].route_set.s && cell->legs[dst_leg].route_set.len){ if( parse_rr_body(cell->legs[dst_leg].route_set.s, cell->legs[dst_leg].route_set.len, &td->route_set) !=0){ LM_ERR("failed to parse route set\n"); goto error; } } /*remote target--- Request URI*/ if (cell->legs[dst_leg].contact.s==0 || cell->legs[dst_leg].contact.len==0){ LM_ERR("no contact available\n"); goto error; } td->rem_target = cell->legs[dst_leg].contact; td->rem_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_from_uri(cell,dst_leg): *dlg_leg_to_uri(cell,dst_leg); td->loc_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_to_uri(cell,dst_leg): *dlg_leg_from_uri(cell,dst_leg); td->id.call_id = cell->callid; td->id.rem_tag = cell->legs[dst_leg].tag; td->id.loc_tag = cell->legs[src_leg].tag; td->state= DLG_CONFIRMED; td->send_sock = cell->legs[dst_leg].bind_addr; return td; error: free_tm_dlg(td); return NULL; }