Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Revision:
149:5f4cb161cec3
Parent:
137:a1c8bfa9d691
Child:
152:a3d286bf94e5
--- a/modules/pico_dns_client.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dns_client.c	Wed Apr 09 14:31:41 2014 +0200
@@ -11,6 +11,7 @@
 #include "pico_addressing.h"
 #include "pico_socket.h"
 #include "pico_ipv4.h"
+#include "pico_ipv6.h"
 #include "pico_dns_client.h"
 #include "pico_tree.h"
 
@@ -27,7 +28,7 @@
 #define PICO_DNS_CLIENT_MAX_RETRANS 3
 
 /* Default nameservers + port */
-#define PICO_DNS_NS_GOOGLE "8.8.8.8"
+#define PICO_DNS_NS_DEFAULT "208.67.222.222"
 #define PICO_DNS_NS_PORT 53
 
 /* FLAG values */
@@ -53,6 +54,7 @@
 
 /* QTYPE values */
 #define PICO_DNS_TYPE_A 1
+#define PICO_DNS_TYPE_AAAA 28
 #define PICO_DNS_TYPE_PTR 12
 
 /* QCLASS values */
@@ -71,19 +73,20 @@
 
 /* Len of an IPv4 address string */
 #define PICO_DNS_IPV4_ADDR_LEN 16
+#define PICO_DNS_IPV6_ADDR_LEN 54
 
 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
 static void pico_dns_client_retransmission(pico_time now, void *arg);
 
 /* RFC 1035 section 4. MESSAGES */
-struct __attribute__((packed)) pico_dns_name
+PACKED_STRUCT_DEF pico_dns_name
 {
-    char name[0];
+    char name[1];
 };
 
 /* prefix = header + name pointer
  * flags splitted in 2x uint8 due to endianness */
-struct __attribute__((packed)) pico_dns_prefix
+PACKED_STRUCT_DEF pico_dns_prefix
 {
     uint16_t id;
     uint8_t rd : 1; /* recursion desired  */
@@ -101,13 +104,13 @@
     struct pico_dns_name domain;
 };
 
-struct __attribute__((packed)) pico_dns_query_suffix
+PACKED_STRUCT_DEF pico_dns_query_suffix
 {
     uint16_t qtype;
     uint16_t qclass;
 };
 
-struct __attribute__((packed)) pico_dns_answer_suffix
+PACKED_STRUCT_DEF pico_dns_answer_suffix
 {
     uint16_t qtype;
     uint16_t qclass;
@@ -127,7 +130,7 @@
     if (a->ns.addr == b->ns.addr)
         return 0;
 
-    return (a->ns.addr < b->ns.addr) ? -1 : 1;
+    return (a->ns.addr < b->ns.addr) ? (-1) : (1);
 }
 PICO_TREE_DECLARE(NSTable, dns_ns_cmp);
 
@@ -151,7 +154,7 @@
     if (a->id == b->id)
         return 0;
 
-    return (a->id < b->id) ? -1 : 1;
+    return (a->id < b->id) ? (-1) : (1);
 }
 PICO_TREE_DECLARE(DNSTable, dns_query_cmp);
 
@@ -165,7 +168,7 @@
         return -1;
 
     pico_tree_delete(&NSTable, found);
-    pico_free(found);
+    PICO_FREE(found);
 
     /* no NS left, add default NS */
     if (pico_tree_empty(&NSTable))
@@ -178,7 +181,7 @@
 {
     struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}};
 
-    dns = pico_zalloc(sizeof(struct pico_dns_ns));
+    dns = PICO_ZALLOC(sizeof(struct pico_dns_ns));
     if (!dns) {
         pico_err = PICO_ERR_ENOMEM;
         return NULL;
@@ -188,12 +191,12 @@
 
     found = pico_tree_insert(&NSTable, dns);
     if (found) { /* nameserver already present */
-        pico_free(dns);
+        PICO_FREE(dns);
         return found;
     }
 
     /* default NS found, remove it */
-    pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
+    pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&test.ns.addr);
     found = pico_tree_findKey(&NSTable, &test);
     if (found && (found->ns.addr != ns_addr->addr))
         pico_dns_client_del_ns(&found->ns);
