Beispiel #1
0
/* returns : -1 - error
 *            0 - ok, but no contact added
 *            n - ok and n contacts added
 */
static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl,
											long max, pv_elem_t *reason)
{
	static struct sip_msg  dup_rpl;
	static str scontacts[MAX_CONTACTS_PER_REPLY];
	static qvalue_t  sqvalues[MAX_CONTACTS_PER_REPLY];
	struct hdr_field *hdr;
	struct hdr_field *contact_hdr;
	contact_t        *contacts;
	str backup_uri;
	int n,i;
	int added;
	int dup;
	int ret;

	dup = 0; /* sh_rpl not duplicated */
	ret = 0; /* success and no contact added */
	contact_hdr = NULL;
	hdr = NULL;

	if (sh_rpl==0 || sh_rpl==FAKED_REPLY)
		return 0;

	if ( sh_rpl->msg_flags&FL_SHM_CLONE ) {
		/* duplicate the reply into private memory to be able
		 * to parse it and after words to free the parsed mems */
		memcpy( &dup_rpl, sh_rpl, sizeof(struct sip_msg) );
		LM_DBG("duplicating shm reply\n");
		dup = 1;
		/* ok -> force the parsing of contact header */
		if ( parse_headers( &dup_rpl, HDR_EOH_F, 0)<0 ) {
			LM_ERR("dup_rpl parse failed\n");
			ret = -1;
			goto restore;
		}
		if (dup_rpl.contact==0) {
			LM_DBG("contact hdr not found in dup_rpl\n");
			goto restore;
		}
		contact_hdr = dup_rpl.contact;
	} else {
		/* parse directly the current copy */
		/* force the parsing of contact header */
		if ( parse_headers( sh_rpl, HDR_EOH_F, 0)<0 ) {
			LM_ERR("sh_rpl parse failed\n");
			ret = -1;
			goto restore;
		}
		if (sh_rpl->contact==0) {
			LM_DBG("contact hdr not found in sh_rpl\n");
			goto restore;
		}
		contact_hdr = sh_rpl->contact;
	}

	/* iterate through all contact headers and extract the URIs */
	for( n=0,hdr=contact_hdr ; hdr ; hdr=hdr->sibling ) {

		/* parse the body of contact header */
		if (hdr->parsed==0) {
			if ( parse_contact(hdr)<0 ) {
				LM_ERR("contact hdr parse failed\n");
				ret = -1;
				goto restore;
			}
		}

		/* we have the contact header and its body parsed -> sort the contacts
		 * based on the q value */
		contacts = ((contact_body_t*)hdr->parsed)->contacts;
		if (contacts==0) {
			LM_DBG("contact hdr has no contacts\n");
		} else {
			sort_contacts( contacts, scontacts, sqvalues, &n);
		}

		/* clean currently added contact */
		if (dup)
			free_contact( (contact_body_t**)(void*)(&hdr->parsed) );
	}

	if (n==0) {
		LM_DBG("no contacts left after filtering\n");
		goto restore;
	}

	/* to many branches ? */
	if (max!=-1 && n>max)
		n = max;

	LM_DBG("%d contacts remaining after filtering and sorting\n",n);

	added = 0;

	/* add the sorted contacts as branches in dset and log this! */
	for ( i=0 ; i<n ; i++ ) {
		LM_DBG("adding contact <%.*s>\n",
			scontacts[i].len, scontacts[i].s);
		if (i==0) {
			/* set RURI*/
			if ( set_ruri( req, &scontacts[i])==-1 ) {
				LM_ERR("failed to set new RURI\n");
				goto restore;
			}
			set_ruri_q(req, sqvalues[i]);
		} else {
			if (append_branch(0,&scontacts[i],0,0,sqvalues[i],0,0)<0) {
				LM_ERR("failed to add contact to dset\n");
				continue;
			}
		}
		added++;
		if (rd_acc_fct!=0 && reason) {
			/* log the redirect */
			backup_uri = req->new_uri;
			req->new_uri =  scontacts[i];
			//FIXME
			rd_acc_fct( req, (char*)reason, acc_db_table,
					NULL, NULL, NULL, NULL);
			req->new_uri = backup_uri;
		}
	}

	ret = (added==0)?-1:added;
restore:
	if (dup==1) {
		/* free current parsed contact header */
		if (hdr && hdr->parsed)
			free_contact( (contact_body_t**)(void*)(&hdr->parsed) );
		/* are any new headers found? */
		if (dup_rpl.last_header!=sh_rpl->last_header) {
			/* identify in the new headere list (from dup_rpl)
			 * the sh_rpl->last_header and start remove everything after */
			hdr = sh_rpl->last_header;
			free_hdr_field_lst(hdr->next);
			hdr->next=0;
		}
	}
	return ret;
}
Beispiel #2
0
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;
}
Beispiel #3
0
/* returns : -1 - error
 *            0 - ok, but no contact added
 *            n - ok and n contacts added
 */
