-more debug messages
[oweals/gnunet.git] / src / namestore / namestore_common.c
index 22a4e77367c72272f25106375bc60484b8d121c8..af7eee04c1cefde48e73d7e173f2659ef13f2bc9 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+     (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_constants.h"
+#include "gnunet_signatures.h"
 #include "gnunet_arm_service.h"
 #include "gnunet_namestore_service.h"
+#include "gnunet_dnsparser_lib.h"
+#include "../dns/dnsparser.h"
 #include "namestore.h"
-#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING
+
 
 #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__)
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
 /**
- * Serialize an array of GNUNET_NAMESTORE_RecordData *rd to transmit over the
- * network
- *
- * @param dest where to write the serialized data
- * @param rd_count number of elements in array
- * @param rd array
- *
- * @return number of bytes written to destination dest
+ * Internal format of a record in the serialized form.
  */
-size_t
-GNUNET_NAMESTORE_records_serialize (char ** dest,
-                             unsigned int rd_count,
-                             const struct GNUNET_NAMESTORE_RecordData *rd)
+struct NetworkRecord
 {
-  //size_t len = 0;
-  struct GNUNET_NAMESTORE_NetworkRecord nr;
-  char * d = (*dest);
-  int c = 0;
-  int offset;
 
-  GNUNET_assert (rd != NULL);
+  /**
+   * Expiration time for the DNS record; relative or absolute depends
+   * on 'flags', network byte order.
+   */
+  uint64_t expiration_time GNUNET_PACKED;
 
-  size_t total_len = rd_count * sizeof (struct GNUNET_NAMESTORE_NetworkRecord);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Struct size: %u\n", total_len);
+  /**
+   * Number of bytes in 'data', network byte order.
+   */
+  uint32_t data_size GNUNET_PACKED;
 
-  /* figure out total len required */
-  for (c = 0; c < rd_count; c ++)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data size record[%i] : %u\n", c, rd[c].data_size);
-    total_len += rd[c].data_size;
-  }
+  /**
+   * Type of the GNS/DNS record, network byte order.
+   */
+  uint32_t record_type GNUNET_PACKED;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Serializing %i records with total length of %llu\n", rd_count, total_len);
+  /**
+   * Flags for the record, network byte order.
+   */
+  uint32_t flags GNUNET_PACKED;
+  
+};
 
-  (*dest) = GNUNET_malloc (total_len);
-  d = (*dest);
+GNUNET_NETWORK_STRUCT_END
 
-  /* copy records */
-  offset = 0;
 
-  for (c = 0; c < rd_count; c ++)
+/**
+ * Convert a short hash to a string (for printing debug messages).
+ * This is one of the very few calls in the entire API that is
+ * NOT reentrant!
+ *
+ * @param hc the short hash code
+ * @return string form; will be overwritten by next call to GNUNET_h2s.
+ */
+const char *
+GNUNET_short_h2s (const struct GNUNET_CRYPTO_ShortHashCode * hc)
+{
+  static struct GNUNET_CRYPTO_ShortHashAsciiEncoded ret;
+
+  GNUNET_CRYPTO_short_hash_to_enc (hc, &ret);
+  return (const char *) &ret;
+}
+
+
+/**
+ * Calculate how many bytes we will need to serialize the given
+ * records.
+ *
+ * @param rd_count number of records in the rd array
+ * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements
+ *
+ * @return the required size to serialize
+ *
+ */
+size_t
+GNUNET_NAMESTORE_records_get_size (unsigned int rd_count,
+                                  const struct GNUNET_NAMESTORE_RecordData *rd)
+{
+  unsigned int i;
+  size_t ret;
+
+  ret = sizeof (struct NetworkRecord) * rd_count;
+  for (i=0;i<rd_count;i++)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Serialized record [%i]: data_size %i\n", c,rd[c].data_size);
-
-    // nr = (struct GNUNET_NAMESTORE_NetworkRecord *) &d[offset];
-    nr.data_size = htonl (rd[c].data_size);
-    nr.flags = htonl (rd[c].flags);
-    nr.record_type = htonl (rd[c].record_type);
-    nr.expiration = GNUNET_TIME_absolute_hton(rd[c].expiration);
-    memcpy (&d[offset], &nr, sizeof (nr));
-    offset += sizeof (struct GNUNET_NAMESTORE_NetworkRecord);
-
-    /*put data here */
-    memcpy (&d[offset], rd[c].data, rd[c].data_size);
-    offset += rd[c].data_size;
+    GNUNET_assert ((ret + rd[i].data_size) >= ret);
+    ret += rd[i].data_size;
   }
