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; }
/* 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; }
/* 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; }
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; }
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; }
/* 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; }