Example #1
0
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, TO = {0}, *pfrom = NULL;
	int size= 0;
	unsigned int hash_code;
	int flag ;
	str record_route= {0, 0};
	int rt;
	str contact;
	int initial_request = 0;
	int end_transaction = 1;

	if( ps->param== NULL || *ps->param== NULL )
	{
		LM_ERR("null callback parameter\n");
		return;
	}

	if (dbmode == PUA_DB_ONLY && pua_dbf.start_transaction)
	{
		if (pua_dbf.start_transaction(pua_db, db_table_lock) < 0)
		{
			LM_ERR("in start_transaction\n");
			goto error;
		}
	}

	LM_DBG("completed with status %d\n",ps->code) ;
	hentity= (ua_pres_t*)(*ps->param);
	hash_code= core_hash(hentity->pres_uri,hentity->watcher_uri,
				HASH_SIZE);
	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)
	{
		struct hdr_field *callid = NULL, *from = NULL;
		struct to_body FROM = {0};

		callid = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field));
		if (callid == NULL)
		{
			LM_ERR("Out of memory\n");
			goto faked_error;
		}
		memset(callid, 0, sizeof(struct hdr_field));
		get_hdr_field(t->callid.s, t->callid.s + t->callid.len, callid);
		hentity->call_id = callid->body;

		from = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field));
		if (from == NULL)
		{
			LM_ERR("Out of memory\n");
			goto faked_error;
		}
		memset(from, 0, sizeof(struct hdr_field));
		get_hdr_field(t->from.s, t->from.s + t->from.len, from);
		parse_to(from->body.s, from->body.s + from->body.len + 1, &FROM);
		if(FROM.uri.len <= 0) 
		{
			LM_ERR("'From' header NOT parsed\n");
			goto faked_error;
		}
	
		hentity->call_id = callid->body;
		hentity->from_tag = (&FROM)->tag_value;
		hentity->to_tag.s = NULL;
		hentity->to_tag.len = 0;

		find_and_delete_dialog(hentity, hash_code);
