Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b
Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/dns/dname.c b/src/dns/dname.c
new file mode 100644
index 0000000..eda9ba4
--- /dev/null
+++ b/src/dns/dname.c
@@ -0,0 +1,219 @@
+/**
+ * @file dname.c DNS domain names
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_list.h>
+#include <re_hash.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_net.h>
+#include <re_dns.h>
+
+
+#define COMP_MASK 0xc0
+#define OFFSET_MASK 0x3fff
+#define COMP_LOOP 255
+
+
+struct dname {
+ struct le he;
+ size_t pos;
+ char *name;
+};
+
+
+static void destructor(void *arg)
+{
+ struct dname *dn = arg;
+
+ hash_unlink(&dn->he);
+ mem_deref(dn->name);
+}
+
+
+static void dname_append(struct hash *ht_dname, const char *name, size_t pos)
+{
+ struct dname *dn;
+
+ if (!ht_dname || pos > OFFSET_MASK || !*name)
+ return;
+
+ dn = mem_zalloc(sizeof(*dn), destructor);
+ if (!dn)
+ return;
+
+ if (str_dup(&dn->name, name)) {
+ mem_deref(dn);
+ return;
+ }
+
+ hash_append(ht_dname, hash_joaat_str_ci(name), &dn->he, dn);
+ dn->pos = pos;
+}
+
+
+static bool lookup_handler(struct le *le, void *arg)
+{
+ struct dname *dn = le->data;
+
+ return 0 == str_casecmp(dn->name, arg);
+}
+
+
+static inline struct dname *dname_lookup(struct hash *ht_dname,
+ const char *name)
+{
+ return list_ledata(hash_lookup(ht_dname, hash_joaat_str_ci(name),
+ lookup_handler, (void *)name));
+}
+
+
+static inline int dname_encode_pointer(struct mbuf *mb, size_t pos)
+{
+ return mbuf_write_u16(mb, htons(pos | (COMP_MASK<<8)));
+}
+
+
+/**
+ * Encode a DNS Domain name into a memory buffer
+ *
+ * @param mb Memory buffer
+ * @param name Domain name
+ * @param ht_dname Domain name hashtable
+ * @param start Start position
+ * @param comp Enable compression
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int dns_dname_encode(struct mbuf *mb, const char *name,
+ struct hash *ht_dname, size_t start, bool comp)
+{
+ struct dname *dn;
+ size_t pos;
+ int err;
+
+ if (!mb || !name)
+ return EINVAL;
+
+ dn = dname_lookup(ht_dname, name);
+ if (dn && comp)
+ return dname_encode_pointer(mb, dn->pos);
+
+ pos = mb->pos;
+ if (!dn)
+ dname_append(ht_dname, name, pos - start);
+ err = mbuf_write_u8(mb, 0);
+
+ if ('.' == name[0] && '\0' == name[1])
+ return err;
+
+ while (err == 0) {
+
+ const size_t lablen = mb->pos - pos - 1;
+
+ if ('\0' == *name) {
+ if (!lablen)
+ break;
+
+ mb->buf[pos] = lablen;
+ err |= mbuf_write_u8(mb, 0);
+ break;
+ }
+ else if ('.' == *name) {
+ if (!lablen)
+ return EINVAL;
+
+ mb->buf[pos] = lablen;
+
+ dn = dname_lookup(ht_dname, name + 1);
+ if (dn && comp) {
+ err |= dname_encode_pointer(mb, dn->pos);
+ break;
+ }
+
+ pos = mb->pos;
+ if (!dn)
+ dname_append(ht_dname, name + 1, pos - start);
+ err |= mbuf_write_u8(mb, 0);
+ }
+ else {
+ err |= mbuf_write_u8(mb, *name);
+ }
+
+ ++name;
+ }
+
+ return err;
+}
+
+
+/**
+ * Decode a DNS domain name from a memory buffer
+ *
+ * @param mb Memory buffer to decode from
+ * @param name Pointer to allocated string with domain name
+ * @param start Start position
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int dns_dname_decode(struct mbuf *mb, char **name, size_t start)
+{
+ uint32_t i = 0, loopc = 0;
+ bool comp = false;
+ size_t pos = 0;
+ char buf[256];
+
+ if (!mb || !name)
+ return EINVAL;
+
+ while (mb->pos < mb->end) {
+
+ uint8_t len = mb->buf[mb->pos++];
+ if (!len) {
+ if (comp)
+ mb->pos = pos;
+
+ buf[i++] = '\0';
+
+ *name = mem_alloc(i, NULL);
+ if (!*name)
+ return ENOMEM;
+
+ str_ncpy(*name, buf, i);
+
+ return 0;
+ }
+ else if ((len & COMP_MASK) == COMP_MASK) {
+ uint16_t offset;
+
+ if (loopc++ > COMP_LOOP)
+ break;
+
+ --mb->pos;
+
+ offset = ntohs(mbuf_read_u16(mb)) & OFFSET_MASK;
+ if (!comp) {
+ pos = mb->pos;
+ comp = true;
+ }
+
+ mb->pos = offset + start;
+ continue;
+ }
+ else if (len > mbuf_get_left(mb))
+ break;
+ else if (len > sizeof(buf) - i - 2)
+ break;
+
+ if (i > 0)
+ buf[i++] = '.';
+
+ while (len--)
+ buf[i++] = mb->buf[mb->pos++];
+ }
+
+ return EINVAL;
+}