static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl,
								long max, struct acc_param *reason, unsigned int bflags)
{
	static struct sip_msg  dup_rpl;
	static contact_t *scontacts[MAX_CONTACTS_PER_REPLY];
	static qvalue_t  sqvalues[MAX_CONTACTS_PER_REPLY];
	struct hdr_field *hdr;
	struct hdr_field *contact_hdr;
	contact_t        *contacts;
	int n,i;
	int added;
	int dup;
	int ret;

	/* dup can be:
	 *    0 - sh reply but nothing duplicated 
	 *    1 - sh reply but only contact body parsed
	 *    2 - sh reply and contact header and body parsed
	 *    3 - private reply
	 */
	dup = 0; /* sh_rpl not duplicated */
	ret = 0; /* success and no contact added */
	contact_hdr = 0;

	if (sh_rpl==0 || sh_rpl==FAKED_REPLY)
		return 0;

	if (sh_rpl->contact==0) {
		/* contact header is not parsed */
		if ( sh_rpl->msg_flags&FL_SHM_CLONE ) {
			/* duplicate the reply into private memory to be able 
			 * to parse it and afterwards to free the parsed mems */
			memcpy( &dup_rpl, sh_rpl, sizeof(struct sip_msg) );
			dup = 2;
			/* ok -> force the parsing of contact header */
			if ( parse_headers( &dup_rpl, HDR_EOH_F, 0)<0 ) {
				LM_ERR("dup_rpl parse failed\n");
				ret = -1;
				goto restore;
			}
			if (dup_rpl.contact==0) {
				LM_DBG("contact hdr not found in dup_rpl\n");
				goto restore;
			}
			contact_hdr = dup_rpl.contact;
		} else {
			dup = 3;
			/* force the parsing of contact header */
			if ( parse_headers( sh_rpl, HDR_EOH_F, 0)<0 ) {
				LM_ERR("sh_rpl parse failed\n");
				ret = -1;
				goto restore;
			}
			if (sh_rpl->contact==0) {
				LM_DBG("contact hdr not found in sh_rpl\n");
				goto restore;
			}
			contact_hdr = sh_rpl->contact;
		}
	} else {
		contact_hdr = sh_rpl->contact;
	}

	/* parse the body of contact headers */
	hdr = contact_hdr;
	while(hdr) {
		if (hdr->type == HDR_CONTACT_T) {
			if (hdr->parsed==0) {
				if(parse_contact(hdr) < 0) {
					LM_ERR("failed to parse Contact body\n");
					ret = -1;
					goto restore;
				}
				if (dup==0)
					dup = 1;
				}
		}
		hdr = hdr->next;
	}

	/* we have the contact header and its body parsed -> sort the contacts
	 * based on the q value */
	contacts = ((contact_body_t*)contact_hdr->parsed)->contacts;
	if (contacts==0) {
		LM_DBG("contact hdr has no contacts\n");
		goto restore;
	}
	n = sort_contacts(contact_hdr, scontacts, sqvalues);
	if (n==0) {
		LM_DBG("no contacts left after filtering\n");
		goto restore;
	}

	i=0;

	/* more branches than requested in the parameter
	 * - add only the last ones from sorted array,
	 *   because the order is by increasing q */
	if (max!=-1 && n>max)
		i = n - max;

	added = 0;

	/* add the sortet contacts as branches in dset and log this! */
	for (  ; i<n ; i++ ) {
		LM_DBG("adding contact <%.*s>\n", scontacts[i]->uri.len,
				scontacts[i]->uri.s);
		if(sruid_next(&_redirect_sruid)==0) {
			if(append_branch( 0, &scontacts[i]->uri, 0, 0, sqvalues[i],
						bflags, 0, &_redirect_sruid.uid, 0,
						&_redirect_sruid.uid, &_redirect_sruid.uid)<0) {
				LM_ERR("failed to add contact to dset\n");
			} else {
				added++;
				if (rd_acc_fct!=0 && reason) {
					/* log the redirect */
					req->new_uri =  scontacts[i]->uri;
					//FIXME
					rd_acc_fct( req, (char*)reason, acc_db_table);
				}
			}
		} else {
			LM_ERR("failed to generate ruid for a new branch\n");
		}
	}

	ret = (added==0)?-1:added;
restore:
	if (dup==1) {
		free_contact( (contact_body_t**)(void*)(&contact_hdr->parsed) );
	} else if (dup==2) {
		/* are any new headers found? */
		if (dup_rpl.last_header!=sh_rpl->last_header) {
			/* identify in the new headere list (from dup_rpl) 
			 * the sh_rpl->last_header and start remove everything after */
			hdr = sh_rpl->last_header;
			free_hdr_field_lst(hdr->next);
			hdr->next=0;
		}
	}
	return ret;

}
Beispiel #4
0
/*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;
}
Beispiel #5
0
/* Build a local request based on a previous request; the only
   customers of this function are local ACK and local CANCEL
 */
char *build_local(struct cell *Trans,unsigned int branch,
	str *method, str *extra, struct sip_msg* rpl, unsigned int *len)
{
	char                *cancel_buf, *p, *via;
	unsigned int         via_len;
	struct hdr_field    *buf_hdrs;
	struct hdr_field    *hdr;
	struct sip_msg      *req;
	char branch_buf[MAX_BRANCH_PARAM_LEN];
	str branch_str;
	struct hostport hp;
	str from;
	str to;
	str cseq_n;

	req = Trans->uas.request;
	cseq_n = Trans->cseq_n;
	buf_hdrs = 0;

	if (rpl && rpl!=FAKED_REPLY) {
		/* take from and to hdrs from reply */
		to.s = rpl->to->name.s;
		to.len = rpl->to->len;
		from.s = rpl->from->name.s;
		from.len = rpl->from->len;
	} else {
		to = Trans->to;
		from = Trans->from;
		if (req && req->msg_flags&(FL_USE_UAC_FROM|FL_USE_UAC_TO)) {
			if ( extract_ftc_hdrs( Trans->uac[branch].request.buffer.s,
				Trans->uac[branch].request.buffer.len,
				(req->msg_flags&FL_USE_UAC_FROM)?&from:0 ,
				(req->msg_flags&FL_USE_UAC_TO)?&to:0 , 0 )!=0 ) {
				LM_ERR("build_local: failed to extract UAC hdrs\n");
				goto error;
			}
		}
	}

	LM_DBG("using FROM=<%.*s>, TO=<%.*s>, CSEQ_N=<%.*s>\n",
		from.len,from.s , to.len,to.s , cseq_n.len,cseq_n.s);

	/* method, separators, version  */
	*len=SIP_VERSION_LEN + method->len + 2 /* spaces */ + CRLF_LEN;
	*len+=Trans->uac[branch].uri.len;

	/*via*/
	branch_str.s=branch_buf;
	if (!t_calc_branch(Trans,  branch, branch_str.s, &branch_str.len ))
		goto error;
	set_hostport(&hp, (is_local(Trans))?0:req);
	via=via_builder(&via_len, Trans->uac[branch].request.dst.send_sock,
		&branch_str, 0, Trans->uac[branch].request.dst.proto, &hp );
	if (!via){
		LM_ERR("no via header got from builder\n");
		goto error;
	}
	*len+= via_len;
	/*headers*/
	*len+=from.len+Trans->callid.len+to.len+cseq_n.len+1+method->len+CRLF_LEN;

	/* copy'n'paste Route headers that were sent out */
	if (!is_local(Trans) &&
	( (req && req->route) || /* at least one route was received*/
	(Trans->uac[branch].path_vec.len!=0)) ) /* path was forced */
	{
		buf_hdrs = extract_parsed_hdrs(Trans->uac[branch].request.buffer.s,
			Trans->uac[branch].request.buffer.len );
		if (buf_hdrs==NULL) {
			LM_ERR("failed to reparse the request buffer\n");
			goto error01;
		}
		for ( hdr=buf_hdrs ; hdr ; hdr=hdr->next )
			if (hdr->type==HDR_ROUTE_T)
				*len+=hdr->len;
	}

	/* User Agent */
	if (server_signature) {
		*len += user_agent_header.len + CRLF_LEN;
	}
	/* Content Length, MaxFwd, EoM */
	*len+=LOCAL_MAXFWD_HEADER_LEN + CONTENT_LENGTH_LEN+1 + (extra?extra->len:0)
		+ (Trans->extra_hdrs.s?Trans->extra_hdrs.len:0) + CRLF_LEN + CRLF_LEN;

	cancel_buf=shm_malloc( *len+1 );
	if (!cancel_buf)
	{
		LM_ERR("no more share memory\n");
		goto error02;
	}
	p = cancel_buf;

	append_string( p, method->s, method->len );
	*(p++) = ' ';
	append_string( p, Trans->uac[branch].uri.s, Trans->uac[branch].uri.len);
	append_string( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN );

	/* insert our via */
	append_string(p,via,via_len);

	/*other headers*/
	append_string( p, from.s, from.len );
	append_string( p, Trans->callid.s, Trans->callid.len );
	append_string( p, to.s, to.len );

	append_string( p, cseq_n.s, cseq_n.len );
	*(p++) = ' ';
	append_string( p, method->s, method->len );
	append_string( p, CRLF LOCAL_MAXFWD_HEADER,
		CRLF_LEN+LOCAL_MAXFWD_HEADER_LEN );

	/* add Route hdrs (if any) */
	for ( hdr=buf_hdrs ; hdr ; hdr=hdr->next )
		if(hdr->type==HDR_ROUTE_T) {
			append_string(p, hdr->name.s, hdr->len );
		}

	if (extra)
		append_string(p, extra->s, extra->len );

	if (Trans->extra_hdrs.s)
		append_string(p, Trans->extra_hdrs.s, Trans->extra_hdrs.len );

	/* User Agent header, Content Length, EoM */
	if (server_signature) {
		append_string(p, user_agent_header.s, user_agent_header.len);
		append_string(p, CRLF CONTENT_LENGTH "0" CRLF CRLF ,
			CRLF_LEN+CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN);
	} else {
		append_string(p, CONTENT_LENGTH "0" CRLF CRLF ,
			CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN);
	}
	*p=0;

	pkg_free(via);
	free_hdr_field_lst(buf_hdrs);
	return cancel_buf;
error02:
	free_hdr_field_lst(buf_hdrs);
error01:
	pkg_free(via);
error:
	return NULL;
}
Beispiel #6
0
int t_uac_send(str *method, str *ruri, str *nexthop, str *send_socket,
		str *headers, str *body)
{
	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, fromtag, cseq_is, cseq;
	dlg_t dlg;
	uac_req_t uac_req;

	ret = -1;

	/* check and parse parameters */
	if (method->len<=0){
		LM_ERR("Empty method");
		return -1;
	}
	if (parse_uri(ruri->s, ruri->len, &p_uri)<0){
		LM_ERR("Invalid request uri \"%s\"", ruri->s);
		return -1;
	}
	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){
		LM_ERR("Invalid next-hop uri \"%s\"", nexthop->s);
		return -1;
	}
	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]=='(')
			){
		LM_ERR("Invalid send socket \"%s\"", send_socket->s);
		return -1;
	}else if (saddr.len && (ssock=grep_sock_info(&saddr, sport, sproto))==0){
		LM_ERR("No local socket for \"%s\"", send_socket->s);
		return -1;
	}
	/* 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){
		LM_ERR("Invalid headers");
		return -1;
	}
	/* at this moment all the parameters are parsed => more sanity checks */
	if (t_uac_check_msg(&faked_msg, method, body, &fromtag,
				&cseq_is, &cseq, &callid)<0) {
		LM_ERR("checking values failed\n");
		goto error;
	}
	hfb.s=get_hfblock(nexthop->len? nexthop: ruri, faked_msg.headers,
			PROTO_NONE, ssock, &hfb.len);
	if (hfb.s==0){
		LM_ERR("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;

	ret = t_uac(&uac_req);

	if (ret <= 0) {
		LM_ERR("UAC error");
		goto error01;
	}
error01:
	if (hfb.s) pkg_free(hfb.s);
error:
	if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);

	return ret;
}
Beispiel #7
0
/** 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);
}