-
-  GNUNET_assert (offset == total_len);
-  return total_len;
+  return ret;  
 }
 
-void
-GNUNET_NAMESTORE_records_free (unsigned int rd_count, struct GNUNET_NAMESTORE_RecordData *rd)
+
+/**
+ * Serialize the given records to the given destination buffer.
+ *
+ * @param rd_count number of records in the rd array
+ * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements
+ * @param dest_size size of the destination array
+ * @param dest where to write the result
+ *
+ * @return the size of serialized records
+ */
+ssize_t
+GNUNET_NAMESTORE_records_serialize (unsigned int rd_count,
+                                   const struct GNUNET_NAMESTORE_RecordData *rd,
+                                   size_t dest_size,
+                                   char *dest)
 {
-  int c;
-  if ((rd == NULL) || (rd_count == 0))
-    return;
+  struct NetworkRecord rec;
+  unsigned int i;
+  size_t off;
+  
+  off = 0;
+  for (i=0;i<rd_count;i++)
+  {
+    rec.expiration_time = GNUNET_htonll (rd[i].expiration_time);
+    rec.data_size = htonl ((uint32_t) rd[i].data_size);
+    rec.record_type = htonl (rd[i].record_type);
+    rec.flags = htonl (rd[i].flags);
+    if (off + sizeof (rec) > dest_size)
+      return -1;
+    memcpy (&dest[off], &rec, sizeof (rec));
+    off += sizeof (rec);
+    if (off + rd[i].data_size > dest_size)
+      return -1;
+    memcpy (&dest[off], rd[i].data, rd[i].data_size);
+    off += rd[i].data_size;
+  }
+  return off;
+}
+
 
-  for (c = 0; c < rd_count; c++)
-    GNUNET_free_non_null ((void *) rd[c].data);
-  GNUNET_free (rd);
+/**
+ * Compares if two records are equal (ignoring flags such
+ * as authority, private and pending, but not relative vs.
+ * absolute expiration time).
+ *
+ * @param a record
+ * @param b record
+ * @return GNUNET_YES if the records are equal or GNUNET_NO if they are not
+ */
+int
+GNUNET_NAMESTORE_records_cmp (const struct GNUNET_NAMESTORE_RecordData *a,
+                              const struct GNUNET_NAMESTORE_RecordData *b)
+{
+  if ((a->record_type == b->record_type) &&
+      (a->expiration_time == b->expiration_time) &&
+      ((a->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) 
+       == (b->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) ) &&
+      (a->data_size == b->data_size) &&
+      (0 == memcmp (a->data, b->data, a->data_size)))
+    return GNUNET_YES;
+  return GNUNET_NO;
 }
 
 
 /**
- * Deserialize an array of GNUNET_NAMESTORE_RecordData *rd after transmission
- * over the network
+ * Deserialize the given records to the given destination.
  *
- * @param source where to read the data to deserialize
- * @param rd_count number of elements in array
- * @param rd array
+ * @param len size of the serialized record data
+ * @param src the serialized record data
+ * @param rd_count number of records in the rd array
+ * @param dest where to put the data
  *
- * @return number of elements deserialized
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
  */
 int
-GNUNET_NAMESTORE_records_deserialize ( struct GNUNET_NAMESTORE_RecordData **dest, char *src, size_t len)
+GNUNET_NAMESTORE_records_deserialize (size_t len,
+                                     const char *src,
+                                     unsigned int rd_count,
+                                     struct GNUNET_NAMESTORE_RecordData *dest)
 {
-  struct GNUNET_NAMESTORE_NetworkRecord * nr;
-  struct GNUNET_NAMESTORE_RecordData *d = (*dest);
-  int elements;
-  size_t offset;
-  uint32_t data_size;
-  int c;
-
-  if (len == 0)
+  struct NetworkRecord rec;
+  unsigned int i;
+  size_t off;
+  
+  off = 0;
+  for (i=0;i<rd_count;i++)
   {
-    (*dest) = NULL;
-    return 0;
+    if (off + sizeof (rec) > len)
+      return GNUNET_SYSERR;
+    memcpy (&rec, &src[off], sizeof (rec));
+    dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time);
+    dest[i].data_size = ntohl ((uint32_t) rec.data_size);
+    dest[i].record_type = ntohl (rec.record_type);
+    dest[i].flags = ntohl (rec.flags);
+    off += sizeof (rec);
+
+    if (off + dest[i].data_size > len)
+      return GNUNET_SYSERR;
+    dest[i].data = &src[off];
+    off += dest[i].data_size;
   }
