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