/** Frees a hdr_field list. * WARNING: frees only ->parsed and ->next*/ void free_hdr_field_lst(struct hdr_field* hf) { struct hdr_field* foo; while(hf) { foo=hf; hf=hf->next; clean_hdr_field(foo); pkg_free(foo); } }
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; }
/* Continues the SIP request processing previously saved by * t_suspend(). The script does not continue from the same * point, but a separate route block is executed instead. * * Return value: * 0 - success * <0 - failure */ int t_continue(unsigned int hash_index, unsigned int label, struct action *route) { struct cell *t; struct sip_msg faked_req; struct cancel_info cancel_data; int branch; struct ua_client *uac =NULL; int ret; int cb_type; int msg_status; int last_uac_status; int reply_status; int do_put_on_wait; struct hdr_field *hdr, *prev = 0, *tmp = 0; if (t_lookup_ident(&t, hash_index, label) < 0) { LM_ERR("transaction not found\n"); return -1; } if (!(t->flags & T_ASYNC_SUSPENDED)) { LM_WARN("transaction is not suspended [%u:%u]\n", hash_index, label); return -2; } if (t->flags & T_CANCELED) { t->flags &= ~T_ASYNC_SUSPENDED; /* The transaction has already been canceled, * needless to continue */ UNREF(t); /* t_unref would kill the transaction */ /* reset T as we have no working T anymore */ set_t(T_UNDEFINED, T_BR_UNDEFINED); return 1; } /* The transaction has to be locked to protect it * form calling t_continue() multiple times simultaneously */ LOCK_ASYNC_CONTINUE(t); t->flags |= T_ASYNC_CONTINUE; /* we can now know anywhere in kamailio * that we are executing post a suspend */ /* which route block type were we in when we were suspended */ cb_type = FAILURE_CB_TYPE;; switch (t->async_backup.backup_route) { case REQUEST_ROUTE: cb_type = FAILURE_CB_TYPE; break; case FAILURE_ROUTE: cb_type = FAILURE_CB_TYPE; break; case TM_ONREPLY_ROUTE: cb_type = ONREPLY_CB_TYPE; break; case BRANCH_ROUTE: cb_type = FAILURE_CB_TYPE; break; } if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){ branch = t->async_backup.blind_uac; /* get the branch of the blind UAC setup * during suspend */ if (branch >= 0) { stop_rb_timers(&t->uac[branch].request); if (t->uac[branch].last_received != 0) { /* Either t_continue() has already been * called or the branch has already timed out. * Needless to continue. */ t->flags &= ~T_ASYNC_SUSPENDED; UNLOCK_ASYNC_CONTINUE(t); UNREF(t); /* t_unref would kill the transaction */ return 1; } /* Set last_received to something >= 200, * the actual value does not matter, the branch * will never be picked up for response forwarding. * If last_received is lower than 200, * then the branch may tried to be cancelled later, * for example when t_reply() is called from * a failure route => deadlock, because both * of them need the reply lock to be held. */ t->uac[branch].last_received=500; uac = &t->uac[branch]; } /* else Not a huge problem, fr timer will fire, but CANCEL will not be sent. last_received will be set to 408. */ /* We should not reset kr here to 0 as it's quite possible before continuing the dev. has correctly set the * kr by, for example, sending a transactional reply in code - resetting here will cause a dirty log message * "WARNING: script writer didn't release transaction" to appear in log files. TODO: maybe we need to add * a special kr for async? * reset_kr(); */ /* fake the request and the environment, like in failure_route */ if (!fake_req(&faked_req, t->uas.request, 0 /* extra flags */, uac)) { LM_ERR("building fake_req failed\n"); ret = -1; goto kill_trans; } faked_env( t, &faked_req, 1); /* execute the pre/post -script callbacks based on original route block */ if (exec_pre_script_cb(&faked_req, cb_type)>0) { if (run_top_route(route, &faked_req, 0)<0) LM_ERR("failure inside run_top_route\n"); exec_post_script_cb(&faked_req, cb_type); } /* TODO: save_msg_lumps should clone the lumps to shm mem */ /* restore original environment and free the fake msg */ faked_env( t, 0, 1); free_faked_req(&faked_req, t); /* update the flags */ t->uas.request->flags = faked_req.flags; if (t->uas.status < 200) { /* No final reply has been sent yet. * Check whether or not there is any pending branch. */ for ( branch = 0; branch < t->nr_of_outgoings; branch++ ) { if (t->uac[branch].last_received < 200) break; } if (branch == t->nr_of_outgoings) { /* There is not any open branch so there is * no chance that a final response will be received. */ ret = 0; goto kill_trans; } } } else { branch = t->async_backup.backup_branch; init_cancel_info(&cancel_data); LM_DBG("continuing from a suspended reply" " - resetting the suspend branch flag\n"); if (t->uac[branch].reply) { t->uac[branch].reply->msg_flags &= ~FL_RPL_SUSPENDED; } else { LM_WARN("no reply in t_continue for branch. not much we can do\n"); return 0; } if (t->uas.request) t->uas.request->msg_flags&= ~FL_RPL_SUSPENDED; faked_env( t, t->uac[branch].reply, 1); if (exec_pre_script_cb(t->uac[branch].reply, cb_type)>0) { if (run_top_route(route, t->uac[branch].reply, 0)<0){ LOG(L_ERR, "ERROR: t_continue_reply: Error in run_top_route\n"); } exec_post_script_cb(t->uac[branch].reply, cb_type); } LM_DBG("restoring previous environment"); faked_env( t, 0, 1); /*lock transaction replies - will be unlocked when reply is relayed*/ LOCK_REPLIES( t ); if ( is_local(t) ) { LM_DBG("t is local - sending reply with status code: [%d]\n", t->uac[branch].reply->first_line.u.reply.statuscode); reply_status = local_reply( t, t->uac[branch].reply, branch, t->uac[branch].reply->first_line.u.reply.statuscode, &cancel_data ); if (reply_status == RPS_COMPLETED) { /* no more UAC FR/RETR (if I received a 2xx, there may * be still pending branches ... */ cleanup_uac_timers( t ); if (is_invite(t)) cancel_uacs(t, &cancel_data, F_CANCEL_B_KILL); /* There is no need to call set_final_timer because we know * that the transaction is local */ put_on_wait(t); }else if (unlikely(cancel_data.cancel_bitmap)){ /* cancel everything, even non-INVITEs (e.g in case of 6xx), use * cancel_b_method for canceling unreplied branches */ cancel_uacs(t, &cancel_data, cfg_get(tm,tm_cfg, cancel_b_flags)); } } else { LM_DBG("t is not local - relaying reply with status code: [%d]\n", t->uac[branch].reply->first_line.u.reply.statuscode); do_put_on_wait = 0; if(t->uac[branch].reply->first_line.u.reply.statuscode>=200){ do_put_on_wait = 1; } reply_status=relay_reply( t, t->uac[branch].reply, branch, t->uac[branch].reply->first_line.u.reply.statuscode, &cancel_data, do_put_on_wait ); if (reply_status == RPS_COMPLETED) { /* no more UAC FR/RETR (if I received a 2xx, there may be still pending branches ... */ cleanup_uac_timers( t ); /* 2xx is a special case: we can have a COMPLETED request * with branches still open => we have to cancel them */ if (is_invite(t) && cancel_data.cancel_bitmap) cancel_uacs( t, &cancel_data, F_CANCEL_B_KILL); /* FR for negative INVITES, WAIT anything else */ /* Call to set_final_timer is embedded in relay_reply to avoid * race conditions when reply is sent out and an ACK to stop * retransmissions comes before retransmission timer is set.*/ }else if (unlikely(cancel_data.cancel_bitmap)){ /* cancel everything, even non-INVITEs (e.g in case of 6xx), use * cancel_b_method for canceling unreplied branches */ cancel_uacs(t, &cancel_data, cfg_get(tm,tm_cfg, cancel_b_flags)); } } t->uac[branch].request.flags|=F_RB_REPLIED; if (reply_status==RPS_ERROR){ goto done; } /* update FR/RETR timers on provisional replies */ msg_status=t->uac[branch].reply->REPLY_STATUS; last_uac_status=t->uac[branch].last_received; if (is_invite(t) && msg_status<200 && ( cfg_get(tm, tm_cfg, restart_fr_on_each_reply) || ( (last_uac_status<msg_status) && ((msg_status>=180) || (last_uac_status==0)) ) ) ) { /* provisional now */ restart_rb_fr(& t->uac[branch].request, t->fr_inv_timeout); t->uac[branch].request.flags|=F_RB_FR_INV; /* mark fr_inv */ } } done: UNLOCK_ASYNC_CONTINUE(t); if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){ /* unref the transaction */ t_unref(t->uas.request); } else { tm_ctx_set_branch_index(T_BR_UNDEFINED); /* unref the transaction */ t_unref(t->uac[branch].reply); LOG(L_DBG,"DEBUG: t_continue_reply: Freeing earlier cloned reply\n"); /* free lumps that were added during reply processing */ del_nonshm_lump( &(t->uac[branch].reply->add_rm) ); del_nonshm_lump( &(t->uac[branch].reply->body_lumps) ); del_nonshm_lump_rpl( &(t->uac[branch].reply->reply_lump) ); /* free header's parsed structures that were added */ for( hdr=t->uac[branch].reply->headers ; hdr ; hdr=hdr->next ) { if ( hdr->parsed && hdr_allocs_parse(hdr) && (hdr->parsed<(void*)t->uac[branch].reply || hdr->parsed>=(void*)t->uac[branch].end_reply)) { clean_hdr_field(hdr); hdr->parsed = 0; } } /* now go through hdr_fields themselves and remove the pkg allocated space */ hdr = t->uac[branch].reply->headers; while (hdr) { if ( hdr && ((void*)hdr<(void*)t->uac[branch].reply || (void*)hdr>=(void*)t->uac[branch].end_reply)) { //this header needs to be freed and removed form the list. if (!prev) { t->uac[branch].reply->headers = hdr->next; } else { prev->next = hdr->next; } tmp = hdr; hdr = hdr->next; pkg_free(tmp); } else { prev = hdr; hdr = hdr->next; } } sip_msg_free(t->uac[branch].reply); t->uac[branch].reply = 0; } /*This transaction is no longer suspended so unsetting the SUSPEND flag*/ t->flags &= ~T_ASYNC_SUSPENDED; return 0; kill_trans: t->flags &= ~T_ASYNC_SUSPENDED; /* The script has hopefully set the error code. If not, * let us reply with a default error. */ if ((kill_transaction_unsafe(t, tm_error ? tm_error : E_UNSPEC)) <=0 ) { LOG(L_ERR, "ERROR: t_continue: " "reply generation failed\n"); /* The transaction must be explicitely released, * no more timer is running */ UNLOCK_ASYNC_CONTINUE(t); t_release_transaction(t); } else { UNLOCK_ASYNC_CONTINUE(t); } if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){ t_unref(t->uas.request); } else { /* unref the transaction */ t_unref(t->uac[branch].reply); } return ret; }
/* initiate a report if we previously enabled accounting for this t */ static inline void acc_onreply( struct cell* t, struct sip_msg *req, struct sip_msg *reply, int code) { str new_uri_bk; int br = -1; hdr_field_t *hdr; sip_msg_t tmsg; sip_msg_t *preq; /* acc_onreply is bound to TMCB_REPLY which may be called from _reply, like when FR hits; we should not miss this event for missed calls either */ if (is_invite(t) && code>=300 && is_mc_on(req) ) on_missed(t, req, reply, code); if (!should_acc_reply(req, reply, code)) return; if(_acc_clone_msg==1) { memcpy(&tmsg, req, sizeof(sip_msg_t)); preq = &tmsg; } else { preq = req; } /* get winning branch index, if set */ if (t->relayed_reply_branch>=0) { br = t->relayed_reply_branch; } else { if(code>=300) { br = tmb.t_get_picked_branch(); } } /* for reply processing, set as new_uri the one from selected branch */ if (br>=0) { new_uri_bk = preq->new_uri; preq->new_uri = t->uac[br].uri; preq->parsed_uri_ok = 0; } else { new_uri_bk.len = -1; new_uri_bk.s = 0; } /* set env variables */ env_set_to( get_rpl_to(t,reply) ); env_set_code_status( code, reply); if ( is_log_acc_on(preq) ) { env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN); acc_log_request(preq); } #ifdef SQL_ACC if (is_db_acc_on(preq)) { if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) { LM_ERR("cannot set acc db table name\n"); } else { acc_db_request(preq); } } #endif #ifdef RAD_ACC if (is_rad_acc_on(preq)) acc_rad_request(preq); #endif /* DIAMETER */ #ifdef DIAM_ACC if (is_diam_acc_on(preq)) acc_diam_request(preq); #endif /* run extra acc engines */ acc_run_engines(preq, 0, NULL); if (new_uri_bk.len>=0) { req->new_uri = new_uri_bk; req->parsed_uri_ok = 0; } /* free header's parsed structures that were added by resolving acc attributes */ for( hdr=req->headers ; hdr ; hdr=hdr->next ) { if ( hdr->parsed && hdr_allocs_parse(hdr) && (hdr->parsed<(void*)t->uas.request || hdr->parsed>=(void*)t->uas.end_request)) { /* header parsed filed doesn't point inside uas.request memory * chunck -> it was added by resolving acc attributes -> free it as pkg */ DBG("removing hdr->parsed %d\n", hdr->type); clean_hdr_field(hdr); hdr->parsed = 0; } } }
/* initiate a report if we previously enabled accounting for this t */ static void acc_onreply(tm_cell_t *t, sip_msg_t *req, sip_msg_t *reply, int code) { str new_uri_bk; int br = -1; hdr_field_t *hdr; sip_msg_t *cmsg = 0; int cmsg_len = 0; sip_msg_t *preq = 0; void *mstart; void *mend; /* acc_onreply is bound to TMCB_REPLY which may be called from _reply, like when FR hits; we should not miss this event for missed calls either */ if (is_invite(t) && code>=300 && is_mc_on(req) ) on_missed(t, req, reply, code); if (!should_acc_reply(req, reply, code)) return; if(_acc_clone_msg==1) { /* make a clone so eventual new parsed headers in pkg are not visible * to other processes -- other attributes should be already parsed, * available in the req structure and propagated by cloning */ cmsg = sip_msg_shm_clone(req, &cmsg_len, 1); if(cmsg==NULL) { LM_ERR("failed to clone the request - acc aborted\n"); return; } mstart = cmsg; mend = ((char*)cmsg) + cmsg_len; preq = cmsg; } else { mstart = t->uas.request; mend = t->uas.end_request; preq = req; } /* get winning branch index, if set */ if (t->relayed_reply_branch>=0) { br = t->relayed_reply_branch; } else { if(code>=300) { br = tmb.t_get_picked_branch(); } } /* for reply processing, set as new_uri the one from selected branch */ if (br>=0) { new_uri_bk = preq->new_uri; preq->new_uri = t->uac[br].uri; preq->parsed_uri_ok = 0; } else { new_uri_bk.len = -1; new_uri_bk.s = 0; } /* set env variables */ env_set_to( get_rpl_to(t,reply) ); env_set_code_status( code, reply); if ( is_log_acc_on(preq) ) { env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN); acc_log_request(preq); } #ifdef SQL_ACC if (is_db_acc_on(preq)) { if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) { LM_ERR("cannot set acc db table name\n"); } else { acc_db_request(preq); } } #endif /* DIAMETER */ #ifdef DIAM_ACC if (is_diam_acc_on(preq)) acc_diam_request(preq); #endif /* run extra acc engines */ acc_run_engines(preq, 0, NULL); if (new_uri_bk.len>=0) { preq->new_uri = new_uri_bk; preq->parsed_uri_ok = 0; } /* free header's parsed structures that were added by resolving acc attributes */ for( hdr=preq->headers ; hdr ; hdr=hdr->next ) { if (hdr->parsed && hdr_allocs_parse(hdr) && (hdr->parsed<mstart || hdr->parsed>=mend)) { /* header parsed filed doesn't point inside cloned request memory * chunck -> it was added by resolving acc attributes -> free it as pkg */ DBG("removing hdr->parsed %d\n", hdr->type); clean_hdr_field(hdr); hdr->parsed = 0; } } if(cmsg!=NULL) { shm_free(cmsg); } }