faked_error:
		if (callid) pkg_free(callid);
		free_to_params(&FROM);
		if (from) pkg_free(from);
		goto done;
	}
	
	if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
	{
		LM_ERR("when parsing headers\n");
		goto error;
	}

	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 error;
		}
		lexpire = ((exp_body_t*)msg->expires->parsed)->val;
		LM_DBG("lexpire= %d\n", lexpire);
	}

	/*if initial request */
	if(hentity->call_id.s== NULL)
	{
		initial_request = 1;

		if( msg->callid==NULL || msg->callid->body.s==NULL)
		{
			LM_ERR("cannot parse callid header\n");
			goto error;
		}
		
		if (!msg->from || !msg->from->body.s)
		{
			LM_ERR("cannot find 'from' header!\n");
			goto error;
		}
		if (msg->from->parsed == NULL)
		{
			if ( parse_from_header( msg )<0 ) 
			{
				LM_ERR("cannot parse From header\n");
				goto error;
			}
		}
		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 error;
		}

		hentity->call_id=  msg->callid->body;
		hentity->from_tag= pfrom->tag_value;

		if(ps->code >= 300 || lexpire == 0)
		{
			hentity->to_tag.s = NULL;
			hentity->to_tag.len = 0;
			find_and_delete_dialog(hentity, hash_code);
			goto done;
		}

		if( msg->to==NULL || msg->to->body.s==NULL)
		{
			LM_ERR("cannot parse TO header\n");
			goto error;
		}			
		if(msg->to->parsed != NULL)
		{
			pto = (struct to_body*)msg->to->parsed;
			LM_DBG("'To' header ALREADY PARSED: <%.*s>\n",pto->uri.len,pto->uri.s);
		}
		else
		{
			parse_to(msg->to->body.s,msg->to->body.s +
				msg->to->body.len + 1, &TO);
			if(TO.uri.len <= 0) 
			{
				LM_ERR("'To' header NOT parsed\n");
				goto error;
			}
			pto = &TO;
		}			
		if( pto->tag_value.s ==NULL || pto->tag_value.len == 0)
		{
			LM_ERR("no to tag value present\n");
			goto error;
		}
		hentity->to_tag= pto->tag_value;
	}

	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*/	
		
		subs_info_t subs;

		hentity->to_tag.s = NULL;
		hentity->to_tag.len = 0;
		find_and_delete_dialog(hentity, hash_code);

		if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction)
		{
			if (pua_dbf.end_transaction(pua_db) < 0)
			{
				LM_ERR("in end_transaction\n");
				goto error;
			}
		}

		end_transaction = 0;

		/* Redirect if the response 3XX */
		memset(&subs, 0, sizeof(subs_info_t));
		subs.pres_uri= hentity->pres_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 error;
		}
		goto done;
	}

	if(lexpire== 0 )
	{
		LM_DBG("lexpire= 0 Delete from hash table");
		find_and_delete_dialog(hentity, hash_code);
		goto done;
	}

	/* 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( msg->cseq==NULL || msg->cseq->body.s==NULL)
	{
		LM_ERR("cannot parse cseq header\n");
		goto error;
	}

	if( str2int( &(get_cseq(msg)->number), &cseq)< 0)
	{
		LM_ERR("while converting str to int\n");
		goto error;
	}

	if(initial_request == 0)
	{
		hentity->cseq = cseq;
		find_and_update_dialog(hentity, hash_code, lexpire, &contact);
		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)+( 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);

	if(hentity->extra_headers)
		size+= sizeof(str)+ hentity->extra_headers->len*sizeof(char);

	presentity= (ua_pres_t*)shm_malloc(size);
	if(presentity== NULL)
	{
		LM_ERR("no more share memory\n");
		goto error;
	}
	
	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, pto->uri.s, pto->uri.len);
	presentity->pres_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);
		record_route.s = NULL;
	}

	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)
	{
		presentity->extra_headers= (str*)((char*)presentity+ size);
		size+= sizeof(str);
		presentity->extra_headers->s=(char*)presentity+ size;
		memcpy(presentity->extra_headers->s, hentity->extra_headers->s, 
			hentity->extra_headers->len);
		presentity->extra_headers->len= hentity->extra_headers->len; 
		size+= 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);

	if (dbmode==PUA_DB_ONLY)
	{
		if (pua_dbf.end_transaction)
		{
			if (pua_dbf.end_transaction(pua_db) < 0)
			{
				LM_ERR("in end_transaction\n");
				goto error;
			}
		}

		if (pua_dbf.start_transaction)
		{
			if (pua_dbf.start_transaction(pua_db, db_table_lock) < 0)
			{
				LM_ERR("in start_transaction\n");
				goto error;
			}
		}

		if (convert_temporary_dialog_puadb(presentity) < 0)
		{
			LM_ERR("Could not convert temporary dialog into a dialog\n");
			goto error;
		}
	}
	else
	{
		if (convert_temporary_dialog(presentity) < 0)
		{
			LM_ERR("Could not convert temporary dialog into a dialog\n");
			goto error;
		}
	}

done:
	if(hentity->ua_flag == REQ_OTHER)
	{
		hentity->flag= flag;
		run_pua_callbacks( hentity, msg);
	}

	if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction && end_transaction)
	{
		if (pua_dbf.end_transaction(pua_db) < 0)
		{
			LM_ERR("in end_transaction\n");
			goto error;
		}
	}

	goto end;

error:	
        if (presentity)
	{
		if (presentity->remote_contact.s) shm_free(presentity->remote_contact.s);
	 	shm_free(presentity);
	}

	if(record_route.s)
		pkg_free(record_route.s);

	if (dbmode == PUA_DB_ONLY && pua_dbf.abort_transaction)
	{
		if (pua_dbf.abort_transaction(pua_db) < 0)
			LM_ERR("in abort_transaction\n");
	}

end:

	if(hentity)
	{	
		shm_free(hentity);
		hentity= NULL;
	}

	free_to_params(&TO);
	return;
}
Example #2
0
/* note: it continues where it previously stopped and goes ahead until
   end is encountered or desired HFs are found; if you call it twice
   for the same HF which is present only once, it will fail the second
   time; if you call it twice and the HF is found on second time too,
   it's not replaced in the well-known HF pointer but just added to
   header list; if you want to use a dumb convenience function which will
   give you the first occurrence of a header you are interested in,
   look at check_transaction_quadruple
*/
int parse_headers(struct sip_msg* const msg, const hdr_flags_t flags, const int next)
{
    struct hdr_field* hf;
    char* tmp;
    char* rest;
    char* end;
    hdr_flags_t orig_flag;

    end=msg->buf+msg->len;
    tmp=msg->unparsed;

    if (unlikely(next)) {
        orig_flag = msg->parsed_flag;
        msg->parsed_flag &= ~flags;
    } else
        orig_flag=0;

#ifdef EXTRA_DEBUG
    DBG("parse_headers: flags=%llx\n", (unsigned long long)flags);
#endif
    while( tmp<end && (flags & msg->parsed_flag) != flags) {
        prefetch_loc_r(tmp+64, 1);
        hf=pkg_malloc(sizeof(struct hdr_field));
        if (unlikely(hf==0)) {
            ser_error=E_OUT_OF_MEM;
            LOG(L_ERR, "ERROR:parse_headers: memory allocation error\n");
            goto error;
        }
        memset(hf,0, sizeof(struct hdr_field));
        hf->type=HDR_ERROR_T;
        rest=get_hdr_field(tmp, end, hf);
        switch (hf->type) {
        case HDR_ERROR_T:
            LOG(L_INFO,"ERROR: bad header field [%.*s]\n",
                (end-tmp>20)?20:(int)(end-tmp), tmp);
            goto  error;
        case HDR_EOH_T:
            msg->eoh=tmp; /* or rest?*/
            msg->parsed_flag|=HDR_EOH_F;
            pkg_free(hf);
            goto skip;
        case HDR_ACCEPTCONTACT_T:
        case HDR_ALLOWEVENTS_T:
        case HDR_CONTENTENCODING_T:
        case HDR_REFERREDBY_T:
        case HDR_REJECTCONTACT_T:
        case HDR_REQUESTDISPOSITION_T:
        case HDR_WWW_AUTHENTICATE_T:
        case HDR_PROXY_AUTHENTICATE_T:
        case HDR_RETRY_AFTER_T:
        case HDR_OTHER_T: /* mark the type as found/parsed*/
            msg->parsed_flag|=HDR_T2F(hf->type);
            break;
        case HDR_CALLID_T:
            if (msg->callid==0) msg->callid=hf;
            msg->parsed_flag|=HDR_CALLID_F;
            break;
        case HDR_SIPIFMATCH_T:
            if (msg->sipifmatch==0) msg->sipifmatch=hf;
            msg->parsed_flag|=HDR_SIPIFMATCH_F;
            break;
        case HDR_TO_T:
            if (msg->to==0) msg->to=hf;
            msg->parsed_flag|=HDR_TO_F;
            break;
        case HDR_CSEQ_T:
            if (msg->cseq==0) msg->cseq=hf;
            msg->parsed_flag|=HDR_CSEQ_F;
            break;
        case HDR_FROM_T:
            if (msg->from==0) msg->from=hf;
            msg->parsed_flag|=HDR_FROM_F;
            break;
        case HDR_CONTACT_T:
            if (msg->contact==0) msg->contact=hf;
            msg->parsed_flag|=HDR_CONTACT_F;
            break;
        case HDR_MAXFORWARDS_T:
            if(msg->maxforwards==0) msg->maxforwards=hf;
            msg->parsed_flag|=HDR_MAXFORWARDS_F;
            break;
        case HDR_ROUTE_T:
            if (msg->route==0) msg->route=hf;
            msg->parsed_flag|=HDR_ROUTE_F;
            break;
        case HDR_RECORDROUTE_T:
            if (msg->record_route==0) msg->record_route = hf;
            msg->parsed_flag|=HDR_RECORDROUTE_F;
            break;
        case HDR_CONTENTTYPE_T:
            if (msg->content_type==0) msg->content_type = hf;
            msg->parsed_flag|=HDR_CONTENTTYPE_F;
            break;
        case HDR_CONTENTLENGTH_T:
            if (msg->content_length==0) msg->content_length = hf;
            msg->parsed_flag|=HDR_CONTENTLENGTH_F;
            break;
        case HDR_AUTHORIZATION_T:
            if (msg->authorization==0) msg->authorization = hf;
            msg->parsed_flag|=HDR_AUTHORIZATION_F;
            break;
        case HDR_EXPIRES_T:
            if (msg->expires==0) msg->expires = hf;
            msg->parsed_flag|=HDR_EXPIRES_F;
            break;
        case HDR_PROXYAUTH_T:
            if (msg->proxy_auth==0) msg->proxy_auth = hf;
            msg->parsed_flag|=HDR_PROXYAUTH_F;
            break;
        case HDR_PROXYREQUIRE_T:
            if (msg->proxy_require==0) msg->proxy_require = hf;
            msg->parsed_flag|=HDR_PROXYREQUIRE_F;
            break;
        case HDR_SUPPORTED_T:
            if (msg->supported==0) msg->supported=hf;
            msg->parsed_flag|=HDR_SUPPORTED_F;
            break;
        case HDR_REQUIRE_T:
            if (msg->require==0) msg->require=hf;
            msg->parsed_flag|=HDR_REQUIRE_F;
            break;
        case HDR_UNSUPPORTED_T:
            if (msg->unsupported==0) msg->unsupported=hf;
            msg->parsed_flag|=HDR_UNSUPPORTED_F;
            break;
        case HDR_ALLOW_T:
            if (msg->allow==0) msg->allow = hf;
            msg->parsed_flag|=HDR_ALLOW_F;
            break;
        case HDR_EVENT_T:
            if (msg->event==0) msg->event = hf;
            msg->parsed_flag|=HDR_EVENT_F;
            break;
        case HDR_ACCEPT_T:
            if (msg->accept==0) msg->accept = hf;
            msg->parsed_flag|=HDR_ACCEPT_F;
            break;
        case HDR_ACCEPTLANGUAGE_T:
            if (msg->accept_language==0) msg->accept_language = hf;
            msg->parsed_flag|=HDR_ACCEPTLANGUAGE_F;
            break;
        case HDR_ORGANIZATION_T:
            if (msg->organization==0) msg->organization = hf;
            msg->parsed_flag|=HDR_ORGANIZATION_F;
            break;
        case HDR_PRIORITY_T:
            if (msg->priority==0) msg->priority = hf;
            msg->parsed_flag|=HDR_PRIORITY_F;
            break;
        case HDR_SUBJECT_T:
            if (msg->subject==0) msg->subject = hf;
            msg->parsed_flag|=HDR_SUBJECT_F;
            break;
        case HDR_USERAGENT_T:
            if (msg->user_agent==0) msg->user_agent = hf;
            msg->parsed_flag|=HDR_USERAGENT_F;
            break;
        case HDR_SERVER_T:
            if (msg->server==0) msg->server = hf;
            msg->parsed_flag|=HDR_SERVER_F;
            break;
        case HDR_CONTENTDISPOSITION_T:
            if (msg->content_disposition==0) msg->content_disposition = hf;
            msg->parsed_flag|=HDR_CONTENTDISPOSITION_F;
            break;
        case HDR_DIVERSION_T:
            if (msg->diversion==0) msg->diversion = hf;
            msg->parsed_flag|=HDR_DIVERSION_F;
            break;
        case HDR_RPID_T:
            if (msg->rpid==0) msg->rpid = hf;
            msg->parsed_flag|=HDR_RPID_F;
            break;
        case HDR_REFER_TO_T:
            if (msg->refer_to==0) msg->refer_to = hf;
            msg->parsed_flag|=HDR_REFER_TO_F;
            break;
        case HDR_SESSIONEXPIRES_T:
            if (msg->session_expires==0) msg->session_expires = hf;
            msg->parsed_flag|=HDR_SESSIONEXPIRES_F;
            break;
        case HDR_MIN_SE_T:
            if (msg->min_se==0) msg->min_se = hf;
            msg->parsed_flag|=HDR_MIN_SE_F;
            break;
        case HDR_SUBSCRIPTION_STATE_T:
            if (msg->subscription_state==0) msg->subscription_state = hf;
            msg->parsed_flag|=HDR_SUBSCRIPTION_STATE_F;
            break;
        case HDR_VIA_T:
            msg->parsed_flag|=HDR_VIA_F;
            DBG("parse_headers: Via found, flags=%llx\n",
                (unsigned long long)flags);
            if (msg->via1==0) {
                DBG("parse_headers: this is the first via\n");
                msg->h_via1=hf;
                msg->via1=hf->parsed;
                if (msg->via1->next) {
                    msg->via2=msg->via1->next;
                    msg->parsed_flag|=HDR_VIA2_F;
                }
            } else if (msg->via2==0) {
                msg->h_via2=hf;
                msg->via2=hf->parsed;
                msg->parsed_flag|=HDR_VIA2_F;
                DBG("parse_headers: this is the second via\n");
            }
            break;
        case HDR_DATE_T:
            if (msg->date==0) msg->date=hf;
            msg->parsed_flag|=HDR_DATE_F;
            break;
        case HDR_IDENTITY_T:
            if (msg->identity==0) msg->identity=hf;
            msg->parsed_flag|=HDR_IDENTITY_F;
            break;
        case HDR_IDENTITY_INFO_T:
            if (msg->identity_info==0) msg->identity_info=hf;
            msg->parsed_flag|=HDR_IDENTITY_INFO_F;
            break;
        case HDR_PATH_T:
            if (msg->path==0) msg->path=hf;
            msg->parsed_flag|=HDR_PATH_F;
            break;
        case HDR_PRIVACY_T:
            if (msg->privacy==0) msg->privacy=hf;
            msg->parsed_flag|=HDR_PRIVACY_F;
            break;
        case HDR_PAI_T:
            if (msg->pai==0) msg->pai=hf;
            msg->parsed_flag|=HDR_PAI_F;
            break;
        case HDR_PPI_T:
            if (msg->ppi==0) msg->ppi=hf;
            msg->parsed_flag|=HDR_PPI_F;
            break;
        case HDR_REASON_T:
            msg->parsed_flag|=HDR_REASON_F;
            break;
        default:
            LOG(L_CRIT, "BUG: parse_headers: unknown header type %d\n",
                hf->type);
            goto error;
        }
        /* add the header to the list*/
        if (msg->last_header==0) {
            msg->headers=hf;
            msg->last_header=hf;
        } else {
            msg->last_header->next=hf;
            msg->last_header=hf;
        }
#ifdef EXTRA_DEBUG
        DBG("header field type %d, name=<%.*s>, body=<%.*s>\n",
            hf->type,
            hf->name.len, ZSW(hf->name.s),
            hf->body.len, ZSW(hf->body.s));
#endif
        tmp=rest;
    }
skip:
    msg->unparsed=tmp;
    /* restore original flags */
    msg->parsed_flag |= orig_flag;
    return 0;

error:
    ser_error=E_BAD_REQ;
    if (hf) pkg_free(hf);
    /* restore original flags */
    msg->parsed_flag |= orig_flag;
    return -1;
}
Example #3
0
/* note: it continues where it previously stopped and goes ahead until
   end is encountered or desired HFs are found; if you call it twice
   for the same HF which is present only once, it will fail the second
   time; if you call it twice and the HF is found on second time too,
   it's not replaced in the well-known HF pointer but just added to
   header list; if you want to use a dumb convenience function which will
   give you the first occurrence of a header you are interested in,
   look at check_transaction_quadruple
*/
int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next)
{
	struct hdr_field* hf;
	char* tmp;
	char* rest;
	char* end;
	hdr_flags_t orig_flag;

	end=msg->buf+msg->len;
	tmp=msg->unparsed;
	
	if (next) {
		orig_flag = msg->parsed_flag;
		msg->parsed_flag &= ~flags;
	}else
		orig_flag=0; 
	
	DBG("parse_headers: flags=%llx\n", (unsigned long long)flags);
	while( tmp<end && (flags & msg->parsed_flag) != flags){
		hf=pkg_malloc(sizeof(struct hdr_field));
		if (hf==0){
			ser_error=E_OUT_OF_MEM;
			LOG(L_ERR, "ERROR:parse_headers: memory allocation error\n");
			goto error;
		}
		memset(hf,0, sizeof(struct hdr_field));
		hf->type=HDR_ERROR_T;
		rest=get_hdr_field(tmp, msg->buf+msg->len, hf);
		switch (hf->type){
			case HDR_ERROR_T:
				LOG(L_INFO,"ERROR: bad header  field\n");
				goto  error;
			case HDR_EOH_T:
				msg->eoh=tmp; /* or rest?*/
				msg->parsed_flag|=HDR_EOH_F;
				pkg_free(hf);
				goto skip;
			case HDR_OTHER_T: /*do nothing*/
				break;
			case HDR_CALLID_T:
				if (msg->callid==0) msg->callid=hf;
				msg->parsed_flag|=HDR_CALLID_F;
				break;
			case HDR_TO_T:
				if (msg->to==0) msg->to=hf;
				msg->parsed_flag|=HDR_TO_F;
				break;
			case HDR_CSEQ_T:
				if (msg->cseq==0) msg->cseq=hf;
				msg->parsed_flag|=HDR_CSEQ_F;
				break;
			case HDR_FROM_T:
				if (msg->from==0) msg->from=hf;
				msg->parsed_flag|=HDR_FROM_F;
				break;
			case HDR_CONTACT_T:
				if (msg->contact==0) msg->contact=hf;
				msg->parsed_flag|=HDR_CONTACT_F;
				break;
			case HDR_MAXFORWARDS_T:
				if(msg->maxforwards==0) msg->maxforwards=hf;
				msg->parsed_flag|=HDR_MAXFORWARDS_F;
				break;
			case HDR_ROUTE_T:
				if (msg->route==0) msg->route=hf;
				msg->parsed_flag|=HDR_ROUTE_F;
				break;
			case HDR_RECORDROUTE_T:
				if (msg->record_route==0) msg->record_route = hf;
				msg->parsed_flag|=HDR_RECORDROUTE_F;
				break;
			case HDR_CONTENTTYPE_T:
				if (msg->content_type==0) msg->content_type = hf;
				msg->parsed_flag|=HDR_CONTENTTYPE_F;
				break;
			case HDR_CONTENTLENGTH_T:
				if (msg->content_length==0) msg->content_length = hf;
				msg->parsed_flag|=HDR_CONTENTLENGTH_F;
				break;
			case HDR_AUTHORIZATION_T:
				if (msg->authorization==0) msg->authorization = hf;
				msg->parsed_flag|=HDR_AUTHORIZATION_F;
				break;
			case HDR_EXPIRES_T:
				if (msg->expires==0) msg->expires = hf;
				msg->parsed_flag|=HDR_EXPIRES_F;
				break;
			case HDR_PROXYAUTH_T:
				if (msg->proxy_auth==0) msg->proxy_auth = hf;
				msg->parsed_flag|=HDR_PROXYAUTH_F;
				break;
		        case HDR_PROXYREQUIRE_T:
				if (msg->proxy_require==0) msg->proxy_require = hf;
				msg->parsed_flag|=HDR_PROXYREQUIRE_F;
				break;
	                case HDR_SUPPORTED_T:
				if (msg->supported==0) msg->supported=hf;
				msg->parsed_flag|=HDR_SUPPORTED_F;
				break;
			case HDR_UNSUPPORTED_T:
				if (msg->unsupported==0) msg->unsupported=hf;
				msg->parsed_flag|=HDR_UNSUPPORTED_F;
				break;
			case HDR_ALLOW_T:
				if (msg->allow==0) msg->allow = hf;
				msg->parsed_flag|=HDR_ALLOW_F;
				break;
			case HDR_EVENT_T:
				if (msg->event==0) msg->event = hf;
				msg->parsed_flag|=HDR_EVENT_F;
				break;
	        case HDR_ACCEPT_T:
				if (msg->accept==0) msg->accept = hf;
				msg->parsed_flag|=HDR_ACCEPT_F;
				break;
	        case HDR_ACCEPTLANGUAGE_T:
				if (msg->accept_language==0) msg->accept_language = hf;
				msg->parsed_flag|=HDR_ACCEPTLANGUAGE_F;
				break;
	        case HDR_ORGANIZATION_T:
				if (msg->organization==0) msg->organization = hf;
				msg->parsed_flag|=HDR_ORGANIZATION_F;
				break;
	        case HDR_PRIORITY_T:
				if (msg->priority==0) msg->priority = hf;
				msg->parsed_flag|=HDR_PRIORITY_F;
				break;
	        case HDR_SUBJECT_T:
				if (msg->subject==0) msg->subject = hf;
				msg->parsed_flag|=HDR_SUBJECT_F;
				break;
	        case HDR_USERAGENT_T:
				if (msg->user_agent==0) msg->user_agent = hf;
				msg->parsed_flag|=HDR_USERAGENT_F;
				break;
	        case HDR_CONTENTDISPOSITION_T:
				if (msg->content_disposition==0) msg->content_disposition = hf;
				msg->parsed_flag|=HDR_CONTENTDISPOSITION_F;
				break;
	        case HDR_ACCEPTDISPOSITION_T:
				if (msg->accept_disposition==0) msg->accept_disposition = hf;
				msg->parsed_flag|=HDR_ACCEPTDISPOSITION_F;
				break;
	        case HDR_DIVERSION_T:
				if (msg->diversion==0) msg->diversion = hf;
				msg->parsed_flag|=HDR_DIVERSION_F;
				break;
	        case HDR_RPID_T:
				if (msg->rpid==0) msg->rpid = hf;
				msg->parsed_flag|=HDR_RPID_F;
				break;
			case HDR_REFER_TO_T:
				if (msg->refer_to==0) msg->refer_to = hf;
				msg->parsed_flag|=HDR_REFER_TO_F;
				break;
			case HDR_VIA_T:
				msg->parsed_flag|=HDR_VIA_F;
				DBG("parse_headers: Via found, flags=%llx\n",
						(unsigned long long)flags);
				if (msg->via1==0) {
					DBG("parse_headers: this is the first via\n");
					msg->h_via1=hf;
					msg->via1=hf->parsed;
					if (msg->via1->next){
						msg->via2=msg->via1->next;
						msg->parsed_flag|=HDR_VIA2_F;
					}
				}else if (msg->via2==0){
					msg->h_via2=hf;
					msg->via2=hf->parsed;
					msg->parsed_flag|=HDR_VIA2_F;
					DBG("parse_headers: this is the second via\n");
				}
				break;
			default:
				LOG(L_CRIT, "BUG: parse_headers: unknown header type %d\n",
							hf->type);
				goto error;
		}
		/* add the header to the list*/
		if (msg->last_header==0){
			msg->headers=hf;
			msg->last_header=hf;
		}else{
			msg->last_header->next=hf;
			msg->last_header=hf;
		}
#ifdef EXTRA_DEBUG
		DBG("header field type %d, name=<%.*s>, body=<%.*s>\n",
			hf->type, 
			hf->name.len, ZSW(hf->name.s), 
			hf->body.len, ZSW(hf->body.s));
#endif
		tmp=rest;
	}
skip:
	msg->unparsed=tmp;
	return 0;

error:
	ser_error=E_BAD_REQ;
	if (hf) pkg_free(hf);
	if (next) msg->parsed_flag |= orig_flag;
	return -1;
}
Example #4
0
static int mc_compact_cb(char** buf_p, void* param, int type, int* olen)
{
	int i;
	int msg_total_len;
	int rtpmap_val=0, rtpmap_len;
	int new_body_len;
	int hdr_len;

	str msg_start;
	str new_buf;

	char *buf=*buf_p;
	char *buf_cpy;
	char *end=buf+*olen;

	struct hdr_field *hf;
	struct hdr_field** hdr_mask;
	struct mc_cmpct_args* args;

	body_frag_p frg;
	body_frag_p frg_head;
	body_frag_p temp;

	mc_param_p wh_param;
	mc_whitelist_p wh_list;


	args = (struct mc_cmpct_args*)param;

	wh_param = args->wh_param;
	wh_list  = args->wh_list;

	hdr_mask = pkg_malloc(HDR_EOH_T * sizeof(struct hdr_field*));

	if (!hdr_mask)
		goto memerr;

	memset(hdr_mask, 0, HDR_EOH_T * sizeof(struct hdr_field*));

	mc_parse_first_line( &msg_start, &buf);

	msg_total_len = msg_start.len;

	/* Start to parse the headers and print them*/
	while (1) {
		hf = pkg_malloc(sizeof(struct hdr_field));
		if (hf == NULL) {
			LM_ERR("no more pkg mem\n");
			goto memerr;
		}
		memset(hf, 0, sizeof(struct hdr_field));
		hf->type=HDR_ERROR_T;
		buf=get_hdr_field(buf, end, hf);

		if (hf->type == HDR_ERROR_T) {
			goto free_mem;
		}

		if (hf->type == HDR_EOH_T) {
			pkg_free(hf);
			break;
		}

		if (mc_is_in_whitelist(hf, wh_list)) {
			if (hdr_mask[hf->type]) {
				/* If hdr already found or hdr of type other */
				if (append_hf2lst(&hdr_mask[hf->type], hf,
							&msg_total_len)) {
					LM_ERR("Cannot append hdr to lst\n");
					return -1;
				}
			} else {
				unsigned char c;

				/* Get the compact form of the header */
				if (hf->type != HDR_OTHER_T &&
					(c=get_compact_form(hf)) != NO_FORM) {

					hf->name.s = COMPACT_FORMS+c;
					hf->name.len = 1;
				}

				/* update the len of the new buffer */
				msg_total_len += hf->name.len + DELIM_LEN;
				msg_total_len += hf->body.len + CRLF_LEN;

				hdr_mask[hf->type] = hf;
			}
		} else {
			clean_hdr_field(hf);
		}

		hf = 0;
	}

	hdr_len = msg_total_len;

	buf_cpy = buf+CRLF_LEN;
	frg = frg_head = pkg_malloc(sizeof(body_frag_t));
	if (!frg)
		goto memerr;

	frg->begin = 0;
	frg->end = CRLF_LEN;
	frg->next = NULL;

	/* parse the body and extract fragments */
	while (buf_cpy != end) {
		while (*buf_cpy == ' ' || *buf_cpy == '\t')
				(buf_cpy++, frg->end++);

		if (*buf_cpy != 'a') {
			/* Jump over the entire row*/
			goto row_jump;
		}
		else if (strncmp(buf_cpy, "a=rtpmap:", 9))
			goto row_jump;
		/* found rtpmap */
		else {
			buf_cpy += 9;
			frg->end--; /* already on 'a' char */
			rtpmap_len = rtpmap_val = 0;

			while (*buf_cpy >= '0' && *buf_cpy <= '9') {
				rtpmap_val = rtpmap_val*10 + (*buf_cpy - '0');
				(buf_cpy++, rtpmap_len++);
			}

			if (rtpmap_val < 98) {
				msg_total_len += frg->end - frg->begin + 1;
				frg->next = pkg_malloc(sizeof(body_frag_t));
				if (!frg->next)
					goto memerr;

				frg = frg->next;
				frg->next = NULL;

				/* find the next line and set the start of the next fragment */
				while (*buf_cpy != '\n') buf_cpy++;
				buf_cpy++;

				frg->end = frg->begin = buf_cpy - buf;
				continue;
			} else {
				/*currently on \n before rtpmap. Need to jump over \nrtpmap:RT_VAL */
				frg->end += 9 + rtpmap_len + 1;
			}
		}

		row_jump:
			while (*buf_cpy != '\n') {
				if (*buf_cpy == '\0') {
					LM_ERR("BUG! Message body not containing '\\n' in the end\n");
					return -1;
				}
				(buf_cpy++, frg->end++);
			}
		(buf_cpy++, frg->end++);
	}

	int foo;

	/* not storing '\0' at the end of the message */
	(buf_cpy--, frg->end--);

	msg_total_len += frg->end - frg->begin + 1;

	new_body_len = msg_total_len - hdr_len;

	/* creating the new content length */
	hf = pkg_malloc(sizeof(struct hdr_field));
	if (hf == NULL)
		goto memerr;
	memset(hf, 0, sizeof(struct hdr_field));

	hf->type = HDR_CONTENTLENGTH_T;
	hf->name.s = COMPACT_FORMS + get_compact_form(hf);
	hf->name.len = 1;

	if (new_body_len <= CRLF_LEN)
		new_body_len = 0;

	hf->body.len = mc_ndigits(new_body_len);
	hf->body.s = int2str( new_body_len, &foo);
	if (hf->body.s == 0) {
		LM_ERR("failed to convert int to string\n");
		goto memerr;
	}

	/*
	 * If body is empty Content-Type is not necessary anymore
	 * But only if Content-Type exists
	 */
	if (hdr_mask[HDR_CONTENTTYPE_T] && new_body_len == 0) {
		clean_hdr_field(hdr_mask[HDR_CONTENTTYPE_T]);
		hdr_mask[HDR_CONTENTTYPE_T] = NULL;
	}

	msg_total_len += hf->name.len + DELIM_LEN + hf->body.len + CRLF_LEN;
	hdr_mask[hf->type] = hf;

	/* build the new buffer */
	if (wrap_realloc(&buf_out, msg_total_len))
		goto free_mem;

	new_buf.s = buf_out.s;
	new_buf.len = 0;

	/* Copy the beginning of the message */
	wrap_copy_and_update( &new_buf.s, msg_start.s, msg_start.len,
							&new_buf.len);

	/* Copy all the headers */
	for (i = HDR_VIA_T; i <= HDR_EOH_T; i++) {
		/* Just to put headers of type other after
			all the other headers */
		if (i == HDR_EOH_T)
			i = HDR_OTHER_T;
again:
		if (hdr_mask[i]) {
			/* Compact form name so the header have
				to be built */
			if (LOWER_CASE(hdr_mask[i]->name.s)) {
				/* Copy the name of the header */
				wrap_copy_and_update(&new_buf.s,
					hdr_mask[i]->name.s,
					hdr_mask[i]->name.len, &new_buf.len);

				/* Copy the ': ' delimiter*/
				wrap_copy_and_update(&new_buf.s, DELIM,
						DELIM_LEN, &new_buf.len);
				/* Copy the first field of the header*/
				wrap_copy_and_update(&new_buf.s,
					hdr_mask[i]->body.s,
					hdr_mask[i]->body.len, &new_buf.len);
			/* Normal form header so it can be copied in one step */
			} else {
				wrap_copy_and_update(
					&new_buf.s,
					hdr_mask[i]->name.s,
					/* Possible siblings. No CRLF yet */
					hdr_mask[i]->len - CRLF_LEN,
					&new_buf.len
				);
			}

			/* Copy the rest of the header fields(siblings)
							if they exist */
			struct hdr_field* temp = hdr_mask[i]->sibling,
								*hdr_field;
			while (temp) {
				/* Put ', ' delimiter before header body*/
				wrap_copy_and_update(&new_buf.s, ATTR_DELIM,
						ATTR_DELIM_LEN, &new_buf.len);

				/* Append the header content */
				wrap_copy_and_update(&new_buf.s, temp->body.s,
						temp->body.len, &new_buf.len);

				hdr_field = temp->sibling;
				clean_hdr_field(temp);
				temp = hdr_field;
			}

			/* Copy CRLF to the end of the header */
			wrap_copy_and_update(&new_buf.s, CRLF, CRLF_LEN,
								&new_buf.len);

			if (hdr_mask[i]->next) {
				/* If more other headers, put all of them in
					the new buffer and free every allocated
					member */
				temp = hdr_mask[i];
				hdr_mask[i] = hdr_mask[i]->next;
				clean_hdr_field(temp);

				goto again;
			} else {
				/* if it is not an OTHER_HDR or it is the last
					one in OTHER_HDR list */
				pkg_free(hdr_mask[i]);
				hdr_mask[i] = 0;
			}
		}

		if (i == HDR_OTHER_T)
			break;
	}
	/* Copy the body of the message */
	frg = frg_head;
	while (frg) {
		temp = frg;
		wrap_copy_and_update( &new_buf.s, buf + frg->begin,
					frg->end-frg->begin+1, &new_buf.len);
		frg = frg->next;
		pkg_free(temp);
	}

	switch (type) {
		case TM_CB:
			*buf_p = shm_malloc(new_buf.len);
			if (*buf_p == NULL) {
				LM_ERR("no more sh mem\n");
				goto free_mem;
			}
			break;
		case PROCESSING_CB:
			*buf_p = pkg_malloc(new_buf.len);
			if (*buf_p == NULL) {
				LM_ERR("no more pkg mem\n");
				goto free_mem;
			}
			break;
		default:
			LM_ERR("invalid type\n");
			goto free_mem;
	}

	memcpy(*buf_p, new_buf.s, new_buf.len);
	*olen = new_buf.len;

	/* Free the vector */
	pkg_free(hdr_mask);

	/* Free the whitelist if pvs */
	if (wh_param && wh_param->type == WH_TYPE_PVS)
		free_whitelist(&wh_list);

	return 0;
memerr:
	LM_ERR("No more pkg mem\n");
free_mem:
	free_hdr_mask(hdr_mask);
	free_whitelist(&wh_list);
	return -1;
}
Example #5
0
int mc_compress_cb(char** buf_p, void* param, int type, int* olen)
{
	int rc;
	int len;
	int algo;
	int flags;
	int compress_len=0;
	int uncompress_len=0;
	int hdr_compress_len=0;

	str msg_start;

	char *buf=*buf_p;
	char *end=buf+strlen(buf);
	unsigned long temp;
	struct mc_comp_args *args=(struct mc_comp_args*)param;

	struct hdr_field *hf;
	struct hdr_field *mnd_hdrs=NULL;
	struct hdr_field *non_mnd_hdrs=NULL;
	struct hdr_field *mnd_hdrs_head=NULL;
	struct hdr_field *non_mnd_hdrs_head=NULL;

	mc_param_p wh_param;
	mc_whitelist_p hdr2compress_list;

	wh_param = args->wh_param;
	hdr2compress_list = args->hdr2compress_list;
	algo = args->algo;
	flags = args->flags;

	mc_parse_first_line(&msg_start, &buf);

	uncompress_len = msg_start.len;

	/* Parse the message until the body is found
		Build two lists one of mandatory headers and one
			of non mandatory headers */

	while (1) {
		hf = pkg_malloc(sizeof(struct hdr_field));
		if (hf == NULL) {
			LM_ERR("no more pkg mem\n");
			goto free_mem_full;
		}
		memset(hf, 0, sizeof(struct hdr_field));
		hf->type=HDR_ERROR_T;
		buf=get_hdr_field(buf, end, hf);

		if (hf->type == HDR_ERROR_T) {
			goto free_mem_full;
		}

		if (hf->type == HDR_EOH_T) {
			compress_len += strlen(buf);
			compress_len = compress_len > CRLF_LEN ? compress_len : 0;
			pkg_free(hf);
			break;
		}

		/*if Content-Length=0 then header must remain*/
		if (hf->type == HDR_CONTENTLENGTH_T &&
				hf->body.s[0] == '0') {
			goto set_mandatory;
		}

		if (mc_is_in_whitelist(hf, hdr2compress_list)) {
			if (!non_mnd_hdrs) {
				non_mnd_hdrs_head = non_mnd_hdrs = hf;
			} else {
				non_mnd_hdrs->next = hf;
				non_mnd_hdrs = non_mnd_hdrs->next;
			}

			/* in case will have a separate compressed header */
			if ((flags&SEPARATE_COMP_FLG && flags&BODY_COMP_FLG &&
							flags&HDR_COMP_FLG) ||
				(flags&HDR_COMP_FLG && !(flags&BODY_COMP_FLG)))
				hdr_compress_len += hf->len;
			else
				compress_len += hf->len;

		} else {
		set_mandatory:
			if (!mnd_hdrs) {
				mnd_hdrs_head = mnd_hdrs = hf;
			} else {
				mnd_hdrs->next = hf;
				mnd_hdrs = mnd_hdrs->next;
			}
			uncompress_len += hf->len;
		}
		hf = 0;
	}

	str buf2compress={NULL, 0};
	str hdr_buf2compress={NULL, 0};

	/* Copy headers only if they exist and only if were asked*/
	non_mnd_hdrs = non_mnd_hdrs_head;
	if (!non_mnd_hdrs || !(flags&HDR_COMP_FLG))
		goto only_body;

	/* If body compression and header compression flags are set and
		they have to be together in the body */
	if ((flags&BODY_COMP_FLG && flags&HDR_COMP_FLG &&
						!(flags&SEPARATE_COMP_FLG)) ||
		(flags&BODY_COMP_FLG && !(flags&HDR_COMP_FLG))){

		if (wrap_realloc(&body_in, compress_len))
			goto free_mem_full;

		buf2compress.s = body_in.s;
		buf2compress.len = 0;

		for (hf = non_mnd_hdrs; hf; hf = hf->next) {
			wrap_copy_and_update( &buf2compress.s, hf->name.s,
						hf->len, &buf2compress.len);
		}
	/* body compression and header compression but separately or
		only header compression */
	} else if ((flags&BODY_COMP_FLG && flags&HDR_COMP_FLG &&
			flags&SEPARATE_COMP_FLG) ||
		    (!(flags&BODY_COMP_FLG) && flags&HDR_COMP_FLG)) {

		if (wrap_realloc(&hdr_in, hdr_compress_len))
			goto free_mem_full;

		hdr_buf2compress.s = hdr_in.s;

		for (hf = non_mnd_hdrs; hf; hf = hf->next) {
			wrap_copy_and_update( &hdr_buf2compress.s, hf->name.s,
						hf->len, &hdr_buf2compress.len);
		}
	}

only_body:
	/* Copy the body of the message only if body compression is asked */
	if (flags&BODY_COMP_FLG && compress_len) {
		if (!buf2compress.s) {
			if (wrap_realloc(&body_in, compress_len))
				goto free_mem_full;
			buf2compress.s = body_in.s;
		}

		wrap_copy_and_update( &buf2compress.s, buf, strlen(buf),
							&buf2compress.len);
	}

	if (!buf2compress.s && !hdr_buf2compress.s) {
		LM_WARN("Nothing to compress. Specified headers not found\n");
		goto free_mem_full;
	}

	/* Compress the message */
	str bufcompressed={NULL, 0};
	str hdr_bufcompressed={NULL, 0};

	switch (algo) {
	case 0: /* deflate */

		if (buf2compress.s) {
			bufcompressed.len = compressBound((unsigned long)buf2compress.len);
			if (wrap_realloc(&body_out, bufcompressed.len))
				goto free_mem_full;

			bufcompressed.s = body_out.s;
			temp = (unsigned long)bufcompressed.len;

			rc = compress2((unsigned char*)bufcompressed.s,
					&temp,
					(unsigned char*)buf2compress.s,
					(unsigned long)buf2compress.len,
					mc_level);

			bufcompressed.len = (int)temp;

			if (check_zlib_rc(rc)) {
				LM_ERR("Body compression failed\n");
				goto free_mem_full;
			}
		}

		if ((flags&HDR_COMP_FLG) && hdr_buf2compress.s) {
			hdr_bufcompressed.len = compressBound((unsigned long)hdr_buf2compress.len);
			if (wrap_realloc(&hdr_out, hdr_bufcompressed.len))
				goto free_mem_full;

			hdr_bufcompressed.s = hdr_out.s;
			temp = (unsigned long)hdr_bufcompressed.len;

			rc = compress2((unsigned char*)hdr_bufcompressed.s,
					&temp,
					(unsigned char*)hdr_buf2compress.s,
					(unsigned long)hdr_buf2compress.len,
					mc_level);

			hdr_bufcompressed.len = temp;

			if (check_zlib_rc(rc)) {
				LM_ERR("Header compression failed\n");
				goto free_mem_full;
			}
		}

		break;
	case 1: /* gzip */
		if (buf2compress.s) {
			rc = gzip_compress(
					(unsigned char*)buf2compress.s,
					(unsigned long)buf2compress.len,
					&body_out,
					&temp,
					mc_level);

			if (check_zlib_rc(rc)) {
				LM_ERR("Body compression failed\n");
				goto free_mem_full;
			}

			bufcompressed.s = body_out.s;
			bufcompressed.len = (int)temp;
		}

		if ((flags&HDR_COMP_FLG) && hdr_buf2compress.s) {
			rc = gzip_compress(
					(unsigned char*)hdr_buf2compress.s,
					(unsigned long)hdr_buf2compress.len,
					&hdr_out,
					&temp,
					mc_level);

			if (check_zlib_rc(rc)) {
				LM_ERR("Header compression failed\n");
				goto free_mem_full;
			}
			hdr_bufcompressed.s = hdr_out.s;
			hdr_bufcompressed.len = temp;
		}

		break;
	default:
		LM_WARN("Invalind algo! no compression made\n");
		goto free_mem_full;
	}

	str bufencoded={NULL, 0};
	str hdr_bufencoded={NULL, 0};

	if ((flags&B64_ENCODED_FLG) && bufcompressed.s) {
		bufencoded.len = calc_base64_encode_len(bufcompressed.len);
		if (wrap_realloc( &body_in, 2*CRLF_LEN + bufencoded.len))
			goto free_mem_full;
		bufencoded.s = body_in.s;

		memcpy(bufencoded.s, CRLF, CRLF_LEN);

		base64encode((unsigned char*)(bufencoded.s + CRLF_LEN),
				(unsigned char*)bufcompressed.s,
							bufcompressed.len);
	} else if (bufcompressed.s) {
		if (wrap_realloc(&body_in, bufcompressed.len + 2*CRLF_LEN))
			goto free_mem_full;

		/* !!! shift buf2compressed CRLF_LEN to the right !!! */
		memcpy(body_in.s+CRLF_LEN, bufcompressed.s, bufcompressed.len);
		memcpy(body_in.s, CRLF, CRLF_LEN);

		bufencoded.len = bufcompressed.len;
		bufencoded.s = body_in.s;
	}

	if (hdr_bufcompressed.s) {

		hdr_bufencoded.len = calc_base64_encode_len(hdr_bufcompressed.len);

		if (wrap_realloc( &hdr_in, hdr_bufencoded.len + CRLF_LEN))
			goto free_mem_full;
		hdr_bufencoded.s = hdr_in.s;

		base64encode((unsigned char*)hdr_bufencoded.s,
				(unsigned char*)hdr_bufcompressed.s,
							hdr_bufcompressed.len);

		wrap_copy_and_update(&hdr_bufencoded.s, CRLF, CRLF_LEN,
							&hdr_bufencoded.len);
	}

	/* Allocate the new buffer */
	int alloc_size;
	str buf2send={NULL, 0};

	alloc_size = msg_start.len + uncompress_len + CRLF_LEN/*the one before all headers*/;

	if (hdr_bufencoded.s) {
		alloc_size += COMP_HDRS_LEN + hdr_bufencoded.len;
		alloc_size += sizeof(HDRS_ENCODING) - 1;
	}

	/* if body compressed new content length and content encoding
	 * plus if required more space for base64 in content encoding header*/

	if (bufencoded.s) {
		alloc_size += CL_NAME_LEN + mc_ndigits(bufencoded.len) + CRLF_LEN;
		alloc_size += CE_NAME_LEN + CRLF_LEN;
		if (flags&B64_ENCODED_FLG) {
			alloc_size += ATTR_DELIM_LEN + (sizeof(BASE64_ALGO)-1);
		}
	}


	switch (algo) {
		case 0: /* deflate*/
			if (bufencoded.s)
				alloc_size += DEFLATE_CE_LEN;
			if (hdr_bufencoded.s)
				alloc_size += sizeof(DEFLATE_ALGO) - 1;
			break;
		case 1: /* gzip */
			if (bufencoded.s)
				alloc_size += GZIP_CE_LEN;
			if (hdr_bufencoded.s)
				alloc_size += sizeof(GZIP_ALGO) - 1;
			break;
		default:
			LM_ERR("compression algo not impelemented\n");
			goto free_mem_full;
	}

	if (bufencoded.s)
		alloc_size += bufencoded.len + CRLF_LEN;
	else
		alloc_size += strlen(buf);

	if (wrap_realloc(&buf_out, alloc_size))
		goto free_mem_full;

	buf2send.s = buf_out.s;

	/* Copy message start */
	wrap_copy_and_update( &buf2send.s, msg_start.s, msg_start.len,
							&buf2send.len);

	/* Copy mandatory headers */
	for (mnd_hdrs = mnd_hdrs_head; mnd_hdrs; mnd_hdrs = mnd_hdrs->next) {
		wrap_copy_and_update( &buf2send.s, mnd_hdrs->name.s,
						mnd_hdrs->len, &buf2send.len);
	}


	if ((flags&BODY_COMP_FLG) && bufencoded.s) {
		wrap_copy_and_update( &buf2send.s, CL_NAME,
						CL_NAME_LEN, &buf2send.len);

		wrap_copy_and_update( &buf2send.s, int2str(bufencoded.len, &len),
					mc_ndigits(bufencoded.len), &buf2send.len);
		wrap_copy_and_update( &buf2send.s, CRLF, CRLF_LEN, &buf2send.len);
	}

	if (hdr_bufencoded.s) {
		wrap_copy_and_update( &buf2send.s, COMP_HDRS, COMP_HDRS_LEN,
								&buf2send.len);

		wrap_copy_and_update( &buf2send.s, hdr_bufencoded.s,
					hdr_bufencoded.len, &buf2send.len);

	}

	switch (algo) {
	case 0: /* deflate */
		if (hdr_bufencoded.s) {
			str hdr_name = str_init(HDRS_ENCODING),
				hdr_value = str_init(DEFLATE_ALGO);
			wrap_copy_and_update(&buf2send.s, hdr_name.s,
						hdr_name.len, &buf2send.len);

			if (flags & B64_ENCODED_FLG) {
				wrap_copy_and_update(&buf2send.s, BASE64_ALGO,
						sizeof(BASE64_ALGO)-1, &buf2send.len);
				wrap_copy_and_update(&buf2send.s, ATTR_DELIM,
						ATTR_DELIM_LEN, &buf2send.len);
			}
			wrap_copy_and_update(&buf2send.s, hdr_value.s,
						hdr_value.len, &buf2send.len);
			wrap_copy_and_update(&buf2send.s, CRLF,
							CRLF_LEN, &buf2send.len);

		}

		if (bufencoded.s) {
			wrap_copy_and_update(&buf2send.s, CE_NAME,
						CE_NAME_LEN, &buf2send.len);

			if (flags & B64_ENCODED_FLG) {
				wrap_copy_and_update(&buf2send.s, BASE64_ALGO,
						sizeof(BASE64_ALGO)-1, &buf2send.len);
				wrap_copy_and_update(&buf2send.s, ATTR_DELIM,
						ATTR_DELIM_LEN, &buf2send.len);
			}
			wrap_copy_and_update(&buf2send.s, DEFLATE_ALGO,
							sizeof(DEFLATE_ALGO)-1, &buf2send.len);
			wrap_copy_and_update(&buf2send.s, CRLF,
							CRLF_LEN, &buf2send.len);
		}
		break;
	case 1: /* gzip */
		if (hdr_bufencoded.s) {
			str hdr_name = str_init(HDRS_ENCODING),
				hdr_value = str_init(GZIP_ALGO);
			if (flags & B64_ENCODED_FLG) {
				wrap_copy_and_update(&buf2send.s, BASE64_ALGO,
						sizeof(BASE64_ALGO)-1, &buf2send.len);
				wrap_copy_and_update(&buf2send.s, ATTR_DELIM,
						ATTR_DELIM_LEN, &buf2send.len);
			}
			wrap_copy_and_update(&buf2send.s, hdr_name.s,
						hdr_name.len, &buf2send.len);
			wrap_copy_and_update(&buf2send.s, hdr_value.s,
						hdr_value.len, &buf2send.len);
			wrap_copy_and_update(&buf2send.s, CRLF,
							CRLF_LEN, &buf2send.len);
		}

		if (bufencoded.s) {
			wrap_copy_and_update(&buf2send.s, CE_NAME,
						CE_NAME_LEN, &buf2send.len);
			if (flags & B64_ENCODED_FLG) {
				wrap_copy_and_update(&buf2send.s, BASE64_ALGO,
						sizeof(BASE64_ALGO)-1, &buf2send.len);
				wrap_copy_and_update(&buf2send.s, ATTR_DELIM,
						ATTR_DELIM_LEN, &buf2send.len);
			}
			wrap_copy_and_update(&buf2send.s, GZIP_ALGO,
							sizeof(GZIP_ALGO)-1, &buf2send.len);
			wrap_copy_and_update(&buf2send.s, CRLF,
							CRLF_LEN, &buf2send.len);
		}
		break;
	default:
		LM_ERR("compression algo not impelemented\n");
		goto free_mem_full;
	}


	/* Copy message body */
	if (bufencoded.s) {
		wrap_copy_and_update( &buf2send.s, bufencoded.s,
					bufencoded.len+CRLF_LEN, &buf2send.len);

		wrap_copy_and_update( &buf2send.s, CRLF,
						CRLF_LEN, &buf2send.len);
	} else {
		wrap_copy_and_update( &buf2send.s, buf, strlen(buf),
							&buf2send.len);
	}

	switch (type) {
		case TM_CB:
			shm_free(*buf_p);
			*buf_p = shm_malloc(buf2send.len+1);
			if (*buf_p == NULL) {
				LM_ERR("no more sh mem\n");
				goto free_mem_full;
			}
			break;
		case PROCESSING_CB:
			*buf_p = pkg_malloc(buf2send.len+1);
			if (*buf_p == NULL) {
				LM_ERR("no more pkg mem\n");
				goto free_mem_full;
			}
			break;
		default:
			LM_ERR("invalid type\n");
			goto free_mem_full;
	}

	memcpy(*buf_p, buf2send.s, buf2send.len);
	(*buf_p)[buf2send.len] = '\0';
	*olen = buf2send.len;

	free_hdr_list(&mnd_hdrs_head);
	free_hdr_list(&non_mnd_hdrs_head);

	if (wh_param && wh_param->type == WH_TYPE_PVS)
		free_whitelist(&hdr2compress_list);

	return 0;

free_mem_full:
	free_hdr_list(&mnd_hdrs_head);
	free_hdr_list(&non_mnd_hdrs_head);
	if (wh_param && wh_param->type == WH_TYPE_PVS)
		free_whitelist(&hdr2compress_list);

	return -1;
}
Example #6
0
/* note: it continues where it previously stopped and goes ahead until
   end is encountered or desired HFs are found; if you call it twice
   for the same HF which is present only once, it will fail the second
   time; if you call it twice and the HF is found on second time too,
   it's not replaced in the well-known HF pointer but just added to
   header list; if you want to use a dumb convenience function which will
   give you the first occurrence of a header you are interested in,
   look at check_transaction_quadruple
*/
int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next)
{
	struct hdr_field *hf;
	struct hdr_field *itr;
	char* tmp;
	char* rest;
	char* end;
	hdr_flags_t orig_flag;

#define link_sibling_hdr(_hook, _hdr) \
	do{ \
		if (msg->_hook==0) msg->_hook=_hdr;\
			else {\
				for(itr=msg->_hook;itr->sibling;itr=itr->sibling);\
				itr->sibling = _hdr;\
			}\
	}while(0)

	end=msg->buf+msg->len;
	tmp=msg->unparsed;

	if (next) {
		orig_flag = msg->parsed_flag;
		msg->parsed_flag &= ~flags;
	}else
		orig_flag=0;

	LM_DBG("flags=%llx\n", (unsigned long long)flags);
	while( tmp<end && (flags & msg->parsed_flag) != flags){
		hf=pkg_malloc(sizeof(struct hdr_field));
		if (hf==0){
			ser_error=E_OUT_OF_MEM;
			LM_ERR("pkg memory allocation failed\n");
			goto error;
		}
		memset(hf,0, sizeof(struct hdr_field));
		hf->type=HDR_ERROR_T;
		rest=get_hdr_field(tmp, msg->buf+msg->len, hf);
		switch (hf->type){
			case HDR_ERROR_T:
				LM_INFO("bad header field\n");
				goto  error;
			case HDR_EOH_T:
				msg->eoh=tmp; /* or rest?*/
				msg->parsed_flag|=HDR_EOH_F;
				pkg_free(hf);
				goto skip;
			case HDR_OTHER_T: /*do nothing*/
				break;
			case HDR_CALLID_T:
				if (msg->callid==0) msg->callid=hf;
				msg->parsed_flag|=HDR_CALLID_F;
				break;
			case HDR_TO_T:
				if (msg->to==0) msg->to=hf;
				msg->parsed_flag|=HDR_TO_F;
				break;
			case HDR_CSEQ_T:
				if (msg->cseq==0) msg->cseq=hf;
				msg->parsed_flag|=HDR_CSEQ_F;
				break;
			case HDR_FROM_T:
				if (msg->from==0) msg->from=hf;
				msg->parsed_flag|=HDR_FROM_F;
				break;
			case HDR_CONTACT_T:
				link_sibling_hdr(contact,hf);
				msg->parsed_flag|=HDR_CONTACT_F;
				break;
			case HDR_MAXFORWARDS_T:
				if(msg->maxforwards==0) msg->maxforwards=hf;
				msg->parsed_flag|=HDR_MAXFORWARDS_F;
				break;
			case HDR_ROUTE_T:
				link_sibling_hdr(route,hf);
				msg->parsed_flag|=HDR_ROUTE_F;
				break;
			case HDR_RECORDROUTE_T:
				link_sibling_hdr(record_route,hf);
				msg->parsed_flag|=HDR_RECORDROUTE_F;
				break;
			case HDR_PATH_T:
				link_sibling_hdr(path,hf);
				msg->parsed_flag|=HDR_PATH_F;
				break;
			case HDR_CONTENTTYPE_T:
				if (msg->content_type==0) msg->content_type = hf;
				msg->parsed_flag|=HDR_CONTENTTYPE_F;
				break;
			case HDR_CONTENTLENGTH_T:
				if (msg->content_length==0) msg->content_length = hf;
				msg->parsed_flag|=HDR_CONTENTLENGTH_F;
				break;
			case HDR_AUTHORIZATION_T:
				link_sibling_hdr(authorization,hf);
				msg->parsed_flag|=HDR_AUTHORIZATION_F;
				break;
			case HDR_EXPIRES_T:
				if (msg->expires==0) msg->expires = hf;
				msg->parsed_flag|=HDR_EXPIRES_F;
				break;
			case HDR_PROXYAUTH_T:
				link_sibling_hdr(proxy_auth,hf);
				msg->parsed_flag|=HDR_PROXYAUTH_F;
				break;
			case HDR_PROXYREQUIRE_T:
				link_sibling_hdr(proxy_require,hf);
				msg->parsed_flag|=HDR_PROXYREQUIRE_F;
				break;
			case HDR_SUPPORTED_T:
				link_sibling_hdr(supported,hf);
				msg->parsed_flag|=HDR_SUPPORTED_F;
				break;
			case HDR_UNSUPPORTED_T:
				link_sibling_hdr(unsupported,hf);
				msg->parsed_flag|=HDR_UNSUPPORTED_F;
				break;
			case HDR_ALLOW_T:
				link_sibling_hdr(allow,hf);
				msg->parsed_flag|=HDR_ALLOW_F;
				break;
			case HDR_EVENT_T:
				link_sibling_hdr(event,hf);
				msg->parsed_flag|=HDR_EVENT_F;
				break;
			case HDR_ACCEPT_T:
				link_sibling_hdr(accept,hf);
				msg->parsed_flag|=HDR_ACCEPT_F;
				break;
			case HDR_ACCEPTLANGUAGE_T:
				link_sibling_hdr(accept_language,hf);
				msg->parsed_flag|=HDR_ACCEPTLANGUAGE_F;
				break;
			case HDR_ORGANIZATION_T:
				if (msg->organization==0) msg->organization = hf;
				msg->parsed_flag|=HDR_ORGANIZATION_F;
				break;
			case HDR_PRIORITY_T:
				if (msg->priority==0) msg->priority = hf;
				msg->parsed_flag|=HDR_PRIORITY_F;
				break;
			case HDR_SUBJECT_T:
				if (msg->subject==0) msg->subject = hf;
				msg->parsed_flag|=HDR_SUBJECT_F;
				break;
			case HDR_USERAGENT_T:
				if (msg->user_agent==0) msg->user_agent = hf;
				msg->parsed_flag|=HDR_USERAGENT_F;
				break;
			case HDR_CONTENTDISPOSITION_T:
				if (msg->content_disposition==0) msg->content_disposition = hf;
				msg->parsed_flag|=HDR_CONTENTDISPOSITION_F;
				break;
			case HDR_ACCEPTDISPOSITION_T:
				link_sibling_hdr(accept_disposition,hf);
				msg->parsed_flag|=HDR_ACCEPTDISPOSITION_F;
				break;
			case HDR_DIVERSION_T:
				link_sibling_hdr(diversion,hf);
				msg->parsed_flag|=HDR_DIVERSION_F;
				break;
			case HDR_RPID_T:
				if (msg->rpid==0) msg->rpid = hf;
				msg->parsed_flag|=HDR_RPID_F;
				break;
			case HDR_CALL_INFO_T:
				link_sibling_hdr(call_info,hf);
				msg->parsed_flag|=HDR_CALL_INFO_F;
				break;
			case HDR_WWW_AUTHENTICATE_T:
				link_sibling_hdr(www_authenticate,hf);
				msg->parsed_flag|=HDR_WWW_AUTHENTICATE_F;
				break;
			case HDR_PROXY_AUTHENTICATE_T:
				link_sibling_hdr(proxy_authenticate,hf);
				msg->parsed_flag|=HDR_PROXY_AUTHENTICATE_F;
				break;
			case HDR_REFER_TO_T:
				if (msg->refer_to==0) msg->refer_to = hf;
				msg->parsed_flag|=HDR_REFER_TO_F;
				break;
			case HDR_SESSION_EXPIRES_T:
				if ( msg->session_expires == 0 ) msg->session_expires = hf;
				msg->parsed_flag |= HDR_SESSION_EXPIRES_F;
				break;
			case HDR_MIN_SE_T:
				if ( msg->min_se == 0 ) msg->min_se = hf;
				msg->parsed_flag |= HDR_MIN_SE_F;
				break;
			case HDR_MIN_EXPIRES_T:
				if ( msg->min_expires == 0 ) msg->min_expires = hf;
				msg->parsed_flag |= HDR_MIN_EXPIRES_F;
				break;
			case HDR_PPI_T:
				if (msg->ppi==0) msg->ppi = hf;
				msg->parsed_flag|=HDR_PPI_F;
				break;
			case HDR_PAI_T:
				if (msg->pai==0) msg->pai = hf;
				msg->parsed_flag|=HDR_PAI_F;
				break;
			case HDR_PRIVACY_T:
				if (msg->privacy==0) msg->privacy = hf;
				msg->parsed_flag|=HDR_PRIVACY_F;
				break;
			case HDR_RETRY_AFTER_T:
				break;
			case HDR_VIA_T:
				link_sibling_hdr(h_via1,hf);
				msg->parsed_flag|=HDR_VIA_F;
				LM_DBG("via found, flags=%llx\n", (unsigned long long)flags);
				if (msg->via1==0) {
					LM_DBG("this is the first via\n");
					msg->h_via1=hf;
					msg->via1=hf->parsed;
					if (msg->via1->next){
						msg->via2=msg->via1->next;
						msg->parsed_flag|=HDR_VIA2_F;
					}
				}else if (msg->via2==0){
					msg->h_via2=hf;
					msg->via2=hf->parsed;
					msg->parsed_flag|=HDR_VIA2_F;
					LM_DBG("parse_headers: this is the second via\n");
				}
				break;
			default:
				LM_CRIT("unknown header type %d\n",	hf->type);
				goto error;
		}
		/* add the header to the list*/
		if (msg->last_header==0){
			msg->headers=hf;
			msg->last_header=hf;
		}else{
			msg->last_header->next=hf;
			msg->last_header=hf;
		}
#ifdef EXTRA_DEBUG
		LM_DBG("header field type %d, name=<%.*s>, body=<%.*s>\n",
			hf->type,
			hf->name.len, ZSW(hf->name.s),
			hf->body.len, ZSW(hf->body.s));
#endif
		tmp=rest;
	}
skip:
	msg->unparsed=tmp;
	return 0;

error:
	ser_error=E_BAD_REQ;
	if (hf) pkg_free(hf);
	if (next) msg->parsed_flag |= orig_flag;
	return -1;
}