-LRN: W32 NS provider for GNS
authorChristian Grothoff <christian@grothoff.org>
Fri, 6 Jul 2012 07:39:24 +0000 (07:39 +0000)
committerChristian Grothoff <christian@grothoff.org>
Fri, 6 Jul 2012 07:39:24 +0000 (07:39 +0000)
Also a helper service.
A couple tools for installing/removing the provder.
And a resolver tool that loads the provider directly.

src/gns/Makefile.am
src/gns/gnunet-gns-helper-service-w32.c [new file with mode: 0644]
src/gns/gnunet_w32nsp_lib.h [new file with mode: 0644]
src/gns/w32nsp-install.c [new file with mode: 0644]
src/gns/w32nsp-resolve.c [new file with mode: 0644]
src/gns/w32nsp-uninstall.c [new file with mode: 0644]
src/gns/w32nsp.c [new file with mode: 0644]
src/gns/w32resolver.h [new file with mode: 0644]

index 8f322789c72c00b72871b7b97b11c7a797874dab..26d1c0a67d934de27a80b9a0c0adb764f9544a43 100644 (file)
@@ -8,6 +8,9 @@ SUBDIRS = . $(NSS_SUBDIR)
 
 if MINGW
   WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
 
 if MINGW
   WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+  DO_W32_HELPER = gnunet-gns-helper-service-w32
+  DO_W32_NSP = libw32nsp.la
+  DO_W32_NSPTOOLS = w32nsp-install w32nsp-uninstall w32nsp-resolve
 endif
 
 if USE_COVERAGE
 endif
 
 if USE_COVERAGE
@@ -19,9 +22,11 @@ pkgcfgdir= $(pkgdatadir)/config.d/
 plugindir = $(libdir)/gnunet
 
 pkgcfg_DATA = \
 plugindir = $(libdir)/gnunet
 
 pkgcfg_DATA = \
+  gns-helper-service-w32.conf \
   gns.conf
 
 lib_LTLIBRARIES = \
   gns.conf
 
 lib_LTLIBRARIES = \
+  $(DO_W32_NSP) \
   libgnunetgns.la
 
 if HAVE_MHD
   libgnunetgns.la
 
 if HAVE_MHD
@@ -35,6 +40,8 @@ bin_PROGRAMS = \
   gnunet-service-gns \
   $(DO_FCFSD) \
        $(DO_PROXY) \
   gnunet-service-gns \
   $(DO_FCFSD) \
        $(DO_PROXY) \
+  $(DO_W32_HELPER) \
+  $(DO_W32_NSPTOOLS) \
   gnunet-gns
 
 bin_SCRIPTS=gnunet-gns-proxy-setup-ca
   gnunet-gns
 
 bin_SCRIPTS=gnunet-gns-proxy-setup-ca
@@ -274,6 +281,27 @@ gnunet_gns_proxy_LDADD = -lmicrohttpd -lcurl -lgnutls \
 gnunet_gns_proxy_DEPENDENCIES = \
   libgnunetgns.la
 
 gnunet_gns_proxy_DEPENDENCIES = \
   libgnunetgns.la
 
+gnunet_gns_helper_service_w32_SOURCES = \
+  gnunet-gns-helper-service-w32.c
+gnunet_gns_helper_service_w32_LDADD = \
+  $(top_builddir)/src/gns/libgnunetgns.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL)
+gnunet_gns_helper_service_w32_DEPENDENCIES = \
+  libgnunetgns.la
+
+w32nsp_install_SOURCES = \
+  w32nsp-install.c
+w32nsp_install_LDADD = -lws2_32
+
+w32nsp_uninstall_SOURCES = \
+  w32nsp-uninstall.c
+w32nsp_uninstall_LDADD = -lws2_32
+
+w32nsp_resolve_SOURCES = \
+  w32nsp-resolve.c
+w32nsp_resolve_LDADD = -lws2_32
+
 gnunet_service_gns_SOURCES = \
  gnunet-service-gns.c \
  gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \
 gnunet_service_gns_SOURCES = \
  gnunet-service-gns.c \
  gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \
@@ -308,6 +336,13 @@ gnunet_gns_fcfsd_DEPENDENCIES = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/namestore/libgnunetnamestore.la
 
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/namestore/libgnunetnamestore.la
 
+libw32nsp_la_SOURCES = \
+  w32nsp.c
+libw32nsp_la_LIBADD = \
+  -lole32 -lws2_32
+libw32nsp_la_LDFLAGS = \
+  -export-symbols $(top_srcdir)/src/gns/w32nsp.def \
+  $(GN_LIB_LDFLAGS)
 
 libgnunetgns_la_SOURCES = \
  gns_api.c gns.h
 
 libgnunetgns_la_SOURCES = \
  gns_api.c gns.h