+  return GNUNET_OK; 
+}
 
-  offset = 0;
-  elements = 0;
-  while (offset < len)
-  {
-    nr = (struct GNUNET_NAMESTORE_NetworkRecord *) &src[offset];
-    offset += sizeof (struct GNUNET_NAMESTORE_NetworkRecord);
 
-    data_size = ntohl (nr->data_size);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Datasize record[%i]: %u\n", elements, data_size);
-    offset += data_size;
-    elements ++;
+/**
+ * Sign name and records
+ *
+ * @param key the private key
+ * @param expire block expiration
+ * @param name the name
+ * @param rd record data
+ * @param rd_count number of records
+ *
+ * @return the signature
+ */
+struct GNUNET_CRYPTO_RsaSignature *
+GNUNET_NAMESTORE_create_signature (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
+                                  struct GNUNET_TIME_Absolute expire,
+                                  const char *name,
+                                  const struct GNUNET_NAMESTORE_RecordData *rd,
+                                  unsigned int rd_count)
+{
+  struct GNUNET_CRYPTO_RsaSignature *sig;
+  struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose;
+  struct GNUNET_TIME_AbsoluteNBO expire_nbo;
+  size_t rd_ser_len;
+  size_t name_len;
+  struct GNUNET_TIME_AbsoluteNBO *expire_tmp;
+  char * name_tmp;
+  char * rd_tmp;
+  int res;
+  uint32_t sig_len;
+
+  if (NULL == name)
+  {
+    GNUNET_break (0);
+    return NULL;
   }
-
-  if (elements == 0)
+  sig = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaSignature));
+  name_len = strlen (name) + 1;
+  expire_nbo = GNUNET_TIME_absolute_hton (expire);
+  rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
   {
-    (*dest) = NULL;
-    return 0;
+    char rd_ser[rd_ser_len];
+
+    GNUNET_assert (rd_ser_len ==
+                  GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser));
+    sig_len = sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len;
+    sig_purpose = GNUNET_malloc (sig_len);
+    sig_purpose->size = htonl (sig_len);
+    sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
+    expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1];
+    memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO));
+    name_tmp = (char *) &expire_tmp[1];
+    memcpy (name_tmp, name, name_len);
+    rd_tmp = &name_tmp[name_len];
+    memcpy (rd_tmp, rd_ser, rd_ser_len);
+    res = GNUNET_CRYPTO_rsa_sign (key, sig_purpose, sig);
+    GNUNET_free (sig_purpose);
   }
+  if (GNUNET_OK != res)
+  {
+    GNUNET_break (0);
+    GNUNET_free (sig);
+    return NULL;
+  }
+  return sig;
+}
 