@@ -224,7 +227,7 @@
 {
     struct pico_dns_query *q = NULL, *found = NULL;
 
-    q = pico_zalloc(sizeof(struct pico_dns_query));
+    q = PICO_ZALLOC(sizeof(struct pico_dns_query));
     if (!q)
         return NULL;
 
@@ -239,7 +242,7 @@
     q->arg = arg;
     q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
     if (!q->s) {
-        pico_free(q);
+        PICO_FREE(q);
         return NULL;
     }
 
@@ -247,7 +250,7 @@
     if (found) {
         pico_err = PICO_ERR_EAGAIN;
         pico_socket_close(q->s);
-        pico_free(q);
+        PICO_FREE(q);
         return NULL;
     }
 
@@ -265,10 +268,10 @@
     if (!found)
         return -1;
 
-    pico_free(found->query);
+    PICO_FREE(found->query);
     pico_socket_close(found->s);
     pico_tree_delete(&DNSTable, found);
-    pico_free(found);
+    PICO_FREE(found);
     return 0;
 }
 
@@ -312,6 +315,8 @@
     return ptr + 1;
 }
 
+/* mirror ip6 */
+
 /* mirror ip address numbers
  * f.e. 192.168.0.1 => 1.0.168.192 */
 static int8_t pico_dns_client_mirror(char *ptr)
@@ -461,6 +466,11 @@
 
 static int pico_dns_client_check_asuffix(struct pico_dns_answer_suffix *suf, struct pico_dns_query *q)
 {
+    if (!suf) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
     if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) {
         dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass));
         return -1;
@@ -480,6 +490,8 @@
     uint16_t comp = 0, compression = 0;
     uint16_t i = 0;
     char *psuffix = suf;
+    if (!suf)
+        return NULL;
 
     while (i++ < short_be(pre->ancount)) {
         comp = short_from(psuffix);
@@ -506,6 +518,9 @@
         }
 
         asuffix = (struct pico_dns_answer_suffix *)psuffix;