diff --git a/src/gns/gnunet-gns-helper-service-w32.c b/src/gns/gnunet-gns-helper-service-w32.c
new file mode 100644 (file)
index 0000000..198dfb8
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+     This file is part of GNUnet.
+     (C) 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file gnunet-gns-helper-service-w32.c
+ * @brief an intermediary service to access distributed GNS
+ * @author Christian Grothoff
+ * @author LRN
+ */
+#define INITGUID
+#include "platform.h"
+#include <gnunet_util_lib.h>
+#include <gnunet_dnsparser_lib.h>
+#include <gnunet_namestore_service.h>
+#include <gnunet_gns_service.h>
+#include <gnunet_w32nsp_lib.h>
+#include "w32resolver.h"
+#include <nspapi.h>
+#include <unistr.h>
+
+#define DEFINE_DNS_GUID(a,x) DEFINE_GUID(a, 0x00090035, 0x0000, x, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_A, 0x0001);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_NS, 0x0002);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_CNAME, 0x0005);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_SOA, 0x0006);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_PTR, 0x000c);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_MX, 0x000f);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_TEXT, 0x0010);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_AAAA, 0x001c);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_SRV, 0x0021);
+DEFINE_GUID(SVCID_HOSTNAME, 0x0002a800, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+DEFINE_GUID(SVCID_INET_HOSTADDRBYNAME, 0x0002a803, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+
+struct request
+{
+  struct GNUNET_SERVER_Client *client;
+  GUID sc;
+  int af;
+  wchar_t *name;
+  char *u8name;
+};
+
+/**
+ * Handle to GNS service.
+ */
+static struct GNUNET_GNS_Handle *gns;
+
+static struct GNUNET_CRYPTO_ShortHashCode *zone = NULL;
+static struct GNUNET_CRYPTO_ShortHashCode user_zone;
+struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key = NULL;
+
+
+/**
+ * Task run on shutdown.  Cleans up everything.
+ *
+ * @param cls unused
+ * @param tc scheduler context
+ */
+static void
+do_shutdown (void *cls,
+            const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  if (NULL != gns)
+  {
+    GNUNET_GNS_disconnect (gns);
+    gns = NULL;
+  }
+}
+
+/**
+ * Context for transmitting replies to clients.
+ */
+struct TransmitCallbackContext
+{
+
+  /**
+   * We keep these in a doubly-linked list (for cleanup).
+   */
+  struct TransmitCallbackContext *next;
+
+  /**
+   * We keep these in a doubly-linked list (for cleanup).
+   */
+  struct TransmitCallbackContext *prev;
+
+  /**
+   * The message that we're asked to transmit.
+   */
+  struct GNUNET_MessageHeader *msg;
+
+  size_t msgsize;
+
+  /**
+   * Handle for the transmission request.
+   */
+  struct GNUNET_SERVER_TransmitHandle *th;
+
+  /**
+   * Client that we are transmitting to.
+   */
+  struct GNUNET_SERVER_Client *client;
+
+};
+
+
+/**
+ * Head of the doubly-linked list (for cleanup).
+ */
+static struct TransmitCallbackContext *tcc_head;
+
+/**
+ * Tail of the doubly-linked list (for cleanup).
+ */
+static struct TransmitCallbackContext *tcc_tail;
+
+/**
+ * Have we already cleaned up the TCCs and are hence no longer
+ * willing (or able) to transmit anything to anyone?
+ */
+static int cleaning_done;
+
+/**
+ * Function called to notify a client about the socket
+ * begin ready to queue more data.  "buf" will be
+ * NULL and "size" zero if the socket was closed for
+ * writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_callback (void *cls, size_t size, void *buf)
+{
+  struct TransmitCallbackContext *tcc = cls;
+  size_t msize;
+
+  tcc->th = NULL;
+  GNUNET_CONTAINER_DLL_remove (tcc_head, tcc_tail, tcc);
+  msize = tcc->msgsize;
+  if (size == 0)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                _("Transmission to client failed!\n"));
+    GNUNET_SERVER_client_drop (tcc->client);
+    GNUNET_free (tcc->msg);
+    GNUNET_free (tcc);
+    return 0;
+  }
+  GNUNET_assert (size >= msize);
+  memcpy (buf, tcc->msg, msize);
+  GNUNET_SERVER_client_drop (tcc->client);
+  GNUNET_free (tcc->msg);
+  GNUNET_free (tcc);
+  return msize;
+}
+
+
+/**
+ * Transmit the given message to the client.
+ *
+ * @param client target of the message
+ * @param msg message to transmit, will be freed!
+ */
+static void
+transmit (struct GNUNET_SERVER_Client *client, struct GNUNET_MessageHeader *msg, size_t msgsize)
+{
+  struct TransmitCallbackContext *tcc;
+
+  if (GNUNET_YES == cleaning_done)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                _("Shutdown in progress, aborting transmission.\n"));
+    GNUNET_SERVER_client_drop (client);
+    GNUNET_free (msg);
+    return;
+  }
+  tcc = GNUNET_malloc (sizeof (struct TransmitCallbackContext));
+  tcc->msg = msg;
+  tcc->msgsize = msgsize;
+  tcc->client = client;
+  if (NULL ==
+      (tcc->th =
+       GNUNET_SERVER_notify_transmit_ready (client, msgsize,
+                                            GNUNET_TIME_UNIT_FOREVER_REL,
+                                            &transmit_callback, tcc)))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_client_drop (client);
+    GNUNET_free (msg);
+    GNUNET_free (tcc);
+    return;
+  }
+  GNUNET_SERVER_client_keep (client);
+  GNUNET_CONTAINER_DLL_insert (tcc_head, tcc_tail, tcc);
+}
+
+#define MarshallPtr(ptr, base, type) \
+  if (ptr) \
+    ptr = (type *) ((char *) ptr - (char *) base)
+
+void
+MarshallWSAQUERYSETW (WSAQUERYSETW *qs, GUID *sc)
+{
+  int i;
+  MarshallPtr (qs->lpszServiceInstanceName, qs, wchar_t);
+  MarshallPtr (qs->lpServiceClassId, qs, GUID);
+  MarshallPtr (qs->lpVersion, qs, WSAVERSION);
+  MarshallPtr (qs->lpNSProviderId, qs, GUID);
+  MarshallPtr (qs->lpszContext, qs, wchar_t);
+  MarshallPtr (qs->lpafpProtocols, qs, AFPROTOCOLS);
+  MarshallPtr (qs->lpszQueryString, qs, wchar_t);
+  for (i = 0; i < qs->dwNumberOfCsAddrs; i++)
+  {
+    MarshallPtr (qs->lpcsaBuffer[i].LocalAddr.lpSockaddr, qs, SOCKADDR);
+    MarshallPtr (qs->lpcsaBuffer[i].RemoteAddr.lpSockaddr, qs, SOCKADDR);
+  }
+  MarshallPtr (qs->lpcsaBuffer, qs, CSADDR_INFO);
+  if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, sc) && qs->lpBlob != NULL && qs->lpBlob->pBlobData != NULL)
+  {
+    struct hostent *he;
+    he = (struct hostent *) qs->lpBlob->pBlobData;
+    for (i = 0; he->h_aliases[i] != NULL; i++)
+      MarshallPtr (he->h_aliases[i], he, char);
+    MarshallPtr (he->h_aliases, he, char *);
+    MarshallPtr (he->h_name, he, char);
+    for (i = 0; he->h_addr_list[i] != NULL; i++)
+      MarshallPtr (he->h_addr_list[i], he, void);
+    MarshallPtr (he->h_addr_list, he, char *);
+    MarshallPtr (qs->lpBlob->pBlobData, qs, void);
+  }
+  MarshallPtr (qs->lpBlob, qs, BLOB);
+}
+
+static void
+process_ip_lookup_result (void* cls, uint32_t rd_count,
+    const struct GNUNET_NAMESTORE_RecordData *rd)
+{
+  int i, j, csanum;
+  struct request *rq = (struct request *) cls;
+  struct GNUNET_W32RESOLVER_GetMessage *msg;
+  struct GNUNET_MessageHeader *msgend;
+  WSAQUERYSETW *qs;
+  size_t size;
+  size_t size_recalc;
+  char *ptr;
+  size_t blobsize = 0;
+  size_t blobaddrcount = 0;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Got lookup result with count %u for rq %p with client %p\n",
+              rd_count, rq, rq->client);
+
+  if (rd_count == 0)
+  {
+    size = sizeof (struct GNUNET_MessageHeader);
+    msg = GNUNET_malloc (size);
+    msg->header.size = htons (size);
+    msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
+    transmit (rq->client, &msg->header, msg->header.size);
+    return;
+  }
+
+  size = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW);
+  size += (wcslen (rq->name) + 1) * sizeof (wchar_t);
+  size += sizeof (GUID);
+  /* lpszComment ? a TXT record? */
+  size += sizeof (GUID);
+  /* lpszContext ? Not sure what it is */
+  csanum = 0;
+  for (i = 0; i < rd_count; i++)
+  {
+    switch (rd[i].record_type)
+    {
+    case GNUNET_GNS_RECORD_A:
+      if (rd[i].data_size != sizeof (struct in_addr))
+        continue;
+      size += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in) * 2;
+      csanum++;
+      break;
+    case GNUNET_GNS_RECORD_AAAA:
+      if (rd[i].data_size != sizeof (struct in6_addr))
+        continue;
+      size += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in6) * 2;
+      csanum++;
+      break;
+    }
+  }
+  if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &rq->sc))
+  {
+    size += sizeof (BLOB);
+    blobsize += sizeof (struct hostent);
+    blobsize += strlen (rq->u8name) + 1;
+    blobsize += sizeof (void *); /* For aliases */
+    blobsize += sizeof (void *); /* For addresses */
+    for (i = 0; i < rd_count; i++)
+    {
+      if ((rq->af == AF_INET || rq->af == AF_UNSPEC) && rd[i].record_type == GNUNET_GNS_RECORD_A)
+      {
+        blobsize += sizeof (void *);
+        blobsize += sizeof (struct in_addr);
+        blobaddrcount++;
+      }
+      else if (rq->af == AF_INET6 && rd[i].record_type == GNUNET_GNS_RECORD_AAAA)
+      {
+        blobsize += sizeof (void *);
+        blobsize += sizeof (struct in6_addr);
+        blobaddrcount++;
+      }
+    }
+    size += blobsize;
+  }
+  size += sizeof (struct GNUNET_MessageHeader);
+  size_recalc = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW);
+  msg = GNUNET_malloc (size);
+  msg->header.size = htons (size - sizeof (struct GNUNET_MessageHeader));
+  msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
+  msg->af = htonl (rq->af);
+  msg->sc_data1 = htonl (rq->sc.Data1);
+  msg->sc_data2 = htons (rq->sc.Data2);
+  msg->sc_data3 = htons (rq->sc.Data3);
+  msg->sc_data4 = 0;
+  for (i = 0; i < 8; i++)
+    msg->sc_data4 |= rq->sc.Data4[i] << ((7 - i) * 8);
+  msg->sc_data4 = GNUNET_htonll (msg->sc_data4);
+  qs = (WSAQUERYSETW *) &msg[1];
+  ptr = (char *) &qs[1];
+  GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+  qs->dwSize = sizeof (WSAQUERYSETW);
+  qs->lpszServiceInstanceName = (wchar_t *) ptr;
+  ptr += (wcslen (rq->name) + 1) * sizeof (wchar_t);
+  size_recalc += (wcslen (rq->name) + 1) * sizeof (wchar_t);
+  GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+  wcscpy (qs->lpszServiceInstanceName, rq->name);
+  qs->lpServiceClassId = (GUID *) ptr;
+  ptr += sizeof (GUID);
+  size_recalc += sizeof (GUID);
+  GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+  memcpy (qs->lpServiceClassId, &rq->sc, sizeof (GUID));
+  qs->lpVersion = NULL;
+  qs->dwNameSpace = NS_DNS;
+  qs->lpNSProviderId = (GUID *) ptr;
+  ptr += sizeof (GUID);
+  size_recalc += sizeof (GUID);
+  GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+  memcpy (qs->lpNSProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS, sizeof (GUID));
+  qs->lpszContext = NULL;
+  qs->dwNumberOfProtocols = 0;
+  qs->lpafpProtocols = NULL;
+  /* Don't bother with this... */
+  qs->lpszQueryString = NULL;
+  qs->dwNumberOfCsAddrs = rd_count;
+  qs->lpcsaBuffer = (CSADDR_INFO *) ptr;
+  ptr += sizeof (CSADDR_INFO) * csanum;
+  j = 0;
+  for (i = 0; i < rd_count; i++)
+  {
+    switch (rd[i].record_type)
+    {
+    case GNUNET_GNS_RECORD_A:
+      if (rd[i].data_size != sizeof (struct in_addr))
+        continue;
+      qs->lpcsaBuffer[j].iSocketType = SOCK_STREAM;
+      qs->lpcsaBuffer[j].iProtocol = IPPROTO_TCP;
+
+      qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength = sizeof (struct sockaddr_in);
+      qs->lpcsaBuffer[j].LocalAddr.lpSockaddr = (SOCKADDR *) ptr;
+      ptr += qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength;
+      memset (qs->lpcsaBuffer[j].LocalAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength);
+      ((struct sockaddr_in *)qs->lpcsaBuffer[j].LocalAddr.lpSockaddr)->sin_family = AF_INET;
+
+      qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength = sizeof (struct sockaddr_in);
+      qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr = (SOCKADDR *) ptr;
+      ptr += qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength;
+      memset (qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength);
+      ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_family = AF_INET;
+      ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_port = htonl (53); /* Don't ask why it's 53 */
+      ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_addr = *(struct in_addr *) rd[i].data;
+      size_recalc += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in) * 2;
+      j++;
+      break;
+    case GNUNET_GNS_RECORD_AAAA:
+      if (rd[i].data_size != sizeof (struct in6_addr))
+        continue;
+      qs->lpcsaBuffer[j].iSocketType = SOCK_STREAM;
+      qs->lpcsaBuffer[j].iProtocol = IPPROTO_TCP;
+
+      qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength = sizeof (struct sockaddr_in6);
+      qs->lpcsaBuffer[j].LocalAddr.lpSockaddr = (SOCKADDR *) ptr;
+      ptr += qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength;
+      memset (qs->lpcsaBuffer[j].LocalAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength);
+      ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].LocalAddr.lpSockaddr)->sin6_family = AF_INET6;
+
+      qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength = sizeof (struct sockaddr_in6);
+      qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr = (SOCKADDR *) ptr;
+      ptr += qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength;
+      memset (qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength);
+      ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_family = AF_INET6;
+      ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_port = htonl (53); /* Don't ask why it's 53 */
+      ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_addr = *(struct in6_addr *) rd[i].data;
+      size_recalc += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in6) * 2;
+      j++;
+      break;
+    default:
+      break;
+    }
+  }
+  GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+  qs->dwOutputFlags = 0;
+  if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &rq->sc))
+  {
+    struct hostent *he;
+    qs->lpBlob = (BLOB *) ptr;
+    ptr += sizeof (BLOB);
+
+    size_recalc += sizeof (BLOB);
+    GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+
+    qs->lpBlob->cbSize = blobsize;
+    qs->lpBlob->pBlobData = (BYTE *) ptr;
+    ptr += sizeof (struct hostent);
+
+    size_recalc += sizeof (struct hostent);
+    GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+
+    he = (struct hostent *) qs->lpBlob->pBlobData;
+    he->h_name = (char *) ptr;
+    ptr += strlen (rq->u8name) + 1;
+
+    size_recalc += strlen (rq->u8name) + 1;
+    GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+
+    strcpy (he->h_name, rq->u8name);
+    he->h_aliases = (char **) ptr;
+    ptr += sizeof (void *);
+
+    size_recalc += sizeof (void *); /* For aliases */
+    GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+
+    he->h_aliases[0] = NULL;
+    he->h_addrtype = rq->af;
+    he->h_length = rq->af == AF_INET || rq->af == AF_UNSPEC ? sizeof (struct in_addr) : sizeof (struct in6_addr);
+    he->h_addr_list = (char **) ptr;
+    ptr += sizeof (void *) * (blobaddrcount + 1);
+
+    size_recalc += sizeof (void *) * (blobaddrcount + 1); /* For addresses */
+    GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+
+    j = 0;
+    for (i = 0; i < rd_count; i++)
+    {
+      if ((rq->af == AF_INET || rq->af == AF_UNSPEC) &&
+          rd[i].record_type == GNUNET_GNS_RECORD_A)
+      {
+        he->h_addr_list[j] = (char *) ptr;
+        ptr += sizeof (struct in_addr);
+
+        size_recalc += sizeof (struct in_addr);
+        GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+
+        memcpy (he->h_addr_list[j], rd[i].data, sizeof (struct in_addr));
+        j++;
+      }
+      else if (rq->af == AF_INET6 && rd[i].record_type == GNUNET_GNS_RECORD_AAAA)
+      {
+        he->h_addr_list[j] = (char *) ptr;
+        ptr += sizeof (struct in6_addr);
+
+        size_recalc += sizeof (struct in6_addr);
+        GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
+
+        memcpy (he->h_addr_list[j], rd[i].data, sizeof (struct in6_addr));
+        j++;
+      }
+    }
+    he->h_addr_list[j] = NULL;
+  }
+  msgend = (struct GNUNET_MessageHeader *) ptr;
+  ptr += sizeof (struct GNUNET_MessageHeader);
+  size_recalc += sizeof (struct GNUNET_MessageHeader);
+
+  msgend->type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
+  msgend->size = htons (sizeof (struct GNUNET_MessageHeader));
+
+  if ((char *) ptr - (char *) msg != size || size_recalc != size || size_recalc != ((char *) ptr - (char *) msg))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error in WSAQUERYSETW size calc: expected %lu, got %lu (recalc %lu)\n", size, (unsigned long) ((char *) ptr - (char *) msg), size_recalc);
+  }
+  MarshallWSAQUERYSETW (qs, &rq->sc);
+  transmit (rq->client, &msg->header, size);
+}
+
+static void
+get_ip_from_hostname (struct GNUNET_SERVER_Client *client,
+    const wchar_t *name, int af, GUID sc)
+{
+  struct request *rq;
+  char *hostname;
+  size_t strl;
+  size_t namelen;
+  uint32_t rtype;
+
+  if (IsEqualGUID (&SVCID_DNS_TYPE_A, &sc))
+    rtype = GNUNET_GNS_RECORD_A;
+  else if (IsEqualGUID (&SVCID_DNS_TYPE_NS, &sc))
+    rtype = GNUNET_GNS_RECORD_NS;
+  else if (IsEqualGUID (&SVCID_DNS_TYPE_CNAME, &sc))
+    rtype = GNUNET_GNS_RECORD_CNAME;
+  else if (IsEqualGUID (&SVCID_DNS_TYPE_SOA, &sc))
+    rtype = GNUNET_GNS_RECORD_SOA;
+  else if (IsEqualGUID (&SVCID_DNS_TYPE_PTR, &sc))
+    rtype = GNUNET_GNS_RECORD_PTR;
+  else if (IsEqualGUID (&SVCID_DNS_TYPE_MX, &sc))
+    rtype = GNUNET_GNS_RECORD_MX;
+  else if (IsEqualGUID (&SVCID_DNS_TYPE_TEXT, &sc))
+    rtype = GNUNET_GNS_RECORD_TXT;
+  else if (IsEqualGUID (&SVCID_DNS_TYPE_AAAA, &sc))
+    rtype = GNUNET_GNS_RECORD_AAAA;
+  else if (IsEqualGUID (&SVCID_DNS_TYPE_SRV, &sc))
+    rtype = GNUNET_GNS_RECORD_SRV;
+  else if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &sc))
+    rtype = GNUNET_GNS_RECORD_A;
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Unknown GUID: %08X-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
+                sc.Data1, sc.Data2, sc.Data3, sc.Data4[0], sc.Data4[1], sc.Data4[2],
+                sc.Data4[3], sc.Data4[4], sc.Data4[5], sc.Data4[6], sc.Data4[7]);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+
+  if (name)
+    namelen = wcslen (name);
+  else
+    namelen = 0;
+  if (namelen > 0)
+    hostname = (char *) u16_to_u8 (name, namelen + 1, NULL, &strl);
+  
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "W32 DNS resolver asked to look up %s for `%s'.\n",
+              af == AF_INET ? "IPv4" : af == AF_INET6 ? "IPv6" : "anything",
+              hostname);
+  rq = GNUNET_malloc (sizeof (struct request));
+  rq->sc = sc;
+  rq->client = client;
+  rq->af = af;
+  if (rq->af != AF_INET && rq->af != AF_INET6)
+    rq->af = AF_INET;
+  if (namelen)
+  {
+    rq->name = GNUNET_malloc ((namelen + 1) * sizeof (wchar_t));
+    memcpy (rq->name, name, (namelen + 1) * sizeof (wchar_t));
+    rq->u8name = hostname;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Launching a lookup for client %p with rq %p\n",
+              client, rq);
+
+  if (NULL != GNUNET_GNS_lookup_zone (gns, hostname, zone, rtype,
+      GNUNET_YES, shorten_key, &process_ip_lookup_result, rq))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Lookup launched, waiting for a reply\n");
+    GNUNET_SERVER_client_keep (client);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Lookup was not, disconnecting the client\n");
+    if (namelen)
+    {
+      GNUNET_free (rq->name);
+      free (rq->u8name);
+    }
+    GNUNET_free (rq);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+  }
+}
+
+/**
+ * Handle GET-message.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_get (void *cls, struct GNUNET_SERVER_Client *client,
+            const struct GNUNET_MessageHeader *message)
+{
+  uint16_t msize;
+  const struct GNUNET_W32RESOLVER_GetMessage *msg;
+  GUID sc;
+  uint16_t size;
+  uint64_t data4;
+  int i;
+  const wchar_t *hostname;
+  int af;
+
+  msize = ntohs (message->size);
+  if (msize < sizeof (struct GNUNET_W32RESOLVER_GetMessage))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  msg = (const struct GNUNET_W32RESOLVER_GetMessage *) message;
+  size = msize - sizeof (struct GNUNET_W32RESOLVER_GetMessage);
+  af = ntohl (msg->af);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got NBO GUID: %08X-%04X-%04X-%016llX\n",
+      msg->sc_data1, msg->sc_data2, msg->sc_data3, msg->sc_data4);
+  sc.Data1 = ntohl (msg->sc_data1);
+  sc.Data2 = ntohs (msg->sc_data2);
+  sc.Data3 = ntohs (msg->sc_data3);
+  data4 = GNUNET_ntohll (msg->sc_data4);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got GUID: %08X-%04X-%04X-%016llX\n",
+      sc.Data1, sc.Data2, sc.Data3, data4);
+  for (i = 0; i < 8; i++)
+    sc.Data4[i] = 0xFF & (data4 >> ((7 - i) * 8));
+  
+  hostname = (const wchar_t *) &msg[1];
+  if (hostname[size - 1] != L'\0')
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "name of length %u, not 0-terminated: %*S\n",
+        size, size, hostname);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  get_ip_from_hostname (client, hostname, af, sc);
+  return;
+}
+
+
+/**
+ * Start up gns-helper-w32 service.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param cfg configuration to use
+ */
+static void
+run (void *cls, struct GNUNET_SERVER_Handle *server,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+    {&handle_get, NULL, GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST, 0},
+    {NULL, NULL, 0, 0}
+  };
+
+  char* keyfile;
+  struct GNUNET_CRYPTO_RsaPrivateKey *key = NULL;
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
+  struct GNUNET_CRYPTO_ShortHashAsciiEncoded zonename;
+
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
+                                                           "ZONEKEY", &keyfile))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "No private key for root zone found, using default!\n");
+    zone = NULL;
+  }
+  else
+  {
+    if (GNUNET_YES == GNUNET_DISK_file_test (keyfile))
+    {
+      key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
+      GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
+      GNUNET_CRYPTO_short_hash(&pkey,
+                         sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                         &user_zone);
+      zone = &user_zone;
+      GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Using zone: %s!\n", &zonename);
+      GNUNET_CRYPTO_rsa_key_free(key);
+    }
+    GNUNET_free(keyfile);
+  }
+
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
+                                                   "SHORTEN_ZONEKEY", &keyfile))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "No shorten key found!\n");
+    shorten_key = NULL;
+  }
+  else
+  {
+    if (GNUNET_YES == GNUNET_DISK_file_test (keyfile))
+    {
+      shorten_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
+    }
+    GNUNET_free(keyfile);
+  }
+
+  gns = GNUNET_GNS_connect (cfg);
+  if (gns == NULL)
+    return;
+
+  GNUNET_SERVER_add_handlers (server, handlers);
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_shutdown,
+                                NULL);
+
+}
+
+
+/**
+ * The main function for gns-helper-w32.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  int ret;
+
+  ret =
+      (GNUNET_OK ==
+       GNUNET_SERVICE_run (argc, argv, "gns-helper-service-w32", GNUNET_SERVICE_OPTION_NONE,
+                           &run, NULL)) ? 0 : 1;
+
+  return ret;
+}
+
+/* end of gnunet-gns.c */
diff --git a/src/gns/gnunet_w32nsp_lib.h b/src/gns/gnunet_w32nsp_lib.h
new file mode 100644 (file)
index 0000000..f20859c
--- /dev/null
@@ -0,0 +1,9 @@
+#if !defined(GNUENT_W32NSP_LIB_H)\r
+#define GNUENT_W32NSP_LIB_H\r
+\r
+#include <basetyps.h>\r
+\r
+/* E0D24085-622C-4A93-9A0018-034469DE28DA */\r
+DEFINE_GUID (GNUNET_NAMESPACE_PROVIDER_DNS, 0xE0D24085L, 0x622C, 0x4A93, 0x9A, 0x18, 0x03, 0x44, 0x69, 0xDE, 0x28, 0xDA);\r
+\r
+#endif /* GNUENT_W32NSP_LIB_H */
\ No newline at end of file
diff --git a/src/gns/w32nsp-install.c b/src/gns/w32nsp-install.c
new file mode 100644 (file)
index 0000000..c9ba994
--- /dev/null
@@ -0,0 +1,56 @@
+#define INITGUID\r
+#include <windows.h>\r
+#include <nspapi.h>\r
+#include <ws2spi.h>\r
+#include <gnunet_w32nsp_lib.h>\r
+#include <stdio.h>\r
+\r
+int\r
+main (int argc, char **argv)\r
+{\r
+  int ret;\r
+  int r = 1;\r
+  WSADATA wsd;\r
+  GUID id = GNUNET_NAMESPACE_PROVIDER_DNS;\r
+  wchar_t *cmdl;\r
+  int wargc;\r
+  wchar_t **wargv;\r
+\r
+  if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)\r
+  {\r
+    fprintf (stderr, "WSAStartup() failed: %lu\n", GetLastError());\r
+    return 5;\r
+  }\r
+\r
+  cmdl = GetCommandLineW ();\r
+  if (cmdl == NULL)\r
+  {\r
+    WSACleanup();\r
+    return 2;\r
+  }\r
+  wargv = CommandLineToArgvW (cmdl, &wargc);\r
+  if (wargv == NULL)\r
+  {\r
+    WSACleanup();\r
+    return 3;\r
+  }\r
+  r = 4;\r
+\r
+  if (wargc == 2)\r
+  {\r
+    ret = WSCInstallNameSpace (L"GNUnet DNS provider", wargv[1], NS_DNS, 1, &id);\r
+    if (ret == NO_ERROR)\r
+    {\r
+      r = 0;\r
+    }\r
+    else\r
+    {\r
+      r = 1;\r
+      fprintf (stderr,\r
+          "WSCInstallNameSpace(L\"GNUnet DNS provider\", \"%S\", %d, 0, %p) failed: %lu\n",\r
+          wargv[1], NS_DNS, &id, GetLastError ());\r
+    }\r
+  }\r
+  WSACleanup();\r
+  return r;\r
+}
\ No newline at end of file
diff --git a/src/gns/w32nsp-resolve.c b/src/gns/w32nsp-resolve.c
new file mode 100644 (file)
index 0000000..f5ba224
--- /dev/null
@@ -0,0 +1,340 @@
+#define INITGUID\r
+#include <windows.h>\r
+#include <nspapi.h>\r
+#include <ws2spi.h>\r
+#include <nspapi.h>\r
+#include <ws2tcpip.h>\r
+#include <gnunet_w32nsp_lib.h>\r
+#include <stdio.h>\r
+\r
+typedef int (WSPAPI *LPNSPSTARTUP) (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines);\r
+\r
+GUID host = {0x0002a800,0,0,{ 0xC0,0,0,0,0,0,0,0x46 }};\r
+GUID ip4 = {0x00090035,0,1,{ 0xc0,0,0,0,0,0,0,0x046}}; \r
+GUID ip6 = {0x00090035,0,0x001c, { 0xc0,0,0,0,0,0,0,0x046}};\r
+\r
+DEFINE_GUID(W32_DNS, 0x22059D40, 0x7E9E, 0x11CF, 0xAE, 0x5A, 0x00, 0xAA, 0x00, 0xA7, 0x11, 0x2B);\r
+\r
+#define DEFINE_DNS_GUID(a,x) DEFINE_GUID(a, 0x00090035, 0x0000, x, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_A, 0x0001);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_NS, 0x0002);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_CNAME, 0x0005);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_SOA, 0x0006);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_PTR, 0x000c);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_MX, 0x000f);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_TEXT, 0x0010);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_AAAA, 0x001c);
+DEFINE_DNS_GUID(SVCID_DNS_TYPE_SRV, 0x0021);
+DEFINE_GUID(SVCID_HOSTNAME, 0x0002a800, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+DEFINE_GUID(SVCID_INET_HOSTADDRBYNAME, 0x0002a803, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+\r
+//\r
+// Utility to turn a list of offsets into a list of addresses. Used\r
+// to convert structures returned as BLOBs.\r
+//\r
+\r
+VOID FixList(PCHAR ** List, PCHAR Base)\r
+{\r
+    if(*List)\r
+    {\r
+        PCHAR * Addr;\r
+\r
+        Addr = *List = (PCHAR *)( ((DWORD)*List + Base) );\r
+        while(*Addr)\r
+        {\r
+            *Addr = (PCHAR)(((DWORD)*Addr + Base));\r
+            Addr++;\r
+        }\r
+    }\r
+}\r
+\r
+\r
+//\r
+// Routine to convert a hostent returned in a BLOB to one with\r
+// usable pointers. The structure is converted in-place.\r
+//\r
+VOID UnpackHostEnt(struct hostent * hostent)\r
+{\r
+     PCHAR pch;\r
+\r
+     pch = (PCHAR)hostent;\r
+\r
+     if(hostent->h_name)\r
+     {\r
+         hostent->h_name = (PCHAR)((DWORD)hostent->h_name + pch);\r
+     }\r
+     FixList(&hostent->h_aliases, pch);\r
+     FixList(&hostent->h_addr_list, pch);\r
+}\r
+\r
+void\r
+print_hostent (struct hostent *he)\r
+{\r
+  int i;\r
+  char **pAlias;\r
+  printf("\tOfficial name: %s\n", he->h_name);\r
+  for (pAlias = he->h_aliases; *pAlias != 0; pAlias++) {\r
+      printf("\tAlternate name #%d: %s\n", ++i, *pAlias);\r
+  }\r
+  printf("\tAddress type: ");\r
+  switch (he->h_addrtype) {\r
+  case AF_INET:\r
+      printf("AF_INET\n");\r
+      break;\r
+  case AF_INET6:\r
+      printf("AF_INET6\n");\r
+      break;\r
+  case AF_NETBIOS:\r
+      printf("AF_NETBIOS\n");\r
+      break;\r
+  default:\r
+      printf(" %d\n", he->h_addrtype);\r
+      break;\r
+  }\r
+  printf("\tAddress length: %d\n", he->h_length);\r
+\r
+  if (he->h_addrtype == AF_INET) {\r
+    struct sockaddr_in addr;\r
+    memset (&addr, 0, sizeof (addr));\r
+    addr.sin_family = AF_INET;\r
+    addr.sin_port = 0;\r
+    i = 0;\r
+    while (he->h_addr_list[i] != 0) {\r
+      char buf[1024];\r
+      DWORD buflen = 1024;\r
+      addr.sin_addr = *(struct in_addr *) he->h_addr_list[i++];\r
+      if (NO_ERROR == WSAAddressToStringA ((LPSOCKADDR) &addr, sizeof (addr), NULL, buf, &buflen))\r
+        printf("\tIPv4 Address #%d: %s\n", i, buf);\r
+      else\r
+        printf("\tIPv4 Address #%d: Can't convert: %lu\n", i, GetLastError ());\r
+    }\r
+  } else if (he->h_addrtype == AF_INET6) {\r
+    struct sockaddr_in6 addr;\r
+    memset (&addr, 0, sizeof (addr));\r
+    addr.sin6_family = AF_INET6;\r
+    addr.sin6_port = 0;\r
+    i = 0;\r
+    while (he->h_addr_list[i] != 0) {\r
+      char buf[1024];\r
+      DWORD buflen = 1024;\r
+      addr.sin6_addr = *(struct in6_addr *) he->h_addr_list[i++];\r
+      if (NO_ERROR == WSAAddressToStringA ((LPSOCKADDR) &addr, sizeof (addr), NULL, buf, &buflen))\r
+        printf("\tIPv6 Address #%d: %s\n", i, buf);\r
+      else\r
+        printf("\tIPv6 Address #%d: Can't convert: %lu\n", i, GetLastError ());\r
+    }\r
+  }\r
+}\r
+\r
+int\r
+main (int argc, char **argv)\r
+{\r
+  int ret;\r
+  int r = 1;\r
+  WSADATA wsd;\r
+  GUID *prov = NULL;\r
+  GUID *sc = NULL;\r
+  wchar_t *cmdl;\r
+  int wargc;\r
+  wchar_t **wargv;\r
+\r
+  if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)\r
+  {\r
+    fprintf (stderr, "WSAStartup() failed: %lu\n", GetLastError());\r
+    return 5;\r
+  }\r
+\r
+  cmdl = GetCommandLineW ();\r
+  if (cmdl == NULL)\r
+  {\r
+    WSACleanup();\r
+    return 2;\r
+  }\r
+  wargv = CommandLineToArgvW (cmdl, &wargc);\r
+  if (wargv == NULL)\r
+  {\r
+    WSACleanup();\r
+    return 3;\r
+  }\r
+  r = 4;\r
+\r
+  if (wargc == 5)\r
+  {\r
+    if (wcscmp (wargv[1], L"A") == 0)\r
+      sc = &SVCID_DNS_TYPE_A;\r
+    else if (wcscmp (wargv[1], L"AAAA") == 0)\r
+      sc = &SVCID_DNS_TYPE_AAAA;\r
+    else if (wcscmp (wargv[1], L"name") == 0)\r
+      sc = &SVCID_HOSTNAME;\r
+    else if (wcscmp (wargv[1], L"addr") == 0)\r
+      sc = &SVCID_INET_HOSTADDRBYNAME;\r
+    else\r
+      wargc -= 1;\r
+    if (wcscmp (wargv[4], L"mswdns") == 0)\r
+      prov = &W32_DNS;\r
+    else if (wcscmp (wargv[4], L"gnunetdns") == 0)\r
+      prov = &GNUNET_NAMESPACE_PROVIDER_DNS;\r
+    else\r
+      wargc -= 1;\r
+  }\r
+\r
+  if (wargc == 5)\r
+  {\r
+    HMODULE nsp;\r
+   \r
+    nsp = LoadLibraryW (wargv[3]);\r
+    if (nsp == NULL)\r
+    {\r
+      fprintf (stderr, "Failed to load library `%S'\n", wargv[3]);\r
+    }\r
+    else\r
+    {\r
+      LPNSPSTARTUP startup = (LPNSPSTARTUP) GetProcAddress (nsp, "NSPStartup");\r
+      if (startup != NULL)\r
+      {\r
+        NSP_ROUTINE api;\r
+        ret = startup (prov, &api);\r
+        if (NO_ERROR != ret)\r
+          fprintf (stderr, "startup failed\n");\r
+        else\r
+        {\r
+          HANDLE lookup;\r
+          WSAQUERYSETW search;\r
+          char buf[4096];\r
+          WSAQUERYSETW *result = (WSAQUERYSETW *) buf;\r
+          DWORD resultsize;\r
+          DWORD err;\r
+          memset (&search, 0, sizeof (search));\r
+          search.dwSize = sizeof (search);\r
+          search.lpszServiceInstanceName = (wcscmp (wargv[2], L" ") == 0) ? NULL : wargv[2];\r
+          search.lpServiceClassId = sc;\r
+          search.lpNSProviderId = prov;\r
+          search.dwNameSpace = NS_ALL;\r
+          ret = api.NSPLookupServiceBegin (prov, &search, NULL, LUP_RETURN_ALL, &lookup);\r
+          if (ret != NO_ERROR)\r
+          {\r
+            fprintf (stderr, "lookup start failed\n");\r
+          }\r
+          else\r
+          {\r
+            resultsize = 4096;\r
+            ret = api.NSPLookupServiceNext (lookup, LUP_RETURN_ALL, &resultsize, result);\r
+            err = GetLastError ();\r
+            if (ret != NO_ERROR)\r
+            {\r
+              fprintf (stderr, "lookup next failed\n");\r
+            }\r
+            else\r
+            {\r
+              int i;\r
+              printf ("Got result:\n");\r
+              printf ("  lpszServiceInstanceName: %S\n", result->lpszServiceInstanceName ? result->lpszServiceInstanceName : L"NULL");\r
+              if (result->lpServiceClassId)\r
+                printf ("  lpServiceClassId:        { 0x%08lX,0x%04X,0x%04X, { 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X } }\n",\r
+                    result->lpServiceClassId->Data1, result->lpServiceClassId->Data2, result->lpServiceClassId->Data3, result->lpServiceClassId->Data4[0],\r
+                    result->lpServiceClassId->Data4[1], result->lpServiceClassId->Data4[2], result->lpServiceClassId->Data4[3], result->lpServiceClassId->Data4[4],\r
+                    result->lpServiceClassId->Data4[5], result->lpServiceClassId->Data4[6], result->lpServiceClassId->Data4[7]);\r
+              else\r
+                printf ("  lpServiceClassId:        NULL\n");\r
+              if (result->lpVersion)\r
+                printf ("  lpVersion:               0x%08lX, %d\n", result->lpVersion->dwVersion, result->lpVersion->ecHow);\r
+              else\r
+                printf ("  lpVersion:               NULL\n");\r
+              printf ("  lpszComment:             %S\n", result->lpszComment ? result->lpszComment : L"NULL");\r
+              printf ("  dwNameSpace:             %lu\n", result->dwNameSpace);\r
+              if (result->lpNSProviderId)\r
+                printf ("  lpNSProviderId:          { 0x%08lX,0x%04X,0x%04X, { 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X } }\n",\r
+                    result->lpNSProviderId->Data1, result->lpNSProviderId->Data2, result->lpNSProviderId->Data3, result->lpNSProviderId->Data4[0],\r
+                    result->lpNSProviderId->Data4[1], result->lpNSProviderId->Data4[2], result->lpNSProviderId->Data4[3], result->lpNSProviderId->Data4[4],\r
+                    result->lpNSProviderId->Data4[5], result->lpNSProviderId->Data4[6], result->lpNSProviderId->Data4[7]);\r
+              else\r
+                printf ("  lpNSProviderId:          NULL\n");\r
+              printf ("  lpszContext:             %S\n", result->lpszContext ? result->lpszContext : L"NULL");\r
+              printf ("  dwNumberOfProtocols:     %lu\n", result->dwNumberOfProtocols);\r
+              printf ("  lpszQueryString:         %S\n", result->lpszQueryString ? result->lpszQueryString : L"NULL");\r
+              printf ("  dwNumberOfCsAddrs:       %lu\n", result->dwNumberOfCsAddrs);\r
+              for (i = 0; i < result->dwNumberOfCsAddrs; i++)\r
+              {\r
+                switch (result->lpcsaBuffer[i].iSocketType)\r
+                {\r
+                case SOCK_STREAM:\r
+                  printf ("    %d: iSocketType = SOCK_STREAM\n", i);\r
+                  break;\r
+                case SOCK_DGRAM:\r
+                  printf ("    %d: iSocketType = SOCK_DGRAM\n", i);\r
+                  break;\r
+                default:\r
+                  printf ("    %d: iSocketType = %d\n", i, result->lpcsaBuffer[i].iSocketType);\r
+                }\r
+                switch (result->lpcsaBuffer[i].iProtocol)\r
+                {\r
+                case IPPROTO_TCP:\r
+                  printf ("    %d: iProtocol   = IPPROTO_TCP\n", i);\r
+                  break;\r
+                case IPPROTO_UDP:\r
+                  printf ("    %d: iProtocol   = IPPROTO_UDP\n", i);\r
+                  break;\r
+                default:\r
+                  printf ("    %d: iProtocol   = %d\n", i, result->lpcsaBuffer[i].iProtocol);\r
+                }\r
+                switch (result->lpcsaBuffer[i].LocalAddr.lpSockaddr->sa_family)\r
+                {\r
+                case AF_INET:\r
+                  printf ("    %d: loc family  = AF_INET\n", i);\r
+                  break;\r
+                case AF_INET6:\r
+                  printf ("    %d: loc family  = AF_INET6\n", i);\r
+                  break;\r
+                default:\r
+                  printf ("    %d: loc family  = %hu\n", i, result->lpcsaBuffer[i].LocalAddr.lpSockaddr->sa_family);\r
+                }\r
+                switch (result->lpcsaBuffer[i].RemoteAddr.lpSockaddr->sa_family)\r
+                {\r
+                case AF_INET:\r
+                  printf ("    %d: rem family  = AF_INET\n", i);\r
+                  break;\r
+                case AF_INET6:\r
+                  printf ("    %d: rem family  = AF_INET6\n", i);\r
+                  break;\r
+                default:\r
+                  printf ("    %d: rem family = %hu\n", i, result->lpcsaBuffer[i].RemoteAddr.lpSockaddr->sa_family);\r
+                }\r
+                char buf[1024];\r
+                DWORD buflen = 1024;\r
+                if (NO_ERROR == WSAAddressToStringA (result->lpcsaBuffer[i].LocalAddr.lpSockaddr, result->lpcsaBuffer[i].LocalAddr.iSockaddrLength, NULL, buf, &buflen))\r
+                  printf("\tLocal Address #%d: %s\n", i, buf);\r
+                else\r
+                  printf("\tLocal Address #%d: Can't convert: %lu\n", i, GetLastError ());\r
+                buflen = 1024;\r
+                if (NO_ERROR == WSAAddressToStringA (result->lpcsaBuffer[i].RemoteAddr.lpSockaddr, result->lpcsaBuffer[i].RemoteAddr.iSockaddrLength, NULL, buf, &buflen))\r
+                  printf("\tRemote Address #%d: %s\n", i, buf);\r
+                else\r
+                  printf("\tRemote Address #%d: Can't convert: %lu\n", i, GetLastError ());\r
+              }\r
+              printf ("  dwOutputFlags:           0x%08lX\n", result->dwOutputFlags);\r
+              printf ("  lpBlob:                  0x%p\n", result->lpBlob);\r
+              if (result->lpBlob)\r
+              {\r
+                struct hostent *he = malloc (result->lpBlob->cbSize);\r
+                if (he != NULL)\r
+                {\r
+                  memcpy (he, result->lpBlob->pBlobData, result->lpBlob->cbSize);\r
+                  UnpackHostEnt (he);\r
+                  print_hostent (he);\r
+                  free (he);\r
+                }\r
+              }\r
+            }\r
+            ret = api.NSPLookupServiceEnd (lookup);\r
+            if (ret != NO_ERROR)\r
+              printf ("NSPLookupServiceEnd() failed: %lu\n", GetLastError ());\r
+          }\r
+          api.NSPCleanup (prov);\r
+        }\r
+      }\r
+      FreeLibrary (nsp);\r
+    }\r
+  }\r
+  WSACleanup();\r
+  return r;\r
+}
\ No newline at end of file
diff --git a/src/gns/w32nsp-uninstall.c b/src/gns/w32nsp-uninstall.c
new file mode 100644 (file)
index 0000000..5afc2b1
--- /dev/null
@@ -0,0 +1,30 @@
+#define INITGUID\r
+#include <windows.h>\r
+#include <nspapi.h>\r
+#include <ws2spi.h>\r
+#include <gnunet_w32nsp_lib.h>\r
+#include <stdio.h>\r
+\r
+int\r
+main (int argc, char **argv)\r
+{\r
+  int ret;\r
+  GUID id = GNUNET_NAMESPACE_PROVIDER_DNS;\r
+  WSADATA wsd;\r
+\r
+  if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)\r
+  {\r
+    fprintf (stderr, "WSAStartup() failed: %lu\n", GetLastError());\r
+    return 5;\r
+  }\r
+\r
+  ret = WSCUnInstallNameSpace (&id);\r
+  if (ret == NO_ERROR)\r
+  {\r
+    WSACleanup ();\r
+    return 0;\r
+  }\r
+  fprintf (stderr, "WSCUnInstallNameSpace() failed: %lu\n", GetLastError ());\r
+  WSACleanup ();\r
+  return 1;\r
+}
\ No newline at end of file
diff --git a/src/gns/w32nsp.c b/src/gns/w32nsp.c
new file mode 100644 (file)
index 0000000..b360427
--- /dev/null
@@ -0,0 +1,681 @@
+/* This code is partially based upon samples from the book\r
+ * "Network Programming For Microsoft Windows, 2Nd Edition".\r
+ */\r
+\r
+#define INITGUID\r
+#include <windows.h>\r
+#include <nspapi.h>\r
+#include <stdint.h>\r
+#include <ws2tcpip.h>\r
+#include <ws2spi.h>\r
+\r
+#if 1\r
+#  define DEBUGLOG(s, ...)\r
+#endif\r
+#if 0\r
+#  define DEBUGLOG(s, ...) printf (s, ##__VA_ARGS__)\r
+#endif\r
+\r
+#define WINDOWS 1\r
+#define MINGW 1\r
+#ifndef __BYTE_ORDER
+#ifdef _BYTE_ORDER
+#define __BYTE_ORDER _BYTE_ORDER
+#else
+#ifdef BYTE_ORDER
+#define __BYTE_ORDER BYTE_ORDER
+#endif
+#endif
+#endif
+#ifndef __BIG_ENDIAN
+#ifdef _BIG_ENDIAN
+#define __BIG_ENDIAN _BIG_ENDIAN
+#else
+#ifdef BIG_ENDIAN
+#define __BIG_ENDIAN BIG_ENDIAN
+#endif
+#endif
+#endif
+#ifndef __LITTLE_ENDIAN
+#ifdef _LITTLE_ENDIAN
+#define __LITTLE_ENDIAN _LITTLE_ENDIAN
+#else
+#ifdef LITTLE_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#endif
+#endif
+#endif
+#include <gnunet_w32nsp_lib.h>\r
+#include <w32resolver.h>\r
+\r
+#define NSPAPI_VERSION_MAJOR 4\r
+#define NSPAPI_VERSION_MINOR 4\r
+\r
+#define REPLY_LIFETIME 60*5\r
+\r
+#define STATE_BEGIN  0x01\r
+#define STATE_END    0x02\r
+#define STATE_REPLY  0x04\r
+#define STATE_GHBN   0x08\r
+\r
+uint64_t
+GNUNET_htonll (uint64_t n)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+  return n;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+  return (((uint64_t) htonl (n)) << 32) + htonl (n >> 32);
+#else
+  #error byteorder undefined
+#endif
+}
+\r
+CRITICAL_SECTION records_cs;\r
+\r
+struct record\r
+{\r
+  SOCKET s;\r
+  DWORD flags;\r
+  uint8_t state;\r
+  char *buf;\r
+  wchar_t *name;\r
+};\r
+\r
+static struct record *records = NULL;\r
+static size_t records_len = 0;\r
+static size_t records_size = 0;\r
+\r
+int\r
+resize_records ()\r
+{\r
+  size_t new_size = records_len > 0 ? records_len * 2 : 5;\r
+  struct record *new_records = malloc (new_size * sizeof (struct record));\r
+  if (new_records == NULL)\r
+  {\r
+    SetLastError (WSA_NOT_ENOUGH_MEMORY);\r
+    return 0;\r
+  }\r
+  memcpy (new_records, records, records_len * sizeof (struct record));\r
+  memset (&new_records[records_len], 0, sizeof (struct record) * (new_size - records_len));\r
+  records_size = new_size;\r
+  free (records);\r
+  records = new_records;\r
+  return 1;\r
+}\r
+\r
+int\r
+add_record (SOCKET s, const wchar_t *name, DWORD flags)\r
+{\r
+  int res = 1;\r
+  int i;\r
+  int empty = -1;\r
+  //EnterCriticalSection (&records_cs);\r
+  for (i = 0; i < records_len; i++)\r
+    if (records[i].state == 0)\r
+      break;\r
+  empty = i;\r
+  if (i == records_len)\r
+  {\r
+    res = resize_records ();\r
+    if (res)\r
+      empty = records_len++;\r
+  }\r
+  if (res)\r
+  {\r
+    struct record r;\r
+    r.s = s;\r
+    r.flags = flags;\r
+    r.name = (wchar_t *) name;\r
+    r.state = 1;\r
+    r.buf = NULL;\r
+    if (name)\r
+      r.name = wcsdup (name);\r
+    records[empty] = r;\r
+  }\r
+  //LeaveCriticalSection (&records_cs);\r
+  return res;\r
+}\r
+\r
+void\r
+free_record (int i)\r
+{\r
+  if (records[i].name)\r
+    free (records[i].name);\r
+  records[i].state = 0;\r
+}\r
+\r
+/* These are not defined by mingw.org headers at the moment*/\r
+typedef INT (WSPAPI *LPNSPIOCTL) (HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPWSACOMPLETION,LPWSATHREADID);\r
+typedef struct _NSP_ROUTINE_XP {\r
+  DWORD cbSize;
+  DWORD dwMajorVersion;
+  DWORD dwMinorVersion;
+  LPNSPCLEANUP NSPCleanup;
+  LPNSPLOOKUPSERVICEBEGIN NSPLookupServiceBegin;
+  LPNSPLOOKUPSERVICENEXT NSPLookupServiceNext;
+  LPNSPLOOKUPSERVICEEND NSPLookupServiceEnd;
+  LPNSPSETSERVICE NSPSetService;
+  LPNSPINSTALLSERVICECLASS NSPInstallServiceClass;
+  LPNSPREMOVESERVICECLASS NSPRemoveServiceClass;
+  LPNSPGETSERVICECLASSINFO NSPGetServiceClassInfo;
+  LPNSPIOCTL NSPIoctl;
+} NSP_ROUTINE_XP, *PNSP_ROUTINE_XP, *LPNSP_ROUTINE_XP;
+\r
+static SOCKET\r
+connect_to_dns_resolver ()\r
+{\r
+  struct sockaddr_in addr;\r
+  SOCKET r;\r
+  int ret;\r
+\r
+  r = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
+  if (INVALID_SOCKET == r)\r
+  {\r
+    SetLastError (16004);\r
+    return r;\r
+  }\r
+\r
+  addr.sin_family = AF_INET;\r
+  addr.sin_port = htons (5353); /* TCP 5353 is not registered; UDP 5353 is */\r
+  addr.sin_addr.s_addr = inet_addr ("127.0.0.1");\r
+\r
+  ret = connect (r, (struct sockaddr *) &addr, sizeof (addr));\r
+  if (SOCKET_ERROR == ret)\r
+  {\r
+    DWORD err = GetLastError ();\r
+    closesocket (r);\r
+    SetLastError (err);\r
+    SetLastError (16005);\r
+    r = INVALID_SOCKET;\r
+  }\r
+  return r;\r
+}\r
+\r
+static int\r
+send_name_to_ip_request (LPWSAQUERYSETW lpqsRestrictions,\r
+    LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,\r
+    SOCKET *resolver)\r
+{\r
+  struct GNUNET_W32RESOLVER_GetMessage *msg;
+  int af4 = 0;
+  int af6 = 0;
+  char *buf;\r
+  int ret = 1;\r
+  int i;\r
+  uint32_t id;\r
+  size_t size = sizeof (struct GNUNET_W32RESOLVER_GetMessage);\r
+  size_t namelen = 0;\r
+  if (lpqsRestrictions->lpszServiceInstanceName)\r
+    namelen = sizeof (wchar_t) * (wcslen (lpqsRestrictions->lpszServiceInstanceName) + 1);\r
+  size += namelen;\r
+  buf = malloc (size);\r
+  msg = (struct GNUNET_W32RESOLVER_GetMessage *) buf;\r
+  msg->header.size = htons (size);
+  msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST);
+  if (lpqsRestrictions->dwNumberOfProtocols > 0)
+  {
+    int i;
+    for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
+    {
+      if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
+        af4 = 1;
+      if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
+        af6 = 1;
+    }
+  }
+  if (af4 && !af6)
+    msg->af = htonl (AF_INET);
+  else if (af6 && !af4)
+    msg->af = htonl (AF_INET6);
+  else
+    msg->af = htonl (AF_UNSPEC);
+  if (lpqsRestrictions->lpszServiceInstanceName)
+    memcpy (&msg[1], lpqsRestrictions->lpszServiceInstanceName, namelen);
+  msg->sc_data1 = htonl (lpqsRestrictions->lpServiceClassId->Data1);
+  msg->sc_data2 = htons (lpqsRestrictions->lpServiceClassId->Data2);
+  msg->sc_data3 = htons (lpqsRestrictions->lpServiceClassId->Data3);
+  msg->sc_data4 = 0;
+  for (i = 0; i < 8; i++)
+    msg->sc_data4 |= ((uint64_t) lpqsRestrictions->lpServiceClassId->Data4[i]) << ((7 - i) * 8);
+  msg->sc_data4 = GNUNET_htonll (msg->sc_data4);
+  *resolver = connect_to_dns_resolver ();
+  if (*resolver != INVALID_SOCKET)
+  {
+    if (size != send (*resolver, buf, size, 0))\r
+    {\r
+      DWORD err = GetLastError ();\r
+      closesocket (*resolver);\r
+      *resolver = INVALID_SOCKET;\r
+      DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to send request: %lu\n", err);\r
+      SetLastError (WSATRY_AGAIN);\r
+      ret = 0;\r
+    }\r
+  }\r
+  else\r
+    ret = 0;\r
+  free (buf);\r
+  return ret;\r
+}\r
+\r
+int WSPAPI\r
+NSPCleanup (LPGUID lpProviderId)\r
+{\r
+  DEBUGLOG ("NSPCleanup\n");\r
+  if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))\r
+  {\r
+    return NO_ERROR;\r
+  }\r
+  SetLastError (WSAEINVALIDPROVIDER);\r
+  return SOCKET_ERROR;\r
+}\r
+\r
+BOOL WINAPI\r
+DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)\r
+{\r
+  switch (fdwReason)\r
+  {\r
+    case DLL_PROCESS_ATTACH:\r
+      if (!InitializeCriticalSectionAndSpinCount (&records_cs, 0x00000400))\r
+      {\r
+        return FALSE;\r
+      }\r
+      break;\r
+    case DLL_THREAD_ATTACH:\r
+      break;\r
+    case DLL_THREAD_DETACH:\r
+      break;\r
+    case DLL_PROCESS_DETACH:\r
+      DeleteCriticalSection (&records_cs);\r
+      break;\r
+  }\r
+  return TRUE;\r
+}\r
+\r
+\r
+\r
+\r
+int WSPAPI\r
+GNUNET_W32NSP_LookupServiceBegin (LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,\r
+    LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,\r
+    LPHANDLE lphLookup)\r
+{\r
+  DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin\n");\r
+  if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))\r
+  {\r
+    SOCKET s;\r
+    if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)\r
+    {\r
+      DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");\r
+      SetLastError (WSANO_DATA);\r
+      return SOCKET_ERROR;\r
+    }\r
+    if (lpqsRestrictions->lpszServiceInstanceName != NULL)\r
+    {\r
+      wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;\r
+      size_t len = wcslen (s);\r
+      if (len >= 4 && wcscmp (&s[len - 4], L"zkey") == 0)\r
+      {\r
+      }\r
+      else if (len >= 6 && wcscmp (&s[len - 6], L"gnunet") == 0)\r
+      {\r
+      }\r
+      else\r
+      {\r
+        DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");\r
+        SetLastError (WSANO_DATA);\r
+        return SOCKET_ERROR;\r
+      }\r
+    }\r
+\r
+    if (send_name_to_ip_request (lpqsRestrictions,\r
+        lpServiceClassInfo, dwControlFlags, &s))\r
+    {\r
+      if (!(add_record (s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))\r
+      {\r
+        DWORD err = GetLastError ();\r
+        DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");\r
+        closesocket (s);\r
+        SetLastError (err);\r
+        return SOCKET_ERROR;\r
+      }\r
+      *lphLookup = (HANDLE) s;\r
+      DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError ());\r
+      return NO_ERROR;\r
+    }\r
+    return SOCKET_ERROR;\r
+  }\r
+  DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");\r
+  SetLastError (WSAEINVALIDPROVIDER);\r
+  return SOCKET_ERROR;\r
+}\r
+\r
+#define UnmarshallPtr(ptr, ptrtype, base) \\r
+  if (ptr) \\r
+    ptr = (ptrtype *) (base + (uintptr_t) ptr)\r
+\r
+void\r
+UnmarshallWSAQUERYSETW (LPWSAQUERYSETW req)\r
+{\r
+  int i;\r
+  char *base = (char *) req;\r
+  UnmarshallPtr (req->lpszServiceInstanceName, wchar_t, base);\r
+  UnmarshallPtr (req->lpServiceClassId, GUID, base);\r
+  UnmarshallPtr (req->lpVersion, WSAVERSION, base);\r
+  UnmarshallPtr (req->lpszComment, wchar_t, base);\r
+  UnmarshallPtr (req->lpNSProviderId, GUID, base);\r
+  UnmarshallPtr (req->lpszContext, wchar_t, base);\r
+  UnmarshallPtr (req->lpafpProtocols, AFPROTOCOLS, base);\r
+  UnmarshallPtr (req->lpszQueryString, wchar_t, base);\r
+  UnmarshallPtr (req->lpcsaBuffer, CSADDR_INFO, base);\r
+  for (i = 0; i < req->dwNumberOfCsAddrs; i++)\r
+  {\r
+    UnmarshallPtr (req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);\r
+    UnmarshallPtr (req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);\r
+  }\r
+  UnmarshallPtr (req->lpBlob, BLOB, base);\r
+  if (req->lpBlob)\r
+    UnmarshallPtr (req->lpBlob->pBlobData, BYTE, base);\r
+}\r
+\r
+int WSAAPI\r
+GNUNET_W32NSP_LookupServiceNext (HANDLE hLookup, DWORD dwControlFlags,\r
+    LPDWORD lpdwBufferLength, LPWSAQUERYSET lpqsResults)\r
+{\r
+  DWORD effective_flags;\r
+  int i;\r
+  struct GNUNET_MessageHeader header = {0, 0};
+  int rec = -1;\r
+  int rc;\r
+  int to_receive;\r
+  int t;\r
+  char *buf;\r
+\r
+  DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext\n");\r
+  //EnterCriticalSection (&records_cs);\r
+  for (i = 0; i < records_len; i++)\r
+  {\r
+    if (records[i].s == (SOCKET) hLookup)\r
+    {\r
+      rec = i;\r
+      break;\r
+    }\r
+  }\r
+  if (rec == -1)\r
+  {\r
+    DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");\r
+    SetLastError (WSA_INVALID_HANDLE);\r
+    //LeaveCriticalSection (&records_cs);\r
+    return SOCKET_ERROR;\r
+  }\r
+  if (records[rec].state & 4)\r
+  {\r
+    DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: session is closed\n");\r
+    SetLastError (WSA_E_NO_MORE);\r
+    //LeaveCriticalSection (&records_cs);\r
+    return SOCKET_ERROR;\r
+  }\r
+  effective_flags = dwControlFlags & records[rec].flags;\r
+  if (records[rec].buf)\r
+  {\r
+    header = *((struct GNUNET_MessageHeader *) records[rec].buf);\r
+    if (dwControlFlags & LUP_FLUSHCACHE)\r
+    {\r
+      free (records[rec].buf);\r
+      records[rec].buf = NULL;\r
+    }\r
+    else\r
+    {\r
+      if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))\r
+      {\r
+        DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");\r
+        SetLastError (WSAEFAULT);\r
+        //LeaveCriticalSection (&records_cs);\r
+        return SOCKET_ERROR;\r
+      }\r
+      memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)records[rec].buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));\r
+      free (records[rec].buf);\r
+      records[rec].buf = NULL;\r
+      //LeaveCriticalSection (&records_cs);\r
+      UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);\r
+      DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK (from buffer)\n");\r
+      return NO_ERROR;\r
+    }\r
+  }\r
+  records[rec].state |= 8;\r
+  //LeaveCriticalSection (&records_cs);\r
+  to_receive = sizeof (header);\r
+  rc = 0;\r
+  while (to_receive > 0)\r
+  {\r
+    t = recv ((SOCKET) hLookup, &((char *) &header)[rc], to_receive, 0);\r
+    if (t > 0)\r
+    {\r
+      rc += t;\r
+      to_receive -= t;\r
+    }\r
+    else\r
+      break;\r
+  }\r
+  //EnterCriticalSection (&records_cs);\r
+  records[rec].state &= ~8;\r
+  if (rc != sizeof (header))\r
+  {\r
+    if (records[rec].state & 2)\r
+    {\r
+      DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");\r
+      SetLastError (WSA_E_CANCELLED);\r
+    }\r
+    else\r
+    {\r
+      DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");\r
+      SetLastError (WSA_E_NO_MORE);\r
+    }\r
+    records[rec].state |= 4;\r
+    //LeaveCriticalSection (&records_cs);\r
+    return SOCKET_ERROR;\r
+  }\r
+  records[rec].state &= ~8;\r
+  header.type = ntohs (header.type);\r
+  header.size = ntohs (header.size);\r
+  if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE ||\r
+      (header.type == GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE &&\r
+      header.size == sizeof (header)))\r
+  {\r
+    records[rec].state |= 4;\r
+    DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header is wrong or type is wrong or no data\n");\r
+    //LeaveCriticalSection (&records_cs);\r
+    SetLastError (WSA_E_NO_MORE);\r
+    return SOCKET_ERROR;\r
+  }\r
+  buf = malloc (header.size);\r
+  if (buf == NULL)\r
+  {\r
+    records[rec].state |= 4;\r
+    DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");\r
+    //LeaveCriticalSection (&records_cs);\r
+    SetLastError (WSA_E_NO_MORE);\r
+    return SOCKET_ERROR;\r
+  }\r
+  records[rec].state |= 8;\r
+  //LeaveCriticalSection (&records_cs);\r
+  memcpy (buf, &header, sizeof (header));\r
+  to_receive = header.size - sizeof (header);\r
+  rc = 0;\r
+  while (to_receive > 0)\r
+  {\r
+    t = recv ((SOCKET) hLookup, &((char *) &((struct GNUNET_MessageHeader *) buf)[1])[rc], to_receive, 0);\r
+    if (t > 0)\r
+    {\r
+      rc += t;\r
+      to_receive -= t;\r
+    }\r
+    else\r
+      break;\r
+  }\r
+  //EnterCriticalSection (&records_cs);\r
+  records[rec].state &= ~8;\r
+  if (rc != header.size - sizeof (header))\r
+  {\r
+    free (buf);\r
+    if (records[rec].state & 2)\r
+    {\r
+      DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");\r
+      SetLastError (WSA_E_CANCELLED);\r
+    }\r
+    else\r
+    {\r
+      DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");\r
+      SetLastError (WSA_E_NO_MORE);\r
+    }\r
+    records[rec].state |= 4;\r
+    //LeaveCriticalSection (&records_cs);\r
+    return SOCKET_ERROR;\r
+  }\r
+  if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))\r
+  {\r
+    DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");\r
+    SetLastError (WSAEFAULT);\r
+    records[rec].buf = buf;\r
+    //LeaveCriticalSection (&records_cs);\r
+    return SOCKET_ERROR;\r
+  }\r
+  //LeaveCriticalSection (&records_cs);\r
+  memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));\r
+  free (buf);\r
+  DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK\n");\r
+  UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);\r
+  DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError ());\r
+  return NO_ERROR;\r
+}\r
+\r
+int WSPAPI\r
+GNUNET_W32NSP_LookupServiceEnd (HANDLE hLookup)\r
+{\r
+  DWORD effective_flags;\r
+  int i;\r
+  struct GNUNET_MessageHeader header = {0, 0};
+  int rec = -1;\r
+  int rc;\r
+  char *buf;\r
+\r
+  DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd\n");\r
+  //EnterCriticalSection (&records_cs);\r
+  for (i = 0; i < records_len; i++)\r
+  {\r
+    if (records[i].s == (SOCKET) hLookup)\r
+    {\r
+      rec = i;\r
+      break;\r
+    }\r
+  }\r
+  if (rec == -1)\r
+  {\r
+    SetLastError (WSA_INVALID_HANDLE);\r
+    //LeaveCriticalSection (&records_cs);\r
+    DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");\r
+    return SOCKET_ERROR;\r
+  }\r
+  records[rec].state |= 2;\r
+  closesocket (records[rec].s);\r
+  while (records[rec].state & 8)\r
+  {\r
+    //LeaveCriticalSection (&records_cs);\r
+    Sleep (10);\r
+    //EnterCriticalSection (&records_cs);\r
+  }\r
+  if (records[rec].buf)\r
+    free (records[rec].buf);\r
+  records[rec].buf = NULL;\r
+  records[rec].state = 0;\r
+  if (records[rec].name)\r
+    free (records[rec].name);\r
+  //LeaveCriticalSection (&records_cs);\r
+  DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: OK\n");\r
+  return NO_ERROR;\r
+}\r
+\r
+int WSAAPI\r
+GNUNET_W32NSP_SetService (LPGUID lpProviderId,\r
+    LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,\r
+    WSAESETSERVICEOP essOperation, DWORD dwControlFlags)\r
+{\r
+  DEBUGLOG ("GNUNET_W32NSP_SetService\n");\r
+  SetLastError (WSAEOPNOTSUPP);\r
+  return SOCKET_ERROR;\r
+}\r
+\r
+int WSAAPI\r
+GNUNET_W32NSP_InstallServiceClass (LPGUID lpProviderId,\r
+    LPWSASERVICECLASSINFOW lpServiceClassInfo)\r
+{\r
+  DEBUGLOG ("GNUNET_W32NSP_InstallServiceClass\n");\r
+  SetLastError (WSAEOPNOTSUPP);\r
+  return SOCKET_ERROR;\r
+}\r
+\r
+\r
+int WSAAPI\r
+GNUNET_W32NSP_RemoveServiceClass (LPGUID lpProviderId, LPGUID lpServiceClassId)\r
+{\r
+  DEBUGLOG ("GNUNET_W32NSP_RemoveServiceClass\n");\r
+  SetLastError (WSAEOPNOTSUPP);\r
+  return SOCKET_ERROR;\r
+}\r
+\r
+int WSAAPI\r
+GNUNET_W32NSP_GetServiceClassInfo (LPGUID lpProviderId, LPDWORD lpdwBufSize,\r
+  LPWSASERVICECLASSINFOW lpServiceClassInfo)\r
+{\r
+  DEBUGLOG ("GNUNET_W32NSP_GetServiceClassInfo\n");\r
+  SetLastError (WSAEOPNOTSUPP);\r
+  return SOCKET_ERROR;\r
+}\r
+\r
+int WSAAPI\r
+GNUNET_W32NSP_Ioctl (HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,\r
+    DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,\r
+    LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion,\r
+    LPWSATHREADID lpThreadId)\r
+{\r
+  DEBUGLOG ("GNUNET_W32NSP_Ioctl\n");\r
+  SetLastError (WSAEOPNOTSUPP);\r
+  return SOCKET_ERROR;\r
+}\r
+\r
+/**\r
+ * This function is called by Winsock to hook up our provider.\r
+ * It is the only function that [should be/is] exported by the\r
+ * provider. All other routines are passed as pointers in lpnspRoutines.\r
+ */\r
+int WSPAPI\r
+NSPStartup (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)\r
+{\r
+  if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))\r
+  {\r
+    if (!connect_to_dns_resolver ())\r
+    {\r
+      return SOCKET_ERROR;\r
+    }\r
+    /* This assumes that NSP_ROUTINE struct doesn't have a NSPIoctl member.\r
+     * If it does, you need to use FIELD_OFFSET() macro to get offset of NSPIoctl\r
+     * and use that offset as cbSize.\r
+     */\r
+    lpnspRoutines->cbSize = sizeof(NSP_ROUTINE_XP);\r
+\r
+    lpnspRoutines->dwMajorVersion = NSPAPI_VERSION_MAJOR;\r
+    lpnspRoutines->dwMinorVersion = NSPAPI_VERSION_MINOR;\r
+    lpnspRoutines->NSPCleanup = NSPCleanup;\r
+    lpnspRoutines->NSPLookupServiceBegin = GNUNET_W32NSP_LookupServiceBegin;\r
+    lpnspRoutines->NSPLookupServiceNext = GNUNET_W32NSP_LookupServiceNext;\r
+    lpnspRoutines->NSPLookupServiceEnd = GNUNET_W32NSP_LookupServiceEnd;\r
+    lpnspRoutines->NSPSetService = GNUNET_W32NSP_SetService;\r
+    lpnspRoutines->NSPInstallServiceClass = GNUNET_W32NSP_InstallServiceClass;\r
+    lpnspRoutines->NSPRemoveServiceClass = GNUNET_W32NSP_RemoveServiceClass;\r
+    lpnspRoutines->NSPGetServiceClassInfo = GNUNET_W32NSP_GetServiceClassInfo;\r
+    ((NSP_ROUTINE_XP *) lpnspRoutines)->NSPIoctl = GNUNET_W32NSP_Ioctl;\r
+    return NO_ERROR;\r
+  }\r
+  SetLastError (WSAEINVALIDPROVIDER);\r
+  return SOCKET_ERROR;\r
+}\r
+\r
diff --git a/src/gns/w32resolver.h b/src/gns/w32resolver.h
new file mode 100644 (file)
index 0000000..47078ad
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009, 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
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @author Christian Grothoff
+ * @file gns/w32resolver.h
+ */
+#ifndef W32RESOLVER_H
+#define W32RESOLVER_H
+
+#include "gnunet_common.h"
+
+/**
+ * Request DNS resolution.
+ */
+#define GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST 4
+
+/**
+ * Response to a DNS resolution request.
+ */
+#define GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE 5
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Request for the resolver.  Followed by the 0-terminated hostname.
+ *
+ * The response will be one or more messages of type
+ * W32RESOLVER_RESPONSE, each with the message header immediately
+ * followed by the requested data (struct in[6]_addr).
+ * The last W32RESOLVER_RESPONSE will just be a header without any data
+ * (used to indicate the end of the list).
+ */
+struct GNUNET_W32RESOLVER_GetMessage
+{
+  /**
+   * Type:  GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST
+   */
+  struct GNUNET_MessageHeader header;
+
+  uint32_t af GNUNET_PACKED;
+
+  uint32_t sc_data1 GNUNET_PACKED;
+  uint16_t sc_data2 GNUNET_PACKED;
+  uint16_t sc_data3 GNUNET_PACKED;
+  uint64_t sc_data4 GNUNET_PACKED;
+  /* followed by 0-terminated string for A/AAAA lookup */
+};
+
+GNUNET_NETWORK_STRUCT_END
+
+#endif