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