/*Actions are composed as follows: * (the action length and type as always= 5 bytes) * 4:uac_id * * int request(str* method, str* req_uri, str* to, str* from, str* headers, str* body, transaction_cb c, void* cp) * TODO performance speedup: instead of using * dynamically allocated memory for headers,body,totag,reason and my_msg * use static buffers. * */ int ac_uac_req(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len) { unsigned int cseq; char err_buf[MAX_REASON_LEN]; struct sip_msg *my_msg; struct to_body *fb,*tb; struct cseq_body *cseqb; struct as_uac_param *the_param; dlg_t *my_dlg; int k,retval,uac_id,sip_error,ret,err_ret; long clen; str headers,body,fake_uri; uac_req_t uac_r; headers.s=body.s=fake_uri.s=NULL; my_dlg=NULL; my_msg=NULL; the_param=NULL; k=clen=0; net2hostL(uac_id,action,k); if(!(headers.s=pkg_malloc(MAX_HEADER))){ LM_ERR("Out of Memory!!"); goto error; } headers.len=0; LM_DBG("Action UAC Message: uac_id:%d processor_id=%d\n",uac_id,processor_id); if (!(my_msg = parse_ac_msg(HDR_EOH_F,action+k,len-k))) { LM_ERR("out of memory!\n"); goto error; } if(my_msg->first_line.type==SIP_REPLY){ LM_ERR("trying to create a UAC with a SIP response!!\n"); goto error; } if(parse_headers(my_msg,HDR_EOH_F,0)==-1){ LM_ERR("ERROR:seas:ac_uac_req:parsing headers\n"); goto error; } if(parse_from_header(my_msg)<0){ LM_ERR("parsing from header ! \n"); goto error; } if(check_transaction_quadruple(my_msg)==0){ as_action_fail_resp(uac_id,SE_UAC,"Headers missing (to,from,call-id,cseq)?",0); LM_ERR("Headers missing (to,from,call-id,cseq)?"); goto error; } if(!(get_from(my_msg)) || !(get_from(my_msg)->tag_value.s) || !(get_from(my_msg)->tag_value.len)){ as_action_fail_resp(uac_id,SE_UAC,"From tag missing",0); LM_ERR("From tag missing"); goto error; } fb=my_msg->from->parsed; tb=my_msg->to->parsed; cseqb=my_msg->cseq->parsed; if(0!=(str2int(&cseqb->number,&cseq))){ LM_DBG("unable to parse CSeq\n"); goto error; } if(my_msg->first_line.u.request.method_value != METHOD_ACK && my_msg->first_line.u.request.method_value != METHOD_CANCEL) { /** we trick req_within */ cseq--; } if(seas_f.tmb.new_dlg_uac(&(my_msg->callid->body),&(fb->tag_value),cseq,\ &(fb->uri),&(tb->uri),&my_dlg) < 0) { as_action_fail_resp(uac_id,SE_UAC,"Error creating new dialog",0); LM_ERR("Error while creating new dialog\n"); goto error; } if(seas_f.tmb.dlg_add_extra(my_dlg,&(fb->display),&(tb->display)) < 0 ) { as_action_fail_resp(uac_id,SE_UAC, "Error adding the display names to the new dialog",0); LM_ERR("failed to add display names to the new dialog\n"); goto error; } if(tb->tag_value.s && tb->tag_value.len) shm_str_dup(&my_dlg->id.rem_tag,&tb->tag_value); /**Awful hack: to be able to set our own CSeq, from_tag and call-ID we have * to use req_within instead of req_outside (it sets it's own CSeq,Call-ID * and ftag), so we have to simulate that the dialog is already in completed * state so... */ server_signature=0; my_dlg->state = DLG_CONFIRMED; if(0>(headers.len=extract_allowed_headers(my_msg,1,-1,HDR_CONTENTLENGTH_F|HDR_ROUTE_F|HDR_TO_F|HDR_FROM_F|HDR_CALLID_F|HDR_CSEQ_F,headers.s,MAX_HEADER))) { LM_ERR("Unable to extract allowed headers!!\n"); goto error; } headers.s[headers.len]=0; /*let's get the body*/ if(my_msg->content_length) clen=(long)get_content_length(my_msg); if(clen!=0){ if(!(body.s=pkg_malloc(clen))){ LM_ERR("Out of Memory!"); goto error; } memcpy(body.s,get_body(my_msg),clen); body.len=clen; body.s[clen]=0; LM_DBG("Trying to construct a Sip Request with: body:%d[%.*s] headers:%d[%.*s]\n",\ body.len,body.len,body.s,headers.len,headers.len,headers.s); /*t_reply_with_body un-ref-counts the transaction, so dont use it anymore*/ }else{ body.s=NULL; body.len=0; } /*Now... create the UAC !! * it would be great to know the hash_index and the label that have been assigned * to our newly created cell, but t_uac does not leave any way for us to know... * only that when that transaction transitions its state (ie. a response is received, * a timeout is reached, etc...) the callback will be called with the given parameter. * * So the only way we have to know who we are, is passing as a parameter a structure with * 2 pointers: one to the app_server and the other, the identifier of the UAC (uac_id). * */ if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){ LM_ERR("out of shared memory\n"); goto error; } the_param->who=my_as; the_param->uac_id=uac_id; the_param->processor_id=processor_id; the_param->destroy_cb_set=0; shm_str_dup(&my_dlg->rem_target,&my_msg->first_line.u.request.uri); if (my_msg->route) { if (parse_rr(my_msg->route) < 0) { LM_ERR( "Error while parsing Route body\n"); goto error; } /* TODO route_set should be a shm copy of my_msg->route->parsed */ my_dlg->route_set=(rr_t*)my_msg->route->parsed; /** this SHOULD be: shm_duplicate_rr(&my_dlg->route_set,my_msg->route->parsed); * but it will last more... */ } calculate_hooks(my_dlg); if(flags & SPIRAL_FLAG){ memcpy(headers.s+headers.len,SPIRAL_HDR CRLF,SPIRAL_HDR_LEN + CRLF_LEN); headers.len+=SPIRAL_HDR_LEN+CRLF_LEN; headers.s[headers.len]=0; fake_uri.s=pkg_malloc(200); fake_uri.len=print_local_uri(the_as,processor_id,fake_uri.s,200); if(fake_uri.len<0){ LM_ERR("printing local uri\n"); goto error; } my_dlg->hooks.next_hop=&fake_uri; } /* Kamailio and OpenSIPs seem to have diverged quite a bit on flags and events notified to UACs. Let's see if kamailio gets it right by now, if not this is a TODO: check PASS_PROVISIONAL my_dlg->T_flags=T_NO_AUTO_ACK|T_PASS_PROVISIONAL_FLAG ; this is the same as (TMCB_DONT_ACK|TMCB_LOCAL_RESPONSE_OUT) in Kamailio */ set_uac_req(&uac_r, &(my_msg->first_line.u.request.method), &headers, &body, my_dlg,TMCB_DONT_ACK|TMCB_LOCAL_RESPONSE_OUT, uac_cb, (void*)the_param); ret=seas_f.tmb.t_request_within(&uac_r); /** now undo all the fakes we have put in my_dlg*/ /*because my_dlg->route_set should be shm but we fake it (its pkg_mem)*/ my_dlg->route_set=(rr_t *)0; if (ret < 0) { err_ret = err2reason_phrase(ret,&sip_error,err_buf, sizeof(err_buf), "SEAS/UAC"); LM_ERR("failed to send the [%.*s] request\n",uac_r.method->len,uac_r.method->s); LM_ERR("Error on request_within %s\n",err_buf ); if(err_ret > 0) { as_action_fail_resp(uac_id,ret,err_buf,0); }else{ as_action_fail_resp(uac_id,E_UNSPEC,"500 SEAS/UAC error",0); } goto error; } retval=0; goto exit; error: retval = -1; if(the_param) shm_free(the_param); exit: seas_f.tmb.free_dlg(my_dlg); if(headers.s) pkg_free(headers.s); if(body.s) pkg_free(body.s); if(fake_uri.s) pkg_free(fake_uri.s); if(my_msg){ if(my_msg->headers) free_hdr_field_lst(my_msg->headers); pkg_free(my_msg); } return retval; }
int ac_cancel(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len) { unsigned int ret,cancelled_hashIdx,cancelled_label,i; struct sip_msg *my_msg; struct as_uac_param *the_param; struct cell* t_invite; int k,retval,uac_id; str headers,body; body.s=headers.s=NULL; my_msg=NULL; the_param=NULL; i=k=0; net2hostL(uac_id,action,k); net2hostL(cancelled_hashIdx,action,k); net2hostL(cancelled_label,action,k); if(!(headers.s=pkg_malloc(MAX_HEADER))){ LM_ERR("Out of Memory!!"); goto error; } headers.len=0; if(!(my_msg=pkg_malloc(sizeof(struct sip_msg)))){ LM_ERR("out of memory!\n"); goto error; } memset(my_msg,0,sizeof(struct sip_msg)); my_msg->buf=action+k; my_msg->len=len-k; LM_DBG("Action UAC Message: uac_id:%d processor_id=%d, message:[%.*s]\n", uac_id,processor_id,len-4,&action[4]); if(parse_msg(action+k,len-k,my_msg)<0){ LM_ERR("parsing sip_msg"); goto error; } if(my_msg->first_line.type==SIP_REPLY){ LM_ERR("trying to create a UAC with a SIP response!!\n"); goto error; } if(parse_headers(my_msg,HDR_EOH_F,0)==-1){ LM_ERR("parsing headers\n"); goto error; } if(0>(headers.len=extract_allowed_headers(my_msg,1,-1,HDR_CONTENTLENGTH_F|HDR_ROUTE_F|HDR_TO_F|HDR_FROM_F|HDR_CALLID_F|HDR_CSEQ_F,headers.s,MAX_HEADER))) { LM_ERR("Unable to extract allowed headers!!\n"); goto error; } if(flags & SPIRAL_FLAG){ memcpy(headers.s+headers.len,SPIRAL_HDR CRLF,SPIRAL_HDR_LEN + CRLF_LEN); headers.len+=SPIRAL_HDR_LEN+CRLF_LEN; /*headers.s[headers.len]=0; fake_uri.s=pkg_malloc(200); fake_uri.len=print_local_uri(the_as,processor_id,fake_uri.s,200); if(fake_uri.len<0){ SLM_ERR("printing local uri\n"); goto error; } my_dlg->hooks.next_hop=&fake_uri;*/ } headers.s[headers.len]=0; /*let's get the body*/ i=(unsigned int)get_content_length(my_msg); if(i!=0){ if(!(body.s=pkg_malloc(i))){ LM_ERR("Out of Memory!"); goto error; } memcpy(body.s,get_body(my_msg),i); body.len=i; LM_DBG("Trying to construct a Sip Request with: body:%d[%s]" " headers:%d[%s]\n", body.len,body.s,headers.len,headers.s); }else{ body.s=NULL; body.len=0; } if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){ LM_ERR("no more share memory\n"); goto error; } if(seas_f.tmb.t_lookup_ident(&t_invite,cancelled_hashIdx,cancelled_label)<0){ LM_ERR("failed to t_lookup_ident hash_idx=%d," "label=%d\n", cancelled_hashIdx,cancelled_label); goto error; } seas_f.tmb.unref_cell(t_invite); the_param->who=my_as; the_param->uac_id=uac_id; the_param->processor_id=processor_id; the_param->destroy_cb_set=0; /* registers TMCB_RESPONSE_IN|TMCB_LOCAL_COMPLETED tm callbacks */ ret=seas_f.tmb.t_cancel_uac(&headers,&body,cancelled_hashIdx,cancelled_label,uac_cb,(void*)the_param); if (ret == 0) { LM_ERR( "t_cancel_uac failed\n"); as_action_fail_resp(uac_id,SE_CANCEL,SE_CANCEL_MSG,SE_CANCEL_MSG_LEN); goto error; }else{ the_param->label=ret; } seas_f.tmb.unref_cell(t_invite); retval=0; goto exit; error: retval = -1; if(the_param) shm_free(the_param); exit: if(headers.s) pkg_free(headers.s); if(body.s) pkg_free(headers.s); if(my_msg){ if(my_msg->headers) free_hdr_field_lst(my_msg->headers); pkg_free(my_msg); } return retval; }
/** * ac_reply: UAS transaction Reply action. It replies to an incoming request with a response. * @param the_as The App Server that sent this action. * @param action action * @param len length * * function description * * Returns: what */ int ac_reply(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len) { unsigned int hash_index,label,contentlength; struct cell *c=NULL; struct sip_msg *my_msg; struct to_body *tb; str new_header,body,totag; char *ttag; int i,k,retval; static char headers[MAX_HEADER]; struct as_uac_param *the_param; contentlength=0; ttag=NULL; my_msg=NULL; i=k=0; the_param=NULL; net2hostL(hash_index,action,k); net2hostL(label,action,k); if(seas_f.tmb.t_lookup_ident(&c,hash_index,label)<0){ LM_ERR("Failed to t_lookup_ident hash_idx=%d,label=%d\n",hash_index,label); goto error; } if(use_stats) action_stat(c); if(c->uas.status>=200){ LM_ERR("ac_reply: trying to reply to a \"%.*s\" transaction" "that is already in completed state\n",REQ_LINE(c->uas.request).method.len,REQ_LINE(c->uas.request).method.s); goto error; } if (!(my_msg=parse_ac_msg(HDR_EOH_F,action+k,len-k))) { LM_ERR("Failed to parse_ac_msg hash_idx=%d,label=%d\n",hash_index,label); goto error; } tb=(struct to_body*)my_msg->to->parsed; if(tb->tag_value.s && tb->tag_value.len){ totag=tb->tag_value; }else{ totag.s=NULL; totag.len=0; /*if(!(ttag=pkg_malloc(TOTAG_VALUE_LEN))){ LM_ERR("Out of memory !!!\n"); goto error; } totag.s=ttag; calc_crc_suffix(c->uas.request,seas_tag_suffix); LM_DBG("seas_tags = %.*s\n",TOTAG_VALUE_LEN,seas_tags); memcpy(totag.s,seas_tags,TOTAG_VALUE_LEN); totag.len=TOTAG_VALUE_LEN;*/ } LM_DBG("Using totag=[%.*s]\n",totag.len,totag.s); if(my_msg->content_length) contentlength=(unsigned int)(long)my_msg->content_length->parsed; if(0>(i=recordroute_diff(c->uas.request,my_msg))){/*not likely..*/ LM_DBG("Seems that request had more RecordRoutes than response...\n"); /* This prevents host->proxy->host from working. TODO review recordroute_diff code. goto error; */ }else LM_DBG("Recordroute Diff = %d\n",i); if(0>(i=extract_allowed_headers(my_msg,0,i,HDR_VIA_F|HDR_TO_F|HDR_FROM_F|HDR_CSEQ_F|HDR_CALLID_F|HDR_CONTENTLENGTH_F,headers,MAX_HEADER))){ LM_ERR("ac_reply() filtering headers !\n"); goto error; } headers[i]=0; new_header.s=headers; new_header.len=i; /* If it is INVITE and response is success (>=200 && <300), we mark it as local so that * SER does NOT retransmit the final response (by default, SER retransmit local UAS final * responses...*/ if(is_invite(c) && my_msg->first_line.u.reply.statuscode>=200 && my_msg->first_line.u.reply.statuscode<300){ c->flags |= T_IS_LOCAL_FLAG; if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){ LM_ERR("no more share memory\n"); goto error; } the_param->processor_id=processor_id; the_param->who=my_as; the_param->destroy_cb_set=0; if (seas_f.tmb.register_tmcb( 0, c, TMCB_E2EACK_IN,uas_e2e_ack_cb, the_param,¶m_free)<=0) { LM_ERR("cannot register additional callbacks\n"); goto error; } } /*WARNING casting unsigned int to int*/ body.len=contentlength; body.s=get_body(my_msg); LM_DBG("Trying to construct a SipReply with: ReasonPhrase:[%.*s] body:[%.*s] headers:[%.*s] totag:[%.*s]\n",\ my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.reason.s,\ body.len,body.s,new_header.len,new_header.s,totag.len,totag.s); /* t_reply_with_body un-ref-counts the transaction, so dont use it anymore*/ if(seas_f.tmb.t_reply_with_body(c,my_msg->first_line.u.reply.statuscode,&(my_msg->first_line.u.reply.reason),&body,&new_header,&totag)<0){ LM_ERR("Failed to t_reply\n"); goto error; } retval=0; goto exit; error: retval = -1; if(c) seas_f.tmb.unref_cell(c); if(the_param) shm_free(the_param); exit: if(ttag) pkg_free(ttag); if(my_msg){ free_sip_msg_lite(my_msg); pkg_free(my_msg); } return retval; }
/** * ac_reply: UAS transaction Reply action. It replies to an incoming request with a response. * @param the_as The App Server that sent this action. * @param action action * @param len length * * function description * * Returns: what */ int ac_reply(as_p the_as,char *action,int len) { unsigned int flags,hash_index,label; struct cell *c; struct sip_msg *my_msg; struct to_body *tb; str new_header,body,totag; char *ttag; int i,k,retval; static char headers[MAX_HEADER]; ttag=NULL; my_msg=NULL; i=k=0; net2hostL(flags,action,k); net2hostL(hash_index,action,k); net2hostL(label,action,k); if(seas_f.tmb.t_lookup_ident(&c,hash_index,label)<0){ LM_ERR("Failed to t_lookup_ident hash_idx=%d,label=%d\n",hash_index,label); goto error; } if(use_stats) action_stat(c); if(c->uas.status>=200){ LM_ERR("ac_reply: trying to reply to a \"%.*s\" transaction" "that is already in completed state\n",REQ_LINE(c->uas.request).method.len,REQ_LINE(c->uas.request).method.s); goto error; } if (!(my_msg=parse_ac_msg(HDR_EOH_F,action+k,len-k))) { LM_ERR("Failed to parse_ac_msg hash_idx=%d,label=%d\n",hash_index,label); goto error; } tb=(struct to_body*)my_msg->to->parsed; if(tb->tag_value.s && tb->tag_value.len){ totag=tb->tag_value; }else{ totag.s=NULL; totag.len=0; /*if(!(ttag=pkg_malloc(TOTAG_VALUE_LEN))){ LM_ERR("Out of memory !!!\n"); goto error; } totag.s=ttag; calc_crc_suffix(c->uas.request,seas_tag_suffix); LM_DBG("seas_tags = %.*s\n",TOTAG_VALUE_LEN,seas_tags); memcpy(totag.s,seas_tags,TOTAG_VALUE_LEN); totag.len=TOTAG_VALUE_LEN;*/ } LM_DBG("Using totag=[%.*s]\n",totag.len,totag.s); if(0>(i=recordroute_diff(c->uas.request,my_msg))){/*not likely..*/ LM_DBG("Seems that request had more RecordRoutes than response...\n"); goto error; }else LM_DBG("Recordroute Diff = %d\n",i); if(0>(i=extract_allowed_headers(my_msg,0,i,HDR_VIA_F|HDR_TO_F|HDR_FROM_F|HDR_CSEQ_F|HDR_CALLID_F|HDR_CONTENTLENGTH_F,headers,MAX_HEADER))){ LM_ERR("ac_reply() filtering headers !\n"); goto error; } headers[i]=0; new_header.s=headers; new_header.len=i; /* If it is INVITE and response is success (>=200 && <300), we mark it as local so that * SER does NOT retransmit the final response (by default, SER retransmit local UAS final * responses...*/ if(is_invite(c) && my_msg->first_line.u.reply.statuscode>=200 && my_msg->first_line.u.reply.statuscode<300) c->flags |= T_IS_LOCAL_FLAG; /*WARNING casting unsigned int to int*/ get_body(my_msg, &body); LM_DBG("Trying to construct a SipReply with: ReasonPhrase:[%.*s] body:[%.*s] headers:[%.*s] totag:[%.*s]\n",\ my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.reason.s,\ body.len,body.s,new_header.len,new_header.s,totag.len,totag.s); if(seas_f.tmb.t_reply_with_body(c,my_msg->first_line.u.reply.statuscode, &(my_msg->first_line.u.reply.reason),&body,&new_header,&totag)<0){ LM_ERR("Failed to t_reply\n"); goto error; } seas_f.tmb.unref_cell(c); retval=0; goto exit; error: retval = -1; seas_f.tmb.unref_cell(c); exit: if(ttag) pkg_free(ttag); if(my_msg){ free_sip_msg_lite(my_msg); pkg_free(my_msg); } return retval; }