Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 267670)
+++ channels/chan_sip.c	(working copy)
@@ -1527,8 +1527,8 @@
 static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
 static void make_our_tag(char *tagbuf, size_t len);
 static int add_header(struct sip_request *req, const char *var, const char *value);
-static int add_header_contentLength(struct sip_request *req, int len);
-static int add_line(struct sip_request *req, const char *line);
+static int add_content(struct sip_request *req, const char *line);
+static int finalize_content(struct sip_request *req);
 static int add_text(struct sip_request *req, const char *text);
 static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode);
 static int add_rpid(struct sip_request *req, struct sip_pvt *p);
@@ -8623,30 +8623,37 @@
 	return 0;	
 }
 
-/*! \brief Add 'Content-Length' header to SIP message */
-static int add_header_contentLength(struct sip_request *req, int len)
+/*! \brief Add 'Content-Length' header and content to SIP message */
+static int finalize_content(struct sip_request *req)
 {
 	char clen[10];
 
-	snprintf(clen, sizeof(clen), "%d", len);
-	return add_header(req, "Content-Length", clen);
+	snprintf(clen, sizeof(clen), "%zd", ast_str_strlen(req->content));
+	add_header(req, "Content-Length", clen);
+
+	if (ast_str_strlen(req->content)) {
+		ast_str_append(&req->data, 0, "\r\n%s", req->content->str);
+		req->len = ast_str_strlen(req->data);
+	}
+	req->lines = ast_str_strlen(req->content) ? 1 : 0;
+	return 0;
 }
 
 /*! \brief Add content (not header) to SIP message */
-static int add_line(struct sip_request *req, const char *line)
+static int add_content(struct sip_request *req, const char *line)
 {
 	if (req->lines == SIP_MAX_LINES)  {
 		ast_log(LOG_WARNING, "Out of SIP line space\n");
 		return -1;
 	}
-	if (!req->lines)
-		/* Add extra empty return */
-		req->len += ast_str_append(&req->data, 0, "\r\n");
-	req->line[req->lines] = req->len;
-	ast_str_append(&req->data, 0, "%s", line);
-	req->len = ast_str_strlen(req->data);
-	req->lines++;
-	return 0;	
+
+	if (req->lines) {
+		ast_log(LOG_WARNING, "Can't add more content when the content has been finalized\n");
+		return -1;
+	}
+
+	ast_str_append(&req->content, 0, "%s", line);
+	return 0;
 }
 
 /*! \brief Copy one header field from one request to another */
@@ -8858,12 +8865,20 @@
 	memset(resp, 0, sizeof(*resp));
 	resp->method = SIP_RESPONSE;
 	if (!(resp->data = ast_str_create(SIP_MIN_PACKET)))
-		return -1;
+		goto e_return;
+	if (!(resp->content = ast_str_create(SIP_MIN_PACKET)))
+		goto e_free_data;
 	resp->header[0] = 0;
 	ast_str_set(&resp->data, 0, "SIP/2.0 %s\r\n", msg);
 	resp->len = resp->data->used;
 	resp->headers++;
 	return 0;
+
+e_free_data:
+	ast_free(resp->data);
+	resp->data = NULL;
+e_return:
+	return -1;
 }
 
 /*! \brief Initialize SIP request */
@@ -8872,13 +8887,21 @@
 	/* Initialize a request */
 	memset(req, 0, sizeof(*req));
 	if (!(req->data = ast_str_create(SIP_MIN_PACKET)))
-		return -1;
+		goto e_return;
+	if (!(req->content = ast_str_create(SIP_MIN_PACKET)))
+		goto e_free_data;
 	req->method = sipmethod;
 	req->header[0] = 0;
 	ast_str_set(&req->data, 0, "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip);
 	req->len = ast_str_strlen(req->data);
 	req->headers++;
 	return 0;
+
+e_free_data:
+	ast_free(req->data);
+	req->data = NULL;
+e_return:
+	return -1;
 }
 
 /*! \brief Test if this response needs a contact header */
@@ -9162,7 +9185,8 @@
 		add_cc_call_info_to_response(p, &resp);
 	}
 
