Example #1
0
bool random_stress(void) {
  void *ptr_array[256];
  size_t i;
  int idx;

  corruption_cnt = 0;

  printf("Size of umm_heap is %u\n", (unsigned int) sizeof(test_umm_heap));

  umm_init();

  umm_info(NULL, 1);

  for (idx = 0; idx < 256; ++idx) ptr_array[idx] = (void *) NULL;

  for (idx = 0; idx < 100000; ++idx) {
    i = rand() % 256;

    /* try to realloc some pointer to deliberately too large value */
    {
      void *tmp = wrap_realloc(ptr_array[i], UMM_MALLOC_CFG__HEAP_SIZE);
      if (tmp != NULL) {
        printf("realloc to too large buffer should return NULL");
        return false;
      }
    }

    switch (rand() % 16) {
      case 0:
      case 1:
      case 2:
      case 3:
      case 4:
      case 5:
      case 6: {
        ptr_array[i] = wrap_realloc(ptr_array[i], 0);
        break;
      }
      case 7:
      case 8: {
        size_t size = rand() % 40;
        ptr_array[i] = wrap_realloc(ptr_array[i], size);
        memset(ptr_array[i], 0xfe, size);
        break;
      }

      case 9:
      case 10:
      case 11:
      case 12: {
        size_t size = rand() % 100;
        ptr_array[i] = wrap_realloc(ptr_array[i], size);
        memset(ptr_array[i], 0xfe, size);
        break;
      }

      case 13:
      case 14: {
        size_t size = rand() % 200;
        wrap_free(ptr_array[i]);
        ptr_array[i] = wrap_calloc(1, size);
        if (ptr_array[i] != NULL) {
          int a;
          for (a = 0; a < size; a++) {
            if (((char *) ptr_array[i])[a] != 0x00) {
              printf("calloc returned non-zeroed memory\n");
              return false;
            }
          }
        }
        memset(ptr_array[i], 0xfe, size);
        break;
      }

      default: {
        size_t size = rand() % 400;
        wrap_free(ptr_array[i]);
        ptr_array[i] = wrap_malloc(size);
        memset(ptr_array[i], 0xfe, size);
        break;
      }
    }
  }

  return (corruption_cnt == 0);
}
Example #2
0
/*
 * Function to decompress a compressed message
 */
