static int kill_transaction( struct cell *trans ) { char err_buffer[128]; int sip_err; int reply_ret; int ret; str reason; /* we reply statefully and enter WAIT state since error might have occurred in middle of forking and we do not want to put the forking burden on upstream client; however, it may fail too due to lack of memory */ ret=err2reason_phrase( ser_error, &sip_err, err_buffer, sizeof(err_buffer), "TM" ); if (ret>0) { reason.s = err_buffer; reason.len = ret; reply_ret=t_reply( trans, trans->uas.request, sip_err, &reason); /* t_release_transaction( T ); */ return reply_ret; } else { LM_ERR("err2reason failed\n"); return -1; } }
int sl_reply_error(struct sip_msg *msg ) { static char err_buf[MAX_REASON_LEN]; int sip_error; int ret; ret=err2reason_phrase( prev_ser_error, &sip_error, err_buf, sizeof(err_buf), "SL"); if (ret>0) { sl_send_reply( msg, sip_error, err_buf ); LOG(L_ERR, "ERROR: sl_reply_error used: %s\n", err_buf ); return 1; } else { LOG(L_ERR, "ERROR: sl_reply_error: err2reason failed\n"); return -1; } }
int sl_reply_error(struct sip_msg *msg ) { char err_buf[MAX_REASON_LEN]; int sip_error; str text; int ret; ret = err2reason_phrase( prev_ser_error, &sip_error, err_buf, sizeof(err_buf), "SL"); if (ret<=0) { LM_ERR("err2reason failed\n"); return -1; } text.len = ret; text.s = err_buf; LM_DBG("error text is %.*s\n",text.len,text.s); ret = sl_send_reply_helper( msg, sip_error, &text); if (ret==-1) return -1; if_update_stat( sl_enable_stats, sent_err_rpls , 1); return ret; }
/*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; }
static void pua_rpc_publish(rpc_t* rpc, void* c) { str pres_uri, expires, event, content_type, id, etag, outbound_proxy, extra_headers, body; rpc_delayed_ctx_t* dctx; int exp, sign, ret, err_ret, sip_error; char err_buf[MAX_REASON_LEN]; struct sip_uri uri; publ_info_t publ; body.s = 0; body.len = 0; dctx = 0; LM_DBG("rpc publishing ...\n"); if ((rpc->capabilities == 0) || !(rpc->capabilities(c) & RPC_DELAYED_REPLY)) { rpc->fault(c, 600, "Reply wait/async mode not supported" " by this rpc transport"); return; } ret = rpc->scan(c, "SSSSSSSS*S", &pres_uri, &expires, &event, &content_type, &id, &etag, &outbound_proxy, &extra_headers, &body); if (ret < 8) { rpc->fault(c, 400, "Too few or wrong type of parameters (%d)", ret); return; } if (parse_uri(pres_uri.s, pres_uri.len, &uri) <0) { LM_ERR("bad resentity uri\n"); rpc->fault(c, 400, "Invalid presentity uri '%s'", pres_uri.s); return; } LM_DBG("presentity uri '%.*s'\n", pres_uri.len, pres_uri.s); if (expires.s[0]== '-') { sign= -1; expires.s++; expires.len--; } else { sign = 1; } if (str2int(&expires, (unsigned int*)&exp) < 0) { LM_ERR("invalid expires parameter\n" ); rpc->fault(c, 400, "Invalid expires value '%s'", expires.s); return; } exp = exp * sign; LM_DBG("expires '%d'\n", exp); LM_DBG("event '%.*s'\n", event.len, event.s); LM_DBG("content type '%.*s'\n", content_type.len, content_type.s); LM_DBG("id '%.*s'\n", id.len, id.s); LM_DBG("ETag '%.*s'\n", etag.len, etag.s); LM_DBG("outbound_proxy '%.*s'\n", outbound_proxy.len, outbound_proxy.s); LM_DBG("extra headers '%.*s'\n", extra_headers.len, extra_headers.s); if (body.len > 0) LM_DBG("body '%.*s'\n", body.len, body.s); if ((body.s == 0) && (content_type.len != 1 || content_type.s[0] != '.')) { LM_ERR("body is missing, but content type is not .\n"); rpc->fault(c, 400, "Body is missing"); return; } memset(&publ, 0, sizeof(publ_info_t)); publ.pres_uri= &pres_uri; publ.expires= exp; publ.event= get_event_flag(&event); if (publ.event < 0) { LM_ERR("unknown event '%.*s'\n", event.len, event.s); rpc->fault(c, 400, "Unknown event"); return; } if (content_type.len != 1) { publ.content_type= content_type; } if (!((id.len == 1) && (id.s[0]== '.'))) { publ.id= id; } if (!((etag.len== 1) && (etag.s[0]== '.'))) { publ.etag= &etag; } if (!((outbound_proxy.len == 1) && (outbound_proxy.s[0] == '.'))) { publ.outbound_proxy = &outbound_proxy; } if (!((extra_headers.len == 1) && (extra_headers.s[0] == '.'))) { publ.extra_headers = &extra_headers; } if (body.s != 0) { publ.body= &body; } dctx = rpc->delayed_ctx_new(c); if (dctx == 0) { LM_ERR("internal error: failed to create context\n"); rpc->fault(c, 500, "Internal error: failed to create context"); return; } publ.cb_param = dctx; publ.source_flag = MI_ASYN_PUBLISH; ret = pua_rpc_api.send_publish(&publ); LM_DBG("pua send_publish returned %d\n", ret); if (dctx->reply_ctx != 0) { /* callback was not executed or its execution failed */ rpc = &dctx->rpc; c = dctx->reply_ctx; } else { return; } if (ret < 0) { LM_ERR("pua send_publish failed\n"); err_ret = err2reason_phrase(ret, &sip_error, err_buf, sizeof(err_buf), "RPC/PUBLISH") ; if (err_ret > 0 ) { rpc->fault(c, sip_error, "%s", err_buf); } else { rpc->fault(c, 500, "RPC/PUBLISH error"); } rpc->delayed_ctx_close(dctx); } if (ret == 418) { rpc->fault(c, 500, "Wrong ETag"); rpc->delayed_ctx_close(dctx); } return; }
/** rpc t_uac version- * It expects the following list of strings as parameters: * method * request_uri * dst_uri (next hop) -- can be empty (either "" or ".", which is still * supported for backwards compatibility with fifo) * send_socket (socket from which the message will be sent) * headers (message headers separated by CRLF, at least From and To * must be present) * body (optional, might be null or completely missing) * * If all the parameters are ok it will call t_uac() using them. * Note: this version will wait for the transaction final reply * only if reply_wait is set to 1. Otherwise the rpc reply will be sent * immediately and it will be success if the paremters were ok and t_uac did * not report any error. * Note: reply waiting (reply_wait==1) is not yet supported. * @param rpc - rpc handle * @param c - rpc current context * @param reply_wait - if 1 do not generate a rpc reply until final response * for the transaction arrives, if 0 immediately send * an rpc reply (see above). */ static void rpc_t_uac(rpc_t* rpc, void* c, int reply_wait) { /* rpc params */ str method, ruri, nexthop, send_socket, headers, body; /* other internal vars.*/ str hfb, callid; struct sip_uri p_uri, pnexthop; struct sip_msg faked_msg; struct socket_info* ssock; str saddr; int sport, sproto; int ret, sip_error, err_ret, fromtag, cseq_is, cseq; char err_buf[MAX_REASON_LEN]; dlg_t dlg; uac_req_t uac_req; rpc_delayed_ctx_t* dctx; body.s=0; body.len=0; dctx=0; if (reply_wait && (rpc->capabilities == 0 || !(rpc->capabilities(c) & RPC_DELAYED_REPLY))) { rpc->fault(c, 600, "Reply wait/async mode not supported" " by this rpc transport"); return; } ret=rpc->scan(c, "SSSSS*S", &method, &ruri, &nexthop, &send_socket, &headers, &body); if (ret<5 && ! (-ret == 5)){ rpc->fault(c, 400, "too few parameters (%d/5)", ret?ret:-ret); return; } /* check and parse parameters */ if (method.len==0){ rpc->fault(c, 400, "Empty method"); return; } if (parse_uri(ruri.s, ruri.len, &p_uri)<0){ rpc->fault(c, 400, "Invalid request uri \"%s\"", ruri.s); return; } /* old fifo & unixsock backwards compatibility for nexthop: '.' is still allowed */ if (nexthop.len==1 && nexthop.s[0]=='.'){ /* empty nextop */ nexthop.len=0; nexthop.s=0; }else if (nexthop.len==0){ nexthop.s=0; }else if (parse_uri(nexthop.s, nexthop.len, &pnexthop)<0){ rpc->fault(c, 400, "Invalid next-hop uri \"%s\"", nexthop.s); return; } /* kamailio backwards compatibility for send_socket: '.' is still allowed for an empty socket */ ssock=0; saddr.s=0; saddr.len=0; if (send_socket.len==1 && send_socket.s[0]=='.'){ /* empty send socket */ send_socket.len=0; }else if (send_socket.len && (parse_phostport(send_socket.s, &saddr.s, &saddr.len, &sport, &sproto)!=0 || /* check also if it's not a MH addr. */ saddr.len==0 || saddr.s[0]=='(') ){ rpc->fault(c, 400, "Invalid send socket \"%s\"", send_socket.s); return; }else if (saddr.len && (ssock=grep_sock_info(&saddr, sport, sproto))==0){ rpc->fault(c, 400, "No local socket for \"%s\"", send_socket.s); return; } /* check headers using the SIP parser to look in the header list */ memset(&faked_msg, 0, sizeof(struct sip_msg)); faked_msg.len=headers.len; faked_msg.buf=faked_msg.unparsed=headers.s; if (parse_headers(&faked_msg, HDR_EOH_F, 0)==-1){ rpc->fault(c, 400, "Invalid headers"); return; } /* at this moment all the parameters are parsed => more sanity checks */ if (rpc_uac_check_msg(rpc, c, &faked_msg, &method, &body, &fromtag, &cseq_is, &cseq, &callid)<0) goto error; hfb.s=get_hfblock(nexthop.len? &nexthop: &ruri, faked_msg.headers, PROTO_NONE, ssock, &hfb.len); if (hfb.s==0){ rpc->fault(c, 500, "out of memory"); goto error; } /* proceed to transaction creation */ memset(&dlg, 0, sizeof(dlg_t)); /* fill call-id if call-id present or else generate a callid */ if (callid.s && callid.len) dlg.id.call_id=callid; else generate_callid(&dlg.id.call_id); /* We will not fill in dlg->id.rem_tag because * if present it will be printed within To HF */ /* Generate fromtag if not present */ if (!fromtag) { generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id); } /* Fill in CSeq */ if (cseq_is) dlg.loc_seq.value = cseq; else dlg.loc_seq.value = DEFAULT_CSEQ; dlg.loc_seq.is_set = 1; dlg.loc_uri = faked_msg.from->body; dlg.rem_uri = faked_msg.to->body; dlg.rem_target = ruri; dlg.dst_uri = nexthop; dlg.send_sock=ssock; memset(&uac_req, 0, sizeof(uac_req)); uac_req.method=&method; uac_req.headers=&hfb; uac_req.body=body.len?&body:0; uac_req.dialog=&dlg; if (reply_wait){ dctx=rpc->delayed_ctx_new(c); if (dctx==0){ rpc->fault(c, 500, "internal error: failed to create context"); return; } uac_req.cb=rpc_uac_callback; uac_req.cbp=dctx; uac_req.cb_flags=TMCB_LOCAL_COMPLETED; /* switch to dctx, in case adding the callback fails and we want to still send a reply */ rpc=&dctx->rpc; c=dctx->reply_ctx; } ret = t_uac(&uac_req); if (ret <= 0) { err_ret = err2reason_phrase(ret, &sip_error, err_buf, sizeof(err_buf), "RPC/UAC") ; if (err_ret > 0 ) { rpc->fault(c, sip_error, "%s", err_buf); } else { rpc->fault(c, 500, "RPC/UAC error"); } if (dctx) rpc->delayed_ctx_close(dctx); goto error01; } error01: if (hfb.s) pkg_free(hfb.s); error: if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers); }