-	add_header_contentLength(&resp, 0);
+	finalize_content(&resp);
+
 	/* If we are cancelling an incoming invite for some reason, add information
 		about the reason why we are doing this in clear text */
 	if (p->method == SIP_INVITE && msg[0] != '1') {
@@ -9292,7 +9316,7 @@
 	respprep(&resp, p, msg, req);
 	append_date(&resp);
 	add_header(&resp, "Unsupported", unsupported);
-	add_header_contentLength(&resp, 0);
+	finalize_content(&resp);
 	return send_response(p, &resp, XMIT_UNRELIABLE, 0);
 }
 
@@ -9307,8 +9331,8 @@
 
 	snprintf(minse_str, sizeof(minse_str), "%d", minse_int);
 	add_header(&resp, "Min-SE", minse_str);
+	finalize_content(&resp);
 
-	add_header_contentLength(&resp, 0);
 	return send_response(p, &resp, XMIT_UNRELIABLE, 0);
 }
 
@@ -9339,7 +9363,7 @@
 	struct sip_request resp;
 	respprep(&resp, p, msg, req);
 	append_date(&resp);
-	add_header_contentLength(&resp, 0);
+	finalize_content(&resp);
 	return send_response(p, &resp, XMIT_UNRELIABLE, 0);
 }
 
@@ -9349,7 +9373,7 @@
 	struct sip_request resp;
 	respprep(&resp, p, msg, req);
 	add_header(&resp, "Accept", "application/sdp");
-	add_header_contentLength(&resp, 0);
+	finalize_content(&resp);
 	return send_response(p, &resp, reliable, 0);
 }
 
@@ -9372,7 +9396,7 @@
 	snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"%s", p->realm, randdata, stale ? ", stale=true" : "");
 	respprep(&resp, p, msg, req);
 	add_header(&resp, header, tmp);
-	add_header_contentLength(&resp, 0);
+	finalize_content(&resp);
 	append_history(p, "AuthChal", "Auth challenge sent for %s - nc %d", p->username, p->noncecount);
 	return send_response(p, &resp, reliable, seqno);
 }
@@ -9469,8 +9493,8 @@
 {
 	/* XXX Convert \n's to \r\n's XXX */
 	add_header(req, "Content-Type", "text/plain;charset=UTF-8");
-	add_header_contentLength(req, strlen(text));
-	add_line(req, text);
+	add_content(req, text);
+	finalize_content(req);
 	return 0;
 }
 
@@ -9494,14 +9518,14 @@
 			event = atoi(&digit);
 		snprintf(tmp, sizeof(tmp), "%d\r\n", event);
 		add_header(req, "Content-Type", "application/dtmf");
-		add_header_contentLength(req, strlen(tmp));
-		add_line(req, tmp);
+		add_content(req, tmp);
+		finalize_content(req);
 	} else {
 		/* Application/dtmf-relay as documented by Cisco */
 		snprintf(tmp, sizeof(tmp), "Signal=%c\r\nDuration=%u\r\n", digit, duration);
 		add_header(req, "Content-Type", "application/dtmf-relay");
-		add_header_contentLength(req, strlen(tmp));
-		add_line(req, tmp);
+		add_content(req, tmp);
+		finalize_content(req);
 	}
 	return 0;
 }
@@ -9607,8 +9631,8 @@
 		"  </vc_primitive>\r\n"
 		" </media_control>\r\n";
 	add_header(req, "Content-Type", "application/media_control+xml");
-	add_header_contentLength(req, strlen(xml_is_a_huge_waste_of_space));
-	add_line(req, xml_is_a_huge_waste_of_space);
+	add_content(req, xml_is_a_huge_waste_of_space);
+	finalize_content(req);
 	return 0;
 }
 
@@ -9855,7 +9879,6 @@
 */
 static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38)
 {
-	int len = 0;
 	format_t alreadysent = 0;
 
 	struct sockaddr_in sin = { 0, };
@@ -10143,57 +10166,47 @@
  	if (needtext)
  		ast_str_append(&m_text, 0, "\r\n");
 
- 	len = strlen(version) + strlen(subject) + strlen(owner) +
-		strlen(connection) + strlen(session_time);
-	if (needaudio)
-		len += m_audio->used + a_audio->used + strlen(hold);
- 	if (needvideo) /* only if video response is appropriate */
- 		len += m_video->used + a_video->used + strlen(bandwidth) + strlen(hold);
- 	if (needtext) /* only if text response is appropriate */
- 		len += m_text->used + a_text->used + strlen(hold);
-	if (add_t38)
-		len += m_modem->used + a_modem->used;
-
 	add_header(resp, "Content-Type", "application/sdp");
-	add_header_contentLength(resp, len);
-	add_line(resp, version);
-	add_line(resp, owner);
-	add_line(resp, subject);
-	add_line(resp, connection);
+	add_content(resp, version);
+	add_content(resp, owner);
+	add_content(resp, subject);
+	add_content(resp, connection);
 	if (needvideo)	 	/* only if video response is appropriate */
-		add_line(resp, bandwidth);
-	add_line(resp, session_time);
+		add_content(resp, bandwidth);
+	add_content(resp, session_time);
 	if (needaudio) {
-		add_line(resp, m_audio->str);
-		add_line(resp, a_audio->str);
-		add_line(resp, hold);
+		add_content(resp, m_audio->str);
+		add_content(resp, a_audio->str);
+		add_content(resp, hold);
 	} else if (p->offered_media[SDP_AUDIO].offered) {
 		snprintf(dummy_answer, sizeof(dummy_answer), "m=audio 0 RTP/AVP %s\r\n", p->offered_media[SDP_AUDIO].codecs);
-		add_line(resp, dummy_answer);
+		add_content(resp, dummy_answer);
 	}
 	if (needvideo) { /* only if video response is appropriate */
-		add_line(resp, m_video->str);
-		add_line(resp, a_video->str);
-		add_line(resp, hold);	/* Repeat hold for the video stream */
+		add_content(resp, m_video->str);
+		add_content(resp, a_video->str);
+		add_content(resp, hold);	/* Repeat hold for the video stream */
 	} else if (p->offered_media[SDP_VIDEO].offered) {
 		snprintf(dummy_answer, sizeof(dummy_answer), "m=video 0 RTP/AVP %s\r\n", p->offered_media[SDP_VIDEO].codecs);
-		add_line(resp, dummy_answer);
+		add_content(resp, dummy_answer);
 	}
 	if (needtext) { /* only if text response is appropriate */
-		add_line(resp, m_text->str);
-		add_line(resp, a_text->str);
-		add_line(resp, hold);	/* Repeat hold for the text stream */
+		add_content(resp, m_text->str);
+		add_content(resp, a_text->str);
+		add_content(resp, hold);	/* Repeat hold for the text stream */
 	} else if (p->offered_media[SDP_TEXT].offered) {
 		snprintf(dummy_answer, sizeof(dummy_answer), "m=text 0 RTP/AVP %s\r\n", p->offered_media[SDP_TEXT].codecs);
-		add_line(resp, dummy_answer);
+		add_content(resp, dummy_answer);
 	}
 	if (add_t38) {
-		add_line(resp, m_modem->str);
-		add_line(resp, a_modem->str);
+		add_content(resp, m_modem->str);
+		add_content(resp, a_modem->str);
 	} else if (p->offered_media[SDP_IMAGE].offered) {
-		add_line(resp, "m=image 0 udptl t38\r\n");
+		add_content(resp, "m=image 0 udptl t38\r\n");
 	}
 
+	finalize_content(resp);
+
 	/* Update lastrtprx when we send our SDP */
 	p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
 
@@ -10820,9 +10833,8 @@
 	} else if (p->notify) {
 		for (var = p->notify->headers; var; var = var->next)
 			add_header(&req, var->name, var->value);
-		add_header_contentLength(&req, ast_str_strlen(p->notify->content));
 		if (ast_str_strlen(p->notify->content))
-			add_line(&req, ast_str_buffer(p->notify->content));
+			add_content(&req, ast_str_buffer(p->notify->content));
 	} else if (sipmethod == SIP_PUBLISH) {
 		char expires[SIPBUFSIZE];
 		switch (p->epa_entry->static_data->event) {
@@ -10835,17 +10847,13 @@
 			}
 			if (!ast_strlen_zero(p->epa_entry->body)) {
 				add_header(&req, "Content-Type", "application/pidf+xml");
-				add_header_contentLength(&req, strlen(p->epa_entry->body));
-				add_line(&req, p->epa_entry->body);
-			} else {
-				add_header_contentLength(&req, 0);
+				add_content(&req, p->epa_entry->body);
 			}
 		default:
 			break;
 		}