+/**
+ * Checks if a name is wellformed
+ *
+ * @param name the name to check
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GNUNET_NAMESTORE_check_name (const char * name)
+{
+  if (name == NULL)
+    return GNUNET_SYSERR;
+  if (strlen (name) > 63)
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
 
-  GNUNET_assert (len == offset);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deserializing %i records with total length of %u\n", elements, len);
-
-  (*dest) = GNUNET_malloc (elements * sizeof (struct GNUNET_NAMESTORE_RecordData));
-  d = (*dest);
 
-  offset = 0;
-  for (c = 0; c < elements; c++)
+/**
+ * Convert the 'value' of a record to a string.
+ *
+ * @param type type of the record
+ * @param data value in binary encoding
+ * @param data_size number of bytes in data
+ * @return NULL on error, otherwise human-readable representation of the value
+ */
+char *
+GNUNET_NAMESTORE_value_to_string (uint32_t type,
+                                 const void *data,
+                                 size_t data_size)
+{
+  char tmp[INET6_ADDRSTRLEN];
+  struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
+  uint16_t mx_pref;
+  char* result;
+  char* soa_rname;
+  char* soa_mname;
+  struct soa_data *soa;
+
+  struct vpn_data *vpn;
+  char* vpn_str;
+  char* srv_str;
+  struct GNUNET_CRYPTO_HashAsciiEncoded s_peer;
+  struct srv_data *srv;
+
+  switch (type)
   {
-    nr = (struct GNUNET_NAMESTORE_NetworkRecord *) &src[offset];
-    d[c].expiration = GNUNET_TIME_absolute_ntoh(nr->expiration);
-    d[c].record_type = ntohl (nr->record_type);
-    d[c].flags = ntohl (nr->flags);
-    d[c].data_size = ntohl (nr->data_size);
-    if (d[c].data_size > 0)
-      d[c].data = GNUNET_malloc (d[c].data_size);
+  case 0:
+    return NULL;
+  case GNUNET_DNSPARSER_TYPE_A:
+    if (data_size != sizeof (struct in_addr))
+      return NULL;
+    if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp)))
+      return NULL;
+    return GNUNET_strdup (tmp);
+  case GNUNET_DNSPARSER_TYPE_NS:
+    return GNUNET_strndup (data, data_size);
+  case GNUNET_DNSPARSER_TYPE_CNAME:
+    return GNUNET_strndup (data, data_size);
+  case GNUNET_DNSPARSER_TYPE_SOA:
+    soa = (struct soa_data*)data;
+    soa_rname = (char*)&soa[1];
+    soa_mname = (char*)&soa[1]+strlen(soa_rname)+1;
+    if (GNUNET_asprintf(&result, "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu", 
+                     soa_rname, soa_mname,
+                     ntohl (soa->serial), ntohl (soa->refresh),
+                     ntohl (soa->retry), ntohl (soa->expire), ntohl (soa->minimum)))
+      return result;
+    else
+      return NULL;
+  case GNUNET_DNSPARSER_TYPE_PTR:
+    return GNUNET_strndup (data, data_size);
+  case GNUNET_DNSPARSER_TYPE_MX:
+    mx_pref = ntohs(*((uint16_t*)data));
+    if (GNUNET_asprintf(&result, "%hu,%s", mx_pref, data+sizeof(uint16_t))
+        != 0)
+      return result;
     else
-      d[c].data = NULL;
+      return NULL;
+  case GNUNET_DNSPARSER_TYPE_TXT:
+    return GNUNET_strndup (data, data_size);
+  case GNUNET_DNSPARSER_TYPE_AAAA:
+    if (data_size != sizeof (struct in6_addr))
+      return NULL;
+    if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp)))
+      return NULL;
+    return GNUNET_strdup (tmp);
+  case GNUNET_NAMESTORE_TYPE_PKEY:
+    if (data_size != sizeof (struct GNUNET_CRYPTO_ShortHashCode))
+      return NULL;
+    GNUNET_CRYPTO_short_hash_to_enc (data,
+                                    &enc);
+    return GNUNET_strdup ((const char*) enc.short_encoding);
+  case GNUNET_NAMESTORE_TYPE_PSEU:
+    return GNUNET_strndup (data, data_size);
+  case GNUNET_NAMESTORE_TYPE_LEHO:
+    return GNUNET_strndup (data, data_size);
+  case GNUNET_NAMESTORE_TYPE_VPN:
+    vpn = (struct vpn_data*)data;
+
+    GNUNET_CRYPTO_hash_to_enc (&vpn->peer, &s_peer);
+    if (GNUNET_OK != GNUNET_asprintf (&vpn_str, "%d:%s:%s",
+                                      vpn->proto,
+                                      (char*)&s_peer,
+                                      (char*)&vpn[1]))
+      return NULL;
+    return vpn_str;
+  case GNUNET_DNSPARSER_TYPE_SRV:
+    srv = (struct srv_data*)data;
+
+    if (GNUNET_OK != GNUNET_asprintf (&srv_str, "%d:%d:%d:%s",
+                                      ntohs (srv->prio),
+                                      ntohs (srv->weight),
+                                      ntohs (srv->port),
+                                      (char*)&srv[1]))
+      return NULL;
+    return srv_str;
+  default:
+    GNUNET_break (0);
+  }
+  GNUNET_break (0); // not implemented
+  return NULL;
+}
 