+        if (!asuffix)
+            break;
+
         if (pico_dns_client_check_asuffix(asuffix, q) < 0) {
             psuffix += (sizeof(struct pico_dns_answer_suffix) + short_be(asuffix->rdlength));
             continue;
@@ -518,7 +533,12 @@
 
 static int pico_dns_client_send(struct pico_dns_query *q)
 {
-    uint16_t *paramID = pico_zalloc(sizeof(uint16_t));
+    uint16_t *paramID = PICO_ZALLOC(sizeof(uint16_t));
+    if (!paramID) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
     dns_dbg("DNS: sending query to %08X\n", q->q_ns.ns.addr);
     if (!q->s)
         goto failure;
@@ -533,7 +553,7 @@
     return 0;
 
 failure:
-    pico_free(paramID);
+    PICO_FREE(paramID);
     return -1;
 }
 
@@ -549,7 +569,7 @@
     /* search for the dns query and free used space */
     dummy.id = *(uint16_t *)arg;
     q = (struct pico_dns_query *)pico_tree_findKey(&DNSTable, &dummy);
-    pico_free(arg);
+    PICO_FREE(arg);
 
     /* dns query successful? */
     if (!q) {
@@ -575,13 +595,27 @@
     {
     case PICO_DNS_TYPE_A:
         ip = long_from(asuffix->rdata);
-        str = pico_zalloc(PICO_DNS_IPV4_ADDR_LEN);
+        str = PICO_ZALLOC(PICO_DNS_IPV4_ADDR_LEN);
         pico_ipv4_to_string(str, ip);
         break;
-
+#ifdef PICO_SUPPORT_IPV6
+    case PICO_DNS_TYPE_AAAA:
+    {
+        struct pico_ip6 ip6;
+        memcpy(&ip6.addr, asuffix->rdata, sizeof(struct pico_ip6));
+        str = PICO_ZALLOC(PICO_DNS_IPV6_ADDR_LEN);
+        pico_ipv6_to_string(str, ip6.addr);
+        break;
+    }
+#endif
     case PICO_DNS_TYPE_PTR:
         pico_dns_client_answer_domain((char *)asuffix->rdata);
-        str = pico_zalloc((size_t)(asuffix->rdlength - PICO_DNS_LABEL_INITIAL));
+        str = PICO_ZALLOC((size_t)(asuffix->rdlength - PICO_DNS_LABEL_INITIAL));
+        if (!str) {
+            pico_err = PICO_ERR_ENOMEM;
+            return -1;
+        }
+
         memcpy(str, asuffix->rdata + PICO_DNS_LABEL_INITIAL, short_be(asuffix->rdlength) - PICO_DNS_LABEL_INITIAL);
         break;
 
@@ -593,6 +627,7 @@
     if (q->retrans) {
         q->callback(str, q->arg);
         q->retrans = 0;
+        PICO_FREE(str);
         pico_dns_client_del_query(q->id);
     }
 
@@ -647,7 +682,7 @@
     return;
 }
 
-int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
+static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg)
 {
     char *msg = NULL;
     struct pico_dns_prefix *prefix = NULL;
@@ -655,6 +690,7 @@
     struct pico_dns_query_suffix *qsuffix = NULL;
     struct pico_dns_query *q = NULL;
     uint16_t len = 0, lblen = 0, strlen = 0;
+    (void)proto;
 
     if (!url || !callback) {
         pico_err = PICO_ERR_EINVAL;
@@ -664,7 +700,7 @@
     strlen = pico_dns_client_strlen(url);
     lblen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + PICO_DNS_LABEL_ROOT);
     len = (uint16_t)(sizeof(struct pico_dns_prefix) + lblen + sizeof(struct pico_dns_query_suffix));
-    msg = pico_zalloc(len);
+    msg = PICO_ZALLOC(len);
     if (!msg) {
         pico_err = PICO_ERR_ENOMEM;
         return -1;
@@ -678,11 +714,17 @@
     /* assemble dns message */
     pico_dns_client_query_prefix(prefix);
     pico_dns_client_query_domain(domain->name);
+
+#ifdef PICO_SUPPORT_IPV6
+    if (proto == PICO_PROTO_IPV6) {
+        pico_dns_client_query_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN);
+    } else
+#endif
     pico_dns_client_query_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN);
 
     q = pico_dns_client_add_query(prefix, len, qsuffix, callback, arg);
     if (!q) {
-        pico_free(msg);
+        PICO_FREE(msg);
         return -1;
     }
 
@@ -694,6 +736,16 @@
     return 0;
 }
 
+int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
+{
+    return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV4, callback, arg);
+}
+
+int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg)
+{
+    return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV6, callback, arg);
+}
+
 int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
 {
     const char *inaddr_arpa = ".in-addr.arpa";
@@ -713,7 +765,7 @@
     arpalen = pico_dns_client_strlen(inaddr_arpa);
     lblen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT);
     len = (uint16_t)(sizeof(struct pico_dns_prefix) + lblen + sizeof(struct pico_dns_query_suffix));
-    msg = pico_zalloc(len);
+    msg = PICO_ZALLOC(len);
     if (!msg) {
         pico_err = PICO_ERR_ENOMEM;
         return -1;
@@ -725,15 +777,13 @@
     memcpy(domain->name + PICO_DNS_LABEL_INITIAL, ip, strlen);
     pico_dns_client_mirror(domain->name + PICO_DNS_LABEL_INITIAL);
     memcpy(domain->name + PICO_DNS_LABEL_INITIAL + strlen, inaddr_arpa, arpalen);
-
     /* assemble dns message */
     pico_dns_client_query_prefix(prefix);
     pico_dns_client_query_domain(domain->name);
     pico_dns_client_query_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN);