-	} else {
-		add_header_contentLength(&req, 0);
-    }
+	}
+	finalize_content(&req);
 
 	if (!p->initreq.headers || init > 2)
 		initialize_initreq(p, &req);
@@ -11144,12 +11152,11 @@
 		generate_uri(subscription, agent_pvt->notify_uri, sizeof(agent_pvt->notify_uri));
 		snprintf(uri, sizeof(uri) - 1, "cc-URI: %s\r\n", agent_pvt->notify_uri);
 	}
-	add_header_contentLength(&req, strlen(state_str) +
-			(state == CC_READY ? strlen(uri) : 0));
-	add_line(&req, state_str);
+	add_content(&req, state_str);
 	if (state == CC_READY) {
-		add_line(&req, uri);
+		add_content(&req, uri);
 	}
+	finalize_content(&req);
 	return send_request(subscription, &req, XMIT_RELIABLE, subscription->ocseq);
 }
 
@@ -11230,8 +11237,8 @@
 		break;
 	}
 
-	add_header_contentLength(&req, tmp->used);
-	add_line(&req, tmp->str);
+	add_content(&req, tmp->str);
+	finalize_content(&req);
 
 	p->pendinginvite = p->ocseq;	/* Remember that we have a pending NOTIFY in order not to confuse the NOTIFY subsystem */
 
@@ -11284,8 +11291,8 @@
 			add_header(&req, "Subscription-State", "terminated;reason=timeout");
 	}
 
-	add_header_contentLength(&req, out->used);
-	add_line(&req, out->str);
+	add_content(&req, out->str);
+	finalize_content(&req);
 
 	if (!p->initreq.headers)
 		initialize_initreq(p, &req);
@@ -11307,8 +11314,8 @@
 	add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
 
 	snprintf(tmp, sizeof(tmp), "SIP/2.0 %s\r\n", message);
-	add_header_contentLength(&req, strlen(tmp));
-	add_line(&req, tmp);
+	add_content(&req, tmp);
+	finalize_content(&req);
 
 	if (!p->initreq.headers)
 		initialize_initreq(p, &req);
@@ -11418,7 +11425,7 @@
 			reqprep(&req, p, SIP_UPDATE, 0, 1);
 			add_rpid(&req, p);
 			add_header(&req, "X-Asterisk-rpid-update", "Yes");
-			add_header_contentLength(&req, 0);
+			finalize_content(&req);
 			send_request(p, &req, XMIT_CRITICAL, p->ocseq);
 		} else {
 			/* We cannot send the update yet, so we have to wait until we can */
@@ -11776,7 +11783,7 @@
 	snprintf(tmp, sizeof(tmp), "%d", r->expiry);
 	add_header(&req, "Expires", tmp);
 	add_header(&req, "Contact", p->our_contact);
-	add_header_contentLength(&req, 0);
+	finalize_content(&req);
 
 	initialize_initreq(p, &req);
 	if (sip_debug_test_pvt(p)) {
@@ -11977,7 +11984,7 @@
 	if (sipmethod == SIP_CANCEL && p->answered_elsewhere)
 		add_header(&resp, "Reason", "SIP;cause=200;text=\"Call completed elsewhere\"");
 
-	add_header_contentLength(&resp, 0);
+	finalize_content(&resp);
 	return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
 }
 
@@ -12029,7 +12036,7 @@
 		add_header(&resp, "X-Asterisk-HangupCauseCode", buf);
 	}
 
-	add_header_contentLength(&resp, 0);
+	finalize_content(&resp);
 	return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);	
 }
 
Index: channels/sip/include/sip.h
===================================================================
--- channels/sip/include/sip.h	(revision 267670)
+++ channels/sip/include/sip.h	(working copy)
@@ -743,6 +743,7 @@
 	ptrdiff_t header[SIP_MAX_HEADERS]; /*!< Array of offsets into the request string of each SIP header*/
 	ptrdiff_t line[SIP_MAX_LINES];     /*!< Array of offsets into the request string of each SDP line*/
 	struct ast_str *data;	
+	struct ast_str *content;
 	/* XXX Do we need to unref socket.ser when the request goes away? */
 	struct sip_socket socket;          /*!< The socket used for this request */
 	AST_LIST_ENTRY(sip_request) next;
