-not sure I see how this test can work, disabling for now
[oweals/gnunet.git] / src / gns / gnunet-gns-helper-service-w32.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file gnunet-gns-helper-service-w32.c
22  * @brief an intermediary service to access distributed GNS
23  * @author Christian Grothoff
24  * @author LRN
25  */
26 #define INITGUID
27 #include "platform.h"
28 #include <gnunet_util_lib.h>
29 #include <gnunet_dnsparser_lib.h>
30 #include <gnunet_namestore_service.h>
31 #include <gnunet_gns_service.h>
32 #include "gnunet_w32nsp_lib.h"
33 #include "w32resolver.h"
34 #include <nspapi.h>
35 #include <unistr.h>
36
37 #define DEFINE_DNS_GUID(a,x) DEFINE_GUID(a, 0x00090035, 0x0000, x, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)
38 DEFINE_DNS_GUID(SVCID_DNS_TYPE_A, 0x0001);
39 DEFINE_DNS_GUID(SVCID_DNS_TYPE_NS, 0x0002);
40 DEFINE_DNS_GUID(SVCID_DNS_TYPE_CNAME, 0x0005);
41 DEFINE_DNS_GUID(SVCID_DNS_TYPE_SOA, 0x0006);
42 DEFINE_DNS_GUID(SVCID_DNS_TYPE_PTR, 0x000c);
43 DEFINE_DNS_GUID(SVCID_DNS_TYPE_MX, 0x000f);
44 DEFINE_DNS_GUID(SVCID_DNS_TYPE_TEXT, 0x0010);
45 DEFINE_DNS_GUID(SVCID_DNS_TYPE_AAAA, 0x001c);
46 DEFINE_DNS_GUID(SVCID_DNS_TYPE_SRV, 0x0021);
47 DEFINE_GUID(SVCID_HOSTNAME, 0x0002a800, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
48 DEFINE_GUID(SVCID_INET_HOSTADDRBYNAME, 0x0002a803, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
49
50 struct request
51 {
52   struct GNUNET_SERVER_Client *client;
53   GUID sc;
54   int af;
55   wchar_t *name;
56   char *u8name;
57 };
58
59 /**
60  * Handle to GNS service.
61  */
62 static struct GNUNET_GNS_Handle *gns;
63
64 static struct GNUNET_CRYPTO_EccPublicSignKey *zone = NULL;
65 static struct GNUNET_HashCode user_zone;
66 struct GNUNET_CRYPTO_EccPrivateKey *shorten_key = NULL;
67
68
69 /**
70  * Task run on shutdown.  Cleans up everything.
71  *
72  * @param cls unused
73  * @param tc scheduler context
74  */
75 static void
76 do_shutdown (void *cls,
77              const struct GNUNET_SCHEDULER_TaskContext *tc)
78 {
79   if (NULL != gns)
80   {
81     GNUNET_GNS_disconnect (gns);
82     gns = NULL;
83   }
84 }
85
86 /**
87  * Context for transmitting replies to clients.
88  */
89 struct TransmitCallbackContext
90 {
91
92   /**
93    * We keep these in a doubly-linked list (for cleanup).
94    */
95   struct TransmitCallbackContext *next;
96
97   /**
98    * We keep these in a doubly-linked list (for cleanup).
99    */
100   struct TransmitCallbackContext *prev;
101
102   /**
103    * The message that we're asked to transmit.
104    */
105   struct GNUNET_MessageHeader *msg;
106
107   /**
108    * Handle for the transmission request.
109    */
110   struct GNUNET_SERVER_TransmitHandle *th;
111
112 };
113
114
115 /**
116  * Head of the doubly-linked list (for cleanup).
117  */
118 static struct TransmitCallbackContext *tcc_head;
119
120 /**
121  * Tail of the doubly-linked list (for cleanup).
122  */
123 static struct TransmitCallbackContext *tcc_tail;
124
125 /**
126  * Have we already cleaned up the TCCs and are hence no longer
127  * willing (or able) to transmit anything to anyone?
128  */
129 static int cleaning_done;
130
131
132 /**
133  * Function called to notify a client about the socket
134  * begin ready to queue more data.  "buf" will be
135  * NULL and "size" zero if the socket was closed for
136  * writing in the meantime.
137  *
138  * @param cls closure
139  * @param size number of bytes available in buf
140  * @param buf where the callee should write the message
141  * @return number of bytes written to buf
142  */
143 static size_t
144 transmit_callback (void *cls, size_t size, void *buf)
145 {
146   struct TransmitCallbackContext *tcc = cls;
147   size_t msize;
148
149   tcc->th = NULL;
150   GNUNET_CONTAINER_DLL_remove (tcc_head, tcc_tail, tcc);
151   msize = ntohs (tcc->msg->size);
152   if (size == 0)
153   {
154     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
155                 _("Transmission to client failed!\n"));
156     GNUNET_free (tcc->msg);
157     GNUNET_free (tcc);
158     return 0;
159   }
160   GNUNET_assert (size >= msize);
161   memcpy (buf, tcc->msg, msize);
162   GNUNET_free (tcc->msg);
163   GNUNET_free (tcc);
164   return msize;
165 }
166
167
168 /**
169  * Transmit the given message to the client.
170  *
171  * @param client target of the message
172  * @param msg message to transmit, will be freed!
173  */
174 static void
175 transmit (struct GNUNET_SERVER_Client *client, 
176           struct GNUNET_MessageHeader *msg)
177 {
178   struct TransmitCallbackContext *tcc;
179
180   if (GNUNET_YES == cleaning_done)
181   {
182     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
183                 _("Shutdown in progress, aborting transmission.\n"));
184     GNUNET_free (msg);
185     return;
186   }
187   tcc = GNUNET_malloc (sizeof (struct TransmitCallbackContext));
188   tcc->msg = msg;
189   if (NULL ==
190       (tcc->th =
191        GNUNET_SERVER_notify_transmit_ready (client, 
192                                             ntohs (msg->size),
193                                             GNUNET_TIME_UNIT_FOREVER_REL,
194                                             &transmit_callback, tcc)))
195   {
196     GNUNET_break (0);
197     GNUNET_free (msg);
198     GNUNET_free (tcc);
199     return;
200   }
201   GNUNET_CONTAINER_DLL_insert (tcc_head, tcc_tail, tcc);
202 }
203
204
205 #define MarshallPtr(ptr, base, type) \
206   if (ptr) \
207     ptr = (type *) ((char *) ptr - (char *) base)
208
209
210 void
211 MarshallWSAQUERYSETW (WSAQUERYSETW *qs, GUID *sc)
212 {
213   int i;
214   MarshallPtr (qs->lpszServiceInstanceName, qs, wchar_t);
215   MarshallPtr (qs->lpServiceClassId, qs, GUID);
216   MarshallPtr (qs->lpVersion, qs, WSAVERSION);
217   MarshallPtr (qs->lpNSProviderId, qs, GUID);
218   MarshallPtr (qs->lpszContext, qs, wchar_t);
219   MarshallPtr (qs->lpafpProtocols, qs, AFPROTOCOLS);
220   MarshallPtr (qs->lpszQueryString, qs, wchar_t);
221   for (i = 0; i < qs->dwNumberOfCsAddrs; i++)
222   {
223     MarshallPtr (qs->lpcsaBuffer[i].LocalAddr.lpSockaddr, qs, SOCKADDR);
224     MarshallPtr (qs->lpcsaBuffer[i].RemoteAddr.lpSockaddr, qs, SOCKADDR);
225   }
226   MarshallPtr (qs->lpcsaBuffer, qs, CSADDR_INFO);
227   if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, sc) && qs->lpBlob != NULL && qs->lpBlob->pBlobData != NULL)
228   {
229     struct hostent *he;
230     he = (struct hostent *) qs->lpBlob->pBlobData;
231     for (i = 0; he->h_aliases[i] != NULL; i++)
232       MarshallPtr (he->h_aliases[i], he, char);
233     MarshallPtr (he->h_aliases, he, char *);
234     MarshallPtr (he->h_name, he, char);
235     for (i = 0; he->h_addr_list[i] != NULL; i++)
236       MarshallPtr (he->h_addr_list[i], he, void);
237     MarshallPtr (he->h_addr_list, he, char *);
238     MarshallPtr (qs->lpBlob->pBlobData, qs, void);
239   }
240   MarshallPtr (qs->lpBlob, qs, BLOB);
241 }
242
243
244 static void
245 process_ip_lookup_result (void* cls, 
246                           uint32_t rd_count,
247                           const struct GNUNET_NAMESTORE_RecordData *rd)
248 {
249   int i, j, csanum;
250   struct request *rq = (struct request *) cls;
251   struct GNUNET_W32RESOLVER_GetMessage *msg;
252   struct GNUNET_MessageHeader *msgend;
253   WSAQUERYSETW *qs;
254   size_t size;
255   size_t size_recalc;
256   char *ptr;
257   size_t blobsize = 0;
258   size_t blobaddrcount = 0;
259
260   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261               "Got lookup result with count %u for rq %p with client %p\n",
262               rd_count, rq, rq->client);
263
264   if (rd_count == 0)
265   {
266     size = sizeof (struct GNUNET_MessageHeader);
267     msg = GNUNET_malloc (size);
268     msg->header.size = htons (size);
269     msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
270     transmit (rq->client, &msg->header);
271     return;
272   }
273
274   size = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW);
275   size += (wcslen (rq->name) + 1) * sizeof (wchar_t);
276   size += sizeof (GUID);
277   /* lpszComment ? a TXT record? */
278   size += sizeof (GUID);
279   /* lpszContext ? Not sure what it is */
280   csanum = 0;
281   for (i = 0; i < rd_count; i++)
282   {
283     switch (rd[i].record_type)
284     {
285     case GNUNET_DNSPARSER_TYPE_A:
286       if (rd[i].data_size != sizeof (struct in_addr))
287         continue;
288       size += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in) * 2;
289       csanum++;
290       break;
291     case GNUNET_DNSPARSER_TYPE_AAAA:
292       if (rd[i].data_size != sizeof (struct in6_addr))
293         continue;
294       size += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in6) * 2;
295       csanum++;
296       break;
297     }
298   }
299   if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &rq->sc))
300   {
301     size += sizeof (BLOB);
302     blobsize += sizeof (struct hostent);
303     blobsize += strlen (rq->u8name) + 1;
304     blobsize += sizeof (void *); /* For aliases */
305     blobsize += sizeof (void *); /* For addresses */
306     for (i = 0; i < rd_count; i++)
307     {
308       if ((rq->af == AF_INET || rq->af == AF_UNSPEC) && rd[i].record_type == GNUNET_DNSPARSER_TYPE_A)
309       {
310         blobsize += sizeof (void *);
311         blobsize += sizeof (struct in_addr);
312         blobaddrcount++;
313       }
314       else if (rq->af == AF_INET6 && rd[i].record_type == GNUNET_DNSPARSER_TYPE_AAAA)
315       {
316         blobsize += sizeof (void *);
317         blobsize += sizeof (struct in6_addr);
318         blobaddrcount++;
319       }
320     }
321     size += blobsize;
322   }
323   size += sizeof (struct GNUNET_MessageHeader);
324   size_recalc = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW);
325   msg = GNUNET_malloc (size);
326   msg->header.size = htons (size - sizeof (struct GNUNET_MessageHeader));
327   msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
328   msg->af = htonl (rq->af);
329   msg->sc_data1 = htonl (rq->sc.Data1);
330   msg->sc_data2 = htons (rq->sc.Data2);
331   msg->sc_data3 = htons (rq->sc.Data3);
332   msg->sc_data4 = 0;
333   for (i = 0; i < 8; i++)
334     msg->sc_data4 |= rq->sc.Data4[i] << ((7 - i) * 8);
335   msg->sc_data4 = GNUNET_htonll (msg->sc_data4);
336   qs = (WSAQUERYSETW *) &msg[1];
337   ptr = (char *) &qs[1];
338   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
339   qs->dwSize = sizeof (WSAQUERYSETW);
340   qs->lpszServiceInstanceName = (wchar_t *) ptr;
341   ptr += (wcslen (rq->name) + 1) * sizeof (wchar_t);
342   size_recalc += (wcslen (rq->name) + 1) * sizeof (wchar_t);
343   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
344   wcscpy (qs->lpszServiceInstanceName, rq->name);
345   qs->lpServiceClassId = (GUID *) ptr;
346   ptr += sizeof (GUID);
347   size_recalc += sizeof (GUID);
348   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
349   memcpy (qs->lpServiceClassId, &rq->sc, sizeof (GUID));
350   qs->lpVersion = NULL;
351   qs->dwNameSpace = NS_DNS;
352   qs->lpNSProviderId = (GUID *) ptr;
353   ptr += sizeof (GUID);
354   size_recalc += sizeof (GUID);
355   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
356   memcpy (qs->lpNSProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS, sizeof (GUID));
357   qs->lpszContext = NULL;
358   qs->dwNumberOfProtocols = 0;
359   qs->lpafpProtocols = NULL;
360   /* Don't bother with this... */
361   qs->lpszQueryString = NULL;
362   qs->dwNumberOfCsAddrs = rd_count;
363   qs->lpcsaBuffer = (CSADDR_INFO *) ptr;
364   ptr += sizeof (CSADDR_INFO) * csanum;
365   j = 0;
366   for (i = 0; i < rd_count; i++)
367   {
368     switch (rd[i].record_type)
369     {
370     case GNUNET_DNSPARSER_TYPE_A:
371       if (rd[i].data_size != sizeof (struct in_addr))
372         continue;
373       qs->lpcsaBuffer[j].iSocketType = SOCK_STREAM;
374       qs->lpcsaBuffer[j].iProtocol = IPPROTO_TCP;
375
376       qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength = sizeof (struct sockaddr_in);
377       qs->lpcsaBuffer[j].LocalAddr.lpSockaddr = (SOCKADDR *) ptr;
378       ptr += qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength;
379       memset (qs->lpcsaBuffer[j].LocalAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength);
380       ((struct sockaddr_in *)qs->lpcsaBuffer[j].LocalAddr.lpSockaddr)->sin_family = AF_INET;
381
382       qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength = sizeof (struct sockaddr_in);
383       qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr = (SOCKADDR *) ptr;
384       ptr += qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength;
385       memset (qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength);
386       ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_family = AF_INET;
387       ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_port = htonl (53); /* Don't ask why it's 53 */
388       ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_addr = *(struct in_addr *) rd[i].data;
389       size_recalc += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in) * 2;
390       j++;
391       break;
392     case GNUNET_DNSPARSER_TYPE_AAAA:
393       if (rd[i].data_size != sizeof (struct in6_addr))
394         continue;
395       qs->lpcsaBuffer[j].iSocketType = SOCK_STREAM;
396       qs->lpcsaBuffer[j].iProtocol = IPPROTO_TCP;
397
398       qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength = sizeof (struct sockaddr_in6);
399       qs->lpcsaBuffer[j].LocalAddr.lpSockaddr = (SOCKADDR *) ptr;
400       ptr += qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength;
401       memset (qs->lpcsaBuffer[j].LocalAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength);
402       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].LocalAddr.lpSockaddr)->sin6_family = AF_INET6;
403
404       qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength = sizeof (struct sockaddr_in6);
405       qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr = (SOCKADDR *) ptr;
406       ptr += qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength;
407       memset (qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength);
408       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_family = AF_INET6;
409       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_port = htonl (53); /* Don't ask why it's 53 */
410       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_addr = *(struct in6_addr *) rd[i].data;
411       size_recalc += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in6) * 2;
412       j++;
413       break;
414     default:
415       break;
416     }
417   }
418   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
419   qs->dwOutputFlags = 0;
420   if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &rq->sc))
421   {
422     struct hostent *he;
423     qs->lpBlob = (BLOB *) ptr;
424     ptr += sizeof (BLOB);
425
426     size_recalc += sizeof (BLOB);
427     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
428
429     qs->lpBlob->cbSize = blobsize;
430     qs->lpBlob->pBlobData = (BYTE *) ptr;
431     ptr += sizeof (struct hostent);
432
433     size_recalc += sizeof (struct hostent);
434     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
435
436     he = (struct hostent *) qs->lpBlob->pBlobData;
437     he->h_name = (char *) ptr;
438     ptr += strlen (rq->u8name) + 1;
439
440     size_recalc += strlen (rq->u8name) + 1;
441     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
442
443     strcpy (he->h_name, rq->u8name);
444     he->h_aliases = (char **) ptr;
445     ptr += sizeof (void *);
446
447     size_recalc += sizeof (void *); /* For aliases */
448     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
449
450     he->h_aliases[0] = NULL;
451     he->h_addrtype = rq->af;
452     he->h_length = rq->af == AF_INET || rq->af == AF_UNSPEC ? sizeof (struct in_addr) : sizeof (struct in6_addr);
453     he->h_addr_list = (char **) ptr;
454     ptr += sizeof (void *) * (blobaddrcount + 1);
455
456     size_recalc += sizeof (void *) * (blobaddrcount + 1); /* For addresses */
457     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
458
459     j = 0;
460     for (i = 0; i < rd_count; i++)
461     {
462       if ((rq->af == AF_INET || rq->af == AF_UNSPEC) &&
463           rd[i].record_type == GNUNET_DNSPARSER_TYPE_A)
464       {
465         he->h_addr_list[j] = (char *) ptr;
466         ptr += sizeof (struct in_addr);
467
468         size_recalc += sizeof (struct in_addr);
469         GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
470
471         memcpy (he->h_addr_list[j], rd[i].data, sizeof (struct in_addr));
472         j++;
473       }
474       else if (rq->af == AF_INET6 && rd[i].record_type == GNUNET_DNSPARSER_TYPE_AAAA)
475       {
476         he->h_addr_list[j] = (char *) ptr;
477         ptr += sizeof (struct in6_addr);
478
479         size_recalc += sizeof (struct in6_addr);
480         GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
481
482         memcpy (he->h_addr_list[j], rd[i].data, sizeof (struct in6_addr));
483         j++;
484       }
485     }
486     he->h_addr_list[j] = NULL;
487   }
488   msgend = (struct GNUNET_MessageHeader *) ptr;
489   ptr += sizeof (struct GNUNET_MessageHeader);
490   size_recalc += sizeof (struct GNUNET_MessageHeader);
491
492   msgend->type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
493   msgend->size = htons (sizeof (struct GNUNET_MessageHeader));
494
495   if ((char *) ptr - (char *) msg != size || size_recalc != size || size_recalc != ((char *) ptr - (char *) msg))
496   {
497     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);
498   }
499   MarshallWSAQUERYSETW (qs, &rq->sc);
500   transmit (rq->client, &msg->header);
501 }
502
503
504 static void
505 get_ip_from_hostname (struct GNUNET_SERVER_Client *client,
506     const wchar_t *name, int af, GUID sc)
507 {
508   struct request *rq;
509   char *hostname;
510   size_t strl;
511   size_t namelen;
512   uint32_t rtype;
513
514   if (IsEqualGUID (&SVCID_DNS_TYPE_A, &sc))
515     rtype = GNUNET_DNSPARSER_TYPE_A;
516   else if (IsEqualGUID (&SVCID_DNS_TYPE_NS, &sc))
517     rtype = GNUNET_DNSPARSER_TYPE_NS;
518   else if (IsEqualGUID (&SVCID_DNS_TYPE_CNAME, &sc))
519     rtype = GNUNET_DNSPARSER_TYPE_CNAME;
520   else if (IsEqualGUID (&SVCID_DNS_TYPE_SOA, &sc))
521     rtype = GNUNET_DNSPARSER_TYPE_SOA;
522   else if (IsEqualGUID (&SVCID_DNS_TYPE_PTR, &sc))
523     rtype = GNUNET_DNSPARSER_TYPE_PTR;
524   else if (IsEqualGUID (&SVCID_DNS_TYPE_MX, &sc))
525     rtype = GNUNET_DNSPARSER_TYPE_MX;
526   else if (IsEqualGUID (&SVCID_DNS_TYPE_TEXT, &sc))
527     rtype = GNUNET_DNSPARSER_TYPE_TXT;
528   else if (IsEqualGUID (&SVCID_DNS_TYPE_AAAA, &sc))
529     rtype = GNUNET_DNSPARSER_TYPE_AAAA;
530   else if (IsEqualGUID (&SVCID_DNS_TYPE_SRV, &sc))
531     rtype = GNUNET_DNSPARSER_TYPE_SRV;
532   else if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &sc))
533     rtype = GNUNET_DNSPARSER_TYPE_A;
534   else
535   {
536     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537                 "Unknown GUID: %08X-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
538                 sc.Data1, sc.Data2, sc.Data3, sc.Data4[0], sc.Data4[1], sc.Data4[2],
539                 sc.Data4[3], sc.Data4[4], sc.Data4[5], sc.Data4[6], sc.Data4[7]);
540     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
541     return;
542   }
543
544   if (name)
545     namelen = wcslen (name);
546   else
547     namelen = 0;
548   if (namelen > 0)
549     hostname = (char *) u16_to_u8 (name, namelen + 1, NULL, &strl);
550   
551   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552               "W32 DNS resolver asked to look up %s for `%s'.\n",
553               af == AF_INET ? "IPv4" : af == AF_INET6 ? "IPv6" : "anything",
554               hostname);
555   rq = GNUNET_malloc (sizeof (struct request));
556   rq->sc = sc;
557   rq->client = client;
558   rq->af = af;
559   if (rq->af != AF_INET && rq->af != AF_INET6)
560     rq->af = AF_INET;
561   if (namelen)
562   {
563     rq->name = GNUNET_malloc ((namelen + 1) * sizeof (wchar_t));
564     memcpy (rq->name, name, (namelen + 1) * sizeof (wchar_t));
565     rq->u8name = hostname;
566   }
567
568   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
569               "Launching a lookup for client %p with rq %p\n",
570               client, rq);
571
572   if (NULL != GNUNET_GNS_lookup (gns, hostname, zone, rtype,
573       GNUNET_YES, shorten_key, &process_ip_lookup_result, rq))
574   {
575     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576                 "Lookup launched, waiting for a reply\n");
577     GNUNET_SERVER_receive_done (client, GNUNET_OK);
578   }
579   else
580   {
581     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
582                 "Lookup was not, disconnecting the client\n");
583     if (namelen)
584     {
585       GNUNET_free (rq->name);
586       free (rq->u8name);
587     }
588     GNUNET_free (rq);
589     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
590   }
591 }
592
593
594 /**
595  * Handle GET-message.
596  *
597  * @param cls closure
598  * @param client identification of the client
599  * @param message the actual message
600  */
601 static void
602 handle_get (void *cls, struct GNUNET_SERVER_Client *client,
603             const struct GNUNET_MessageHeader *message)
604 {
605   uint16_t msize;
606   const struct GNUNET_W32RESOLVER_GetMessage *msg;
607   GUID sc;
608   uint16_t size;
609   uint64_t data4;
610   int i;
611   const wchar_t *hostname;
612   int af;
613
614   msize = ntohs (message->size);
615   if (msize < sizeof (struct GNUNET_W32RESOLVER_GetMessage))
616   {
617     GNUNET_break (0);
618     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
619     return;
620   }
621   msg = (const struct GNUNET_W32RESOLVER_GetMessage *) message;
622   size = msize - sizeof (struct GNUNET_W32RESOLVER_GetMessage);
623   af = ntohl (msg->af);
624   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got NBO GUID: %08X-%04X-%04X-%016llX\n",
625       msg->sc_data1, msg->sc_data2, msg->sc_data3, msg->sc_data4);
626   sc.Data1 = ntohl (msg->sc_data1);
627   sc.Data2 = ntohs (msg->sc_data2);
628   sc.Data3 = ntohs (msg->sc_data3);
629   data4 = GNUNET_ntohll (msg->sc_data4);
630   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got GUID: %08X-%04X-%04X-%016llX\n",
631       sc.Data1, sc.Data2, sc.Data3, data4);
632   for (i = 0; i < 8; i++)
633     sc.Data4[i] = 0xFF & (data4 >> ((7 - i) * 8));
634   
635   hostname = (const wchar_t *) &msg[1];
636   if (hostname[size - 1] != L'\0')
637   {
638     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "name of length %u, not 0-terminated: %*S\n",
639         size, size, hostname);
640     GNUNET_break (0);
641     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
642     return;
643   }
644   get_ip_from_hostname (client, hostname, af, sc);
645 }
646
647
648 /**
649  * Start up gns-helper-w32 service.
650  *
651  * @param cls closure
652  * @param server the initialized server
653  * @param cfg configuration to use
654  */
655 static void
656 run (void *cls, struct GNUNET_SERVER_Handle *server,
657      const struct GNUNET_CONFIGURATION_Handle *cfg)
658 {
659   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
660     {&handle_get, NULL, GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST, 0},
661     {NULL, NULL, 0, 0}
662   };
663
664   char* keyfile;
665   struct GNUNET_CRYPTO_EccPrivateKey *key = NULL;
666   struct GNUNET_CRYPTO_EccPublicSignKey pkey;
667   struct GNUNET_CRYPTO_HashAsciiEncoded zonename;
668
669   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
670                                                            "ZONEKEY", &keyfile))
671   {
672     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
673                 "No private key for root zone found, using default!\n");
674     zone = NULL;
675   }
676   else
677   {
678     if (GNUNET_YES == GNUNET_DISK_file_test (keyfile))
679     {
680       key = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
681       GNUNET_CRYPTO_ecc_key_get_public_for_signature (key, &pkey);
682       GNUNET_CRYPTO_hash (&pkey, sizeof(struct GNUNET_CRYPTO_EccPublicSignKey),
683                           &user_zone);
684       GNUNET_CRYPTO_hash_to_enc (&user_zone, &zonename);
685       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686                   "Using zone: %s!\n", &zonename);
687       GNUNET_free(key);
688     }
689     GNUNET_free(keyfile);
690   }
691
692   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
693                                                    "SHORTEN_ZONEKEY", &keyfile))
694   {
695     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
696                 "No shorten key found!\n");
697     shorten_key = NULL;
698   }
699   else
700   {
701     if (GNUNET_YES == GNUNET_DISK_file_test (keyfile))
702     {
703       shorten_key = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
704     }
705     GNUNET_free(keyfile);
706   }
707
708   gns = GNUNET_GNS_connect (cfg);
709   if (gns == NULL)
710     return;
711
712   GNUNET_SERVER_add_handlers (server, handlers);
713   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_shutdown,
714                                 NULL);
715
716 }
717
718
719 /**
720  * The main function for gns-helper-w32.
721  *
722  * @param argc number of arguments from the command line
723  * @param argv command line arguments
724  * @return 0 ok, 1 on error
725  */
726 int
727 main (int argc, char *const *argv)
728 {
729   int ret;
730
731   ret =
732       (GNUNET_OK ==
733        GNUNET_SERVICE_run (argc, argv, "gns-helper-service-w32", GNUNET_SERVICE_OPTION_NONE,
734                            &run, NULL)) ? 0 : 1;
735
736   return ret;
737 }
738
739 /* end of gnunet-gns-helper-service-w32.c */