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