Tomas Hozza 3ddaff
From 527e971a732d645d411df842ec4f8c401248ca0c Mon Sep 17 00:00:00 2001
Tomas Hozza 3ddaff
From: Tomas Hozza <thozza@redhat.com>
Tomas Hozza 3ddaff
Date: Fri, 18 Oct 2013 10:47:21 +0200
Tomas Hozza 3ddaff
Subject: [PATCH] Dynamically allocate send buffers when sending query
Tomas Hozza 3ddaff
Tomas Hozza 3ddaff
This prevents race condition, when the same buffer could be added into
Tomas Hozza 3ddaff
multiple bufferlists. One case when this happens is when timeout of sent
Tomas Hozza 3ddaff
UDP query expires before send_done() is called.
Tomas Hozza 3ddaff
Tomas Hozza 3ddaff
New function isc_buffer_cloneused() has been added, so dynamically
Tomas Hozza 3ddaff
allocated copy of used region of a buffer can be created easily.
Tomas Hozza 3ddaff
(It should be added into buffer.c but to prevent API change it is
Tomas Hozza 3ddaff
in dighost.c)
Tomas Hozza 3ddaff
Tomas Hozza 3ddaff
All functions creating a send socket event with send_done() callback
Tomas Hozza 3ddaff
have been modified to make dynamically allocated copies of every buffer
Tomas Hozza 3ddaff
added into query->sendlist. This list is then bounded to the send socket
Tomas Hozza 3ddaff
event. This way the same buffer can not be anymore added to the same
Tomas Hozza 3ddaff
bufferlist. Previously allocated copies of buffers are freed in
Tomas Hozza 3ddaff
send_done() callback.
Tomas Hozza 3ddaff
Tomas Hozza 3ddaff
Signed-off-by: Tomas Hozza <thozza@redhat.com>
Tomas Hozza 3ddaff
---
Tomas Hozza 3ddaff
 bin/dig/dighost.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
Tomas Hozza 3ddaff
 1 file changed, 53 insertions(+), 5 deletions(-)
Tomas Hozza 3ddaff
Tomas Hozza 3ddaff
diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c
Tomas Hozza 3ddaff
index 0d41529..7899c49 100644
Tomas Hozza 3ddaff
--- a/bin/dig/dighost.c
Tomas Hozza 3ddaff
+++ b/bin/dig/dighost.c
Tomas Hozza 3ddaff
@@ -362,6 +362,36 @@ struct_tk_list tk_list = { {NULL, NULL, NULL, NULL, NULL}, 0};
Tomas Hozza 3ddaff
 		     "isc_mutex_unlock");\
Tomas Hozza 3ddaff
 }
Tomas Hozza 3ddaff
 
Tomas Hozza 3ddaff
+static isc_result_t
Tomas Hozza 3ddaff
+isc_buffer_cloneused(isc_mem_t *mctx, isc_buffer_t *src_buffer, isc_buffer_t **dynbuffer) {
Tomas Hozza 3ddaff
+	/*
Tomas Hozza 3ddaff
+	 * Make 'dynbuffer' refer to a dynamically allocated copy of used region of 'src_buffer'.
Tomas Hozza 3ddaff
+	 */
Tomas Hozza 3ddaff
+	isc_result_t result;
Tomas Hozza 3ddaff
+	isc_region_t used_region;
Tomas Hozza 3ddaff
+	isc_buffer_t *tmpbuf = NULL;
Tomas Hozza 3ddaff
+
Tomas Hozza 3ddaff
+	REQUIRE(dynbuffer != NULL);
Tomas Hozza 3ddaff
+	REQUIRE(*dynbuffer == NULL);
Tomas Hozza 3ddaff
+	REQUIRE(src_buffer != NULL);
Tomas Hozza 3ddaff
+	REQUIRE(ISC_BUFFER_VALID(src_buffer));
Tomas Hozza 3ddaff
+
Tomas Hozza 3ddaff
+	result = isc_buffer_allocate(mctx, &tmpbuf, src_buffer->length);
Tomas Hozza 3ddaff
+	if (result != ISC_R_SUCCESS)
Tomas Hozza 3ddaff
+		return result;
Tomas Hozza 3ddaff
+
Tomas Hozza 3ddaff
+	isc_buffer_usedregion(src_buffer, &used_region);
Tomas Hozza 3ddaff
+	result = isc_buffer_copyregion(tmpbuf, &used_region);
Tomas Hozza 3ddaff
+	if (result != ISC_R_SUCCESS) {
Tomas Hozza 3ddaff
+		isc_buffer_free(&tmpbuf);
Tomas Hozza 3ddaff
+		return result;
Tomas Hozza 3ddaff
+	}
Tomas Hozza 3ddaff
+
Tomas Hozza 3ddaff
+	*dynbuffer = tmpbuf;
Tomas Hozza 3ddaff
+
Tomas Hozza 3ddaff
+	return (ISC_R_SUCCESS);
Tomas Hozza 3ddaff
+}
Tomas Hozza 3ddaff
+
Tomas Hozza 3ddaff
 static void
Tomas Hozza 3ddaff
 cancel_lookup(dig_lookup_t *lookup);
Tomas Hozza 3ddaff
 
