BUG/MEDIUM: dns: Properly handle error when a response consumed

When a response is consumed, result for co_getblk() is never checked. It
seems ok because amount of output data is always checked first. But There is
an issue when we try to get the first 2 bytes to read the message length. If
there is only one byte followed by a shutdown, the applet ignore the
shutdown and loop till the timeout to get more data.

So to avoid any issue and improve shutdown detection, the co_getblk() return
value is always tested. In addition, if there is not enough data, the applet
explicitly ask for more data by calling applet_need_more_data().

This patch relies on the previous one:

   * BUG/MEDIUM: channel: Improve reports for shut in co_getblk()

Both should be backported as far as 2.4. On 2.5 and 2.4,
applet_need_more_data() must be replaced by si_rx_endp_more().

(cherry picked from commit 28975e1e1012e4a009b4208f3fc022ea2bfb8b82)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit dc608287aedf7fe65a49fca27d933882790513c5)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 10a19f1841d759732ce59a7e64770fa887049b54)
[cf: In fact applet_need_more_data() must be replaced by si_cant_get()]
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit fad221e24604a68d17044f7c4ca3d95143a722f6)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/dns.c b/src/dns.c
index c4b2af0..3277f40 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -656,30 +656,35 @@
 			struct dns_query *query;
 
 			if (!ds->rx_msg.len) {
-				/* next message len is not fully available into the channel */
-				if (co_data(si_oc(si)) < 2)
-					break;
-
 				/* retrieve message len */
-				co_getblk(si_oc(si), (char *)&msg_len, 2, 0);
+				ret = co_getblk(si_oc(si), (char *)&msg_len, 2, 0);
+				if (ret <= 0) {
+					if (ret == -1)
+						goto close;
+					si_cant_get(si);
+					break;
+				}
 
 				/* mark as consumed */
 				co_skip(si_oc(si), 2);
 
 				/* store message len */
 				ds->rx_msg.len = ntohs(msg_len);
+				if (!ds->rx_msg.len)
+					continue;
 			}
 
-			if (!co_data(si_oc(si))) {
-				/* we need more data but nothing is available */
-				break;
-			}
-
 			if (co_data(si_oc(si)) + ds->rx_msg.offset < ds->rx_msg.len) {
 				/* message only partially available */
 
 				/* read available data */
-				co_getblk(si_oc(si), ds->rx_msg.area + ds->rx_msg.offset, co_data(si_oc(si)), 0);
+				ret = co_getblk(si_oc(si), ds->rx_msg.area + ds->rx_msg.offset, co_data(si_oc(si)), 0);
+				if (ret <= 0) {
+					if (ret == -1)
+						goto close;
+					si_cant_get(si);
+					break;
+				}
 
 				/* update message offset */
 				ds->rx_msg.offset += co_data(si_oc(si));
@@ -688,13 +693,20 @@
 				co_skip(si_oc(si), co_data(si_oc(si)));
 
 				/* we need to wait for more data */
+				si_cant_get(si);
 				break;
 			}
 
 			/* enough data is available into the channel to read the message until the end */
 
 			/* read from the channel until the end of the message */
-			co_getblk(si_oc(si), ds->rx_msg.area + ds->rx_msg.offset, ds->rx_msg.len - ds->rx_msg.offset, 0);
+			ret = co_getblk(si_oc(si), ds->rx_msg.area + ds->rx_msg.offset, ds->rx_msg.len - ds->rx_msg.offset, 0);
+			if (ret <= 0) {
+				if (ret == -1)
+					goto close;
+				si_cant_get(si);
+				break;
+			}
 
 			/* consume all data until the end of the message from the channel */
 			co_skip(si_oc(si), ds->rx_msg.len - ds->rx_msg.offset);