-
     q = pico_dns_client_add_query(prefix, len, qsuffix, callback, arg);
     if (!q) {
-        pico_free(msg);
+        PICO_FREE(msg);
         return -1;
     }
 
@@ -745,6 +795,89 @@
     return 0;
 }
 
+
+#ifdef PICO_SUPPORT_IPV6
+#define STRLEN_PTR_IP6 63
+
+static inline char dns_ptr_ip6_nibble_lo(uint8_t byte)
+{
+    uint8_t nibble = byte & 0x0f;
+    if (nibble < 10)
+        return (char)(nibble + '0');
+    else
+        return (char)(nibble - 0xa + 'a');
+}
+
+static inline char dns_ptr_ip6_nibble_hi(uint8_t byte)
+{
+    uint8_t nibble = (byte & 0xf0u) >> 4u;
+    if (nibble < 10u)
+        return (char)(nibble + '0');
+    else
+        return (char)(nibble - 0xa + 'a');
+}
+
+static void pico_dns_ipv6_set_ptr(const char *ip, char *dst)
+{
+    struct pico_ip6 ip6;
+    int i, j = 0;
+    pico_string_to_ipv6(ip, ip6.addr);
+    for (i = 15; i >= 0; i--) {
+        dst[j++] = dns_ptr_ip6_nibble_lo(ip6.addr[i]);
+        dst[j++] = '.';
+        dst[j++] = dns_ptr_ip6_nibble_hi(ip6.addr[i]);
+        dst[j++] = '.';
+    }
+}
+
+int pico_dns_client_getname6(const char *ip, void (*callback)(char *, void *), void *arg)
+{
+    const char *inaddr6_arpa = ".IP6.ARPA";
+    char *msg = NULL;
+    struct pico_dns_prefix *prefix = NULL;
+    struct pico_dns_name *domain = NULL;
+    struct pico_dns_query_suffix *qsuffix = NULL;
+    struct pico_dns_query *q = NULL;
+    uint16_t len = 0, lblen = 0, arpalen = 0;
+
+    if (!ip || !callback) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    arpalen = pico_dns_client_strlen(inaddr6_arpa);
+    lblen = (uint16_t)(PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6 + arpalen + PICO_DNS_LABEL_ROOT);
+    len = (uint16_t)(sizeof(struct pico_dns_prefix) + lblen + sizeof(struct pico_dns_query_suffix));
+    msg = PICO_ZALLOC(len);
+    if (!msg) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
+    prefix = (struct pico_dns_prefix *)msg;
+    domain = &prefix->domain;
+    qsuffix = (struct pico_dns_query_suffix *)(prefix->domain.name + lblen);
+    pico_dns_ipv6_set_ptr(ip, domain->name + PICO_DNS_LABEL_INITIAL);
+    memcpy(domain->name + PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6, inaddr6_arpa, arpalen);
+    /* assemble dns message */
+    pico_dns_client_query_prefix(prefix);
+    pico_dns_client_query_domain(domain->name);
+    pico_dns_client_query_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN);
+    q = pico_dns_client_add_query(prefix, len, qsuffix, callback, arg);
+    if (!q) {
+        PICO_FREE(msg);
+        return -1;
+    }
+
+    if (pico_dns_client_send(q) < 0) {
+        pico_dns_client_del_query(q->id); /* frees msg */
+        return -1;
+    }
+
+    return 0;
+}
+#endif
+
 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
 {
     if (!ns) {
@@ -781,7 +914,7 @@
         0
     };
 
-    if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) < 0)
+    if (pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&default_ns.addr) < 0)
         return -1;
 
     return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD);