33de2aab6e69cd1129b6978bb7ae726554d35701
[oweals/gnunet.git] / src / gns / gnunet-gns-helper-service-w32.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2017 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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 #include "platform.h"
27 #include <gnunet_util_lib.h>
28 #include <gnunet_identity_service.h>
29 #include <gnunet_dnsparser_lib.h>
30 #include <gnunet_namestore_service.h>
31 #include <gnunet_gns_service.h>
32 #include <initguid.h>
33 #include "gnunet_w32nsp_lib.h"
34 #include "w32resolver.h"
35 #include <nspapi.h>
36 #include <unistr.h>
37
38 #define DEFINE_DNS_GUID(a,x) DEFINE_GUID(a, 0x00090035, 0x0000, x, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)
39 DEFINE_DNS_GUID(SVCID_DNS_TYPE_A, 0x0001);
40 DEFINE_DNS_GUID(SVCID_DNS_TYPE_NS, 0x0002);
41 DEFINE_DNS_GUID(SVCID_DNS_TYPE_CNAME, 0x0005);
42 DEFINE_DNS_GUID(SVCID_DNS_TYPE_SOA, 0x0006);
43 DEFINE_DNS_GUID(SVCID_DNS_TYPE_PTR, 0x000c);
44 DEFINE_DNS_GUID(SVCID_DNS_TYPE_MX, 0x000f);
45 DEFINE_DNS_GUID(SVCID_DNS_TYPE_TEXT, 0x0010);
46 DEFINE_DNS_GUID(SVCID_DNS_TYPE_AAAA, 0x001c);
47 DEFINE_DNS_GUID(SVCID_DNS_TYPE_SRV, 0x0021);
48 DEFINE_GUID(SVCID_HOSTNAME, 0x0002a800, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
49 DEFINE_GUID(SVCID_INET_HOSTADDRBYNAME, 0x0002a803, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
50
51
52 struct request
53 {
54   /**
55    * We keep these in a doubly-linked list (for cleanup).
56    */
57   struct request *next;
58
59   /**
60    * We keep these in a doubly-linked list (for cleanup).
61    */
62   struct request *prev;
63
64   /**
65    * Client that issued the request
66    */
67   struct GNUNET_SERVICE_Client *client;
68
69   GUID sc;
70
71   int af;
72
73   wchar_t *name;
74
75   char *u8name;
76
77   struct GNUNET_GNS_LookupRequest *lookup_request;
78 };
79
80
81 /**
82  * Head of the doubly-linked list (for cleanup).
83  */
84 static struct request *rq_head;
85
86 /**
87  * Tail of the doubly-linked list (for cleanup).
88  */
89 static struct request *rq_tail;
90
91 /**
92  * Handle to GNS service.
93  */
94 static struct GNUNET_GNS_Handle *gns;
95
96 /**
97  * Active operation on identity service.
98  */
99 static struct GNUNET_IDENTITY_Operation *id_op;
100
101 /**
102  * Handle for identity service.
103  */
104 static struct GNUNET_IDENTITY_Handle *identity;
105
106 /**
107  * Public key of the gns-master ego
108  */
109 static struct GNUNET_CRYPTO_EcdsaPublicKey gns_master_pubkey;
110
111 /**
112  * Set to 1 once egos are obtained.
113  */
114 static int got_egos;
115
116
117 /**
118  * Task run on shutdown.  Cleans up everything.
119  *
120  * @param cls unused
121  */
122 static void
123 do_shutdown (void *cls)
124 {
125   struct request *rq;
126
127   if (NULL != id_op)
128   {
129     GNUNET_IDENTITY_cancel (id_op);
130     id_op = NULL;
131   }
132   if (NULL != identity)
133   {
134     GNUNET_IDENTITY_disconnect (identity);
135     identity = NULL;
136   }
137   while (NULL != (rq = rq_head))
138   {
139     if (NULL != rq->lookup_request)
140       GNUNET_GNS_lookup_cancel (rq->lookup_request);
141     GNUNET_CONTAINER_DLL_remove (rq_head,
142                                  rq_tail,
143                                  rq);
144     GNUNET_free_non_null (rq->name);
145     if (rq->u8name)
146       free (rq->u8name);
147     GNUNET_free (rq);
148   }
149   if (NULL != gns)
150   {
151     GNUNET_GNS_disconnect (gns);
152     gns = NULL;
153   }
154 }
155
156
157 /**
158  * Transmit the given message to the client.
159  *
160  * @param client target of the message
161  * @param msg message to transmit, will be freed!
162  */
163 static void
164 transmit (struct GNUNET_SERVICE_Client *client,
165           struct GNUNET_MessageHeader *msg)
166 {
167   struct GNUNET_MQ_Handle *mq = GNUNET_SERVICE_client_get_mq (client);
168   struct GNUNET_MQ_Envelope *env;
169
170   /* NOTE: small hack here, should have constructed and
171      passed an 'env' in the first place... */
172   env = GNUNET_MQ_msg_copy (msg);
173   GNUNET_MQ_send (mq,
174                   env);
175 }
176
177
178 #define MarshallPtr(ptr, base, type) \
179   if (ptr) \
180     ptr = (type *) ((char *) ptr - (char *) base)
181
182
183 void
184 MarshallWSAQUERYSETW (WSAQUERYSETW *qs, GUID *sc)
185 {
186   MarshallPtr (qs->lpszServiceInstanceName, qs, wchar_t);
187   MarshallPtr (qs->lpServiceClassId, qs, GUID);
188   MarshallPtr (qs->lpVersion, qs, WSAVERSION);
189   MarshallPtr (qs->lpNSProviderId, qs, GUID);
190   MarshallPtr (qs->lpszContext, qs, wchar_t);
191   MarshallPtr (qs->lpafpProtocols, qs, AFPROTOCOLS);
192   MarshallPtr (qs->lpszQueryString, qs, wchar_t);
193   for (int i = 0; i < qs->dwNumberOfCsAddrs; i++)
194   {
195     MarshallPtr (qs->lpcsaBuffer[i].LocalAddr.lpSockaddr, qs, SOCKADDR);
196     MarshallPtr (qs->lpcsaBuffer[i].RemoteAddr.lpSockaddr, qs, SOCKADDR);
197   }
198   MarshallPtr (qs->lpcsaBuffer, qs, CSADDR_INFO);
199   if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, sc) && qs->lpBlob != NULL && qs->lpBlob->pBlobData != NULL)
200   {
201     struct hostent *he;
202
203     he = (struct hostent *) qs->lpBlob->pBlobData;
204     for (int i = 0; he->h_aliases[i] != NULL; i++)
205       MarshallPtr (he->h_aliases[i], he, char);
206     MarshallPtr (he->h_aliases, he, char *);
207     MarshallPtr (he->h_name, he, char);
208     for (int i = 0; he->h_addr_list[i] != NULL; i++)
209       MarshallPtr (he->h_addr_list[i], he, void);
210     MarshallPtr (he->h_addr_list, he, char *);
211     MarshallPtr (qs->lpBlob->pBlobData, qs, void);
212   }
213   MarshallPtr (qs->lpBlob, qs, BLOB);
214 }
215
216
217 static void
218 process_lookup_result (void *cls,
219                        uint32_t rd_count,
220                        const struct GNUNET_GNSRECORD_Data *rd)
221 {
222   struct request *rq = cls;
223   int i, j, csanum;
224   struct GNUNET_W32RESOLVER_GetMessage *msg;
225   struct GNUNET_MessageHeader *msgend;
226   WSAQUERYSETW *qs;
227   size_t size;
228   size_t size_recalc;
229   char *ptr;
230   size_t blobsize = 0;
231   size_t blobaddrcount = 0;
232
233   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234               "Got lookup result with count %u for rq %p with client %p\n",
235               rd_count,
236               rq,
237               rq->client);
238   rq->lookup_request = NULL;
239
240   if (0 == rd_count)
241   {
242     msg = GNUNET_new (struct GNUNET_MessageHeader);
243     msg->header.size = htons (sizeof (struct GNUNET_MessageHeader));
244     msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
245     transmit (rq->client,
246               &msg->header);
247     GNUNET_CONTAINER_DLL_remove (rq_head,
248                                  rq_tail,
249                                  rq);
250     GNUNET_free_non_null (rq->name);
251     if (rq->u8name)
252       free (rq->u8name);
253     GNUNET_free (rq);
254     return;
255   }
256
257   size = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW);
258   size += (wcslen (rq->name) + 1) * sizeof (wchar_t);
259   size += sizeof (GUID);
260   /* lpszComment ? a TXT record? */
261   size += sizeof (GUID);
262   /* lpszContext ? Not sure what it is */
263   csanum = 0;
264   for (i = 0; i < rd_count; i++)
265   {
266     switch (rd[i].record_type)
267     {
268     case GNUNET_DNSPARSER_TYPE_A:
269       if (rd[i].data_size != sizeof (struct in_addr))
270         continue;
271       size += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in) * 2;
272       csanum++;
273       break;
274     case GNUNET_DNSPARSER_TYPE_AAAA:
275       if (rd[i].data_size != sizeof (struct in6_addr))
276         continue;
277       size += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in6) * 2;
278       csanum++;
279       break;
280     }
281   }
282   if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &rq->sc))
283   {
284     size += sizeof (BLOB);
285     blobsize += sizeof (struct hostent);
286     blobsize += strlen (rq->u8name) + 1;
287     blobsize += sizeof (void *); /* For aliases */
288     blobsize += sizeof (void *); /* For addresses */
289     for (i = 0; i < rd_count; i++)
290     {
291       if ((rq->af == AF_INET || rq->af == AF_UNSPEC) && rd[i].record_type == GNUNET_DNSPARSER_TYPE_A)
292       {
293         blobsize += sizeof (void *);
294         blobsize += sizeof (struct in_addr);
295         blobaddrcount++;
296       }
297       else if (rq->af == AF_INET6 && rd[i].record_type == GNUNET_DNSPARSER_TYPE_AAAA)
298       {
299         blobsize += sizeof (void *);
300         blobsize += sizeof (struct in6_addr);
301         blobaddrcount++;
302       }
303     }
304     size += blobsize;
305   }
306   size_recalc = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW);
307   msg = GNUNET_malloc (size);
308   msg->header.size = htons (size - sizeof (struct GNUNET_MessageHeader));
309   msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
310   msg->af = htonl (rq->af);
311   msg->sc_data1 = htonl (rq->sc.Data1);
312   msg->sc_data2 = htons (rq->sc.Data2);
313   msg->sc_data3 = htons (rq->sc.Data3);
314   for (i = 0; i < 8; i++)
315     msg->sc_data4[i] = rq->sc.Data4[i];
316   qs = (WSAQUERYSETW *) &msg[1];
317   ptr = (char *) &qs[1];
318   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
319   qs->dwSize = sizeof (WSAQUERYSETW);
320   qs->lpszServiceInstanceName = (wchar_t *) ptr;
321   ptr += (wcslen (rq->name) + 1) * sizeof (wchar_t);
322   size_recalc += (wcslen (rq->name) + 1) * sizeof (wchar_t);
323   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
324   wcscpy (qs->lpszServiceInstanceName, rq->name);
325   qs->lpServiceClassId = (GUID *) ptr;
326   ptr += sizeof (GUID);
327   size_recalc += sizeof (GUID);
328   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
329   GNUNET_memcpy (qs->lpServiceClassId, &rq->sc, sizeof (GUID));
330   qs->lpVersion = NULL;
331   qs->dwNameSpace = NS_DNS;
332   qs->lpNSProviderId = (GUID *) ptr;
333   ptr += sizeof (GUID);
334   size_recalc += sizeof (GUID);
335   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
336   GNUNET_memcpy (qs->lpNSProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS, sizeof (GUID));
337   qs->lpszContext = NULL;
338   qs->dwNumberOfProtocols = 0;
339   qs->lpafpProtocols = NULL;
340   /* Don't bother with this... */
341   qs->lpszQueryString = NULL;
342   qs->dwNumberOfCsAddrs = rd_count;
343   qs->lpcsaBuffer = (CSADDR_INFO *) ptr;
344   ptr += sizeof (CSADDR_INFO) * csanum;
345   j = 0;
346   for (i = 0; i < rd_count; i++)
347   {
348     switch (rd[i].record_type)
349     {
350     case GNUNET_DNSPARSER_TYPE_A:
351       if (rd[i].data_size != sizeof (struct in_addr))
352         continue;
353       qs->lpcsaBuffer[j].iSocketType = SOCK_STREAM;
354       qs->lpcsaBuffer[j].iProtocol = IPPROTO_TCP;
355
356       qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength = sizeof (struct sockaddr_in);
357       qs->lpcsaBuffer[j].LocalAddr.lpSockaddr = (SOCKADDR *) ptr;
358       ptr += qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength;
359       memset (qs->lpcsaBuffer[j].LocalAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength);
360       ((struct sockaddr_in *)qs->lpcsaBuffer[j].LocalAddr.lpSockaddr)->sin_family = AF_INET;
361
362       qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength = sizeof (struct sockaddr_in);
363       qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr = (SOCKADDR *) ptr;
364       ptr += qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength;
365       memset (qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength);
366       ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_family = AF_INET;
367       ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_port = htonl (53); /* Don't ask why it's 53 */
368       ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_addr = *(struct in_addr *) rd[i].data;
369       size_recalc += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in) * 2;
370       j++;
371       break;
372     case GNUNET_DNSPARSER_TYPE_AAAA:
373       if (rd[i].data_size != sizeof (struct in6_addr))
374         continue;
375       qs->lpcsaBuffer[j].iSocketType = SOCK_STREAM;
376       qs->lpcsaBuffer[j].iProtocol = IPPROTO_TCP;
377
378       qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength = sizeof (struct sockaddr_in6);
379       qs->lpcsaBuffer[j].LocalAddr.lpSockaddr = (SOCKADDR *) ptr;
380       ptr += qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength;
381       memset (qs->lpcsaBuffer[j].LocalAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength);
382       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].LocalAddr.lpSockaddr)->sin6_family = AF_INET6;
383
384       qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength = sizeof (struct sockaddr_in6);
385       qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr = (SOCKADDR *) ptr;
386       ptr += qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength;
387       memset (qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength);
388       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_family = AF_INET6;
389       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_port = htonl (53); /* Don't ask why it's 53 */
390       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_addr = *(struct in6_addr *) rd[i].data;
391       size_recalc += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in6) * 2;
392       j++;
393       break;
394     default:
395       break;
396     }
397   }
398   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
399   qs->dwOutputFlags = 0;
400   if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &rq->sc))
401   {
402     struct hostent *he;
403     qs->lpBlob = (BLOB *) ptr;
404     ptr += sizeof (BLOB);
405
406     size_recalc += sizeof (BLOB);
407     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
408
409     qs->lpBlob->cbSize = blobsize;
410     qs->lpBlob->pBlobData = (BYTE *) ptr;
411     ptr += sizeof (struct hostent);
412
413     size_recalc += sizeof (struct hostent);
414     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
415
416     he = (struct hostent *) qs->lpBlob->pBlobData;
417     he->h_name = (char *) ptr;
418     ptr += strlen (rq->u8name) + 1;
419
420     size_recalc += strlen (rq->u8name) + 1;
421     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
422
423     strcpy (he->h_name, rq->u8name);
424     he->h_aliases = (char **) ptr;
425     ptr += sizeof (void *);
426
427     size_recalc += sizeof (void *); /* For aliases */
428     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
429
430     he->h_aliases[0] = NULL;
431     he->h_addrtype = rq->af;
432     he->h_length = rq->af == AF_INET || rq->af == AF_UNSPEC ? sizeof (struct in_addr) : sizeof (struct in6_addr);
433     he->h_addr_list = (char **) ptr;
434     ptr += sizeof (void *) * (blobaddrcount + 1);
435
436     size_recalc += sizeof (void *) * (blobaddrcount + 1); /* For addresses */
437     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
438
439     j = 0;
440     for (i = 0; i < rd_count; i++)
441     {
442       if ((rq->af == AF_INET || rq->af == AF_UNSPEC) &&
443           rd[i].record_type == GNUNET_DNSPARSER_TYPE_A)
444       {
445         he->h_addr_list[j] = (char *) ptr;
446         ptr += sizeof (struct in_addr);
447
448         size_recalc += sizeof (struct in_addr);
449         GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
450
451         GNUNET_memcpy (he->h_addr_list[j], rd[i].data, sizeof (struct in_addr));
452         j++;
453       }
454       else if (rq->af == AF_INET6 && rd[i].record_type == GNUNET_DNSPARSER_TYPE_AAAA)
455       {
456         he->h_addr_list[j] = (char *) ptr;
457         ptr += sizeof (struct in6_addr);
458
459         size_recalc += sizeof (struct in6_addr);
460         GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
461
462         GNUNET_memcpy (he->h_addr_list[j], rd[i].data, sizeof (struct in6_addr));
463         j++;
464       }
465     }
466     he->h_addr_list[j] = NULL;
467   }
468   msgend = GNUNET_new (struct GNUNET_MessageHeader);
469
470   msgend->type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
471   msgend->size = htons (sizeof (struct GNUNET_MessageHeader));
472
473   if ((char *) ptr - (char *) msg != size || size_recalc != size || size_recalc != ((char *) ptr - (char *) msg))
474   {
475     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
476                 "Error in WSAQUERYSETW size calc: expected %u, got %lu (recalc %u)\n",
477                 size,
478                 (unsigned long) ((char *) ptr - (char *) msg),
479                 size_recalc);
480   }
481   MarshallWSAQUERYSETW (qs, &rq->sc);
482   transmit (rq->client,
483             &msg->header);
484   transmit (rq->client,
485             msgend);
486   GNUNET_CONTAINER_DLL_remove (rq_head,
487                                rq_tail,
488                                rq);
489   GNUNET_free_non_null (rq->name);
490   if (rq->u8name)
491     free (rq->u8name);
492   GNUNET_free (rq);
493 }
494
495
496 static void
497 get_ip_from_hostname (struct GNUNET_SERVICE_Client *client,
498                       const wchar_t *name,
499                       int af,
500                       GUID sc)
501 {
502   struct request *rq;
503   char *hostname;
504   size_t strl;
505   size_t namelen;
506   uint32_t rtype;
507
508   if (IsEqualGUID (&SVCID_DNS_TYPE_A, &sc))
509     rtype = GNUNET_DNSPARSER_TYPE_A;
510   else if (IsEqualGUID (&SVCID_DNS_TYPE_NS, &sc))
511     rtype = GNUNET_DNSPARSER_TYPE_NS;
512   else if (IsEqualGUID (&SVCID_DNS_TYPE_CNAME, &sc))
513     rtype = GNUNET_DNSPARSER_TYPE_CNAME;
514   else if (IsEqualGUID (&SVCID_DNS_TYPE_SOA, &sc))
515     rtype = GNUNET_DNSPARSER_TYPE_SOA;
516   else if (IsEqualGUID (&SVCID_DNS_TYPE_PTR, &sc))
517     rtype = GNUNET_DNSPARSER_TYPE_PTR;
518   else if (IsEqualGUID (&SVCID_DNS_TYPE_MX, &sc))
519     rtype = GNUNET_DNSPARSER_TYPE_MX;
520   else if (IsEqualGUID (&SVCID_DNS_TYPE_TEXT, &sc))
521     rtype = GNUNET_DNSPARSER_TYPE_TXT;
522   else if (IsEqualGUID (&SVCID_DNS_TYPE_AAAA, &sc))
523     rtype = GNUNET_DNSPARSER_TYPE_AAAA;
524   else if (IsEqualGUID (&SVCID_DNS_TYPE_SRV, &sc))
525     rtype = GNUNET_DNSPARSER_TYPE_SRV;
526   else if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &sc))
527     rtype = GNUNET_DNSPARSER_TYPE_A;
528   else
529   {
530     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
531                 "Unknown GUID: %08lX-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
532                 sc.Data1,
533                 sc.Data2,
534                 sc.Data3,
535                 sc.Data4[0],
536                 sc.Data4[1],
537                 sc.Data4[2],
538                 sc.Data4[3],
539                 sc.Data4[4],
540                 sc.Data4[5],
541                 sc.Data4[6],
542                 sc.Data4[7]);
543     GNUNET_SERVICE_client_drop (client);
544     return;
545   }
546
547   if (name)
548     namelen = wcslen (name);
549   else
550     namelen = 0;
551   if (namelen > 0)
552     hostname = (char *) u16_to_u8 (name, namelen + 1, NULL, &strl);
553   else
554     hostname = NULL;
555
556   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
557               "W32 DNS resolver asked to look up %s for `%s'.\n",
558               af == AF_INET ? "IPv4" : af == AF_INET6 ? "IPv6" : "anything",
559               hostname);
560
561   rq = GNUNET_new (struct request);
562   rq->sc = sc;
563   rq->client = client;
564   rq->af = af;
565   if (rq->af != AF_INET && rq->af != AF_INET6)
566     rq->af = AF_INET;
567   if (namelen)
568   {
569     rq->name = GNUNET_malloc ((namelen + 1) * sizeof (wchar_t));
570     GNUNET_memcpy (rq->name,
571                    name,
572                    (namelen + 1) * sizeof (wchar_t));
573     rq->u8name = hostname;
574   }
575
576   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
577               "Launching a lookup for client %p with rq %p\n",
578               client,
579               rq);
580   rq->lookup_request = GNUNET_GNS_lookup (gns,
581                                           hostname,
582                                           &gns_master_pubkey,
583                                           rtype,
584                                           GNUNET_NO /* Use DHT */,
585                                           &process_lookup_result,
586                                           rq);
587   if (NULL != rq->lookup_request)
588   {
589     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
590                 "Lookup launched, waiting for a reply\n");
591     GNUNET_SERVICE_client_continue (client);
592     GNUNET_CONTAINER_DLL_insert (rq_head,
593                                  rq_tail,
594                                  rq);
595   }
596   else
597   {
598     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
599                 "Lookup was not launched, disconnecting the client\n");
600     GNUNET_free_non_null (rq->name);
601     if (rq->u8name)
602       free (rq->u8name);
603     GNUNET_free (rq);
604     GNUNET_SERVICE_client_drop (client);
605   }
606 }
607
608
609 /**
610  * Check GET-message.
611  *
612  * @param cls identification of the client
613  * @param msg the actual message
614  * @return #GNUNET_OK if @a msg is well-formed
615  */
616 static int
617 check_get (void *cls,
618             const struct GNUNET_W32RESOLVER_GetMessage *msg)
619 {
620   uint16_t size;
621   const wchar_t *hostname;
622
623   if (! got_egos)
624   {
625     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
626                 _("Not ready to process requests, lacking ego data\n"));
627     return GNUNET_SYSERR;
628   }
629   size = ntohs (msg->header.size) - sizeof (struct GNUNET_W32RESOLVER_GetMessage);
630   hostname = (const wchar_t *) &msg[1];
631   if (hostname[size / 2 - 1] != L'\0')
632   {
633     GNUNET_break (0);
634     return GNUNET_SYSERR;
635   }
636   return GNUNET_OK;
637 }
638
639
640 /**
641  * Handle GET-message.
642  *
643  * @param cls identification of the client
644  * @param msg the actual message
645  */
646 static void
647 handle_get (void *cls,
648             const struct GNUNET_W32RESOLVER_GetMessage *msg)
649 {
650   struct GNUNET_SERVICE_Client *client = cls;
651   GUID sc;
652   uint16_t size;
653   const wchar_t *hostname;
654   int af;
655
656   size = ntohs (msg->header.size) - sizeof (struct GNUNET_W32RESOLVER_GetMessage);
657   af = ntohl (msg->af);
658   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659               "Got NBO GUID: %08X-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
660               msg->sc_data1,
661               msg->sc_data2,
662               msg->sc_data3,
663               msg->sc_data4[0],
664               msg->sc_data4[1],
665               msg->sc_data4[2],
666               msg->sc_data4[3],
667               msg->sc_data4[4],
668               msg->sc_data4[5],
669               msg->sc_data4[6],
670               msg->sc_data4[7]);
671   sc.Data1 = ntohl (msg->sc_data1);
672   sc.Data2 = ntohs (msg->sc_data2);
673   sc.Data3 = ntohs (msg->sc_data3);
674   for (int i = 0; i < 8; i++)
675     sc.Data4[i] = msg->sc_data4[i];
676   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
677               "Got GUID: %08lX-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
678               sc.Data1,
679               sc.Data2,
680               sc.Data3,
681               sc.Data4[0],
682               sc.Data4[1],
683               sc.Data4[2],
684               sc.Data4[3],
685               sc.Data4[4],
686               sc.Data4[5],
687               sc.Data4[6],
688               sc.Data4[7]);
689   hostname = (const wchar_t *) &msg[1];
690   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
691               "Name of %u bytes (last word is 0x%0X): %*S\n",
692               size,
693               hostname[size / 2 - 2],
694               size / 2,
695               hostname);
696   get_ip_from_hostname (client,
697                         hostname,
698                         af,
699                         sc);
700 }
701
702
703 /**
704  * Method called to with the ego we are to use for the lookup,
705  * when the ego is the one for the default master zone.
706  *
707  * @param cls closure (NULL, unused)
708  * @param ego ego handle, NULL if not found
709  * @param ctx context for application to store data for this ego
710  *                 (during the lifetime of this process, initially NULL)
711  * @param name name assigned by the user for this ego,
712  *                   NULL if the user just deleted the ego and it
713  *                   must thus no longer be used
714  */
715 static void
716 identity_master_cb (void *cls,
717                     struct GNUNET_IDENTITY_Ego *ego,
718                     void **ctx,
719                     const char *name)
720 {
721   id_op = NULL;
722   if (NULL == ego)
723   {
724     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
725                 _("Ego for `gns-master' not found, cannot perform lookup.  Did you run gnunet-gns-import.sh?\n"));
726     GNUNET_SCHEDULER_shutdown ();
727     return;
728   }
729   GNUNET_IDENTITY_ego_get_public_key (ego,
730                                       &gns_master_pubkey);
731   got_egos = 1;
732 }
733
734
735 /**
736  * Start up gns-helper-w32 service.
737  *
738  * @param cls closure
739  * @param cfg configuration to use
740  * @param service the initialized service
741  */
742 static void
743 run (void *cls,
744      const struct GNUNET_CONFIGURATION_Handle *cfg,
745      struct GNUNET_SERVICE_Handle *service)
746 {
747   gns = GNUNET_GNS_connect (cfg);
748   if (NULL == gns)
749   {
750     fprintf (stderr,
751              _("Failed to connect to GNS\n"));
752     GNUNET_SCHEDULER_shutdown ();
753     return;
754   }
755   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
756                                  NULL);
757   identity = GNUNET_IDENTITY_connect (cfg,
758                                       NULL,
759                                       NULL);
760   if (NULL == identity)
761   {
762     fprintf (stderr,
763              _("Failed to connect to identity service\n"));
764     GNUNET_SCHEDULER_shutdown ();
765     return;
766   }
767   id_op = GNUNET_IDENTITY_get (identity,
768                                "gns-master",
769                                &identity_master_cb,
770                                NULL);
771   GNUNET_assert (NULL != id_op);
772 }
773
774
775 /**
776  * Handle client connecting to the service.
777  *
778  * @param cls NULL
779  * @param client the new client
780  * @param mq the message queue of @a client
781  * @return @a client
782  */
783 static void *
784 client_connect_cb (void *cls,
785                    struct GNUNET_SERVICE_Client *client,
786                    struct GNUNET_MQ_Handle *mq)
787 {
788   return client;
789 }
790
791
792 /**
793  * Callback called when a client disconnected from the service
794  *
795  * @param cls closure for the service
796  * @param c the client that disconnected
797  * @param internal_cls should be equal to @a c
798  */
799 static void
800 client_disconnect_cb (void *cls,
801                       struct GNUNET_SERVICE_Client *client,
802                       void *internal_cls)
803 {
804   GNUNET_assert (internal_cls == client);
805 }
806
807
808 /**
809  * Define "main" method using service macro.
810  */
811 GNUNET_SERVICE_MAIN
812 ("gns-helper-service-w32",
813  GNUNET_SERVICE_OPTION_NONE,
814  &run,
815  &client_connect_cb,
816  &client_disconnect_cb,
817  NULL,
818  GNUNET_MQ_hd_var_size (get,
819                         GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST,
820                         struct GNUNET_W32RESOLVER_GetMessage,
821                         NULL),
822  GNUNET_MQ_handler_end());
823
824
825 /* end of gnunet-gns-helper-service-w32.c */