-    offset += sizeof (struct GNUNET_NAMESTORE_NetworkRecord);
-    memcpy((char *) d[c].data, &src[offset], d[c].data_size);
 
-    offset += d[c].data_size;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deserialized record[%i] /w data_size %i\n", c, d[c].data_size);
+/**
+ * Convert human-readable version of a 'value' of a record to the binary
+ * representation.
+ *
+ * @param type type of the record
+ * @param s human-readable string
+ * @param data set to value in binary encoding (will be allocated)
+ * @param data_size set to number of bytes in data
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_NAMESTORE_string_to_value (uint32_t type,
+                                 const char *s,
+                                 void **data,
+                                 size_t *data_size)
+{
+  struct in_addr value_a;
+  struct in6_addr value_aaaa;
+  struct GNUNET_CRYPTO_ShortHashCode pkey;
+  uint16_t mx_pref;
+  uint16_t mx_pref_n;
+  struct soa_data *soa;
+  char result[253];
+  char soa_rname[63];
+  char soa_mname[63];
+  uint32_t soa_serial;
+  uint32_t soa_refresh;
+  uint32_t soa_retry;
+  uint32_t soa_expire;
+  uint32_t soa_min;
+  struct GNUNET_CRYPTO_HashAsciiEncoded s_peer;
+  char s_serv[253];
+  struct vpn_data* vpn;
+  uint16_t proto;
+  
+  switch (type)
+  {
+  case 0:
+    return GNUNET_SYSERR;
+  case GNUNET_DNSPARSER_TYPE_A:
+    if (1 != inet_pton (AF_INET, s, &value_a))
+      return GNUNET_SYSERR;
+    *data = GNUNET_malloc (sizeof (struct in_addr));
+    memcpy (*data, &value_a, sizeof (value_a));
+    *data_size = sizeof (value_a);
+    return GNUNET_OK;
+  case GNUNET_DNSPARSER_TYPE_NS:
+    *data = GNUNET_strdup (s);
+    *data_size = strlen (s);
+    return GNUNET_OK;
+  case GNUNET_DNSPARSER_TYPE_CNAME:
+    *data = GNUNET_strdup (s);
+    *data_size = strlen (s);
+    return GNUNET_OK;
+  case GNUNET_DNSPARSER_TYPE_SOA:
+    
+    if (SSCANF(s, "rname=%s mname=%s %u,%u,%u,%u,%u",
+               soa_rname, soa_mname,
+               &soa_serial, &soa_refresh, &soa_retry, &soa_expire, &soa_min) 
+        != 7)
+      return GNUNET_SYSERR;
+    
+    *data_size = sizeof (struct soa_data)+strlen(soa_rname)+strlen(soa_mname)+2;
+    *data = GNUNET_malloc (*data_size);
+    soa = (struct soa_data*)*data;
+    soa->serial = htonl(soa_serial);
+    soa->refresh = htonl(soa_refresh);
+    soa->retry = htonl(soa_retry);
+    soa->expire = htonl(soa_expire);
+    soa->minimum = htonl(soa_min);
+    strcpy((char*)&soa[1], soa_rname);
+    strcpy((char*)&soa[1]+strlen(*data)+1, soa_mname);
+    return GNUNET_OK;
+
+  case GNUNET_DNSPARSER_TYPE_PTR:
+    *data = GNUNET_strdup (s);
+    *data_size = strlen (s);
+    return GNUNET_OK;
+  case GNUNET_DNSPARSER_TYPE_MX:
+    if (SSCANF(s, "%hu,%s", &mx_pref, result) != 2)
+      return GNUNET_SYSERR;
+    *data_size = sizeof (uint16_t)+strlen(result)+1;
+    *data = GNUNET_malloc (*data_size);
+    mx_pref_n = htons(mx_pref);
+    memcpy(*data, &mx_pref_n, sizeof (uint16_t));
+    strcpy((*data)+sizeof (uint16_t), result);
+    return GNUNET_OK;
+  case GNUNET_DNSPARSER_TYPE_TXT:
+    *data = GNUNET_strdup (s);
+    *data_size = strlen (s);
+    return GNUNET_OK;
+  case GNUNET_DNSPARSER_TYPE_AAAA:
+    if (1 != inet_pton (AF_INET6, s, &value_aaaa))    
+      return GNUNET_SYSERR;    
+    *data = GNUNET_malloc (sizeof (struct in6_addr));
+    *data_size = sizeof (struct in6_addr);
+    memcpy (*data, &value_aaaa, sizeof (value_aaaa));
+    return GNUNET_OK;
+  case GNUNET_NAMESTORE_TYPE_PKEY:
+    if (GNUNET_OK !=
+       GNUNET_CRYPTO_short_hash_from_string (s, &pkey))
+      return GNUNET_SYSERR;
+    *data = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode));
+    memcpy (*data, &pkey, sizeof (pkey));
+    *data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode);
+    return GNUNET_OK;
+  case GNUNET_NAMESTORE_TYPE_PSEU:
+    *data = GNUNET_strdup (s);
+    *data_size = strlen (s);
+    return GNUNET_OK;
+  case GNUNET_NAMESTORE_TYPE_LEHO:
+    *data = GNUNET_strdup (s);
+    *data_size = strlen (s);
+    return GNUNET_OK;
+  case GNUNET_NAMESTORE_TYPE_VPN:
+    
+    
+    if (4 != SSCANF (s,"%hu:%s:%s",
+                     &proto, (char*)&s_peer, s_serv))
+    {
+      return GNUNET_SYSERR;
+    }
+    *data_size = sizeof (struct vpn_data) + strlen (s_serv) + 1;
+    
+    *data = GNUNET_malloc (*data_size);
+
+    vpn = (struct vpn_data*)*data;
+    
+    if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char*)&s_peer, &vpn->peer))
+    {
+      GNUNET_free (*data);
+      return GNUNET_SYSERR;
+    }
+
+    vpn->proto = htons (proto);
+    strcpy ((char*)&vpn[1], s_serv);
+    return GNUNET_OK;
+  default:
+    GNUNET_break (0);
   }
-  GNUNET_assert(offset == len);
+  return GNUNET_SYSERR;
+}
+
+
+static struct { 
+  const char *name; 
+  uint32_t number; 
+} name_map[] = {
+  { "A", GNUNET_DNSPARSER_TYPE_A },
+  { "NS", GNUNET_DNSPARSER_TYPE_NS },
+  { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME },
+  { "SOA", GNUNET_DNSPARSER_TYPE_SOA },
+  { "PTR", GNUNET_DNSPARSER_TYPE_PTR },
+  { "MX", GNUNET_DNSPARSER_TYPE_MX },
+  { "TXT", GNUNET_DNSPARSER_TYPE_TXT },
+  { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA },
+  { "PKEY",  GNUNET_NAMESTORE_TYPE_PKEY },
+  { "PSEU",  GNUNET_NAMESTORE_TYPE_PSEU },
+  { "LEHO",  GNUNET_NAMESTORE_TYPE_LEHO },
+  { NULL, UINT32_MAX }
+};
+
+
+/**
+ * Convert a type name (i.e. "AAAA") to the corresponding number.
+ *
+ * @param typename name to convert
+ * @return corresponding number, UINT32_MAX on error
+ */
+uint32_t
+GNUNET_NAMESTORE_typename_to_number (const char *typename)
+{
+  unsigned int i;
 
-  return elements;
+  i=0;
+  while ( (name_map[i].name != NULL) &&
+         (0 != strcasecmp (typename, name_map[i].name)) )
+    i++;
+  return name_map[i].number;  
 }
 
-/* end of namestore_api.c */
+
+/**
+ * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
+ *
+ * @param type number of a type to convert
+ * @return corresponding typestring, NULL on error
+ */
+const char *
+GNUNET_NAMESTORE_number_to_typename (uint32_t type)
+{
+  unsigned int i;
+
+  i=0;
+  while ( (name_map[i].name != NULL) &&
+         (type != name_map[i].number) )
+    i++;
+  return name_map[i].name;  
+}
+
+
+
+/* end of namestore_common.c */