static int mc_decompress(struct sip_msg* msg)
{
	#define HDRS_TO_SKIP 4

	int i;
	int j;
	int rc;
	int algo=-1;
	int hdrs_algo=-1;
	int b64_required=-1;

	str msg_body;
	str msg_final;

	str b64_decode={NULL, 0};
	str hdr_b64_decode={NULL,0};
	str uncomp_body={NULL,0};
	str uncomp_hdrs={NULL,0};

	char *new_buf;

	unsigned long temp;

	/* hdr_vec allows to sort the headers. This will help skipping
		these headers when building the new message */
	struct hdr_field *hf;
	struct hdr_field *hdr_vec[HDRS_TO_SKIP];
					/*hdr_vec : 	0 Content-Length
							1 Comp-Hdrs
							2 Headers-Algo
							3 Content-Encoding*/

	memset(hdr_vec, 0, HDRS_TO_SKIP * sizeof(struct hdr_field*));

	if (parse_headers(msg, HDR_EOH_F, 0) != 0) {
		LM_ERR("failed to parse SIP message\n");
		return -1;
	}

	/*If compressed with this module there are great chances that Content-Encoding is last*/
	hdr_vec[3] = msg->last_header;

	if (!is_content_encoding(hdr_vec[3])) {
		hdr_vec[3] = NULL;
		for (hf = msg->headers; hf; hf = hf->next) {
			if (is_content_encoding(hf)) {
				hdr_vec[3] = hf;
				continue;
			}
			if (hf->type == HDR_OTHER_T &&
				!strncasecmp(hf->name.s, COMP_HDRS,COMP_HDRS_LEN)) {
				hdr_vec[1] = hf;
				continue;
			}

			if (hf->type == HDR_OTHER_T &&
				!strncasecmp(hf->name.s, HDRS_ENCODING,
						sizeof(HDRS_ENCODING)-1)) {
				hdr_vec[2] = hf;
			}

			if (hdr_vec[1] && hdr_vec[2] && hdr_vec[3])
					break;
		}
	} else {
		for (hf = msg->headers; hf; hf = hf->next) {
			if (!hdr_vec[1] && hf->type == HDR_OTHER_T &&
				!strncasecmp(hf->name.s, COMP_HDRS,COMP_HDRS_LEN)) {
				hdr_vec[1] = hf;
				continue;
			}

			if (!hdr_vec[2] && hf->type == HDR_OTHER_T &&
				!strncasecmp(hf->name.s, HDRS_ENCODING,
						sizeof(HDRS_ENCODING)-1))
				hdr_vec[2] = hf;

			if (hdr_vec[2] && hdr_vec[3] && hdr_vec[1])
					break;
		}
	}

	/* Only if content-encoding present, Content-Length will be replaced
		with the one in the compressed body or in compressed headers*/

	if (hdr_vec[3]) {
		hdr_vec[0] = msg->content_length;
		parse_algo_hdr(hdr_vec[3], &algo, &b64_required);
	}


	if (b64_required > 0 && hdr_vec[3]) {
		msg_body.s = msg->last_header->name.s + msg->last_header->len + CRLF_LEN;
		msg_body.len = strlen(msg_body.s);

		/* Cutting CRLF'S at the end of the message */
		while (WORD(msg_body.s + msg_body.len-CRLF_LEN) == PARSE_CRLF) {
			msg_body.len -= CRLF_LEN;
		}

		if (wrap_realloc(&body_in, calc_max_base64_decode_len(msg_body.len)))
			return -1;

		b64_decode.s = body_in.s;

		b64_decode.len = base64decode((unsigned char*)b64_decode.s,
						(unsigned char*)msg_body.s,
							msg_body.len);
	} else if (hdr_vec[3]) {
		if (get_body(msg, &msg_body) < 0) {
			LM_ERR("failed to get body\n");
			return -1;
		}

		b64_decode.s = msg_body.s;
		b64_decode.len = msg_body.len;
	}

	b64_required=0;
	if (hdr_vec[2]) {
		parse_algo_hdr(hdr_vec[3], &algo, &b64_required);
	}

	if (b64_required > 0 &&  hdr_vec[1]) {
		if (wrap_realloc(&hdr_in, calc_max_base64_decode_len(hdr_vec[1]->body.len)))
			return -1;

		hdr_b64_decode.s = hdr_in.s;

		hdr_b64_decode.len = base64decode(
					(unsigned char*)hdr_b64_decode.s,
					(unsigned char*)hdr_vec[1]->body.s,
							hdr_vec[1]->body.len
					);
	} else if (hdr_vec[1]) {
		hdr_b64_decode.s = hdr_vec[1]->body.s;
		hdr_b64_decode.len = hdr_vec[1]->body.len;
	}

	switch (hdrs_algo) {
		case 0: /* deflate */
			temp = (unsigned long)BUFLEN;

			rc = uncompress((unsigned char*)hdr_buf,
					&temp,
					(unsigned char*)hdr_b64_decode.s,
					(unsigned long)hdr_b64_decode.len);

			uncomp_hdrs.s = hdr_buf;
			uncomp_hdrs.len = temp;

			if (check_zlib_rc(rc)) {
				LM_ERR("header decompression failed\n");
				return -1;
			}
			break;
		case 1: /* gzip */
			rc = gzip_uncompress(
					(unsigned char*)hdr_b64_decode.s,
					(unsigned long)hdr_b64_decode.len,
					&hdr_out,
					&temp);

			if (check_zlib_rc(rc)) {
				LM_ERR("header decompression failed\n");
				return -1;
			}

			uncomp_hdrs.s = hdr_out.s;
			uncomp_hdrs.len = temp;

			break;
		case -1:
			break;
		default:
			return -1;
	}

	switch (algo) {
		case 0: /* deflate */
			temp = (unsigned long)BUFLEN;

			rc = uncompress((unsigned char*)body_buf,
					&temp,
					(unsigned char*)b64_decode.s,
					(unsigned long)b64_decode.len);

			if (check_zlib_rc(rc)) {
				LM_ERR("body decompression failed\n");
				return -1;
			}

			uncomp_body.s = body_buf;
			uncomp_body.len = temp;

			break;
		case 1: /* gzip */
			rc = gzip_uncompress(
					(unsigned char*)b64_decode.s,
					(unsigned long)b64_decode.len,
					&body_out,
					&temp);

			if (check_zlib_rc(rc)) {
				LM_ERR("body decompression failed\n");
				return -1;
			}

			uncomp_body.s = body_out.s;
			uncomp_body.len = temp;

			break;
		case -1:
			LM_DBG("no body\n");
			break;
		default:
			LM_ERR("invalid algo\n");
			return -1;
	}

	/* Sort to have the headers in order */
	for (i = 0; i < HDRS_TO_SKIP - 1; i++) {
		for (j = i + 1; j < HDRS_TO_SKIP; j++) {
			if (!hdr_vec[j])
				continue;

			if (!hdr_vec[i] && hdr_vec[j]) {
				hdr_vec[i] = hdr_vec[j];
				hdr_vec[j] = NULL;
			}

			if ((hdr_vec[i] && hdr_vec[j]) &&
				(hdr_vec[i]->name.s > hdr_vec[j]->name.s)) {
				hf = hdr_vec[i];
				hdr_vec[i] = hdr_vec[j];
				hdr_vec[j] = hf;
			}
		}
	}

	int msg_final_len = 0;
	int msg_ptr=0;

	for ( i = 0; i < HDRS_TO_SKIP; i++) {
		if (hdr_vec[i]) {
			msg_final_len += hdr_vec[i]->name.s - (msg->buf+msg_ptr);
			msg_ptr += hdr_vec[i]->name.s+hdr_vec[i]->len - (msg->buf+msg_ptr);
		}
	}

	msg_final_len += msg->last_header->name.s + msg->last_header->len -
				(msg->buf + msg_ptr);

	if (hdrs_algo >= 0)
		msg_final_len += uncomp_hdrs.len;

	if (algo >= 0)
		msg_final_len += uncomp_body.len;
	else
		msg_final_len += strlen(msg->eoh);

	if (wrap_realloc(&buf_out, msg_final_len))
		return -1;

	msg_ptr = 0;

	msg_final.len = 0;
	msg_final.s = buf_out.s;

	for ( i = 0; i < HDRS_TO_SKIP; i++) {
		if (hdr_vec[i]) {
			wrap_copy_and_update(&msg_final.s,
					msg->buf+msg_ptr,
					hdr_vec[i]->name.s-(msg->buf+msg_ptr),
					&msg_final.len);

			msg_ptr += (hdr_vec[i]->name.s+hdr_vec[i]->len) -
					(msg->buf+msg_ptr);
		}
	}

	wrap_copy_and_update(
			&msg_final.s,
			msg->buf+msg_ptr,
			(msg->last_header->name.s+msg->last_header->len)-
							(msg->buf+msg_ptr),
			&msg_final.len
		);

	if (hdrs_algo >= 0) {
		wrap_copy_and_update(&msg_final.s, uncomp_hdrs.s,
					uncomp_hdrs.len,&msg_final.len);
	}

	if (algo >= 0) {
		wrap_copy_and_update(&msg_final.s, uncomp_body.s,
					uncomp_body.len, &msg_final.len);
	} else {
		wrap_copy_and_update(&msg_final.s, msg->eoh, strlen(msg->eoh), &msg_final.len);
	}

	/* new buffer because msg_final(out_buf) will
	 * be overwritten at next iteration */
#ifdef DYN_BUF
	new_buf = pkg_malloc(msg_final.len+1);
	if (new_buf == NULL) {
		LM_ERR("no more pkg mem\n");
		return -1;
	}
#else
	new_buf = msg->buf;
#endif

	memcpy(new_buf, msg_final.s, msg_final.len);
	new_buf[msg_final.len] = '\0';

	struct sip_msg tmp;

	memcpy(&tmp, msg, sizeof(struct sip_msg));

	/*reset dst_uri and path_vec to avoid free*/
	if (msg->dst_uri.s != NULL) {
		msg->dst_uri.s = NULL;
		msg->dst_uri.len = 0;
	}
	if (msg->path_vec.s != NULL)
	{
		msg->path_vec.s = NULL;
		msg->path_vec.len = 0;
	}

	free_sip_msg(msg);
	memset(msg, 0, sizeof(struct sip_msg));

	/* restore msg fields */
	msg->id					= tmp.id;
	msg->rcv				= tmp.rcv;
	msg->set_global_address = tmp.set_global_address;
	msg->set_global_port    = tmp.set_global_port;
	msg->flags              = tmp.flags;
	msg->msg_flags          = tmp.msg_flags;
	msg->hash_index         = tmp.hash_index;
	msg->force_send_socket  = tmp.force_send_socket;
	msg->dst_uri            = tmp.dst_uri;
	msg->path_vec           = tmp.path_vec;
	/* set the new ones */
	msg->buf = new_buf;
	msg->len = msg_final.len;

	/* reparse the message */
	if (parse_msg(msg->buf, msg->len, msg) != 0)
		LM_ERR("parse_msg failed\n");

	return 1;
}
Example #3
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 #4
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;
}