From 6bb8a5c145428ff3d5a37a3db7c047e5a8f08bc0 Mon Sep 17 00:00:00 2001
From: Koen Zandberg <koen@bergzand.net>
Date: Sun, 6 May 2018 14:40:37 +0200
Subject: [PATCH] nanocoap_sock: split request function from get

The nanocoap_get function is refactored to split of the request part
into a separate function for reuse by other modules. Support for
retransmissions when the received frame is malformed is dropped as it
was broken anyway.
---
 sys/include/net/nanocoap_sock.h           | 18 ++++++-
 sys/net/application_layer/nanocoap/sock.c | 61 +++++++++++++++--------
 2 files changed, 56 insertions(+), 23 deletions(-)

diff --git a/sys/include/net/nanocoap_sock.h b/sys/include/net/nanocoap_sock.h
index e7b2c98bb3..7a56581adf 100644
--- a/sys/include/net/nanocoap_sock.h
+++ b/sys/include/net/nanocoap_sock.h
@@ -51,12 +51,28 @@ int nanocoap_server(sock_udp_ep_t *local, uint8_t *buf, size_t bufsize);
  * @param[out]  buf     buffer to write response to
  * @param[in]   len     length of @p buffer
  *
- * @returns     length of response on success
+ * @returns     length of response payload on success
  * @returns     <0 on error
  */
 ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, uint8_t *buf,
                      size_t len);
 
+/**
+ * @brief   Simple synchronous CoAP request
+ *
+ * @param[in,out]   pkt     Packet struct containing the request. Is reused for
+ *                          the response
+ * @param[in]       local   Local UDP endpoint, may be NULL
+ * @param[in]       remote  remote UDP endpoint
+ * @param[in]       len     Total length of the buffer associated with the
+ *                          request
+ *
+ * @returns     length of response on success
+ * @returns     <0 on error
+ */
+ssize_t nanocoap_request(coap_pkt_t *pkt, sock_udp_ep_t *local,
+                         sock_udp_ep_t *remote, size_t len);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/sys/net/application_layer/nanocoap/sock.c b/sys/net/application_layer/nanocoap/sock.c
index 96c651b298..3de7e104af 100644
--- a/sys/net/application_layer/nanocoap/sock.c
+++ b/sys/net/application_layer/nanocoap/sock.c
@@ -28,24 +28,22 @@
 #define ENABLE_DEBUG (0)
 #include "debug.h"
 
-ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, uint8_t *buf, size_t len)
+ssize_t nanocoap_request(coap_pkt_t *pkt, sock_udp_ep_t *local, sock_udp_ep_t *remote, size_t len)
 {
     ssize_t res;
+    size_t pdu_len = (pkt->payload - (uint8_t *)pkt->hdr) + pkt->payload_len;
+    uint8_t *buf = (uint8_t*)pkt->hdr;
     sock_udp_t sock;
 
     if (!remote->port) {
         remote->port = COAP_PORT;
     }
 
-    res = sock_udp_create(&sock, NULL, remote, 0);
+    res = sock_udp_create(&sock, local, remote, 0);
     if (res < 0) {
         return res;
     }
 
-    uint8_t *pktpos = buf;
-    pktpos += coap_build_hdr((coap_hdr_t *)pktpos, COAP_REQ, NULL, 0, COAP_METHOD_GET, 1);
-    pktpos += coap_put_option_uri(pktpos, 0, path, COAP_OPT_URI_PATH);
-
     /* TODO: timeout random between between ACK_TIMEOUT and (ACK_TIMEOUT *
      * ACK_RANDOM_FACTOR) */
     uint32_t timeout = COAP_ACK_TIMEOUT * (1000000U);
@@ -57,7 +55,7 @@ ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, uint8_t *buf, size
             goto out;
         }
 
-        res = sock_udp_send(&sock, buf, pktpos - buf, NULL);
+        res = sock_udp_send(&sock, buf, pdu_len, NULL);
         if (res <= 0) {
             DEBUG("nanocoap: error sending coap request\n");
             goto out;
@@ -74,22 +72,10 @@ ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, uint8_t *buf, size
             DEBUG("nanocoap: error receiving coap request\n");
             break;
         }
-
-        coap_pkt_t pkt;
-        if (coap_parse(&pkt, (uint8_t *)buf, res) < 0) {
-            puts("error parsing packet");
-            continue;
-        }
         else {
-            res = coap_get_code(&pkt);
-            if (res != 205) {
-                res = -res;
-            }
-            else {
-                if (pkt.payload_len) {
-                    memcpy(buf, pkt.payload, pkt.payload_len);
-                }
-                res = pkt.payload_len;
+            if (coap_parse(pkt, (uint8_t *)buf, res) < 0) {
+                DEBUG("nanocoap: error parsing packet\n");
+                res = -EBADMSG;
             }
             break;
         }
@@ -101,6 +87,37 @@ out:
     return res;
 }
 
+ssize_t nanocoap_get(sock_udp_ep_t *remote, const char *path, uint8_t *buf, size_t len)
+{
+    ssize_t res;
+    coap_pkt_t pkt;
+    uint8_t *pktpos = buf;
+
+    pkt.hdr = (coap_hdr_t*)buf;
+    pktpos += coap_build_hdr(pkt.hdr, COAP_REQ, NULL, 0, COAP_METHOD_GET, 1);
+    pktpos += coap_put_option_uri(pktpos, 0, path, COAP_OPT_URI_PATH);
+    pkt.payload = pktpos;
+    pkt.payload_len = 0;
+
+    res = nanocoap_request(&pkt, NULL, remote, len);
+    if (res < 0) {
+        return res;
+    }
+    else {
+        res = coap_get_code(&pkt);
+        if (res != 205) {
+            res = -res;
+        }
+        else {
+            if (pkt.payload_len) {
+                memmove(buf, pkt.payload, pkt.payload_len);
+            }
+            res = pkt.payload_len;
+        }
+    }
+    return res;
+}
+
 int nanocoap_server(sock_udp_ep_t *local, uint8_t *buf, size_t bufsize)
 {
     sock_udp_t sock;
-- 
GitLab