Tomas Hozza 3ddaff
@@ -2416,8 +2446,10 @@ send_done(isc_task_t *_task, isc_event_t *event) {
Tomas Hozza 3ddaff
 
Tomas Hozza 3ddaff
 	for  (b = ISC_LIST_HEAD(sevent->bufferlist);
Tomas Hozza 3ddaff
 	      b != NULL;
Tomas Hozza 3ddaff
-	      b = ISC_LIST_HEAD(sevent->bufferlist))
Tomas Hozza 3ddaff
+	      b = ISC_LIST_HEAD(sevent->bufferlist)) {
Tomas Hozza 3ddaff
 		ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
Tomas Hozza 3ddaff
+		isc_buffer_free(&b);
Tomas Hozza 3ddaff
+	}
Tomas Hozza 3ddaff
 
Tomas Hozza 3ddaff
 	query = event->ev_arg;
Tomas Hozza 3ddaff
 	query->waiting_senddone = ISC_FALSE;
Tomas Hozza 3ddaff
@@ -2617,6 +2649,7 @@ send_tcp_connect(dig_query_t *query) {
Tomas Hozza 3ddaff
 static void
Tomas Hozza 3ddaff
 send_udp(dig_query_t *query) {
Tomas Hozza 3ddaff
 	dig_lookup_t *l = NULL;
Tomas Hozza 3ddaff
+	isc_buffer_t *tmpbuf = NULL;
Tomas Hozza 3ddaff
 	isc_result_t result;
Tomas Hozza 3ddaff
 
Tomas Hozza 3ddaff
 	debug("send_udp(%p)", query);
Tomas Hozza 3ddaff
@@ -2663,8 +2696,14 @@ send_udp(dig_query_t *query) {
Tomas Hozza 3ddaff
 		recvcount++;
Tomas Hozza 3ddaff
 		debug("recvcount=%d", recvcount);
Tomas Hozza 3ddaff
 	}
Tomas Hozza 3ddaff
+	/*
Tomas Hozza 3ddaff
+	 * Make a copy of the query send buffer so it is not reused
Tomas Hozza 3ddaff
+	 * in multiple socket send events. The buffer is freed in send_done().
Tomas Hozza 3ddaff
+	 */
Tomas Hozza 3ddaff
+	result = isc_buffer_cloneused(mctx, &query->sendbuf, &tmpbuf);
Tomas Hozza 3ddaff
+	check_result(result, "isc_buffer_cloneused");
Tomas Hozza 3ddaff
 	ISC_LIST_INIT(query->sendlist);
Tomas Hozza 3ddaff
-	ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link);
Tomas Hozza 3ddaff
+	ISC_LIST_ENQUEUE(query->sendlist, tmpbuf, link);
Tomas Hozza 3ddaff
 	debug("sending a request");
Tomas Hozza 3ddaff
 	TIME_NOW(&query->time_sent);
Tomas Hozza 3ddaff
 	INSIST(query->sock != NULL);
Tomas Hozza 3ddaff
@@ -2838,6 +2877,7 @@ static void
Tomas Hozza 3ddaff
 launch_next_query(dig_query_t *query, isc_boolean_t include_question) {
Tomas Hozza 3ddaff
 	isc_result_t result;
Tomas Hozza 3ddaff
 	dig_lookup_t *l;
Tomas Hozza 3ddaff
+	isc_buffer_t *tmpbuf = NULL;
Tomas Hozza 3ddaff
 
Tomas Hozza 3ddaff
 	INSIST(!free_now);
Tomas Hozza 3ddaff
 
Tomas Hozza 3ddaff
@@ -2861,9 +2901,17 @@ launch_next_query(dig_query_t *query, isc_boolean_t include_question) {
Tomas Hozza 3ddaff
 	isc_buffer_putuint16(&query->slbuf, (isc_uint16_t) query->sendbuf.used);
Tomas Hozza 3ddaff
 	ISC_LIST_INIT(query->sendlist);
Tomas Hozza 3ddaff
 	ISC_LINK_INIT(&query->slbuf, link);
Tomas Hozza 3ddaff
-	ISC_LIST_ENQUEUE(query->sendlist, &query->slbuf, link);
Tomas Hozza 3ddaff
-	if (include_question)
Tomas Hozza 3ddaff
-		ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link);
Tomas Hozza 3ddaff
+
Tomas Hozza 3ddaff
+	/* need to clone send buffers as they are freed in send_done() */
Tomas Hozza 3ddaff
+	result = isc_buffer_cloneused(mctx, &query->slbuf, &tmpbuf);
Tomas Hozza 3ddaff
+	check_result(result, "isc_buffer_cloneused");
Tomas Hozza 3ddaff
+	ISC_LIST_ENQUEUE(query->sendlist, tmpbuf, link);
Tomas Hozza 3ddaff
+	if (include_question) {
Tomas Hozza 3ddaff
+		tmpbuf = NULL;
Tomas Hozza 3ddaff
+		result = isc_buffer_cloneused(mctx, &query->sendbuf, &tmpbuf);
Tomas Hozza 3ddaff
+		check_result(result, "isc_buffer_cloneused");
Tomas Hozza 3ddaff
+		ISC_LIST_ENQUEUE(query->sendlist, tmpbuf, link);
Tomas Hozza 3ddaff
+	}
Tomas Hozza 3ddaff
 	ISC_LINK_INIT(&query->lengthbuf, link);
Tomas Hozza 3ddaff
 	ISC_LIST_ENQUEUE(query->lengthlist, &query->lengthbuf, link);
Tomas Hozza 3ddaff
 
Tomas Hozza 3ddaff
-- 
Tomas Hozza 3ddaff
1.8.3.1
Tomas Hozza 3ddaff